diff --git a/src/CNProtocol.hpp b/src/CNProtocol.hpp index b24959b..cc47ece 100644 --- a/src/CNProtocol.hpp +++ b/src/CNProtocol.hpp @@ -82,7 +82,7 @@ inline bool validOutVarPacket(size_t base, int32_t npayloads, size_t plsize) { size_t trailing = npayloads * plsize; // does it fit in a packet? - if (base + trailing <= CN_PACKET_BUFFER_SIZE) + if (base + trailing > CN_PACKET_BUFFER_SIZE) return false; // everything is a-ok! diff --git a/src/CombatManager.cpp b/src/CombatManager.cpp index 845f879..16bbeb3 100644 --- a/src/CombatManager.cpp +++ b/src/CombatManager.cpp @@ -1,8 +1,9 @@ #include "CombatManager.hpp" #include "PlayerManager.hpp" #include "NPCManager.hpp" +#include "ItemManager.hpp" -#include +#include void CombatManager::init() { REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_ATTACK_NPCs, pcAttackNpcs); @@ -28,7 +29,7 @@ void CombatManager::pcAttackNpcs(CNSocket *sock, CNPacketData *data) { * both incoming and outgoing variable-length packets must be validated. */ if (!validOutVarPacket(sizeof(sP_FE2CL_PC_ATTACK_NPCs_SUCC), pkt->iNPCCnt, sizeof(sAttackResult))) { - std::cout << "[WARN] bad sP_CL2FE_REQ_PC_ATTACK_NPCs packet size\n"; + std::cout << "[WARN] bad sP_FE2CL_PC_ATTACK_NPCs_SUCC packet size\n"; return; } @@ -44,8 +45,6 @@ void CombatManager::pcAttackNpcs(CNSocket *sock, CNPacketData *data) { resp->iNPCCnt = pkt->iNPCCnt; for (int i = 0; i < pkt->iNPCCnt; i++) { - std::cout << pktdata[i] << std::endl; - if (NPCManager::NPCs.find(pktdata[i]) == NPCManager::NPCs.end()) { // not sure how to best handle this std::cout << "[WARN] pcAttackNpcs: mob ID not found" << std::endl; @@ -72,18 +71,44 @@ void CombatManager::combatEnd(CNSocket *sock, CNPacketData *data) {} // stub void CombatManager::dotDamageOnOff(CNSocket *sock, CNPacketData *data) {} // stub void CombatManager::giveReward(CNSocket *sock) { - // reward testing - INITSTRUCT(sP_FE2CL_REP_REWARD_ITEM, reward); Player *plr = PlayerManager::getPlayer(sock); + const size_t resplen = sizeof(sP_FE2CL_REP_REWARD_ITEM) + sizeof(sItemReward); + assert(resplen < CN_PACKET_BUFFER_SIZE); + // we know it's only one trailing struct, so we can skip full validation + + uint8_t respbuf[resplen]; // not a variable length array, don't worry + sP_FE2CL_REP_REWARD_ITEM *reward = (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 += 50; plr->fusionmatter += 70; - reward.m_iCandy = plr->money; - reward.m_iFusionMatter = plr->fusionmatter; - reward.iFatigue = 100; // prevents warning message - reward.iFatigue_Level = 1; + // simple rewards + reward->m_iCandy = plr->money; + reward->m_iFusionMatter = plr->fusionmatter; + reward->iFatigue = 100; // prevents warning message + reward->iFatigue_Level = 1; + reward->iItemCnt = 1; // remember to update resplen if you change this - sock->sendPacket((void*)&reward, P_FE2CL_REP_REWARD_ITEM, sizeof(sP_FE2CL_REP_REWARD_ITEM)); + int slot = ItemManager::findFreeSlot(plr); + if (slot == -1) { + // no room for an item, but you still get FM and taros + sock->sendPacket((void*)respbuf, P_FE2CL_REP_REWARD_ITEM, sizeof(sP_FE2CL_REP_REWARD_ITEM)); + } else { + // item reward + item->sItem.iType = 9; + item->sItem.iID = 1; + item->iSlotNum = slot; + item->eIL = 1; // Inventory Location. 1 means player inventory. + + // update player + plr->Inven[slot] = item->sItem; + + sock->sendPacket((void*)respbuf, P_FE2CL_REP_REWARD_ITEM, resplen); + } } diff --git a/src/ItemManager.cpp b/src/ItemManager.cpp index ad11e55..d43817a 100644 --- a/src/ItemManager.cpp +++ b/src/ItemManager.cpp @@ -4,6 +4,9 @@ #include "PlayerManager.hpp" #include "Player.hpp" +#include // for memset() and memcmp() +#include + void ItemManager::init() { REGISTER_SHARD_PACKET(P_CL2FE_REQ_ITEM_MOVE, itemMoveHandler); REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_ITEM_DELETE, itemDeleteHandler); @@ -18,6 +21,7 @@ void ItemManager::init() { REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TRADE_ITEM_UNREGISTER, itemTradeUnregisterItemHandler); REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TRADE_CASH_REGISTER, itemTradeRegisterCashHandler); REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TRADE_EMOTES_CHAT, itemTradeChatHandler); + REGISTER_SHARD_PACKET(P_CL2FE_REQ_ITEM_CHEST_OPEN, chestOpenHandler); } void ItemManager::itemMoveHandler(CNSocket* sock, CNPacketData* data) { @@ -664,4 +668,64 @@ void ItemManager::itemTradeChatHandler(CNSocket* sock, CNPacketData* data) { sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_EMOTES_CHAT, sizeof(sP_FE2CL_REP_PC_TRADE_EMOTES_CHAT)); otherSock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_EMOTES_CHAT, sizeof(sP_FE2CL_REP_PC_TRADE_EMOTES_CHAT)); -} \ No newline at end of file +} + +void ItemManager::chestOpenHandler(CNSocket *sock, CNPacketData *data) { + if (data->size != sizeof(sP_CL2FE_REQ_ITEM_CHEST_OPEN)) + return; // ignore the malformed packet + + sP_CL2FE_REQ_ITEM_CHEST_OPEN *pkt = (sP_CL2FE_REQ_ITEM_CHEST_OPEN *)data->buf; + Player *plr = PlayerManager::getPlayer(sock); + + // item giving packet + const size_t resplen = sizeof(sP_FE2CL_REP_REWARD_ITEM) + sizeof(sItemReward); + assert(resplen < CN_PACKET_BUFFER_SIZE); + // we know it's only one trailing struct, so we can skip full validation + + uint8_t respbuf[resplen]; // not a variable length array, don't worry + sP_FE2CL_REP_REWARD_ITEM *reward = (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); + + // simple rewards + reward->iFatigue = 100; // prevents warning message + reward->iFatigue_Level = 1; + reward->iItemCnt = 1; // remember to update resplen if you change this + + // item reward + item->sItem.iType = 0; + item->sItem.iID = 96; + item->iSlotNum = pkt->iSlotNum; + item->eIL = pkt->eIL; + + // update player + plr->Inven[pkt->iSlotNum] = item->sItem; + + // transmit item + sock->sendPacket((void*)respbuf, P_FE2CL_REP_REWARD_ITEM, resplen); + + // chest opening acknowledgement packet + INITSTRUCT(sP_FE2CL_REP_ITEM_CHEST_OPEN_SUCC, resp); + + resp.iSlotNum = pkt->iSlotNum; + + std::cout << "opening chest..." << std::endl; + sock->sendPacket((void*)&resp, P_FE2CL_REP_ITEM_CHEST_OPEN_SUCC, sizeof(sP_FE2CL_REP_ITEM_CHEST_OPEN_SUCC)); +} + +// TODO: use this in cleaned up ItemManager +int ItemManager::findFreeSlot(Player *plr) { + int i; + sItemBase free; + + memset((void*)&free, 0, sizeof(sItemBase)); + + for (i = 0; i < AINVEN_COUNT; i++) + if (memcmp((void*)&plr->Inven[i], (void*)&free, sizeof(sItemBase)) == 0) + return i; + + // not found + return -1; +} diff --git a/src/ItemManager.hpp b/src/ItemManager.hpp index 44cf281..4531095 100644 --- a/src/ItemManager.hpp +++ b/src/ItemManager.hpp @@ -1,9 +1,11 @@ #pragma once #include "CNShardServer.hpp" +#include "Player.hpp" namespace ItemManager { void init(); + void itemMoveHandler(CNSocket* sock, CNPacketData* data); void itemDeleteHandler(CNSocket* sock, CNPacketData* data); void itemGMGiveHandler(CNSocket* sock, CNPacketData* data); @@ -17,4 +19,7 @@ namespace ItemManager { void itemTradeUnregisterItemHandler(CNSocket* sock, CNPacketData* data); void itemTradeRegisterCashHandler(CNSocket* sock, CNPacketData* data); void itemTradeChatHandler(CNSocket* sock, CNPacketData* data); + void chestOpenHandler(CNSocket* sock, CNPacketData* data); + + int findFreeSlot(Player *plr); }