diff --git a/src/Abilities.cpp b/src/Abilities.cpp index a94f69e..ed29699 100644 --- a/src/Abilities.cpp +++ b/src/Abilities.cpp @@ -270,10 +270,30 @@ void Abilities::useNPCSkill(EntityRef npc, int skillID, std::vector NPCManager::sendToViewable(entity, pkt, P_FE2CL_NPC_SKILL_HIT, resplen); } -std::vector Abilities::matchTargets(SkillData* skill, int count, int32_t *ids) { +static std::vector entityRefsToCombatants(std::vector refs) { + std::vector combatants; + for(EntityRef ref : refs) { + if(ref.kind == EntityKind::PLAYER) + combatants.push_back(dynamic_cast(PlayerManager::getPlayer(ref.sock))); + else if(ref.kind == EntityKind::COMBAT_NPC || ref.kind == EntityKind::MOB) + combatants.push_back(dynamic_cast(ref.getEntity())); + } + return combatants; +} +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 {}; + } + return entityRefsToCombatants(src->getGroupMembers()); + } + + // individuals std::vector targets; - for (int i = 0; i < count; i++) { int32_t id = ids[i]; if (skill->targetType == SkillTargetType::MOBS) { @@ -286,8 +306,8 @@ std::vector Abilities::matchTargets(SkillData* skill, int count, in } } std::cout << "[WARN] skill: invalid mob target (id " << id << ")\n"; - } else if(skill->targetType == SkillTargetType::SELF || skill->targetType == SkillTargetType::GROUP) { - // players (?) + } else if(skill->targetType == SkillTargetType::PLAYERS) { + // player Player* plr = PlayerManager::getPlayerFromID(id); if (plr != nullptr) { targets.push_back(dynamic_cast(plr)); diff --git a/src/Abilities.hpp b/src/Abilities.hpp index 04680b9..c8d8ee1 100644 --- a/src/Abilities.hpp +++ b/src/Abilities.hpp @@ -21,7 +21,7 @@ enum class SkillEffectTarget { enum class SkillTargetType { MOBS = 1, - SELF = 2, + PLAYERS = 2, GROUP = 3 }; @@ -63,6 +63,6 @@ namespace Abilities { void useNanoSkill(CNSocket*, SkillData*, sNano&, std::vector); void useNPCSkill(EntityRef, int skillID, std::vector); - std::vector matchTargets(SkillData*, int, int32_t*); + std::vector matchTargets(ICombatant*, SkillData*, int, int32_t*); int getCSTBFromST(int eSkillType); } diff --git a/src/Eggs.cpp b/src/Eggs.cpp index 1aa9ef4..04e276d 100644 --- a/src/Eggs.cpp +++ b/src/Eggs.cpp @@ -29,7 +29,7 @@ void Eggs::eggBuffPlayer(CNSocket* sock, int skillId, int eggId, int duration) { SkillData* skill = &Abilities::SkillTable[skillId]; if(skill->drainType == SkillDrainType::PASSIVE) { // apply buff - if(skill->targetType != SkillTargetType::SELF) { + if(skill->targetType != SkillTargetType::PLAYERS) { std::cout << "[WARN] weird skill type for egg " << eggId << " with skill " << skillId << ", should be " << (int)skill->targetType << std::endl; } diff --git a/src/Nanos.cpp b/src/Nanos.cpp index 03fae57..0c47219 100644 --- a/src/Nanos.cpp +++ b/src/Nanos.cpp @@ -73,16 +73,6 @@ std::vector Nanos::applyNanoBuff(SkillData* skill, Player* plr) { assert(skill->drainType == SkillDrainType::PASSIVE); EntityRef self = PlayerManager::getSockFromID(plr->iID); - std::vector affected; - std::vector targets; - if (skill->targetType == SkillTargetType::GROUP) { - targets = plr->getGroupMembers(); // group - } - else if(skill->targetType == SkillTargetType::SELF) { - targets.push_back(self); // self - } else { - std::cout << "[WARN] Passive skill with type " << skill->skillType << " has target type MOB" << std::endl; - } int timeBuffId = Abilities::getCSTBFromST(skill->skillType); int boost = Nanos::getNanoBoost(plr) ? 3 : 0; @@ -95,21 +85,22 @@ std::vector Nanos::applyNanoBuff(SkillData* skill, Player* plr) { BuffClass::NONE, // overwritten per target }; - for (EntityRef target : targets) { - Entity* entity = target.getEntity(); - if (entity->kind != PLAYER && entity->kind != COMBAT_NPC && entity->kind != MOB) - continue; // not a combatant + // 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 == self ? BuffClass::NANO : BuffClass::GROUP_NANO; - ICombatant* combatant = dynamic_cast(entity); - if(combatant->addBuff(timeBuffId, + 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(combatant); + &passiveBuff)) affected.push_back(target); } return affected; @@ -317,8 +308,8 @@ static void nanoSkillUseHandler(CNSocket* sock, CNPacketData* data) { std::cout << PlayerManager::getPlayerName(plr) << " requested to summon nano skill " << std::endl; ) - // TODO ABILITIES - std::vector targetData = Abilities::matchTargets(skillData, pkt->iTargetCnt, (int32_t*)(pkt + 1)); + ICombatant* plrCombatant = dynamic_cast(plr); + 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) diff --git a/src/PlayerManager.cpp b/src/PlayerManager.cpp index a4c4865..dfd0e5a 100644 --- a/src/PlayerManager.cpp +++ b/src/PlayerManager.cpp @@ -401,12 +401,11 @@ static void revivePlayer(CNSocket* sock, CNPacketData* data) { if (!(plr->hasBuff(ECSB_PHOENIX))) return; // sanity check plr->Nanos[plr->activeNano].iStamina = 0; - // TODO ABILITIES - //Abilities::applyBuff(sock, plr->Nanos[plr->activeNano].iSkillID, 2, 1, 0); // fallthrough case ePCRegenType::HereByPhoenixGroup: // revived by group member's nano plr->HP = PC_MAXHEALTH(plr->level) / 2; break; + default: // plain respawn plr->HP = PC_MAXHEALTH(plr->level) / 2; // fallthrough