Merge pull request #118 from JadeShrineMaiden/moblocomotion

Greased up enemies
This commit is contained in:
dongresource 2020-09-27 20:02:52 +02:00 committed by GitHub
commit a324f3fda9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 86 additions and 15 deletions

View File

@ -123,6 +123,9 @@ void ItemManager::itemMoveHandler(CNSocket* sock, CNPacketData* data) {
// send equip event to other players // send equip event to other players
PlayerManager::sendToViewable(sock, (void*)&equipChange, P_FE2CL_PC_EQUIP_CHANGE, sizeof(sP_FE2CL_PC_EQUIP_CHANGE)); PlayerManager::sendToViewable(sock, (void*)&equipChange, P_FE2CL_PC_EQUIP_CHANGE, sizeof(sP_FE2CL_PC_EQUIP_CHANGE));
// set equipment stats serverside
setItemStats(plr.plr);
} }
// send response // send response
@ -859,3 +862,19 @@ void ItemManager::checkItemExpire(CNSocket* sock, Player* player) {
player->toRemoveVehicle.eIL = 0; player->toRemoveVehicle.eIL = 0;
player->toRemoveVehicle.iSlotNum = 0; player->toRemoveVehicle.iSlotNum = 0;
} }
void ItemManager::setItemStats(Player* plr) {
plr->pointDamage = 8 + plr->level * 2;
plr->groupDamage = 8 + plr->level * 2;
plr->defense = 16 + plr->level * 4;
Item* itemStatsDat;
for (int i = 0; i < 4; i++) {
itemStatsDat = ItemManager::getItemData(plr->Equip[i].iID, plr->Equip[i].iType);
plr->pointDamage += itemStatsDat->pointDamage;
plr->groupDamage += itemStatsDat->groupDamage;
plr->defense += itemStatsDat->defense;
}
}

View File

