- #include "stdafx.h"
- #include "../../libgame/include/grid.h"
- #include "constants.h"
- #include "utils.h"
- #include "config.h"
- #include "shop.h"
- #include "desc.h"
- #include "desc_manager.h"
- #include "char.h"
- #include "char_manager.h"
- #include "item.h"
- #include "item_manager.h"
- #include "buffer_manager.h"
- #include "packet.h"
- #include "log.h"
- #include "db.h"
- #include "questmanager.h"
- #include "monarch.h"
- #include "mob_manager.h"
- #include "locale_service.h"
- /* ------------------------------------------------------------------------------------ */
- extern int taxes;
- extern bool raise_empire_prices;
- extern bool trade_effect;
- extern int trade_effect_shop_threshold;
- CShop::CShop()
- : m_dwVnum(0), m_dwNPCVnum(0), m_pkPC(NULL)
- {
- m_pGrid = M2_NEW CGrid(10, 9);
- }
- CShop::~CShop()
- {
- TPacketGCShop pack;
- pack.header = HEADER_GC_SHOP;
- pack.subheader = SHOP_SUBHEADER_GC_END;
- pack.size = sizeof(TPacketGCShop);
- Broadcast(&pack, sizeof(pack));
- GuestMapType::iterator it;
- it = m_map_guest.begin();
- while (it != m_map_guest.end())
- {
- LPCHARACTER ch = it->first;
- ch->SetShop(NULL);
- ++it;
- }
- M2_DELETE(m_pGrid);
- }
- void CShop::SetPCShop(LPCHARACTER ch)
- {
- m_pkPC = ch;
- }
- bool CShop::Create(DWORD dwVnum, DWORD dwNPCVnum, TShopItemTable * pTable)
- {
- /*
- if (NULL == CMobManager::instance().Get(dwNPCVnum))
- {
- sys_err("No such a npc by vnum %d", dwNPCVnum);
- return false;
- }
- */
- sys_log(0, "SHOP #%d (Shopkeeper %d)", dwVnum, dwNPCVnum);
- m_dwVnum = dwVnum;
- m_dwNPCVnum = dwNPCVnum;
- BYTE bItemCount;
- for (bItemCount = 0; bItemCount < SHOP_HOST_ITEM_MAX_NUM; ++bItemCount)
- if (0 == (pTable + bItemCount)->vnum)
- break;
- SetShopItems(pTable, bItemCount);
- return true;
- }
- void CShop::SetShopItems(TShopItemTable * pTable, BYTE bItemCount)
- {
- if (bItemCount > SHOP_HOST_ITEM_MAX_NUM)
- return;
- m_pGrid->Clear();
- m_itemVector.resize(SHOP_HOST_ITEM_MAX_NUM);
- memset(&m_itemVector[0], 0, sizeof(SHOP_ITEM) * m_itemVector.size());
- for (int i = 0; i < bItemCount; ++i)
- {
- LPITEM pkItem = NULL;
- const TItemTable * item_table;
- if (m_pkPC)
- {
- pkItem = m_pkPC->GetItem(pTable->pos);
- if (!pkItem)
- {
- sys_err("cannot find item on pos (%d, %d) (name: %s)", pTable->pos.window_type, pTable->pos.cell, m_pkPC->GetName());
- continue;
- }
- item_table = pkItem->GetProto();
- }
- else
- {
- if (!pTable->vnum)
- continue;
- item_table = ITEM_MANAGER::instance().GetTable(pTable->vnum);
- }
- if (!item_table)
- {
- sys_err("Shop: no item table by item vnum #%d", pTable->vnum);
- continue;
- }
- int iPos;
- if (IsPCShop())
- {
- sys_log(0, "MyShop: use position %d", pTable->display_pos);
- iPos = pTable->display_pos;
- }
- else
- iPos = m_pGrid->FindBlank(1, item_table->bSize);
- if (iPos < 0)
- {
- sys_err("not enough shop window");
- continue;
- }
- if (!m_pGrid->IsEmpty(iPos, 1, item_table->bSize))
- {
- if (IsPCShop())
- {
- sys_err("not empty position for pc shop %s[%d]", m_pkPC->GetName(), m_pkPC->GetPlayerID());
- }
- else
- {
- sys_err("not empty position for npc shop");
- }
- continue;
- }
- m_pGrid->Put(iPos, 1, item_table->bSize);
- SHOP_ITEM & item = m_itemVector[iPos];
- item.pkItem = pkItem;
- item.itemid = 0;
- if (item.pkItem)
- {
- item.vnum = pkItem->GetVnum();
- item.count = pkItem->GetCount(); // PC 샵의 경우 아이템 개수는 진짜 아이템의 개수여야 한다.
- item.price = pTable->price; // 가격도 사용자가 정한대로..
- item.itemid = pkItem->GetID();
- }
- else
- {
- item.vnum = pTable->vnum;
- item.count = pTable->count;
- if (IS_SET(item_table->dwFlags, ITEM_FLAG_COUNT_PER_1GOLD))
- {
- if (item_table->dwGold == 0)
- item.price = 0;
- else
- item.price = item.count / item_table->dwGold;
- }
- else
- item.price = item_table->dwGold * item.count;
- }
- char name[36];
- snprintf(name, sizeof(name), "%-20s(#%-5d) (x %d)", item_table->szName, (int) item.vnum, item.count);
- sys_log(0, "SHOP_ITEM: %-36s PRICE %-5d", name, item.price);
- ++pTable;
- }
- }
- int CShop::Buy(LPCHARACTER ch, BYTE pos)
- {
- if (pos >= m_itemVector.size())
- {
- sys_log(0, "Shop::Buy : invalid position %d : %s", pos, ch->GetName());
- return SHOP_SUBHEADER_GC_INVALID_POS;
- }
- if (ch->GetGMLevel() > GM_PLAYER && ch->GetGMLevel() < GM_IMPLEMENTOR)
- {
- ch->ChatPacket(CHAT_TYPE_INFO, "GameMaster item alamaz.");
- return false;
- }
- sys_log(0, "Shop::Buy : name %s pos %d", ch->GetName(), pos);
- GuestMapType::iterator it = m_map_guest.find(ch);
- if (it == m_map_guest.end())
- return SHOP_SUBHEADER_GC_END;
- SHOP_ITEM& r_item = m_itemVector[pos];
- if (r_item.price < 0)
- {
- LogManager::instance().HackLog("SHOP_BUY_GOLD_OVERFLOW", ch);
- return SHOP_SUBHEADER_GC_NOT_ENOUGH_MONEY;
- }
- LPITEM pkSelectedItem = ITEM_MANAGER::instance().Find(r_item.itemid);
- if(trade_effect)
- {
- if (m_pkPC) {
- for (int i = 1; i < r_item.price+1; i=i+trade_effect_shop_threshold)
- ch->CreateFly(4,m_pkPC); // 1 Fly pro 100kk , sonst laggt es O:
- m_pkPC->CreateFly(5,ch); // 1 Item
- m_pkPC->CreateFly(6,ch); // Allgemeines anzeigen
- }
- }
- if (IsPCShop())
- {
- if (!pkSelectedItem)
- {
- sys_log(0, "Shop::Buy : Critical: This user seems to be a hacker : invalid pcshop item : BuyerPID:%d SellerPID:%d",
- ch->GetPlayerID(),
- m_pkPC->GetPlayerID());
- return false;
- }
- if ((pkSelectedItem->GetOwner() != m_pkPC))
- {
- sys_log(0, "Shop::Buy : Critical: This user seems to be a hacker : invalid pcshop item : BuyerPID:%d SellerPID:%d",
- ch->GetPlayerID(),
- m_pkPC->GetPlayerID());
- return false;
- }
- }
- long long llPrice = static_cast<long long>(r_item.price);
- if (it->second && raise_empire_prices) // if other empire, price is triple
- llPrice *= 3;
- if (ch->GetGold() < llPrice)
- {
- sys_log(1, "Shop::Buy : Not enough money : %s has %lld, price %d", ch->GetName(), ch->GetGold(), llPrice);
- return SHOP_SUBHEADER_GC_NOT_ENOUGH_MONEY;
- }
- LPITEM item;
- if (m_pkPC) // 피씨가 운영하는 샵은 피씨가 실제 아이템을 가지고있어야 한다.
- item = r_item.pkItem;
- else
- item = ITEM_MANAGER::instance().CreateItem(r_item.vnum, r_item.count);
- if (!item)
- return SHOP_SUBHEADER_GC_SOLD_OUT;
- int suprice = 0;
- int wonprice = 0;
- if (ch->GetShopOwner()->IsPC() && ch->GetShopOwner())
- {
- //sys_err("267.satir");
- char bufff[256];
- char bufff2[256];
- snprintf(bufff, sizeof(bufff), "pazar.pazarsuslot%d", pos);
- snprintf(bufff2, sizeof(bufff2), "pazar.pazarbarslot%d", pos);
- //sys_err("272.satir");
- suprice = m_pkPC->GetQuestFlag(bufff);
- wonprice = m_pkPC->GetQuestFlag(bufff2);
- //sys_err("275.satir");
- if (ch->CountSpecifyItem(38053) < suprice && ch->GetShopOwner()->IsPC() == true)
- {
- ch->ChatPacket(CHAT_TYPE_COMMAND, "sutasiyok");
- return SHOP_SUBHEADER_GC_END;
- }
- //sys_err("281.satir");
- if (ch->CountSpecifyItem(38052) < wonprice && ch->GetShopOwner()->IsPC() == true)
- {
- ch->ChatPacket(CHAT_TYPE_COMMAND, "wonyok");
- return SHOP_SUBHEADER_GC_END;
- }
- }
- int iEmptyPos;
- if (item->IsDragonSoul())
- {
- iEmptyPos = ch->GetEmptyDragonSoulInventory(item);
- }
- else
- {
- iEmptyPos = ch->GetEmptyInventory(item->GetSize());
- }
- if (iEmptyPos < 0)
- {
- if (m_pkPC)
- {
- sys_log(1, "Shop::Buy at PC Shop : Inventory full : %s size %d", ch->GetName(), item->GetSize());
- return SHOP_SUBHEADER_GC_INVENTORY_FULL;
- }
- else
- {
- sys_log(1, "Shop::Buy : Inventory full : %s size %d", ch->GetName(), item->GetSize());
- M2_DESTROY_ITEM(item);
- return SHOP_SUBHEADER_GC_INVENTORY_FULL;
- }
- }
- ch->SetQuestNPCID(ch->GetShopOwner()->GetVID());
- quest::CQuestManager::instance().Buy(ch->GetPlayerID());
- ch->PointChange(POINT_GOLD, -llPrice, false);
- //세금 계산
- DWORD dwTax = 0;
- int iVal = 0;
- if(taxes!=0)
- dwTax = llPrice * taxes / 100;
- llPrice = llPrice - dwTax;
- // 상점에서 살 세금 5%
- if (!m_pkPC)
- {
- CMonarch::instance().SendtoDBAddMoney(dwTax, ch->GetEmpire(), ch);
- }
- if (ch->GetShopOwner()->IsPC() == true && ch->GetShopOwner())
- {
- if (ch->IsPC() == true && ch != m_pkPC)
- {
- ch->RemoveSpecifyItem(38053,suprice);
- }
- if (ch->IsPC() == true && ch != m_pkPC)
- {
- ch->RemoveSpecifyItem(38052,wonprice);
- }
- int sumiktar = 0;
- int barmiktar = 0;
- //sys_err("364.satir");
- if (ch != m_pkPC)
- {
- while (sumiktar < suprice && ch->GetShopOwner()->IsPC() == true)
- {
- //m_pkPC->AutoGiveItem(38052,1);
- m_pkPC->AutoGiveItem(38053,1,0,false);
- sumiktar++;
- }
- }
- if (ch != m_pkPC)
- {
- while (barmiktar < wonprice && ch->GetShopOwner()->IsPC() == true)
- {
- //m_pkPC->AutoGiveItem(50513,1);
- m_pkPC->AutoGiveItem(38052,1,0,false);
- barmiktar++;
- }
- }
- }
- // 군주 시스템 : 세금 징수
- if (m_pkPC)
- {
- m_pkPC->SyncQuickslot(QUICKSLOT_TYPE_ITEM, item->GetCell(), 255);
- if (item->GetVnum() == 90008 || item->GetVnum() == 90009) // VCARD
- {
- VCardUse(m_pkPC, ch, item);
- item = NULL;
- }
- else
- {
- char buf[512];
- if (item->GetVnum() >= 80003 && item->GetVnum() <= 38052)
- {
- snprintf(buf, sizeof(buf), "%s FROM: %u TO: %u PRICE: %u", item->GetName(), ch->GetPlayerID(), m_pkPC->GetPlayerID(), llPrice);
- LogManager::instance().GoldBarLog(ch->GetPlayerID(), item->GetID(), SHOP_BUY, buf);
- LogManager::instance().GoldBarLog(m_pkPC->GetPlayerID(), item->GetID(), SHOP_SELL, buf);
- }
- item->RemoveFromCharacter();
- if (item->IsDragonSoul())
- item->AddToCharacter(ch, TItemPos(DRAGON_SOUL_INVENTORY, iEmptyPos));
- else
- item->AddToCharacter(ch, TItemPos(INVENTORY, iEmptyPos));
- ITEM_MANAGER::instance().FlushDelayedSave(item);
- snprintf(buf, sizeof(buf), "%s %u(%s) %u %u", item->GetName(), m_pkPC->GetPlayerID(), m_pkPC->GetName(), llPrice, item->GetCount());
- LogManager::instance().ItemLog(ch, item, "SHOP_BUY", buf);
- snprintf(buf, sizeof(buf), "%s %u(%s) %u %u", item->GetName(), ch->GetPlayerID(), ch->GetName(), llPrice, item->GetCount());
- LogManager::instance().ItemLog(m_pkPC, item, "SHOP_SELL", buf);
- }
- r_item.pkItem = NULL;
- BroadcastUpdateItem(pos);
- m_pkPC->PointChange(POINT_GOLD, llPrice, false);
- if (iVal > 0)
- m_pkPC->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("판매금액의 %d %% 가 세금으로 나가게됩니다"), iVal);
- CMonarch::instance().SendtoDBAddMoney(dwTax, m_pkPC->GetEmpire(), m_pkPC);
- }
- else
- {
- if (item->IsDragonSoul())
- item->AddToCharacter(ch, TItemPos(DRAGON_SOUL_INVENTORY, iEmptyPos));
- else
- item->AddToCharacter(ch, TItemPos(INVENTORY, iEmptyPos));
- ITEM_MANAGER::instance().FlushDelayedSave(item);
- LogManager::instance().ItemLog(ch, item, "BUY", item->GetName());
- if (item->GetVnum() >= 80003 && item->GetVnum() <= 38052)
- {
- LogManager::instance().GoldBarLog(ch->GetPlayerID(), item->GetID(), PERSONAL_SHOP_BUY, "");
- }
- DBManager::instance().SendMoneyLog(MONEY_LOG_SHOP, item->GetVnum(), -llPrice);
- }
- if (item)
- sys_log(0, "SHOP: BUY: name %s %s(x %d):%u price %u", ch->GetName(), item->GetName(), item->GetCount(), item->GetID(), llPrice);
- ch->Save();
- return (SHOP_SUBHEADER_GC_OK);
- }
- bool CShop::AddGuest(LPCHARACTER ch, DWORD owner_vid, bool bOtherEmpire)
- {
- if (!ch)
- return false;
- if (ch->GetExchange())
- return false;
- if (ch->GetShop())
- return false;
- ch->SetShop(this);
- m_map_guest.insert(GuestMapType::value_type(ch, bOtherEmpire));
- TPacketGCShop pack;
- pack.header = HEADER_GC_SHOP;
- pack.subheader = SHOP_SUBHEADER_GC_START;
- TPacketGCShopStart pack2;
- memset(&pack2, 0, sizeof(pack2));
- pack2.owner_vid = owner_vid;
- for (DWORD i = 0; i < m_itemVector.size() && i < SHOP_HOST_ITEM_MAX_NUM; ++i)
- {
- const SHOP_ITEM & item = m_itemVector[i];
- if (m_pkPC && !item.pkItem)
- continue;
- pack2.items[i].vnum = item.vnum;
- if (bOtherEmpire && raise_empire_prices) // no empire price penalty for pc shop
- pack2.items[i].price = item.price * 3;
- else
- pack2.items[i].price = item.price;
- pack2.items[i].count = item.count;
- if (item.pkItem)
- {
- thecore_memcpy(pack2.items[i].alSockets, item.pkItem->GetSockets(), sizeof(pack2.items[i].alSockets));
- thecore_memcpy(pack2.items[i].aAttr, item.pkItem->GetAttributes(), sizeof(pack2.items[i].aAttr));
- }
- }
- pack.size = sizeof(pack) + sizeof(pack2);
- ch->GetDesc()->BufferedPacket(&pack, sizeof(TPacketGCShop));
- ch->GetDesc()->Packet(&pack2, sizeof(TPacketGCShopStart));
- return true;
- }
- void CShop::RemoveGuest(LPCHARACTER ch)
- {
- if (ch->GetShop() != this)
- return;
- m_map_guest.erase(ch);
- ch->SetShop(NULL);
- TPacketGCShop pack;
- pack.header = HEADER_GC_SHOP;
- pack.subheader = SHOP_SUBHEADER_GC_END;
- pack.size = sizeof(TPacketGCShop);
- ch->GetDesc()->Packet(&pack, sizeof(pack));
- }
- void CShop::Broadcast(const void * data, int bytes)
- {
- sys_log(1, "Shop::Broadcast %p %d", data, bytes);
- GuestMapType::iterator it;
- it = m_map_guest.begin();
- while (it != m_map_guest.end())
- {
- LPCHARACTER ch = it->first;
- if (ch->GetDesc())
- ch->GetDesc()->Packet(data, bytes);
- ++it;
- }
- }
- void CShop::BroadcastUpdateItem(BYTE pos)
- {
- TPacketGCShop pack;
- TPacketGCShopUpdateItem pack2;
- TEMP_BUFFER buf;
- pack.header = HEADER_GC_SHOP;
- pack.subheader = SHOP_SUBHEADER_GC_UPDATE_ITEM;
- pack.size = sizeof(pack) + sizeof(pack2);
- pack2.pos = pos;
- if (m_pkPC && !m_itemVector[pos].pkItem)
- pack2.item.vnum = 0;
- else
- {
- pack2.item.vnum = m_itemVector[pos].vnum;
- if (m_itemVector[pos].pkItem)
- {
- thecore_memcpy(pack2.item.alSockets, m_itemVector[pos].pkItem->GetSockets(), sizeof(pack2.item.alSockets));
- thecore_memcpy(pack2.item.aAttr, m_itemVector[pos].pkItem->GetAttributes(), sizeof(pack2.item.aAttr));
- }
- else
- {
- memset(pack2.item.alSockets, 0, sizeof(pack2.item.alSockets));
- memset(pack2.item.aAttr, 0, sizeof(pack2.item.aAttr));
- }
- }
- pack2.item.price = m_itemVector[pos].price;
- pack2.item.count = m_itemVector[pos].count;
- buf.write(&pack, sizeof(pack));
- buf.write(&pack2, sizeof(pack2));
- Broadcast(buf.read_peek(), buf.size());
- }
- int CShop::GetNumberByVnum(DWORD dwVnum)
- {
- int itemNumber = 0;
- for (DWORD i = 0; i < m_itemVector.size() && i < SHOP_HOST_ITEM_MAX_NUM; ++i)
- {
- const SHOP_ITEM & item = m_itemVector[i];
- if (item.vnum == dwVnum)
- {
- itemNumber += item.count;
- }
- }
- return itemNumber;
- }
- bool CShop::IsSellingItem(DWORD itemID)
- {
- bool isSelling = false;
- for (DWORD i = 0; i < m_itemVector.size() && i < SHOP_HOST_ITEM_MAX_NUM; ++i)
- {
- if (static_cast<unsigned long>(m_itemVector[i].itemid) == itemID)
- {
- isSelling = true;
- break;
- }
- }
- return isSelling;
- }