diff --git a/src/Abilities.cpp b/src/Abilities.cpp index 27f36b9..bc438f6 100644 --- a/src/Abilities.cpp +++ b/src/Abilities.cpp @@ -151,15 +151,15 @@ bool doDebuff(CNSocket *sock, sSkillResult_Buff *respdata, int i, int32_t target Combat::hitMob(sock, mob, 0); respdata[i].eCT = 4; - respdata[i].iID = mob->appearanceData.iNPC_ID; + respdata[i].iID = mob->id; respdata[i].bProtected = 1; if (mob->skillStyle < 0 && mob->state != MobState::RETREAT - && !(mob->appearanceData.iConditionBitFlag & CSB_BIT_FREEDOM)) { // only debuff if the enemy is not retreating, casting corruption or in freedom - mob->appearanceData.iConditionBitFlag |= bitFlag; + && !(mob->cbf & CSB_BIT_FREEDOM)) { // only debuff if the enemy is not retreating, casting corruption or in freedom + mob->cbf |= bitFlag; mob->unbuffTimes[bitFlag] = getTime() + duration * 100; respdata[i].bProtected = 0; } - respdata[i].iConditionBitFlag = mob->appearanceData.iConditionBitFlag; + respdata[i].iConditionBitFlag = mob->cbf; return true; } @@ -224,16 +224,16 @@ bool doDamageNDebuff(CNSocket *sock, sSkillResult_Damage_N_Debuff *respdata, int respdata[i].eCT = 4; respdata[i].iDamage = duration / 10; - respdata[i].iID = mob->appearanceData.iNPC_ID; - respdata[i].iHP = mob->appearanceData.iHP; + respdata[i].iID = mob->id; + respdata[i].iHP = mob->hp; respdata[i].bProtected = 1; if (mob->skillStyle < 0 && mob->state != MobState::RETREAT - && !(mob->appearanceData.iConditionBitFlag & CSB_BIT_FREEDOM)) { // only debuff if the enemy is not retreating, casting corruption or in freedom - mob->appearanceData.iConditionBitFlag |= bitFlag; + && !(mob->cbf & CSB_BIT_FREEDOM)) { // only debuff if the enemy is not retreating, casting corruption or in freedom + mob->cbf |= bitFlag; mob->unbuffTimes[bitFlag] = getTime() + duration * 100; respdata[i].bProtected = 0; } - respdata[i].iConditionBitFlag = mob->appearanceData.iConditionBitFlag; + respdata[i].iConditionBitFlag = mob->cbf; return true; } @@ -293,8 +293,8 @@ bool doDamage(CNSocket *sock, sSkillResult_Damage *respdata, int i, int32_t targ respdata[i].eCT = 4; respdata[i].iDamage = damage; - respdata[i].iID = mob->appearanceData.iNPC_ID; - respdata[i].iHP = mob->appearanceData.iHP; + respdata[i].iID = mob->id; + respdata[i].iHP = mob->hp; return true; } @@ -348,8 +348,8 @@ bool doLeech(CNSocket *sock, sSkillResult_Heal_HP *healdata, int i, int32_t targ damagedata->eCT = 4; damagedata->iDamage = damage; - damagedata->iID = mob->appearanceData.iNPC_ID; - damagedata->iHP = mob->appearanceData.iHP; + damagedata->iID = mob->id; + damagedata->iHP = mob->hp; return true; } @@ -476,13 +476,13 @@ bool doHeal(Mob* mob, sSkillResult_Heal_HP* respdata, int i, int32_t targetID, i Mob* targetMob = (Mob*)npc; int healedAmount = amount * targetMob->maxHealth / 1000; - targetMob->appearanceData.iHP += healedAmount; - if (targetMob->appearanceData.iHP > targetMob->maxHealth) - targetMob->appearanceData.iHP = targetMob->maxHealth; + targetMob->hp += healedAmount; + if (targetMob->hp > targetMob->maxHealth) + targetMob->hp = targetMob->maxHealth; respdata[i].eCT = 4; - respdata[i].iID = targetMob->appearanceData.iNPC_ID; - respdata[i].iHP = targetMob->appearanceData.iHP; + respdata[i].iID = targetMob->id; + respdata[i].iHP = targetMob->hp; respdata[i].iHealHP = healedAmount; return true; @@ -490,13 +490,13 @@ bool doHeal(Mob* mob, sSkillResult_Heal_HP* respdata, int i, int32_t targetID, i bool doReturnHeal(Mob* mob, sSkillResult_Heal_HP* respdata, int i, int32_t targetID, int32_t bitFlag, int16_t timeBuffID, int16_t duration, int16_t amount) { int healedAmount = amount * mob->maxHealth / 1000; - mob->appearanceData.iHP += healedAmount; - if (mob->appearanceData.iHP > mob->maxHealth) - mob->appearanceData.iHP = mob->maxHealth; + mob->hp += healedAmount; + if (mob->hp > mob->maxHealth) + mob->hp = mob->maxHealth; respdata[i].eCT = 4; - respdata[i].iID = mob->appearanceData.iNPC_ID; - respdata[i].iHP = mob->appearanceData.iHP; + respdata[i].iID = mob->id; + respdata[i].iHP = mob->hp; respdata[i].iHealHP = healedAmount; return true; @@ -567,13 +567,13 @@ bool doLeech(Mob* mob, sSkillResult_Heal_HP* healdata, int i, int32_t targetID, int healedAmount = amount * PC_MAXHEALTH(plr->level) / 1000; - mob->appearanceData.iHP += healedAmount; - if (mob->appearanceData.iHP > mob->maxHealth) - mob->appearanceData.iHP = mob->maxHealth; + mob->hp += healedAmount; + if (mob->hp > mob->maxHealth) + mob->hp = mob->maxHealth; healdata->eCT = 4; - healdata->iID = mob->appearanceData.iNPC_ID; - healdata->iHP = mob->appearanceData.iHP; + healdata->iID = mob->id; + healdata->iHP = mob->hp; healdata->iHealHP = healedAmount; int damage = healedAmount; @@ -639,9 +639,9 @@ bool doBatteryDrain(Mob* mob, sSkillResult_BatteryDrain* respdata, int i, int32_ bool doBuff(Mob* mob, sSkillResult_Buff* respdata, int i, int32_t targetID, int32_t bitFlag, int16_t timeBuffID, int16_t duration, int16_t amount) { respdata[i].eCT = 4; - respdata[i].iID = mob->appearanceData.iNPC_ID; - mob->appearanceData.iConditionBitFlag |= bitFlag; - respdata[i].iConditionBitFlag = mob->appearanceData.iConditionBitFlag; + respdata[i].iID = mob->id; + mob->cbf |= bitFlag; + respdata[i].iConditionBitFlag = mob->cbf; return true; } @@ -670,7 +670,7 @@ templateiNPC_ID = mob->appearanceData.iNPC_ID; + resp->iNPC_ID = mob->id; resp->iSkillID = skillID; resp->iValue1 = mob->hitX; resp->iValue2 = mob->hitY; diff --git a/src/Chunking.cpp b/src/Chunking.cpp index fcc9150..04b391f 100644 --- a/src/Chunking.cpp +++ b/src/Chunking.cpp @@ -279,42 +279,42 @@ void Chunking::createInstance(uint64_t instanceID) { if (((Mob*)baseNPC)->groupLeader != 0 && ((Mob*)baseNPC)->groupLeader != npcID) continue; // follower; don't copy individually - Mob* newMob = new Mob(baseNPC->x, baseNPC->y, baseNPC->z, baseNPC->appearanceData.iAngle, - instanceID, baseNPC->appearanceData.iNPCType, NPCManager::NPCData[baseNPC->appearanceData.iNPCType], NPCManager::nextId--); - NPCManager::NPCs[newMob->appearanceData.iNPC_ID] = newMob; + Mob* newMob = new Mob(baseNPC->x, baseNPC->y, baseNPC->z, baseNPC->angle, + instanceID, baseNPC->type, NPCManager::NPCData[baseNPC->type], NPCManager::nextId--); + NPCManager::NPCs[newMob->id] = newMob; // if in a group, copy over group members as well if (((Mob*)baseNPC)->groupLeader != 0) { - newMob->groupLeader = newMob->appearanceData.iNPC_ID; // set leader ID for new leader + newMob->groupLeader = newMob->id; // set leader ID for new leader Mob* mobData = (Mob*)baseNPC; for (int i = 0; i < 4; i++) { if (mobData->groupMember[i] != 0) { int followerID = NPCManager::nextId--; // id for follower BaseNPC* baseFollower = NPCManager::NPCs[mobData->groupMember[i]]; // follower from template // new follower instance - Mob* newMobFollower = new Mob(baseFollower->x, baseFollower->y, baseFollower->z, baseFollower->appearanceData.iAngle, - instanceID, baseFollower->appearanceData.iNPCType, NPCManager::NPCData[baseFollower->appearanceData.iNPCType], followerID); + Mob* newMobFollower = new Mob(baseFollower->x, baseFollower->y, baseFollower->z, baseFollower->angle, + instanceID, baseFollower->type, NPCManager::NPCData[baseFollower->type], followerID); // add follower to NPC maps NPCManager::NPCs[followerID] = newMobFollower; // set follower-specific properties - newMobFollower->groupLeader = newMob->appearanceData.iNPC_ID; + newMobFollower->groupLeader = newMob->id; newMobFollower->offsetX = ((Mob*)baseFollower)->offsetX; newMobFollower->offsetY = ((Mob*)baseFollower)->offsetY; // add follower copy to leader copy newMob->groupMember[i] = followerID; NPCManager::updateNPCPosition(followerID, baseFollower->x, baseFollower->y, baseFollower->z, - instanceID, baseFollower->appearanceData.iAngle); + instanceID, baseFollower->angle); } } } - NPCManager::updateNPCPosition(newMob->appearanceData.iNPC_ID, baseNPC->x, baseNPC->y, baseNPC->z, - instanceID, baseNPC->appearanceData.iAngle); + NPCManager::updateNPCPosition(newMob->id, baseNPC->x, baseNPC->y, baseNPC->z, + instanceID, baseNPC->angle); } else { - BaseNPC* newNPC = new BaseNPC(baseNPC->x, baseNPC->y, baseNPC->z, baseNPC->appearanceData.iAngle, - instanceID, baseNPC->appearanceData.iNPCType, NPCManager::nextId--); - NPCManager::NPCs[newNPC->appearanceData.iNPC_ID] = newNPC; - NPCManager::updateNPCPosition(newNPC->appearanceData.iNPC_ID, baseNPC->x, baseNPC->y, baseNPC->z, - instanceID, baseNPC->appearanceData.iAngle); + BaseNPC* newNPC = new BaseNPC(baseNPC->x, baseNPC->y, baseNPC->z, baseNPC->angle, + instanceID, baseNPC->type, NPCManager::nextId--); + NPCManager::NPCs[newNPC->id] = newNPC; + NPCManager::updateNPCPosition(newNPC->id, baseNPC->x, baseNPC->y, baseNPC->z, + instanceID, baseNPC->angle); } } } diff --git a/src/Combat.cpp b/src/Combat.cpp index ce5f668..2e7f76c 100644 --- a/src/Combat.cpp +++ b/src/Combat.cpp @@ -139,9 +139,9 @@ static void pcAttackNpcs(CNSocket *sock, CNPacketData *data) { damage.first = hitMob(sock, mob, damage.first); - respdata[i].iID = mob->appearanceData.iNPC_ID; + respdata[i].iID = mob->id; respdata[i].iDamage = damage.first; - respdata[i].iHP = mob->appearanceData.iHP; + respdata[i].iHP = mob->hp; respdata[i].iHitFlag = damage.second; // hitscan, not a rocket or a grenade } @@ -168,7 +168,7 @@ void Combat::npcAttackPc(Mob *mob, time_t currTime) { if (!(plr->iSpecialState & CN_SPECIAL_STATE_FLAG__INVULNERABLE)) plr->HP -= damage.first; - pkt->iNPC_ID = mob->appearanceData.iNPC_ID; + pkt->iNPC_ID = mob->id; pkt->iPCCnt = 1; atk->iID = plr->iID; @@ -207,20 +207,20 @@ int Combat::hitMob(CNSocket *sock, Mob *mob, int damage) { MobAI::followToCombat(mob); } - mob->appearanceData.iHP -= damage; + mob->hp -= damage; // wake up sleeping monster - if (mob->appearanceData.iConditionBitFlag & CSB_BIT_MEZ) { - mob->appearanceData.iConditionBitFlag &= ~CSB_BIT_MEZ; + if (mob->cbf & CSB_BIT_MEZ) { + mob->cbf &= ~CSB_BIT_MEZ; INITSTRUCT(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT, pkt1); pkt1.eCT = 2; - pkt1.iID = mob->appearanceData.iNPC_ID; - pkt1.iConditionBitFlag = mob->appearanceData.iConditionBitFlag; + pkt1.iID = mob->id; + pkt1.iConditionBitFlag = mob->cbf; NPCManager::sendToViewable(mob, &pkt1, P_FE2CL_CHAR_TIME_BUFF_TIME_OUT, sizeof(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT)); } - if (mob->appearanceData.iHP <= 0) + if (mob->hp <= 0) killMob(mob->target, mob); return damage; @@ -253,7 +253,7 @@ static void genQItemRolls(Player *leader, std::map& rolls) { void Combat::killMob(CNSocket *sock, Mob *mob) { mob->state = MobState::DEAD; mob->target = nullptr; - mob->appearanceData.iConditionBitFlag = 0; + mob->cbf = 0; mob->skillStyle = -1; mob->unbuffTimes.clear(); mob->killedTime = getTime(); // XXX: maybe introduce a shard-global time for each step? @@ -273,7 +273,7 @@ void Combat::killMob(CNSocket *sock, Mob *mob) { if (plr->groupCnt == 1 && plr->iIDGroup == plr->iID) { Items::giveMobDrop(sock, mob, rolled, eventRolled); - Missions::mobKilled(sock, mob->appearanceData.iNPCType, qitemRolls); + Missions::mobKilled(sock, mob->type, qitemRolls); } else { for (int i = 0; i < leader->groupCnt; i++) { CNSocket* sockTo = PlayerManager::getSockFromID(leader->groupIDs[i]); @@ -288,7 +288,7 @@ void Combat::killMob(CNSocket *sock, Mob *mob) { continue; Items::giveMobDrop(sockTo, mob, rolled, eventRolled); - Missions::mobKilled(sockTo, mob->appearanceData.iNPCType, qitemRolls); + Missions::mobKilled(sockTo, mob->type, qitemRolls); } } } @@ -298,10 +298,10 @@ void Combat::killMob(CNSocket *sock, Mob *mob) { // fire any triggered events for (NPCEvent& event : NPCManager::NPCEvents) - if (event.trigger == ON_KILLED && event.npcType == mob->appearanceData.iNPCType) + if (event.trigger == ON_KILLED && event.npcType == mob->type) event.handler(sock, mob); - auto it = Transport::NPCQueues.find(mob->appearanceData.iNPC_ID); + auto it = Transport::NPCQueues.find(mob->id); if (it == Transport::NPCQueues.end() || it->second.empty()) return; @@ -319,7 +319,7 @@ void Combat::killMob(CNSocket *sock, Mob *mob) { queue.push(point); } } else { - Transport::NPCQueues.erase(mob->appearanceData.iNPC_ID); + Transport::NPCQueues.erase(mob->id); } } @@ -513,9 +513,9 @@ static void pcAttackChars(CNSocket *sock, CNPacketData *data) { damage.first = hitMob(sock, mob, damage.first); respdata[i].eCT = pktdata[i*2+1]; - respdata[i].iID = mob->appearanceData.iNPC_ID; + respdata[i].iID = mob->id; respdata[i].iDamage = damage.first; - respdata[i].iHP = mob->appearanceData.iHP; + respdata[i].iHP = mob->hp; respdata[i].iHitFlag = damage.second; // hitscan, not a rocket or a grenade } } @@ -711,9 +711,9 @@ static void projectileHit(CNSocket* sock, CNPacketData* data) { damage.first = hitMob(sock, mob, damage.first); - respdata[i].iID = mob->appearanceData.iNPC_ID; + respdata[i].iID = mob->id; respdata[i].iDamage = damage.first; - respdata[i].iHP = mob->appearanceData.iHP; + respdata[i].iHP = mob->hp; respdata[i].iHitFlag = damage.second; } diff --git a/src/CustomCommands.cpp b/src/CustomCommands.cpp index b277328..d171bbb 100644 --- a/src/CustomCommands.cpp +++ b/src/CustomCommands.cpp @@ -243,20 +243,20 @@ static void summonWCommand(std::string full, std::vector& args, CNS BaseNPC *npc = NPCManager::summonNPC(plr->x, plr->y, plr->z, plr->instanceID, type, true); // update angle - npc->appearanceData.iAngle = (plr->angle + 180) % 360; - NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, plr->x, plr->y, plr->z, plr->instanceID, npc->appearanceData.iAngle); + npc->angle = (plr->angle + 180) % 360; + NPCManager::updateNPCPosition(npc->id, plr->x, plr->y, plr->z, plr->instanceID, npc->angle); // if we're in a lair, we need to spawn the NPC in both the private instance and the template if (PLAYERID(plr->instanceID) != 0) { npc = NPCManager::summonNPC(plr->x, plr->y, plr->z, plr->instanceID, type, true, true); - npc->appearanceData.iAngle = (plr->angle + 180) % 360; - NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, plr->x, plr->y, plr->z, npc->instanceID, npc->appearanceData.iAngle); + npc->angle = (plr->angle + 180) % 360; + NPCManager::updateNPCPosition(npc->id, plr->x, plr->y, plr->z, npc->instanceID, npc->angle); } Chat::sendServerMessage(sock, "/summonW: placed mob with type: " + std::to_string(type) + - ", id: " + std::to_string(npc->appearanceData.iNPC_ID)); - TableData::RunningMobs[npc->appearanceData.iNPC_ID] = npc; // only record the one in the template + ", id: " + std::to_string(npc->id)); + TableData::RunningMobs[npc->id] = npc; // only record the one in the template } static void unsummonWCommand(std::string full, std::vector& args, CNSocket* sock) { @@ -269,21 +269,21 @@ static void unsummonWCommand(std::string full, std::vector& args, C return; } - if (TableData::RunningEggs.find(npc->appearanceData.iNPC_ID) != TableData::RunningEggs.end()) { - Chat::sendServerMessage(sock, "/unsummonW: removed egg with type: " + std::to_string(npc->appearanceData.iNPCType) + - ", id: " + std::to_string(npc->appearanceData.iNPC_ID)); - TableData::RunningEggs.erase(npc->appearanceData.iNPC_ID); - NPCManager::destroyNPC(npc->appearanceData.iNPC_ID); + if (TableData::RunningEggs.find(npc->id) != TableData::RunningEggs.end()) { + Chat::sendServerMessage(sock, "/unsummonW: removed egg with type: " + std::to_string(npc->type) + + ", id: " + std::to_string(npc->id)); + TableData::RunningEggs.erase(npc->id); + NPCManager::destroyNPC(npc->id); return; } - if (TableData::RunningMobs.find(npc->appearanceData.iNPC_ID) == TableData::RunningMobs.end() - && TableData::RunningGroups.find(npc->appearanceData.iNPC_ID) == TableData::RunningGroups.end()) { + if (TableData::RunningMobs.find(npc->id) == TableData::RunningMobs.end() + && TableData::RunningGroups.find(npc->id) == TableData::RunningGroups.end()) { Chat::sendServerMessage(sock, "/unsummonW: Closest NPC is not a gruntwork mob."); return; } - if (NPCManager::NPCs.find(npc->appearanceData.iNPC_ID) != NPCManager::NPCs.end() && NPCManager::NPCs[npc->appearanceData.iNPC_ID]->kind == EntityType::MOB) { + if (NPCManager::NPCs.find(npc->id) != NPCManager::NPCs.end() && NPCManager::NPCs[npc->id]->kind == EntityType::MOB) { int leadId = ((Mob*)npc)->groupLeader; if (leadId != 0) { if (NPCManager::NPCs.find(leadId) == NPCManager::NPCs.end() || NPCManager::NPCs[leadId]->kind != EntityType::MOB) { @@ -308,12 +308,12 @@ static void unsummonWCommand(std::string full, std::vector& args, C } } - Chat::sendServerMessage(sock, "/unsummonW: removed mob with type: " + std::to_string(npc->appearanceData.iNPCType) + - ", id: " + std::to_string(npc->appearanceData.iNPC_ID)); + Chat::sendServerMessage(sock, "/unsummonW: removed mob with type: " + std::to_string(npc->type) + + ", id: " + std::to_string(npc->id)); - TableData::RunningMobs.erase(npc->appearanceData.iNPC_ID); + TableData::RunningMobs.erase(npc->id); - NPCManager::destroyNPC(npc->appearanceData.iNPC_ID); + NPCManager::destroyNPC(npc->id); } static void toggleAiCommand(std::string full, std::vector& args, CNSocket* sock) { @@ -356,24 +356,24 @@ static void npcRotateCommand(std::string full, std::vector& args, C } int angle = (plr->angle + 180) % 360; - NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, npc->x, npc->y, npc->z, npc->instanceID, angle); + NPCManager::updateNPCPosition(npc->id, npc->x, npc->y, npc->z, npc->instanceID, angle); // if it's a gruntwork NPC, rotate in-place - if (TableData::RunningMobs.find(npc->appearanceData.iNPC_ID) != TableData::RunningMobs.end()) { - NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, npc->x, npc->y, npc->z, npc->instanceID, angle); + if (TableData::RunningMobs.find(npc->id) != TableData::RunningMobs.end()) { + NPCManager::updateNPCPosition(npc->id, npc->x, npc->y, npc->z, npc->instanceID, angle); Chat::sendServerMessage(sock, "[NPCR] Successfully set angle to " + std::to_string(angle) + " for gruntwork NPC " - + std::to_string(npc->appearanceData.iNPC_ID)); + + std::to_string(npc->id)); } else { - TableData::RunningNPCRotations[npc->appearanceData.iNPC_ID] = angle; + TableData::RunningNPCRotations[npc->id] = angle; Chat::sendServerMessage(sock, "[NPCR] Successfully set angle to " + std::to_string(angle) + " for NPC " - + std::to_string(npc->appearanceData.iNPC_ID)); + + std::to_string(npc->id)); } // update rotation clientside INITSTRUCT(sP_FE2CL_NPC_ENTER, pkt); - pkt.NPCAppearanceData = npc->appearanceData; + pkt.NPCAppearanceData = npc->getAppearanceData(); sock->sendPacket(pkt, P_FE2CL_NPC_ENTER); } @@ -443,9 +443,9 @@ static void npcInstanceCommand(std::string full, std::vector& args, return; } - Chat::sendServerMessage(sock, "[NPCI] Moving NPC with ID " + std::to_string(npc->appearanceData.iNPC_ID) + " to instance " + std::to_string(instance)); - TableData::RunningNPCMapNumbers[npc->appearanceData.iNPC_ID] = instance; - NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, npc->x, npc->y, npc->z, instance, npc->appearanceData.iAngle); + Chat::sendServerMessage(sock, "[NPCI] Moving NPC with ID " + std::to_string(npc->id) + " to instance " + std::to_string(instance)); + TableData::RunningNPCMapNumbers[npc->id] = instance; + NPCManager::updateNPCPosition(npc->id, npc->x, npc->y, npc->z, instance, npc->angle); } static void minfoCommand(std::string full, std::vector& args, CNSocket* sock) { @@ -610,39 +610,39 @@ static void summonGroupCommand(std::string full, std::vector& args, BaseNPC *npc = NPCManager::summonNPC(x, y, z, plr->instanceID, type, wCommand); if (team == 2 && i > 0 && npc->kind == EntityType::MOB) { - leadNpc->groupMember[i-1] = npc->appearanceData.iNPC_ID; - Mob* mob = (Mob*)NPCManager::NPCs[npc->appearanceData.iNPC_ID]; - mob->groupLeader = leadNpc->appearanceData.iNPC_ID; + leadNpc->groupMember[i-1] = npc->id; + Mob* mob = (Mob*)NPCManager::NPCs[npc->id]; + mob->groupLeader = leadNpc->id; mob->offsetX = x - plr->x; mob->offsetY = y - plr->y; } - npc->appearanceData.iAngle = (plr->angle + 180) % 360; - NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, x, y, z, plr->instanceID, npc->appearanceData.iAngle); + npc->angle = (plr->angle + 180) % 360; + NPCManager::updateNPCPosition(npc->id, x, y, z, plr->instanceID, npc->angle); // if we're in a lair, we need to spawn the NPC in both the private instance and the template if (PLAYERID(plr->instanceID) != 0) { npc = NPCManager::summonNPC(plr->x, plr->y, plr->z, plr->instanceID, type, wCommand, true); if (team == 2 && i > 0 && npc->kind == EntityType::MOB) { - leadNpc->groupMember[i-1] = npc->appearanceData.iNPC_ID; - Mob* mob = (Mob*)NPCManager::NPCs[npc->appearanceData.iNPC_ID]; - mob->groupLeader = leadNpc->appearanceData.iNPC_ID; + leadNpc->groupMember[i-1] = npc->id; + Mob* mob = (Mob*)NPCManager::NPCs[npc->id]; + mob->groupLeader = leadNpc->id; mob->offsetX = x - plr->x; mob->offsetY = y - plr->y; } - npc->appearanceData.iAngle = (plr->angle + 180) % 360; - NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, x, y, z, plr->instanceID, npc->appearanceData.iAngle); + npc->angle = (plr->angle + 180) % 360; + NPCManager::updateNPCPosition(npc->id, x, y, z, plr->instanceID, npc->angle); } Chat::sendServerMessage(sock, "/summonGroup(W): placed mob with type: " + std::to_string(type) + - ", id: " + std::to_string(npc->appearanceData.iNPC_ID)); + ", id: " + std::to_string(npc->id)); if (i == 0 && team == 2 && npc->kind == EntityType::MOB) { type = type2; - leadNpc = (Mob*)NPCManager::NPCs[npc->appearanceData.iNPC_ID]; - leadNpc->groupLeader = leadNpc->appearanceData.iNPC_ID; + leadNpc = (Mob*)NPCManager::NPCs[npc->id]; + leadNpc->groupLeader = leadNpc->id; } } @@ -654,7 +654,7 @@ static void summonGroupCommand(std::string full, std::vector& args, return; } - TableData::RunningGroups[leadNpc->appearanceData.iNPC_ID] = leadNpc; // only record the leader + TableData::RunningGroups[leadNpc->id] = leadNpc; // only record the leader } static void flushCommand(std::string full, std::vector& args, CNSocket* sock) { @@ -671,15 +671,15 @@ static void whoisCommand(std::string full, std::vector& args, CNSoc return; } - Chat::sendServerMessage(sock, "[WHOIS] ID: " + std::to_string(npc->appearanceData.iNPC_ID)); - Chat::sendServerMessage(sock, "[WHOIS] Type: " + std::to_string(npc->appearanceData.iNPCType)); - Chat::sendServerMessage(sock, "[WHOIS] HP: " + std::to_string(npc->appearanceData.iHP)); - Chat::sendServerMessage(sock, "[WHOIS] CBF: " + std::to_string(npc->appearanceData.iConditionBitFlag)); + Chat::sendServerMessage(sock, "[WHOIS] ID: " + std::to_string(npc->id)); + Chat::sendServerMessage(sock, "[WHOIS] Type: " + std::to_string(npc->type)); + Chat::sendServerMessage(sock, "[WHOIS] HP: " + std::to_string(npc->hp)); + Chat::sendServerMessage(sock, "[WHOIS] CBF: " + std::to_string(npc->cbf)); Chat::sendServerMessage(sock, "[WHOIS] EntityType: " + std::to_string((int)npc->kind)); Chat::sendServerMessage(sock, "[WHOIS] X: " + std::to_string(npc->x)); Chat::sendServerMessage(sock, "[WHOIS] Y: " + std::to_string(npc->y)); Chat::sendServerMessage(sock, "[WHOIS] Z: " + std::to_string(npc->z)); - Chat::sendServerMessage(sock, "[WHOIS] Angle: " + std::to_string(npc->appearanceData.iAngle)); + Chat::sendServerMessage(sock, "[WHOIS] Angle: " + std::to_string(npc->angle)); std::string chunkPosition = std::to_string(std::get<0>(npc->chunkPos)) + ", " + std::to_string(std::get<1>(npc->chunkPos)) + ", " + std::to_string(std::get<2>(npc->chunkPos)); Chat::sendServerMessage(sock, "[WHOIS] Chunk: {" + chunkPosition + "}"); Chat::sendServerMessage(sock, "[WHOIS] MapNum: " + std::to_string(MAPNUM(npc->instanceID))); @@ -705,7 +705,7 @@ static void lairUnlockCommand(std::string full, std::vector& args, continue; for (auto it = NPCManager::Warps.begin(); it != NPCManager::Warps.end(); it++) { - if (it->second.npcID == npc->appearanceData.iNPCType) { + if (it->second.npcID == npc->type) { taskID = it->second.limitTaskID; missionID = Missions::Tasks[taskID]->task["m_iHMissionID"]; lastDist = dist; @@ -981,7 +981,7 @@ static void pathCommand(std::string full, std::vector& args, CNSock pathPoints.push_back(marker); // map from player TableData::RunningNPCPaths[plr->iID] = std::make_pair(npc, pathPoints); - Chat::sendServerMessage(sock, "[PATH] NPC " + std::to_string(npc->appearanceData.iNPC_ID) + " is now following you"); + Chat::sendServerMessage(sock, "[PATH] NPC " + std::to_string(npc->id) + " is now following you"); updatePathMarkers(sock); return; } @@ -1008,8 +1008,8 @@ static void pathCommand(std::string full, std::vector& args, CNSock // /path here if (args[1] == "here") { // bring the NPC to where the player is standing - Transport::NPCQueues.erase(npc->appearanceData.iNPC_ID); // delete transport queue - NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, plr->x, plr->y, plr->z, npc->instanceID, 0); + Transport::NPCQueues.erase(npc->id); // delete transport queue + NPCManager::updateNPCPosition(npc->id, plr->x, plr->y, plr->z, npc->instanceID, 0); npc->disappearFromViewOf(sock); npc->enterIntoViewOf(sock); Chat::sendServerMessage(sock, "[PATH] Come here"); @@ -1047,9 +1047,9 @@ static void pathCommand(std::string full, std::vector& args, CNSock speed = speedArg; } // return NPC to home - Transport::NPCQueues.erase(npc->appearanceData.iNPC_ID); // delete transport queue + Transport::NPCQueues.erase(npc->id); // delete transport queue BaseNPC* home = entry->second[0]; - NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, home->x, home->y, home->z, npc->instanceID, 0); + NPCManager::updateNPCPosition(npc->id, home->x, home->y, home->z, npc->instanceID, 0); npc->disappearFromViewOf(sock); npc->enterIntoViewOf(sock); @@ -1065,7 +1065,7 @@ static void pathCommand(std::string full, std::vector& args, CNSock Transport::lerp(&keyframes, from, to, speed); // lerp from A to B from = to; // update point A } - Transport::NPCQueues[npc->appearanceData.iNPC_ID] = keyframes; + Transport::NPCQueues[npc->id] = keyframes; entry->second.pop_back(); // remove temp end point Chat::sendServerMessage(sock, "[PATH] Testing NPC path"); @@ -1075,9 +1075,9 @@ static void pathCommand(std::string full, std::vector& args, CNSock // /path cancel if (args[1] == "cancel") { // return NPC to home - Transport::NPCQueues.erase(npc->appearanceData.iNPC_ID); // delete transport queue + Transport::NPCQueues.erase(npc->id); // delete transport queue BaseNPC* home = entry->second[0]; - NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, home->x, home->y, home->z, npc->instanceID, 0); + NPCManager::updateNPCPosition(npc->id, home->x, home->y, home->z, npc->instanceID, 0); npc->disappearFromViewOf(sock); npc->enterIntoViewOf(sock); // deallocate markers @@ -1087,7 +1087,7 @@ static void pathCommand(std::string full, std::vector& args, CNSock } // unmap TableData::RunningNPCPaths.erase(plr->iID); - Chat::sendServerMessage(sock, "[PATH] NPC " + std::to_string(npc->appearanceData.iNPC_ID) + " is no longer following you"); + Chat::sendServerMessage(sock, "[PATH] NPC " + std::to_string(npc->id) + " is no longer following you"); return; } @@ -1115,9 +1115,9 @@ static void pathCommand(std::string full, std::vector& args, CNSock } // return NPC to home and set path to repeat - Transport::NPCQueues.erase(npc->appearanceData.iNPC_ID); // delete transport queue + Transport::NPCQueues.erase(npc->id); // delete transport queue BaseNPC* home = entry->second[0]; - NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, home->x, home->y, home->z, npc->instanceID, 0); + NPCManager::updateNPCPosition(npc->id, home->x, home->y, home->z, npc->instanceID, 0); npc->disappearFromViewOf(sock); npc->enterIntoViewOf(sock); npc->loopingPath = true; @@ -1134,7 +1134,7 @@ static void pathCommand(std::string full, std::vector& args, CNSock Transport::lerp(&keyframes, from, to, speed); // lerp from A to B from = to; // update point A } - Transport::NPCQueues[npc->appearanceData.iNPC_ID] = keyframes; + Transport::NPCQueues[npc->id] = keyframes; entry->second.pop_back(); // remove temp end point // save to gruntwork @@ -1161,7 +1161,7 @@ static void pathCommand(std::string full, std::vector& args, CNSock finishedPath.isLoop = true; finishedPath.speed = speed; finishedPath.points = finalPoints; - finishedPath.targetIDs.push_back(npc->appearanceData.iNPC_ID); + finishedPath.targetIDs.push_back(npc->id); TableData::FinishedNPCPaths.push_back(finishedPath); @@ -1173,7 +1173,7 @@ static void pathCommand(std::string full, std::vector& args, CNSock // unmap TableData::RunningNPCPaths.erase(plr->iID); - Chat::sendServerMessage(sock, "[PATH] NPC " + std::to_string(npc->appearanceData.iNPC_ID) + " is no longer following you"); + Chat::sendServerMessage(sock, "[PATH] NPC " + std::to_string(npc->id) + " is no longer following you"); TableData::flush(); Chat::sendServerMessage(sock, "[PATH] Path saved to gruntwork"); diff --git a/src/Eggs.cpp b/src/Eggs.cpp index 52fa35e..f29d5cc 100644 --- a/src/Eggs.cpp +++ b/src/Eggs.cpp @@ -135,7 +135,7 @@ static void eggStep(CNServer* serv, time_t currTime) { // respawn it egg->dead = false; egg->deadUntil = 0; - egg->appearanceData.iHP = 400; + egg->hp = 400; Chunking::addEntityToChunks(Chunking::getViewableChunks(egg->chunkPos), {npc.first}); } @@ -180,7 +180,7 @@ static void eggPickup(CNSocket* sock, CNPacketData* data) { } */ - int typeId = egg->appearanceData.iNPCType; + int typeId = egg->type; if (EggTypes.find(typeId) == EggTypes.end()) { std::cout << "[WARN] Egg Type " << typeId << " not found!" << std::endl; return; @@ -255,7 +255,7 @@ static void eggPickup(CNSocket* sock, CNPacketData* data) { Chunking::removeEntityFromChunks(Chunking::getViewableChunks(egg->chunkPos), eggRef); egg->dead = true; egg->deadUntil = getTime() + (time_t)type->regen * 1000; - egg->appearanceData.iHP = 0; + egg->hp = 0; } } diff --git a/src/Entities.cpp b/src/Entities.cpp index ea52eba..a859af2 100644 --- a/src/Entities.cpp +++ b/src/Entities.cpp @@ -39,15 +39,26 @@ Entity *EntityRef::getEntity() const { return NPCManager::NPCs[id]; } +sNPCAppearanceData BaseNPC::getAppearanceData() { + sNPCAppearanceData data = {}; + data.iAngle = angle; + data.iBarkerType = barkerType; + data.iConditionBitFlag = cbf; + data.iHP = hp; + data.iNPCType = type; + data.iNPC_ID = id; + data.iX = x; + data.iY = y; + data.iZ = z; + return data; +} + /* * Entity coming into view. */ void BaseNPC::enterIntoViewOf(CNSocket *sock) { INITSTRUCT(sP_FE2CL_NPC_ENTER, pkt); - pkt.NPCAppearanceData = appearanceData; - pkt.NPCAppearanceData.iX = x; - pkt.NPCAppearanceData.iY = y; - pkt.NPCAppearanceData.iZ = z; + pkt.NPCAppearanceData = getAppearanceData(); sock->sendPacket(pkt, P_FE2CL_NPC_ENTER); } @@ -56,7 +67,7 @@ void Bus::enterIntoViewOf(CNSocket *sock) { // TODO: Potentially decouple this from BaseNPC? pkt.AppearanceData = { - 3, appearanceData.iNPC_ID, appearanceData.iNPCType, + 3, id, type, x, y, z }; @@ -66,28 +77,36 @@ void Bus::enterIntoViewOf(CNSocket *sock) { void Egg::enterIntoViewOf(CNSocket *sock) { INITSTRUCT(sP_FE2CL_SHINY_ENTER, pkt); - Eggs::npcDataToEggData(x, y, z, &appearanceData, &pkt.ShinyAppearanceData); + // TODO: Potentially decouple this from BaseNPC? + pkt.ShinyAppearanceData = { + id, type, 0, // client doesn't care about map num + x, y, z + }; sock->sendPacket(pkt, P_FE2CL_SHINY_ENTER); } - + +sPCAppearanceData Player::getAppearanceData() { + sPCAppearanceData data = {}; + data.iID = iID; + data.iHP = HP; + data.iLv = level; + data.iX = x; + data.iY = y; + data.iZ = z; + data.iAngle = angle; + data.PCStyle = PCStyle; + data.Nano = Nanos[activeNano]; + data.iPCState = iPCState; + data.iSpecialState = iSpecialState; + memcpy(data.ItemEquip, Equip, sizeof(sItemBase) * AEQUIP_COUNT); + return data; +} + // TODO: this is less effiecient than it was, because of memset() void Player::enterIntoViewOf(CNSocket *sock) { INITSTRUCT(sP_FE2CL_PC_NEW, pkt); - - pkt.PCAppearanceData.iID = iID; - pkt.PCAppearanceData.iHP = HP; - pkt.PCAppearanceData.iLv = level; - pkt.PCAppearanceData.iX = x; - pkt.PCAppearanceData.iY = y; - pkt.PCAppearanceData.iZ = z; - pkt.PCAppearanceData.iAngle = angle; - pkt.PCAppearanceData.PCStyle = PCStyle; - pkt.PCAppearanceData.Nano = Nanos[activeNano]; - pkt.PCAppearanceData.iPCState = iPCState; - pkt.PCAppearanceData.iSpecialState = iSpecialState; - memcpy(pkt.PCAppearanceData.ItemEquip, Equip, sizeof(sItemBase) * AEQUIP_COUNT); - + pkt.PCAppearanceData = getAppearanceData(); sock->sendPacket(pkt, P_FE2CL_PC_NEW); } @@ -96,20 +115,20 @@ void Player::enterIntoViewOf(CNSocket *sock) { */ void BaseNPC::disappearFromViewOf(CNSocket *sock) { INITSTRUCT(sP_FE2CL_NPC_EXIT, pkt); - pkt.iNPC_ID = appearanceData.iNPC_ID; + pkt.iNPC_ID = id; sock->sendPacket(pkt, P_FE2CL_NPC_EXIT); } void Bus::disappearFromViewOf(CNSocket *sock) { INITSTRUCT(sP_FE2CL_TRANSPORTATION_EXIT, pkt); pkt.eTT = 3; - pkt.iT_ID = appearanceData.iNPC_ID; + pkt.iT_ID = id; sock->sendPacket(pkt, P_FE2CL_TRANSPORTATION_EXIT); } void Egg::disappearFromViewOf(CNSocket *sock) { INITSTRUCT(sP_FE2CL_SHINY_EXIT, pkt); - pkt.iShinyID = appearanceData.iNPC_ID; + pkt.iShinyID = id; sock->sendPacket(pkt, P_FE2CL_SHINY_EXIT); } diff --git a/src/Entities.hpp b/src/Entities.hpp index a231541..9e56ea0 100644 --- a/src/Entities.hpp +++ b/src/Entities.hpp @@ -74,25 +74,31 @@ struct EntityRef { */ class BaseNPC : public Entity { public: - sNPCAppearanceData appearanceData = {}; + int id; + int type; + int hp; + int angle; + int cbf; + int barkerType; bool loopingPath = false; - BaseNPC(int _X, int _Y, int _Z, int angle, uint64_t iID, int t, int id) { // XXX + BaseNPC(int _X, int _Y, int _Z, int _A, uint64_t iID, int t, int _id) { // XXX x = _X; y = _Y; z = _Z; - appearanceData.iNPCType = t; - appearanceData.iHP = 400; - appearanceData.iAngle = angle; - appearanceData.iConditionBitFlag = 0; - appearanceData.iBarkerType = 0; - appearanceData.iNPC_ID = id; - + type = t; + hp = 400; + angle = _A; + cbf = 0; + barkerType = 0; + id = _id; instanceID = iID; }; virtual void enterIntoViewOf(CNSocket *sock) override; virtual void disappearFromViewOf(CNSocket *sock) override; + + sNPCAppearanceData getAppearanceData(); }; struct CombatNPC : public BaseNPC { @@ -115,7 +121,7 @@ struct CombatNPC : public BaseNPC { _stepAI(this, currTime); } - virtual bool isAlive() override { return appearanceData.iHP > 0; } + virtual bool isAlive() override { return hp > 0; } }; // Mob is in MobAI.hpp, Player is in Player.hpp diff --git a/src/Items.cpp b/src/Items.cpp index 9328c66..166526b 100644 --- a/src/Items.cpp +++ b/src/Items.cpp @@ -822,12 +822,12 @@ static void giveSingleDrop(CNSocket *sock, Mob* mob, int mobDropId, const DropRo void Items::giveMobDrop(CNSocket *sock, Mob* mob, const DropRoll& rolled, const DropRoll& eventRolled) { // sanity check - if (Items::MobToDropMap.find(mob->appearanceData.iNPCType) == Items::MobToDropMap.end()) { - std::cout << "[WARN] Mob ID " << mob->appearanceData.iNPCType << " has no drops assigned" << std::endl; + if (Items::MobToDropMap.find(mob->type) == Items::MobToDropMap.end()) { + std::cout << "[WARN] Mob ID " << mob->type << " has no drops assigned" << std::endl; return; } // find mob drop id - int mobDropId = Items::MobToDropMap[mob->appearanceData.iNPCType]; + int mobDropId = Items::MobToDropMap[mob->type]; giveSingleDrop(sock, mob, mobDropId, rolled); diff --git a/src/Missions.cpp b/src/Missions.cpp index 9d2dd69..bd6891e 100644 --- a/src/Missions.cpp +++ b/src/Missions.cpp @@ -373,9 +373,9 @@ static void taskStart(CNSocket* sock, CNPacketData* data) { for (EntityRef ref : chunk->entities) { if (ref.type != EntityType::PLAYER) { BaseNPC* npc = (BaseNPC*)ref.getEntity(); - NPCPath* path = Transport::findApplicablePath(npc->appearanceData.iNPC_ID, npc->appearanceData.iNPCType, missionData->iTaskNum); + NPCPath* path = Transport::findApplicablePath(npc->id, npc->type, missionData->iTaskNum); if (path != nullptr) { - Transport::constructPathNPC(npc->appearanceData.iNPC_ID, path); + Transport::constructPathNPC(npc->id, path); return; } } diff --git a/src/MobAI.cpp b/src/MobAI.cpp index 562ccce..e396499 100644 --- a/src/MobAI.cpp +++ b/src/MobAI.cpp @@ -47,13 +47,13 @@ static std::pair lerp(int x1, int y1, int x2, int y2, int speed) { void MobAI::clearDebuff(Mob *mob) { mob->skillStyle = -1; - mob->appearanceData.iConditionBitFlag = 0; + mob->cbf = 0; mob->unbuffTimes.clear(); INITSTRUCT(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT, pkt1); pkt1.eCT = 2; - pkt1.iID = mob->appearanceData.iNPC_ID; - pkt1.iConditionBitFlag = mob->appearanceData.iConditionBitFlag; + pkt1.iID = mob->id; + pkt1.iConditionBitFlag = mob->cbf; NPCManager::sendToViewable(mob, &pkt1, P_FE2CL_CHAR_TIME_BUFF_TIME_OUT, sizeof(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT)); } @@ -196,7 +196,7 @@ static void dealCorruption(Mob *mob, std::vector targetData, int skillID, i sP_FE2CL_NPC_SKILL_CORRUPTION_HIT *resp = (sP_FE2CL_NPC_SKILL_CORRUPTION_HIT*)respbuf; sCAttackResult *respdata = (sCAttackResult*)(respbuf+sizeof(sP_FE2CL_NPC_SKILL_CORRUPTION_HIT)); - resp->iNPC_ID = mob->appearanceData.iNPC_ID; + resp->iNPC_ID = mob->id; resp->iSkillID = skillID; resp->iStyle = style; resp->iValue1 = plr->x; @@ -247,7 +247,7 @@ static void dealCorruption(Mob *mob, std::vector targetData, int skillID, i if (plr->Nanos[plr->activeNano].iStamina > 150) respdata[i].iNanoStamina = plr->Nanos[plr->activeNano].iStamina = 150; // fire damage power disguised as a corruption attack back at the enemy - std::vector targetData2 = {1, mob->appearanceData.iNPC_ID, 0, 0, 0}; + std::vector targetData2 = {1, mob->id, 0, 0, 0}; for (auto& pwr : Abilities::Powers) if (pwr.skillType == EST_DAMAGE) pwr.handle(sock, targetData2, plr->activeNano, skillID, 0, 200); @@ -362,7 +362,7 @@ static void useAbilities(Mob *mob, time_t currTime) { if (random < prob1 + prob2) { // corruption windup int skillID = (int)mob->data["m_iCorruptionType"]; INITSTRUCT(sP_FE2CL_NPC_SKILL_CORRUPTION_READY, pkt); - pkt.iNPC_ID = mob->appearanceData.iNPC_ID; + pkt.iNPC_ID = mob->id; pkt.iSkillID = skillID; pkt.iValue1 = plr->x; pkt.iValue2 = plr->y; @@ -381,7 +381,7 @@ static void useAbilities(Mob *mob, time_t currTime) { if (random < prob1 + prob2 + prob3) { // eruption windup int skillID = (int)mob->data["m_iMegaType"]; INITSTRUCT(sP_FE2CL_NPC_SKILL_READY, pkt); - pkt.iNPC_ID = mob->appearanceData.iNPC_ID; + pkt.iNPC_ID = mob->id; pkt.iSkillID = skillID; pkt.iValue1 = mob->hitX = plr->x; pkt.iValue2 = mob->hitY = plr->y; @@ -406,13 +406,13 @@ void MobAI::enterCombat(CNSocket *sock, Mob *mob) { mob->roamZ = mob->z; int skillID = (int)mob->data["m_iPassiveBuff"]; // cast passive - std::vector targetData = {1, mob->appearanceData.iNPC_ID, 0, 0, 0}; + std::vector targetData = {1, mob->id, 0, 0, 0}; for (auto& pwr : Abilities::Powers) if (pwr.skillType == Abilities::SkillTable[skillID].skillType) pwr.handle(mob, targetData, skillID, Abilities::SkillTable[skillID].durationTime[0], Abilities::SkillTable[skillID].powerIntensity[0]); for (NPCEvent& event : NPCManager::NPCEvents) // trigger an ON_COMBAT - if (event.trigger == ON_COMBAT && event.npcType == mob->appearanceData.iNPCType) + if (event.trigger == ON_COMBAT && event.npcType == mob->type) event.handler(sock, mob); } @@ -426,18 +426,18 @@ static void drainMobHP(Mob *mob, int amount) { sP_FE2CL_CHAR_TIME_BUFF_TIME_TICK *pkt = (sP_FE2CL_CHAR_TIME_BUFF_TIME_TICK*)respbuf; sSkillResult_Damage *drain = (sSkillResult_Damage*)(respbuf + sizeof(sP_FE2CL_CHAR_TIME_BUFF_TIME_TICK)); - pkt->iID = mob->appearanceData.iNPC_ID; + pkt->iID = mob->id; pkt->eCT = 4; // mob pkt->iTB_ID = ECSB_BOUNDINGBALL; drain->eCT = 4; - drain->iID = mob->appearanceData.iNPC_ID; + drain->iID = mob->id; drain->iDamage = amount; - drain->iHP = mob->appearanceData.iHP -= amount; + drain->iHP = mob->hp -= amount; NPCManager::sendToViewable(mob, (void*)&respbuf, P_FE2CL_CHAR_TIME_BUFF_TIME_TICK, resplen); - if (mob->appearanceData.iHP <= 0) + if (mob->hp <= 0) Combat::killMob(mob->target, mob); } @@ -448,14 +448,14 @@ static void deadStep(Mob *mob, time_t currTime) { INITSTRUCT(sP_FE2CL_NPC_EXIT, pkt); - pkt.iNPC_ID = mob->appearanceData.iNPC_ID; + pkt.iNPC_ID = mob->id; NPCManager::sendToViewable(mob, &pkt, P_FE2CL_NPC_EXIT, sizeof(sP_FE2CL_NPC_EXIT)); // if it was summoned, mark it for removal if (mob->summoned) { std::cout << "[INFO] Queueing killed summoned mob for removal" << std::endl; - NPCManager::queueNPCRemoval(mob->appearanceData.iNPC_ID); + NPCManager::queueNPCRemoval(mob->id); return; } @@ -466,15 +466,15 @@ static void deadStep(Mob *mob, time_t currTime) { } // to guide their groupmates, group leaders still need to move despite being dead - if (mob->groupLeader == mob->appearanceData.iNPC_ID) + if (mob->groupLeader == mob->id) roamingStep(mob, currTime); if (mob->killedTime != 0 && currTime - mob->killedTime < mob->regenTime * 100) return; - std::cout << "respawning mob " << mob->appearanceData.iNPC_ID << " with HP = " << mob->maxHealth << std::endl; + std::cout << "respawning mob " << mob->id << " with HP = " << mob->maxHealth << std::endl; - mob->appearanceData.iHP = mob->maxHealth; + mob->hp = mob->maxHealth; mob->state = MobState::ROAMING; // if mob is a group leader/follower, spawn where the group is. @@ -491,10 +491,7 @@ static void deadStep(Mob *mob, time_t currTime) { INITSTRUCT(sP_FE2CL_NPC_NEW, pkt); - pkt.NPCAppearanceData = mob->appearanceData; - pkt.NPCAppearanceData.iX = mob->x; - pkt.NPCAppearanceData.iY = mob->y; - pkt.NPCAppearanceData.iZ = mob->z; + pkt.NPCAppearanceData = mob->getAppearanceData(); // notify all nearby players NPCManager::sendToViewable(mob, &pkt, P_FE2CL_NPC_NEW, sizeof(sP_FE2CL_NPC_NEW)); @@ -532,13 +529,13 @@ static void combatStep(Mob *mob, time_t currTime) { // drain if (mob->skillStyle < 0 && (mob->lastDrainTime == 0 || currTime - mob->lastDrainTime >= 1000) - && mob->appearanceData.iConditionBitFlag & CSB_BIT_BOUNDINGBALL) { + && mob->cbf & CSB_BIT_BOUNDINGBALL) { drainMobHP(mob, mob->maxHealth / 20); // lose 5% every second mob->lastDrainTime = currTime; } // if drain killed the mob, return early - if (mob->appearanceData.iHP <= 0) + if (mob->hp <= 0) return; // unbuffing @@ -546,12 +543,12 @@ static void combatStep(Mob *mob, time_t currTime) { while (it != mob->unbuffTimes.end()) { if (currTime >= it->second) { - mob->appearanceData.iConditionBitFlag &= ~it->first; + mob->cbf &= ~it->first; INITSTRUCT(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT, pkt1); pkt1.eCT = 2; - pkt1.iID = mob->appearanceData.iNPC_ID; - pkt1.iConditionBitFlag = mob->appearanceData.iConditionBitFlag; + pkt1.iID = mob->id; + pkt1.iConditionBitFlag = mob->cbf; NPCManager::sendToViewable(mob, &pkt1, P_FE2CL_CHAR_TIME_BUFF_TIME_OUT, sizeof(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT)); it = mob->unbuffTimes.erase(it); @@ -561,7 +558,7 @@ static void combatStep(Mob *mob, time_t currTime) { } // skip attack if stunned or asleep - if (mob->appearanceData.iConditionBitFlag & (CSB_BIT_STUN|CSB_BIT_MEZ)) { + if (mob->cbf & (CSB_BIT_STUN|CSB_BIT_MEZ)) { mob->skillStyle = -1; // in this case we also reset the any outlying abilities the mob might be winding up. return; } @@ -587,7 +584,7 @@ static void combatStep(Mob *mob, time_t currTime) { mob->nextAttack = 0; // halve movement speed if snared - if (mob->appearanceData.iConditionBitFlag & CSB_BIT_DN_MOVE_SPEED) + if (mob->cbf & CSB_BIT_DN_MOVE_SPEED) speed /= 2; int targetX = plr->x; @@ -602,11 +599,11 @@ static void combatStep(Mob *mob, time_t currTime) { if (distanceToTravel < speed*2/5 && currTime >= mob->nextAttack) mob->nextAttack = 0; - NPCManager::updateNPCPosition(mob->appearanceData.iNPC_ID, targ.first, targ.second, mob->z, mob->instanceID, mob->appearanceData.iAngle); + NPCManager::updateNPCPosition(mob->id, targ.first, targ.second, mob->z, mob->instanceID, mob->angle); INITSTRUCT(sP_FE2CL_NPC_MOVE, pkt); - pkt.iNPC_ID = mob->appearanceData.iNPC_ID; + pkt.iNPC_ID = mob->id; pkt.iSpeed = speed; pkt.iToX = mob->x = targ.first; pkt.iToY = mob->y = targ.second; @@ -664,7 +661,7 @@ static void roamingStep(Mob *mob, time_t currTime) { if (mob->staticPath) return; - if (mob->groupLeader != 0 && mob->groupLeader != mob->appearanceData.iNPC_ID) // don't roam by yourself without group leader + if (mob->groupLeader != 0 && mob->groupLeader != mob->id) // don't roam by yourself without group leader return; /* @@ -704,7 +701,7 @@ static void roamingStep(Mob *mob, time_t currTime) { farY = std::clamp(farY, yStart, yStart + mob->idleRange); // halve movement speed if snared - if (mob->appearanceData.iConditionBitFlag & CSB_BIT_DN_MOVE_SPEED) + if (mob->cbf & CSB_BIT_DN_MOVE_SPEED) speed /= 2; std::queue queue; @@ -713,9 +710,9 @@ static void roamingStep(Mob *mob, time_t currTime) { // add a route to the queue; to be processed in Transport::stepNPCPathing() Transport::lerp(&queue, from, to, speed); - Transport::NPCQueues[mob->appearanceData.iNPC_ID] = queue; + Transport::NPCQueues[mob->id] = queue; - if (mob->groupLeader != 0 && mob->groupLeader == mob->appearanceData.iNPC_ID) { + if (mob->groupLeader != 0 && mob->groupLeader == mob->id) { // make followers follow this npc. for (int i = 0; i < 4; i++) { if (mob->groupMember[i] == 0) @@ -731,7 +728,7 @@ static void roamingStep(Mob *mob, time_t currTime) { from = { followerMob->x, followerMob->y, followerMob->z }; to = { farX + followerMob->offsetX, farY + followerMob->offsetY, followerMob->z }; Transport::lerp(&queue2, from, to, speed); - Transport::NPCQueues[followerMob->appearanceData.iNPC_ID] = queue2; + Transport::NPCQueues[followerMob->id] = queue2; } } } @@ -751,7 +748,7 @@ static void retreatStep(Mob *mob, time_t currTime) { auto targ = lerp(mob->x, mob->y, mob->roamX, mob->roamY, (int)mob->speed*4/5); - pkt.iNPC_ID = mob->appearanceData.iNPC_ID; + pkt.iNPC_ID = mob->id; pkt.iSpeed = (int)mob->speed * 2; pkt.iToX = mob->x = targ.first; pkt.iToY = mob->y = targ.second; @@ -766,10 +763,10 @@ static void retreatStep(Mob *mob, time_t currTime) { //if (distance <= mob->data["m_iIdleRange"]) { if (distance <= 10) { // retreat back to the spawn point mob->state = MobState::ROAMING; - mob->appearanceData.iHP = mob->maxHealth; + mob->hp = mob->maxHealth; mob->killedTime = 0; mob->nextAttack = 0; - mob->appearanceData.iConditionBitFlag = 0; + mob->cbf = 0; // cast a return home heal spell, this is the right way(tm) std::vector targetData = {1, 0, 0, 0, 0}; diff --git a/src/MobAI.hpp b/src/MobAI.hpp index 452f6c6..dbf9c84 100644 --- a/src/MobAI.hpp +++ b/src/MobAI.hpp @@ -72,10 +72,10 @@ struct Mob : public CombatNPC { offsetX = 0; offsetY = 0; - appearanceData.iConditionBitFlag = 0; + cbf = 0; // NOTE: there appear to be discrepancies in the dump - appearanceData.iHP = maxHealth; + hp = maxHealth; kind = EntityType::MOB; _stepAI = MobAI::step; diff --git a/src/NPCManager.cpp b/src/NPCManager.cpp index eb262d9..50b3a0a 100644 --- a/src/NPCManager.cpp +++ b/src/NPCManager.cpp @@ -67,7 +67,7 @@ void NPCManager::destroyNPC(int32_t id) { void NPCManager::updateNPCPosition(int32_t id, int X, int Y, int Z, uint64_t I, int angle) { BaseNPC* npc = NPCs[id]; - npc->appearanceData.iAngle = angle; + npc->angle = angle; ChunkPos oldChunk = npc->chunkPos; ChunkPos newChunk = Chunking::chunkPosAt(X, Y, I); npc->x = X; @@ -154,7 +154,7 @@ static void npcSummonHandler(CNSocket* sock, CNPacketData* data) { for (int i = 0; i < req->iNPCCnt; i++) { BaseNPC *npc = summonNPC(plr->x, plr->y, plr->z, plr->instanceID, req->iNPCType); - updateNPCPosition(npc->appearanceData.iNPC_ID, plr->x, plr->y, plr->z, plr->instanceID, 0); + updateNPCPosition(npc->id, plr->x, plr->y, plr->z, plr->instanceID, 0); } } @@ -305,16 +305,16 @@ static void lordFuseStageTwo(CNSocket *sock, BaseNPC *npc) { // Blastons, Heal Mob *newbody = (Mob*)NPCManager::summonNPC(oldbody->spawnX, oldbody->spawnY, oldbody->spawnZ, plr->instanceID, 2467); - newbody->appearanceData.iAngle = oldbody->appearanceData.iAngle; - NPCManager::updateNPCPosition(newbody->appearanceData.iNPC_ID, newbody->spawnX, newbody->spawnY, newbody->spawnZ, - plr->instanceID, oldbody->appearanceData.iAngle); + newbody->angle = oldbody->angle; + NPCManager::updateNPCPosition(newbody->id, newbody->spawnX, newbody->spawnY, newbody->spawnZ, + plr->instanceID, oldbody->angle); // right arm, Adaptium, Stun Mob *arm = (Mob*)NPCManager::summonNPC(oldbody->spawnX - 600, oldbody->spawnY, oldbody->spawnZ, plr->instanceID, 2469); - arm->appearanceData.iAngle = oldbody->appearanceData.iAngle; - NPCManager::updateNPCPosition(arm->appearanceData.iNPC_ID, arm->spawnX, arm->spawnY, arm->spawnZ, - plr->instanceID, oldbody->appearanceData.iAngle); + arm->angle = oldbody->angle; + NPCManager::updateNPCPosition(arm->id, arm->spawnX, arm->spawnY, arm->spawnZ, + plr->instanceID, oldbody->angle); } // summon left arm and stage 3 body @@ -327,16 +327,16 @@ static void lordFuseStageThree(CNSocket *sock, BaseNPC *npc) { // Cosmix, Damage Point Mob *newbody = (Mob*)NPCManager::summonNPC(oldbody->spawnX, oldbody->spawnY, oldbody->spawnZ, plr->instanceID, 2468); - newbody->appearanceData.iAngle = oldbody->appearanceData.iAngle; - NPCManager::updateNPCPosition(newbody->appearanceData.iNPC_ID, newbody->spawnX, newbody->spawnY, newbody->spawnZ, - plr->instanceID, oldbody->appearanceData.iAngle); + newbody->angle = oldbody->angle; + NPCManager::updateNPCPosition(newbody->id, newbody->spawnX, newbody->spawnY, newbody->spawnZ, + plr->instanceID, oldbody->angle); // Blastons, Heal Mob *arm = (Mob*)NPCManager::summonNPC(oldbody->spawnX + 600, oldbody->spawnY, oldbody->spawnZ, plr->instanceID, 2470); - arm->appearanceData.iAngle = oldbody->appearanceData.iAngle; - NPCManager::updateNPCPosition(arm->appearanceData.iNPC_ID, arm->spawnX, arm->spawnY, arm->spawnZ, - plr->instanceID, oldbody->appearanceData.iAngle); + arm->angle = oldbody->angle; + NPCManager::updateNPCPosition(arm->id, arm->spawnX, arm->spawnY, arm->spawnZ, + plr->instanceID, oldbody->angle); } std::vector NPCManager::NPCEvents = { diff --git a/src/Player.hpp b/src/Player.hpp index 7821593..0c425d1 100644 --- a/src/Player.hpp +++ b/src/Player.hpp @@ -89,4 +89,6 @@ struct Player : public Entity { virtual void enterIntoViewOf(CNSocket *sock) override; virtual void disappearFromViewOf(CNSocket *sock) override; + + sPCAppearanceData getAppearanceData(); }; diff --git a/src/PlayerMovement.cpp b/src/PlayerMovement.cpp index c19af28..b00f15b 100644 --- a/src/PlayerMovement.cpp +++ b/src/PlayerMovement.cpp @@ -33,7 +33,7 @@ static void movePlayer(CNSocket* sock, CNPacketData* data) { // [gruntwork] check if player has a follower and move it if (TableData::RunningNPCPaths.find(plr->iID) != TableData::RunningNPCPaths.end()) { BaseNPC* follower = TableData::RunningNPCPaths[plr->iID].first; - Transport::NPCQueues.erase(follower->appearanceData.iNPC_ID); // erase existing points + Transport::NPCQueues.erase(follower->id); // erase existing points std::queue queue; Vec3 from = { follower->x, follower->y, follower->z }; float drag = 0.95f; // this ensures that they don't bump into the player @@ -45,7 +45,7 @@ static void movePlayer(CNSocket* sock, CNPacketData* data) { // add a route to the queue; to be processed in Transport::stepNPCPathing() Transport::lerp(&queue, from, to, NPC_DEFAULT_SPEED * 1.5); // little faster than typical - Transport::NPCQueues[follower->appearanceData.iNPC_ID] = queue; + Transport::NPCQueues[follower->id] = queue; } } diff --git a/src/TableData.cpp b/src/TableData.cpp index 892509f..92a4aca 100644 --- a/src/TableData.cpp +++ b/src/TableData.cpp @@ -315,9 +315,9 @@ static void loadPaths(json& pathData, int32_t* nextId) { passedDistance -= SLIDER_GAP_SIZE; // step down // spawn a slider Bus* slider = new Bus(point.x, point.y, point.z, 0, INSTANCE_OVERWORLD, 1, (*nextId)--); - NPCManager::NPCs[slider->appearanceData.iNPC_ID] = slider; - NPCManager::updateNPCPosition(slider->appearanceData.iNPC_ID, slider->x, slider->y, slider->z, INSTANCE_OVERWORLD, 0); - Transport::NPCQueues[slider->appearanceData.iNPC_ID] = route; + NPCManager::NPCs[slider->id] = slider; + NPCManager::updateNPCPosition(slider->id, slider->x, slider->y, slider->z, INSTANCE_OVERWORLD, 0); + Transport::NPCQueues[slider->id] = route; } // rotate route.pop(); @@ -755,7 +755,7 @@ static void loadGruntworkPost(json& gruntwork, int32_t* nextId) { if (NPCManager::NPCs.find(npcID) == NPCManager::NPCs.end()) continue; // NPC not found BaseNPC* npc = NPCManager::NPCs[npcID]; - npc->appearanceData.iAngle = angle; + npc->angle = angle; RunningNPCRotations[npcID] = angle; } @@ -768,8 +768,8 @@ static void loadGruntworkPost(json& gruntwork, int32_t* nextId) { if (NPCManager::NPCs.find(npcID) == NPCManager::NPCs.end()) continue; // NPC not found BaseNPC* npc = NPCManager::NPCs[npcID]; - NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, npc->x, npc->y, - npc->z, instanceID, npc->appearanceData.iAngle); + NPCManager::updateNPCPosition(npc->id, npc->x, npc->y, + npc->z, instanceID, npc->angle); RunningNPCMapNumbers[npcID] = instanceID; } @@ -794,9 +794,9 @@ static void loadGruntworkPost(json& gruntwork, int32_t* nextId) { npc = new BaseNPC(mob["iX"], mob["iY"], mob["iZ"], mob["iAngle"], instanceID, mob["iNPCType"], id); } - NPCManager::NPCs[npc->appearanceData.iNPC_ID] = npc; - RunningMobs[npc->appearanceData.iNPC_ID] = npc; - NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, mob["iX"], mob["iY"], mob["iZ"], instanceID, mob["iAngle"]); + NPCManager::NPCs[npc->id] = npc; + RunningMobs[npc->id] = npc; + NPCManager::updateNPCPosition(npc->id, mob["iX"], mob["iY"], mob["iZ"], instanceID, mob["iAngle"]); } // mob groups @@ -840,7 +840,7 @@ static void loadGruntworkPost(json& gruntwork, int32_t* nextId) { tmpFol->offsetX = follower.find("iOffsetX") == follower.end() ? 0 : (int)follower["iOffsetX"]; tmpFol->offsetY = follower.find("iOffsetY") == follower.end() ? 0 : (int)follower["iOffsetY"]; - tmpFol->groupLeader = tmp->appearanceData.iNPC_ID; + tmpFol->groupLeader = tmp->id; tmp->groupMember[followerCount++] = *nextId; (*nextId)--; @@ -850,7 +850,7 @@ static void loadGruntworkPost(json& gruntwork, int32_t* nextId) { std::cout << "[WARN] Mob group leader with ID " << *nextId << " has too many followers (" << followers.size() << ")\n"; } - RunningGroups[tmp->appearanceData.iNPC_ID] = tmp; // store as running + RunningGroups[tmp->id] = tmp; // store as running } auto eggs = gruntwork["eggs"]; @@ -1003,7 +1003,7 @@ static void loadMobs(json& npcData, int32_t* nextId) { tmpFol->offsetX = follower.find("iOffsetX") == follower.end() ? 0 : (int)follower["iOffsetX"]; tmpFol->offsetY = follower.find("iOffsetY") == follower.end() ? 0 : (int)follower["iOffsetY"]; - tmpFol->groupLeader = tmp->appearanceData.iNPC_ID; + tmpFol->groupLeader = tmp->id; tmp->groupMember[followerCount++] = *nextId; (*nextId)--; @@ -1238,13 +1238,13 @@ void TableData::flush() { } // NOTE: this format deviates slightly from the one in mobs.json - mob["iNPCType"] = (int)npc->appearanceData.iNPCType; + mob["iNPCType"] = (int)npc->type; mob["iX"] = x; mob["iY"] = y; mob["iZ"] = z; mob["iMapNum"] = MAPNUM(npc->instanceID); // this is a bit imperfect, since this is a live angle, not a spawn angle so it'll change often, but eh - mob["iAngle"] = npc->appearanceData.iAngle; + mob["iAngle"] = npc->angle; // it's called mobs, but really it's everything gruntwork["mobs"].push_back(mob); @@ -1264,7 +1264,7 @@ void TableData::flush() { x = m->spawnX; y = m->spawnY; z = m->spawnZ; - if (m->groupLeader != m->appearanceData.iNPC_ID) { // make sure this is a leader + if (m->groupLeader != m->id) { // make sure this is a leader std::cout << "[WARN] Non-leader mob found in running groups; ignoring\n"; continue; } @@ -1285,13 +1285,13 @@ void TableData::flush() { } // NOTE: this format deviates slightly from the one in mobs.json - mob["iNPCType"] = (int)npc->appearanceData.iNPCType; + mob["iNPCType"] = (int)npc->type; mob["iX"] = x; mob["iY"] = y; mob["iZ"] = z; mob["iMapNum"] = MAPNUM(npc->instanceID); // this is a bit imperfect, since this is a live angle, not a spawn angle so it'll change often, but eh - mob["iAngle"] = npc->appearanceData.iAngle; + mob["iAngle"] = npc->angle; // followers while (followers.size() > 0) { @@ -1300,7 +1300,7 @@ void TableData::flush() { // populate JSON entry json fol; - fol["iNPCType"] = follower->appearanceData.iNPCType; + fol["iNPCType"] = follower->type; fol["iOffsetX"] = follower->offsetX; fol["iOffsetY"] = follower->offsetY; @@ -1325,7 +1325,7 @@ void TableData::flush() { int mapnum = MAPNUM(npc->instanceID); if (mapnum != 0) egg["iMapNum"] = mapnum; - egg["iType"] = npc->appearanceData.iNPCType; + egg["iType"] = npc->type; gruntwork["eggs"].push_back(egg); } diff --git a/src/Transport.cpp b/src/Transport.cpp index 7ed5836..36b0de6 100644 --- a/src/Transport.cpp +++ b/src/Transport.cpp @@ -276,7 +276,7 @@ static void stepNPCPathing() { int distanceBetween = hypot(dXY, point.z - npc->z); // total distance // update NPC location to update viewables - NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, point.x, point.y, point.z, npc->instanceID, npc->appearanceData.iAngle); + NPCManager::updateNPCPosition(npc->id, point.x, point.y, point.z, npc->instanceID, npc->angle); // TODO: move walking logic into Entity stack switch (npc->kind) { @@ -284,7 +284,7 @@ static void stepNPCPathing() { INITSTRUCT(sP_FE2CL_TRANSPORTATION_MOVE, busMove); busMove.eTT = 3; - busMove.iT_ID = npc->appearanceData.iNPC_ID; + busMove.iT_ID = npc->id; busMove.iMoveStyle = 0; // ??? busMove.iToX = point.x; busMove.iToY = point.y; @@ -298,7 +298,7 @@ static void stepNPCPathing() { /* fallthrough */ default: INITSTRUCT(sP_FE2CL_NPC_MOVE, move); - move.iNPC_ID = npc->appearanceData.iNPC_ID; + move.iNPC_ID = npc->id; move.iMoveStyle = 0; // ??? move.iToX = point.x; move.iToY = point.y;