@ -5,7 +5,7 @@
struct Item { struct Item {
bool tradeable, sellable; bool tradeable, sellable;
int buyPrice, sellPrice, stackSize, level, rarity; // TODO: implement more as needed int buyPrice, sellPrice, stackSize, level, rarity, pointDamage, groupDamage, defense; // TODO: implement more as needed
}; };
struct VendorListing { struct VendorListing {
int sort, type, iID; int sort, type, iID;
@ -49,4 +49,5 @@ namespace ItemManager {
int findFreeSlot(Player *plr); int findFreeSlot(Player *plr);
Item* getItemData(int32_t id, int32_t type); Item* getItemData(int32_t id, int32_t type);
void checkItemExpire(CNSocket* sock, Player* player); void checkItemExpire(CNSocket* sock, Player* player);
void setItemStats(Player* plr);
} }

View File

@ -7,6 +7,13 @@
#include <cmath> #include <cmath>
#include <assert.h> #include <assert.h>
#ifndef MIN
# define MIN(A,B) ((A)<(B)?(A):(B))
#endif
#ifndef MAX
# define MAX(A,B) ((A)>(B)?(A):(B))
#endif
std::map<int32_t, Mob*> MobManager::Mobs; std::map<int32_t, Mob*> MobManager::Mobs;
void MobManager::init() { void MobManager::init() {
@ -61,12 +68,19 @@ void MobManager::pcAttackNpcs(CNSocket *sock, CNPacketData *data) {
} }
Mob *mob = Mobs[pktdata[i]]; Mob *mob = Mobs[pktdata[i]];
int damage = hitMob(sock, mob, 150); std::pair<int,int> damage;
if (pkt->iNPCCnt > 1)
damage = getDamage(plr->groupDamage, (int)mob->data["m_iProtection"], true, (int)mob->data["m_iNpcLevel"]);
else
damage = getDamage(plr->pointDamage, (int)mob->data["m_iProtection"], true, (int)mob->data["m_iNpcLevel"]);
damage.first = hitMob(sock, mob, damage.first);
respdata[i].iID = mob->appearanceData.iNPC_ID; respdata[i].iID = mob->appearanceData.iNPC_ID;
respdata[i].iDamage = damage; respdata[i].iDamage = damage.first;
respdata[i].iHP = mob->appearanceData.iHP; respdata[i].iHP = mob->appearanceData.iHP;
respdata[i].iHitFlag = 2; // hitscan, not a rocket or a grenade respdata[i].iHitFlag = damage.second; // hitscan, not a rocket or a grenade
} }
resp->iBatteryW = plr->batteryW; resp->iBatteryW = plr->batteryW;
@ -94,15 +108,16 @@ void MobManager::npcAttackPc(Mob *mob) {
sP_FE2CL_NPC_ATTACK_PCs *pkt = (sP_FE2CL_NPC_ATTACK_PCs*)respbuf; sP_FE2CL_NPC_ATTACK_PCs *pkt = (sP_FE2CL_NPC_ATTACK_PCs*)respbuf;
sAttackResult *atk = (sAttackResult*)(respbuf + sizeof(sP_FE2CL_NPC_ATTACK_PCs)); sAttackResult *atk = (sAttackResult*)(respbuf + sizeof(sP_FE2CL_NPC_ATTACK_PCs));
plr->HP += (int)mob->data["m_iPower"]; // already negative auto damage = getDamage(440 + (int)mob->data["m_iPower"], plr->defense, false, 36 - (int)mob->data["m_iNpcLevel"]);
plr->HP -= damage.first;
pkt->iNPC_ID = mob->appearanceData.iNPC_ID; pkt->iNPC_ID = mob->appearanceData.iNPC_ID;
pkt->iPCCnt = 1; pkt->iPCCnt = 1;
atk->iID = plr->iID; atk->iID = plr->iID;
atk->iDamage = -(int)mob->data["m_iPower"]; atk->iDamage = damage.first;
atk->iHP = plr->HP; atk->iHP = plr->HP;
atk->iHitFlag = 2; atk->iHitFlag = damage.second;
mob->target->sendPacket((void*)respbuf, P_FE2CL_NPC_ATTACK_PCs, resplen); mob->target->sendPacket((void*)respbuf, P_FE2CL_NPC_ATTACK_PCs, resplen);
PlayerManager::sendToViewable(mob->target, (void*)respbuf, P_FE2CL_NPC_ATTACK_PCs, resplen); PlayerManager::sendToViewable(mob->target, (void*)respbuf, P_FE2CL_NPC_ATTACK_PCs, resplen);
@ -275,7 +290,7 @@ void MobManager::combatStep(Mob *mob, time_t currTime) {
// movement logic // movement logic
if (mob->nextMovement != 0 && currTime < mob->nextMovement) if (mob->nextMovement != 0 && currTime < mob->nextMovement)
return; return;
mob->nextMovement = currTime + (int)mob->data["m_iDelayTime"] * 100; mob->nextMovement = currTime + 500;
int speed = mob->data["m_iRunSpeed"]; int speed = mob->data["m_iRunSpeed"];
@ -384,6 +399,11 @@ void MobManager::roamingStep(Mob *mob, time_t currTime) {
void MobManager::retreatStep(Mob *mob, time_t currTime) { void MobManager::retreatStep(Mob *mob, time_t currTime) {
// distance between spawn point and current location // distance between spawn point and current location
if (mob->nextMovement != 0 && currTime < mob->nextMovement)
return;
mob->nextMovement = currTime + 500;
int distance = hypot(mob->appearanceData.iX - mob->spawnX, mob->appearanceData.iY - mob->spawnY); int distance = hypot(mob->appearanceData.iX - mob->spawnX, mob->appearanceData.iY - mob->spawnY);
if (distance > mob->data["m_iIdleRange"]) { if (distance > mob->data["m_iIdleRange"]) {
@ -456,13 +476,21 @@ void MobManager::step(CNServer *serv, time_t currTime) {
std::pair<int,int> MobManager::lerp(int x1, int y1, int x2, int y2, int speed) { std::pair<int,int> MobManager::lerp(int x1, int y1, int x2, int y2, int speed) {
std::pair<int,int> ret = {}; std::pair<int,int> ret = {};
speed /= 2;
int distance = hypot(x1 - x2, y1 - y2); int distance = hypot(x1 - x2, y1 - y2);
if (distance > speed) {
int lerps = distance / speed; int lerps = distance / speed;
// interpolate only the first point // interpolate only the first point
float frac = 1.0f / (lerps+1); float frac = 1.0f / (lerps);
ret.first = (x1 * (1.0f - frac)) + (x2 * frac);
ret.second = (y1 * (1.0f - frac)) + (y2 * frac); ret.first = (x1 + (x2 - x1) * frac);
ret.second = (y1 + (y2 - y1) * frac);
} else {
ret.first = x2;
ret.second = y2;
}
return ret; return ret;
} }
@ -572,3 +600,19 @@ void MobManager::playerTick(CNServer *serv, time_t currTime) {
if (currTime - lastHealTime < 4000) if (currTime - lastHealTime < 4000)
lastHealTime = currTime; lastHealTime = currTime;
} }
std::pair<int,int> MobManager::getDamage(int attackPower, int defensePower, bool shouldCrit, int crutchLevel) {
std::pair<int,int> ret = {};
int damage = (MAX(40, attackPower - defensePower) * (34 + crutchLevel) + MIN(attackPower, attackPower * attackPower / defensePower) * (36 - crutchLevel)) / 70;
ret.first = damage * (rand() % 40 + 80) / 100; // 20% variance
ret.second = 1;
if (shouldCrit && rand() % 20 == 0) {
ret.first *= 2; // critical hit
ret.second = 2;
}
return ret;
}

View File

@ -104,4 +104,5 @@ namespace MobManager {
void killMob(CNSocket *sock, Mob *mob); void killMob(CNSocket *sock, Mob *mob);
void giveReward(CNSocket *sock); void giveReward(CNSocket *sock);
std::pair<int,int> lerp(int, int, int, int, int); std::pair<int,int> lerp(int, int, int, int, int);
std::pair<int,int> getDamage(int, int, bool, int);
} }

View File

@ -47,6 +47,10 @@ struct Player {
bool inCombat; bool inCombat;
bool dotDamage; bool dotDamage;
int pointDamage;
int groupDamage;
int defense;
int64_t aQuestFlag[16]; int64_t aQuestFlag[16];
int tasks[ACTIVE_MISSION_COUNT]; int tasks[ACTIVE_MISSION_COUNT];
int RemainingNPCCount[ACTIVE_MISSION_COUNT][3]; int RemainingNPCCount[ACTIVE_MISSION_COUNT][3];

View File

@ -322,6 +322,9 @@ void PlayerManager::enterPlayer(CNSocket* sock, CNPacketData* data) {
addPlayer(sock, plr); addPlayer(sock, plr);
//check if there is an expiring vehicle //check if there is an expiring vehicle
ItemManager::checkItemExpire(sock, getPlayer(sock)); ItemManager::checkItemExpire(sock, getPlayer(sock));
//set player equip stats
ItemManager::setItemStats(getPlayer(sock));
} }
void PlayerManager::sendToViewable(CNSocket* sock, void* buf, uint32_t type, size_t size) { void PlayerManager::sendToViewable(CNSocket* sock, void* buf, uint32_t type, size_t size) {

View File

@ -117,8 +117,7 @@ void TableData::init() {
auto item = _item.value(); auto item = _item.value();
int typeOverride = getItemType(i); // used for special cases where iEquipLoc doesn't indicate item type int typeOverride = getItemType(i); // used for special cases where iEquipLoc doesn't indicate item type
ItemManager::ItemData[std::pair<int32_t, int32_t>(item["m_iItemNumber"], typeOverride != -1 ? typeOverride : (int)item["m_iEquipLoc"])] ItemManager::ItemData[std::pair<int32_t, int32_t>(item["m_iItemNumber"], typeOverride != -1 ? typeOverride : (int)item["m_iEquipLoc"])]
= { item["m_iTradeAble"] == 1, item["m_iSellAble"] == 1, item["m_iItemPrice"], item["m_iItemSellPrice"], item["m_iStackNumber"], i > 9 ? 0 : (int)item["m_iMinReqLev"], = { item["m_iTradeAble"] == 1, item["m_iSellAble"] == 1, item["m_iItemPrice"], item["m_iItemSellPrice"], item["m_iStackNumber"], i > 9 ? 0 : (int)item["m_iMinReqLev"], i > 9 ? 1 : (int)item["m_iRarity"], i > 9 ? 0 : (int)item["m_iPointRat"], i > 9 ? 0 : (int)item["m_iGroupRat"], i > 9 ? 0 : (int)item["m_iDefenseRat"] };
i > 9 ? 1 : (int)item["m_iRarity"] };
} }
} }