Cleaned up implementation of active nano powers.

This commit is contained in:
dongresource 2020-09-15 16:46:52 +02:00
parent 0fc072d591
commit dc9de5a54a
3 changed files with 244 additions and 256 deletions

View File

@ -5,6 +5,39 @@
#include "NPCManager.hpp" #include "NPCManager.hpp"
#include "CombatManager.hpp" #include "CombatManager.hpp"
namespace NanoManager {
// active powers
std::set<int> StunPowers = {1, 13, 42, 59, 78, 103};
std::set<int> HealPowers = {2, 7, 12, 38, 53, 61, 82, 92, 98};
std::set<int> RecallPowers = {5, 25, 66, 69, 75, 87};
std::set<int> DrainPowers = {10, 34, 37, 56, 93, 97};
std::set<int> SnarePowers = {17, 18, 27, 41, 43, 47, 90, 96, 106};
std::set<int> DamagePowers = {19, 21, 33, 45, 46, 52, 101, 105, 108};
std::set<int> GroupRevivePowers = {20, 63, 91};
std::set<int> LeechPowers = {24, 51, 89};
std::set<int> SleepPowers = {28, 30, 32, 49, 70, 71, 81, 85, 94};
// passive powers
std::set<int> ScavangePowers = {3, 50, 99};
std::set<int> RunPowers = {4, 8, 62, 68, 73, 86};
std::set<int> BonusPowers = {6, 54, 104};
std::set<int> GuardPowers = {9, 57, 76};
std::set<int> RadarPowers = {11, 67, 95};
std::set<int> AnitdotePowers = {14, 58, 102};
std::set<int> FreedomPowers = {15, 31, 39, 55, 77, 107};
std::set<int> JumpPowers = {16, 35, 44, 60, 88, 100};
std::set<int> SelfRevivePowers = {22, 48, 83};
std::set<int> SneakPowers = {23, 29, 65, 72, 80, 82};
std::set<int> 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() { void NanoManager::init() {
REGISTER_SHARD_PACKET(P_CL2FE_REQ_NANO_ACTIVE, nanoSummonHandler); REGISTER_SHARD_PACKET(P_CL2FE_REQ_NANO_ACTIVE, nanoSummonHandler);
REGISTER_SHARD_PACKET(P_CL2FE_REQ_NANO_EQUIP, nanoEquipHandler); 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) { 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); Player *plr = PlayerManager::getPlayer(sock);
int16_t nanoId = plr->activeNano; int16_t nanoId = plr->activeNano;
int16_t skillId = plr->Nanos[nanoId].iSkillID; int16_t skillId = plr->Nanos[nanoId].iSkillID;
if (skillId == 1 || skillId == 13 || skillId == 42 || skillId == 59 || skillId == 78 || skillId == 103) for (auto& pwr : ActivePowers)
nanoDebuff(sock, data, nanoId, skillId, 8, 512); // Stun if (pwr.powers.count(skillId)) // std::set's contains method is C++20 only...
else if (skillId == 2 || skillId == 7 || skillId == 12 || skillId == 38 || skillId == 53 || skillId == 61 || skillId == 82 || skillId == 92 || skillId == 98 ) pwr.handle(sock, data, nanoId, skillId);
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
DEBUGLOG( DEBUGLOG(
std::cout << U16toU8(plr->PCStyle.szFirstName) << U16toU8(plr->PCStyle.szLastName) << " requested to summon nano skill " << std::endl; 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; nano.iSkillID = 0;
plr->Nanos[nanoId] = nano; plr->Nanos[nanoId] = nano;
} }
#pragma endregion
// this is where the fun begins #pragma region Active Powers
void NanoManager::nanoDebuff(CNSocket* sock, CNPacketData* data, int16_t nanoId, int16_t skillId, int16_t eSkillType, int32_t iCBFlag, int32_t damageAmount) { namespace NanoManager {
sP_CL2FE_REQ_NANO_SKILL_USE* pkt = (sP_CL2FE_REQ_NANO_SKILL_USE*)data->buf;
// sanity check bool doDebuff(CNSocket *sock, int32_t *pktdata, sSkillResult_Damage_N_Debuff *respdata, int i, int16_t iCBFlag, int32_t amount) {
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_N_Debuff))) {
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_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()) { if (NPCManager::NPCs.find(pktdata[i]) == NPCManager::NPCs.end()) {
// not sure how to best handle this // not sure how to best handle this
std::cout << "[WARN] nanoDebuffEnemy: mob ID not found" << std::endl; std::cout << "[WARN] nanoDebuffEnemy: mob ID not found" << std::endl;
return; return false;
} }
BaseNPC& mob = NPCManager::NPCs[pktdata[i]]; BaseNPC& mob = NPCManager::NPCs[pktdata[i]];
mob.appearanceData.iHP -= damageAmount; mob.appearanceData.iHP -= amount;
if (mob.appearanceData.iHP <= 0) if (mob.appearanceData.iHP <= 0)
CombatManager::giveReward(sock); CombatManager::giveReward(sock);
respdata[i].eCT = 4; respdata[i].eCT = 4;
respdata[i].iDamage = damageAmount; respdata[i].iDamage = amount;
respdata[i].iID = mob.appearanceData.iNPC_ID; respdata[i].iID = mob.appearanceData.iNPC_ID;
respdata[i].iHP = mob.appearanceData.iHP; respdata[i].iHP = mob.appearanceData.iHP;
respdata[i].iConditionBitFlag = iCBFlag; 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); std::cout << (int)mob.appearanceData.iNPC_ID << " was debuffed" << std::endl;
for (CNSocket* s : PlayerManager::players[sock].viewable)
s->sendPacket((void*)&respbuf, P_FE2CL_NANO_SKILL_USE, resplen); return true;
} }
void NanoManager::nanoHeal(CNSocket* sock, CNPacketData* data, int16_t nanoId, int16_t skillId, int16_t healAmount) { bool doHeal(CNSocket *sock, int32_t *pktdata, sSkillResult_Heal_HP *respdata, int i, int16_t iCBFlag, int32_t amount) {
sP_CL2FE_REQ_NANO_SKILL_USE* pkt = (sP_CL2FE_REQ_NANO_SKILL_USE*)data->buf; Player *plr = nullptr;
for (auto& pair : PlayerManager::players) {
if (pair.second.plr->iID == pktdata[i]) {
plr = pair.second.plr;
break;
}
}
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;
}
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); 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<class sPAYLOAD,
bool (*work)(CNSocket*,int32_t*,sPAYLOAD*,int,int16_t,int32_t),
bool isLeech=false>
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)) { 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; return;
} }
int32_t *pktdata = (int32_t*)((uint8_t*)data->buf + sizeof(sP_CL2FE_REQ_NANO_SKILL_USE)); int32_t *pktdata = (int32_t*)((uint8_t*)data->buf + sizeof(sP_CL2FE_REQ_NANO_SKILL_USE));
/* // validate response packet
* Due to the possibility of multiplication overflow (and regular buffer overflow), if (!validOutVarPacket(sizeof(sP_FE2CL_NANO_SKILL_USE_SUCC), pkt->iTargetCnt, sizeof(sPAYLOAD))) {
* both incoming and outgoing variable-length packets must be validated, at least if std::cout << "[WARN] bad sP_FE2CL_NANO_SKILL_USE packet size" << std::endl;
* 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";
return; return;
} }
size_t resplen = sizeof(sP_FE2CL_NANO_SKILL_USE) + pkt->iTargetCnt * sizeof(sSkillResult_Heal_HP); size_t resplen;
uint8_t respbuf[4096];
// 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); memset(respbuf, 0, resplen);
sP_FE2CL_NANO_SKILL_USE *resp = (sP_FE2CL_NANO_SKILL_USE*)respbuf; sP_FE2CL_NANO_SKILL_USE_SUCC *resp = (sP_FE2CL_NANO_SKILL_USE_SUCC*)respbuf;
sSkillResult_Heal_HP *respdata = (sSkillResult_Heal_HP*)(respbuf+sizeof(sP_FE2CL_NANO_SKILL_USE)); sPAYLOAD *respdata = (sPAYLOAD*)(respbuf+sizeof(sP_FE2CL_NANO_SKILL_USE_SUCC));
Player *plr = PlayerManager::getPlayer(sock);
resp->iPC_ID = plr->iID; resp->iPC_ID = plr->iID;
resp->iSkillID = skillId; resp->iSkillID = skillId;
resp->iNanoID = nanoId; resp->iNanoID = nanoId;
resp->iNanoStamina = 150; resp->iNanoStamina = 150;
resp->eST = 2; //heal enum TODO: Send these enums to Defines resp->eST = (int32_t)eSkillType;
resp->iTargetCnt = pkt->iTargetCnt; resp->iTargetCnt = pkt->iTargetCnt;
for (int i = 0; i < pkt->iTargetCnt; i++) { for (int i = 0; i < pkt->iTargetCnt; i++) {
for (auto pair : PlayerManager::players) { if (!work(sock, pktdata, respdata, i, iCBFlag, amount))
if (pair.second.plr->iID == pktdata[i]) { return;
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;
}
}
} }
sock->sendPacket((void*)&respbuf, P_FE2CL_NANO_SKILL_USE_SUCC, resplen); 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); s->sendPacket((void*)&respbuf, P_FE2CL_NANO_SKILL_USE, resplen);
} }
// active nano power dispatch table
std::vector<ActivePower> ActivePowers = {
ActivePower(StunPowers, activePower<sSkillResult_Damage_N_Debuff, doDebuff>, SkillType::STUN, 0x200, 0),
ActivePower(HealPowers, activePower<sSkillResult_Heal_HP, doHeal>, SkillType::HEAL, 0, 333),
// TODO: Recall
ActivePower(DrainPowers, activePower<sSkillResult_Damage_N_Debuff, doDebuff>, SkillType::DRAIN, 0x40000, 0),
ActivePower(SnarePowers, activePower<sSkillResult_Damage_N_Debuff, doDebuff>, SkillType::SNARE, 0x80, 0),
ActivePower(DamagePowers, activePower<sSkillResult_Damage, doDamage>, SkillType::DAMAGE, 0, 133),
// TODO: GroupRevive
ActivePower(LeechPowers, activePower<sSkillResult_Heal_HP, doLeech, true>, SkillType::LEECH, 0, 133),
ActivePower(SleepPowers, activePower<sSkillResult_Damage_N_Debuff, doDebuff>, 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) { 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); 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); 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); memset(respbuf, 0, resplen);
@ -476,7 +568,7 @@ void NanoManager::nanoBuff(CNSocket* sock, int16_t nanoId, int skillId, int16_t
resp->iSkillID = skillId; resp->iSkillID = skillId;
resp->iNanoID = nanoId; resp->iNanoID = nanoId;
resp->iNanoStamina = 150; resp->iNanoStamina = 150;
resp->eST = eSkillType; //run enum TODO: Send these enums to Defines resp->eST = eSkillType;
resp->iTargetCnt = 1; resp->iTargetCnt = 1;
// this looks stupid but in the future there will be more counts (for group powers) // 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)); 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 #pragma endregion

View File

@ -1,9 +1,43 @@
#pragma once #pragma once
#include <set>
#include <vector>
#include "CNShardServer.hpp" #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<int> powers;
ActivePowerHandler handler;
SkillType eSkillType;
int32_t flag;
int32_t amount;
ActivePower(std::set<int> 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 { namespace NanoManager {
extern std::vector<ActivePower> ActivePowers;
void init(); void init();
void nanoSummonHandler(CNSocket* sock, CNPacketData* data); void nanoSummonHandler(CNSocket* sock, CNPacketData* data);
void nanoEquipHandler(CNSocket* sock, CNPacketData* data); void nanoEquipHandler(CNSocket* sock, CNPacketData* data);
void nanoUnEquipHandler(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 setNanoSkill(CNSocket* sock, int16_t nanoId, int16_t skillId);
void resetNanoSkill(CNSocket* sock, int16_t nanoId); 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 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 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);
} }

View File

@ -8,6 +8,8 @@
#define ACTIVE_MISSION_COUNT 6 #define ACTIVE_MISSION_COUNT 6
#define PC_MAXHEALTH(level) (925 + 75 * (level))
struct Player { struct Player {
int accountId; int accountId;
int64_t SerialKey; int64_t SerialKey;