Group Mobs Initial Implementation

* For now only mob.json is read for grouped mobs.
* Grouped mobs are fully functional granted the mobs.json is prepared correctly.
* Removed redundant move packet.
This commit is contained in:
Jade 2020-11-15 07:06:29 +00:00 committed by Gent S
parent e9ffbe6148
commit 883a1c17e6
3 changed files with 87 additions and 16 deletions

View File

@ -434,6 +434,10 @@ void MobManager::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)
roamingStep(mob, currTime);
if (mob->killedTime != 0 && currTime - mob->killedTime < mob->regenTime * 100)
return;
@ -443,8 +447,21 @@ void MobManager::deadStep(Mob *mob, time_t currTime) {
mob->state = MobState::ROAMING;
// reset position
if (mob->groupLeader != 0) {
// mob is a group leader/follower, spawn where the group is.
if (Mobs.find(mob->groupLeader) != Mobs.end()) {
Mob* leaderMob = Mobs[mob->groupLeader];
mob->appearanceData.iX = leaderMob->appearanceData.iX + mob->offsetX;
mob->appearanceData.iY = leaderMob->appearanceData.iY + mob->offsetY;
} else {
std::cout << "[WARN] deadStep: mob cannot find it's leader!" << std::endl;
mob->appearanceData.iX = mob->spawnX;
mob->appearanceData.iY = mob->spawnY;
}
} else {
mob->appearanceData.iX = mob->spawnX;
mob->appearanceData.iY = mob->spawnY;
}
mob->appearanceData.iZ = mob->spawnZ;
INITSTRUCT(sP_FE2CL_NPC_NEW, pkt);
@ -523,15 +540,6 @@ void MobManager::combatStep(Mob *mob, time_t currTime) {
if (distance <= (int)mob->data["m_iAtkRange"]) {
// attack logic
if (mob->nextAttack == 0) {
INITSTRUCT(sP_FE2CL_NPC_MOVE, pkt);
pkt.iNPC_ID = mob->appearanceData.iNPC_ID;
pkt.iSpeed = (int)mob->data["m_iRunSpeed"];
pkt.iToX = mob->appearanceData.iX;
pkt.iToY = mob->appearanceData.iY;
pkt.iToZ = mob->target->plr->z;
pkt.iMoveStyle = 1;
NPCManager::sendToViewable(mob, &pkt, P_FE2CL_NPC_MOVE, sizeof(sP_FE2CL_NPC_MOVE));
mob->nextAttack = currTime + (int)mob->data["m_iInitalTime"] * 100; //I *think* this is what this is
npcAttackPc(mob, currTime);
} else if (mob->nextAttack != 0 && currTime >= mob->nextAttack) {
@ -562,6 +570,10 @@ 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;
@ -591,8 +603,9 @@ void MobManager::roamingStep(Mob *mob, time_t currTime) {
/*
* We reuse nextAttack to avoid scanning for players all the time, but to still
* do so more often than if we waited for nextMovement (which is way too slow).
* In the case of group leaders, this step will be called by dead mobs, so disable attack.
*/
if (mob->nextAttack == 0 || currTime >= mob->nextAttack) {
if (mob->state != MobState::DEAD && (mob->nextAttack == 0 || currTime >= mob->nextAttack)) {
mob->nextAttack = currTime + 500;
if (aggroCheck(mob, currTime))
return;
@ -615,6 +628,9 @@ void MobManager::roamingStep(Mob *mob, time_t currTime) {
* so we don't have to check if there's already entries in the queue since we know there won't be.
*/
if (mob->groupLeader != 0 && mob->groupLeader != mob->appearanceData.iNPC_ID) // don't roam by yourself without group leader
return;
int xStart = mob->spawnX - mob->idleRange/2;
int yStart = mob->spawnY - mob->idleRange/2;
int speed = mob->data["m_iWalkSpeed"];
@ -622,10 +638,6 @@ void MobManager::roamingStep(Mob *mob, time_t currTime) {
int farX, farY;
int distance; // for short walk detection
/*
* We don't want the mob to just take one step and stop, so we make sure
* it has walked a half-decent distance.
*/
do {
farX = xStart + rand() % mob->idleRange;
farY = yStart + rand() % mob->idleRange;
@ -644,6 +656,26 @@ void MobManager::roamingStep(Mob *mob, time_t currTime) {
// add a route to the queue; to be processed in TransportManager::stepNPCPathing()
TransportManager::lerp(&queue, from, to, speed);
TransportManager::NPCQueues[mob->appearanceData.iNPC_ID] = queue;
if (mob->groupLeader != 0 && mob->groupLeader == mob->appearanceData.iNPC_ID) {
// make followers follow this npc.
for (int i = 0; i < 4; i++) {
if (mob->groupMember[i] == 0)
break;
if (Mobs.find(mob->groupMember[i]) == Mobs.end()) {
std::cout << "[WARN] roamingStep: leader can't find a group member!" << std::endl;
continue;
}
std::queue<WarpLocation> queue2;
Mob* followerMob = Mobs[mob->groupMember[i]];
from = { followerMob->appearanceData.iX, followerMob->appearanceData.iY, followerMob->appearanceData.iZ };
to = { farX + followerMob->offsetX, farY + followerMob->offsetY, followerMob->appearanceData.iZ };
TransportManager::lerp(&queue2, from, to, speed);
TransportManager::NPCQueues[followerMob->appearanceData.iNPC_ID] = queue2;
}
}
}
void MobManager::retreatStep(Mob *mob, time_t currTime) {

View File

@ -51,6 +51,11 @@ struct Mob : public BaseNPC {
// drop
int dropType;
// group
int groupLeader = 0;
int offsetX, offsetY;
int groupMember[4] = {0, 0, 0, 0};
// temporary; until we're sure what's what
nlohmann::json data;

View File

@ -201,17 +201,51 @@ void TableData::init() {
// read file into json
inFile >> npcData;
int leaderMob = -1;
int leaderMobFollowers = 0;
for (nlohmann::json::iterator _npc = npcData.begin(); _npc != npcData.end(); _npc++) {
auto npc = _npc.value();
auto td = NPCManager::NPCData[(int)npc["iNPCType"]];
uint64_t instanceID = npc.find("iMapNum") == npc.end() ? INSTANCE_OVERWORLD : (int)npc["iMapNum"];
Mob *tmp = new Mob(npc["iX"], npc["iY"], npc["iZ"], npc["iAngle"], instanceID, npc["iNPCType"], npc["iHP"], td, nextId);
NPCManager::NPCs[nextId] = tmp;
MobManager::Mobs[nextId] = (Mob*)NPCManager::NPCs[nextId];
NPCManager::updateNPCPosition(nextId, npc["iX"], npc["iY"], npc["iZ"], instanceID, npc["iAngle"]);
// handling groups
if (npc.find("iOffsetX") != npc.end() && MobManager::Mobs.find(nextId) != MobManager::Mobs.end()) {
Mob* currNpc = MobManager::Mobs[nextId];
if (leaderMob == -1) {
if (MobManager::Mobs.find(nextId-1) != MobManager::Mobs.end()) {
Mob* leadNpc = MobManager::Mobs[nextId-1];
leaderMob = nextId-1;
leadNpc->groupMember[leaderMobFollowers] = nextId;
leaderMobFollowers++;
currNpc->groupLeader = nextId-1;
leadNpc->groupLeader = nextId-1;
}
} else {
if (MobManager::Mobs.find(leaderMob) != MobManager::Mobs.end()) {
Mob* leadNpc = MobManager::Mobs[leaderMob];
leaderMob = leaderMob;
leadNpc->groupMember[leaderMobFollowers] = nextId;
leaderMobFollowers++;
currNpc->groupLeader = leaderMob;
}
}
currNpc->offsetX = (int)npc["iOffsetX"];
currNpc->offsetY = npc.find("iOffsetY") == npc.end() ? 0 : (int)npc["iOffsetY"];
std::cout << "[INFO] Added group NPC " << nextId << " to ID " << currNpc->groupLeader << std::endl;
} else {
leaderMob = -1;
leaderMobFollowers = 0;
}
nextId++;
}