#include "CNShardServer.hpp" #include "CNStructs.hpp" #include "ItemManager.hpp" #include "PlayerManager.hpp" #include "Player.hpp" #include // for memset() and memcmp() #include std::map, Item> ItemManager::ItemData; std::map> ItemManager::VendorTables; void ItemManager::init() { REGISTER_SHARD_PACKET(P_CL2FE_REQ_ITEM_MOVE, itemMoveHandler); REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_ITEM_DELETE, itemDeleteHandler); REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_GIVE_ITEM, itemGMGiveHandler); // Bank REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_BANK_OPEN, itemBankOpenHandler); // Trade handlers REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TRADE_OFFER, itemTradeOfferHandler); REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TRADE_OFFER_ACCEPT, itemTradeOfferAcceptHandler); REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TRADE_OFFER_REFUSAL, itemTradeOfferRefusalHandler); REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TRADE_CONFIRM, itemTradeConfirmHandler); REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TRADE_CONFIRM_CANCEL, itemTradeConfirmCancelHandler); REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TRADE_ITEM_REGISTER, itemTradeRegisterItemHandler); 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) { if (data->size != sizeof(sP_CL2FE_REQ_ITEM_MOVE)) return; // ignore the malformed packet sP_CL2FE_REQ_ITEM_MOVE* itemmove = (sP_CL2FE_REQ_ITEM_MOVE*)data->buf; INITSTRUCT(sP_FE2CL_PC_ITEM_MOVE_SUCC, resp); PlayerView& plr = PlayerManager::players[sock]; // sanity check if (plr.plr->Equip[itemmove->iFromSlotNum].iType != 0 && itemmove->eFrom == 0 && itemmove->eTo == 0) { // this packet should never happen unless it is a weapon, tell the client to do nothing and do nothing ourself resp.eTo = itemmove->eFrom; resp.iToSlotNum = itemmove->iFromSlotNum; resp.ToSlotItem = plr.plr->Equip[itemmove->iToSlotNum]; resp.eFrom = itemmove->eTo; resp.iFromSlotNum = itemmove->iToSlotNum; resp.FromSlotItem = plr.plr->Equip[itemmove->iFromSlotNum]; sock->sendPacket((void*)&resp, P_FE2CL_PC_ITEM_MOVE_SUCC, sizeof(sP_FE2CL_PC_ITEM_MOVE_SUCC)); return; } // sanity check if (itemmove->iToSlotNum > ABANK_COUNT || itemmove->iToSlotNum < 0) return; // get the fromItem sItemBase *fromItem; switch ((SlotType)itemmove->eFrom) { case SlotType::EQUIP: fromItem = &plr.plr->Equip[itemmove->iFromSlotNum]; break; case SlotType::INVENTORY: fromItem = &plr.plr->Inven[itemmove->iFromSlotNum]; break; case SlotType::BANK: fromItem = &plr.plr->Bank[itemmove->iFromSlotNum]; break; } // get the toItem sItemBase* toItem; switch ((SlotType)itemmove->eTo) { case SlotType::EQUIP: toItem = &plr.plr->Equip[itemmove->iToSlotNum]; break; case SlotType::INVENTORY: toItem = &plr.plr->Inven[itemmove->iToSlotNum]; break; case SlotType::BANK: toItem = &plr.plr->Bank[itemmove->iToSlotNum]; break; } // save items to response resp.ToSlotItem = *toItem; resp.FromSlotItem = *fromItem; // swap items in session sItemBase temp = *toItem; *toItem = *fromItem; *fromItem = temp; // send equip change to viewable players if (itemmove->eFrom == (int)SlotType::EQUIP || itemmove->eTo == (int)SlotType::EQUIP) { INITSTRUCT(sP_FE2CL_PC_EQUIP_CHANGE, equipChange); equipChange.iPC_ID = plr.plr->iID; if (itemmove->eFrom == (int)SlotType::EQUIP) { equipChange.iEquipSlotNum = itemmove->iFromSlotNum; equipChange.EquipSlotItem = resp.ToSlotItem; } else { equipChange.iEquipSlotNum = itemmove->iToSlotNum; equipChange.EquipSlotItem = resp.FromSlotItem; } // unequip vehicle if equip slot 8 is 0 if (plr.plr->Equip[8].iID == 0) plr.plr->iPCState = 0; // send equip event to other players for (CNSocket* otherSock : plr.viewable) { otherSock->sendPacket((void*)&equipChange, P_FE2CL_PC_EQUIP_CHANGE, sizeof(sP_FE2CL_PC_EQUIP_CHANGE)); } } // send response resp.eTo = itemmove->eFrom; resp.iToSlotNum = itemmove->iFromSlotNum; resp.eFrom = itemmove->eTo; resp.iFromSlotNum = itemmove->iToSlotNum; sock->sendPacket((void*)&resp, P_FE2CL_PC_ITEM_MOVE_SUCC, sizeof(sP_FE2CL_PC_ITEM_MOVE_SUCC)); } void ItemManager::itemDeleteHandler(CNSocket* sock, CNPacketData* data) { if (data->size != sizeof(sP_CL2FE_REQ_PC_ITEM_DELETE)) return; // ignore the malformed packet sP_CL2FE_REQ_PC_ITEM_DELETE* itemdel = (sP_CL2FE_REQ_PC_ITEM_DELETE*)data->buf; INITSTRUCT(sP_FE2CL_REP_PC_ITEM_DELETE_SUCC, resp); PlayerView& plr = PlayerManager::players[sock]; resp.eIL = itemdel->eIL; resp.iSlotNum = itemdel->iSlotNum; // so, im not sure what this eIL thing does since you always delete items in inventory and not equips plr.plr->Inven[itemdel->iSlotNum].iID = 0; plr.plr->Inven[itemdel->iSlotNum].iType = 0; plr.plr->Inven[itemdel->iSlotNum].iOpt = 0; sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_ITEM_DELETE_SUCC, sizeof(sP_FE2CL_REP_PC_ITEM_DELETE_SUCC)); } void ItemManager::itemGMGiveHandler(CNSocket* sock, CNPacketData* data) { if (data->size != sizeof(sP_CL2FE_REQ_PC_GIVE_ITEM)) return; // ignore the malformed packet sP_CL2FE_REQ_PC_GIVE_ITEM* itemreq = (sP_CL2FE_REQ_PC_GIVE_ITEM*)data->buf; PlayerView& plr = PlayerManager::players[sock]; // Commented and disabled for future use //if (!plr.plr->IsGM) { // TODO: send fail packet // return; //} if (itemreq->eIL == 2) { // Quest item, not a real item, handle this later, stubbed for now // sock->sendPacket(new CNPacketData((void*)resp, P_FE2CL_REP_PC_GIVE_ITEM_FAIL, sizeof(sP_FE2CL_REP_PC_GIVE_ITEM_FAIL), sock->getFEKey())); } else if (itemreq->eIL == 1 && itemreq->Item.iType >= 0 && itemreq->Item.iType <= 10) { INITSTRUCT(sP_FE2CL_REP_PC_GIVE_ITEM_SUCC, resp); resp.eIL = itemreq->eIL; resp.iSlotNum = itemreq->iSlotNum; resp.Item = itemreq->Item; plr.plr->Inven[itemreq->iSlotNum] = itemreq->Item; sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_GIVE_ITEM_SUCC, sizeof(sP_FE2CL_REP_PC_GIVE_ITEM_SUCC)); } } void ItemManager::itemBankOpenHandler(CNSocket* sock, CNPacketData* data) { if (data->size != sizeof(sP_CL2FE_REQ_PC_BANK_OPEN)) return; // ignore the malformed packet // just send bank inventory INITSTRUCT(sP_FE2CL_REP_PC_BANK_OPEN_SUCC, resp); for (int i = 0; i < ABANK_COUNT; i++) { resp.aBank[i] = PlayerManager::players[sock].plr->Bank[i]; } resp.iExtraBank = 1; sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_BANK_OPEN_SUCC, sizeof(sP_FE2CL_REP_PC_BANK_OPEN_SUCC)); } void ItemManager::itemTradeOfferHandler(CNSocket* sock, CNPacketData* data) { if (data->size != sizeof(sP_CL2FE_REQ_PC_TRADE_OFFER)) return; // ignore the malformed packet sP_CL2FE_REQ_PC_TRADE_OFFER* pacdat = (sP_CL2FE_REQ_PC_TRADE_OFFER*)data->buf; int iID_Check; if (pacdat->iID_Request == pacdat->iID_From) { iID_Check = pacdat->iID_To; } else { iID_Check = pacdat->iID_From; } CNSocket* otherSock = sock; for (auto& pair : PlayerManager::players) { if (pair.second.plr->iID == iID_Check) { otherSock = pair.first; break; } } PlayerView& plr = PlayerManager::players[otherSock]; if (plr.plr->isTrading) { INITSTRUCT(sP_FE2CL_REP_PC_TRADE_OFFER_REFUSAL, resp); resp.iID_Request = pacdat->iID_To; resp.iID_From = pacdat->iID_From; resp.iID_To = pacdat->iID_To; sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_OFFER_REFUSAL, sizeof(sP_FE2CL_REP_PC_TRADE_OFFER_REFUSAL)); return; // prevent trading with a player already trading } INITSTRUCT(sP_FE2CL_REP_PC_TRADE_OFFER, resp); resp.iID_Request = pacdat->iID_Request; resp.iID_From = pacdat->iID_From; resp.iID_To = pacdat->iID_To; otherSock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_OFFER, sizeof(sP_FE2CL_REP_PC_TRADE_OFFER)); } void ItemManager::itemTradeOfferAcceptHandler(CNSocket* sock, CNPacketData* data) { if (data->size != sizeof(sP_CL2FE_REQ_PC_TRADE_OFFER_ACCEPT)) return; // ignore the malformed packet sP_CL2FE_REQ_PC_TRADE_OFFER_ACCEPT* pacdat = (sP_CL2FE_REQ_PC_TRADE_OFFER_ACCEPT*)data->buf; int iID_Check; if (pacdat->iID_Request == pacdat->iID_From) { iID_Check = pacdat->iID_To; } else { iID_Check = pacdat->iID_From; } CNSocket* otherSock = sock; for (auto& pair : PlayerManager::players) { if (pair.second.plr->iID == iID_Check) { otherSock = pair.first; break; } } INITSTRUCT(sP_FE2CL_REP_PC_TRADE_OFFER, resp); resp.iID_Request = pacdat->iID_Request; resp.iID_From = pacdat->iID_From; resp.iID_To = pacdat->iID_To; // Clearing up trade slots PlayerView& plr = PlayerManager::players[sock]; PlayerView& plr2 = PlayerManager::players[otherSock]; if (plr2.plr->isTrading) { INITSTRUCT(sP_FE2CL_REP_PC_TRADE_OFFER_REFUSAL, resp); resp.iID_Request = pacdat->iID_To; resp.iID_From = pacdat->iID_From; resp.iID_To = pacdat->iID_To; sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_OFFER_REFUSAL, sizeof(sP_FE2CL_REP_PC_TRADE_OFFER_REFUSAL)); return; // prevent trading with a player already trading } plr.plr->isTrading = true; plr2.plr->isTrading = true; plr.plr->isTradeConfirm = false; plr2.plr->isTradeConfirm = false; memset(&plr.plr->Trade, 0, sizeof(plr.plr->Trade)); memset(&plr2.plr->Trade, 0, sizeof(plr2.plr->Trade)); otherSock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_OFFER_SUCC, sizeof(sP_FE2CL_REP_PC_TRADE_OFFER_SUCC)); } void ItemManager::itemTradeOfferRefusalHandler(CNSocket* sock, CNPacketData* data) { if (data->size != sizeof(sP_CL2FE_REQ_PC_TRADE_OFFER_REFUSAL)) return; // ignore the malformed packet sP_CL2FE_REQ_PC_TRADE_OFFER_REFUSAL* pacdat = (sP_CL2FE_REQ_PC_TRADE_OFFER_REFUSAL*)data->buf; INITSTRUCT(sP_FE2CL_REP_PC_TRADE_OFFER_REFUSAL, resp); resp.iID_Request = pacdat->iID_Request; resp.iID_From = pacdat->iID_From; resp.iID_To = pacdat->iID_To; int iID_Check; if (pacdat->iID_Request == pacdat->iID_From) { iID_Check = pacdat->iID_To; } else { iID_Check = pacdat->iID_From; } CNSocket* otherSock = sock; for (auto& pair : PlayerManager::players) { if (pair.second.plr->iID == iID_Check) { otherSock = pair.first; break; } } otherSock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_OFFER_REFUSAL, sizeof(sP_FE2CL_REP_PC_TRADE_OFFER_REFUSAL)); } void ItemManager::itemTradeConfirmHandler(CNSocket* sock, CNPacketData* data) { if (data->size != sizeof(sP_CL2FE_REQ_PC_TRADE_CONFIRM)) return; // ignore the malformed packet sP_CL2FE_REQ_PC_TRADE_CONFIRM* pacdat = (sP_CL2FE_REQ_PC_TRADE_CONFIRM*)data->buf; int iID_Check; if (pacdat->iID_Request == pacdat->iID_From) { iID_Check = pacdat->iID_To; } else { iID_Check = pacdat->iID_From; } CNSocket* otherSock = sock; for (auto& pair : PlayerManager::players) { if (pair.second.plr->iID == iID_Check) { otherSock = pair.first; break; } } PlayerView& plr = PlayerManager::players[sock]; PlayerView& plr2 = PlayerManager::players[otherSock]; if (plr2.plr->isTradeConfirm) { plr.plr->isTrading = false; plr2.plr->isTrading = false; plr.plr->isTradeConfirm = false; plr2.plr->isTradeConfirm = false; // Check if we have enough free slots int freeSlots = 0; int freeSlotsNeeded = 0; int freeSlots2 = 0; int freeSlotsNeeded2 = 0; for (int i = 0; i < AINVEN_COUNT; i++) { if (plr.plr->Inven[i].iID == 0) freeSlots++; } for (int i = 0; i < 5; i++) { if (plr.plr->Trade[i].iID != 0) freeSlotsNeeded++; } for (int i = 0; i < AINVEN_COUNT; i++) { if (plr2.plr->Inven[i].iID == 0) freeSlots2++; } for (int i = 0; i < 5; i++) { if (plr2.plr->Trade[i].iID != 0) freeSlotsNeeded2++; } if (freeSlotsNeeded2 - freeSlotsNeeded > freeSlots) { INITSTRUCT(sP_FE2CL_REP_PC_TRADE_CONFIRM_ABORT, resp); resp.iID_Request = pacdat->iID_Request; resp.iID_From = pacdat->iID_From; resp.iID_To = pacdat->iID_To; sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_CONFIRM_ABORT, sizeof(sP_FE2CL_REP_PC_TRADE_CONFIRM_ABORT)); otherSock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_CONFIRM_ABORT, sizeof(sP_FE2CL_REP_PC_TRADE_CONFIRM_ABORT)); return; // Fail trade because of the lack of slots } if (freeSlotsNeeded - freeSlotsNeeded2 > freeSlots2) { INITSTRUCT(sP_FE2CL_REP_PC_TRADE_CONFIRM_CANCEL, resp); resp.iID_Request = pacdat->iID_Request; resp.iID_From = pacdat->iID_From; resp.iID_To = pacdat->iID_To; sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_CONFIRM_CANCEL, sizeof(sP_FE2CL_REP_PC_TRADE_CONFIRM_CANCEL)); otherSock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_CONFIRM_CANCEL, sizeof(sP_FE2CL_REP_PC_TRADE_CONFIRM_CANCEL)); return; // Fail trade because of the lack of slots } INITSTRUCT(sP_FE2CL_REP_PC_TRADE_CONFIRM, resp); resp.iID_Request = pacdat->iID_Request; resp.iID_From = pacdat->iID_From; resp.iID_To = pacdat->iID_To; sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_CONFIRM, sizeof(sP_FE2CL_REP_PC_TRADE_CONFIRM)); // ^^ this is a must have or else the player won't accept a succ packet for some reason for (int i = 0; i < freeSlotsNeeded; i++) { plr.plr->Inven[plr.plr->Trade[i].iInvenNum].iID = 0; plr.plr->Inven[plr.plr->Trade[i].iInvenNum].iType = 0; plr.plr->Inven[plr.plr->Trade[i].iInvenNum].iOpt = 0; } for (int i = 0; i < freeSlotsNeeded2; i++) { plr2.plr->Inven[plr2.plr->Trade[i].iInvenNum].iID = 0; plr2.plr->Inven[plr2.plr->Trade[i].iInvenNum].iType = 0; plr2.plr->Inven[plr2.plr->Trade[i].iInvenNum].iOpt = 0; } for (int i = 0; i < AINVEN_COUNT; i++) { if (freeSlotsNeeded <= 0) break; if (plr2.plr->Inven[i].iID == 0) { plr2.plr->Inven[i].iID = plr.plr->Trade[freeSlotsNeeded - 1].iID; plr2.plr->Inven[i].iType = plr.plr->Trade[freeSlotsNeeded - 1].iType; plr2.plr->Inven[i].iOpt = plr.plr->Trade[freeSlotsNeeded - 1].iOpt; plr.plr->Trade[freeSlotsNeeded - 1].iInvenNum = i; freeSlotsNeeded--; } } for (int i = 0; i < AINVEN_COUNT; i++) { if (freeSlotsNeeded2 <= 0) break; if (plr.plr->Inven[i].iID == 0) { plr.plr->Inven[i].iID = plr2.plr->Trade[freeSlotsNeeded2 - 1].iID; plr.plr->Inven[i].iType = plr2.plr->Trade[freeSlotsNeeded2 - 1].iType; plr.plr->Inven[i].iOpt = plr2.plr->Trade[freeSlotsNeeded2 - 1].iOpt; plr2.plr->Trade[freeSlotsNeeded2 - 1].iInvenNum = i; freeSlotsNeeded2--; } } INITSTRUCT(sP_FE2CL_REP_PC_TRADE_CONFIRM_SUCC, resp2); resp2.iID_Request = pacdat->iID_Request; resp2.iID_From = pacdat->iID_From; resp2.iID_To = pacdat->iID_To; plr.plr->money = plr.plr->money + plr2.plr->moneyInTrade - plr.plr->moneyInTrade; resp2.iCandy = plr.plr->money; memcpy(resp2.Item, plr2.plr->Trade, sizeof(plr2.plr->Trade)); memcpy(resp2.ItemStay, plr.plr->Trade, sizeof(plr.plr->Trade)); sock->sendPacket((void*)&resp2, P_FE2CL_REP_PC_TRADE_CONFIRM_SUCC, sizeof(sP_FE2CL_REP_PC_TRADE_CONFIRM_SUCC)); plr2.plr->money = plr2.plr->money + plr.plr->moneyInTrade - plr2.plr->moneyInTrade; resp2.iCandy = plr2.plr->money; memcpy(resp2.Item, plr.plr->Trade, sizeof(plr.plr->Trade)); memcpy(resp2.ItemStay, plr2.plr->Trade, sizeof(plr2.plr->Trade)); otherSock->sendPacket((void*)&resp2, P_FE2CL_REP_PC_TRADE_CONFIRM_SUCC, sizeof(sP_FE2CL_REP_PC_TRADE_CONFIRM_SUCC)); } else { INITSTRUCT(sP_FE2CL_REP_PC_TRADE_CONFIRM, resp); resp.iID_Request = pacdat->iID_Request; resp.iID_From = pacdat->iID_From; resp.iID_To = pacdat->iID_To; plr.plr->isTradeConfirm = true; sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_CONFIRM, sizeof(sP_FE2CL_REP_PC_TRADE_CONFIRM)); otherSock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_CONFIRM, sizeof(sP_FE2CL_REP_PC_TRADE_CONFIRM)); } } void ItemManager::itemTradeConfirmCancelHandler(CNSocket* sock, CNPacketData* data) { if (data->size != sizeof(sP_CL2FE_REQ_PC_TRADE_CONFIRM_CANCEL)) return; // ignore the malformed packet sP_CL2FE_REQ_PC_TRADE_CONFIRM_CANCEL* pacdat = (sP_CL2FE_REQ_PC_TRADE_CONFIRM_CANCEL*)data->buf; INITSTRUCT(sP_FE2CL_REP_PC_TRADE_CONFIRM_CANCEL, resp); resp.iID_Request = pacdat->iID_Request; resp.iID_From = pacdat->iID_From; resp.iID_To = pacdat->iID_To; int iID_Check; if (pacdat->iID_Request == pacdat->iID_From) { iID_Check = pacdat->iID_To; } else { iID_Check = pacdat->iID_From; } CNSocket* otherSock = sock; for (auto pair : PlayerManager::players) { if (pair.second.plr->iID == iID_Check) { otherSock = pair.first; } } PlayerView& plr = PlayerManager::players[sock]; PlayerView& plr2 = PlayerManager::players[otherSock]; plr.plr->isTrading = false; plr.plr->isTradeConfirm = false; plr2.plr->isTrading = false; plr2.plr->isTradeConfirm = false; otherSock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_CONFIRM_CANCEL, sizeof(sP_FE2CL_REP_PC_TRADE_CONFIRM_CANCEL)); } void ItemManager::itemTradeRegisterItemHandler(CNSocket* sock, CNPacketData* data) { if (data->size != sizeof(sP_CL2FE_REQ_PC_TRADE_ITEM_REGISTER)) return; // ignore the malformed packet sP_CL2FE_REQ_PC_TRADE_ITEM_REGISTER* pacdat = (sP_CL2FE_REQ_PC_TRADE_ITEM_REGISTER*)data->buf; if (pacdat->Item.iSlotNum < 0 || pacdat->Item.iSlotNum > 4) return; // sanity check INITSTRUCT(sP_FE2CL_REP_PC_TRADE_ITEM_REGISTER_SUCC, resp); resp.iID_Request = pacdat->iID_Request; resp.iID_From = pacdat->iID_From; resp.iID_To = pacdat->iID_To; resp.TradeItem = pacdat->Item; resp.InvenItem = pacdat->Item; int iID_Check; if (pacdat->iID_Request == pacdat->iID_From) { iID_Check = pacdat->iID_To; } else { iID_Check = pacdat->iID_From; } CNSocket* otherSock = sock; for (auto pair : PlayerManager::players) { if (pair.second.plr->iID == iID_Check) { otherSock = pair.first; } } PlayerView& plr = PlayerManager::players[sock]; plr.plr->Trade[pacdat->Item.iSlotNum] = pacdat->Item; plr.plr->isTradeConfirm = false; sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_ITEM_REGISTER_SUCC, sizeof(sP_FE2CL_REP_PC_TRADE_ITEM_REGISTER_SUCC)); otherSock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_ITEM_REGISTER_SUCC, sizeof(sP_FE2CL_REP_PC_TRADE_ITEM_REGISTER_SUCC)); } void ItemManager::itemTradeUnregisterItemHandler(CNSocket* sock, CNPacketData* data) { if (data->size != sizeof(sP_CL2FE_REQ_PC_TRADE_ITEM_UNREGISTER)) return; // ignore the malformed packet sP_CL2FE_REQ_PC_TRADE_ITEM_UNREGISTER* pacdat = (sP_CL2FE_REQ_PC_TRADE_ITEM_UNREGISTER*)data->buf; INITSTRUCT(sP_FE2CL_REP_PC_TRADE_ITEM_UNREGISTER_SUCC, resp); resp.iID_Request = pacdat->iID_Request; resp.iID_From = pacdat->iID_From; resp.iID_To = pacdat->iID_To; resp.TradeItem = pacdat->Item; PlayerView& plr = PlayerManager::players[sock]; resp.InvenItem = plr.plr->Trade[pacdat->Item.iSlotNum]; plr.plr->isTradeConfirm = false; int iID_Check; if (pacdat->iID_Request == pacdat->iID_From) { iID_Check = pacdat->iID_To; } else { iID_Check = pacdat->iID_From; } CNSocket* otherSock = sock; for (auto pair : PlayerManager::players) { if (pair.second.plr->iID == iID_Check) { otherSock = pair.first; } } int temp_num = pacdat->Item.iSlotNum; if (temp_num >= 0 && temp_num <= 4) { plr.plr->Trade[temp_num].iID = 0; plr.plr->Trade[temp_num].iType = 0; plr.plr->Trade[temp_num].iOpt = 0; plr.plr->Trade[temp_num].iInvenNum = 0; plr.plr->Trade[temp_num].iSlotNum = 0; } sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_ITEM_UNREGISTER_SUCC, sizeof(sP_FE2CL_REP_PC_TRADE_ITEM_UNREGISTER_SUCC)); otherSock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_ITEM_UNREGISTER_SUCC, sizeof(sP_FE2CL_REP_PC_TRADE_ITEM_UNREGISTER_SUCC)); } void ItemManager::itemTradeRegisterCashHandler(CNSocket* sock, CNPacketData* data) { if (data->size != sizeof(sP_CL2FE_REQ_PC_TRADE_CASH_REGISTER)) return; // ignore the malformed packet sP_CL2FE_REQ_PC_TRADE_CASH_REGISTER* pacdat = (sP_CL2FE_REQ_PC_TRADE_CASH_REGISTER*)data->buf; PlayerView& plr = PlayerManager::players[sock]; if (pacdat->iCandy < 0 || pacdat->iCandy > plr.plr->money) return; // famous glitch, begone INITSTRUCT(sP_FE2CL_REP_PC_TRADE_CASH_REGISTER_SUCC, resp); resp.iID_Request = pacdat->iID_Request; resp.iID_From = pacdat->iID_From; resp.iID_To = pacdat->iID_To; resp.iCandy = pacdat->iCandy; int iID_Check; if (pacdat->iID_Request == pacdat->iID_From) { iID_Check = pacdat->iID_To; } else { iID_Check = pacdat->iID_From; } CNSocket* otherSock = sock; for (auto pair : PlayerManager::players) { if (pair.second.plr->iID == iID_Check) { otherSock = pair.first; } } plr.plr->moneyInTrade = pacdat->iCandy; plr.plr->isTradeConfirm = false; sock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_CASH_REGISTER_SUCC, sizeof(sP_FE2CL_REP_PC_TRADE_CASH_REGISTER_SUCC)); otherSock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_CASH_REGISTER_SUCC, sizeof(sP_FE2CL_REP_PC_TRADE_CASH_REGISTER_SUCC)); } void ItemManager::itemTradeChatHandler(CNSocket* sock, CNPacketData* data) { if (data->size != sizeof(sP_CL2FE_REQ_PC_TRADE_EMOTES_CHAT)) return; // malformed packet sP_CL2FE_REQ_PC_TRADE_EMOTES_CHAT* pacdat = (sP_CL2FE_REQ_PC_TRADE_EMOTES_CHAT*)data->buf; INITSTRUCT(sP_FE2CL_REP_PC_TRADE_EMOTES_CHAT, resp); resp.iID_Request = pacdat->iID_Request; resp.iID_From = pacdat->iID_From; resp.iID_To = pacdat->iID_To; memcpy(resp.szFreeChat, pacdat->szFreeChat, sizeof(pacdat->szFreeChat)); resp.iEmoteCode = pacdat->iEmoteCode; int iID_Check; if (pacdat->iID_Request == pacdat->iID_From) { iID_Check = pacdat->iID_To; } else { iID_Check = pacdat->iID_From; } CNSocket* otherSock = sock; for (auto pair : PlayerManager::players) { if (pair.second.plr->iID == iID_Check) { otherSock = pair.first; } } 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)); } 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 - 8); // 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); // maintain stats 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 // 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; for (i = 0; i < AINVEN_COUNT; i++) if (plr->Inven[i].iType == 0 && plr->Inven[i].iID == 0 && plr->Inven[i].iOpt == 0) return i; // not found return -1; } bool ItemManager::isItemRegistered(int32_t id, int32_t type) { return ItemData.find(std::pair(id, type)) != ItemData.end(); } Item ItemManager::getItemData(int32_t id, int32_t type) { return ItemData[std::pair(id, type)]; }