diff --git a/Makefile b/Makefile index bc94891..987749b 100644 --- a/Makefile +++ b/Makefile @@ -41,6 +41,7 @@ CXXSRC=\ src/MissionManager.cpp\ src/MobManager.cpp\ src/NanoManager.cpp\ + src/Abilities.cpp\ src/ItemManager.cpp\ src/NPCManager.cpp\ src/PlayerManager.cpp\ @@ -83,6 +84,7 @@ CXXHDR=\ src/MissionManager.hpp\ src/MobManager.hpp\ src/NanoManager.hpp\ + src/Abilities.hpp\ src/ItemManager.hpp\ src/NPCManager.hpp\ src/Player.hpp\ diff --git a/src/Abilities.cpp b/src/Abilities.cpp new file mode 100644 index 0000000..4237c0d --- /dev/null +++ b/src/Abilities.cpp @@ -0,0 +1,772 @@ +#include "Abilities.hpp" +#include "PlayerManager.hpp" +#include "Player.hpp" +#include "NPCManager.hpp" +#include "NanoManager.hpp" +#include "GroupManager.hpp" + +/* + * TODO: This file is in desperate need of deduplication and rewriting. + */ + +std::map NanoManager::SkillTable; + +/* + * targetData approach + * first integer is the count + * second to fifth integers are IDs, these can be either player iID or mob's iID + */ +std::vector NanoManager::findTargets(Player* plr, int skillID, CNPacketData* data) { + std::vector tD(5); + + if (SkillTable[skillID].targetType <= 2 && data != nullptr) { // client gives us the targets + 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" << std::endl; + return tD; + } + + int32_t *pktdata = (int32_t*)((uint8_t*)data->buf + sizeof(sP_CL2FE_REQ_NANO_SKILL_USE)); + tD[0] = pkt->iTargetCnt; + + for (int i = 0; i < pkt->iTargetCnt; i++) + tD[i+1] = pktdata[i]; + + } else if (SkillTable[skillID].targetType == 2) { // self target only + tD[0] = 1; + tD[1] = plr->iID; + + } else if (SkillTable[skillID].targetType == 3) { // entire group as target + Player *otherPlr = PlayerManager::getPlayerFromID(plr->iIDGroup); + + if (otherPlr == nullptr) + return tD; + + if (SkillTable[skillID].effectArea == 0) { // for buffs + tD[0] = otherPlr->groupCnt; + for (int i = 0; i < otherPlr->groupCnt; i++) + tD[i+1] = otherPlr->groupIDs[i]; + return tD; + } + + for (int i = 0; i < otherPlr->groupCnt; i++) { // group heals have an area limit + Player *otherPlr2 = PlayerManager::getPlayerFromID(otherPlr->groupIDs[i]); + if (otherPlr2 == nullptr) + continue; + if (true) {//hypot(otherPlr2->x - plr->x, otherPlr2->y - plr->y) < SkillTable[skillID].effectArea) { + tD[i+1] = otherPlr->groupIDs[i]; + tD[0] += 1; + } + } + } + + return tD; +} + +void NanoManager::nanoUnbuff(CNSocket* sock, std::vector targetData, int32_t bitFlag, int16_t timeBuffID, int16_t amount, bool groupPower) { + Player *plr = PlayerManager::getPlayer(sock); + + plr->iSelfConditionBitFlag &= ~bitFlag; + int groupFlags = 0; + + if (groupPower) { + plr->iGroupConditionBitFlag &= ~bitFlag; + Player *leader = PlayerManager::getPlayerFromID(plr->iIDGroup); + if (leader != nullptr) + groupFlags = GroupManager::getGroupFlags(leader); + } + + for (int i = 0; i < targetData[0]; i++) { + Player* varPlr = PlayerManager::getPlayerFromID(targetData[i+1]); + if (!((groupFlags | varPlr->iSelfConditionBitFlag) & bitFlag)) { + CNSocket* sockTo = PlayerManager::getSockFromID(targetData[i+1]); + if (sockTo == nullptr) + continue; // sanity check + + INITSTRUCT(sP_FE2CL_PC_BUFF_UPDATE, resp); + resp.eCSTB = timeBuffID; // eCharStatusTimeBuffID + resp.eTBU = 2; // eTimeBuffUpdate + resp.eTBT = 1; // eTimeBuffType 1 means nano + varPlr->iConditionBitFlag &= ~bitFlag; + resp.iConditionBitFlag = varPlr->iConditionBitFlag |= groupFlags | varPlr->iSelfConditionBitFlag; + + if (amount > 0) + resp.TimeBuff.iValue = amount; + + sockTo->sendPacket((void*)&resp, P_FE2CL_PC_BUFF_UPDATE, sizeof(sP_FE2CL_PC_BUFF_UPDATE)); + } + } +} + +int NanoManager::applyBuff(CNSocket* sock, int skillID, int eTBU, int eTBT, int32_t groupFlags) { + if (SkillTable[skillID].drainType == 1) + return 0; + + int32_t bitFlag = 0; + + for (auto& pwr : NanoPowers) { + if (pwr.skillType == SkillTable[skillID].skillType) { + bitFlag = pwr.bitFlag; + Player *plr = PlayerManager::getPlayer(sock); + if (eTBU == 1 || !((groupFlags | plr->iSelfConditionBitFlag) & bitFlag)) { + INITSTRUCT(sP_FE2CL_PC_BUFF_UPDATE, resp); + resp.eCSTB = pwr.timeBuffID; + resp.eTBU = eTBU; + resp.eTBT = eTBT; + + if (eTBU == 1) + plr->iConditionBitFlag |= bitFlag; + else + plr->iConditionBitFlag &= ~bitFlag; + + resp.iConditionBitFlag = plr->iConditionBitFlag |= groupFlags | plr->iSelfConditionBitFlag; + resp.TimeBuff.iValue = SkillTable[skillID].powerIntensity[0]; + sock->sendPacket((void*)&resp, P_FE2CL_PC_BUFF_UPDATE, sizeof(sP_FE2CL_PC_BUFF_UPDATE)); + } + return bitFlag; + } + } + + return 0; +} + +#pragma region Nano Powers +namespace NanoManager { + +bool doDebuff(CNSocket *sock, sSkillResult_Buff *respdata, int i, int32_t targetID, int32_t bitFlag, int16_t timeBuffID, int16_t duration, int16_t amount) { + if (MobManager::Mobs.find(targetID) == MobManager::Mobs.end()) { + std::cout << "[WARN] doDebuff: mob ID not found" << std::endl; + return false; + } + + Mob* mob = MobManager::Mobs[targetID]; + MobManager::hitMob(sock, mob, 0); + + respdata[i].eCT = 4; + respdata[i].iID = mob->appearanceData.iNPC_ID; + respdata[i].bProtected = 1; + if (mob->skillStyle < 0 && mob->state != MobState::RETREAT + && !(mob->appearanceData.iConditionBitFlag & CSB_BIT_FREEDOM)) { // only debuff if the enemy is not retreating, casting corruption or in freedom + mob->appearanceData.iConditionBitFlag |= bitFlag; + mob->unbuffTimes[bitFlag] = getTime() + duration * 100; + respdata[i].bProtected = 0; + } + respdata[i].iConditionBitFlag = mob->appearanceData.iConditionBitFlag; + + return true; +} + +bool doBuff(CNSocket *sock, sSkillResult_Buff *respdata, int i, int32_t targetID, int32_t bitFlag, int16_t timeBuffID, int16_t duration, int16_t amount) { + Player *plr = nullptr; + CNSocket *sockTo = nullptr; + + for (auto& pair : PlayerManager::players) { + if (pair.second->iID == targetID) { + sockTo = pair.first; + plr = pair.second; + break; + } + } + + // player not found + if (sockTo == nullptr || plr == nullptr) { + std::cout << "[WARN] doBuff: player ID not found" << std::endl; + return false; + } + + respdata[i].eCT = 1; + respdata[i].iID = plr->iID; + respdata[i].iConditionBitFlag = 0; + + // only apply buffs if the player is actually alive + if (plr->HP > 0) { + respdata[i].iConditionBitFlag = bitFlag; + + INITSTRUCT(sP_FE2CL_PC_BUFF_UPDATE, pkt); + pkt.eCSTB = timeBuffID; // eCharStatusTimeBuffID + pkt.eTBU = 1; // eTimeBuffUpdate + pkt.eTBT = 1; // eTimeBuffType 1 means nano + pkt.iConditionBitFlag = plr->iConditionBitFlag |= bitFlag; + + if (amount > 0) + pkt.TimeBuff.iValue = amount; + + sockTo->sendPacket((void*)&pkt, P_FE2CL_PC_BUFF_UPDATE, sizeof(sP_FE2CL_PC_BUFF_UPDATE)); + } + + return true; +} + +bool doDamageNDebuff(CNSocket *sock, sSkillResult_Damage_N_Debuff *respdata, int i, int32_t targetID, int32_t bitFlag, int16_t timeBuffID, int16_t duration, int16_t amount) { + if (MobManager::Mobs.find(targetID) == MobManager::Mobs.end()) { + // not sure how to best handle this + std::cout << "[WARN] doDamageNDebuff: mob ID not found" << std::endl; + return false; + } + + Mob* mob = MobManager::Mobs[targetID]; + + MobManager::hitMob(sock, mob, 0); // just to gain aggro + + respdata[i].eCT = 4; + respdata[i].iDamage = duration / 10; + respdata[i].iID = mob->appearanceData.iNPC_ID; + respdata[i].iHP = mob->appearanceData.iHP; + respdata[i].bProtected = 1; + if (mob->skillStyle < 0 && mob->state != MobState::RETREAT + && !(mob->appearanceData.iConditionBitFlag & CSB_BIT_FREEDOM)) { // only debuff if the enemy is not retreating, casting corruption or in freedom + mob->appearanceData.iConditionBitFlag |= bitFlag; + mob->unbuffTimes[bitFlag] = getTime() + duration * 100; + respdata[i].bProtected = 0; + } + respdata[i].iConditionBitFlag = mob->appearanceData.iConditionBitFlag; + + return true; +} + +bool doHeal(CNSocket *sock, sSkillResult_Heal_HP *respdata, int i, int32_t targetID, int32_t bitFlag, int16_t timeBuffID, int16_t duration, int16_t amount) { + Player *plr = nullptr; + + for (auto& pair : PlayerManager::players) { + if (pair.second->iID == targetID) { + plr = pair.second; + break; + } + } + + // player not found + if (plr == nullptr) { + std::cout << "[WARN] doHeal: player ID not found" << std::endl; + return false; + } + + int healedAmount = PC_MAXHEALTH(plr->level) * amount / 1000; + + // do not heal dead players + if (plr->HP <= 0) + healedAmount = 0; + + plr->HP += healedAmount; + + if (plr->HP > PC_MAXHEALTH(plr->level)) + plr->HP = PC_MAXHEALTH(plr->level); + + respdata[i].eCT = 1; + respdata[i].iID = plr->iID; + respdata[i].iHP = plr->HP; + respdata[i].iHealHP = healedAmount; + + return true; +} + +bool doDamage(CNSocket *sock, sSkillResult_Damage *respdata, int i, int32_t targetID, int32_t bitFlag, int16_t timeBuffID, int16_t duration, int16_t amount) { + if (MobManager::Mobs.find(targetID) == MobManager::Mobs.end()) { + // not sure how to best handle this + std::cout << "[WARN] doDamage: mob ID not found" << std::endl; + return false; + } + Mob* mob = MobManager::Mobs[targetID]; + + Player *plr = PlayerManager::getPlayer(sock); + + int damage = MobManager::hitMob(sock, mob, std::max(PC_MAXHEALTH(plr->level) * amount / 1000, mob->maxHealth * amount / 1000)); + + respdata[i].eCT = 4; + respdata[i].iDamage = damage; + respdata[i].iID = mob->appearanceData.iNPC_ID; + respdata[i].iHP = mob->appearanceData.iHP; + + return true; +} + +/* + * NOTE: Leech is specially encoded. + * + * It manages to fit inside the nanoPower<>() 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, sSkillResult_Heal_HP *healdata, int i, int32_t targetID, int32_t bitFlag, int16_t timeBuffID, int16_t duration, int16_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); + + int healedAmount = amount; + + plr->HP += healedAmount; + + if (plr->HP > PC_MAXHEALTH(plr->level)) + plr->HP = PC_MAXHEALTH(plr->level); + + healdata->eCT = 1; + healdata->iID = plr->iID; + healdata->iHP = plr->HP; + healdata->iHealHP = healedAmount; + + if (MobManager::Mobs.find(targetID) == MobManager::Mobs.end()) { + // not sure how to best handle this + std::cout << "[WARN] doLeech: mob ID not found" << std::endl; + return false; + } + Mob* mob = MobManager::Mobs[targetID]; + + int damage = MobManager::hitMob(sock, mob, amount * 2); + + damagedata->eCT = 4; + damagedata->iDamage = damage; + damagedata->iID = mob->appearanceData.iNPC_ID; + damagedata->iHP = mob->appearanceData.iHP; + + return true; +} + +bool doResurrect(CNSocket *sock, sSkillResult_Resurrect *respdata, int i, int32_t targetID, int32_t bitFlag, int16_t timeBuffID, int16_t duration, int16_t amount) { + Player *plr = nullptr; + + for (auto& pair : PlayerManager::players) { + if (pair.second->iID == targetID) { + plr = pair.second; + break; + } + } + + // player not found + if (plr == nullptr) { + std::cout << "[WARN] doResurrect: player ID not found" << std::endl; + return false; + } + + respdata[i].eCT = 1; + respdata[i].iID = plr->iID; + respdata[i].iRegenHP = plr->HP; + + return true; +} + +bool doMove(CNSocket *sock, sSkillResult_Move *respdata, int i, int32_t targetID, int32_t bitFlag, int16_t timeBuffID, int16_t duration, int16_t amount) { + Player *plr = nullptr; + + for (auto& pair : PlayerManager::players) { + if (pair.second->iID == targetID) { + plr = pair.second; + break; + } + } + + // player not found + if (plr == nullptr) { + std::cout << "[WARN] doMove: player ID not found" << std::endl; + return false; + } + + Player *plr2 = PlayerManager::getPlayer(sock); + + respdata[i].eCT = 1; + respdata[i].iID = plr->iID; + respdata[i].iMapNum = plr2->recallInstance; + respdata[i].iMoveX = plr2->recallX; + respdata[i].iMoveY = plr2->recallY; + respdata[i].iMoveZ = plr2->recallZ; + + return true; +} + +template +void nanoPower(CNSocket *sock, std::vector targetData, + int16_t nanoID, int16_t skillID, int16_t duration, int16_t amount, + int16_t skillType, int32_t bitFlag, int16_t timeBuffID) { + Player *plr = PlayerManager::getPlayer(sock); + + if (skillType == EST_RETROROCKET_SELF || skillType == EST_RECALL) // rocket and self recall does not need any trailing structs + targetData[0] = 0; + + size_t resplen; + // special case since leech is atypically encoded + if (skillType == EST_BLOODSUCKING) + resplen = sizeof(sP_FE2CL_NANO_SKILL_USE_SUCC) + sizeof(sSkillResult_Heal_HP) + sizeof(sSkillResult_Damage); + else + resplen = sizeof(sP_FE2CL_NANO_SKILL_USE_SUCC) + targetData[0] * sizeof(sPAYLOAD); + + // validate response packet + if (!validOutVarPacket(sizeof(sP_FE2CL_NANO_SKILL_USE_SUCC), targetData[0], sizeof(sPAYLOAD))) { + std::cout << "[WARN] bad sP_FE2CL_NANO_SKILL_USE packet size" << std::endl; + return; + } + + 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)); + + resp->iPC_ID = plr->iID; + resp->iSkillID = skillID; + resp->iNanoID = nanoID; + resp->iNanoStamina = plr->Nanos[plr->activeNano].iStamina; + resp->eST = skillType; + resp->iTargetCnt = targetData[0]; + + if (SkillTable[skillID].drainType == 2) { + if (SkillTable[skillID].targetType >= 2) + plr->iSelfConditionBitFlag |= bitFlag; + if (SkillTable[skillID].targetType == 3) + plr->iGroupConditionBitFlag |= bitFlag; + } + + for (int i = 0; i < targetData[0]; i++) + if (!work(sock, respdata, i, targetData[i+1], bitFlag, timeBuffID, duration, amount)) + return; + + sock->sendPacket((void*)&respbuf, P_FE2CL_NANO_SKILL_USE_SUCC, resplen); + assert(sizeof(sP_FE2CL_NANO_SKILL_USE_SUCC) == sizeof(sP_FE2CL_NANO_SKILL_USE)); + if (skillType == EST_RECALL_GROUP) { // in the case of group recall, nobody but group members need the packet + for (int i = 0; i < targetData[0]; i++) { + CNSocket *sock2 = PlayerManager::getSockFromID(targetData[i+1]); + sock2->sendPacket((void*)&respbuf, P_FE2CL_NANO_SKILL_USE, resplen); + } + } else + PlayerManager::sendToViewable(sock, (void*)&respbuf, P_FE2CL_NANO_SKILL_USE, resplen); + + // Warping on recall + if (skillType == EST_RECALL || skillType == EST_RECALL_GROUP) { + if ((int32_t)plr->instanceID == plr->recallInstance) + PlayerManager::sendPlayerTo(sock, plr->recallX, plr->recallY, plr->recallZ, plr->recallInstance); + else { + INITSTRUCT(sP_FE2CL_REP_WARP_USE_RECALL_FAIL, response) + sock->sendPacket((void*)&response, P_FE2CL_REP_WARP_USE_RECALL_FAIL, sizeof(sP_FE2CL_REP_WARP_USE_RECALL_FAIL)); + } + } +} + +// nano power dispatch table +std::vector NanoPowers = { + NanoPower(EST_STUN, CSB_BIT_STUN, ECSB_STUN, nanoPower), + NanoPower(EST_HEAL_HP, CSB_BIT_NONE, ECSB_NONE, nanoPower), + NanoPower(EST_BOUNDINGBALL, CSB_BIT_BOUNDINGBALL, ECSB_BOUNDINGBALL, nanoPower), + NanoPower(EST_SNARE, CSB_BIT_DN_MOVE_SPEED, ECSB_DN_MOVE_SPEED, nanoPower), + NanoPower(EST_DAMAGE, CSB_BIT_NONE, ECSB_NONE, nanoPower), + NanoPower(EST_BLOODSUCKING, CSB_BIT_NONE, ECSB_NONE, nanoPower), + NanoPower(EST_SLEEP, CSB_BIT_MEZ, ECSB_MEZ, nanoPower), + NanoPower(EST_REWARDBLOB, CSB_BIT_REWARD_BLOB, ECSB_REWARD_BLOB, nanoPower), + NanoPower(EST_RUN, CSB_BIT_UP_MOVE_SPEED, ECSB_UP_MOVE_SPEED, nanoPower), + NanoPower(EST_REWARDCASH, CSB_BIT_REWARD_CASH, ECSB_REWARD_CASH, nanoPower), + NanoPower(EST_PROTECTBATTERY, CSB_BIT_PROTECT_BATTERY, ECSB_PROTECT_BATTERY, nanoPower), + NanoPower(EST_MINIMAPENEMY, CSB_BIT_MINIMAP_ENEMY, ECSB_MINIMAP_ENEMY, nanoPower), + NanoPower(EST_PROTECTINFECTION, CSB_BIT_PROTECT_INFECTION, ECSB_PROTECT_INFECTION, nanoPower), + NanoPower(EST_JUMP, CSB_BIT_UP_JUMP_HEIGHT, ECSB_UP_JUMP_HEIGHT, nanoPower), + NanoPower(EST_FREEDOM, CSB_BIT_FREEDOM, ECSB_FREEDOM, nanoPower), + NanoPower(EST_PHOENIX, CSB_BIT_PHOENIX, ECSB_PHOENIX, nanoPower), + NanoPower(EST_STEALTH, CSB_BIT_UP_STEALTH, ECSB_UP_STEALTH, nanoPower), + NanoPower(EST_MINIMAPTRESURE, CSB_BIT_MINIMAP_TRESURE, ECSB_MINIMAP_TRESURE, nanoPower), + NanoPower(EST_RECALL, CSB_BIT_NONE, ECSB_NONE, nanoPower), + NanoPower(EST_RECALL_GROUP, CSB_BIT_NONE, ECSB_NONE, nanoPower), + NanoPower(EST_RETROROCKET_SELF, CSB_BIT_NONE, ECSB_NONE, nanoPower), + NanoPower(EST_PHOENIX_GROUP, CSB_BIT_NONE, ECSB_NONE, nanoPower), + NanoPower(EST_NANOSTIMPAK, CSB_BIT_STIMPAKSLOT1, ECSB_STIMPAKSLOT1, nanoPower), + NanoPower(EST_NANOSTIMPAK, CSB_BIT_STIMPAKSLOT2, ECSB_STIMPAKSLOT2, nanoPower), + NanoPower(EST_NANOSTIMPAK, CSB_BIT_STIMPAKSLOT3, ECSB_STIMPAKSLOT3, nanoPower) +}; + +}; // namespace +#pragma endregion + +#pragma region Mob Powers +namespace MobManager { +bool doDamageNDebuff(Mob *mob, sSkillResult_Damage_N_Debuff *respdata, int i, int32_t targetID, int32_t bitFlag, int16_t timeBuffID, int16_t duration, int16_t amount) { + CNSocket *sock = nullptr; + Player *plr = nullptr; + + for (auto& pair : PlayerManager::players) { + if (pair.second->iID == targetID) { + sock = pair.first; + plr = pair.second; + break; + } + } + + // player not found + if (plr == nullptr) { + std::cout << "[WARN] doDamageNDebuff: player ID not found" << std::endl; + return false; + } + + respdata[i].eCT = 1; + respdata[i].iDamage = duration / 10; + respdata[i].iID = plr->iID; + respdata[i].iHP = plr->HP; + respdata[i].iStamina = plr->Nanos[plr->activeNano].iStamina; + if (plr->iConditionBitFlag & CSB_BIT_FREEDOM) + respdata[i].bProtected = 1; + else { + if (!(plr->iConditionBitFlag & bitFlag)) { + INITSTRUCT(sP_FE2CL_PC_BUFF_UPDATE, pkt); + pkt.eCSTB = timeBuffID; // eCharStatusTimeBuffID + pkt.eTBU = 1; // eTimeBuffUpdate + pkt.eTBT = 2; + pkt.iConditionBitFlag = plr->iConditionBitFlag |= bitFlag; + pkt.TimeBuff.iValue = amount * 5; + sock->sendPacket((void*)&pkt, P_FE2CL_PC_BUFF_UPDATE, sizeof(sP_FE2CL_PC_BUFF_UPDATE)); + } + + respdata[i].bProtected = 0; + std::pair key = std::make_pair(sock, bitFlag); + time_t until = getTime() + (time_t)duration * 100; + NPCManager::EggBuffs[key] = until; + } + respdata[i].iConditionBitFlag = plr->iConditionBitFlag; + + if (plr->HP <= 0) { + mob->target = nullptr; + mob->state = MobState::RETREAT; + if (!aggroCheck(mob, getTime())) { + clearDebuff(mob); + if (mob->groupLeader != 0) + groupRetreat(mob); + } + } + + return true; +} + +bool doHeal(Mob *mob, sSkillResult_Heal_HP *respdata, int i, int32_t targetID, int32_t bitFlag, int16_t timeBuffID, int16_t duration, int16_t amount) { + if (MobManager::Mobs.find(targetID) == MobManager::Mobs.end()) { + std::cout << "[WARN] doDebuff: mob ID not found" << std::endl; + return false; + } + + Mob* targetMob = MobManager::Mobs[targetID]; + + int healedAmount = amount * targetMob->maxHealth / 1000; + targetMob->appearanceData.iHP += healedAmount; + if (targetMob->appearanceData.iHP > targetMob->maxHealth) + targetMob->appearanceData.iHP = targetMob->maxHealth; + + respdata[i].eCT = 4; + respdata[i].iID = targetMob->appearanceData.iNPC_ID; + respdata[i].iHP = targetMob->appearanceData.iHP; + respdata[i].iHealHP = healedAmount; + + return true; +} + +bool doReturnHeal(Mob *mob, sSkillResult_Heal_HP *respdata, int i, int32_t targetID, int32_t bitFlag, int16_t timeBuffID, int16_t duration, int16_t amount) { + int healedAmount = amount * mob->maxHealth / 1000; + mob->appearanceData.iHP += healedAmount; + if (mob->appearanceData.iHP > mob->maxHealth) + mob->appearanceData.iHP = mob->maxHealth; + + respdata[i].eCT = 4; + respdata[i].iID = mob->appearanceData.iNPC_ID; + respdata[i].iHP = mob->appearanceData.iHP; + respdata[i].iHealHP = healedAmount; + + return true; +} + +bool doDamage(Mob *mob, sSkillResult_Damage *respdata, int i, int32_t targetID, int32_t bitFlag, int16_t timeBuffID, int16_t duration, int16_t amount) { + Player *plr = nullptr; + + for (auto& pair : PlayerManager::players) { + if (pair.second->iID == targetID) { + plr = pair.second; + break; + } + } + + // player not found + if (plr == nullptr) { + std::cout << "[WARN] doDamage: player ID not found" << std::endl; + return false; + } + + int damage = amount * PC_MAXHEALTH((int)mob->data["m_iNpcLevel"]) / 1500; + + if (plr->iSpecialState & CN_SPECIAL_STATE_FLAG__INVULNERABLE) + damage = 0; + + respdata[i].eCT = 1; + respdata[i].iDamage = damage; + respdata[i].iID = plr->iID; + respdata[i].iHP = plr->HP -= damage; + + if (plr->HP <= 0) { + mob->target = nullptr; + mob->state = MobState::RETREAT; + if (!aggroCheck(mob, getTime())) { + clearDebuff(mob); + if (mob->groupLeader != 0) + groupRetreat(mob); + } + } + + return true; +} + +bool doLeech(Mob *mob, sSkillResult_Heal_HP *healdata, int i, int32_t targetID, int32_t bitFlag, int16_t timeBuffID, int16_t duration, int16_t amount) { + // this sanity check is VERY important + if (i != 0) { + std::cout << "[WARN] Mob attempted to leech more than one player!" << std::endl; + return false; + } + + Player *plr = nullptr; + + for (auto& pair : PlayerManager::players) { + if (pair.second->iID == targetID) { + plr = pair.second; + break; + } + } + + // player not found + if (plr == nullptr) { + std::cout << "[WARN] doLeech: player ID not found" << std::endl; + return false; + } + + sSkillResult_Damage *damagedata = (sSkillResult_Damage*)(((uint8_t*)healdata) + sizeof(sSkillResult_Heal_HP)); + + int healedAmount = amount * PC_MAXHEALTH(plr->level) / 1000; + + mob->appearanceData.iHP += healedAmount; + if (mob->appearanceData.iHP > mob->maxHealth) + mob->appearanceData.iHP = mob->maxHealth; + + healdata->eCT = 4; + healdata->iID = mob->appearanceData.iNPC_ID; + healdata->iHP = mob->appearanceData.iHP; + healdata->iHealHP = healedAmount; + + int damage = healedAmount; + + if (plr->iSpecialState & CN_SPECIAL_STATE_FLAG__INVULNERABLE) + damage = 0; + + damagedata->eCT = 1; + damagedata->iDamage = damage; + damagedata->iID = plr->iID; + damagedata->iHP = plr->HP -= damage; + + if (plr->HP <= 0) { + mob->target = nullptr; + mob->state = MobState::RETREAT; + if (!aggroCheck(mob, getTime())) { + clearDebuff(mob); + if (mob->groupLeader != 0) + groupRetreat(mob); + } + } + + return true; +} + +bool doBatteryDrain(Mob *mob, sSkillResult_BatteryDrain *respdata, int i, int32_t targetID, int32_t bitFlag, int16_t timeBuffID, int16_t duration, int16_t amount) { + Player *plr = nullptr; + + for (auto& pair : PlayerManager::players) { + if (pair.second->iID == targetID) { + plr = pair.second; + break; + } + } + + // player not found + if (plr == nullptr) { + std::cout << "[WARN] doBatteryDrain: player ID not found" << std::endl; + return false; + } + + respdata[i].eCT = 1; + respdata[i].iID = plr->iID; + + if (plr->iConditionBitFlag & CSB_BIT_PROTECT_BATTERY) { + respdata[i].bProtected = 1; + respdata[i].iDrainW = 0; + respdata[i].iDrainN = 0; + } else { + respdata[i].bProtected = 0; + respdata[i].iDrainW = amount * (18 + (int)mob->data["m_iNpcLevel"]) / 36; + respdata[i].iDrainN = amount * (18 + (int)mob->data["m_iNpcLevel"]) / 36; + } + + respdata[i].iBatteryW = plr->batteryW -= (respdata[i].iDrainW < plr->batteryW) ? respdata[i].iDrainW : plr->batteryW; + respdata[i].iBatteryN = plr->batteryN -= (respdata[i].iDrainN < plr->batteryN) ? respdata[i].iDrainN : plr->batteryN; + respdata[i].iStamina = plr->Nanos[plr->activeNano].iStamina; + respdata[i].iConditionBitFlag = plr->iConditionBitFlag; + + return true; +} + +bool doBuff(Mob *mob, sSkillResult_Buff *respdata, int i, int32_t targetID, int32_t bitFlag, int16_t timeBuffID, int16_t duration, int16_t amount) { + respdata[i].eCT = 4; + respdata[i].iID = mob->appearanceData.iNPC_ID; + mob->appearanceData.iConditionBitFlag |= bitFlag; + respdata[i].iConditionBitFlag = mob->appearanceData.iConditionBitFlag; + + return true; +} + +template +void mobPower(Mob *mob, std::vector targetData, + int16_t skillID, int16_t duration, int16_t amount, + int16_t skillType, int32_t bitFlag, int16_t timeBuffID) { + size_t resplen; + // special case since leech is atypically encoded + if (skillType == EST_BLOODSUCKING) + resplen = sizeof(sP_FE2CL_NPC_SKILL_HIT) + sizeof(sSkillResult_Heal_HP) + sizeof(sSkillResult_Damage); + else + resplen = sizeof(sP_FE2CL_NPC_SKILL_HIT) + targetData[0] * sizeof(sPAYLOAD); + + // validate response packet + if (!validOutVarPacket(sizeof(sP_FE2CL_NPC_SKILL_HIT), targetData[0], sizeof(sPAYLOAD))) { + std::cout << "[WARN] bad sP_FE2CL_NPC_SKILL_HIT packet size" << std::endl; + return; + } + + uint8_t respbuf[CN_PACKET_BUFFER_SIZE]; + memset(respbuf, 0, resplen); + + sP_FE2CL_NPC_SKILL_HIT *resp = (sP_FE2CL_NPC_SKILL_HIT*)respbuf; + sPAYLOAD *respdata = (sPAYLOAD*)(respbuf+sizeof(sP_FE2CL_NPC_SKILL_HIT)); + + resp->iNPC_ID = mob->appearanceData.iNPC_ID; + resp->iSkillID = skillID; + resp->iValue1 = mob->hitX; + resp->iValue2 = mob->hitY; + resp->iValue3 = mob->hitZ; + resp->eST = skillType; + resp->iTargetCnt = targetData[0]; + + for (int i = 0; i < targetData[0]; i++) + if (!work(mob, respdata, i, targetData[i+1], bitFlag, timeBuffID, duration, amount)) + return; + + NPCManager::sendToViewable(mob, (void*)&respbuf, P_FE2CL_NPC_SKILL_HIT, resplen); +} + +// nano power dispatch table +std::vector MobPowers = { + MobPower(EST_STUN, CSB_BIT_STUN, ECSB_STUN, mobPower), + MobPower(EST_HEAL_HP, CSB_BIT_NONE, ECSB_NONE, mobPower), + MobPower(EST_RETURNHOMEHEAL, CSB_BIT_NONE, ECSB_NONE, mobPower), + MobPower(EST_SNARE, CSB_BIT_DN_MOVE_SPEED, ECSB_DN_MOVE_SPEED, mobPower), + MobPower(EST_DAMAGE, CSB_BIT_NONE, ECSB_NONE, mobPower), + MobPower(EST_BATTERYDRAIN, CSB_BIT_NONE, ECSB_NONE, mobPower), + MobPower(EST_SLEEP, CSB_BIT_MEZ, ECSB_MEZ, mobPower), + MobPower(EST_BLOODSUCKING, CSB_BIT_NONE, ECSB_NONE, mobPower), + MobPower(EST_FREEDOM, CSB_BIT_FREEDOM, ECSB_FREEDOM, mobPower) +}; + +}; // namespace +#pragma endregion diff --git a/src/Abilities.hpp b/src/Abilities.hpp new file mode 100644 index 0000000..4599676 --- /dev/null +++ b/src/Abilities.hpp @@ -0,0 +1,62 @@ +#pragma once + +#include "CNProtocol.hpp" +#include "MobManager.hpp" + +typedef void (*PowerHandler)(CNSocket*, std::vector, int16_t, int16_t, int16_t, int16_t, int16_t, int32_t, int16_t); + +struct NanoPower { + int16_t skillType; + int32_t bitFlag; + int16_t timeBuffID; + PowerHandler handler; + + NanoPower(int16_t s, int32_t b, int16_t t, PowerHandler h) : skillType(s), bitFlag(b), timeBuffID(t), handler(h) {} + + void handle(CNSocket *sock, std::vector targetData, int16_t nanoID, int16_t skillID, int16_t duration, int16_t amount) { + if (handler == nullptr) + return; + + handler(sock, targetData, nanoID, skillID, duration, amount, skillType, bitFlag, timeBuffID); + } +}; + +typedef void (*MobPowerHandler)(Mob*, std::vector, int16_t, int16_t, int16_t, int16_t, int32_t, int16_t); + +struct MobPower { + int16_t skillType; + int32_t bitFlag; + int16_t timeBuffID; + MobPowerHandler handler; + + MobPower(int16_t s, int32_t b, int16_t t, MobPowerHandler h) : skillType(s), bitFlag(b), timeBuffID(t), handler(h) {} + + void handle(Mob *mob, std::vector targetData, int16_t skillID, int16_t duration, int16_t amount) { + if (handler == nullptr) + return; + + handler(mob, targetData, skillID, duration, amount, skillType, bitFlag, timeBuffID); + } +}; + +struct SkillData { + int skillType; + int targetType; + int drainType; + int effectArea; + int batteryUse[4]; + int durationTime[4]; + int powerIntensity[4]; +}; + +namespace NanoManager { + extern std::vector NanoPowers; + extern std::map SkillTable; + + void nanoUnbuff(CNSocket* sock, std::vector targetData, int32_t bitFlag, int16_t timeBuffID, int16_t amount, bool groupPower); + int applyBuff(CNSocket* sock, int skillID, int eTBU, int eTBT, int32_t groupFlags); +} + +namespace MobManager { + extern std::vector MobPowers; +} diff --git a/src/GroupManager.cpp b/src/GroupManager.cpp index 1b20573..41d6849 100644 --- a/src/GroupManager.cpp +++ b/src/GroupManager.cpp @@ -3,6 +3,7 @@ #include "PlayerManager.hpp" #include "GroupManager.hpp" #include "NanoManager.hpp" +#include "Abilities.hpp" #include #include diff --git a/src/ItemManager.cpp b/src/ItemManager.cpp index 240d1e9..8a65d19 100644 --- a/src/ItemManager.cpp +++ b/src/ItemManager.cpp @@ -5,6 +5,7 @@ #include "NanoManager.hpp" #include "NPCManager.hpp" #include "Player.hpp" +#include "Abilities.hpp" #include // for memset() #include @@ -621,4 +622,4 @@ void ItemManager::init() { // Bank REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_BANK_OPEN, itemBankOpenHandler); REGISTER_SHARD_PACKET(P_CL2FE_REQ_ITEM_CHEST_OPEN, chestOpenHandler); -} \ No newline at end of file +} diff --git a/src/MobManager.cpp b/src/MobManager.cpp index d2f4531..bf8d7b2 100644 --- a/src/MobManager.cpp +++ b/src/MobManager.cpp @@ -7,6 +7,7 @@ #include "GroupManager.hpp" #include "TransportManager.hpp" #include "RacingManager.hpp" +#include "Abilities.hpp" #include #include @@ -1752,294 +1753,3 @@ void MobManager::enterCombat(CNSocket *sock, Mob *mob) { if (event.trigger == ON_COMBAT && event.npcType == mob->appearanceData.iNPCType) event.handler(sock, mob); } - -#pragma region Mob Powers -namespace MobManager { -bool doDamageNDebuff(Mob *mob, sSkillResult_Damage_N_Debuff *respdata, int i, int32_t targetID, int32_t bitFlag, int16_t timeBuffID, int16_t duration, int16_t amount) { - CNSocket *sock = nullptr; - Player *plr = nullptr; - - for (auto& pair : PlayerManager::players) { - if (pair.second->iID == targetID) { - sock = pair.first; - plr = pair.second; - break; - } - } - - // player not found - if (plr == nullptr) { - std::cout << "[WARN] doDamageNDebuff: player ID not found" << std::endl; - return false; - } - - respdata[i].eCT = 1; - respdata[i].iDamage = duration / 10; - respdata[i].iID = plr->iID; - respdata[i].iHP = plr->HP; - respdata[i].iStamina = plr->Nanos[plr->activeNano].iStamina; - if (plr->iConditionBitFlag & CSB_BIT_FREEDOM) - respdata[i].bProtected = 1; - else { - if (!(plr->iConditionBitFlag & bitFlag)) { - INITSTRUCT(sP_FE2CL_PC_BUFF_UPDATE, pkt); - pkt.eCSTB = timeBuffID; // eCharStatusTimeBuffID - pkt.eTBU = 1; // eTimeBuffUpdate - pkt.eTBT = 2; - pkt.iConditionBitFlag = plr->iConditionBitFlag |= bitFlag; - pkt.TimeBuff.iValue = amount * 5; - sock->sendPacket((void*)&pkt, P_FE2CL_PC_BUFF_UPDATE, sizeof(sP_FE2CL_PC_BUFF_UPDATE)); - } - - respdata[i].bProtected = 0; - std::pair key = std::make_pair(sock, bitFlag); - time_t until = getTime() + (time_t)duration * 100; - NPCManager::EggBuffs[key] = until; - } - respdata[i].iConditionBitFlag = plr->iConditionBitFlag; - - if (plr->HP <= 0) { - mob->target = nullptr; - mob->state = MobState::RETREAT; - if (!aggroCheck(mob, getTime())) { - clearDebuff(mob); - if (mob->groupLeader != 0) - groupRetreat(mob); - } - } - - return true; -} - -bool doHeal(Mob *mob, sSkillResult_Heal_HP *respdata, int i, int32_t targetID, int32_t bitFlag, int16_t timeBuffID, int16_t duration, int16_t amount) { - if (MobManager::Mobs.find(targetID) == MobManager::Mobs.end()) { - std::cout << "[WARN] doDebuff: mob ID not found" << std::endl; - return false; - } - - Mob* targetMob = MobManager::Mobs[targetID]; - - int healedAmount = amount * targetMob->maxHealth / 1000; - targetMob->appearanceData.iHP += healedAmount; - if (targetMob->appearanceData.iHP > targetMob->maxHealth) - targetMob->appearanceData.iHP = targetMob->maxHealth; - - respdata[i].eCT = 4; - respdata[i].iID = targetMob->appearanceData.iNPC_ID; - respdata[i].iHP = targetMob->appearanceData.iHP; - respdata[i].iHealHP = healedAmount; - - return true; -} - -bool doReturnHeal(Mob *mob, sSkillResult_Heal_HP *respdata, int i, int32_t targetID, int32_t bitFlag, int16_t timeBuffID, int16_t duration, int16_t amount) { - int healedAmount = amount * mob->maxHealth / 1000; - mob->appearanceData.iHP += healedAmount; - if (mob->appearanceData.iHP > mob->maxHealth) - mob->appearanceData.iHP = mob->maxHealth; - - respdata[i].eCT = 4; - respdata[i].iID = mob->appearanceData.iNPC_ID; - respdata[i].iHP = mob->appearanceData.iHP; - respdata[i].iHealHP = healedAmount; - - return true; -} - -bool doDamage(Mob *mob, sSkillResult_Damage *respdata, int i, int32_t targetID, int32_t bitFlag, int16_t timeBuffID, int16_t duration, int16_t amount) { - Player *plr = nullptr; - - for (auto& pair : PlayerManager::players) { - if (pair.second->iID == targetID) { - plr = pair.second; - break; - } - } - - // player not found - if (plr == nullptr) { - std::cout << "[WARN] doDamage: player ID not found" << std::endl; - return false; - } - - int damage = amount * PC_MAXHEALTH((int)mob->data["m_iNpcLevel"]) / 1500; - - if (plr->iSpecialState & CN_SPECIAL_STATE_FLAG__INVULNERABLE) - damage = 0; - - respdata[i].eCT = 1; - respdata[i].iDamage = damage; - respdata[i].iID = plr->iID; - respdata[i].iHP = plr->HP -= damage; - - if (plr->HP <= 0) { - mob->target = nullptr; - mob->state = MobState::RETREAT; - if (!aggroCheck(mob, getTime())) { - clearDebuff(mob); - if (mob->groupLeader != 0) - groupRetreat(mob); - } - } - - return true; -} - -bool doLeech(Mob *mob, sSkillResult_Heal_HP *healdata, int i, int32_t targetID, int32_t bitFlag, int16_t timeBuffID, int16_t duration, int16_t amount) { - // this sanity check is VERY important - if (i != 0) { - std::cout << "[WARN] Mob attempted to leech more than one player!" << std::endl; - return false; - } - - Player *plr = nullptr; - - for (auto& pair : PlayerManager::players) { - if (pair.second->iID == targetID) { - plr = pair.second; - break; - } - } - - // player not found - if (plr == nullptr) { - std::cout << "[WARN] doLeech: player ID not found" << std::endl; - return false; - } - - sSkillResult_Damage *damagedata = (sSkillResult_Damage*)(((uint8_t*)healdata) + sizeof(sSkillResult_Heal_HP)); - - int healedAmount = amount * PC_MAXHEALTH(plr->level) / 1000; - - mob->appearanceData.iHP += healedAmount; - if (mob->appearanceData.iHP > mob->maxHealth) - mob->appearanceData.iHP = mob->maxHealth; - - healdata->eCT = 4; - healdata->iID = mob->appearanceData.iNPC_ID; - healdata->iHP = mob->appearanceData.iHP; - healdata->iHealHP = healedAmount; - - int damage = healedAmount; - - if (plr->iSpecialState & CN_SPECIAL_STATE_FLAG__INVULNERABLE) - damage = 0; - - damagedata->eCT = 1; - damagedata->iDamage = damage; - damagedata->iID = plr->iID; - damagedata->iHP = plr->HP -= damage; - - if (plr->HP <= 0) { - mob->target = nullptr; - mob->state = MobState::RETREAT; - if (!aggroCheck(mob, getTime())) { - clearDebuff(mob); - if (mob->groupLeader != 0) - groupRetreat(mob); - } - } - - return true; -} - -bool doBatteryDrain(Mob *mob, sSkillResult_BatteryDrain *respdata, int i, int32_t targetID, int32_t bitFlag, int16_t timeBuffID, int16_t duration, int16_t amount) { - Player *plr = nullptr; - - for (auto& pair : PlayerManager::players) { - if (pair.second->iID == targetID) { - plr = pair.second; - break; - } - } - - // player not found - if (plr == nullptr) { - std::cout << "[WARN] doBatteryDrain: player ID not found" << std::endl; - return false; - } - - respdata[i].eCT = 1; - respdata[i].iID = plr->iID; - - if (plr->iConditionBitFlag & CSB_BIT_PROTECT_BATTERY) { - respdata[i].bProtected = 1; - respdata[i].iDrainW = 0; - respdata[i].iDrainN = 0; - } else { - respdata[i].bProtected = 0; - respdata[i].iDrainW = amount * (18 + (int)mob->data["m_iNpcLevel"]) / 36; - respdata[i].iDrainN = amount * (18 + (int)mob->data["m_iNpcLevel"]) / 36; - } - - respdata[i].iBatteryW = plr->batteryW -= (respdata[i].iDrainW < plr->batteryW) ? respdata[i].iDrainW : plr->batteryW; - respdata[i].iBatteryN = plr->batteryN -= (respdata[i].iDrainN < plr->batteryN) ? respdata[i].iDrainN : plr->batteryN; - respdata[i].iStamina = plr->Nanos[plr->activeNano].iStamina; - respdata[i].iConditionBitFlag = plr->iConditionBitFlag; - - return true; -} - -bool doBuff(Mob *mob, sSkillResult_Buff *respdata, int i, int32_t targetID, int32_t bitFlag, int16_t timeBuffID, int16_t duration, int16_t amount) { - respdata[i].eCT = 4; - respdata[i].iID = mob->appearanceData.iNPC_ID; - mob->appearanceData.iConditionBitFlag |= bitFlag; - respdata[i].iConditionBitFlag = mob->appearanceData.iConditionBitFlag; - - return true; -} - -template -void mobPower(Mob *mob, std::vector targetData, - int16_t skillID, int16_t duration, int16_t amount, - int16_t skillType, int32_t bitFlag, int16_t timeBuffID) { - size_t resplen; - // special case since leech is atypically encoded - if (skillType == EST_BLOODSUCKING) - resplen = sizeof(sP_FE2CL_NPC_SKILL_HIT) + sizeof(sSkillResult_Heal_HP) + sizeof(sSkillResult_Damage); - else - resplen = sizeof(sP_FE2CL_NPC_SKILL_HIT) + targetData[0] * sizeof(sPAYLOAD); - - // validate response packet - if (!validOutVarPacket(sizeof(sP_FE2CL_NPC_SKILL_HIT), targetData[0], sizeof(sPAYLOAD))) { - std::cout << "[WARN] bad sP_FE2CL_NPC_SKILL_HIT packet size" << std::endl; - return; - } - - uint8_t respbuf[CN_PACKET_BUFFER_SIZE]; - memset(respbuf, 0, resplen); - - sP_FE2CL_NPC_SKILL_HIT *resp = (sP_FE2CL_NPC_SKILL_HIT*)respbuf; - sPAYLOAD *respdata = (sPAYLOAD*)(respbuf+sizeof(sP_FE2CL_NPC_SKILL_HIT)); - - resp->iNPC_ID = mob->appearanceData.iNPC_ID; - resp->iSkillID = skillID; - resp->iValue1 = mob->hitX; - resp->iValue2 = mob->hitY; - resp->iValue3 = mob->hitZ; - resp->eST = skillType; - resp->iTargetCnt = targetData[0]; - - for (int i = 0; i < targetData[0]; i++) - if (!work(mob, respdata, i, targetData[i+1], bitFlag, timeBuffID, duration, amount)) - return; - - NPCManager::sendToViewable(mob, (void*)&respbuf, P_FE2CL_NPC_SKILL_HIT, resplen); -} - -// nano power dispatch table -std::vector MobPowers = { - MobPower(EST_STUN, CSB_BIT_STUN, ECSB_STUN, mobPower), - MobPower(EST_HEAL_HP, CSB_BIT_NONE, ECSB_NONE, mobPower), - MobPower(EST_RETURNHOMEHEAL, CSB_BIT_NONE, ECSB_NONE, mobPower), - MobPower(EST_SNARE, CSB_BIT_DN_MOVE_SPEED, ECSB_DN_MOVE_SPEED, mobPower), - MobPower(EST_DAMAGE, CSB_BIT_NONE, ECSB_NONE, mobPower), - MobPower(EST_BATTERYDRAIN, CSB_BIT_NONE, ECSB_NONE, mobPower), - MobPower(EST_SLEEP, CSB_BIT_MEZ, ECSB_MEZ, mobPower), - MobPower(EST_BLOODSUCKING, CSB_BIT_NONE, ECSB_NONE, mobPower), - MobPower(EST_FREEDOM, CSB_BIT_FREEDOM, ECSB_FREEDOM, mobPower) -}; - -}; // namespace -#pragma endregion diff --git a/src/MobManager.hpp b/src/MobManager.hpp index d564d14..f604408 100644 --- a/src/MobManager.hpp +++ b/src/MobManager.hpp @@ -122,24 +122,6 @@ struct Bullet { int bulletType; }; -typedef void (*MobPowerHandler)(Mob*, std::vector, int16_t, int16_t, int16_t, int16_t, int32_t, int16_t); - -struct MobPower { - int16_t skillType; - int32_t bitFlag; - int16_t timeBuffID; - MobPowerHandler handler; - - MobPower(int16_t s, int32_t b, int16_t t, MobPowerHandler h) : skillType(s), bitFlag(b), timeBuffID(t), handler(h) {} - - void handle(Mob *mob, std::vector targetData, int16_t skillID, int16_t duration, int16_t amount) { - if (handler == nullptr) - return; - - handler(mob, targetData, skillID, duration, amount, skillType, bitFlag, timeBuffID); - } -}; - namespace MobManager { extern std::map Mobs; extern std::queue RemovalQueue; @@ -147,7 +129,6 @@ namespace MobManager { extern std::map MobDrops; extern std::map> Bullets; extern bool simulateMobs; - extern std::vector MobPowers; void init(); void step(CNServer*, time_t); diff --git a/src/NPCManager.cpp b/src/NPCManager.cpp index 91e86b8..26d3ad7 100644 --- a/src/NPCManager.cpp +++ b/src/NPCManager.cpp @@ -9,6 +9,7 @@ #include "GroupManager.hpp" #include "RacingManager.hpp" #include "Vendor.hpp" +#include "Abilities.hpp" #include #include diff --git a/src/NanoManager.cpp b/src/NanoManager.cpp index 953c89b..eabddcb 100644 --- a/src/NanoManager.cpp +++ b/src/NanoManager.cpp @@ -6,12 +6,12 @@ #include "MobManager.hpp" #include "MissionManager.hpp" #include "GroupManager.hpp" +#include "Abilities.hpp" #include std::map NanoManager::NanoTable; std::map NanoManager::NanoTunings; -std::map NanoManager::SkillTable; void NanoManager::init() { REGISTER_SHARD_PACKET(P_CL2FE_REQ_NANO_ACTIVE, nanoSummonHandler); @@ -112,7 +112,6 @@ void NanoManager::nanoSummonHandler(CNSocket* sock, CNPacketData* data) { summonNano(sock, pkt->iNanoSlotNum); - // Send to client DEBUGLOG( std::cout << PlayerManager::getPlayerName(plr) << " requested to summon nano slot: " << pkt->iNanoSlotNum << std::endl; ) @@ -440,73 +439,6 @@ void NanoManager::resetNanoSkill(CNSocket* sock, int16_t nanoID) { plr->Nanos[nanoID] = nano; } -void NanoManager::nanoUnbuff(CNSocket* sock, std::vector targetData, int32_t bitFlag, int16_t timeBuffID, int16_t amount, bool groupPower) { - Player *plr = PlayerManager::getPlayer(sock); - - plr->iSelfConditionBitFlag &= ~bitFlag; - int groupFlags = 0; - - if (groupPower) { - plr->iGroupConditionBitFlag &= ~bitFlag; - Player *leader = PlayerManager::getPlayerFromID(plr->iIDGroup); - if (leader != nullptr) - groupFlags = GroupManager::getGroupFlags(leader); - } - - for (int i = 0; i < targetData[0]; i++) { - Player* varPlr = PlayerManager::getPlayerFromID(targetData[i+1]); - if (!((groupFlags | varPlr->iSelfConditionBitFlag) & bitFlag)) { - CNSocket* sockTo = PlayerManager::getSockFromID(targetData[i+1]); - if (sockTo == nullptr) - continue; // sanity check - - INITSTRUCT(sP_FE2CL_PC_BUFF_UPDATE, resp); - resp.eCSTB = timeBuffID; // eCharStatusTimeBuffID - resp.eTBU = 2; // eTimeBuffUpdate - resp.eTBT = 1; // eTimeBuffType 1 means nano - varPlr->iConditionBitFlag &= ~bitFlag; - resp.iConditionBitFlag = varPlr->iConditionBitFlag |= groupFlags | varPlr->iSelfConditionBitFlag; - - if (amount > 0) - resp.TimeBuff.iValue = amount; - - sockTo->sendPacket((void*)&resp, P_FE2CL_PC_BUFF_UPDATE, sizeof(sP_FE2CL_PC_BUFF_UPDATE)); - } - } -} - -int NanoManager::applyBuff(CNSocket* sock, int skillID, int eTBU, int eTBT, int32_t groupFlags) { - if (SkillTable[skillID].drainType == 1) - return 0; - - int32_t bitFlag = 0; - - for (auto& pwr : NanoPowers) { - if (pwr.skillType == SkillTable[skillID].skillType) { - bitFlag = pwr.bitFlag; - Player *plr = PlayerManager::getPlayer(sock); - if (eTBU == 1 || !((groupFlags | plr->iSelfConditionBitFlag) & bitFlag)) { - INITSTRUCT(sP_FE2CL_PC_BUFF_UPDATE, resp); - resp.eCSTB = pwr.timeBuffID; - resp.eTBU = eTBU; - resp.eTBT = eTBT; - - if (eTBU == 1) - plr->iConditionBitFlag |= bitFlag; - else - plr->iConditionBitFlag &= ~bitFlag; - - resp.iConditionBitFlag = plr->iConditionBitFlag |= groupFlags | plr->iSelfConditionBitFlag; - resp.TimeBuff.iValue = SkillTable[skillID].powerIntensity[0]; - sock->sendPacket((void*)&resp, P_FE2CL_PC_BUFF_UPDATE, sizeof(sP_FE2CL_PC_BUFF_UPDATE)); - } - return bitFlag; - } - } - - return 0; -} - // 0=A 1=B 2=C -1=Not found int NanoManager::nanoStyle(int nanoID) { if (nanoID < 1 || nanoID >= (int)NanoTable.size()) @@ -514,58 +446,6 @@ int NanoManager::nanoStyle(int nanoID) { return NanoTable[nanoID].style; } -/* - * targetData approach - * first integer is the count - * second to fifth integers are IDs, these can be either player iID or mob's iID - */ -std::vector NanoManager::findTargets(Player* plr, int skillID, CNPacketData* data) { - std::vector tD(5); - - if (SkillTable[skillID].targetType <= 2 && data != nullptr) { // client gives us the targets - 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" << std::endl; - return tD; - } - - int32_t *pktdata = (int32_t*)((uint8_t*)data->buf + sizeof(sP_CL2FE_REQ_NANO_SKILL_USE)); - tD[0] = pkt->iTargetCnt; - - for (int i = 0; i < pkt->iTargetCnt; i++) - tD[i+1] = pktdata[i]; - } else if (SkillTable[skillID].targetType == 2) { // self target only - tD[0] = 1; - tD[1] = plr->iID; - } else if (SkillTable[skillID].targetType == 3) { // entire group as target - Player *otherPlr = PlayerManager::getPlayerFromID(plr->iIDGroup); - - if (otherPlr == nullptr) - return tD; - - if (SkillTable[skillID].effectArea == 0) { // for buffs - tD[0] = otherPlr->groupCnt; - for (int i = 0; i < otherPlr->groupCnt; i++) - tD[i+1] = otherPlr->groupIDs[i]; - return tD; - } - - for (int i = 0; i < otherPlr->groupCnt; i++) { // group heals have an area limit - Player *otherPlr2 = PlayerManager::getPlayerFromID(otherPlr->groupIDs[i]); - if (otherPlr2 == nullptr) - continue; - if (true) {//hypot(otherPlr2->x - plr->x, otherPlr2->y - plr->y) < SkillTable[skillID].effectArea) { - tD[i+1] = otherPlr->groupIDs[i]; - tD[0] += 1; - } - } - } - - return tD; -} - bool NanoManager::getNanoBoost(Player* plr) { for (int i = 0; i < 3; i++) if (plr->equippedNanos[i] == plr->activeNano) @@ -574,351 +454,3 @@ bool NanoManager::getNanoBoost(Player* plr) { return false; } #pragma endregion - -#pragma region Nano Powers -namespace NanoManager { - -bool doDebuff(CNSocket *sock, sSkillResult_Buff *respdata, int i, int32_t targetID, int32_t bitFlag, int16_t timeBuffID, int16_t duration, int16_t amount) { - if (MobManager::Mobs.find(targetID) == MobManager::Mobs.end()) { - std::cout << "[WARN] doDebuff: mob ID not found" << std::endl; - return false; - } - - Mob* mob = MobManager::Mobs[targetID]; - MobManager::hitMob(sock, mob, 0); - - respdata[i].eCT = 4; - respdata[i].iID = mob->appearanceData.iNPC_ID; - respdata[i].bProtected = 1; - if (mob->skillStyle < 0 && mob->state != MobState::RETREAT - && !(mob->appearanceData.iConditionBitFlag & CSB_BIT_FREEDOM)) { // only debuff if the enemy is not retreating, casting corruption or in freedom - mob->appearanceData.iConditionBitFlag |= bitFlag; - mob->unbuffTimes[bitFlag] = getTime() + duration * 100; - respdata[i].bProtected = 0; - } - respdata[i].iConditionBitFlag = mob->appearanceData.iConditionBitFlag; - - return true; -} - -bool doBuff(CNSocket *sock, sSkillResult_Buff *respdata, int i, int32_t targetID, int32_t bitFlag, int16_t timeBuffID, int16_t duration, int16_t amount) { - Player *plr = nullptr; - CNSocket *sockTo = nullptr; - - for (auto& pair : PlayerManager::players) { - if (pair.second->iID == targetID) { - sockTo = pair.first; - plr = pair.second; - break; - } - } - - // player not found - if (sockTo == nullptr || plr == nullptr) { - std::cout << "[WARN] doBuff: player ID not found" << std::endl; - return false; - } - - respdata[i].eCT = 1; - respdata[i].iID = plr->iID; - respdata[i].iConditionBitFlag = 0; - - // only apply buffs if the player is actually alive - if (plr->HP > 0) { - respdata[i].iConditionBitFlag = bitFlag; - - INITSTRUCT(sP_FE2CL_PC_BUFF_UPDATE, pkt); - pkt.eCSTB = timeBuffID; // eCharStatusTimeBuffID - pkt.eTBU = 1; // eTimeBuffUpdate - pkt.eTBT = 1; // eTimeBuffType 1 means nano - pkt.iConditionBitFlag = plr->iConditionBitFlag |= bitFlag; - - if (amount > 0) - pkt.TimeBuff.iValue = amount; - - sockTo->sendPacket((void*)&pkt, P_FE2CL_PC_BUFF_UPDATE, sizeof(sP_FE2CL_PC_BUFF_UPDATE)); - } - - return true; -} - -bool doDamageNDebuff(CNSocket *sock, sSkillResult_Damage_N_Debuff *respdata, int i, int32_t targetID, int32_t bitFlag, int16_t timeBuffID, int16_t duration, int16_t amount) { - if (MobManager::Mobs.find(targetID) == MobManager::Mobs.end()) { - // not sure how to best handle this - std::cout << "[WARN] doDamageNDebuff: mob ID not found" << std::endl; - return false; - } - - Mob* mob = MobManager::Mobs[targetID]; - - MobManager::hitMob(sock, mob, 0); // just to gain aggro - - respdata[i].eCT = 4; - respdata[i].iDamage = duration / 10; - respdata[i].iID = mob->appearanceData.iNPC_ID; - respdata[i].iHP = mob->appearanceData.iHP; - respdata[i].bProtected = 1; - if (mob->skillStyle < 0 && mob->state != MobState::RETREAT - && !(mob->appearanceData.iConditionBitFlag & CSB_BIT_FREEDOM)) { // only debuff if the enemy is not retreating, casting corruption or in freedom - mob->appearanceData.iConditionBitFlag |= bitFlag; - mob->unbuffTimes[bitFlag] = getTime() + duration * 100; - respdata[i].bProtected = 0; - } - respdata[i].iConditionBitFlag = mob->appearanceData.iConditionBitFlag; - - return true; -} - -bool doHeal(CNSocket *sock, sSkillResult_Heal_HP *respdata, int i, int32_t targetID, int32_t bitFlag, int16_t timeBuffID, int16_t duration, int16_t amount) { - Player *plr = nullptr; - - for (auto& pair : PlayerManager::players) { - if (pair.second->iID == targetID) { - plr = pair.second; - break; - } - } - - // player not found - if (plr == nullptr) { - std::cout << "[WARN] doHeal: player ID not found" << std::endl; - return false; - } - - int healedAmount = PC_MAXHEALTH(plr->level) * amount / 1000; - - // do not heal dead players - if (plr->HP <= 0) - healedAmount = 0; - - plr->HP += healedAmount; - - if (plr->HP > PC_MAXHEALTH(plr->level)) - plr->HP = PC_MAXHEALTH(plr->level); - - respdata[i].eCT = 1; - respdata[i].iID = plr->iID; - respdata[i].iHP = plr->HP; - respdata[i].iHealHP = healedAmount; - - return true; -} - -bool doDamage(CNSocket *sock, sSkillResult_Damage *respdata, int i, int32_t targetID, int32_t bitFlag, int16_t timeBuffID, int16_t duration, int16_t amount) { - if (MobManager::Mobs.find(targetID) == MobManager::Mobs.end()) { - // not sure how to best handle this - std::cout << "[WARN] doDamage: mob ID not found" << std::endl; - return false; - } - Mob* mob = MobManager::Mobs[targetID]; - - Player *plr = PlayerManager::getPlayer(sock); - - int damage = MobManager::hitMob(sock, mob, std::max(PC_MAXHEALTH(plr->level) * amount / 1000, mob->maxHealth * amount / 1000)); - - respdata[i].eCT = 4; - respdata[i].iDamage = damage; - respdata[i].iID = mob->appearanceData.iNPC_ID; - respdata[i].iHP = mob->appearanceData.iHP; - - return true; -} - -/* - * NOTE: Leech is specially encoded. - * - * It manages to fit inside the nanoPower<>() 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, sSkillResult_Heal_HP *healdata, int i, int32_t targetID, int32_t bitFlag, int16_t timeBuffID, int16_t duration, int16_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); - - int healedAmount = amount; - - plr->HP += healedAmount; - - if (plr->HP > PC_MAXHEALTH(plr->level)) - plr->HP = PC_MAXHEALTH(plr->level); - - healdata->eCT = 1; - healdata->iID = plr->iID; - healdata->iHP = plr->HP; - healdata->iHealHP = healedAmount; - - if (MobManager::Mobs.find(targetID) == MobManager::Mobs.end()) { - // not sure how to best handle this - std::cout << "[WARN] doLeech: mob ID not found" << std::endl; - return false; - } - Mob* mob = MobManager::Mobs[targetID]; - - int damage = MobManager::hitMob(sock, mob, amount * 2); - - damagedata->eCT = 4; - damagedata->iDamage = damage; - damagedata->iID = mob->appearanceData.iNPC_ID; - damagedata->iHP = mob->appearanceData.iHP; - - return true; -} - -bool doResurrect(CNSocket *sock, sSkillResult_Resurrect *respdata, int i, int32_t targetID, int32_t bitFlag, int16_t timeBuffID, int16_t duration, int16_t amount) { - Player *plr = nullptr; - - for (auto& pair : PlayerManager::players) { - if (pair.second->iID == targetID) { - plr = pair.second; - break; - } - } - - // player not found - if (plr == nullptr) { - std::cout << "[WARN] doResurrect: player ID not found" << std::endl; - return false; - } - - respdata[i].eCT = 1; - respdata[i].iID = plr->iID; - respdata[i].iRegenHP = plr->HP; - - return true; -} - -bool doMove(CNSocket *sock, sSkillResult_Move *respdata, int i, int32_t targetID, int32_t bitFlag, int16_t timeBuffID, int16_t duration, int16_t amount) { - Player *plr = nullptr; - - for (auto& pair : PlayerManager::players) { - if (pair.second->iID == targetID) { - plr = pair.second; - break; - } - } - - // player not found - if (plr == nullptr) { - std::cout << "[WARN] doMove: player ID not found" << std::endl; - return false; - } - - Player *plr2 = PlayerManager::getPlayer(sock); - - respdata[i].eCT = 1; - respdata[i].iID = plr->iID; - respdata[i].iMapNum = plr2->recallInstance; - respdata[i].iMoveX = plr2->recallX; - respdata[i].iMoveY = plr2->recallY; - respdata[i].iMoveZ = plr2->recallZ; - - return true; -} - -template -void nanoPower(CNSocket *sock, std::vector targetData, - int16_t nanoID, int16_t skillID, int16_t duration, int16_t amount, - int16_t skillType, int32_t bitFlag, int16_t timeBuffID) { - Player *plr = PlayerManager::getPlayer(sock); - - if (skillType == EST_RETROROCKET_SELF || skillType == EST_RECALL) // rocket and self recall does not need any trailing structs - targetData[0] = 0; - - size_t resplen; - // special case since leech is atypically encoded - if (skillType == EST_BLOODSUCKING) - resplen = sizeof(sP_FE2CL_NANO_SKILL_USE_SUCC) + sizeof(sSkillResult_Heal_HP) + sizeof(sSkillResult_Damage); - else - resplen = sizeof(sP_FE2CL_NANO_SKILL_USE_SUCC) + targetData[0] * sizeof(sPAYLOAD); - - // validate response packet - if (!validOutVarPacket(sizeof(sP_FE2CL_NANO_SKILL_USE_SUCC), targetData[0], sizeof(sPAYLOAD))) { - std::cout << "[WARN] bad sP_FE2CL_NANO_SKILL_USE packet size" << std::endl; - return; - } - - 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)); - - resp->iPC_ID = plr->iID; - resp->iSkillID = skillID; - resp->iNanoID = nanoID; - resp->iNanoStamina = plr->Nanos[plr->activeNano].iStamina; - resp->eST = skillType; - resp->iTargetCnt = targetData[0]; - - if (SkillTable[skillID].drainType == 2) { - if (SkillTable[skillID].targetType >= 2) - plr->iSelfConditionBitFlag |= bitFlag; - if (SkillTable[skillID].targetType == 3) - plr->iGroupConditionBitFlag |= bitFlag; - } - - for (int i = 0; i < targetData[0]; i++) - if (!work(sock, respdata, i, targetData[i+1], bitFlag, timeBuffID, duration, amount)) - return; - - sock->sendPacket((void*)&respbuf, P_FE2CL_NANO_SKILL_USE_SUCC, resplen); - assert(sizeof(sP_FE2CL_NANO_SKILL_USE_SUCC) == sizeof(sP_FE2CL_NANO_SKILL_USE)); - if (skillType == EST_RECALL_GROUP) { // in the case of group recall, nobody but group members need the packet - for (int i = 0; i < targetData[0]; i++) { - CNSocket *sock2 = PlayerManager::getSockFromID(targetData[i+1]); - sock2->sendPacket((void*)&respbuf, P_FE2CL_NANO_SKILL_USE, resplen); - } - } else - PlayerManager::sendToViewable(sock, (void*)&respbuf, P_FE2CL_NANO_SKILL_USE, resplen); - - // Warping on recall - if (skillType == EST_RECALL || skillType == EST_RECALL_GROUP) { - if ((int32_t)plr->instanceID == plr->recallInstance) - PlayerManager::sendPlayerTo(sock, plr->recallX, plr->recallY, plr->recallZ, plr->recallInstance); - else { - INITSTRUCT(sP_FE2CL_REP_WARP_USE_RECALL_FAIL, response) - sock->sendPacket((void*)&response, P_FE2CL_REP_WARP_USE_RECALL_FAIL, sizeof(sP_FE2CL_REP_WARP_USE_RECALL_FAIL)); - } - } -} - -// nano power dispatch table -std::vector NanoPowers = { - NanoPower(EST_STUN, CSB_BIT_STUN, ECSB_STUN, nanoPower), - NanoPower(EST_HEAL_HP, CSB_BIT_NONE, ECSB_NONE, nanoPower), - NanoPower(EST_BOUNDINGBALL, CSB_BIT_BOUNDINGBALL, ECSB_BOUNDINGBALL, nanoPower), - NanoPower(EST_SNARE, CSB_BIT_DN_MOVE_SPEED, ECSB_DN_MOVE_SPEED, nanoPower), - NanoPower(EST_DAMAGE, CSB_BIT_NONE, ECSB_NONE, nanoPower), - NanoPower(EST_BLOODSUCKING, CSB_BIT_NONE, ECSB_NONE, nanoPower), - NanoPower(EST_SLEEP, CSB_BIT_MEZ, ECSB_MEZ, nanoPower), - NanoPower(EST_REWARDBLOB, CSB_BIT_REWARD_BLOB, ECSB_REWARD_BLOB, nanoPower), - NanoPower(EST_RUN, CSB_BIT_UP_MOVE_SPEED, ECSB_UP_MOVE_SPEED, nanoPower), - NanoPower(EST_REWARDCASH, CSB_BIT_REWARD_CASH, ECSB_REWARD_CASH, nanoPower), - NanoPower(EST_PROTECTBATTERY, CSB_BIT_PROTECT_BATTERY, ECSB_PROTECT_BATTERY, nanoPower), - NanoPower(EST_MINIMAPENEMY, CSB_BIT_MINIMAP_ENEMY, ECSB_MINIMAP_ENEMY, nanoPower), - NanoPower(EST_PROTECTINFECTION, CSB_BIT_PROTECT_INFECTION, ECSB_PROTECT_INFECTION, nanoPower), - NanoPower(EST_JUMP, CSB_BIT_UP_JUMP_HEIGHT, ECSB_UP_JUMP_HEIGHT, nanoPower), - NanoPower(EST_FREEDOM, CSB_BIT_FREEDOM, ECSB_FREEDOM, nanoPower), - NanoPower(EST_PHOENIX, CSB_BIT_PHOENIX, ECSB_PHOENIX, nanoPower), - NanoPower(EST_STEALTH, CSB_BIT_UP_STEALTH, ECSB_UP_STEALTH, nanoPower), - NanoPower(EST_MINIMAPTRESURE, CSB_BIT_MINIMAP_TRESURE, ECSB_MINIMAP_TRESURE, nanoPower), - NanoPower(EST_RECALL, CSB_BIT_NONE, ECSB_NONE, nanoPower), - NanoPower(EST_RECALL_GROUP, CSB_BIT_NONE, ECSB_NONE, nanoPower), - NanoPower(EST_RETROROCKET_SELF, CSB_BIT_NONE, ECSB_NONE, nanoPower), - NanoPower(EST_PHOENIX_GROUP, CSB_BIT_NONE, ECSB_NONE, nanoPower), - NanoPower(EST_NANOSTIMPAK, CSB_BIT_STIMPAKSLOT1, ECSB_STIMPAKSLOT1, nanoPower), - NanoPower(EST_NANOSTIMPAK, CSB_BIT_STIMPAKSLOT2, ECSB_STIMPAKSLOT2, nanoPower), - NanoPower(EST_NANOSTIMPAK, CSB_BIT_STIMPAKSLOT3, ECSB_STIMPAKSLOT3, nanoPower) -}; - -}; // namespace -#pragma endregion diff --git a/src/NanoManager.hpp b/src/NanoManager.hpp index 457cc56..9fc2eef 100644 --- a/src/NanoManager.hpp +++ b/src/NanoManager.hpp @@ -6,24 +6,6 @@ #include "Player.hpp" #include "CNShardServer.hpp" -typedef void (*PowerHandler)(CNSocket*, std::vector, int16_t, int16_t, int16_t, int16_t, int16_t, int32_t, int16_t); - -struct NanoPower { - int16_t skillType; - int32_t bitFlag; - int16_t timeBuffID; - PowerHandler handler; - - NanoPower(int16_t s, int32_t b, int16_t t, PowerHandler h) : skillType(s), bitFlag(b), timeBuffID(t), handler(h) {} - - void handle(CNSocket *sock, std::vector targetData, int16_t nanoID, int16_t skillID, int16_t duration, int16_t amount) { - if (handler == nullptr) - return; - - handler(sock, targetData, nanoID, skillID, duration, amount, skillType, bitFlag, timeBuffID); - } -}; - struct NanoData { int style; }; @@ -33,21 +15,9 @@ struct NanoTuning { int reqItems; }; -struct SkillData { - int skillType; - int targetType; - int drainType; - int effectArea; - int batteryUse[4]; - int durationTime[4]; - int powerIntensity[4]; -}; - namespace NanoManager { - extern std::vector NanoPowers; extern std::map NanoTable; extern std::map NanoTunings; - extern std::map SkillTable; void init(); void nanoSummonHandler(CNSocket* sock, CNPacketData* data); @@ -66,8 +36,6 @@ namespace NanoManager { void summonNano(CNSocket* sock, int slot, bool silent = false); void setNanoSkill(CNSocket* sock, sP_CL2FE_REQ_NANO_TUNE* skill); void resetNanoSkill(CNSocket* sock, int16_t nanoID); - void nanoUnbuff(CNSocket* sock, std::vector targetData, int32_t bitFlag, int16_t timeBuffID, int16_t amount, bool groupPower); - int applyBuff(CNSocket* sock, int skillID, int eTBU, int eTBT, int32_t groupFlags); int nanoStyle(int nanoID); std::vector findTargets(Player* plr, int skillID, CNPacketData* data = nullptr); bool getNanoBoost(Player* plr); diff --git a/src/PlayerManager.cpp b/src/PlayerManager.cpp index a3538a5..ee7da44 100644 --- a/src/PlayerManager.cpp +++ b/src/PlayerManager.cpp @@ -11,6 +11,7 @@ #include "MobManager.hpp" #include "RacingManager.hpp" #include "BuiltinCommands.hpp" +#include "Abilities.hpp" #include "settings.hpp" diff --git a/src/TableData.cpp b/src/TableData.cpp index d1da352..02d361e 100644 --- a/src/TableData.cpp +++ b/src/TableData.cpp @@ -9,6 +9,7 @@ #include "NanoManager.hpp" #include "RacingManager.hpp" #include "Vendor.hpp" +#include "Abilities.hpp" #include "JSON.hpp"