int TradeShopHandler::helper_trade_shop_sell(SimulatorThread *sim, CharacterServerData *pld, SimulatorQuery *query, CreatureInstance *creatureInstance, const char *itemHex) { //Return the query response when selling stuff to an NPC shop. unsigned int CCSID = strtol(itemHex, NULL, 16); InventorySlot *item = pld->charPtr->inventory.GetItemPtrByCCSID(CCSID); if (item == NULL) return PrepExt_QueryResponseError(sim->SendBuf, query->ID, "Item not found in inventory."); ItemDef *itemPtr = item->ResolveItemPtr(); if (itemPtr == NULL) return PrepExt_QueryResponseError(sim->SendBuf, query->ID, "Item does not exist in server database."); int wpos = 0; wpos += PrepExt_QueryResponseString(&sim->SendBuf[wpos], query->ID, "OK"); int cost = itemPtr->mValue; cost *= item->GetStackCount(); wpos += pld->charPtr->inventory.AddBuyBack(item, &sim->SendBuf[wpos]); wpos += RemoveItemUpdate(&sim->SendBuf[wpos], sim->Aux3, item); pld->charPtr->inventory.RemItem(CCSID); pld->charPtr->pendingChanges++; creatureInstance->AdjustCopper(cost); return wpos; }
int TradeShopHandler::helper_trade_shop_buyback(SimulatorThread *sim, CharacterServerData *pld, SimulatorQuery *query, CreatureInstance *creatureInstance,unsigned int CCSID) { InventorySlot *buybackItem = pld->charPtr->inventory.GetItemPtrByCCSID( CCSID); if (buybackItem == NULL) return PrepExt_QueryResponseError(sim->SendBuf, query->ID, "Item not found in buyback list."); int freeslot = pld->charPtr->inventory.GetFreeSlot(INV_CONTAINER); if (freeslot == -1) return PrepExt_QueryResponseError(sim->SendBuf, query->ID, "No free inventory space."); ItemDef *itemPtr = buybackItem->ResolveItemPtr(); if (itemPtr == NULL) return PrepExt_QueryResponseError(sim->SendBuf, query->ID, "Item does not exist in database."); int cost = itemPtr->mValue * buybackItem->GetStackCount(); if (creatureInstance->css.copper < cost) return PrepExt_QueryResponseError(sim->SendBuf, query->ID, "Not enough coin."); InventorySlot newItem; newItem.CopyFrom(*buybackItem, false); newItem.CCSID = pld->charPtr->inventory.GetCCSID(INV_CONTAINER, freeslot); int r = pld->charPtr->inventory.AddItem(INV_CONTAINER, newItem); if (r == -1) return PrepExt_QueryResponseError(sim->SendBuf, query->ID, "Failed to create item."); pld->charPtr->pendingChanges++; int wpos = 0; wpos = RemoveItemUpdate(sim->SendBuf, sim->Aux3, buybackItem); wpos += AddItemUpdate(&sim->SendBuf[wpos], sim->Aux3, &newItem); wpos += PrepExt_QueryResponseString(&sim->SendBuf[wpos], query->ID, "OK"); pld->charPtr->inventory.RemItem(buybackItem->CCSID); pld->charPtr->pendingChanges++; creatureInstance->AdjustCopper(-cost); return wpos; }
int TradeAcceptHandler::handleQuery(SimulatorThread *sim, CharacterServerData *pld, SimulatorQuery *query, CreatureInstance *creatureInstance) { /* Query: trade.accept A player has accepted the trade offer. Args : [none] */ int rval = protected_helper_query_trade_accept(sim, pld, query, creatureInstance); if (rval <= 0) rval = PrepExt_QueryResponseError(sim->SendBuf, query->ID, sim->GetErrorString(rval)); return rval; }
int TradeCurrencyHandler::handleQuery(SimulatorThread *sim, CharacterServerData *pld, SimulatorQuery *query, CreatureInstance *creatureInstance) { /* Query: trade.currency Sent when the player offers a coin amount. Args : [0] currency name, ex: "COPPER" [1] amount offered */ int rval = protected_helper_query_trade_currency(sim, pld, query, creatureInstance); if (rval <= 0) rval = PrepExt_QueryResponseError(sim->SendBuf, query->ID, sim->GetErrorString(rval)); return rval; }
int TradeStartHandler::handleQuery(SimulatorThread *sim, CharacterServerData *pld, SimulatorQuery *query, CreatureInstance *creatureInstance) { /* Query: trade.start Attempt to open a trade with another player. Args : [0] = Creature ID of the player to trade with. */ int rval = protected_helper_query_trade_start(sim, pld, query, creatureInstance); if (rval <= 0) { rval = PrepExt_SendInfoMessage(sim->SendBuf, sim->GetErrorString(rval), INFOMSG_ERROR); rval += PrepExt_QueryResponseError(&sim->SendBuf[rval], query->ID, ""); } return rval; }
int PersonaCreateHandler::handleQuery(SimulatorThread *sim, CharacterServerData *pld, SimulatorQuery *query, CreatureInstance *creatureInstance) { /* Query: persona.create Args : [variable] list of attributes Notes: Attributes are customized by the player in the Character Creation steps. Return: Unknown. Possibly an index for use in the client? */ g_AccountManager.cs.Enter("SimulatorThread::handle_query_persona_create"); CharacterData newChar; int r = g_AccountManager.CreateCharacter(query->args, pld->accPtr, newChar); g_AccountManager.cs.Leave(); if (r < AccountManager::CHARACTER_SUCCESS) return PrepExt_QueryResponseError(sim->SendBuf, query->ID, g_AccountManager.GetCharacterErrorMessage(r)); g_CharacterManager.SaveCharacter(newChar.cdef.CreatureDefID); sprintf(sim->Aux1, "%d", r + 1); return PrepExt_QueryResponseString(sim->SendBuf, query->ID, sim->Aux1); }
int PersonaDeleteHandler::handleQuery(SimulatorThread *sim, CharacterServerData *pld, SimulatorQuery *query, CreatureInstance *creatureInstance) { /* Query: persona.delete Args : [0] index to remove */ if (query->argCount < 1) return PrepExt_QueryResponseError(sim->SendBuf, query->ID, "Invalid query"); int index = query->GetInteger(0); if (index >= 0 && index <= pld->accPtr->MAX_CHARACTER_SLOTS) { int CDefID = pld->accPtr->CharacterSet[index]; CharacterData *cd = g_CharacterManager.RequestCharacter(CDefID, true); if (cd->clan > 0) { Clans::Clan c = g_ClanManager.mClans[cd->clan]; if (c.mId > 0) { Clans::ClanMember me = c.GetMember(CDefID); c.RemoveMember(me); if (c.mMembers.size() < 1) { g_Logs.event->info( "[CLAN] Disbanding clan %v because the last member left.", c.mName.c_str()); g_ClanManager.RemoveClan(c); } else { if (me.mRank == Clans::Rank::LEADER) { Clans::ClanMember nextLeader = c.GetFirstMemberOfRank( Clans::Rank::OFFICER); if (nextLeader.mID == 0) { nextLeader = c.GetFirstMemberOfRank( Clans::Rank::MEMBER); if (nextLeader.mID == 0) { nextLeader = c.GetFirstMemberOfRank( Clans::Rank::INITIATE); if (nextLeader.mID == 0) { g_Logs.event->warn( "[CLAN] There is nobody to pass leadership of clan of %v to! Removing the clan", c.mName.c_str()); g_ClanManager.RemoveClan(c); BroadcastClanDisbandment(c); } } } if (nextLeader.mID != 0) { nextLeader.mRank = Clans::Rank::LEADER; c.UpdateMember(nextLeader); BroadcastClanRankChange(cd->cdef.css.display_name, c, nextLeader); g_ClanManager.SaveClan(c); } } else { g_ClanManager.SaveClan(c); } } } } } g_AccountManager.DeleteCharacter(index, pld->accPtr); return PrepExt_QueryResponseString(sim->SendBuf, query->ID, "OK"); }
int TradeEssenceHandler::handleQuery(SimulatorThread *sim, CharacterServerData *pld, SimulatorQuery *query, CreatureInstance *creatureInstance) { /* Query: trade.essence Sent when an item is purchased from a chest using tokens or essences, instead of gold. Args : [0] = Creature Instance ID [1] = Item proto of the player's selection. */ // [0] = Creature Instance ID // [1] = Item Proto that was selected ex: "item143548:0:0:0" if (query->argCount < 2) return 0; int CID = atoi(query->args[0].c_str()); int CDef = sim->ResolveCreatureDef(CID); //Since the Essence Shop scanning functions modify the string while searching //for tokens, copy it to a buffer here. Util::SafeCopy(sim->Aux1, query->args[1].c_str(), sizeof(sim->Aux1)); EssenceShopItem *iptr = NULL; EssenceShop *esptr = creatureInstance->actInst->essenceShopList.GetEssenceShopPtr(CDef, sim->Aux1, &iptr); if (esptr == NULL || iptr == NULL) { g_Logs.simulator->error( "[%d] Failed to process EssenceShop item [%s] for CreatureDef [%d]", sim->InternalID, sim->Aux1, CDef); return PrepExt_QueryResponseError(sim->SendBuf, query->ID, "Failed to determine item selection."); } InventoryManager &inv = pld->charPtr->inventory; int currentItemCount = inv.GetItemCount(INV_CONTAINER, esptr->EssenceID); if (currentItemCount < iptr->EssenceCost) { g_Logs.simulator->warn("[%v] Essence requirement for item %v: %v / %v", sim->InternalID, esptr->EssenceID, currentItemCount, iptr->EssenceCost); return PrepExt_QueryResponseString(sim->SendBuf, query->ID, "You do not have enough essences."); } InventorySlot *newItem = pld->charPtr->inventory.AddItem_Ex(INV_CONTAINER, iptr->ItemID, 1); if (newItem == NULL) { pld->charPtr->pendingChanges++; int err = pld->charPtr->inventory.LastError; if (err == InventoryManager::ERROR_ITEM) return PrepExt_QueryResponseString(sim->SendBuf, query->ID, "Server error: item does not exist."); else if (err == InventoryManager::ERROR_SPACE) return PrepExt_QueryResponseString(sim->SendBuf, query->ID, "You do not have any free inventory space."); else if (err == InventoryManager::ERROR_LIMIT) return PrepExt_QueryResponseString(sim->SendBuf, query->ID, "You already the maximum amount of these items."); else return PrepExt_QueryResponseString(sim->SendBuf, query->ID, "Server error: undefined error."); } sim->ActivateActionAbilities(newItem); STRINGLIST result; result.push_back("OK"); sprintf(sim->Aux3, "%d", iptr->EssenceCost); result.push_back(sim->Aux3); int wpos = PrepExt_QueryResponseStringList(sim->SendBuf, query->ID, result); wpos += AddItemUpdate(&sim->SendBuf[wpos], sim->Aux3, newItem); wpos += inv.RemoveItemsAndUpdate(INV_CONTAINER, esptr->EssenceID, iptr->EssenceCost, &sim->SendBuf[wpos]); pld->charPtr->pendingChanges++; return wpos; }
int TradeShopHandler::handleQuery(SimulatorThread *sim, CharacterServerData *pld, SimulatorQuery *query, CreatureInstance *creatureInstance) { /* Query: trade.shop Sent when an item is purchased from a shop. Args : [0] = Creature ID of the NPC If buying from shop: [1] = Item proto of selection (ex: item143548:0:0:0); If buying from buyback: [1] = Hex string of item container/slot ID If selling [1] = String constant: "sell" [2] = Hex string of item container/slot ID */ if (query->argCount < 2) return PrepExt_QueryResponseString(sim->SendBuf, query->ID, "OK"); if (pld->zoneDef->mGrove == true) if (sim->CheckPermissionSimple(Perm_Account, Permission_Admin) == false) return PrepExt_QueryResponseError(sim->SendBuf, query->ID, "You cannot use shops in a grove."); //if(HasQueryArgs(2) == false) // return 0; int CID = atoi(query->args[0].c_str()); int CDef = sim->ResolveCreatureDef(CID); if (query->args[1].compare("sell") == 0) { //if(HasQueryArgs(3) == false) // return 0; if (query->argCount < 3) return PrepExt_QueryResponseString(sim->SendBuf, query->ID, "OK"); //[2] = Hex String, pass it to the helper function return helper_trade_shop_sell(sim, pld, query, creatureInstance, query->args[2].c_str()); } //Since the Essence Shop scanning functions modify the string while searching //for tokens, copy it to a buffer here. Util::SafeCopy(sim->Aux1, query->args[1].c_str(), sizeof(sim->Aux1)); EssenceShopItem *iptr = NULL; EssenceShop *esptr = creatureInstance->actInst->itemShopList.GetEssenceShopPtr( CDef, sim->Aux1, &iptr); if (esptr == NULL || iptr == NULL) { //This might be a buyback item. unsigned int CCSID = strtol(sim->Aux1, NULL, 16); int r = helper_trade_shop_buyback(sim, pld, query, creatureInstance,CCSID); if (r > 0) return r; g_Logs.simulator->error( "[%d] Failed to process Shop item [%s] for CreatureDef [%d]", sim->InternalID, sim->Aux1, CDef); return PrepExt_QueryResponseError(sim->SendBuf, query->ID, "Failed to determine item selection."); } ItemDef *itemPtr = g_ItemManager.GetPointerByID(iptr->ItemID); if (itemPtr == NULL) return PrepExt_QueryResponseString(sim->SendBuf, query->ID, "Server error: item does not exist."); int cost = (int) (itemPtr->mValue * g_VendorMarkup); if (creatureInstance->css.copper < cost) return PrepExt_QueryResponseString(sim->SendBuf, query->ID, "Not enough coin."); //Check to see if this was a gambled item, and modify its ID accordingly. int newItemID = 0; newItemID = g_ItemManager.RunPurchaseModifier(itemPtr->mID); //If the normal gamble options failed, it will return the same ID. Check for new randomized gamble options instead. if (newItemID == itemPtr->mID) { VirtualItemSpawnParams viParam; if (g_ItemManager.CheckVirtualItemGamble(itemPtr, creatureInstance->css.level, &viParam, cost) == true) { //Coin amount may be modified. if (creatureInstance->css.copper < cost) return PrepExt_QueryResponseString(sim->SendBuf, query->ID, "Not enough coin."); newItemID = g_ItemManager.RollVirtualItem(viParam); } } if (newItemID == 0) return PrepExt_QueryResponseString(sim->SendBuf, query->ID, "A purchase modifier has failed."); InventorySlot *newItem = pld->charPtr->inventory.AddItem_Ex(INV_CONTAINER, newItemID, 1); if (newItem == NULL) { pld->charPtr->pendingChanges++; int err = pld->charPtr->inventory.LastError; if (err == InventoryManager::ERROR_ITEM) return PrepExt_QueryResponseString(sim->SendBuf, query->ID, "Server error: item does not exist."); else if (err == InventoryManager::ERROR_SPACE) return PrepExt_QueryResponseString(sim->SendBuf, query->ID, "You do not have any free inventory space."); else if (err == InventoryManager::ERROR_LIMIT) return PrepExt_QueryResponseString(sim->SendBuf, query->ID, "You already the maximum amount of these items."); else return PrepExt_QueryResponseString(sim->SendBuf, query->ID, "Server error: undefined error."); } else { sim->ActivateActionAbilities(newItem); } int wpos = PrepExt_QueryResponseString(sim->SendBuf, query->ID, "OK"); wpos += AddItemUpdate(&sim->SendBuf[wpos], sim->Aux3, newItem); creatureInstance->AdjustCopper(-cost); return wpos; }
// //GameQueryMessage // int GameQueryMessage::handleMessage(SimulatorThread *sim, CharacterServerData *pld, SimulatorQuery *query, CreatureInstance *creatureInstance) { #ifdef DEBUG_TIME unsigned long startTime = g_PlatformTime.getMilliseconds(); #endif int PendingData = 0; query->Clear(); //Clear it here so that debug polls can fetch the most recent query. sim->ReadQueryFromMessage(); //LogMessageL(MSG_SHOW, "[DEBUG] handle_game_query:%s (ID:%d)", query.name.c_str(), query.ID); // Debug /* LogMessageL(MSG_SHOW, "Query: %d=%s", query.ID, query.name.c_str()); for(int i = 0; i < query.argCount; i++) LogMessageL(MSG_SHOW, " %d=%s", i, query.args[i].c_str()); */ QueryHandler *qh = g_QueryManager.getQueryHandler(query->name); if (qh == NULL) { // See if the instance script will handle the command if (creatureInstance != NULL && creatureInstance->actInst != NULL && creatureInstance->actInst->nutScriptPlayer != NULL) { std::vector<ScriptCore::ScriptParam> p; p.push_back(creatureInstance->CreatureID); p.insert(p.end(), query->args.begin(), query->args.end()); Util::SafeFormat(sim->Aux1, sizeof(sim->Aux1), "on_command_%s", query->name.c_str()); if (creatureInstance->actInst->nutScriptPlayer->RunFunction( sim->Aux1, p, true)) { return PrepExt_QueryResponseString(sim->SendBuf, query->ID, "OK."); } } g_Logs.simulator->warn("[%v] Unhandled query in game: %v", sim->InternalID, query->name.c_str()); for (unsigned int i = 0; i < query->argCount; i++) g_Logs.simulator->warn("[%v] [%v]=[%v]", sim->InternalID, i, query->args[i].c_str()); PendingData = PrepExt_QueryResponseError(sim->SendBuf, query->ID, "Unknown query."); } else { PendingData = qh->handleQuery(sim, pld, query, creatureInstance); } #ifdef DEBUG_TIME unsigned long passTime = g_PlatformTime.getMilliseconds() - startTime; if (passTime > 50) { g_Logs.simulator->debug( "[%v] TIME PASS handle_game_query() %v ms for query:%v (ID:%v)", sim->InternalID, passTime, query->name.c_str(), query->ID); for (unsigned int i = 0; i < query->argCount; i++) g_Logs.simulator->debug("[%v] [%v]=%v", sim->InternalID, i, query->args[i].c_str()); } #ifdef DEBUG_PROFILER _DebugProfiler.AddQuery(query->name, passTime); #endif #endif return PendingData; }