diff --git a/src/NanoManager.cpp b/src/NanoManager.cpp index 4ce4844..80ecbca 100644 --- a/src/NanoManager.cpp +++ b/src/NanoManager.cpp @@ -5,6 +5,39 @@ #include "NPCManager.hpp" #include "CombatManager.hpp" +namespace NanoManager { + +// active powers +std::set StunPowers = {1, 13, 42, 59, 78, 103}; +std::set HealPowers = {2, 7, 12, 38, 53, 61, 82, 92, 98}; +std::set RecallPowers = {5, 25, 66, 69, 75, 87}; +std::set DrainPowers = {10, 34, 37, 56, 93, 97}; +std::set SnarePowers = {17, 18, 27, 41, 43, 47, 90, 96, 106}; +std::set DamagePowers = {19, 21, 33, 45, 46, 52, 101, 105, 108}; +std::set GroupRevivePowers = {20, 63, 91}; +std::set LeechPowers = {24, 51, 89}; +std::set SleepPowers = {28, 30, 32, 49, 70, 71, 81, 85, 94}; + +// passive powers +std::set ScavangePowers = {3, 50, 99}; +std::set RunPowers = {4, 8, 62, 68, 73, 86}; +std::set BonusPowers = {6, 54, 104}; +std::set GuardPowers = {9, 57, 76}; +std::set RadarPowers = {11, 67, 95}; +std::set AnitdotePowers = {14, 58, 102}; +std::set FreedomPowers = {15, 31, 39, 55, 77, 107}; +std::set JumpPowers = {16, 35, 44, 60, 88, 100}; +std::set SelfRevivePowers = {22, 48, 83}; +std::set SneakPowers = {23, 29, 65, 72, 80, 82}; +std::set TreasureFinderPowers = {26, 40, 74}; + +/* + * The active nano power table is down below activePower<>() and its + * worker functions so we don't have to have unsightly function declarations. + */ + +}; // namespace + void NanoManager::init() { REGISTER_SHARD_PACKET(P_CL2FE_REQ_NANO_ACTIVE, nanoSummonHandler); REGISTER_SHARD_PACKET(P_CL2FE_REQ_NANO_EQUIP, nanoEquipHandler); @@ -97,31 +130,13 @@ void NanoManager::nanoSummonHandler(CNSocket* sock, CNPacketData* data) { } void NanoManager::nanoSkillUseHandler(CNSocket* sock, CNPacketData* data) { - //if (data->size != sizeof(sP_CL2FE_REQ_NANO_SKILL_USE)) - // return; // malformed packet - Player *plr = PlayerManager::getPlayer(sock); int16_t nanoId = plr->activeNano; int16_t skillId = plr->Nanos[nanoId].iSkillID; - - if (skillId == 1 || skillId == 13 || skillId == 42 || skillId == 59 || skillId == 78 || skillId == 103) - nanoDebuff(sock, data, nanoId, skillId, 8, 512); // Stun - else if (skillId == 2 || skillId == 7 || skillId == 12 || skillId == 38 || skillId == 53 || skillId == 61 || skillId == 82 || skillId == 92 || skillId == 98 ) - nanoHeal(sock, data, nanoId, skillId, 333); // Heal - else if (skillId == 5 || skillId == 25 || skillId == 66 || skillId == 69 || skillId == 75 || skillId == 87) { - // Recall - } else if (skillId == 10 || skillId == 34 || skillId == 37 || skillId == 56 || skillId == 93 || skillId == 97) - nanoDebuff(sock, data, nanoId, skillId, 3, 262144); // Drain - else if (skillId == 17 || skillId == 18 || skillId == 27 || skillId == 41 || skillId == 43 || skillId == 47 || skillId == 90 || skillId == 96 || skillId == 106) - nanoDebuff(sock, data, nanoId, skillId, 5, 128); // Snare - else if (skillId == 19 || skillId == 21 || skillId == 33 || skillId == 45 || skillId == 46 || skillId == 52 || skillId == 101 || skillId == 105 || skillId == 108) - nanoDamage(sock, data, nanoId, skillId, 133); // Damage - else if (skillId == 20 || skillId == 63 || skillId == 91) { - // Group Revive - } else if (skillId == 24 || skillId == 51 || skillId == 89) { - nanoLeech(sock, data, nanoId, skillId, 133); // Leech - } else if (skillId == 28 || skillId == 30 || skillId == 32 || skillId == 49 || skillId == 70 || skillId == 71 || skillId == 81 || skillId == 85 || skillId == 94) - nanoDebuff(sock, data, nanoId, skillId, 4, 1024); // Sleep + + for (auto& pwr : ActivePowers) + if (pwr.powers.count(skillId)) // std::set's contains method is C++20 only... + pwr.handle(sock, data, nanoId, skillId); DEBUGLOG( std::cout << U16toU8(plr->PCStyle.szFirstName) << U16toU8(plr->PCStyle.szLastName) << " requested to summon nano skill " << std::endl; @@ -328,127 +343,187 @@ void NanoManager::resetNanoSkill(CNSocket* sock, int16_t nanoId) { nano.iSkillID = 0; plr->Nanos[nanoId] = nano; } +#pragma endregion -// this is where the fun begins -void NanoManager::nanoDebuff(CNSocket* sock, CNPacketData* data, int16_t nanoId, int16_t skillId, int16_t eSkillType, int32_t iCBFlag, int32_t damageAmount) { - sP_CL2FE_REQ_NANO_SKILL_USE* pkt = (sP_CL2FE_REQ_NANO_SKILL_USE*)data->buf; +#pragma region Active Powers +namespace NanoManager { - // sanity check - if (!validInVarPacket(sizeof(sP_CL2FE_REQ_NANO_SKILL_USE), pkt->iTargetCnt, sizeof(int32_t), data->size)) { - std::cout << "[WARN] bad sP_CL2FE_REQ_NANO_SKILL_USE packet size\n"; - return; +bool doDebuff(CNSocket *sock, int32_t *pktdata, sSkillResult_Damage_N_Debuff *respdata, int i, int16_t iCBFlag, int32_t amount) { + if (NPCManager::NPCs.find(pktdata[i]) == NPCManager::NPCs.end()) { + // not sure how to best handle this + std::cout << "[WARN] nanoDebuffEnemy: mob ID not found" << std::endl; + return false; } - int32_t *pktdata = (int32_t*)((uint8_t*)data->buf + sizeof(sP_CL2FE_REQ_NANO_SKILL_USE)); + BaseNPC& mob = NPCManager::NPCs[pktdata[i]]; + + mob.appearanceData.iHP -= amount; - /* - * Due to the possibility of multiplication overflow (and regular buffer overflow), - * both incoming and outgoing variable-length packets must be validated, at least if - * the number of trailing structs isn't well known (ie. it's from the client). - */ - if (!validOutVarPacket(sizeof(sP_FE2CL_NANO_SKILL_USE), pkt->iTargetCnt, sizeof(sSkillResult_Damage_N_Debuff))) { - std::cout << "[WARN] bad sP_FE2CL_NANO_SKILL_USE packet size\n"; - return; - } + if (mob.appearanceData.iHP <= 0) + CombatManager::giveReward(sock); - size_t resplen = sizeof(sP_FE2CL_NANO_SKILL_USE) + pkt->iTargetCnt * sizeof(sSkillResult_Damage_N_Debuff); - uint8_t respbuf[4096]; - - memset(respbuf, 0, resplen); - - sP_FE2CL_NANO_SKILL_USE *resp = (sP_FE2CL_NANO_SKILL_USE*)respbuf; - sSkillResult_Damage_N_Debuff *respdata = (sSkillResult_Damage_N_Debuff*)(respbuf+sizeof(sP_FE2CL_NANO_SKILL_USE)); - - Player *plr = PlayerManager::getPlayer(sock); - - resp->iPC_ID = plr->iID; - resp->iSkillID = skillId; - resp->iNanoID = nanoId; - resp->iNanoStamina = 150; - resp->eST = eSkillType; - resp->iTargetCnt = pkt->iTargetCnt; - - for (int i = 0; i < pkt->iTargetCnt; i++) { - if (NPCManager::NPCs.find(pktdata[i]) == NPCManager::NPCs.end()) { - // not sure how to best handle this - std::cout << "[WARN] nanoDebuffEnemy: mob ID not found" << std::endl; - return; + respdata[i].eCT = 4; + respdata[i].iDamage = amount; + respdata[i].iID = mob.appearanceData.iNPC_ID; + respdata[i].iHP = mob.appearanceData.iHP; + respdata[i].iConditionBitFlag = iCBFlag; + + std::cout << (int)mob.appearanceData.iNPC_ID << " was debuffed" << std::endl; + + return true; +} + +bool doHeal(CNSocket *sock, int32_t *pktdata, sSkillResult_Heal_HP *respdata, int i, int16_t iCBFlag, int32_t amount) { + Player *plr = nullptr; + + for (auto& pair : PlayerManager::players) { + if (pair.second.plr->iID == pktdata[i]) { + plr = pair.second.plr; + break; } - BaseNPC& mob = NPCManager::NPCs[pktdata[i]]; - - mob.appearanceData.iHP -= damageAmount; - - if (mob.appearanceData.iHP <= 0) - CombatManager::giveReward(sock); - - respdata[i].eCT = 4; - respdata[i].iDamage = damageAmount; - respdata[i].iID = mob.appearanceData.iNPC_ID; - respdata[i].iHP = mob.appearanceData.iHP; - respdata[i].iConditionBitFlag = iCBFlag; - std::cout << (int)mob.appearanceData.iNPC_ID << " was debuffed" << std::endl; } - sock->sendPacket((void*)&respbuf, P_FE2CL_NANO_SKILL_USE_SUCC, resplen); - for (CNSocket* s : PlayerManager::players[sock].viewable) - s->sendPacket((void*)&respbuf, P_FE2CL_NANO_SKILL_USE, resplen); + if (plr == nullptr) + return false; + + if (plr->HP + amount > PC_MAXHEALTH(plr->level)) + plr->HP = PC_MAXHEALTH(plr->level); + else + plr->HP += amount; + + respdata[i].eCT = 1; + respdata[i].iID = plr->iID; + respdata[i].iHP = plr->HP; + respdata[i].iHealHP = amount; + + std::cout << (int)plr->iID << " was healed" << std::endl; + + return true; } -void NanoManager::nanoHeal(CNSocket* sock, CNPacketData* data, int16_t nanoId, int16_t skillId, int16_t healAmount) { - sP_CL2FE_REQ_NANO_SKILL_USE* pkt = (sP_CL2FE_REQ_NANO_SKILL_USE*)data->buf; +bool doDamage(CNSocket *sock, int32_t *pktdata, sSkillResult_Damage *respdata, int i, int16_t iCBFlag, int32_t amount) { + if (NPCManager::NPCs.find(pktdata[i]) == NPCManager::NPCs.end()) { + // not sure how to best handle this + std::cout << "[WARN] nanoDebuffEnemy: mob ID not found" << std::endl; + return false; + } + BaseNPC& mob = NPCManager::NPCs[pktdata[i]]; + + mob.appearanceData.iHP -= amount; + + if (mob.appearanceData.iHP <= 0) + CombatManager::giveReward(sock); + + respdata[i].eCT = 4; + respdata[i].iDamage = amount; + respdata[i].iID = mob.appearanceData.iNPC_ID; + respdata[i].iHP = mob.appearanceData.iHP; + + std::cout << (int)mob.appearanceData.iNPC_ID << " was damaged" << std::endl; + + return true; +} + +/* + * NOTE: Leech is specially encoded. + * + * It manages to fit inside the activePower<>() mold with only a slight hack, + * but it really is it's own thing. There is a hard assumption that players + * will only every leech a single mob, and the sanity check that enforces that + * assumption is critical. + */ +bool doLeech(CNSocket *sock, int32_t *pktdata, sSkillResult_Heal_HP *healdata, int i, int16_t iCBFlag, int32_t amount) { + // this sanity check is VERY important + if (i != 0) { + std::cout << "[WARN] Player attempted to leech more than one mob!" << std::endl; + return false; + } + + sSkillResult_Damage *damagedata = (sSkillResult_Damage*)(((uint8_t*)healdata) + sizeof(sSkillResult_Heal_HP)); Player *plr = PlayerManager::getPlayer(sock); - // sanity check + if (plr->HP + amount > PC_MAXHEALTH(plr->level)) + plr->HP = PC_MAXHEALTH(plr->level); + else + plr->HP += amount; + + healdata->eCT = 1; + healdata->iID = plr->iID; + healdata->iHP = plr->HP; + healdata->iHealHP = amount; + + if (NPCManager::NPCs.find(pktdata[i]) == NPCManager::NPCs.end()) { + // not sure how to best handle this + std::cout << "[WARN] doLeech: mob ID not found" << std::endl; + return false; + } + BaseNPC& mob = NPCManager::NPCs[pktdata[i]]; + + mob.appearanceData.iHP -= amount; + + if (mob.appearanceData.iHP <= 0) + CombatManager::giveReward(sock); + + damagedata->eCT = 4; + damagedata->iDamage = amount; + damagedata->iID = mob.appearanceData.iNPC_ID; + damagedata->iHP = mob.appearanceData.iHP; + + std::cout << (int)mob.appearanceData.iNPC_ID << " was leeched" << std::endl; + + return true; +} + +template +void activePower(CNSocket *sock, CNPacketData *data, + int16_t nanoId, int16_t skillId, SkillType eSkillType, + int32_t iCBFlag, int32_t amount) { + + sP_CL2FE_REQ_NANO_SKILL_USE* pkt = (sP_CL2FE_REQ_NANO_SKILL_USE*)data->buf; + + // validate request check if (!validInVarPacket(sizeof(sP_CL2FE_REQ_NANO_SKILL_USE), pkt->iTargetCnt, sizeof(int32_t), data->size)) { - std::cout << "[WARN] bad sP_CL2FE_REQ_NANO_SKILL_USE packet size\n"; + std::cout << "[WARN] bad sP_CL2FE_REQ_NANO_SKILL_USE packet size" << std::endl; return; } int32_t *pktdata = (int32_t*)((uint8_t*)data->buf + sizeof(sP_CL2FE_REQ_NANO_SKILL_USE)); - /* - * Due to the possibility of multiplication overflow (and regular buffer overflow), - * both incoming and outgoing variable-length packets must be validated, at least if - * the number of trailing structs isn't well known (ie. it's from the client). - */ - if (!validOutVarPacket(sizeof(sP_FE2CL_NANO_SKILL_USE), pkt->iTargetCnt, sizeof(sSkillResult_Heal_HP))) { - std::cout << "[WARN] bad sP_FE2CL_NANO_SKILL_USE packet size\n"; + // validate response packet + if (!validOutVarPacket(sizeof(sP_FE2CL_NANO_SKILL_USE_SUCC), pkt->iTargetCnt, sizeof(sPAYLOAD))) { + std::cout << "[WARN] bad sP_FE2CL_NANO_SKILL_USE packet size" << std::endl; return; } - - size_t resplen = sizeof(sP_FE2CL_NANO_SKILL_USE) + pkt->iTargetCnt * sizeof(sSkillResult_Heal_HP); - uint8_t respbuf[4096]; - + + size_t resplen; + + // special case since leech is atypically encoded + if constexpr (isLeech) + resplen = sizeof(sP_FE2CL_NANO_SKILL_USE_SUCC) + sizeof(sSkillResult_Heal_HP) + sizeof(sSkillResult_Damage); + else + resplen = sizeof(sP_FE2CL_NANO_SKILL_USE_SUCC) + pkt->iTargetCnt * sizeof(sPAYLOAD); + + uint8_t respbuf[CN_PACKET_BUFFER_SIZE]; + memset(respbuf, 0, resplen); + + sP_FE2CL_NANO_SKILL_USE_SUCC *resp = (sP_FE2CL_NANO_SKILL_USE_SUCC*)respbuf; + sPAYLOAD *respdata = (sPAYLOAD*)(respbuf+sizeof(sP_FE2CL_NANO_SKILL_USE_SUCC)); - sP_FE2CL_NANO_SKILL_USE *resp = (sP_FE2CL_NANO_SKILL_USE*)respbuf; - sSkillResult_Heal_HP *respdata = (sSkillResult_Heal_HP*)(respbuf+sizeof(sP_FE2CL_NANO_SKILL_USE)); + Player *plr = PlayerManager::getPlayer(sock); resp->iPC_ID = plr->iID; resp->iSkillID = skillId; resp->iNanoID = nanoId; resp->iNanoStamina = 150; - resp->eST = 2; //heal enum TODO: Send these enums to Defines + resp->eST = (int32_t)eSkillType; resp->iTargetCnt = pkt->iTargetCnt; - - for (int i = 0; i < pkt->iTargetCnt; i++) { - for (auto pair : PlayerManager::players) { - if (pair.second.plr->iID == pktdata[i]) { - Player* plr = pair.second.plr; - - if (plr->HP + healAmount > 3625) - plr->HP = 3625; - else - plr->HP += healAmount; - - respdata[i].eCT = 1; - respdata[i].iID = plr->iID; - respdata[i].iHP = plr->HP; - respdata[i].iHealHP = healAmount; - - std::cout << (int)plr->iID << " was healed" << std::endl; - } - } + + for (int i = 0; i < pkt->iTargetCnt; i++) { + if (!work(sock, pktdata, respdata, i, iCBFlag, amount)) + return; } sock->sendPacket((void*)&respbuf, P_FE2CL_NANO_SKILL_USE_SUCC, resplen); @@ -456,6 +531,23 @@ void NanoManager::nanoHeal(CNSocket* sock, CNPacketData* data, int16_t nanoId, i s->sendPacket((void*)&respbuf, P_FE2CL_NANO_SKILL_USE, resplen); } +// active nano power dispatch table +std::vector ActivePowers = { + ActivePower(StunPowers, activePower, SkillType::STUN, 0x200, 0), + ActivePower(HealPowers, activePower, SkillType::HEAL, 0, 333), + // TODO: Recall + ActivePower(DrainPowers, activePower, SkillType::DRAIN, 0x40000, 0), + ActivePower(SnarePowers, activePower, SkillType::SNARE, 0x80, 0), + ActivePower(DamagePowers, activePower, SkillType::DAMAGE, 0, 133), + // TODO: GroupRevive + ActivePower(LeechPowers, activePower, SkillType::LEECH, 0, 133), + ActivePower(SleepPowers, activePower, SkillType::SLEEP, 0x400, 0), +}; + +}; // namespace +#pragma endregion + +#pragma region Passive Powers void NanoManager::nanoBuff(CNSocket* sock, int16_t nanoId, int skillId, int16_t eSkillType, int32_t iCBFlag, int16_t eCharStatusTimeBuffID, int16_t iValue) { Player *plr = PlayerManager::getPlayer(sock); @@ -465,7 +557,7 @@ void NanoManager::nanoBuff(CNSocket* sock, int16_t nanoId, int skillId, int16_t } size_t resplen = sizeof(sP_FE2CL_NANO_SKILL_USE) + sizeof(sSkillResult_Buff); - uint8_t respbuf[4096]; + uint8_t respbuf[CN_PACKET_BUFFER_SIZE]; memset(respbuf, 0, resplen); @@ -476,7 +568,7 @@ void NanoManager::nanoBuff(CNSocket* sock, int16_t nanoId, int skillId, int16_t resp->iSkillID = skillId; resp->iNanoID = nanoId; resp->iNanoStamina = 150; - resp->eST = eSkillType; //run enum TODO: Send these enums to Defines + resp->eST = eSkillType; resp->iTargetCnt = 1; // this looks stupid but in the future there will be more counts (for group powers) @@ -526,140 +618,4 @@ void NanoManager::nanoUnbuff(CNSocket* sock, int32_t iCBFlag, int16_t eCharStatu sock->sendPacket((void*)&resp1, P_FE2CL_PC_BUFF_UPDATE, sizeof(sP_FE2CL_PC_BUFF_UPDATE)); } -void NanoManager::nanoDamage(CNSocket* sock, CNPacketData* data, int16_t nanoId, int16_t skillId, int32_t damageAmount) { - sP_CL2FE_REQ_NANO_SKILL_USE* pkt = (sP_CL2FE_REQ_NANO_SKILL_USE*)data->buf; - - // sanity check - if (!validInVarPacket(sizeof(sP_CL2FE_REQ_NANO_SKILL_USE), pkt->iTargetCnt, sizeof(int32_t), data->size)) { - std::cout << "[WARN] bad sP_CL2FE_REQ_NANO_SKILL_USE packet size\n"; - return; - } - - int32_t *pktdata = (int32_t*)((uint8_t*)data->buf + sizeof(sP_CL2FE_REQ_NANO_SKILL_USE)); - - /* - * Due to the possibility of multiplication overflow (and regular buffer overflow), - * both incoming and outgoing variable-length packets must be validated, at least if - * the number of trailing structs isn't well known (ie. it's from the client). - */ - if (!validOutVarPacket(sizeof(sP_FE2CL_NANO_SKILL_USE), pkt->iTargetCnt, sizeof(sSkillResult_Damage))) { - std::cout << "[WARN] bad sP_FE2CL_NANO_SKILL_USE packet size\n"; - return; - } - - size_t resplen = sizeof(sP_FE2CL_NANO_SKILL_USE) + pkt->iTargetCnt * sizeof(sSkillResult_Damage); - uint8_t respbuf[4096]; - - memset(respbuf, 0, resplen); - - sP_FE2CL_NANO_SKILL_USE *resp = (sP_FE2CL_NANO_SKILL_USE*)respbuf; - sSkillResult_Damage *respdata = (sSkillResult_Damage*)(respbuf+sizeof(sP_FE2CL_NANO_SKILL_USE)); - - Player *plr = PlayerManager::getPlayer(sock); - - resp->iPC_ID = plr->iID; - resp->iSkillID = skillId; - resp->iNanoID = nanoId; - resp->iNanoStamina = 150; - resp->eST = 1; - resp->iTargetCnt = pkt->iTargetCnt; - - for (int i = 0; i < pkt->iTargetCnt; i++) { - if (NPCManager::NPCs.find(pktdata[i]) == NPCManager::NPCs.end()) { - // not sure how to best handle this - std::cout << "[WARN] nanoDebuffEnemy: mob ID not found" << std::endl; - return; - } - BaseNPC& mob = NPCManager::NPCs[pktdata[i]]; - - mob.appearanceData.iHP -= damageAmount; - - if (mob.appearanceData.iHP <= 0) - CombatManager::giveReward(sock); - - respdata[i].eCT = 4; - respdata[i].iDamage = damageAmount; - respdata[i].iID = mob.appearanceData.iNPC_ID; - respdata[i].iHP = mob.appearanceData.iHP; - std::cout << (int)mob.appearanceData.iNPC_ID << " was damaged" << std::endl; - } - - sock->sendPacket((void*)&respbuf, P_FE2CL_NANO_SKILL_USE_SUCC, resplen); - for (CNSocket* s : PlayerManager::players[sock].viewable) - s->sendPacket((void*)&respbuf, P_FE2CL_NANO_SKILL_USE, resplen); -} - -void NanoManager::nanoLeech(CNSocket* sock, CNPacketData* data, int16_t nanoId, int16_t skillId, int32_t leechAmount) { - sP_CL2FE_REQ_NANO_SKILL_USE* pkt = (sP_CL2FE_REQ_NANO_SKILL_USE*)data->buf; - - // sanity check - if (!validInVarPacket(sizeof(sP_CL2FE_REQ_NANO_SKILL_USE), pkt->iTargetCnt, sizeof(int32_t), data->size)) { - std::cout << "[WARN] bad sP_CL2FE_REQ_NANO_SKILL_USE packet size\n"; - return; - } - - int32_t *pktdata = (int32_t*)((uint8_t*)data->buf + sizeof(sP_CL2FE_REQ_NANO_SKILL_USE)); - - /* - * Due to the possibility of multiplication overflow (and regular buffer overflow), - * both incoming and outgoing variable-length packets must be validated, at least if - * the number of trailing structs isn't well known (ie. it's from the client). - */ - if (!validOutVarPacket(sizeof(sP_FE2CL_NANO_SKILL_USE) + sizeof(sSkillResult_Heal_HP), pkt->iTargetCnt, sizeof(sSkillResult_Damage))) { - std::cout << "[WARN] bad sP_FE2CL_NANO_SKILL_USE packet size\n"; - return; - } - - size_t resplen = sizeof(sP_FE2CL_NANO_SKILL_USE) + sizeof(sSkillResult_Heal_HP) + pkt->iTargetCnt * sizeof(sSkillResult_Damage); - uint8_t respbuf[4096]; - - memset(respbuf, 0, resplen); - - sP_FE2CL_NANO_SKILL_USE *resp = (sP_FE2CL_NANO_SKILL_USE*)respbuf; - sSkillResult_Heal_HP *resp2 = (sSkillResult_Heal_HP*)(respbuf+sizeof(sP_FE2CL_NANO_SKILL_USE)); - sSkillResult_Damage *respdata = (sSkillResult_Damage*)(respbuf+sizeof(sP_FE2CL_NANO_SKILL_USE)+sizeof(sSkillResult_Heal_HP)); - - Player *plr = PlayerManager::getPlayer(sock); - - resp->iPC_ID = plr->iID; - resp->iSkillID = skillId; - resp->iNanoID = nanoId; - resp->iNanoStamina = 150; - resp->eST = 30; - resp->iTargetCnt = pkt->iTargetCnt; - - if (plr->HP + leechAmount > 3625) - plr->HP = 3625; - else - plr->HP += leechAmount; - - resp2->eCT = 1; - resp2->iID = plr->iID; - resp2->iHP = plr->HP; - resp2->iHealHP = leechAmount; - - for (int i = 0; i < pkt->iTargetCnt; i++) { - if (NPCManager::NPCs.find(pktdata[i]) == NPCManager::NPCs.end()) { - // not sure how to best handle this - std::cout << "[WARN] nanoDebuffEnemy: mob ID not found" << std::endl; - return; - } - BaseNPC& mob = NPCManager::NPCs[pktdata[i]]; - - mob.appearanceData.iHP -= leechAmount; - - if (mob.appearanceData.iHP <= 0) - CombatManager::giveReward(sock); - - respdata[i].eCT = 4; - respdata[i].iDamage = leechAmount; - respdata[i].iID = mob.appearanceData.iNPC_ID; - respdata[i].iHP = mob.appearanceData.iHP; - std::cout << (int)mob.appearanceData.iNPC_ID << " was damaged" << std::endl; - } - - sock->sendPacket((void*)&respbuf, P_FE2CL_NANO_SKILL_USE_SUCC, resplen); - for (CNSocket* s : PlayerManager::players[sock].viewable) - s->sendPacket((void*)&respbuf, P_FE2CL_NANO_SKILL_USE, resplen); -} #pragma endregion diff --git a/src/NanoManager.hpp b/src/NanoManager.hpp index 9f5eccc..f4f5060 100644 --- a/src/NanoManager.hpp +++ b/src/NanoManager.hpp @@ -1,9 +1,43 @@ #pragma once +#include +#include + #include "CNShardServer.hpp" +enum class SkillType { + DAMAGE = 1, + HEAL = 2, + DRAIN = 3, + SLEEP = 4, + SNARE = 5, + STUN = 8, + LEECH = 30, // ...what? +}; + +typedef void (*ActivePowerHandler)(CNSocket*, CNPacketData*, int16_t, int16_t, SkillType, int32_t, int32_t); + +struct ActivePower { + std::set powers; + ActivePowerHandler handler; + SkillType eSkillType; + int32_t flag; + int32_t amount; + + ActivePower(std::set p, ActivePowerHandler h, SkillType t, int32_t f, int32_t a) : powers(p), handler(h), eSkillType(t), flag(f), amount(a) {} + + void handle(CNSocket *sock, CNPacketData *data, int16_t nanoId, int16_t skillId) { + if (handler == nullptr) + return; + + handler(sock, data, nanoId, skillId, eSkillType, flag, amount); + } +}; + namespace NanoManager { + extern std::vector ActivePowers; void init(); + void nanoSummonHandler(CNSocket* sock, CNPacketData* data); void nanoEquipHandler(CNSocket* sock, CNPacketData* data); void nanoUnEquipHandler(CNSocket* sock, CNPacketData* data); @@ -19,10 +53,6 @@ namespace NanoManager { void setNanoSkill(CNSocket* sock, int16_t nanoId, int16_t skillId); void resetNanoSkill(CNSocket* sock, int16_t nanoId); - void nanoDebuff(CNSocket* sock, CNPacketData* data, int16_t nanoId, int16_t skillId, int16_t eSkillType, int32_t iCBFlag, int32_t damageAmount = 0); - void nanoHeal(CNSocket* sock, CNPacketData* data, int16_t nanoId, int16_t skillId, int16_t healAmount); void nanoBuff(CNSocket* sock, int16_t nanoId, int skillId, int16_t eSkillType, int32_t iCBFlag, int16_t eCharStatusTimeBuffID, int16_t iValue = 0); void nanoUnbuff(CNSocket* sock, int32_t iCBFlag, int16_t eCharStatusTimeBuffID, int16_t iValue = 0); - void nanoDamage(CNSocket* sock, CNPacketData* data, int16_t nanoId, int16_t skillId, int32_t damageAmount); - void nanoLeech(CNSocket* sock, CNPacketData* data, int16_t nanoId, int16_t skillId, int32_t leechAmount); } diff --git a/src/Player.hpp b/src/Player.hpp index dd906bb..4417aed 100644 --- a/src/Player.hpp +++ b/src/Player.hpp @@ -8,6 +8,8 @@ #define ACTIVE_MISSION_COUNT 6 +#define PC_MAXHEALTH(level) (925 + 75 * (level)) + struct Player { int accountId; int64_t SerialKey;