diff --git a/src/ChatManager.cpp b/src/ChatManager.cpp index a689ed4..01a53bb 100644 --- a/src/ChatManager.cpp +++ b/src/ChatManager.cpp @@ -203,7 +203,7 @@ void mssCommand(std::string full, std::vector& args, CNSocket* sock void summonWCommand(std::string full, std::vector& args, CNSocket* sock) { if (args.size() < 2) { - ChatManager::sendServerMessage(sock, "/level: no mob type specified"); + ChatManager::sendServerMessage(sock, "/summonW: no mob type specified"); return; } Player* plr = PlayerManager::getPlayer(sock); @@ -225,7 +225,7 @@ void summonWCommand(std::string full, std::vector& args, CNSocket* BaseNPC *npc = nullptr; if (team == 2) { - npc = new Mob(plr->x, plr->y, plr->z + 1000, plr->instanceID, type, NPCManager::NPCData[type], NPCManager::nextId++); + npc = new Mob(plr->x, plr->y, plr->z + 200, plr->instanceID, type, NPCManager::NPCData[type], NPCManager::nextId++); npc->appearanceData.iAngle = (plr->angle + 180) % 360; NPCManager::NPCs[npc->appearanceData.iNPC_ID] = npc; @@ -240,9 +240,22 @@ void summonWCommand(std::string full, std::vector& args, CNSocket* NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, plr->x, plr->y, plr->z); + // if we're in a lair, we need to spawn the mob in both the private instance and the template + if ((plr->instanceID >> 32) != 0) { + npc = new Mob(plr->x, plr->y, plr->z + 200, plr->instanceID & 0xffffffff, type, NPCManager::NPCData[type], NPCManager::nextId++); + npc->appearanceData.iAngle = (plr->angle + 180) % 360; + + NPCManager::NPCs[npc->appearanceData.iNPC_ID] = npc; + MobManager::Mobs[npc->appearanceData.iNPC_ID] = (Mob*)npc; + + ((Mob*)npc)->summoned = false; + + NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, plr->x, plr->y, plr->z); + } + ChatManager::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; + TableData::RunningMobs[npc->appearanceData.iNPC_ID] = npc; // only record the one in the template } void unsummonWCommand(std::string full, std::vector& args, CNSocket* sock) { diff --git a/src/MobManager.cpp b/src/MobManager.cpp index 979f7b4..da4f5cf 100644 --- a/src/MobManager.cpp +++ b/src/MobManager.cpp @@ -8,6 +8,7 @@ #include "TransportManager.hpp" #include +#include #include std::map MobManager::Mobs; @@ -501,7 +502,8 @@ void MobManager::combatStep(Mob *mob, time_t currTime) { } // retreat if the player leaves combat range - distance = hypot(plr->x - mob->roamX, plr->y - mob->roamY); + int xyDistance = hypot(plr->x - mob->roamX, plr->y - mob->roamY); + distance = hypot(xyDistance, plr->z - mob->roamZ); if (distance >= mob->data["m_iCombatRange"]) { mob->target = nullptr; mob->state = MobState::RETREAT; @@ -1034,6 +1036,9 @@ void MobManager::resendMobHP(Mob *mob) { * as the mob, since it might be near a chunk boundary. */ bool MobManager::aggroCheck(Mob *mob, time_t currTime) { + CNSocket *closest = nullptr; + int closestDistance = INT_MAX; + for (Chunk *chunk : mob->currentChunks) { for (CNSocket *s : chunk->players) { Player *plr = s->plr; @@ -1053,22 +1058,28 @@ bool MobManager::aggroCheck(Mob *mob, time_t currTime) { int xyDistance = hypot(mob->appearanceData.iX - plr->x, mob->appearanceData.iY - plr->y); int distance = hypot(xyDistance, mob->appearanceData.iZ - plr->z); - if (distance > mobRange) + if (distance > mobRange || distance > closestDistance) continue; - // found player. engage. - mob->target = s; - mob->state = MobState::COMBAT; - mob->nextMovement = currTime; - mob->nextAttack = 0; - - mob->roamX = mob->appearanceData.iX; - mob->roamY = mob->appearanceData.iY; - mob->roamZ = mob->appearanceData.iZ; - - return true; + // found a player + closest = s; + closestDistance = distance; } } + if (closest != nullptr) { + // found closest player. engage. + mob->target = closest; + mob->state = MobState::COMBAT; + mob->nextMovement = currTime; + mob->nextAttack = 0; + + mob->roamX = mob->appearanceData.iX; + mob->roamY = mob->appearanceData.iY; + mob->roamZ = mob->appearanceData.iZ; + + return true; + } + return false; } diff --git a/src/TableData.cpp b/src/TableData.cpp index 33f3796..05ef7e2 100644 --- a/src/TableData.cpp +++ b/src/TableData.cpp @@ -50,7 +50,8 @@ void TableData::init() { } } catch (const std::exception& err) { - std::cerr << "[WARN] Malformed NPCs.json file! Reason:" << err.what() << std::endl; + std::cerr << "[FATAL] Malformed NPCs.json file! Reason:" << err.what() << std::endl; + terminate(0); } // load everything else from xdttable @@ -176,7 +177,8 @@ void TableData::init() { std::cout << "[INFO] Loaded " << NanoManager::NanoTable.size() << " nanos" << std::endl; } catch (const std::exception& err) { - std::cerr << "[WARN] Malformed xdt.json file! Reason:" << err.what() << std::endl; + std::cerr << "[FATAL] Malformed xdt.json file! Reason:" << err.what() << std::endl; + terminate(0); } // load temporary mob dump @@ -203,7 +205,8 @@ void TableData::init() { std::cout << "[INFO] Populated " << NPCManager::NPCs.size() << " NPCs" << std::endl; } catch (const std::exception& err) { - std::cerr << "[WARN] Malformed mobs.json file! Reason:" << err.what() << std::endl; + std::cerr << "[FATAL] Malformed mobs.json file! Reason:" << err.what() << std::endl; + terminate(0); } loadDrops(); @@ -300,7 +303,8 @@ void TableData::loadPaths(int* nextId) { std::cout << "[INFO] Loaded " << TransportManager::NPCQueues.size() << " NPC paths" << std::endl; } catch (const std::exception& err) { - std::cerr << "[WARN] Malformed paths.json file! Reason:" << err.what() << std::endl; + std::cerr << "[FATAL] Malformed paths.json file! Reason:" << err.what() << std::endl; + terminate(0); } } @@ -413,7 +417,8 @@ void TableData::loadDrops() { } catch (const std::exception& err) { - std::cerr << "[WARN] Malformed drops.json file! Reason:" << err.what() << std::endl; + std::cerr << "[FATAL] Malformed drops.json file! Reason:" << err.what() << std::endl; + terminate(0); } } @@ -563,7 +568,8 @@ void TableData::loadGruntwork(int32_t *nextId) { std::cout << "[INFO] Loaded gruntwork.json" << std::endl; } catch (const std::exception& err) { - std::cerr << "[WARN] Malformed gruntwork.json file! Reason:" << err.what() << std::endl; + std::cerr << "[FATAL] Malformed gruntwork.json file! Reason:" << err.what() << std::endl; + terminate(0); } } @@ -623,7 +629,7 @@ void TableData::flush() { mob["iX"] = m->spawnX; mob["iY"] = m->spawnY; mob["iZ"] = m->spawnZ; - mob["iMapNum"] = m->instanceID; + mob["iMapNum"] = m->instanceID & 0xffffffff; // this is a bit imperfect, since this is a live angle, not a spawn angle so it'll change often, but eh mob["iAngle"] = m->appearanceData.iAngle;