From 2782706355a82bf82ce98cb88021375a282a96cd Mon Sep 17 00:00:00 2001 From: Jade Date: Sat, 17 Oct 2020 05:58:51 +0100 Subject: [PATCH] Group warping & mob movement smoothing * Warping into IZs and Fusion Lairs now will also take into account your group members. * MobManager lerp does not confusingly divide speed by 2 anymore. * Mobs pursue their targets more smoothly, they will avoid phasing into the player during combat. * Nerfed retreat speed by a factor of 1.5, normal mobs retreated way too quickly however mobs like Don Doom and Bad Max do not retreat fast enough. * Bugfixed sendPlayerTo, it did not call updatePlayerPosition leaving undesirable anomalies. --- src/MobManager.cpp | 40 +++++++++++++++++++++++++++------------- src/NPCManager.cpp | 29 ++++++++++++++++++++++++++--- src/PlayerManager.cpp | 2 ++ 3 files changed, 55 insertions(+), 16 deletions(-) diff --git a/src/MobManager.cpp b/src/MobManager.cpp index e78d64a..88ab1d2 100644 --- a/src/MobManager.cpp +++ b/src/MobManager.cpp @@ -467,7 +467,15 @@ void MobManager::combatStep(Mob *mob, time_t currTime) { if (distance <= (int)mob->data["m_iAtkRange"]) { // attack logic if (mob->nextAttack == 0) { - mob->nextAttack = currTime + (int)mob->data["m_iInitalTime"] * 100; // I *think* this is what this is + 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; + 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) { mob->nextAttack = currTime + (int)mob->data["m_iDelayTime"] * 100; @@ -477,7 +485,9 @@ void MobManager::combatStep(Mob *mob, time_t currTime) { // movement logic if (mob->nextMovement != 0 && currTime < mob->nextMovement) return; - mob->nextMovement = currTime + 500; + mob->nextMovement = currTime + 399; + if (currTime >= mob->nextAttack) + mob->nextAttack = 0; int speed = mob->data["m_iRunSpeed"]; @@ -485,7 +495,7 @@ 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, speed); + 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)); NPCManager::updateNPCPosition(mob->appearanceData.iNPC_ID, targ.first, targ.second, mob->appearanceData.iZ); @@ -493,9 +503,11 @@ void MobManager::combatStep(Mob *mob, time_t currTime) { pkt.iNPC_ID = mob->appearanceData.iNPC_ID; pkt.iSpeed = speed; - pkt.iToX = mob->appearanceData.iX = targ.first; - pkt.iToY = mob->appearanceData.iY = targ.second; - pkt.iToZ = mob->appearanceData.iZ; + pkt.iToX = (targ.first - mob->appearanceData.iX) * 5 / 2 + mob->appearanceData.iX; + pkt.iToY = (targ.second - mob->appearanceData.iY) * 5 / 2 + mob->appearanceData.iY; + mob->appearanceData.iX = targ.first; + mob->appearanceData.iY = targ.second; + pkt.iToZ = mob->target->plr->z; // notify all nearby players NPCManager::sendToViewable(mob, &pkt, P_FE2CL_NPC_MOVE, sizeof(sP_FE2CL_NPC_MOVE)); @@ -581,7 +593,7 @@ void MobManager::retreatStep(Mob *mob, time_t currTime) { if (mob->nextMovement != 0 && currTime < mob->nextMovement) return; - mob->nextMovement = currTime + 500; + mob->nextMovement = currTime + 399; // distance between spawn point and current location int distance = hypot(mob->appearanceData.iX - mob->roamX, mob->appearanceData.iY - mob->roamY); @@ -590,12 +602,16 @@ void MobManager::retreatStep(Mob *mob, time_t currTime) { if (distance > 10) { INITSTRUCT(sP_FE2CL_NPC_MOVE, pkt); - auto targ = lerp(mob->appearanceData.iX, mob->appearanceData.iY, mob->roamX, mob->roamY, (int)mob->data["m_iRunSpeed"] * 3); + auto targ = lerp(mob->appearanceData.iX, mob->appearanceData.iY, mob->roamX, mob->roamY, (int)mob->data["m_iRunSpeed"]*4/5); pkt.iNPC_ID = mob->appearanceData.iNPC_ID; - pkt.iSpeed = (int)mob->data["m_iRunSpeed"] * 3; - pkt.iToX = mob->appearanceData.iX = targ.first; - pkt.iToY = mob->appearanceData.iY = targ.second; + pkt.iSpeed = (int)mob->data["m_iRunSpeed"] * 2; + mob->appearanceData.iX = targ.first; + mob->appearanceData.iY = targ.second; + pkt.iToX = (targ.first - mob->appearanceData.iX) * 5 / 2 + mob->appearanceData.iX; + pkt.iToY = (targ.second - mob->appearanceData.iY) * 5 / 2 + mob->appearanceData.iY; + mob->appearanceData.iX = targ.first; + mob->appearanceData.iY = targ.second; pkt.iToZ = mob->appearanceData.iZ; // notify all nearby players @@ -667,8 +683,6 @@ void MobManager::step(CNServer *serv, time_t currTime) { std::pair MobManager::lerp(int x1, int y1, int x2, int y2, int speed) { std::pair ret = {x1, y1}; - speed /= 2; - if (speed == 0) return ret; diff --git a/src/NPCManager.cpp b/src/NPCManager.cpp index b1303aa..ed854f8 100644 --- a/src/NPCManager.cpp +++ b/src/NPCManager.cpp @@ -596,9 +596,32 @@ void NPCManager::handleWarp(CNSocket* sock, int32_t warpId) { ChunkManager::createInstance(instanceID); } - PlayerManager::sendPlayerTo(sock, Warps[warpId].x, Warps[warpId].y, Warps[warpId].z, instanceID); - } else { - INITSTRUCT(sP_FE2CL_REP_PC_WARP_USE_NPC_SUCC, resp); // Can only be used for exiting instances because it sets the instance flag to false + if (plrv.plr->iID == plrv.plr->iIDGroup && plrv.plr->groupCnt == 1) + PlayerManager::sendPlayerTo(sock, Warps[warpId].x, Warps[warpId].y, Warps[warpId].z, instanceID); + else { + Player* leaderPlr = PlayerManager::getPlayerFromID(plrv.plr->iIDGroup); + + for (int i = 0; i < leaderPlr->groupCnt; i++) { + Player* otherPlr = PlayerManager::getPlayerFromID(leaderPlr->groupIDs[i]); + CNSocket* sockTo = PlayerManager::getSockFromID(leaderPlr->groupIDs[i]); + + if (otherPlr == nullptr || sockTo == nullptr) + continue; + + if (otherPlr->instanceID == 0) { + otherPlr->lastX = otherPlr->x; + otherPlr->lastY = otherPlr->y; + otherPlr->lastZ = otherPlr->z; + otherPlr->lastAngle = otherPlr->angle; + } + + PlayerManager::sendPlayerTo(sockTo, Warps[warpId].x, Warps[warpId].y, Warps[warpId].z, instanceID); + } + } + } + else + { + INITSTRUCT(sP_FE2CL_REP_PC_WARP_USE_NPC_SUCC, resp); //Can only be used for exiting instances because it sets the instance flag to false resp.iX = Warps[warpId].x; resp.iY = Warps[warpId].y; resp.iZ = Warps[warpId].z; diff --git a/src/PlayerManager.cpp b/src/PlayerManager.cpp index 8573909..ffcb8a8 100644 --- a/src/PlayerManager.cpp +++ b/src/PlayerManager.cpp @@ -261,6 +261,7 @@ void PlayerManager::sendPlayerTo(CNSocket* sock, int X, int Y, int Z, uint64_t I PlayerManager::removePlayerFromChunks(plrv.currentChunks, sock); plrv.currentChunks.clear(); sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_WARP_USE_NPC_SUCC, sizeof(sP_FE2CL_REP_PC_WARP_USE_NPC_SUCC)); + updatePlayerPosition(sock, X, Y, Z); } ChunkManager::destroyInstanceIfEmpty(fromInstance); @@ -279,6 +280,7 @@ void PlayerManager::sendPlayerTo(CNSocket* sock, int X, int Y, int Z) { plrv.currentChunks.clear(); plrv.chunkPos = std::make_tuple(0, 0, plrv.plr->instanceID); sock->sendPacket((void*)&pkt, P_FE2CL_REP_PC_GOTO_SUCC, sizeof(sP_FE2CL_REP_PC_GOTO_SUCC)); + updatePlayerPosition(sock, X, Y, Z); } void PlayerManager::enterPlayer(CNSocket* sock, CNPacketData* data) {