From f7c84c62edb1bbfaf5f472c2859903fece3a2ab5 Mon Sep 17 00:00:00 2001 From: Jade Date: Fri, 5 Mar 2021 14:18:36 +0000 Subject: [PATCH 1/6] Possibly fixed item duping via trading --- src/ItemManager.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/ItemManager.cpp b/src/ItemManager.cpp index 52ec7c3..d5620aa 100644 --- a/src/ItemManager.cpp +++ b/src/ItemManager.cpp @@ -530,7 +530,9 @@ bool ItemManager::doTrade(Player* plr, Player* plr2) { for (int i = 0; i < 5; i++) { // remove items offered by us if (plr->Trade[i].iID != 0) { - if (plrInven[plr->Trade[i].iInvenNum].iID == 0) // pulling a fast one on us + if (plrInven[plr->Trade[i].iInvenNum].iID == 0 + || plr->Trade[i].iID != plrInven[plr->Trade[i].iInvenNum].iID + || plr->Trade[i].iType != plrInven[plr->Trade[i].iInvenNum].iType) // pulling a fast one on us return false; if (plr->Trade[i].iOpt < 1) { @@ -551,7 +553,9 @@ bool ItemManager::doTrade(Player* plr, Player* plr2) { } if (plr2->Trade[i].iID != 0) { - if (plr2Inven[plr2->Trade[i].iInvenNum].iID == 0) // pulling a fast one on us + if (plr2Inven[plr2->Trade[i].iInvenNum].iID == 0 + || plr2->Trade[i].iID != plr2Inven[plr2->Trade[i].iInvenNum].iID + || plr2->Trade[i].iType != plr2Inven[plr2->Trade[i].iInvenNum].iType) // pulling a fast one on us return false; if (plr2->Trade[i].iOpt < 1) { From 81c2a2a8b3cd7323d79a297f428b19652af3b94c Mon Sep 17 00:00:00 2001 From: Jade Date: Sat, 9 Jan 2021 13:16:29 +0000 Subject: [PATCH 2/6] Mob Leech and Freedom --- src/MobManager.cpp | 93 +++++++++++++++++++++++---------------------- src/MobManager.hpp | 1 + src/NanoManager.cpp | 6 ++- 3 files changed, 52 insertions(+), 48 deletions(-) diff --git a/src/MobManager.cpp b/src/MobManager.cpp index 4e151a9..d54795b 100644 --- a/src/MobManager.cpp +++ b/src/MobManager.cpp @@ -360,14 +360,7 @@ int MobManager::hitMob(CNSocket *sock, Mob *mob, int damage) { if (mob->state == MobState::ROAMING) { assert(mob->target == nullptr); - mob->target = sock; - mob->state = MobState::COMBAT; - mob->nextMovement = getTime(); - mob->nextAttack = 0; - - mob->roamX = mob->appearanceData.iX; - mob->roamY = mob->appearanceData.iY; - mob->roamZ = mob->appearanceData.iZ; + enterCombat(sock, mob); if (mob->groupLeader != 0) followToCombat(mob); @@ -1253,14 +1246,7 @@ bool MobManager::aggroCheck(Mob *mob, time_t currTime) { 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; + enterCombat(closest, mob); if (mob->groupLeader != 0) followToCombat(mob); @@ -1484,27 +1470,13 @@ void MobManager::followToCombat(Mob *mob) { if (followerMob->state != MobState::ROAMING) // only roaming mobs should transition to 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; + enterCombat(mob->target, followerMob); } if (leadMob->state != MobState::ROAMING) return; - 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; + enterCombat(mob->target, leadMob); } } @@ -1744,6 +1716,23 @@ void MobManager::dealCorruption(Mob *mob, std::vector targetData, int skill NPCManager::sendToViewable(mob, (void*)&respbuf, P_FE2CL_NPC_SKILL_CORRUPTION_HIT, resplen); } +void MobManager::enterCombat(CNSocket *sock, Mob *mob) { + mob->target = sock; + mob->state = MobState::COMBAT; + mob->nextMovement = getTime(); + mob->nextAttack = 0; + + mob->roamX = mob->appearanceData.iX; + mob->roamY = mob->appearanceData.iY; + mob->roamZ = mob->appearanceData.iZ; + + int skillID = (int)mob->data["m_iPassiveBuff"]; // cast passive + std::vector targetData = {1, mob->appearanceData.iNPC_ID, 0, 0, 0}; + for (auto& pwr : MobPowers) + if (pwr.skillType == NanoManager::SkillTable[skillID].skillType) + pwr.handle(mob, targetData, skillID, NanoManager::SkillTable[skillID].durationTime[0], NanoManager::SkillTable[skillID].powerIntensity[0]); +} + #pragma region Mob Powers namespace MobManager { bool doDamageNDebuff(Mob *mob, sSkillResult_Damage_N_Debuff *respdata, int i, int32_t targetID, int32_t bitFlag, int16_t timeBuffID, int16_t duration, int16_t amount) { @@ -1862,18 +1851,6 @@ bool doLeech(Mob *mob, sSkillResult_Heal_HP *healdata, int i, int32_t targetID, return false; } - sSkillResult_Damage *damagedata = (sSkillResult_Damage*)(((uint8_t*)healdata) + sizeof(sSkillResult_Heal_HP)); - - int healedAmount = amount * mob->maxHealth / 1000; - mob->appearanceData.iHP += healedAmount; - if (mob->appearanceData.iHP > mob->maxHealth) - mob->appearanceData.iHP = mob->maxHealth; - - healdata->eCT = 4; - healdata->iID = mob->appearanceData.iNPC_ID; - healdata->iHP = mob->appearanceData.iHP; - healdata->iHealHP = healedAmount; - Player *plr = nullptr; for (auto& pair : PlayerManager::players) { @@ -1889,7 +1866,20 @@ bool doLeech(Mob *mob, sSkillResult_Heal_HP *healdata, int i, int32_t targetID, return false; } - int damage = amount * PC_MAXHEALTH(plr->level) / 1000; + sSkillResult_Damage *damagedata = (sSkillResult_Damage*)(((uint8_t*)healdata) + sizeof(sSkillResult_Heal_HP)); + + int healedAmount = amount * PC_MAXHEALTH(plr->level) / 1000; + + mob->appearanceData.iHP += healedAmount; + if (mob->appearanceData.iHP > mob->maxHealth) + mob->appearanceData.iHP = mob->maxHealth; + + healdata->eCT = 4; + healdata->iID = mob->appearanceData.iNPC_ID; + healdata->iHP = mob->appearanceData.iHP; + healdata->iHealHP = healedAmount; + + int damage = healedAmount; if (plr->iSpecialState & CN_SPECIAL_STATE_FLAG__INVULNERABLE) damage = 0; @@ -1949,6 +1939,15 @@ bool doBatteryDrain(Mob *mob, sSkillResult_BatteryDrain *respdata, int i, int32_ return true; } +bool doBuff(Mob *mob, sSkillResult_Buff *respdata, int i, int32_t targetID, int32_t bitFlag, int16_t timeBuffID, int16_t duration, int16_t amount) { + respdata[i].eCT = 4; + respdata[i].iID = mob->appearanceData.iNPC_ID; + mob->appearanceData.iConditionBitFlag |= bitFlag; + respdata[i].iConditionBitFlag = mob->appearanceData.iConditionBitFlag; + + return true; +} + template void mobPower(Mob *mob, std::vector targetData, @@ -1996,7 +1995,9 @@ std::vector MobPowers = { MobPower(EST_SNARE, CSB_BIT_DN_MOVE_SPEED, ECSB_DN_MOVE_SPEED, mobPower), MobPower(EST_DAMAGE, CSB_BIT_NONE, ECSB_NONE, mobPower), MobPower(EST_BATTERYDRAIN, CSB_BIT_NONE, ECSB_NONE, mobPower), - MobPower(EST_SLEEP, CSB_BIT_MEZ, ECSB_MEZ, mobPower) + MobPower(EST_SLEEP, CSB_BIT_MEZ, ECSB_MEZ, mobPower), + MobPower(EST_BLOODSUCKING, CSB_BIT_NONE, ECSB_NONE, mobPower), + MobPower(EST_FREEDOM, CSB_BIT_FREEDOM, ECSB_FREEDOM, mobPower) }; }; // namespace diff --git a/src/MobManager.hpp b/src/MobManager.hpp index c1fd18d..3555362 100644 --- a/src/MobManager.hpp +++ b/src/MobManager.hpp @@ -190,4 +190,5 @@ namespace MobManager { void groupRetreat(Mob *mob); void useAbilities(Mob *mob, time_t currTime); void dealCorruption(Mob *mob, std::vector targetData, int skillID, int style); + void enterCombat(CNSocket *sock, Mob *mob); } diff --git a/src/NanoManager.cpp b/src/NanoManager.cpp index e2a692d..8ac7804 100644 --- a/src/NanoManager.cpp +++ b/src/NanoManager.cpp @@ -588,7 +588,8 @@ bool doDebuff(CNSocket *sock, sSkillResult_Buff *respdata, int i, int32_t target respdata[i].eCT = 4; respdata[i].iID = mob->appearanceData.iNPC_ID; respdata[i].bProtected = 1; - if (mob->skillStyle < 0 && mob->state != MobState::RETREAT) { // only debuff if the enemy is not retreating and not casting corruption + if (mob->skillStyle < 0 && mob->state != MobState::RETREAT + && !(mob->appearanceData.iConditionBitFlag & CSB_BIT_FREEDOM)) { // only debuff if the enemy is not retreating, casting corruption or in freedom mob->appearanceData.iConditionBitFlag |= bitFlag; mob->unbuffTimes[bitFlag] = getTime() + duration * 100; respdata[i].bProtected = 0; @@ -655,7 +656,8 @@ bool doDamageNDebuff(CNSocket *sock, sSkillResult_Damage_N_Debuff *respdata, int respdata[i].iID = mob->appearanceData.iNPC_ID; respdata[i].iHP = mob->appearanceData.iHP; respdata[i].bProtected = 1; - if (mob->skillStyle < 0 && mob->state != MobState::RETREAT) { // only debuff if the enemy is not retreating and not casting corruption + if (mob->skillStyle < 0 && mob->state != MobState::RETREAT + && !(mob->appearanceData.iConditionBitFlag & CSB_BIT_FREEDOM)) { // only debuff if the enemy is not retreating, casting corruption or in freedom mob->appearanceData.iConditionBitFlag |= bitFlag; mob->unbuffTimes[bitFlag] = getTime() + duration * 100; respdata[i].bProtected = 0; From dc6de46a1f87b60e11e2b86e5440461d00c39cd3 Mon Sep 17 00:00:00 2001 From: Jade Date: Sat, 9 Jan 2021 13:17:28 +0000 Subject: [PATCH 3/6] Added ON_COMBAT trigger --- src/MobManager.cpp | 4 ++++ src/NPCManager.hpp | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/MobManager.cpp b/src/MobManager.cpp index d54795b..c02272e 100644 --- a/src/MobManager.cpp +++ b/src/MobManager.cpp @@ -1731,6 +1731,10 @@ void MobManager::enterCombat(CNSocket *sock, Mob *mob) { for (auto& pwr : MobPowers) if (pwr.skillType == NanoManager::SkillTable[skillID].skillType) pwr.handle(mob, targetData, skillID, NanoManager::SkillTable[skillID].durationTime[0], NanoManager::SkillTable[skillID].powerIntensity[0]); + + for (NPCEvent& event : NPCManager::NPCEvents) // trigger an ON_COMBAT + if (event.trigger == ON_COMBAT && event.npcType == mob->appearanceData.iNPCType) + event.handler(sock, mob); } #pragma region Mob Powers diff --git a/src/NPCManager.hpp b/src/NPCManager.hpp index b21a8e6..da6ea8c 100644 --- a/src/NPCManager.hpp +++ b/src/NPCManager.hpp @@ -12,9 +12,9 @@ #define RESURRECT_HEIGHT 400 -// placeholder; there's only one trigger type right now enum Trigger { - ON_KILLED + ON_KILLED, + ON_COMBAT }; typedef void (*NPCEventHandler)(CNSocket*, BaseNPC*); From 33a26cda7cf15049645593120be0b834a13cb4ae Mon Sep 17 00:00:00 2001 From: Jade Date: Sat, 9 Jan 2021 14:01:56 +0000 Subject: [PATCH 4/6] Split mob heal types --- src/MobManager.cpp | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/MobManager.cpp b/src/MobManager.cpp index c02272e..fb162f7 100644 --- a/src/MobManager.cpp +++ b/src/MobManager.cpp @@ -1796,6 +1796,27 @@ bool doDamageNDebuff(Mob *mob, sSkillResult_Damage_N_Debuff *respdata, int i, in } bool doHeal(Mob *mob, sSkillResult_Heal_HP *respdata, int i, int32_t targetID, int32_t bitFlag, int16_t timeBuffID, int16_t duration, int16_t amount) { + if (MobManager::Mobs.find(targetID) == MobManager::Mobs.end()) { + std::cout << "[WARN] doDebuff: mob ID not found" << std::endl; + return false; + } + + Mob* targetMob = MobManager::Mobs[targetID]; + + int healedAmount = amount * targetMob->maxHealth / 1000; + targetMob->appearanceData.iHP += healedAmount; + if (targetMob->appearanceData.iHP > targetMob->maxHealth) + targetMob->appearanceData.iHP = targetMob->maxHealth; + + respdata[i].eCT = 4; + respdata[i].iID = targetMob->appearanceData.iNPC_ID; + respdata[i].iHP = targetMob->appearanceData.iHP; + respdata[i].iHealHP = healedAmount; + + return true; +} + +bool doReturnHeal(Mob *mob, sSkillResult_Heal_HP *respdata, int i, int32_t targetID, int32_t bitFlag, int16_t timeBuffID, int16_t duration, int16_t amount) { int healedAmount = amount * mob->maxHealth / 1000; mob->appearanceData.iHP += healedAmount; if (mob->appearanceData.iHP > mob->maxHealth) @@ -1995,7 +2016,7 @@ void mobPower(Mob *mob, std::vector targetData, std::vector MobPowers = { MobPower(EST_STUN, CSB_BIT_STUN, ECSB_STUN, mobPower), MobPower(EST_HEAL_HP, CSB_BIT_NONE, ECSB_NONE, mobPower), - MobPower(EST_RETURNHOMEHEAL, CSB_BIT_NONE, ECSB_NONE, mobPower), + MobPower(EST_RETURNHOMEHEAL, CSB_BIT_NONE, ECSB_NONE, mobPower), MobPower(EST_SNARE, CSB_BIT_DN_MOVE_SPEED, ECSB_DN_MOVE_SPEED, mobPower), MobPower(EST_DAMAGE, CSB_BIT_NONE, ECSB_NONE, mobPower), MobPower(EST_BATTERYDRAIN, CSB_BIT_NONE, ECSB_NONE, mobPower), From 540c37a52350695526abbb559b90a6b4abbd6f26 Mon Sep 17 00:00:00 2001 From: Jade Date: Sat, 9 Jan 2021 15:09:04 +0000 Subject: [PATCH 5/6] Aggro is now affected by level --- src/MobManager.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/MobManager.cpp b/src/MobManager.cpp index fb162f7..b35ba14 100644 --- a/src/MobManager.cpp +++ b/src/MobManager.cpp @@ -1228,6 +1228,14 @@ bool MobManager::aggroCheck(Mob *mob, time_t currTime) { || RacingManager::EPRaces.find(s) != RacingManager::EPRaces.end()) mobRange /= 3; + // 0.33x - 1.66x the range + int levelDifference = plr->level - mob->level; + if (levelDifference > -10) + mobRange = levelDifference < 10 ? mobRange - (levelDifference * mobRange / 15) : mobRange / 3; + + if (mob->state != MobState::ROAMING && plr->inCombat) // freshly out of aggro mobs + mobRange = mob->sightRange * 2; // should not be impacted by the above + if (plr->iSpecialState & (CN_SPECIAL_STATE_FLAG__INVISIBLE|CN_SPECIAL_STATE_FLAG__INVULNERABLE)) mobRange = -1; From 3445c0bbc3010ba561ac9a482b939b0cb20cf4c7 Mon Sep 17 00:00:00 2001 From: Jade Date: Sat, 9 Jan 2021 15:27:58 +0000 Subject: [PATCH 6/6] Tweaked mob and nano skills --- src/MobManager.cpp | 2 +- src/NanoManager.cpp | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/MobManager.cpp b/src/MobManager.cpp index b35ba14..7da4924 100644 --- a/src/MobManager.cpp +++ b/src/MobManager.cpp @@ -1779,7 +1779,7 @@ bool doDamageNDebuff(Mob *mob, sSkillResult_Damage_N_Debuff *respdata, int i, in pkt.eTBU = 1; // eTimeBuffUpdate pkt.eTBT = 2; pkt.iConditionBitFlag = plr->iConditionBitFlag |= bitFlag; - pkt.TimeBuff.iValue = amount; + pkt.TimeBuff.iValue = amount * 5; sock->sendPacket((void*)&pkt, P_FE2CL_PC_BUFF_UPDATE, sizeof(sP_FE2CL_PC_BUFF_UPDATE)); } diff --git a/src/NanoManager.cpp b/src/NanoManager.cpp index 8ac7804..953c89b 100644 --- a/src/NanoManager.cpp +++ b/src/NanoManager.cpp @@ -7,6 +7,8 @@ #include "MissionManager.hpp" #include "GroupManager.hpp" +#include + std::map NanoManager::NanoTable; std::map NanoManager::NanoTunings; std::map NanoManager::SkillTable; @@ -712,7 +714,7 @@ bool doDamage(CNSocket *sock, sSkillResult_Damage *respdata, int i, int32_t targ Player *plr = PlayerManager::getPlayer(sock); - int damage = MobManager::hitMob(sock, mob, PC_MAXHEALTH(plr->level) * amount / 2000 + mob->appearanceData.iHP * amount / 2000); + int damage = MobManager::hitMob(sock, mob, std::max(PC_MAXHEALTH(plr->level) * amount / 1000, mob->maxHealth * amount / 1000)); respdata[i].eCT = 4; respdata[i].iDamage = damage;