diff --git a/src/Abilities.cpp b/src/Abilities.cpp index 8c7f84d..54f8c91 100644 --- a/src/Abilities.cpp +++ b/src/Abilities.cpp @@ -8,6 +8,46 @@ std::map Abilities::SkillTable; -namespace Abilities { +/* +// New email notification +static void emailUpdateCheck(CNSocket* sock, CNPacketData* data) { + INITSTRUCT(sP_FE2CL_REP_PC_NEW_EMAIL, resp); + resp.iNewEmailCnt = Database::getUnreadEmailCount(PlayerManager::getPlayer(sock)->iID); + sock->sendPacket(resp, P_FE2CL_REP_PC_NEW_EMAIL); +} +*/ -}; // namespace +std::vector Abilities::matchTargets(SkillData* skill, int count, int32_t *ids) { + + std::vector targets; + + for (int i = 0; i < count; i++) { + int32_t id = ids[i]; + if (skill->targetType == SkillTargetType::MOBS) { + // mob? + if (NPCManager::NPCs.find(id) != NPCManager::NPCs.end()) targets.push_back(id); + else std::cout << "[WARN] skill: id not found\n"; + } else { + // player? + CNSocket* sock = PlayerManager::getSockFromID(id); + if (sock != nullptr) targets.push_back(sock); + else std::cout << "[WARN] skill: sock not found\n"; + } + } + + return targets; +} + +void Abilities::applyAbility(SkillData* skill, EntityRef src, std::vector targets) { + for (EntityRef target : targets) { + Entity* entity = target.getEntity(); + if (entity->kind != PLAYER && entity->kind != COMBAT_NPC && entity->kind != MOB) + continue; // not a combatant + + + } +} + +void Abilities::init() { + //REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_EMAIL_UPDATE_CHECK, emailUpdateCheck); +} diff --git a/src/Abilities.hpp b/src/Abilities.hpp index 022ee64..27c376b 100644 --- a/src/Abilities.hpp +++ b/src/Abilities.hpp @@ -3,16 +3,46 @@ #include "core/Core.hpp" #include "Combat.hpp" +enum class SkillEffectTarget { + POINT = 1, + SELF = 2, + CONE = 3, + WEAPON = 4, + AREA_SELF = 5, + AREA_TARGET = 6 +}; + +enum class SkillTargetType { + MOBS = 1, + SELF = 2, + GROUP = 3 +}; + +enum class SkillDrainType { + ACTIVE = 1, + PASSIVE = 2 +}; + struct SkillData { int skillType; - int targetType; - int drainType; + SkillEffectTarget effectTarget; + int effectType; // always 1? + SkillTargetType targetType; + SkillDrainType drainType; int effectArea; + int batteryUse[4]; int durationTime[4]; - int powerIntensity[4]; + + int valueTypes[3]; + int values[3][4]; }; namespace Abilities { extern std::map SkillTable; + + std::vector matchTargets(SkillData*, int, int32_t*); + void applyAbility(SkillData*, EntityRef, std::vector); + + void init(); } diff --git a/src/Combat.cpp b/src/Combat.cpp index 5f08f9e..16ce751 100644 --- a/src/Combat.cpp +++ b/src/Combat.cpp @@ -695,15 +695,37 @@ static void playerTick(CNServer *serv, time_t currTime) { plr->healCooldown -= 4000; } + // nanos for (int i = 0; i < 3; i++) { - if (plr->activeNano != 0 && plr->equippedNanos[i] == plr->activeNano) { // spend stamina - plr->Nanos[plr->activeNano].iStamina -= 1 + plr->nanoDrainRate / 5; + if (plr->activeNano != 0 && plr->equippedNanos[i] == plr->activeNano) { // tick active nano + sNano& nano = plr->Nanos[plr->activeNano]; + int drainRate = 0; - if (plr->Nanos[plr->activeNano].iStamina <= 0) + if (Abilities::SkillTable.find(nano.iSkillID) != Abilities::SkillTable.end()) { + // nano has skill data + SkillData* skill = &Abilities::SkillTable[nano.iSkillID]; + int boost = Nanos::getNanoBoost(plr); + drainRate = skill->batteryUse[boost * 3]; + + if (skill->drainType == SkillDrainType::PASSIVE) { + // passive buff + std::vector targets; + if (skill->targetType == SkillTargetType::GROUP && plr->group != nullptr) + targets = plr->group->members; // group + else if(skill->targetType == SkillTargetType::SELF) + targets.push_back(sock); // self + + std::cout << "[SKILL] id " << nano.iSkillID << ", type " << skill->skillType << ", target " << (int)skill->targetType << std::endl; + } + } + + nano.iStamina -= 1 + drainRate / 5; + + if (nano.iStamina <= 0) Nanos::summonNano(sock, -1, true); // unsummon nano silently transmit = true; - } else if (plr->Nanos[plr->equippedNanos[i]].iStamina < 150) { // regain stamina + } else if (plr->Nanos[plr->equippedNanos[i]].iStamina < 150) { // tick resting nano sNano& nano = plr->Nanos[plr->equippedNanos[i]]; nano.iStamina += 1; diff --git a/src/Eggs.cpp b/src/Eggs.cpp index 64b1e93..ca82b54 100644 --- a/src/Eggs.cpp +++ b/src/Eggs.cpp @@ -18,7 +18,7 @@ int Eggs::eggBuffPlayer(CNSocket* sock, int skillId, int eggId, int duration) { Player* plr = PlayerManager::getPlayer(sock); // TODO ABILITIES - int bitFlag = plr->group->conditionBitFlag; + //int bitFlag = plr->group->conditionBitFlag; int CBFlag = 0;// Abilities::applyBuff(sock, skillId, 1, 3, bitFlag); size_t resplen; @@ -41,7 +41,7 @@ int Eggs::eggBuffPlayer(CNSocket* sock, int skillId, int eggId, int duration) { memset(respbuf, 0, resplen); skill->eCT = 1; skill->iID = plr->iID; - skill->iDamage = PC_MAXHEALTH(plr->level) * Abilities::SkillTable[skillId].powerIntensity[0] / 1000; + skill->iDamage = PC_MAXHEALTH(plr->level) * Abilities::SkillTable[skillId].values[0][0] / 1000; plr->HP -= skill->iDamage; if (plr->HP < 0) plr->HP = 0; @@ -51,7 +51,7 @@ int Eggs::eggBuffPlayer(CNSocket* sock, int skillId, int eggId, int duration) { memset(respbuf, 0, resplen); skill->eCT = 1; skill->iID = plr->iID; - skill->iHealHP = PC_MAXHEALTH(plr->level) * Abilities::SkillTable[skillId].powerIntensity[0] / 1000; + skill->iHealHP = PC_MAXHEALTH(plr->level) * Abilities::SkillTable[skillId].values[0][0] / 1000; plr->HP += skill->iHealHP; if (plr->HP > PC_MAXHEALTH(plr->level)) plr->HP = PC_MAXHEALTH(plr->level); @@ -98,7 +98,7 @@ static void eggStep(CNServer* serv, time_t currTime) { int32_t CBFlag = it->first.second; Player* plr = PlayerManager::getPlayer(sock); - int groupFlags = plr->group->conditionBitFlag; + //int groupFlags = plr->group->conditionBitFlag; // TODO ABILITIES //for (auto& pwr : Abilities::Powers) { // if (pwr.bitFlag == CBFlag) { // pick the power with the right flag and unbuff diff --git a/src/Groups.cpp b/src/Groups.cpp index 57418b8..f3bf7d8 100644 --- a/src/Groups.cpp +++ b/src/Groups.cpp @@ -153,7 +153,7 @@ static void joinGroup(CNSocket* sock, CNPacketData* data) { resp->iID_NewMember = plr->iID; resp->iMemberPCCnt = players.size(); - int bitFlag = otherPlr->group->conditionBitFlag; + //int bitFlag = otherPlr->group->conditionBitFlag; for (int i = 0; i < players.size(); i++) { Player* varPlr = PlayerManager::getPlayer(players[i].sock); diff --git a/src/Groups.hpp b/src/Groups.hpp index 05bf569..c694597 100644 --- a/src/Groups.hpp +++ b/src/Groups.hpp @@ -12,7 +12,6 @@ enum EntityKind; struct Group { std::vector members; - int32_t conditionBitFlag; std::vector filter(EntityKind kind) { std::vector filtered; diff --git a/src/MobAI.cpp b/src/MobAI.cpp index 4299727..55d6747 100644 --- a/src/MobAI.cpp +++ b/src/MobAI.cpp @@ -281,7 +281,7 @@ static void dealCorruption(Mob *mob, std::vector targetData, int skillID, i int style2 = Nanos::nanoStyle(plr->activeNano); if (style2 == -1) { // no nano respdata[i].iHitFlag = HF_BIT_STYLE_TIE; - respdata[i].iDamage = Abilities::SkillTable[skillID].powerIntensity[0] * PC_MAXHEALTH((int)mob->data["m_iNpcLevel"]) / 1500; + respdata[i].iDamage = Abilities::SkillTable[skillID].values[0][0] * PC_MAXHEALTH((int)mob->data["m_iNpcLevel"]) / 1500; } else if (style == style2) { respdata[i].iHitFlag = HF_BIT_STYLE_TIE; respdata[i].iDamage = 0; @@ -300,7 +300,7 @@ static void dealCorruption(Mob *mob, std::vector targetData, int skillID, i pwr.handle(sock, targetData2, plr->activeNano, skillID, 0, 200);*/ } else { 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].values[0][0] * PC_MAXHEALTH((int)mob->data["m_iNpcLevel"]) / 1500; respdata[i].iNanoStamina = plr->Nanos[plr->activeNano].iStamina -= 90; if (plr->Nanos[plr->activeNano].iStamina < 0) { respdata[i].bNanoDeactive = 1; diff --git a/src/Nanos.cpp b/src/Nanos.cpp index dbab11a..34e200d 100644 --- a/src/Nanos.cpp +++ b/src/Nanos.cpp @@ -82,42 +82,14 @@ void Nanos::summonNano(CNSocket *sock, int slot, bool silent) { if (slot != -1 && plr->Nanos[nanoID].iSkillID == 0) return; // prevent powerless nanos from summoning - plr->nanoDrainRate = 0; - int16_t skillID = plr->Nanos[plr->activeNano].iSkillID; - - // passive nano unbuffing - if (Abilities::SkillTable[skillID].drainType == 2) { - // TODO ABILITIES - /*std::vector targetData = Abilities::findTargets(plr, skillID); - - for (auto& pwr : Abilities::Powers) - if (pwr.skillType == Abilities::SkillTable[skillID].skillType) - Abilities::removeBuff(sock, targetData, pwr.bitFlag, pwr.timeBuffID, 0,(Abilities::SkillTable[skillID].targetType == 3));*/ - } - if (nanoID >= NANO_COUNT || nanoID < 0) return; // sanity check plr->activeNano = nanoID; - skillID = plr->Nanos[nanoID].iSkillID; - // passive nano buffing - if (Abilities::SkillTable[skillID].drainType == 2) { - int boost = 0; - if (getNanoBoost(plr)) - boost = 1; - - // TODO ABILITIES - //std::vector targetData = Abilities::findTargets(plr, skillID); - //for (auto& pwr : Abilities::Powers) { - // 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]); - // } - //} - } + int16_t skillID = plr->Nanos[nanoID].iSkillID; + if (Abilities::SkillTable.count(skillID) > 0 && Abilities::SkillTable[skillID].drainType == SkillDrainType::PASSIVE) + resp.eCSTB___Add = 1; // passive buff effect if (!silent) // silent nano death but only for the summoning player sock->sendPacket(resp, P_FE2CL_REP_NANO_ACTIVE_SUCC); @@ -290,8 +262,15 @@ static void nanoSummonHandler(CNSocket* sock, CNPacketData* data) { static void nanoSkillUseHandler(CNSocket* sock, CNPacketData* data) { Player *plr = PlayerManager::getPlayer(sock); - int16_t nanoID = plr->activeNano; - int16_t skillID = plr->Nanos[nanoID].iSkillID; + // validate request check + sP_CL2FE_REQ_NANO_SKILL_USE* pkt = (sP_CL2FE_REQ_NANO_SKILL_USE*)data->buf; + 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; + } + + int16_t skillID = plr->Nanos[plr->activeNano].iSkillID; + SkillData* skillData = &Abilities::SkillTable[skillID]; DEBUGLOG( std::cout << PlayerManager::getPlayerName(plr) << " requested to summon nano skill " << std::endl; @@ -306,8 +285,8 @@ static void nanoSkillUseHandler(CNSocket* sock, CNPacketData* data) { plr->Nanos[plr->activeNano].iStamina = 0; // TODO ABILITIES - /*std::vector targetData = Abilities::findTargets(plr, skillID, data); - for (auto& pwr : Abilities::Powers) + std::vector targetData = Abilities::matchTargets(skillData, pkt->iTargetCnt, (int32_t*)(pkt + 1)); + /*for (auto& pwr : Abilities::Powers) if (pwr.skillType == Abilities::SkillTable[skillID].skillType) pwr.handle(sock, targetData, nanoID, skillID, Abilities::SkillTable[skillID].durationTime[boost], Abilities::SkillTable[skillID].powerIntensity[boost]);*/ diff --git a/src/Player.hpp b/src/Player.hpp index 84513b8..3b9a40c 100644 --- a/src/Player.hpp +++ b/src/Player.hpp @@ -50,7 +50,6 @@ struct Player : public Entity, public ICombatant { bool inCombat = false; bool onMonkey = false; - int nanoDrainRate = 0; int healCooldown = 0; int pointDamage = 0; diff --git a/src/PlayerManager.cpp b/src/PlayerManager.cpp index 1dcc579..fe71245 100644 --- a/src/PlayerManager.cpp +++ b/src/PlayerManager.cpp @@ -475,8 +475,9 @@ static void revivePlayer(CNSocket* sock, CNPacketData* data) { resp2.PCRegenDataForOtherPC.iAngle = plr->angle; if (plr->group != nullptr) { - int bitFlag = plr->group->conditionBitFlag; - resp2.PCRegenDataForOtherPC.iConditionBitFlag = plr->iConditionBitFlag = plr->iSelfConditionBitFlag | bitFlag; + // TODO ABILITIES + //int bitFlag = plr->group->conditionBitFlag; + //resp2.PCRegenDataForOtherPC.iConditionBitFlag = plr->iConditionBitFlag = plr->iSelfConditionBitFlag | bitFlag; resp2.PCRegenDataForOtherPC.iPCState = plr->iPCState; resp2.PCRegenDataForOtherPC.iSpecialState = plr->iSpecialState; diff --git a/src/TableData.cpp b/src/TableData.cpp index 3461564..11e23fd 100644 --- a/src/TableData.cpp +++ b/src/TableData.cpp @@ -231,15 +231,31 @@ static void loadXDT(json& xdtData) { // load nano powers json skills = xdtData["m_pSkillTable"]["m_pSkillData"]; - for (json::iterator _skills = skills.begin(); _skills != skills.end(); _skills++) { - auto skills = _skills.value(); - SkillData skillData = { skills["m_iSkillType"], skills["m_iTargetType"], skills["m_iBatteryDrainType"], skills["m_iEffectArea"] }; + for (json::iterator _skill = skills.begin(); _skill != skills.end(); _skill++) { + auto skill = _skill.value(); + SkillData skillData = { + skill["m_iSkillType"], + skill["m_iEffectTarget"], + skill["m_iEffectType"], + skill["m_iTargetType"], + skill["m_iBatteryDrainType"], + skill["m_iEffectArea"] + }; + + skillData.valueTypes[0] = skill["m_iValueA_Type"]; + skillData.valueTypes[1] = skill["m_iValueB_Type"]; + skillData.valueTypes[2] = skill["m_iValueC_Type"]; + for (int i = 0; i < 4; i++) { - skillData.batteryUse[i] = skills["m_iBatteryDrainUse"][i]; - skillData.durationTime[i] = skills["m_iDurationTime"][i]; - skillData.powerIntensity[i] = skills["m_iValueA"][i]; + skillData.batteryUse[i] = skill["m_iBatteryDrainUse"][i]; + skillData.durationTime[i] = skill["m_iDurationTime"][i]; + + skillData.values[0][i] = skill["m_iValueA"][i]; + skillData.values[1][i] = skill["m_iValueB"][i]; + skillData.values[2][i] = skill["m_iValueC"][i]; } - Abilities::SkillTable[skills["m_iSkillNumber"]] = skillData; + + Abilities::SkillTable[skill["m_iSkillNumber"]] = skillData; } std::cout << "[INFO] Loaded " << Abilities::SkillTable.size() << " nano skills" << std::endl;