diff --git a/src/ChatManager.cpp b/src/ChatManager.cpp index 21286e6..6262324 100644 --- a/src/ChatManager.cpp +++ b/src/ChatManager.cpp @@ -284,6 +284,22 @@ void unsummonWCommand(std::string full, std::vector& args, CNSocket return; } + int leadId = ((Mob*)npc)->groupLeader; + if (leadId != 0) { + Mob* leadNpc = MobManager::Mobs[leadId]; + for (int i = 0; i < 4; i++) { + if (leadNpc->groupMember[i] == 0) + break; + + TableData::RunningMobs.erase(leadNpc->groupMember[i]); + NPCManager::destroyNPC(leadNpc->groupMember[i]); + } + TableData::RunningMobs.erase(leadId); + NPCManager::destroyNPC(leadId); + ChatManager::sendServerMessage(sock, "/unsummonW: Mob group destroyed."); + return; + } + ChatManager::sendServerMessage(sock, "/unsummonW: removed mob with type: " + std::to_string(npc->appearanceData.iNPCType) + ", id: " + std::to_string(npc->appearanceData.iNPC_ID)); @@ -509,11 +525,11 @@ void notifyCommand(std::string full, std::vector& args, CNSocket* s Player *plr = PlayerManager::getPlayer(sock); if (plr->notify) { - plr->notify = false; - ChatManager::sendServerMessage(sock, "[ADMIN] No longer receiving join notifications"); + plr->notify = false; + ChatManager::sendServerMessage(sock, "[ADMIN] No longer receiving join notifications"); } else { - plr->notify = true; - ChatManager::sendServerMessage(sock, "[ADMIN] Receiving join notifications"); + plr->notify = true; + ChatManager::sendServerMessage(sock, "[ADMIN] Receiving join notifications"); } } @@ -523,14 +539,16 @@ void playersCommand(std::string full, std::vector& args, CNSocket* ChatManager::sendServerMessage(sock, PlayerManager::getPlayerName(pair.second)); } -void summonGroupWCommand(std::string full, std::vector& args, CNSocket* sock) { +void summonGroupCommand(std::string full, std::vector& args, CNSocket* sock) { if (args.size() < 4) { - ChatManager::sendServerMessage(sock, "/summonGroupW [distance]"); + ChatManager::sendServerMessage(sock, "/summonGroup(W) [distance]"); return; } Player* plr = PlayerManager::getPlayer(sock); char *rest; + + bool wCommand = (args[0] == "/summonGroupW"); int type = std::strtol(args[1].c_str(), &rest, 10); int type2 = std::strtol(args[2].c_str(), &rest, 10); int count = std::strtol(args[3].c_str(), &rest, 10); @@ -586,7 +604,8 @@ void summonGroupWCommand(std::string full, std::vector& args, CNSoc } // re-enable respawning - ((Mob*)npc)->summoned = false; + if (wCommand) + ((Mob*)npc)->summoned = false; } else { npc = new BaseNPC(x, y, z + EXTRA_HEIGHT, 0, plr->instanceID, type, id); } @@ -612,8 +631,8 @@ void summonGroupWCommand(std::string full, std::vector& args, CNSoc mob->offsetX = x - plr->x; mob->offsetY = y - plr->y; } - - ((Mob*)npc)->summoned = false; + if (wCommand) + ((Mob*)npc)->summoned = false; } else { npc = new BaseNPC(x, y, z + EXTRA_HEIGHT, 0, MAPNUM(plr->instanceID), type, id); } @@ -624,9 +643,10 @@ void summonGroupWCommand(std::string full, std::vector& args, CNSoc NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, x, y, z); } - ChatManager::sendServerMessage(sock, "/summonGroupW: placed mob with type: " + std::to_string(type) + + ChatManager::sendServerMessage(sock, "/summonGroup(W): 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 + if (wCommand) + TableData::RunningMobs[npc->appearanceData.iNPC_ID] = npc; // only record the one in the template if (i == 0 && team == 2) { type = type2; @@ -666,7 +686,8 @@ void ChatManager::init() { registerCommand("tasks", 30, tasksCommand, "list all active missions and their respective task ids."); registerCommand("notify", 30, notifyCommand, "receive a message whenever a player joins the server"); registerCommand("players", 30, playersCommand, "print all players on the server"); - registerCommand("summonGroupW", 30, summonGroupWCommand, "permanently summon group NPCs"); + registerCommand("summonGroup", 30, summonGroupCommand, "summon group NPCs"); + registerCommand("summonGroupW", 30, summonGroupCommand, "permanently summon group NPCs"); } void ChatManager::registerCommand(std::string cmd, int requiredLevel, CommandHandler handlr, std::string help) { diff --git a/src/MobManager.cpp b/src/MobManager.cpp index ad6ac3a..906766b 100644 --- a/src/MobManager.cpp +++ b/src/MobManager.cpp @@ -133,7 +133,7 @@ void MobManager::npcAttackPc(Mob *mob, time_t currTime) { sP_FE2CL_NPC_ATTACK_PCs *pkt = (sP_FE2CL_NPC_ATTACK_PCs*)respbuf; sAttackResult *atk = (sAttackResult*)(respbuf + sizeof(sP_FE2CL_NPC_ATTACK_PCs)); - auto damage = getDamage(450 + (int)mob->data["m_iPower"], plr->defense, false, false, -1, -1, rand() % plr->level + 1); + auto damage = getDamage(450 + (int)mob->data["m_iPower"], plr->defense, false, false, -1, -1, 0); plr->HP -= damage.first; pkt->iNPC_ID = mob->appearanceData.iNPC_ID; @@ -338,6 +338,9 @@ int MobManager::hitMob(CNSocket *sock, Mob *mob, int damage) { mob->roamX = mob->appearanceData.iX; mob->roamY = mob->appearanceData.iY; mob->roamZ = mob->appearanceData.iZ; + + if (mob->groupLeader != 0) + followToCombat(mob); } mob->appearanceData.iHP -= damage; @@ -560,7 +563,14 @@ void MobManager::combatStep(Mob *mob, time_t currTime) { if (mob->appearanceData.iConditionBitFlag & CSB_BIT_DN_MOVE_SPEED) speed /= 2; - auto targ = lerp(mob->appearanceData.iX, mob->appearanceData.iY, mob->target->plr->x, mob->target->plr->y,std::min(distance-(int)mob->data["m_iAtkRange"]+1, speed*2/5)); + int targetX = mob->target->plr->x; + int targetY = mob->target->plr->y; + if (mob->groupLeader != 0) { + targetX += mob->offsetX*distance/(mob->sightRange+1); + targetY += mob->offsetY*distance/(mob->sightRange+1); + } + + auto targ = lerp(mob->appearanceData.iX, mob->appearanceData.iY, targetX, targetY, std::min(distance-(int)mob->data["m_iAtkRange"]+1, speed*2/5)); NPCManager::updateNPCPosition(mob->appearanceData.iNPC_ID, targ.first, targ.second, mob->appearanceData.iZ, mob->instanceID, mob->appearanceData.iAngle); @@ -570,10 +580,6 @@ void MobManager::combatStep(Mob *mob, time_t currTime) { pkt.iSpeed = speed; pkt.iToX = mob->appearanceData.iX = targ.first; pkt.iToY = mob->appearanceData.iY = targ.second; - if (mob->groupLeader != 0 && mob->groupLeader != mob->appearanceData.iNPC_ID) { - pkt.iToX += mob->offsetX; - pkt.iToY += mob->offsetY; - } pkt.iToZ = mob->target->plr->z; pkt.iMoveStyle = 1; @@ -972,7 +978,7 @@ std::pair MobManager::getDamage(int attackPower, int defensePower, bool // base calculation int damage = attackPower * attackPower / (attackPower + defensePower); - //damage = std::max(10 + attackPower / 10, damage - defensePower * (4 + difficulty) / 100); + damage = std::max(10 + attackPower / 10, damage - (defensePower - attackPower / 2) * difficulty / 72); damage = damage * (rand() % 40 + 80) / 100; // Adaptium/Blastons/Cosmix @@ -1053,7 +1059,7 @@ void MobManager::pcAttackChars(CNSocket *sock, CNPacketData *data) { else damage.first = plr->pointDamage; - damage = getDamage(damage.first, target->defense, true, (plr->batteryW > 6 + plr->level), -1, -1, 1); + damage = getDamage(damage.first, target->defense, true, (plr->batteryW > 6 + plr->level), -1, -1, 0); if (plr->batteryW >= 6 + plr->level) plr->batteryW -= 6 + plr->level; @@ -1188,6 +1194,9 @@ bool MobManager::aggroCheck(Mob *mob, time_t currTime) { mob->roamY = mob->appearanceData.iY; mob->roamZ = mob->appearanceData.iZ; + if (mob->groupLeader != 0) + followToCombat(mob); + return true; } @@ -1380,3 +1389,39 @@ void MobManager::projectileHit(CNSocket* sock, CNPacketData* data) { Bullets[plr->iID].erase(resp->iBulletID); } + +void MobManager::followToCombat(Mob *mob) { + if (Mobs.find(mob->groupLeader) != Mobs.end()) { + Mob* leadMob = Mobs[mob->groupLeader]; + for (int i = 0; i < 4; i++) { + if (leadMob->groupMember[i] == 0) + break; + + if (Mobs.find(leadMob->groupMember[i]) == Mobs.end()) { + std::cout << "[WARN] roamingStep: leader can't find a group member!" << std::endl; + continue; + } + Mob* followerMob = Mobs[leadMob->groupMember[i]]; + + if (followerMob->state == MobState::COMBAT) + continue; + + followerMob->target = mob->target; + followerMob->state = MobState::COMBAT; + followerMob->nextMovement = getTime(); + followerMob->nextAttack = 0; + + followerMob->roamX = followerMob->appearanceData.iX; + followerMob->roamY = followerMob->appearanceData.iY; + followerMob->roamZ = followerMob->appearanceData.iZ; + } + leadMob->target = mob->target; + leadMob->state = MobState::COMBAT; + leadMob->nextMovement = getTime(); + leadMob->nextAttack = 0; + + leadMob->roamX = leadMob->appearanceData.iX; + leadMob->roamY = leadMob->appearanceData.iY; + leadMob->roamZ = leadMob->appearanceData.iZ; + } +} diff --git a/src/MobManager.hpp b/src/MobManager.hpp index 1ab5064..e3145bf 100644 --- a/src/MobManager.hpp +++ b/src/MobManager.hpp @@ -163,4 +163,6 @@ namespace MobManager { /// returns bullet id int8_t addBullet(Player* plr, bool isGrenade); + void followToCombat(Mob *mob); + }