diff --git a/src/ChatManager.cpp b/src/ChatManager.cpp index 03af83a..4c7bb2f 100644 --- a/src/ChatManager.cpp +++ b/src/ChatManager.cpp @@ -216,32 +216,40 @@ void summonWCommand(std::string full, std::vector& args, CNSocket* assert(NPCManager::nextId < INT32_MAX); +#define EXTRA_HEIGHT 200 BaseNPC *npc = nullptr; + int id = NPCManager::nextId++; if (team == 2) { - 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; + npc = new Mob(plr->x, plr->y, plr->z + EXTRA_HEIGHT, plr->instanceID, type, NPCManager::NPCData[type], id); MobManager::Mobs[npc->appearanceData.iNPC_ID] = (Mob*)npc; // re-enable respawning ((Mob*)npc)->summoned = false; } else { - ChatManager::sendServerMessage(sock, "Error: /summonW only supports Mobs at this time."); - return; + npc = new BaseNPC(plr->x, plr->y, plr->z + EXTRA_HEIGHT, 0, plr->instanceID, type, id); } + npc->appearanceData.iAngle = (plr->angle + 180) % 360; + NPCManager::NPCs[npc->appearanceData.iNPC_ID] = npc; + 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 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 = new Mob(plr->x, plr->y, plr->z + 200, MAPNUM(plr->instanceID), type, NPCManager::NPCData[type], NPCManager::nextId++); + id = NPCManager::nextId++; + + if (team == 2) { + npc = new Mob(plr->x, plr->y, plr->z + EXTRA_HEIGHT, MAPNUM(plr->instanceID), type, NPCManager::NPCData[type], id); + + MobManager::Mobs[npc->appearanceData.iNPC_ID] = (Mob*)npc; + + ((Mob*)npc)->summoned = false; + } else { + npc = new BaseNPC(plr->x, plr->y, plr->z + EXTRA_HEIGHT, 0, MAPNUM(plr->instanceID), type, id); + } + 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); } @@ -313,14 +321,24 @@ void npcRotateCommand(std::string full, std::vector& args, CNSocket int angle = (plr->angle + 180) % 360; NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, npc->appearanceData.iX, npc->appearanceData.iY, npc->appearanceData.iZ, angle); - TableData::RunningNPCRotations[npc->appearanceData.iNPC_ID] = 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->appearanceData.iX, npc->appearanceData.iY, npc->appearanceData.iZ, angle); + + ChatManager::sendServerMessage(sock, "[NPCR] Successfully set angle to " + std::to_string(angle) + " for gruntwork NPC " + + std::to_string(npc->appearanceData.iNPC_ID)); + } else { + TableData::RunningNPCRotations[npc->appearanceData.iNPC_ID] = angle; + + ChatManager::sendServerMessage(sock, "[NPCR] Successfully set angle to " + std::to_string(angle) + " for NPC " + + std::to_string(npc->appearanceData.iNPC_ID)); + } + // update rotation clientside INITSTRUCT(sP_FE2CL_NPC_ENTER, pkt); pkt.NPCAppearanceData = npc->appearanceData; sock->sendPacket((void*)&pkt, P_FE2CL_NPC_ENTER, sizeof(sP_FE2CL_NPC_ENTER)); - - ChatManager::sendServerMessage(sock, "[NPCR] Successfully set angle to " + std::to_string(angle) + " for NPC " + std::to_string(npc->appearanceData.iNPC_ID)); } void refreshCommand(std::string full, std::vector& args, CNSocket* sock) { diff --git a/src/TableData.cpp b/src/TableData.cpp index 41bd55f..5f37198 100644 --- a/src/TableData.cpp +++ b/src/TableData.cpp @@ -551,18 +551,25 @@ void TableData::loadGruntwork(int32_t *nextId) { auto mobs = gruntwork["mobs"]; for (auto _mob = mobs.begin(); _mob != mobs.end(); _mob++) { auto mob = _mob.value(); - + BaseNPC *npc; + int id = (*nextId)++; uint64_t instanceID = mob.find("iMapNum") == mob.end() ? INSTANCE_OVERWORLD : (int)mob["iMapNum"]; - Mob *npc = new Mob(mob["iX"], mob["iY"], mob["iZ"], instanceID, mob["iNPCType"], - NPCManager::NPCData[(int)mob["iNPCType"]], (*nextId)++); + + if (NPCManager::NPCData[(int)mob["iNPCType"]]["m_iTeam"] == 2) { + npc = new Mob(mob["iX"], mob["iY"], mob["iZ"], instanceID, mob["iNPCType"], + NPCManager::NPCData[(int)mob["iNPCType"]], id); + + // re-enable respawning + ((Mob*)npc)->summoned = false; + + MobManager::Mobs[npc->appearanceData.iNPC_ID] = (Mob*)npc; + } else { + npc = new BaseNPC(mob["iX"], mob["iY"], mob["iZ"], mob["iAngle"], instanceID, mob["iNPCType"], id); + } NPCManager::NPCs[npc->appearanceData.iNPC_ID] = npc; - MobManager::Mobs[npc->appearanceData.iNPC_ID] = npc; TableData::RunningMobs[npc->appearanceData.iNPC_ID] = npc; NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, mob["iX"], mob["iY"], mob["iZ"]); - - // re-enable respawning - npc->summoned = false; } std::cout << "[INFO] Loaded gruntwork.json" << std::endl; @@ -618,21 +625,36 @@ void TableData::flush() { for (auto& pair : RunningMobs) { nlohmann::json mob; - Mob *m = (Mob*)pair.second; // we need spawnX, etc + BaseNPC *npc = pair.second; if (NPCManager::NPCs.find(pair.first) == NPCManager::NPCs.end()) continue; - // NOTE: this format deviates slightly from the one in mobs.json - mob["iNPCType"] = (int)m->appearanceData.iNPCType; - mob["iHP"] = (int)m->maxHealth; - mob["iX"] = m->spawnX; - mob["iY"] = m->spawnY; - mob["iZ"] = m->spawnZ; - mob["iMapNum"] = MAPNUM(m->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"] = m->appearanceData.iAngle; + int x, y, z, hp; + if (npc->npcClass == NPC_MOB) { + Mob *m = (Mob*)npc; + x = m->spawnX; + y = m->spawnY; + z = m->spawnZ; + hp = m->maxHealth; + } else { + x = npc->appearanceData.iX; + y = npc->appearanceData.iY; + z = npc->appearanceData.iZ; + hp = npc->appearanceData.iHP; + } + // NOTE: this format deviates slightly from the one in mobs.json + mob["iNPCType"] = (int)npc->appearanceData.iNPCType; + mob["iHP"] = hp; + 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; + + // it's called mobs, but really it's everything gruntwork["mobs"].push_back(mob); }