Compare commits

..

1 Commits

Author SHA1 Message Date
Gent Semaj
0b325f6f9f
Merge 9394825d41 into b12aecad63 2023-07-12 21:43:15 +00:00
4 changed files with 59 additions and 38 deletions

View File

@ -57,23 +57,6 @@ static SkillResult handleSkillDamageNDebuff(SkillData* skill, int power, ICombat
} }
static SkillResult handleSkillBuff(SkillData* skill, int power, ICombatant* source, ICombatant* target) { 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{}; sSkillResult_Buff result{};
result.eCT = target->getCharType(); result.eCT = target->getCharType();
result.iID = target->getID(); result.iID = target->getID();
@ -223,16 +206,14 @@ void Abilities::useNanoSkill(CNSocket* sock, SkillData* skill, sNano& nano, std:
if (Nanos::getNanoBoost(plr)) if (Nanos::getNanoBoost(plr))
boost = 3; boost = 3;
if(skill->drainType == SkillDrainType::ACTIVE) {
nano.iStamina -= skill->batteryUse[boost]; nano.iStamina -= skill->batteryUse[boost];
if (nano.iStamina <= 0) if (nano.iStamina < 0)
nano.iStamina = 0; nano.iStamina = 0;
}
std::vector<SkillResult> results = handleSkill(skill, boost, plr, affected); std::vector<SkillResult> results = handleSkill(skill, boost, plr, affected);
if(results.empty()) return; // no effect; no need for confirmation packets size_t resultSize = 0; // guaranteed to be the same for every item
if (!results.empty()) resultSize = results.back().size;
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)) { 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"; std::cout << "[WARN] bad sP_FE2CL_NANO_SKILL_USE_SUCC packet size\n";
return; return;
@ -260,6 +241,9 @@ void Abilities::useNanoSkill(CNSocket* sock, SkillData* skill, sNano& nano, std:
PlayerManager::sendToGroup(sock, pkt, P_FE2CL_NANO_SKILL_USE, resplen); PlayerManager::sendToGroup(sock, pkt, P_FE2CL_NANO_SKILL_USE, resplen);
else else
PlayerManager::sendToViewable(sock, pkt, P_FE2CL_NANO_SKILL_USE, resplen); 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) { void Abilities::useNPCSkill(EntityRef npc, int skillID, std::vector<ICombatant*> affected) {
@ -309,8 +293,14 @@ static std::vector<ICombatant*> entityRefsToCombatants(std::vector<EntityRef> re
std::vector<ICombatant*> Abilities::matchTargets(ICombatant* src, SkillData* skill, int count, int32_t *ids) { std::vector<ICombatant*> Abilities::matchTargets(ICombatant* src, SkillData* skill, int count, int32_t *ids) {
if(skill->targetType == SkillTargetType::GROUP) 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 {};
}
return entityRefsToCombatants(src->getGroupMembers()); return entityRefsToCombatants(src->getGroupMembers());
}
// this check *has* to happen after the group check above due to cases like group recall that use both // this check *has* to happen after the group check above due to cases like group recall that use both
if(skill->effectTarget == SkillEffectTarget::SELF) if(skill->effectTarget == SkillEffectTarget::SELF)
@ -403,8 +393,6 @@ int Abilities::getCSTBFromST(SkillType skillType) {
case SkillType::NANOSTIMPAK: case SkillType::NANOSTIMPAK:
result = ECSB_STIMPAKSLOT1; result = ECSB_STIMPAKSLOT1;
break; break;
default:
break;
} }
return result; return result;
} }

View File

@ -874,12 +874,9 @@ static void playerTick(CNServer *serv, time_t currTime) {
if (Abilities::SkillTable.find(nano->iSkillID) != Abilities::SkillTable.end()) { if (Abilities::SkillTable.find(nano->iSkillID) != Abilities::SkillTable.end()) {
// nano has skill data // nano has skill data
SkillData* skill = &Abilities::SkillTable[nano->iSkillID]; SkillData* skill = &Abilities::SkillTable[nano->iSkillID];
if (skill->drainType == SkillDrainType::PASSIVE) { if (skill->drainType == SkillDrainType::PASSIVE)
ICombatant* src = dynamic_cast<ICombatant*>(plr); Nanos::applyNanoBuff(skill, plr);
int32_t targets[] = { plr->iID }; // ^ composite condition calculation is separate from combat for responsiveness
std::vector<ICombatant*> affectedCombatants = Abilities::matchTargets(src, skill, 1, targets);
Abilities::useNanoSkill(sock, skill, *nano, affectedCombatants);
}
} }
} }

View File

@ -69,6 +69,43 @@ void Nanos::addNano(CNSocket* sock, int16_t nanoID, int16_t slot, bool spendfm)
PlayerManager::sendToViewable(sock, resp2, P_FE2CL_REP_PC_CHANGE_LEVEL); 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) { void Nanos::summonNano(CNSocket *sock, int slot, bool silent) {
INITSTRUCT(sP_FE2CL_REP_NANO_ACTIVE_SUCC, resp); INITSTRUCT(sP_FE2CL_REP_NANO_ACTIVE_SUCC, resp);
resp.iActiveNanoSlotNum = slot; resp.iActiveNanoSlotNum = slot;
@ -93,10 +130,8 @@ void Nanos::summonNano(CNSocket *sock, int slot, bool silent) {
if (slot != -1 && skill != nullptr && skill->drainType == SkillDrainType::PASSIVE) { if (slot != -1 && skill != nullptr && skill->drainType == SkillDrainType::PASSIVE) {
// passive buff effect // passive buff effect
resp.eCSTB___Add = 1; resp.eCSTB___Add = 1;
ICombatant* src = dynamic_cast<ICombatant*>(plr); std::vector<ICombatant*> affectedCombatants = applyNanoBuff(skill, plr);
int32_t targets[] = { plr->iID }; if(!affectedCombatants.empty()) Abilities::useNanoSkill(sock, skill, nano, affectedCombatants);
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 if (!silent) // silent nano death but only for the summoning player
@ -277,7 +312,7 @@ static void nanoSkillUseHandler(CNSocket* sock, CNPacketData* data) {
std::vector<ICombatant*> targetData = Abilities::matchTargets(plrCombatant, skillData, pkt->iTargetCnt, (int32_t*)(pkt + 1)); std::vector<ICombatant*> targetData = Abilities::matchTargets(plrCombatant, skillData, pkt->iTargetCnt, (int32_t*)(pkt + 1));
Abilities::useNanoSkill(sock, skillData, nano, targetData); Abilities::useNanoSkill(sock, skillData, nano, targetData);
if (plr->Nanos[plr->activeNano].iStamina <= 0) if (plr->Nanos[plr->activeNano].iStamina < 0)
summonNano(sock, -1); summonNano(sock, -1);
} }

View File

@ -26,4 +26,5 @@ namespace Nanos {
void summonNano(CNSocket* sock, int slot, bool silent = false); void summonNano(CNSocket* sock, int slot, bool silent = false);
int nanoStyle(int nanoID); int nanoStyle(int nanoID);
bool getNanoBoost(Player* plr); bool getNanoBoost(Player* plr);
std::vector<ICombatant*> applyNanoBuff(SkillData* skill, Player* plr);
} }