diff --git a/src/NanoManager.cpp b/src/NanoManager.cpp index 8ff9bb4..0819c91 100644 --- a/src/NanoManager.cpp +++ b/src/NanoManager.cpp @@ -46,6 +46,7 @@ std::set TreasureFinderPowers = {26, 40, 74}; }; // namespace std::map NanoManager::NanoTable; +std::map NanoManager::NanoTunings; void NanoManager::init() { REGISTER_SHARD_PACKET(P_CL2FE_REQ_NANO_ACTIVE, nanoSummonHandler); @@ -187,7 +188,7 @@ void NanoManager::nanoSkillSetHandler(CNSocket* sock, CNPacketData* data) { return; // malformed packet sP_CL2FE_REQ_NANO_TUNE* skill = (sP_CL2FE_REQ_NANO_TUNE*)data->buf; - setNanoSkill(sock, skill->iNanoID, skill->iTuneID); + setNanoSkill(sock, skill); } void NanoManager::nanoSkillSetGMHandler(CNSocket* sock, CNPacketData* data) { @@ -195,7 +196,7 @@ void NanoManager::nanoSkillSetGMHandler(CNSocket* sock, CNPacketData* data) { return; // malformed packet sP_CL2FE_REQ_NANO_TUNE* skillGM = (sP_CL2FE_REQ_NANO_TUNE*)data->buf; - setNanoSkill(sock, skillGM->iNanoID, skillGM->iTuneID); + setNanoSkill(sock, skillGM); } void NanoManager::nanoRecallHandler(CNSocket* sock, CNPacketData* data) { @@ -347,8 +348,8 @@ void NanoManager::summonNano(CNSocket *sock, int slot) { plr->activeNano = nanoId; } -void NanoManager::setNanoSkill(CNSocket* sock, int16_t nanoId, int16_t skillId) { - if (nanoId > 36) +void NanoManager::setNanoSkill(CNSocket* sock, sP_CL2FE_REQ_NANO_TUNE* skill) { + if (skill->iNanoID > 36) return; Player *plr = PlayerManager::getPlayer(sock); @@ -356,25 +357,68 @@ void NanoManager::setNanoSkill(CNSocket* sock, int16_t nanoId, int16_t skillId) if (plr == nullptr) return; - if (plr->activeNano > 0 && plr->activeNano == nanoId) + if (plr->activeNano > 0 && plr->activeNano == skill->iNanoID) summonNano(sock, -1); // just unsummon the nano to prevent infinite buffs - sNano nano = plr->Nanos[nanoId]; - - nano.iSkillID = skillId; - plr->Nanos[nanoId] = nano; + sNano nano = plr->Nanos[skill->iNanoID]; + nano.iSkillID = skill->iTuneID; + plr->Nanos[skill->iNanoID] = nano; // Send to client INITSTRUCT(sP_FE2CL_REP_NANO_TUNE_SUCC, resp); - resp.iNanoID = nanoId; - resp.iSkillID = skillId; + resp.iNanoID = skill->iNanoID; + resp.iSkillID = skill->iTuneID; resp.iPC_FusionMatter = plr->fusionmatter; - resp.aItem[9] = plr->Inven[0]; // temp fix for a bug TODO: Use this for nano power changing later + resp.aItem[9] = plr->Inven[0]; // quick fix to make sure item in slot 0 doesn't get yeeted by default + + + // check if there's any garbage in the item slot array (this'll happen when a nano station isn't used) + for (int i = 0; i < 10; i++) { + if (skill->aiNeedItemSlotNum[i] < 0 || skill->aiNeedItemSlotNum[i] >= AINVEN_COUNT) { + sock->sendPacket((void*)&resp, P_FE2CL_REP_NANO_TUNE_SUCC, sizeof(sP_FE2CL_REP_NANO_TUNE_SUCC)); + return; // stop execution, don't run consumption logic + } + } + + if (plr->fusionmatter < (int)MissionManager::AvatarGrowth[plr->level]["m_iReqBlob_NanoTune"]) // sanity check + return; + + plr->fusionmatter -= (int)MissionManager::AvatarGrowth[plr->level]["m_iReqBlob_NanoTune"]; + + int reqItemCount = NanoTunings[skill->iTuneID].reqItemCount; + int reqItemID = NanoTunings[skill->iTuneID].reqItems; + int i = 0; + while (reqItemCount > 0 && i < 10) { + + sItemBase& item = plr->Inven[skill->aiNeedItemSlotNum[i]]; + if (item.iType == 7 && item.iID == reqItemID) { + if (item.iOpt > reqItemCount) { + item.iOpt -= reqItemCount; + reqItemCount = 0; + } + else { + reqItemCount -= item.iOpt; + item.iID = 0; + item.iType = 0; + item.iOpt = 0; + } + } + i++; // next slot + } + + resp.iPC_FusionMatter = plr->fusionmatter; // update fusion matter in packet + // update items clientside + for (int i = 0; i < 10; i++) { + if (skill->aiNeedItemSlotNum[i]) { // non-zero check + resp.aItem[i] = plr->Inven[skill->aiNeedItemSlotNum[i]]; + resp.aiItemSlotNum[i] = skill->aiNeedItemSlotNum[i]; + } + } sock->sendPacket((void*)&resp, P_FE2CL_REP_NANO_TUNE_SUCC, sizeof(sP_FE2CL_REP_NANO_TUNE_SUCC)); DEBUGLOG( - std::cout << U16toU8(plr->PCStyle.szFirstName) << U16toU8(plr->PCStyle.szLastName) << " set skill id " << skillId << " for nano: " << nanoId << std::endl; + std::cout << U16toU8(plr->PCStyle.szFirstName) << U16toU8(plr->PCStyle.szLastName) << " set skill id " << skill->iTuneID << " for nano: " << skill->iNanoID << std::endl; ) } diff --git a/src/NanoManager.hpp b/src/NanoManager.hpp index ec9fd2b..b59b34a 100644 --- a/src/NanoManager.hpp +++ b/src/NanoManager.hpp @@ -39,10 +39,16 @@ struct NanoData { int style; }; +struct NanoTuning { + int reqItemCount; + int reqItems; +}; + namespace NanoManager { extern std::vector ActivePowers; extern std::vector PassivePowers; extern std::map NanoTable; + extern std::map NanoTunings; void init(); void nanoSummonHandler(CNSocket* sock, CNPacketData* data); @@ -58,7 +64,7 @@ namespace NanoManager { // Helper methods void addNano(CNSocket* sock, int16_t nanoId, int16_t slot, bool spendfm=false); void summonNano(CNSocket* sock, int slot); - void setNanoSkill(CNSocket* sock, int16_t nanoId, int16_t skillId); + void setNanoSkill(CNSocket* sock, sP_CL2FE_REQ_NANO_TUNE* skill); void resetNanoSkill(CNSocket* sock, int16_t nanoId); void nanoBuff(CNSocket* sock, int16_t nanoId, int skillId, int16_t eSkillType, int32_t iCBFlag, int16_t eCharStatusTimeBuffID, int16_t iValue = 0, bool groupPower = false); diff --git a/src/TableData.cpp b/src/TableData.cpp index 8cddda3..3bae11c 100644 --- a/src/TableData.cpp +++ b/src/TableData.cpp @@ -175,6 +175,18 @@ void TableData::init() { } std::cout << "[INFO] Loaded " << NanoManager::NanoTable.size() << " nanos" << std::endl; + + nlohmann::json nanoTuneInfo = xdtData["m_pNanoTable"]["m_pNanoTuneData"]; + for (nlohmann::json::iterator _nano = nanoTuneInfo.begin(); _nano != nanoTuneInfo.end(); _nano++) { + auto nano = _nano.value(); + NanoTuning nanoData; + nanoData.reqItems = nano["m_iReqItemID"]; + nanoData.reqItemCount = nano["m_iReqItemCount"]; + NanoManager::NanoTunings[nano["m_iSkillID"]] = nanoData; + } + + std::cout << "[INFO] Loaded " << NanoManager::NanoTable.size() << " nano tunings" << std::endl; + } catch (const std::exception& err) { std::cerr << "[FATAL] Malformed xdt.json file! Reason:" << err.what() << std::endl;