diff --git a/src/ChunkManager.cpp b/src/ChunkManager.cpp index f695571..dd689dd 100644 --- a/src/ChunkManager.cpp +++ b/src/ChunkManager.cpp @@ -104,3 +104,15 @@ std::vector ChunkManager::getDeltaChunks(std::vector from, std:: return delta; } + +bool ChunkManager::inPopulatedChunks(int posX, int posY) { + auto chunk = ChunkManager::grabChunk(posX, posY); + auto nearbyChunks = ChunkManager::grabChunks(chunk); + + for (Chunk *c: nearbyChunks) { + if (!c->players.empty()) + return true; + } + + return false; +} diff --git a/src/ChunkManager.hpp b/src/ChunkManager.hpp index 16244c4..3e08ee8 100644 --- a/src/ChunkManager.hpp +++ b/src/ChunkManager.hpp @@ -26,4 +26,5 @@ namespace ChunkManager { std::pair grabChunk(int posX, int posY); std::vector grabChunks(std::pair chunkPos); std::vector getDeltaChunks(std::vector from, std::vector to); + bool inPopulatedChunks(int posX, int posY); } diff --git a/src/MobManager.cpp b/src/MobManager.cpp index 64ce007..82d9696 100644 --- a/src/MobManager.cpp +++ b/src/MobManager.cpp @@ -179,9 +179,47 @@ void MobManager::deadStep(Mob *mob, time_t currTime) { } } +void MobManager::roamingStep(Mob *mob, time_t currTime) { + if (mob->nextMovement != 0 && currTime < mob->nextMovement) + return; + + int delay = (int)mob->data["m_iDelayTime"] * 1000; + mob->nextMovement = currTime + delay/2 + rand() % (delay/2); + + INITSTRUCT(sP_FE2CL_NPC_MOVE, pkt); + int xStart = mob->spawnX - mob->idleRange/2; + int yStart = mob->spawnY - mob->idleRange/2; + + pkt.iNPC_ID = mob->appearanceData.iNPC_ID; + pkt.iSpeed = mob->data["m_iWalkSpeed"]; + pkt.iToX = mob->appearanceData.iX = xStart + rand() % mob->idleRange; + pkt.iToY = mob->appearanceData.iY = yStart + rand() % mob->idleRange; + pkt.iToZ = mob->appearanceData.iZ; + + auto chunk = ChunkManager::grabChunk(mob->appearanceData.iX, mob->appearanceData.iY); + auto chunks = ChunkManager::grabChunks(chunk); + + // notify all nearby players + for (Chunk *chunk : chunks) { + for (CNSocket *s : chunk->players) { + s->sendPacket(&pkt, P_FE2CL_NPC_MOVE, sizeof(sP_FE2CL_NPC_MOVE)); + } + } +} + void MobManager::step(time_t currTime) { for (auto& pair : Mobs) { + int x = pair.second->appearanceData.iX; + int y = pair.second->appearanceData.iY; + + // skip chunks without players + if (!ChunkManager::inPopulatedChunks(x, y)) + continue; + switch (pair.second->state) { + case MobState::ROAMING: + roamingStep(pair.second, currTime); + break; case MobState::DEAD: deadStep(pair.second, currTime); break; diff --git a/src/MobManager.hpp b/src/MobManager.hpp index 1bad7ac..c295847 100644 --- a/src/MobManager.hpp +++ b/src/MobManager.hpp @@ -5,6 +5,8 @@ #include "CNShardServer.hpp" #include "NPC.hpp" +#include "contrib/JSON.hpp" + #include enum class MobState { @@ -22,14 +24,32 @@ struct Mob : public BaseNPC { const int regenTime; bool despawned = false; // for the sake of death animations - Mob(int x, int y, int z, int type, int hp, int angle, int rt) - : BaseNPC(x, y, z, type), maxHealth(hp), regenTime(rt) { + int spawnX; + int spawnY; + int spawnZ; + + const int idleRange; + time_t nextMovement = 0; + + // temporary; until we're sure what's what + nlohmann::json data; + + Mob(int x, int y, int z, int type, int hp, int angle, nlohmann::json d) + : BaseNPC(x, y, z, type), maxHealth(hp), regenTime(d["m_iRegenTime"]), idleRange(d["m_iIdleRange"]), data(d) { state = MobState::ROAMING; + spawnX = appearanceData.iX; + spawnY = appearanceData.iY; + spawnZ = appearanceData.iZ; + // NOTE: there appear to be discrepancies in the dump appearanceData.iHP = maxHealth; } ~Mob() {} + + auto operator[](std::string s) { + return data[s]; + } }; namespace MobManager { @@ -39,6 +59,7 @@ namespace MobManager { void step(time_t); void deadStep(Mob*, time_t); + void roamingStep(Mob*, time_t); void pcAttackNpcs(CNSocket *sock, CNPacketData *data); void combatBegin(CNSocket *sock, CNPacketData *data); diff --git a/src/TableData.cpp b/src/TableData.cpp index 9243eec..fdd2f66 100644 --- a/src/TableData.cpp +++ b/src/TableData.cpp @@ -162,7 +162,7 @@ void TableData::init() { for (nlohmann::json::iterator _npc = npcData.begin(); _npc != npcData.end(); _npc++) { auto npc = _npc.value(); auto td = npcTableData[(int)npc["iNPCType"]]; - Mob *tmp = new Mob(npc["iX"], npc["iY"], npc["iZ"], npc["iNPCType"], npc["iHP"], npc["iAngle"], td["m_iRegenTime"]); + Mob *tmp = new Mob(npc["iX"], npc["iY"], npc["iZ"], npc["iNPCType"], npc["iHP"], npc["iAngle"], td); // Temporary fix, IDs will be pulled from json later tmp->appearanceData.iNPC_ID = i;