From 9b7656117d74b903a193f7292d1ad7b60c2b0e91 Mon Sep 17 00:00:00 2001 From: gsemaj Date: Thu, 20 Jul 2023 17:53:13 -0400 Subject: [PATCH] Reuse `useNanoSkill` codepath for passive powers --- src/Abilities.cpp | 42 +++++++++++++++++++++++++++--------------- src/Combat.cpp | 9 ++++++--- src/Nanos.cpp | 45 +++++---------------------------------------- src/Nanos.hpp | 1 - 4 files changed, 38 insertions(+), 59 deletions(-) diff --git a/src/Abilities.cpp b/src/Abilities.cpp index 8b4d19c..34e5d12 100644 --- a/src/Abilities.cpp +++ b/src/Abilities.cpp @@ -57,6 +57,23 @@ static SkillResult handleSkillDamageNDebuff(SkillData* skill, int power, ICombat } static SkillResult handleSkillBuff(SkillData* skill, int power, ICombatant* source, ICombatant* target) { + BuffStack passiveBuff = { + skill->drainType == SkillDrainType::PASSIVE ? 1 : skill->durationTime[power], // ticks + skill->values[0][power], // value + source->getRef(), // source + source == target ? BuffClass::NANO : BuffClass::GROUP_NANO, // buff class + }; + + int timeBuffId = Abilities::getCSTBFromST(skill->skillType); + if(!target->addBuff(timeBuffId, + [](EntityRef self, Buff* buff, int status, BuffStack* stack) { + Buffs::timeBuffUpdate(self, buff, status, stack); + }, + [](EntityRef self, Buff* buff, time_t currTime) { + // no-op + }, + &passiveBuff)) return SkillResult(); // no result if already buffed + sSkillResult_Buff result{}; result.eCT = target->getCharType(); result.iID = target->getID(); @@ -206,14 +223,16 @@ void Abilities::useNanoSkill(CNSocket* sock, SkillData* skill, sNano& nano, std: if (Nanos::getNanoBoost(plr)) boost = 3; - nano.iStamina -= skill->batteryUse[boost]; - if (nano.iStamina < 0) - nano.iStamina = 0; + if(skill->drainType == SkillDrainType::ACTIVE) { + nano.iStamina -= skill->batteryUse[boost]; + if (nano.iStamina <= 0) + nano.iStamina = 0; + } std::vector results = handleSkill(skill, boost, plr, affected); - size_t resultSize = 0; // guaranteed to be the same for every item - if (!results.empty()) resultSize = results.back().size; + if(results.empty()) return; // no effect; no need for confirmation packets + size_t resultSize = results.back().size; // guaranteed to be the same for every item if (!validOutVarPacket(sizeof(sP_FE2CL_NANO_SKILL_USE_SUCC), results.size(), resultSize)) { std::cout << "[WARN] bad sP_FE2CL_NANO_SKILL_USE_SUCC packet size\n"; return; @@ -241,9 +260,6 @@ void Abilities::useNanoSkill(CNSocket* sock, SkillData* skill, sNano& nano, std: PlayerManager::sendToGroup(sock, pkt, P_FE2CL_NANO_SKILL_USE, resplen); else PlayerManager::sendToViewable(sock, pkt, P_FE2CL_NANO_SKILL_USE, resplen); - - if (nano.iStamina <= 0) - Nanos::summonNano(sock, -1); } void Abilities::useNPCSkill(EntityRef npc, int skillID, std::vector affected) { @@ -293,14 +309,8 @@ static std::vector entityRefsToCombatants(std::vector re std::vector Abilities::matchTargets(ICombatant* src, SkillData* skill, int count, int32_t *ids) { - if(skill->targetType == SkillTargetType::GROUP) { - // group - if(count != 1 || ids[0] != src->getID()) { - std::cout << "[WARN] skill: bad group targeting (id " << ids[0] << ")\n"; - return {}; - } + if(skill->targetType == SkillTargetType::GROUP) return entityRefsToCombatants(src->getGroupMembers()); - } // this check *has* to happen after the group check above due to cases like group recall that use both if(skill->effectTarget == SkillEffectTarget::SELF) @@ -393,6 +403,8 @@ int Abilities::getCSTBFromST(SkillType skillType) { case SkillType::NANOSTIMPAK: result = ECSB_STIMPAKSLOT1; break; + default: + break; } return result; } diff --git a/src/Combat.cpp b/src/Combat.cpp index 4220b1e..4c932a9 100644 --- a/src/Combat.cpp +++ b/src/Combat.cpp @@ -874,9 +874,12 @@ static void playerTick(CNServer *serv, time_t currTime) { if (Abilities::SkillTable.find(nano->iSkillID) != Abilities::SkillTable.end()) { // nano has skill data SkillData* skill = &Abilities::SkillTable[nano->iSkillID]; - if (skill->drainType == SkillDrainType::PASSIVE) - Nanos::applyNanoBuff(skill, plr); - // ^ composite condition calculation is separate from combat for responsiveness + if (skill->drainType == SkillDrainType::PASSIVE) { + ICombatant* src = dynamic_cast(plr); + int32_t targets[] = { plr->iID }; + std::vector affectedCombatants = Abilities::matchTargets(src, skill, 1, targets); + Abilities::useNanoSkill(sock, skill, *nano, affectedCombatants); + } } } diff --git a/src/Nanos.cpp b/src/Nanos.cpp index 0c47219..8fa9629 100644 --- a/src/Nanos.cpp +++ b/src/Nanos.cpp @@ -69,43 +69,6 @@ void Nanos::addNano(CNSocket* sock, int16_t nanoID, int16_t slot, bool spendfm) PlayerManager::sendToViewable(sock, resp2, P_FE2CL_REP_PC_CHANGE_LEVEL); } -std::vector Nanos::applyNanoBuff(SkillData* skill, Player* plr) { - assert(skill->drainType == SkillDrainType::PASSIVE); - - EntityRef self = PlayerManager::getSockFromID(plr->iID); - - int timeBuffId = Abilities::getCSTBFromST(skill->skillType); - int boost = Nanos::getNanoBoost(plr) ? 3 : 0; - int value = skill->values[0][boost]; - - BuffStack passiveBuff = { - 1, // passive nano buffs refreshed every tick - value, - self, - BuffClass::NONE, // overwritten per target - }; - - // for passive skills, using just the player as a target is fine - // this is because the group skill type will ignore the count, - // and the other option is single-target - std::vector targets = Abilities::matchTargets(dynamic_cast(plr), skill, 1, &plr->iID); - std::vector affected; - for (ICombatant* target : targets) { - - passiveBuff.buffStackClass = target == plr ? BuffClass::NANO : BuffClass::GROUP_NANO; - if(target->addBuff(timeBuffId, - [](EntityRef self, Buff* buff, int status, BuffStack* stack) { - Buffs::timeBuffUpdate(self, buff, status, stack); - }, - [](EntityRef self, Buff* buff, time_t currTime) { - // no-op - }, - &passiveBuff)) affected.push_back(target); - } - - return affected; -} - void Nanos::summonNano(CNSocket *sock, int slot, bool silent) { INITSTRUCT(sP_FE2CL_REP_NANO_ACTIVE_SUCC, resp); resp.iActiveNanoSlotNum = slot; @@ -130,8 +93,10 @@ void Nanos::summonNano(CNSocket *sock, int slot, bool silent) { if (slot != -1 && skill != nullptr && skill->drainType == SkillDrainType::PASSIVE) { // passive buff effect resp.eCSTB___Add = 1; - std::vector affectedCombatants = applyNanoBuff(skill, plr); - if(!affectedCombatants.empty()) Abilities::useNanoSkill(sock, skill, nano, affectedCombatants); + ICombatant* src = dynamic_cast(plr); + int32_t targets[] = { plr->iID }; + std::vector affectedCombatants = Abilities::matchTargets(src, skill, 1, targets); + Abilities::useNanoSkill(sock, skill, nano, affectedCombatants); } if (!silent) // silent nano death but only for the summoning player @@ -312,7 +277,7 @@ static void nanoSkillUseHandler(CNSocket* sock, CNPacketData* data) { std::vector targetData = Abilities::matchTargets(plrCombatant, skillData, pkt->iTargetCnt, (int32_t*)(pkt + 1)); Abilities::useNanoSkill(sock, skillData, nano, targetData); - if (plr->Nanos[plr->activeNano].iStamina < 0) + if (plr->Nanos[plr->activeNano].iStamina <= 0) summonNano(sock, -1); } diff --git a/src/Nanos.hpp b/src/Nanos.hpp index b4a3955..e21a297 100644 --- a/src/Nanos.hpp +++ b/src/Nanos.hpp @@ -26,5 +26,4 @@ namespace Nanos { void summonNano(CNSocket* sock, int slot, bool silent = false); int nanoStyle(int nanoID); bool getNanoBoost(Player* plr); - std::vector applyNanoBuff(SkillData* skill, Player* plr); }