[WIP] Active power handling

TODO:
- recall (self and group) is broken
- revive (only group) is broken
- damage + debuff is unimplemented
This commit is contained in:
gsemaj 2022-11-27 17:36:47 -05:00 committed by gsemaj
parent 829f75112c
commit 74588f2c77
No known key found for this signature in database
GPG Key ID: 24B96BAA40497929
3 changed files with 50 additions and 37 deletions

View File

@ -35,7 +35,8 @@ static SkillResult handleSkillDamage(SkillData* skill, int power, ICombatant* so
static SkillResult handleSkillHealHP(SkillData* skill, int power, ICombatant* source, ICombatant* target) { static SkillResult handleSkillHealHP(SkillData* skill, int power, ICombatant* source, ICombatant* target) {
EntityRef sourceRef = source->getRef(); EntityRef sourceRef = source->getRef();
int heal = skill->values[0][power]; int heal = skill->values[0][power];
int healed = target->heal(sourceRef, heal); double scalingFactor = target->getMaxHP() / 1000.0;
int healed = target->heal(sourceRef, heal * scalingFactor);
sSkillResult_Heal_HP result{}; sSkillResult_Heal_HP result{};
result.eCT = target->getCharType(); result.eCT = target->getCharType();
@ -97,6 +98,7 @@ static SkillResult handleSkillMove(SkillData* skill, int power, ICombatant* sour
if(source->getCharType() != 1) if(source->getCharType() != 1)
return SkillResult(); // only Players are valid sources for recall return SkillResult(); // only Players are valid sources for recall
Player* plr = dynamic_cast<Player*>(source); Player* plr = dynamic_cast<Player*>(source);
PlayerManager::sendPlayerTo(source->getRef().sock, plr->recallX, plr->recallY, plr->recallZ, plr->recallInstance);
sSkillResult_Move result{}; sSkillResult_Move result{};
result.eCT = target->getCharType(); result.eCT = target->getCharType();
@ -154,20 +156,22 @@ static std::vector<SkillResult> handleSkill(SkillData* skill, int power, ICombat
resultSize = sizeof(sSkillResult_BatteryDrain); resultSize = sizeof(sSkillResult_BatteryDrain);
skillHandler = handleSkillBatteryDrain; skillHandler = handleSkillBatteryDrain;
break; break;
case EST_RECALL: case EST_RECALL: // still soft lock
case EST_RECALL_GROUP: case EST_RECALL_GROUP: // works for player who uses it
resultSize = sizeof(sSkillResult_Move); resultSize = sizeof(sSkillResult_Move);
skillHandler = handleSkillMove; skillHandler = handleSkillMove;
break; break;
case EST_PHOENIX_GROUP: case EST_PHOENIX_GROUP: // broken
resultSize = sizeof(sSkillResult_Resurrect); resultSize = sizeof(sSkillResult_Resurrect);
skillHandler = handleSkillResurrect; skillHandler = handleSkillResurrect;
break; break;
case EST_RETROROCKET_SELF:
// no-op
return results;
default: default:
std::cout << "[WARN] Unhandled skill type " << skill->skillType << std::endl; std::cout << "[WARN] Unhandled skill type " << skill->skillType << std::endl;
return results; return results;
} }
assert(skillHandler != nullptr);
for(ICombatant* target : targets) { for(ICombatant* target : targets) {
assert(target != nullptr); assert(target != nullptr);
@ -189,15 +193,21 @@ static void attachSkillResults(std::vector<SkillResult> results, size_t resultSi
} }
} }
void Abilities::useNanoSkill(CNSocket* sock, sNano& nano, std::vector<ICombatant*> affected) { void Abilities::useNanoSkill(CNSocket* sock, SkillData* skill, sNano& nano, std::vector<ICombatant*> affected) {
if(SkillTable.count(nano.iSkillID) == 0)
return;
SkillData* skill = &SkillTable[nano.iSkillID];
Player* plr = PlayerManager::getPlayer(sock); Player* plr = PlayerManager::getPlayer(sock);
std::vector<SkillResult> results = handleSkill(skill, Nanos::getNanoBoost(plr), plr, affected); int boost = 0;
size_t resultSize = results.back().size; // guaranteed to be the same for every item if (Nanos::getNanoBoost(plr))
boost = 3;
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 (!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";
@ -221,6 +231,9 @@ void Abilities::useNanoSkill(CNSocket* sock, sNano& nano, std::vector<ICombatant
attachSkillResults(results, resultSize, (uint8_t*)(pkt + 1)); attachSkillResults(results, resultSize, (uint8_t*)(pkt + 1));
sock->sendPacket(pkt, P_FE2CL_NANO_SKILL_USE_SUCC, resplen); sock->sendPacket(pkt, P_FE2CL_NANO_SKILL_USE_SUCC, resplen);
PlayerManager::sendToViewable(sock, pkt, P_FE2CL_NANO_SKILL_USE_SUCC, resplen); PlayerManager::sendToViewable(sock, pkt, P_FE2CL_NANO_SKILL_USE_SUCC, 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) {
@ -257,21 +270,30 @@ void Abilities::useNPCSkill(EntityRef npc, int skillID, std::vector<ICombatant*>
NPCManager::sendToViewable(entity, pkt, P_FE2CL_NPC_SKILL_HIT, resplen); NPCManager::sendToViewable(entity, pkt, P_FE2CL_NPC_SKILL_HIT, resplen);
} }
std::vector<EntityRef> Abilities::matchTargets(SkillData* skill, int count, int32_t *ids) { std::vector<ICombatant*> Abilities::matchTargets(SkillData* skill, int count, int32_t *ids) {
std::vector<EntityRef> targets; std::vector<ICombatant*> targets;
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
int32_t id = ids[i]; int32_t id = ids[i];
if (skill->targetType == SkillTargetType::MOBS) { if (skill->targetType == SkillTargetType::MOBS) {
// mob? // mob
if (NPCManager::NPCs.find(id) != NPCManager::NPCs.end()) targets.push_back(id); if (NPCManager::NPCs.find(id) != NPCManager::NPCs.end()) {
else std::cout << "[WARN] skill: id not found\n"; BaseNPC* npc = NPCManager::NPCs[id];
} else { if (npc->kind == EntityKind::COMBAT_NPC || npc->kind == EntityKind::MOB) {
// player? targets.push_back(dynamic_cast<ICombatant*>(npc));
CNSocket* sock = PlayerManager::getSockFromID(id); continue;
if (sock != nullptr) targets.push_back(sock); }
else std::cout << "[WARN] skill: sock not found\n"; }
std::cout << "[WARN] skill: invalid mob target (id " << id << ")\n";
} else if(skill->targetType == SkillTargetType::SELF || skill->targetType == SkillTargetType::GROUP) {
// players (?)
Player* plr = PlayerManager::getPlayerFromID(id);
if (plr != nullptr) {
targets.push_back(dynamic_cast<ICombatant*>(plr));
continue;
}
std::cout << "[WARN] skill: invalid player target (id " << id << ")\n";
} }
} }

View File

@ -60,9 +60,9 @@ struct SkillData {
namespace Abilities { namespace Abilities {
extern std::map<int32_t, SkillData> SkillTable; extern std::map<int32_t, SkillData> SkillTable;
void useNanoSkill(CNSocket*, sNano&, std::vector<ICombatant*>); void useNanoSkill(CNSocket*, SkillData*, sNano&, std::vector<ICombatant*>);
void useNPCSkill(EntityRef, int skillID, std::vector<ICombatant*>); void useNPCSkill(EntityRef, int skillID, std::vector<ICombatant*>);
std::vector<EntityRef> matchTargets(SkillData*, int, int32_t*); std::vector<ICombatant*> matchTargets(SkillData*, int, int32_t*);
int getCSTBFromST(int eSkillType); int getCSTBFromST(int eSkillType);
} }

View File

@ -140,7 +140,7 @@ void Nanos::summonNano(CNSocket *sock, int slot, bool silent) {
// passive buff effect // passive buff effect
resp.eCSTB___Add = 1; resp.eCSTB___Add = 1;
std::vector<ICombatant*> affectedCombatants = applyNanoBuff(skill, plr); std::vector<ICombatant*> affectedCombatants = applyNanoBuff(skill, plr);
if(!affectedCombatants.empty()) Abilities::useNanoSkill(sock, nano, affectedCombatants); if(!affectedCombatants.empty()) 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
@ -309,26 +309,17 @@ static void nanoSkillUseHandler(CNSocket* sock, CNPacketData* data) {
return; return;
} }
int16_t skillID = plr->Nanos[plr->activeNano].iSkillID; sNano& nano = plr->Nanos[plr->activeNano];
int16_t skillID = nano.iSkillID;
SkillData* skillData = &Abilities::SkillTable[skillID]; SkillData* skillData = &Abilities::SkillTable[skillID];
DEBUGLOG( DEBUGLOG(
std::cout << PlayerManager::getPlayerName(plr) << " requested to summon nano skill " << std::endl; std::cout << PlayerManager::getPlayerName(plr) << " requested to summon nano skill " << std::endl;
) )
int boost = 0;
if (getNanoBoost(plr))
boost = 1;
plr->Nanos[plr->activeNano].iStamina -= Abilities::SkillTable[skillID].batteryUse[boost*3];
if (plr->Nanos[plr->activeNano].iStamina < 0)
plr->Nanos[plr->activeNano].iStamina = 0;
// TODO ABILITIES // TODO ABILITIES
std::vector<EntityRef> targetData = Abilities::matchTargets(skillData, pkt->iTargetCnt, (int32_t*)(pkt + 1)); std::vector<ICombatant*> targetData = Abilities::matchTargets(skillData, pkt->iTargetCnt, (int32_t*)(pkt + 1));
/*for (auto& pwr : Abilities::Powers) Abilities::useNanoSkill(sock, skillData, nano, targetData);
if (pwr.skillType == Abilities::SkillTable[skillID].skillType)
pwr.handle(sock, targetData, nanoID, skillID, Abilities::SkillTable[skillID].durationTime[boost], Abilities::SkillTable[skillID].powerIntensity[boost]);*/
if (plr->Nanos[plr->activeNano].iStamina < 0) if (plr->Nanos[plr->activeNano].iStamina < 0)
summonNano(sock, -1); summonNano(sock, -1);