From 5b49e71de75469661646d724d576765179ffcf1d Mon Sep 17 00:00:00 2001 From: dongresource Date: Wed, 9 Sep 2020 21:09:01 +0200 Subject: [PATCH] Implemented mission rewards. Might need to refactor item drops, especially after implementing task-result quest item drops. --- src/MissionManager.cpp | 66 +++++++++++++++++++++++++++++++++++++++++- src/MissionManager.hpp | 21 +++++++++++++- src/TableData.cpp | 47 +++++++++++++++++++++++------- src/TableData.hpp | 5 ++-- src/main.cpp | 3 +- 5 files changed, 127 insertions(+), 15 deletions(-) diff --git a/src/MissionManager.cpp b/src/MissionManager.cpp index bbd747b..b28a974 100644 --- a/src/MissionManager.cpp +++ b/src/MissionManager.cpp @@ -2,6 +2,9 @@ #include "CNStructs.hpp" #include "MissionManager.hpp" #include "PlayerManager.hpp" +#include "ItemManager.hpp" + +std::map MissionManager::Rewards; void MissionManager::init() { REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TASK_START, acceptMission); @@ -27,9 +30,70 @@ void MissionManager::completeMission(CNSocket* sock, CNPacketData* data) { sP_CL2FE_REQ_PC_TASK_END* missionData = (sP_CL2FE_REQ_PC_TASK_END*)data->buf; INITSTRUCT(sP_FE2CL_REP_PC_TASK_END_SUCC, response); + Player *plr = PlayerManager::getPlayer(sock); response.iTaskNum = missionData->iTaskNum; + + if (Rewards.find(missionData->iTaskNum) == Rewards.end()) { + // not a mission's final task + sock->sendPacket((void*)&response, P_FE2CL_REP_PC_TASK_END_SUCC, sizeof(sP_FE2CL_REP_PC_TASK_END_SUCC)); + return; + } + Reward *reward = Rewards[missionData->iTaskNum]; + + int nrewards = 0; + for (int i = 0; i < 4; i++) { + if (reward->itemIds[i] != 0) + nrewards++; + } + + int slots[4]; + for (int i = 0; i < nrewards; i++) { + slots[i] = ItemManager::findFreeSlot(plr); + if (slots[i] == -1) { + std::cout << "Not enough room to complete task" << std::endl; + INITSTRUCT(sP_FE2CL_REP_PC_TASK_END_FAIL, fail); + + fail.iTaskNum = missionData->iTaskNum; + fail.iErrorCode = 13; // inventory full + + sock->sendPacket((void*)&fail, P_FE2CL_REP_PC_TASK_END_FAIL, sizeof(sP_FE2CL_REP_PC_TASK_END_FAIL)); + return; + } + } + + uint8_t respbuf[CN_PACKET_BUFFER_SIZE]; + size_t resplen = sizeof(sP_FE2CL_REP_REWARD_ITEM) + nrewards * sizeof(sItemReward); + assert(resplen < CN_PACKET_BUFFER_SIZE); + sP_FE2CL_REP_REWARD_ITEM *resp = (sP_FE2CL_REP_REWARD_ITEM *)respbuf; + sItemReward *item = (sItemReward *)(respbuf + sizeof(sP_FE2CL_REP_REWARD_ITEM)); + + // don't forget to zero the buffer! + memset(respbuf, 0, resplen); + + // update player + plr->money += reward->money; + plr->fusionmatter += reward->fusionmatter; + + // simple rewards + resp->m_iCandy = plr->money; + resp->m_iFusionMatter = plr->fusionmatter; + resp->iFatigue = 100; // prevents warning message + resp->iFatigue_Level = 1; + resp->iItemCnt = nrewards; + + for (int i = 0; i < nrewards; i++) { + item[i].sItem.iType = reward->itemTypes[i]; + item[i].sItem.iID = reward->itemIds[i]; + item[i].iSlotNum = slots[i]; + item[i].eIL = 1; + + // update player + plr->Inven[slots[i]] = item->sItem; + } + sock->sendPacket((void*)&response, P_FE2CL_REP_PC_TASK_END_SUCC, sizeof(sP_FE2CL_REP_PC_TASK_END_SUCC)); + sock->sendPacket((void*)respbuf, P_FE2CL_REP_REWARD_ITEM, resplen); } void MissionManager::setMission(CNSocket* sock, CNPacketData* data) { @@ -52,4 +116,4 @@ void MissionManager::quitMission(CNSocket* sock, CNPacketData* data) { response.iTaskNum = missionData->iTaskNum; sock->sendPacket((void*)&response, P_FE2CL_REP_PC_TASK_STOP_SUCC, sizeof(sP_FE2CL_REP_PC_TASK_STOP_SUCC)); -} \ No newline at end of file +} diff --git a/src/MissionManager.hpp b/src/MissionManager.hpp index d799869..def2552 100644 --- a/src/MissionManager.hpp +++ b/src/MissionManager.hpp @@ -2,11 +2,30 @@ #include "CNShardServer.hpp" +#include "contrib/JSON.hpp" + +struct Reward { + int32_t id; + int32_t itemTypes[4]; + int32_t itemIds[4]; + int32_t money; + int32_t fusionmatter; + + Reward(int32_t id, nlohmann::json types, nlohmann::json ids, int32_t m, int32_t fm) : + id(id), money(m), fusionmatter(fm) { + for (int i = 0; i < 4; i++) { + itemTypes[i] = types[i]; + itemIds[i] = ids[i]; + } + }; +}; + namespace MissionManager { + extern std::map Rewards; void init(); void acceptMission(CNSocket* sock, CNPacketData* data); void completeMission(CNSocket* sock, CNPacketData* data); void setMission(CNSocket* sock, CNPacketData* data); void quitMission(CNSocket* sock, CNPacketData* data); -} \ No newline at end of file +} diff --git a/src/TableData.cpp b/src/TableData.cpp index 55729a3..4a49cb9 100644 --- a/src/TableData.cpp +++ b/src/TableData.cpp @@ -1,11 +1,13 @@ #include "TableData.hpp" #include "NPCManager.hpp" #include "settings.hpp" +#include "MissionManager.hpp" + #include "contrib/JSON.hpp" #include -void TabledataManager::init() { +void TableData::init() { int i = 0; // load NPCs from NPC.json @@ -60,16 +62,15 @@ void TabledataManager::init() { std::cerr << "[WARN] Malformed mobs.json file! Reason:" << err.what() << std::endl; } - // load everything else from xdttable + std::ifstream infile(settings::XDTJSON); + nlohmann::json xdtData; + + // read file into json + infile >> xdtData; + + // load warps from m_pInstanceTable.m_pWarpData try { - std::ifstream infile(settings::XDTJSON); - nlohmann::json xdtData; - - // read file into json - infile >> xdtData; - - // load warps from m_pInstanceTable.m_pWarpData nlohmann::json warpData = xdtData["m_pInstanceTable"]["m_pWarpData"]; for (nlohmann::json::iterator warp = warpData.begin(); warp != warpData.end(); warp++) { @@ -79,9 +80,35 @@ void TabledataManager::init() { } std::cout << "[INFO] populated " << NPCManager::Warps.size() << " Warps" << std::endl; + + // missions + nlohmann::json tasks = xdtData["m_pMissionTable"]["m_pMissionData"]; + + for (auto _task = tasks.begin(); _task != tasks.end(); _task++) { + auto task = _task.value(); + + // rewards + if (task["m_iSUReward"] != 0) { + auto tmp = xdtData["m_pMissionTable"]["m_pRewardData"][(int)task["m_iSUReward"]]; + Reward *rew = new Reward(tmp["m_iMissionRewardID"], tmp["m_iMissionRewarItemType"], + tmp["m_iMissionRewardItemID"], tmp["m_iCash"], tmp["m_iFusionMatter"]); + + MissionManager::Rewards[task["m_iHTaskID"]] = rew; + } + } + + std::cout << "[INFO] Loaded mission-related data" << std::endl; } catch (const std::exception& err) { std::cerr << "[WARN] Malformed xdt.json file! Reason:" << err.what() << std::endl; } +} -} \ No newline at end of file +void TableData::cleanup() { + /* + * This is just to shut the address sanitizer up. Dynamically allocated data + * doesn't need to be cleaned up if it's supposed to last the program's full runtime. + */ + for (auto& pair : MissionManager::Rewards) + delete pair.second; +} diff --git a/src/TableData.hpp b/src/TableData.hpp index 8d7c2c4..2ba22b4 100644 --- a/src/TableData.hpp +++ b/src/TableData.hpp @@ -1,6 +1,7 @@ #pragma once #include -namespace TabledataManager { +namespace TableData { void init(); -} \ No newline at end of file + void cleanup(); +} diff --git a/src/main.cpp b/src/main.cpp index 6da73e9..e5cd478 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -34,6 +34,7 @@ void terminate(int arg) { std::cout << "OpenFusion: terminating." << std::endl; shardServer->kill(); shardThread->join(); + TableData::cleanup(); exit(0); } @@ -71,7 +72,7 @@ int main() { settings::init(); std::cout << "[INFO] Protocol version: " << PROTOCOL_VERSION << std::endl; std::cout << "[INFO] Intializing Packet Managers..." << std::endl; - TabledataManager::init(); + TableData::init(); PlayerManager::init(); ChatManager::init(); CombatManager::init();