Reuse `useNanoSkill` codepath for passive powers

This commit is contained in:
gsemaj 2023-07-20 17:53:13 -04:00
parent 9394825d41
commit 9b7656117d
No known key found for this signature in database
GPG Key ID: 24B96BAA40497929
4 changed files with 38 additions and 59 deletions

View File

@ -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<SkillResult> 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<ICombatant*> affected) {
@ -293,14 +309,8 @@ static std::vector<ICombatant*> entityRefsToCombatants(std::vector<EntityRef> re
std::vector<ICombatant*> 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;
}

View File

@ -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<ICombatant*>(plr);
int32_t targets[] = { plr->iID };
std::vector<ICombatant*> affectedCombatants = Abilities::matchTargets(src, skill, 1, targets);
Abilities::useNanoSkill(sock, skill, *nano, affectedCombatants);
}
}
}

View File

@ -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<ICombatant*> 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<ICombatant*> targets = Abilities::matchTargets(dynamic_cast<ICombatant*>(plr), skill, 1, &plr->iID);
std::vector<ICombatant*> 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<ICombatant*> affectedCombatants = applyNanoBuff(skill, plr);
if(!affectedCombatants.empty()) Abilities::useNanoSkill(sock, skill, nano, affectedCombatants);
ICombatant* src = dynamic_cast<ICombatant*>(plr);
int32_t targets[] = { plr->iID };
std::vector<ICombatant*> 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<ICombatant*> 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);
}

View File

@ -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<ICombatant*> applyNanoBuff(SkillData* skill, Player* plr);
}