mirror of
https://github.com/OpenFusionProject/OpenFusion.git
synced 2024-11-17 03:20:06 +00:00
(WIP) TODO ABILITIES
This commit is contained in:
parent
5963ea06be
commit
92846e0eac
@ -6,774 +6,8 @@
|
|||||||
#include "Groups.hpp"
|
#include "Groups.hpp"
|
||||||
#include "Eggs.hpp"
|
#include "Eggs.hpp"
|
||||||
|
|
||||||
/*
|
|
||||||
* TODO: This file is in desperate need of deduplication and rewriting.
|
|
||||||
*/
|
|
||||||
|
|
||||||
std::map<int32_t, SkillData> Abilities::SkillTable;
|
std::map<int32_t, SkillData> Abilities::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<int> Abilities::findTargets(Player* plr, int skillID, CNPacketData* data) {
|
|
||||||
std::vector<int> 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 Abilities::removeBuff(CNSocket* sock, std::vector<int> 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 = Groups::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 Abilities::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 : Powers) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace Abilities {
|
namespace Abilities {
|
||||||
|
|
||||||
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 (NPCManager::NPCs.find(targetID) == NPCManager::NPCs.end()) {
|
|
||||||
std::cout << "[WARN] doDebuff: NPC ID not found" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
BaseNPC* npc = NPCManager::NPCs[targetID];
|
|
||||||
if (npc->kind != EntityKind::MOB) {
|
|
||||||
std::cout << "[WARN] doDebuff: NPC is not a mob" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Mob* mob = (Mob*)npc;
|
|
||||||
mob->takeDamage(sock, 0);
|
|
||||||
|
|
||||||
respdata[i].eCT = 4;
|
|
||||||
respdata[i].iID = mob->id;
|
|
||||||
respdata[i].bProtected = 1;
|
|
||||||
if (mob->skillStyle < 0 && mob->state != AIState::RETREAT
|
|
||||||
&& !(mob->cbf & CSB_BIT_FREEDOM)) { // only debuff if the enemy is not retreating, casting corruption or in freedom
|
|
||||||
mob->cbf |= bitFlag;
|
|
||||||
mob->unbuffTimes[bitFlag] = getTime() + duration * 100;
|
|
||||||
respdata[i].bProtected = 0;
|
|
||||||
}
|
|
||||||
respdata[i].iConditionBitFlag = mob->cbf;
|
|
||||||
|
|
||||||
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 (NPCManager::NPCs.find(targetID) == NPCManager::NPCs.end()) {
|
|
||||||
// not sure how to best handle this
|
|
||||||
std::cout << "[WARN] doDamageNDebuff: NPC ID not found" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
BaseNPC* npc = NPCManager::NPCs[targetID];
|
|
||||||
if (npc->kind != EntityKind::MOB) {
|
|
||||||
std::cout << "[WARN] doDamageNDebuff: NPC is not a mob" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Mob* mob = (Mob*)npc;
|
|
||||||
|
|
||||||
mob->takeDamage(sock, 0);
|
|
||||||
|
|
||||||
respdata[i].eCT = 4;
|
|
||||||
respdata[i].iDamage = duration / 10;
|
|
||||||
respdata[i].iID = mob->id;
|
|
||||||
respdata[i].iHP = mob->hp;
|
|
||||||
respdata[i].bProtected = 1;
|
|
||||||
if (mob->skillStyle < 0 && mob->state != AIState::RETREAT
|
|
||||||
&& !(mob->cbf & CSB_BIT_FREEDOM)) { // only debuff if the enemy is not retreating, casting corruption or in freedom
|
|
||||||
mob->cbf |= bitFlag;
|
|
||||||
mob->unbuffTimes[bitFlag] = getTime() + duration * 100;
|
|
||||||
respdata[i].bProtected = 0;
|
|
||||||
}
|
|
||||||
respdata[i].iConditionBitFlag = mob->cbf;
|
|
||||||
|
|
||||||
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 (NPCManager::NPCs.find(targetID) == NPCManager::NPCs.end()) {
|
|
||||||
// not sure how to best handle this
|
|
||||||
std::cout << "[WARN] doDamage: NPC ID not found" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
BaseNPC* npc = NPCManager::NPCs[targetID];
|
|
||||||
if (npc->kind != EntityKind::MOB) {
|
|
||||||
std::cout << "[WARN] doDamage: NPC is not a mob" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Mob* mob = (Mob*)npc;
|
|
||||||
Player *plr = PlayerManager::getPlayer(sock);
|
|
||||||
|
|
||||||
int damage = mob->takeDamage(sock, std::max(PC_MAXHEALTH(plr->level) * amount / 1000, mob->maxHealth * amount / 1000));
|
|
||||||
|
|
||||||
respdata[i].eCT = 4;
|
|
||||||
respdata[i].iDamage = damage;
|
|
||||||
respdata[i].iID = mob->id;
|
|
||||||
respdata[i].iHP = mob->hp;
|
|
||||||
|
|
||||||
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 (NPCManager::NPCs.find(targetID) == NPCManager::NPCs.end()) {
|
|
||||||
// not sure how to best handle this
|
|
||||||
std::cout << "[WARN] doLeech: NPC ID not found" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
BaseNPC* npc = NPCManager::NPCs[targetID];
|
|
||||||
if (npc->kind != EntityKind::MOB) {
|
|
||||||
std::cout << "[WARN] doLeech: NPC is not a mob" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Mob* mob = (Mob*)npc;
|
|
||||||
|
|
||||||
int damage = mob->takeDamage(sock, amount * 2);
|
|
||||||
|
|
||||||
damagedata->eCT = 4;
|
|
||||||
damagedata->iDamage = damage;
|
|
||||||
damagedata->iID = mob->id;
|
|
||||||
damagedata->iHP = mob->hp;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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<CNSocket*, int32_t> key = std::make_pair(sock, bitFlag);
|
|
||||||
time_t until = getTime() + (time_t)duration * 100;
|
|
||||||
Eggs::EggBuffs[key] = until;
|
|
||||||
}
|
|
||||||
respdata[i].iConditionBitFlag = plr->iConditionBitFlag;
|
|
||||||
|
|
||||||
if (plr->HP <= 0) {
|
|
||||||
if (!MobAI::aggroCheck(mob, getTime()))
|
|
||||||
mob->transition(AIState::RETREAT, mob->target);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 (NPCManager::NPCs.find(targetID) == NPCManager::NPCs.end()) {
|
|
||||||
std::cout << "[WARN] doHeal: NPC ID not found" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
BaseNPC* npc = NPCManager::NPCs[targetID];
|
|
||||||
if (npc->kind != EntityKind::MOB) {
|
|
||||||
std::cout << "[WARN] doHeal: NPC is not a mob" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Mob* targetMob = (Mob*)npc;
|
|
||||||
|
|
||||||
int healedAmount = amount * targetMob->maxHealth / 1000;
|
|
||||||
targetMob->hp += healedAmount;
|
|
||||||
if (targetMob->hp > targetMob->maxHealth)
|
|
||||||
targetMob->hp = targetMob->maxHealth;
|
|
||||||
|
|
||||||
respdata[i].eCT = 4;
|
|
||||||
respdata[i].iID = targetMob->id;
|
|
||||||
respdata[i].iHP = targetMob->hp;
|
|
||||||
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->hp += healedAmount;
|
|
||||||
if (mob->hp > mob->maxHealth)
|
|
||||||
mob->hp = mob->maxHealth;
|
|
||||||
|
|
||||||
respdata[i].eCT = 4;
|
|
||||||
respdata[i].iID = mob->id;
|
|
||||||
respdata[i].iHP = mob->hp;
|
|
||||||
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) {
|
|
||||||
if (!MobAI::aggroCheck(mob, getTime()))
|
|
||||||
mob->transition(AIState::RETREAT, mob->target);
|
|
||||||
}
|
|
||||||
|
|
||||||
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->hp += healedAmount;
|
|
||||||
if (mob->hp > mob->maxHealth)
|
|
||||||
mob->hp = mob->maxHealth;
|
|
||||||
|
|
||||||
healdata->eCT = 4;
|
|
||||||
healdata->iID = mob->id;
|
|
||||||
healdata->iHP = mob->hp;
|
|
||||||
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) {
|
|
||||||
if (!MobAI::aggroCheck(mob, getTime()))
|
|
||||||
mob->transition(AIState::RETREAT, mob->target);
|
|
||||||
}
|
|
||||||
|
|
||||||
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->id;
|
|
||||||
mob->cbf |= bitFlag;
|
|
||||||
respdata[i].iConditionBitFlag = mob->cbf;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class sPAYLOAD,
|
|
||||||
bool (*work)(EntityRef, sPAYLOAD*, int, int32_t, int32_t, int16_t, int16_t, int16_t)>
|
|
||||||
void power(EntityRef ref, std::vector<int> targetData,
|
|
||||||
int16_t nanoID, int16_t skillID, int16_t duration, int16_t amount,
|
|
||||||
int16_t skillType, int32_t bitFlag, int16_t timeBuffID) {
|
|
||||||
|
|
||||||
/*** OLD NANO HANDLER ***
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*** OLD MOB ABILITY HANDLER ***
|
|
||||||
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->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<Power> Powers = {};/*
|
|
||||||
Power(EST_STUN, CSB_BIT_STUN, ECSB_STUN, power<sSkillResult_Damage_N_Debuff, doDamageNDebuff>),
|
|
||||||
Power(EST_HEAL_HP, CSB_BIT_NONE, ECSB_NONE, power<sSkillResult_Heal_HP, doHeal>),
|
|
||||||
Power(EST_BOUNDINGBALL, CSB_BIT_BOUNDINGBALL, ECSB_BOUNDINGBALL, power<sSkillResult_Buff, doDebuff>),
|
|
||||||
Power(EST_SNARE, CSB_BIT_DN_MOVE_SPEED, ECSB_DN_MOVE_SPEED, power<sSkillResult_Damage_N_Debuff, doDamageNDebuff>),
|
|
||||||
Power(EST_DAMAGE, CSB_BIT_NONE, ECSB_NONE, power<sSkillResult_Damage, doDamage>),
|
|
||||||
Power(EST_BLOODSUCKING, CSB_BIT_NONE, ECSB_NONE, power<sSkillResult_Heal_HP, doLeech>),
|
|
||||||
Power(EST_SLEEP, CSB_BIT_MEZ, ECSB_MEZ, power<sSkillResult_Damage_N_Debuff, doDamageNDebuff>),
|
|
||||||
Power(EST_REWARDBLOB, CSB_BIT_REWARD_BLOB, ECSB_REWARD_BLOB, power<sSkillResult_Buff, doBuff>),
|
|
||||||
Power(EST_RUN, CSB_BIT_UP_MOVE_SPEED, ECSB_UP_MOVE_SPEED, power<sSkillResult_Buff, doBuff>),
|
|
||||||
Power(EST_REWARDCASH, CSB_BIT_REWARD_CASH, ECSB_REWARD_CASH, power<sSkillResult_Buff, doBuff>),
|
|
||||||
Power(EST_PROTECTBATTERY, CSB_BIT_PROTECT_BATTERY, ECSB_PROTECT_BATTERY, power<sSkillResult_Buff, doBuff>),
|
|
||||||
Power(EST_MINIMAPENEMY, CSB_BIT_MINIMAP_ENEMY, ECSB_MINIMAP_ENEMY, power<sSkillResult_Buff, doBuff>),
|
|
||||||
Power(EST_PROTECTINFECTION, CSB_BIT_PROTECT_INFECTION, ECSB_PROTECT_INFECTION, power<sSkillResult_Buff, doBuff>),
|
|
||||||
Power(EST_JUMP, CSB_BIT_UP_JUMP_HEIGHT, ECSB_UP_JUMP_HEIGHT, power<sSkillResult_Buff, doBuff>),
|
|
||||||
Power(EST_FREEDOM, CSB_BIT_FREEDOM, ECSB_FREEDOM, power<sSkillResult_Buff, doBuff>),
|
|
||||||
Power(EST_PHOENIX, CSB_BIT_PHOENIX, ECSB_PHOENIX, power<sSkillResult_Buff, doBuff>),
|
|
||||||
Power(EST_STEALTH, CSB_BIT_UP_STEALTH, ECSB_UP_STEALTH, power<sSkillResult_Buff, doBuff>),
|
|
||||||
Power(EST_MINIMAPTRESURE, CSB_BIT_MINIMAP_TRESURE, ECSB_MINIMAP_TRESURE, power<sSkillResult_Buff, doBuff>),
|
|
||||||
Power(EST_RECALL, CSB_BIT_NONE, ECSB_NONE, power<sSkillResult_Move, doMove>),
|
|
||||||
Power(EST_RECALL_GROUP, CSB_BIT_NONE, ECSB_NONE, power<sSkillResult_Move, doMove>),
|
|
||||||
Power(EST_RETROROCKET_SELF, CSB_BIT_NONE, ECSB_NONE, power<sSkillResult_Buff, doBuff>),
|
|
||||||
Power(EST_PHOENIX_GROUP, CSB_BIT_NONE, ECSB_NONE, power<sSkillResult_Resurrect, doResurrect>),
|
|
||||||
Power(EST_NANOSTIMPAK, CSB_BIT_STIMPAKSLOT1, ECSB_STIMPAKSLOT1, power<sSkillResult_Buff, doBuff>),
|
|
||||||
Power(EST_NANOSTIMPAK, CSB_BIT_STIMPAKSLOT2, ECSB_STIMPAKSLOT2, power<sSkillResult_Buff, doBuff>),
|
|
||||||
Power(EST_NANOSTIMPAK, CSB_BIT_STIMPAKSLOT3, ECSB_STIMPAKSLOT3, power<sSkillResult_Buff, doBuff>),
|
|
||||||
//
|
|
||||||
Power(EST_STUN, CSB_BIT_STUN, ECSB_STUN, power<sSkillResult_Damage_N_Debuff, doDamageNDebuff>),
|
|
||||||
Power(EST_HEAL_HP, CSB_BIT_NONE, ECSB_NONE, power<sSkillResult_Heal_HP, doHeal>),
|
|
||||||
Power(EST_RETURNHOMEHEAL, CSB_BIT_NONE, ECSB_NONE, power<sSkillResult_Heal_HP, doReturnHeal>),
|
|
||||||
Power(EST_SNARE, CSB_BIT_DN_MOVE_SPEED, ECSB_DN_MOVE_SPEED, power<sSkillResult_Damage_N_Debuff, doDamageNDebuff>),
|
|
||||||
Power(EST_DAMAGE, CSB_BIT_NONE, ECSB_NONE, power<sSkillResult_Damage, doDamage>),
|
|
||||||
Power(EST_BATTERYDRAIN, CSB_BIT_NONE, ECSB_NONE, power<sSkillResult_BatteryDrain, doBatteryDrain>),
|
|
||||||
Power(EST_SLEEP, CSB_BIT_MEZ, ECSB_MEZ, power<sSkillResult_Damage_N_Debuff, doDamageNDebuff>),
|
|
||||||
Power(EST_BLOODSUCKING, CSB_BIT_NONE, ECSB_NONE, power<sSkillResult_Heal_HP, doLeech>),
|
|
||||||
Power(EST_FREEDOM, CSB_BIT_FREEDOM, ECSB_FREEDOM, power<sSkillResult_Buff, doBuff>)
|
|
||||||
};*/
|
|
||||||
|
|
||||||
}; // namespace
|
}; // namespace
|
||||||
|
@ -3,29 +3,6 @@
|
|||||||
#include "core/Core.hpp"
|
#include "core/Core.hpp"
|
||||||
#include "Combat.hpp"
|
#include "Combat.hpp"
|
||||||
|
|
||||||
typedef void (*PowerHandler)(EntityRef, std::vector<int>, int16_t, int16_t, int16_t, int16_t, int16_t, int32_t, int16_t);
|
|
||||||
|
|
||||||
struct Power {
|
|
||||||
int16_t skillType;
|
|
||||||
int32_t bitFlag;
|
|
||||||
int16_t timeBuffID;
|
|
||||||
PowerHandler handler;
|
|
||||||
|
|
||||||
Power(int16_t s, int32_t b, int16_t t, PowerHandler h) : skillType(s), bitFlag(b), timeBuffID(t), handler(h) {}
|
|
||||||
|
|
||||||
void handle(EntityRef ref, std::vector<int> targetData, int16_t nanoID, int16_t skillID, int16_t duration, int16_t amount) {
|
|
||||||
if (handler == nullptr)
|
|
||||||
return;
|
|
||||||
|
|
||||||
handler(ref, targetData, nanoID, skillID, duration, amount, skillType, bitFlag, timeBuffID);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* overload for non-nano abilities */
|
|
||||||
void handle(EntityRef ref, std::vector<int> targetData, int16_t skillID, int16_t duration, int16_t amount) {
|
|
||||||
handle(ref, targetData, -1, skillID, duration, amount);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SkillData {
|
struct SkillData {
|
||||||
int skillType;
|
int skillType;
|
||||||
int targetType;
|
int targetType;
|
||||||
@ -37,11 +14,5 @@ struct SkillData {
|
|||||||
};
|
};
|
||||||
|
|
||||||
namespace Abilities {
|
namespace Abilities {
|
||||||
extern std::vector<Power> Powers;
|
|
||||||
extern std::map<int32_t, SkillData> SkillTable;
|
extern std::map<int32_t, SkillData> SkillTable;
|
||||||
|
|
||||||
void removeBuff(CNSocket* sock, std::vector<int> 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);
|
|
||||||
|
|
||||||
std::vector<int> findTargets(Player* plr, int skillID, CNPacketData* data = nullptr);
|
|
||||||
}
|
}
|
||||||
|
36
src/Eggs.cpp
36
src/Eggs.cpp
@ -19,7 +19,8 @@ int Eggs::eggBuffPlayer(CNSocket* sock, int skillId, int eggId, int duration) {
|
|||||||
Player* otherPlr = PlayerManager::getPlayerFromID(plr->iIDGroup);
|
Player* otherPlr = PlayerManager::getPlayerFromID(plr->iIDGroup);
|
||||||
|
|
||||||
int bitFlag = Groups::getGroupFlags(otherPlr);
|
int bitFlag = Groups::getGroupFlags(otherPlr);
|
||||||
int CBFlag = Abilities::applyBuff(sock, skillId, 1, 3, bitFlag);
|
// TODO ABILITIES
|
||||||
|
int CBFlag = 0;// Abilities::applyBuff(sock, skillId, 1, 3, bitFlag);
|
||||||
|
|
||||||
size_t resplen;
|
size_t resplen;
|
||||||
|
|
||||||
@ -100,23 +101,24 @@ static void eggStep(CNServer* serv, time_t currTime) {
|
|||||||
Player* otherPlr = PlayerManager::getPlayerFromID(plr->iIDGroup);
|
Player* otherPlr = PlayerManager::getPlayerFromID(plr->iIDGroup);
|
||||||
|
|
||||||
int groupFlags = Groups::getGroupFlags(otherPlr);
|
int groupFlags = Groups::getGroupFlags(otherPlr);
|
||||||
for (auto& pwr : Abilities::Powers) {
|
// TODO ABILITIES
|
||||||
if (pwr.bitFlag == CBFlag) { // pick the power with the right flag and unbuff
|
//for (auto& pwr : Abilities::Powers) {
|
||||||
INITSTRUCT(sP_FE2CL_PC_BUFF_UPDATE, resp);
|
// if (pwr.bitFlag == CBFlag) { // pick the power with the right flag and unbuff
|
||||||
resp.eCSTB = pwr.timeBuffID;
|
// INITSTRUCT(sP_FE2CL_PC_BUFF_UPDATE, resp);
|
||||||
resp.eTBU = 2;
|
// resp.eCSTB = pwr.timeBuffID;
|
||||||
resp.eTBT = 3; // for egg buffs
|
// resp.eTBU = 2;
|
||||||
plr->iConditionBitFlag &= ~CBFlag;
|
// resp.eTBT = 3; // for egg buffs
|
||||||
resp.iConditionBitFlag = plr->iConditionBitFlag |= groupFlags | plr->iSelfConditionBitFlag;
|
// plr->iConditionBitFlag &= ~CBFlag;
|
||||||
sock->sendPacket(resp, P_FE2CL_PC_BUFF_UPDATE);
|
// resp.iConditionBitFlag = plr->iConditionBitFlag |= groupFlags | plr->iSelfConditionBitFlag;
|
||||||
|
// sock->sendPacket(resp, P_FE2CL_PC_BUFF_UPDATE);
|
||||||
|
|
||||||
INITSTRUCT(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT, resp2); // send a buff timeout to other players
|
// INITSTRUCT(sP_FE2CL_CHAR_TIME_BUFF_TIME_OUT, resp2); // send a buff timeout to other players
|
||||||
resp2.eCT = 1;
|
// resp2.eCT = 1;
|
||||||
resp2.iID = plr->iID;
|
// resp2.iID = plr->iID;
|
||||||
resp2.iConditionBitFlag = plr->iConditionBitFlag;
|
// resp2.iConditionBitFlag = plr->iConditionBitFlag;
|
||||||
PlayerManager::sendToViewable(sock, resp2, P_FE2CL_CHAR_TIME_BUFF_TIME_OUT);
|
// PlayerManager::sendToViewable(sock, resp2, P_FE2CL_CHAR_TIME_BUFF_TIME_OUT);
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
// remove buff from the map
|
// remove buff from the map
|
||||||
it = EggBuffs.erase(it);
|
it = EggBuffs.erase(it);
|
||||||
}
|
}
|
||||||
|
@ -135,10 +135,11 @@ static void joinGroup(CNSocket* sock, CNPacketData* data) {
|
|||||||
// client doesnt read nano data here
|
// client doesnt read nano data here
|
||||||
|
|
||||||
if (varPlr != plr) { // apply the new member's buffs to the group and the group's buffs to the new member
|
if (varPlr != plr) { // apply the new member's buffs to the group and the group's buffs to the new member
|
||||||
if (Abilities::SkillTable[varPlr->Nanos[varPlr->activeNano].iSkillID].targetType == 3)
|
// TODO ABILITIES
|
||||||
|
/*if (Abilities::SkillTable[varPlr->Nanos[varPlr->activeNano].iSkillID].targetType == 3)
|
||||||
Abilities::applyBuff(sock, varPlr->Nanos[varPlr->activeNano].iSkillID, 1, 1, bitFlag);
|
Abilities::applyBuff(sock, varPlr->Nanos[varPlr->activeNano].iSkillID, 1, 1, bitFlag);
|
||||||
if (Abilities::SkillTable[plr->Nanos[plr->activeNano].iSkillID].targetType == 3)
|
if (Abilities::SkillTable[plr->Nanos[plr->activeNano].iSkillID].targetType == 3)
|
||||||
Abilities::applyBuff(sockTo, plr->Nanos[plr->activeNano].iSkillID, 1, 1, bitFlag);
|
Abilities::applyBuff(sockTo, plr->Nanos[plr->activeNano].iSkillID, 1, 1, bitFlag);*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,7 +222,8 @@ static void groupUnbuff(Player* plr) {
|
|||||||
Player* otherPlr = PlayerManager::getPlayerFromID(plr->groupIDs[i]);
|
Player* otherPlr = PlayerManager::getPlayerFromID(plr->groupIDs[i]);
|
||||||
CNSocket* sock = PlayerManager::getSockFromID(plr->groupIDs[n]);
|
CNSocket* sock = PlayerManager::getSockFromID(plr->groupIDs[n]);
|
||||||
|
|
||||||
Abilities::applyBuff(sock, otherPlr->Nanos[otherPlr->activeNano].iSkillID, 2, 1, 0);
|
// TODO ABILITIES
|
||||||
|
//Abilities::applyBuff(sock, otherPlr->Nanos[otherPlr->activeNano].iSkillID, 2, 1, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -295,10 +297,11 @@ void Groups::groupKickPlayer(Player* plr) {
|
|||||||
moveDown = 1;
|
moveDown = 1;
|
||||||
otherPlr->groupIDs[i] = 0;
|
otherPlr->groupIDs[i] = 0;
|
||||||
} else { // remove the leaving member's buffs from the group and remove the group buffs from the leaving member.
|
} else { // remove the leaving member's buffs from the group and remove the group buffs from the leaving member.
|
||||||
if (Abilities::SkillTable[varPlr->Nanos[varPlr->activeNano].iSkillID].targetType == 3)
|
// TODO ABILITIES
|
||||||
|
/*if (Abilities::SkillTable[varPlr->Nanos[varPlr->activeNano].iSkillID].targetType == 3)
|
||||||
Abilities::applyBuff(sock, varPlr->Nanos[varPlr->activeNano].iSkillID, 2, 1, 0);
|
Abilities::applyBuff(sock, varPlr->Nanos[varPlr->activeNano].iSkillID, 2, 1, 0);
|
||||||
if (Abilities::SkillTable[plr->Nanos[varPlr->activeNano].iSkillID].targetType == 3)
|
if (Abilities::SkillTable[plr->Nanos[varPlr->activeNano].iSkillID].targetType == 3)
|
||||||
Abilities::applyBuff(sockTo, plr->Nanos[plr->activeNano].iSkillID, 2, 1, bitFlag);
|
Abilities::applyBuff(sockTo, plr->Nanos[plr->activeNano].iSkillID, 2, 1, bitFlag);*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,10 +293,11 @@ static void dealCorruption(Mob *mob, std::vector<int> targetData, int skillID, i
|
|||||||
if (plr->Nanos[plr->activeNano].iStamina > 150)
|
if (plr->Nanos[plr->activeNano].iStamina > 150)
|
||||||
respdata[i].iNanoStamina = plr->Nanos[plr->activeNano].iStamina = 150;
|
respdata[i].iNanoStamina = plr->Nanos[plr->activeNano].iStamina = 150;
|
||||||
// fire damage power disguised as a corruption attack back at the enemy
|
// fire damage power disguised as a corruption attack back at the enemy
|
||||||
std::vector<int> targetData2 = {1, mob->id, 0, 0, 0};
|
// TODO ABILITIES
|
||||||
|
/*std::vector<int> targetData2 = {1, mob->id, 0, 0, 0};
|
||||||
for (auto& pwr : Abilities::Powers)
|
for (auto& pwr : Abilities::Powers)
|
||||||
if (pwr.skillType == EST_DAMAGE)
|
if (pwr.skillType == EST_DAMAGE)
|
||||||
pwr.handle(sock, targetData2, plr->activeNano, skillID, 0, 200);
|
pwr.handle(sock, targetData2, plr->activeNano, skillID, 0, 200);*/
|
||||||
} else {
|
} else {
|
||||||
respdata[i].iHitFlag = HF_BIT_STYLE_LOSE;
|
respdata[i].iHitFlag = HF_BIT_STYLE_LOSE;
|
||||||
respdata[i].iDamage = Abilities::SkillTable[skillID].powerIntensity[0] * PC_MAXHEALTH((int)mob->data["m_iNpcLevel"]) / 1500;
|
respdata[i].iDamage = Abilities::SkillTable[skillID].powerIntensity[0] * PC_MAXHEALTH((int)mob->data["m_iNpcLevel"]) / 1500;
|
||||||
@ -369,9 +370,10 @@ static void useAbilities(Mob *mob, time_t currTime) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& pwr : Abilities::Powers)
|
// TODO ABILITIES
|
||||||
|
/*for (auto& pwr : Abilities::Powers)
|
||||||
if (pwr.skillType == Abilities::SkillTable[skillID].skillType)
|
if (pwr.skillType == Abilities::SkillTable[skillID].skillType)
|
||||||
pwr.handle(mob->id, targetData, skillID, Abilities::SkillTable[skillID].durationTime[0], Abilities::SkillTable[skillID].powerIntensity[0]);
|
pwr.handle(mob->id, targetData, skillID, Abilities::SkillTable[skillID].durationTime[0], Abilities::SkillTable[skillID].powerIntensity[0]);*/
|
||||||
mob->skillStyle = -3; // eruption cooldown
|
mob->skillStyle = -3; // eruption cooldown
|
||||||
mob->nextAttack = currTime + 1000;
|
mob->nextAttack = currTime + 1000;
|
||||||
return;
|
return;
|
||||||
@ -389,13 +391,14 @@ static void useAbilities(Mob *mob, time_t currTime) {
|
|||||||
|
|
||||||
if (random < prob1) { // active skill hit
|
if (random < prob1) { // active skill hit
|
||||||
int skillID = (int)mob->data["m_iActiveSkill1"];
|
int skillID = (int)mob->data["m_iActiveSkill1"];
|
||||||
std::vector<int> targetData = {1, plr->iID, 0, 0, 0};
|
// TODO ABILITIES
|
||||||
for (auto& pwr : Abilities::Powers)
|
//std::vector<int> targetData = {1, plr->iID, 0, 0, 0};
|
||||||
if (pwr.skillType == Abilities::SkillTable[skillID].skillType) {
|
//for (auto& pwr : Abilities::Powers)
|
||||||
if (pwr.bitFlag != 0 && (plr->iConditionBitFlag & pwr.bitFlag))
|
// if (pwr.skillType == Abilities::SkillTable[skillID].skillType) {
|
||||||
return; // prevent debuffing a player twice
|
// if (pwr.bitFlag != 0 && (plr->iConditionBitFlag & pwr.bitFlag))
|
||||||
pwr.handle(mob->id, targetData, skillID, Abilities::SkillTable[skillID].durationTime[0], Abilities::SkillTable[skillID].powerIntensity[0]);
|
// return; // prevent debuffing a player twice
|
||||||
}
|
// pwr.handle(mob->id, targetData, skillID, Abilities::SkillTable[skillID].durationTime[0], Abilities::SkillTable[skillID].powerIntensity[0]);
|
||||||
|
// }
|
||||||
mob->nextAttack = currTime + (int)mob->data["m_iDelayTime"] * 100;
|
mob->nextAttack = currTime + (int)mob->data["m_iDelayTime"] * 100;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -785,10 +788,11 @@ void MobAI::onRoamStart(CombatNPC* npc, EntityRef src) {
|
|||||||
self->cbf = 0;
|
self->cbf = 0;
|
||||||
|
|
||||||
// cast a return home heal spell, this is the right way(tm)
|
// cast a return home heal spell, this is the right way(tm)
|
||||||
std::vector<int> targetData = { 1, 0, 0, 0, 0 };
|
// TODO ABILITIES
|
||||||
|
/*std::vector<int> targetData = { 1, 0, 0, 0, 0 };
|
||||||
for (auto& pwr : Abilities::Powers)
|
for (auto& pwr : Abilities::Powers)
|
||||||
if (pwr.skillType == Abilities::SkillTable[110].skillType)
|
if (pwr.skillType == Abilities::SkillTable[110].skillType)
|
||||||
pwr.handle(self->id, targetData, 110, Abilities::SkillTable[110].durationTime[0], Abilities::SkillTable[110].powerIntensity[0]);
|
pwr.handle(self->id, targetData, 110, Abilities::SkillTable[110].durationTime[0], Abilities::SkillTable[110].powerIntensity[0]);*/
|
||||||
// clear outlying debuffs
|
// clear outlying debuffs
|
||||||
clearDebuff(self);
|
clearDebuff(self);
|
||||||
}
|
}
|
||||||
@ -806,10 +810,11 @@ void MobAI::onCombatStart(CombatNPC* npc, EntityRef src) {
|
|||||||
self->roamZ = self->z;
|
self->roamZ = self->z;
|
||||||
|
|
||||||
int skillID = (int)self->data["m_iPassiveBuff"]; // cast passive
|
int skillID = (int)self->data["m_iPassiveBuff"]; // cast passive
|
||||||
std::vector<int> targetData = { 1, self->id, 0, 0, 0 };
|
// TODO ABILITIES
|
||||||
|
/*std::vector<int> targetData = { 1, self->id, 0, 0, 0 };
|
||||||
for (auto& pwr : Abilities::Powers)
|
for (auto& pwr : Abilities::Powers)
|
||||||
if (pwr.skillType == Abilities::SkillTable[skillID].skillType)
|
if (pwr.skillType == Abilities::SkillTable[skillID].skillType)
|
||||||
pwr.handle(self->id, targetData, skillID, Abilities::SkillTable[skillID].durationTime[0], Abilities::SkillTable[skillID].powerIntensity[0]);
|
pwr.handle(self->id, targetData, skillID, Abilities::SkillTable[skillID].durationTime[0], Abilities::SkillTable[skillID].powerIntensity[0]);*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void MobAI::onRetreat(CombatNPC* npc, EntityRef src) {
|
void MobAI::onRetreat(CombatNPC* npc, EntityRef src) {
|
||||||
|
@ -87,11 +87,12 @@ void Nanos::summonNano(CNSocket *sock, int slot, bool silent) {
|
|||||||
|
|
||||||
// passive nano unbuffing
|
// passive nano unbuffing
|
||||||
if (Abilities::SkillTable[skillID].drainType == 2) {
|
if (Abilities::SkillTable[skillID].drainType == 2) {
|
||||||
std::vector<int> targetData = Abilities::findTargets(plr, skillID);
|
// TODO ABILITIES
|
||||||
|
/*std::vector<int> targetData = Abilities::findTargets(plr, skillID);
|
||||||
|
|
||||||
for (auto& pwr : Abilities::Powers)
|
for (auto& pwr : Abilities::Powers)
|
||||||
if (pwr.skillType == Abilities::SkillTable[skillID].skillType)
|
if (pwr.skillType == Abilities::SkillTable[skillID].skillType)
|
||||||
Abilities::removeBuff(sock, targetData, pwr.bitFlag, pwr.timeBuffID, 0,(Abilities::SkillTable[skillID].targetType == 3));
|
Abilities::removeBuff(sock, targetData, pwr.bitFlag, pwr.timeBuffID, 0,(Abilities::SkillTable[skillID].targetType == 3));*/
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nanoID >= NANO_COUNT || nanoID < 0)
|
if (nanoID >= NANO_COUNT || nanoID < 0)
|
||||||
@ -102,20 +103,20 @@ void Nanos::summonNano(CNSocket *sock, int slot, bool silent) {
|
|||||||
|
|
||||||
// passive nano buffing
|
// passive nano buffing
|
||||||
if (Abilities::SkillTable[skillID].drainType == 2) {
|
if (Abilities::SkillTable[skillID].drainType == 2) {
|
||||||
std::vector<int> targetData = Abilities::findTargets(plr, skillID);
|
|
||||||
|
|
||||||
int boost = 0;
|
int boost = 0;
|
||||||
if (getNanoBoost(plr))
|
if (getNanoBoost(plr))
|
||||||
boost = 1;
|
boost = 1;
|
||||||
|
|
||||||
for (auto& pwr : Abilities::Powers) {
|
// TODO ABILITIES
|
||||||
if (pwr.skillType == Abilities::SkillTable[skillID].skillType) {
|
//std::vector<int> targetData = Abilities::findTargets(plr, skillID);
|
||||||
resp.eCSTB___Add = 1; // the part that makes nano go ZOOMAZOOM
|
//for (auto& pwr : Abilities::Powers) {
|
||||||
plr->nanoDrainRate = Abilities::SkillTable[skillID].batteryUse[boost*3];
|
// if (pwr.skillType == Abilities::SkillTable[skillID].skillType) {
|
||||||
|
// resp.eCSTB___Add = 1; // the part that makes nano go ZOOMAZOOM
|
||||||
|
// plr->nanoDrainRate = Abilities::SkillTable[skillID].batteryUse[boost*3];
|
||||||
|
|
||||||
pwr.handle(sock, targetData, nanoID, skillID, 0, Abilities::SkillTable[skillID].powerIntensity[boost]);
|
// pwr.handle(sock, targetData, nanoID, skillID, 0, Abilities::SkillTable[skillID].powerIntensity[boost]);
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!silent) // silent nano death but only for the summoning player
|
if (!silent) // silent nano death but only for the summoning player
|
||||||
@ -296,8 +297,6 @@ static void nanoSkillUseHandler(CNSocket* sock, CNPacketData* data) {
|
|||||||
std::cout << PlayerManager::getPlayerName(plr) << " requested to summon nano skill " << std::endl;
|
std::cout << PlayerManager::getPlayerName(plr) << " requested to summon nano skill " << std::endl;
|
||||||
)
|
)
|
||||||
|
|
||||||
std::vector<int> targetData = Abilities::findTargets(plr, skillID, data);
|
|
||||||
|
|
||||||
int boost = 0;
|
int boost = 0;
|
||||||
if (getNanoBoost(plr))
|
if (getNanoBoost(plr))
|
||||||
boost = 1;
|
boost = 1;
|
||||||
@ -306,9 +305,11 @@ static void nanoSkillUseHandler(CNSocket* sock, CNPacketData* data) {
|
|||||||
if (plr->Nanos[plr->activeNano].iStamina < 0)
|
if (plr->Nanos[plr->activeNano].iStamina < 0)
|
||||||
plr->Nanos[plr->activeNano].iStamina = 0;
|
plr->Nanos[plr->activeNano].iStamina = 0;
|
||||||
|
|
||||||
|
// TODO ABILITIES
|
||||||
|
/*std::vector<int> targetData = Abilities::findTargets(plr, skillID, data);
|
||||||
for (auto& pwr : Abilities::Powers)
|
for (auto& pwr : Abilities::Powers)
|
||||||
if (pwr.skillType == Abilities::SkillTable[skillID].skillType)
|
if (pwr.skillType == Abilities::SkillTable[skillID].skillType)
|
||||||
pwr.handle(sock, targetData, nanoID, skillID, Abilities::SkillTable[skillID].durationTime[boost], Abilities::SkillTable[skillID].powerIntensity[boost]);
|
pwr.handle(sock, targetData, nanoID, skillID, Abilities::SkillTable[skillID].durationTime[boost], Abilities::SkillTable[skillID].powerIntensity[boost]);*/
|
||||||
|
|
||||||
if (plr->Nanos[plr->activeNano].iStamina < 0)
|
if (plr->Nanos[plr->activeNano].iStamina < 0)
|
||||||
summonNano(sock, -1);
|
summonNano(sock, -1);
|
||||||
|
@ -411,7 +411,8 @@ static void revivePlayer(CNSocket* sock, CNPacketData* data) {
|
|||||||
if (!(plr->iConditionBitFlag & CSB_BIT_PHOENIX))
|
if (!(plr->iConditionBitFlag & CSB_BIT_PHOENIX))
|
||||||
return; // sanity check
|
return; // sanity check
|
||||||
plr->Nanos[plr->activeNano].iStamina = 0;
|
plr->Nanos[plr->activeNano].iStamina = 0;
|
||||||
Abilities::applyBuff(sock, plr->Nanos[plr->activeNano].iSkillID, 2, 1, 0);
|
// TODO ABILITIES
|
||||||
|
//Abilities::applyBuff(sock, plr->Nanos[plr->activeNano].iSkillID, 2, 1, 0);
|
||||||
// fallthrough
|
// fallthrough
|
||||||
case ePCRegenType::HereByPhoenixGroup: // revived by group member's nano
|
case ePCRegenType::HereByPhoenixGroup: // revived by group member's nano
|
||||||
plr->HP = PC_MAXHEALTH(plr->level) / 2;
|
plr->HP = PC_MAXHEALTH(plr->level) / 2;
|
||||||
|
Loading…
Reference in New Issue
Block a user