From 386524938767608c96b73d15c917bf0c9f6eda7d Mon Sep 17 00:00:00 2001 From: Ariii Date: Wed, 9 Sep 2020 03:15:25 +0200 Subject: [PATCH] Vendors, set nano skill command + serverside command issues fixed (#74) Added basic shopkeeper functions, a player can buy the preset 3 items (cannonbolt set), all shopkeepers have the same items atm (need to check the shopkeeper tabledata), setting itemprice is something I didn't figure out. Added set nano skill command Implemented a switch for certain commands like health/taros/fusionmatter etc to be handled on the serverside aswell Co-authored-by: dongresource --- src/NPCManager.cpp | 111 ++++++++++++++++++++++++++++++++++++++++++ src/NPCManager.hpp | 4 ++ src/NanoManager.cpp | 9 ++++ src/NanoManager.hpp | 1 + src/PlayerManager.cpp | 23 +++++++++ 5 files changed, 148 insertions(+) diff --git a/src/NPCManager.cpp b/src/NPCManager.cpp index 0b5d8e9..3f9ba8f 100644 --- a/src/NPCManager.cpp +++ b/src/NPCManager.cpp @@ -1,4 +1,5 @@ #include "NPCManager.hpp" +#include "ItemManager.hpp" #include "settings.hpp" #include @@ -17,6 +18,116 @@ void NPCManager::init() { REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_WARP_USE_NPC, npcWarpHandler); REGISTER_SHARD_PACKET(P_CL2FE_REQ_NPC_SUMMON, npcSummonHandler); REGISTER_SHARD_PACKET(P_CL2FE_REQ_BARKER, npcBarkHandler); + REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_VENDOR_START, npcVendorStart); + REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_VENDOR_TABLE_UPDATE, npcVendorTable); + REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_VENDOR_ITEM_BUY, npcVendorBuy); +} + +void NPCManager::npcVendorBuy(CNSocket* sock, CNPacketData* data) { + if (data->size != sizeof(sP_CL2FE_REQ_PC_VENDOR_ITEM_BUY)) + return; // malformed packet + + sP_CL2FE_REQ_PC_VENDOR_ITEM_BUY* req = (sP_CL2FE_REQ_PC_VENDOR_ITEM_BUY*)data->buf; + Player *plr = PlayerManager::getPlayer(sock); + + int itemCost = 100; // TODO: placeholder, look up the price of item + + int slot = ItemManager::findFreeSlot(plr); + + if (itemCost > plr->money || slot == -1) { + // NOTE: VENDOR_ITEM_BUY_FAIL is not actually handled client-side. + INITSTRUCT(sP_FE2CL_REP_PC_VENDOR_ITEM_BUY_FAIL, failResp); + failResp.iErrorCode = 0; + sock->sendPacket((void*)&failResp, P_FE2CL_REP_PC_VENDOR_ITEM_BUY_FAIL, sizeof(sP_FE2CL_REP_PC_VENDOR_ITEM_BUY_FAIL)); + return; + } + + if (slot != req->iInvenSlotNum) { + // possible item stacking? + std::cout << "[WARN] Client and server disagree on bought item slot" << std::endl; + } + + INITSTRUCT(sP_FE2CL_REP_PC_VENDOR_ITEM_BUY_SUCC, resp); + + plr->money = plr->money - itemCost; + plr->Inven[slot] = req->Item; + + resp.iCandy = plr->money; + resp.iInvenSlotNum = slot; + resp.Item = req->Item; + + sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_VENDOR_ITEM_BUY_SUCC, sizeof(sP_FE2CL_REP_PC_VENDOR_ITEM_BUY_SUCC)); +} + +void NPCManager::npcVendorTable(CNSocket* sock, CNPacketData* data) { + if (data->size != sizeof(sP_CL2FE_REQ_PC_VENDOR_TABLE_UPDATE)) + return; // malformed packet + + //sP_CL2FE_REQ_PC_VENDOR_TABLE_UPDATE* req = (sP_CL2FE_REQ_PC_VENDOR_TABLE_UPDATE*)data->buf; + INITSTRUCT(sP_FE2CL_REP_PC_VENDOR_TABLE_UPDATE_SUCC, resp); + // TODO: data needs to be read from shopkeeper tabledata + // check req->iVendorID and req->iNPC_ID + + // Exaple Items + // shirt + sItemBase base1; + base1.iID = 60; + base1.iOpt = 0; + // expire date + base1.iTimeLimit = -1; + base1.iType = 1; + + sItemVendor item1; + item1.item = base1; + item1.iSortNum = 0; + item1.iVendorID = 1; + // cost amount in float? (doesn't work rn, need to figure out) + item1.fBuyCost = 100.0; + + // pants + sItemBase base2; + base2.iID = 61; + base2.iOpt = 0; + base2.iTimeLimit = -1; + base2.iType = 2; + + sItemVendor item2; + item2.item = base2; + item2.iSortNum = 1; + item2.iVendorID = 1; + item2.fBuyCost = 250.0; + + // shoes + sItemBase base3; + base3.iID = 51; + base3.iOpt = 0; + base3.iTimeLimit = -1; + base3.iType = 3; + + sItemVendor item3; + item3.item = base3; + item3.iSortNum = 2; + item3.iVendorID = 1; + item3.fBuyCost = 350.0; + + resp.item[0] = item1; + resp.item[1] = item2; + resp.item[2] = item3; + + sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_VENDOR_TABLE_UPDATE_SUCC, sizeof(sP_FE2CL_REP_PC_VENDOR_TABLE_UPDATE_SUCC)); +} + +void NPCManager::npcVendorStart(CNSocket* sock, CNPacketData* data) { + if (data->size != sizeof(sP_CL2FE_REQ_PC_VENDOR_START)) + return; // malformed packet + + sP_CL2FE_REQ_PC_VENDOR_START* req = (sP_CL2FE_REQ_PC_VENDOR_START*)data->buf; + INITSTRUCT(sP_FE2CL_REP_PC_VENDOR_START_SUCC, resp); + + resp.iNPC_ID = req->iNPC_ID; + resp.iVendorID = req->iVendorID; + + sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_VENDOR_START_SUCC, sizeof(sP_FE2CL_REP_PC_VENDOR_START_SUCC)); } void NPCManager::updatePlayerNPCS(CNSocket* sock, PlayerView& view) { diff --git a/src/NPCManager.hpp b/src/NPCManager.hpp index 7686b5e..9fbb16b 100644 --- a/src/NPCManager.hpp +++ b/src/NPCManager.hpp @@ -24,5 +24,9 @@ namespace NPCManager { void npcSummonHandler(CNSocket* sock, CNPacketData* data); void npcWarpHandler(CNSocket* sock, CNPacketData* data); + void npcVendorStart(CNSocket* sock, CNPacketData* data); + void npcVendorTable(CNSocket* sock, CNPacketData* data); + void npcVendorBuy(CNSocket* sock, CNPacketData* data); + void updatePlayerNPCS(CNSocket* sock, PlayerView& plr); } diff --git a/src/NanoManager.cpp b/src/NanoManager.cpp index cd7b5a6..160c0b7 100644 --- a/src/NanoManager.cpp +++ b/src/NanoManager.cpp @@ -9,6 +9,7 @@ void NanoManager::init() { REGISTER_SHARD_PACKET(P_CL2FE_REQ_NANO_UNEQUIP, nanoUnEquipHandler); REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_GIVE_NANO, nanoGMGiveHandler); REGISTER_SHARD_PACKET(P_CL2FE_REQ_NANO_TUNE, nanoSkillSetHandler); + REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_GIVE_NANO_SKILL, nanoSkillSetGMHandler); REGISTER_SHARD_PACKET(P_CL2FE_REQ_NANO_SKILL_USE, nanoSkillUseHandler); } @@ -124,6 +125,14 @@ void NanoManager::nanoSkillSetHandler(CNSocket* sock, CNPacketData* data) { setNanoSkill(sock, skill->iNanoID, skill->iTuneID); } +void NanoManager::nanoSkillSetGMHandler(CNSocket* sock, CNPacketData* data) { + if (data->size != sizeof(sP_CL2FE_REQ_PC_GIVE_NANO_SKILL)) + return; // malformed packet + + sP_CL2FE_REQ_NANO_TUNE* skillGM = (sP_CL2FE_REQ_NANO_TUNE*)data->buf; + setNanoSkill(sock, skillGM->iNanoID, skillGM->iTuneID); +} + #pragma region Helper methods void NanoManager::addNano(CNSocket* sock, int16_t nanoId, int16_t slot) { if (nanoId > 36) diff --git a/src/NanoManager.hpp b/src/NanoManager.hpp index 2abda27..7f7b181 100644 --- a/src/NanoManager.hpp +++ b/src/NanoManager.hpp @@ -10,6 +10,7 @@ namespace NanoManager { void nanoGMGiveHandler(CNSocket* sock, CNPacketData* data); void nanoSkillUseHandler(CNSocket* sock, CNPacketData* data); void nanoSkillSetHandler(CNSocket* sock, CNPacketData* data); + void nanoSkillSetGMHandler(CNSocket* sock, CNPacketData* data); // Helper methods void addNano(CNSocket* sock, int16_t nanoId, int16_t slot); diff --git a/src/PlayerManager.cpp b/src/PlayerManager.cpp index 1233e9f..d34ef8b 100644 --- a/src/PlayerManager.cpp +++ b/src/PlayerManager.cpp @@ -548,6 +548,8 @@ void PlayerManager::setSpecialPlayer(CNSocket* sock, CNPacketData* data) { return; // ignore the malformed packet sP_CL2FE_GM_REQ_PC_SET_VALUE* setData = (sP_CL2FE_GM_REQ_PC_SET_VALUE*)data->buf; + Player *plr = PlayerManager::getPlayer(sock); + INITSTRUCT(sP_FE2CL_GM_REP_PC_SET_VALUE, response); DEBUGLOG( @@ -557,6 +559,27 @@ void PlayerManager::setSpecialPlayer(CNSocket* sock, CNPacketData* data) { std::cout << "\tSetValue: " << setData->iSetValue << std::endl; ) + // Handle serverside value-changes + switch (setData->iSetValueType) { + case 1: + plr->HP = setData->iSetValue; + break; + case 2: + // TODO: batteryW + break; + case 3: + // TODO: batteryN nanopotion + break; + case 4: + plr->fusionmatter = setData->iSetValue; + break; + case 5: + plr->money = setData->iSetValue; + break; + default: + break; + } + response.iPC_ID = setData->iPC_ID; response.iSetValue = setData->iSetValue; response.iSetValueType = setData->iSetValueType;