#include "StdAfx.h" #ifdef ENABLE_IKASHOP_RENEWAL #include #include #include #include "../GameLib/ItemManager.h" #include "../EterPack/EterPackManager.h" #include "Packet.h" #include "PythonNetworkStream.h" #include "PythonTextTail.h" #include "PythonPlayer.h" #include "PythonIkarusShop.h" #include "PythonCharacterManager.h" #include "PythonSystem.h" #ifdef min #undef min #undef max #endif #include #include #include #include #include #include #include #include "JsonHelper.h" using namespace ikashop::python; DWORD ikashop::GetItemHash(const TShopPlayerItem& item) { // checking type - skipping non equip items CItemData* table = nullptr; if(!CItemManager::instance().GetItemDataPointer(item.vnum, &table)) return 0; switch(table->GetType()) { case CItemData::ITEM_TYPE_ARMOR: case CItemData::ITEM_TYPE_WEAPON: case CItemData::ITEM_TYPE_COSTUME: case CItemData::ITEM_TYPE_BELT: break; default: return 0; } // copying values auto copy {item}; // resetting non hashable values copy.expiration = {}; copy.id = {}; copy.owner = {}; copy.pos = {}; copy.window = {}; // returning memory hash return GetCRC32(reinterpret_cast(©), sizeof(copy)); } #ifdef ENABLE_IKASHOP_ENTITIES namespace ikashop { #ifdef EXTEND_IKASHOP_ULTIMATE ShopInstance::EffectID ShopInstance::_FindEffectCRC(const SignString& name) { auto it = s_RegisterEffectMap.find(name); if (it != s_RegisterEffectMap.end()) return it->second; EffectID crc = 0; if (!CEffectManager::Instance().RegisterEffect2(name.c_str(), &crc, false)) { crc = 0; TraceError("CANNOT REGISTER EFFECT FILE : %s", name.c_str()); } s_RegisterEffectMap[name] = crc; return crc; } void ShopInstance::LoadShopSkinSettings() { static constexpr char skinSettings[] = "ikashop/ultimate/shop_skins.txt"; static bool s_loaded = false; if(s_loaded) return; s_loaded = true; // getting file data CMappedFile file{}; const void* data = nullptr; if(!CEterPackManager::instance().Get(file, skinSettings, &data)) { TraceError("CANNOT OPEN %s", skinSettings); return; } // getting text file parser CMemoryTextFileLoader text; text.Bind(file.Size(), data); for(int i=0; i < text.GetLineCount(); i++) { // skipping empty lines and comments auto line = msl::trim(text.GetLineString(i)); if(line.empty() || line[0] == '#') continue; // checking tokens auto tokens = msl::string_split(line, "\t"); if(tokens.size() < 3) { TraceError("%s: ERROR ON LINE %d", skinSettings, i); continue; } // extracting index & folder auto& indexstr = tokens[0]; if(!std::all_of(indexstr.begin(), indexstr.end(), [](auto&& ch){ return std::isdigit(ch); })) { TraceError("%s: ERROR ON LINE %d", skinSettings, i); continue; } int index = std::stoi(indexstr.c_str()); auto& folder = tokens[1]; auto& msm = tokens[2]; _LoadShopSkin(index, folder, msm); } } void ShopInstance::_LoadShopSkin(int index, const std::string& folder, const std::string& msm) { if(s_SkinMap.contains(index)) { TraceError("SHOP SKIN INDEX %d ALREADY EXISTS!", index); return; } // getting msm auto msmfile = fmt::format("{}/{}.msm", folder, msm); CTextFileLoader loader; if(!loader.Load(msmfile.c_str())) { TraceError("SHOP SKIN INDEX %d FAILED TO LOAD MSM [%s]!", index, msmfile.c_str()); return; } std::string model; if(!loader.GetTokenString("basemodelfilename", &model)) { TraceError("SHOP SKIN INDEX %d FAILED TO LOAD MSM [%s] CANNOT FIND basemodelfilename!", index, msmfile.c_str()); return; } // registering skin info auto& skin = s_SkinMap[index]; skin.folder = folder; skin.model = model; // extracting effects DWORD datacount = 0; if (loader.SetChildNode("attachingdata") && loader.GetTokenDoubleWord("attachingdatacount", &datacount)) { for (DWORD i = 0; i < datacount; ++i, loader.SetParentNode()) { if (!loader.SetChildNode("attachingdata", i)) continue; DWORD type = 0; if (!loader.GetTokenDoubleWord("attachingdatatype", &type)) continue; if(type != NRaceData::ATTACHING_DATA_TYPE_EFFECT) continue; std::string script; if(!loader.GetTokenString("effectscriptname", &script)) continue; std::string bone{}; loader.GetTokenString("attachingbonename", &bone); D3DXVECTOR3 pos{}; loader.GetTokenVector3("effectposition", &pos); D3DXVECTOR3 rot{}; loader.GetTokenVector3("effectrotation", &rot); auto& effect = skin.effects.emplace_back(); effect.script = script; effect.bone = bone; effect.position = pos; effect.rotation = rot; } } } #endif ShopInstance::ShopInstance(SkinType Skin) { m_VirtualID = 0; m_Skin = Skin; #ifdef EXTEND_IKASHOP_ULTIMATE LoadShopSkinSettings(); #endif } void ShopInstance::SetName(const SignString& str) { static CGraphicText* font = nullptr; if (!font) font = static_cast(DefaultFont_GetResource()); m_Text.SetValue(str.c_str()); m_Text.SetTextPointer(font); m_Text.SetOutline(true); m_Text.SetHorizonalAlign(CGraphicTextInstance::EHorizontalAlign::HORIZONTAL_ALIGN_CENTER); m_Text.SetColor(0xFF7AE75D); m_Text.Update(); } const ShopInstance::SignString& ShopInstance::GetName() { return m_Text.GetValueStringReference(); } void ShopInstance::Show(float x, float y, float z) { std::string model = "ikashop/lite/shop.gr2"; #ifdef EXTEND_IKASHOP_ULTIMATE std::string animation{}; auto iter = s_SkinMap.find(m_Skin); if (iter != s_SkinMap.end()) { model = iter->second.model; animation = fmt::format("{}/wait.gr2", iter->second.folder); } else if(m_Skin == 999) { model = "ikashop/ultimate/auction_deco/auction.gr2"; } #endif m_GraphicThing.Clear(); m_GraphicThing.ReserveModelThing(1); m_GraphicThing.ReserveModelInstance(1); m_GraphicThing.RegisterModelThing( 0, (CGraphicThing*)CResourceManager::Instance().GetResourcePointer(model.c_str())); m_GraphicThing.SetModelInstance(0, 0, 0); #ifdef EXTEND_IKASHOP_ULTIMATE if (!animation.empty()) { m_GraphicThing.RegisterMotionThing( 0, (CGraphicThing*)CResourceManager::Instance().GetResourcePointer(animation.c_str())); m_GraphicThing.SetMotion(0); } #endif m_GraphicThing.SetPosition(x, -y, z); m_GraphicThing.Show(); m_GraphicThing.Update(); m_GraphicThing.Transform(); m_GraphicThing.Deform(); m_TextHeight = m_GraphicThing.GetHeight() + 10; if (!IsSkin()) m_TextHeight -= 50; #ifdef EXTEND_IKASHOP_ULTIMATE auto _AttachEffect = [&](const std::string& script, const std::string& bone, const auto& position, const auto& rotation){ auto id = _FindEffectCRC(script); // searching bone index BoneIndex boneIndex = -1; if (!bone.empty()) if (!m_GraphicThing.FindBoneIndex(0, bone.c_str(), &boneIndex)) boneIndex = -1; // creating effect and registering bone and id EffectID effectId = CEffectManager::Instance().GetEmptyIndex(); CEffectManager::Instance().CreateEffectInstance(effectId, id); auto& attachedEffect = m_AttachedEffect.emplace_back(); attachedEffect.id = effectId; attachedEffect.bone = boneIndex; attachedEffect.position = position; attachedEffect.rotation = rotation; }; // finding effect file & bone name if (iter != s_SkinMap.end()) { for(auto& effect : iter->second.effects) _AttachEffect(effect.script, effect.bone, effect.position, effect.rotation); } else if(m_Skin == 999) { static const D3DXVECTOR3 position{0.0f, 0.0f, -120.0f}; static const D3DXVECTOR3 rotation{}; _AttachEffect("d:/ymir work/effect/npc2/p_shop_05.mse", "", position, rotation); } #endif } void ShopInstance::Clear() { m_GraphicThing.Clear(); m_VirtualID = 0; m_Skin = 0; #ifdef EXTEND_IKASHOP_ULTIMATE for (auto& attach : m_AttachedEffect) CEffectManager::Instance().DestroyEffectInstance(attach.id); m_AttachedEffect.clear(); #endif } void ShopInstance::Render() { m_GraphicThing.Render(); } void ShopInstance::RenderText() { if (m_GraphicThing.isShow()) m_Text.Render(); } void ShopInstance::BlendRender() { m_GraphicThing.BlendRender(); } void ShopInstance::Update() { m_GraphicThing.Deform(); m_GraphicThing.Update(); #ifdef EXTEND_IKASHOP_ULTIMATE // updating effects auto& effectManager = CEffectManager::Instance(); auto& wolrdMatrix = m_GraphicThing.GetWorldMatrix(); for (auto& attachedEffect : m_AttachedEffect) { effectManager.SelectEffectInstance(attachedEffect.id); static D3DXMATRIX resultMatrix{}; D3DXMatrixIdentity(&resultMatrix); // moving to bone matrix if (attachedEffect.bone != -1) { D3DXMATRIX* boneMatrixPtr; if (m_GraphicThing.GetBoneMatrix(0, attachedEffect.bone, &boneMatrixPtr)) resultMatrix *= *boneMatrixPtr; } // moving to worldMatrix resultMatrix *= wolrdMatrix; // moving to attach position resultMatrix._41 += attachedEffect.position.x; resultMatrix._42 += attachedEffect.position.y; resultMatrix._43 += attachedEffect.position.z; // rotating to attach rotation auto& rotation = attachedEffect.rotation; if (rotation.x != 0.0f || rotation.y != 0.0f || rotation.z != 0.0f) { static D3DXMATRIX rotationMatrix{}; D3DXMatrixIdentity(&rotationMatrix); D3DXMatrixRotationYawPitchRoll(&rotationMatrix, rotation.x, rotation.y, rotation.z); resultMatrix *= rotationMatrix; } effectManager.SetEffectInstanceGlobalMatrix(resultMatrix); } #endif // update and render text tail CPythonGraphic& rpyGraphic = CPythonGraphic::Instance(); rpyGraphic.Identity(); float x = 0, y = 0, z = 0; const D3DXVECTOR3& c_rv3Position = m_GraphicThing.GetPosition(); rpyGraphic.ProjectPosition(c_rv3Position.x, c_rv3Position.y, c_rv3Position.z + m_TextHeight, &x, &y, &z); x = floorf(x); y = floorf(y); z *= CPythonGraphic::Instance().GetOrthoDepth() * -1.0f; z += 15.0f; m_Text.SetPosition(x, y, z); } bool ShopInstance::IsPickable() { return m_GraphicThing.isShow(); } bool ShopInstance::IsPicked() { float u, v, t; return m_GraphicThing.Intersect(&u, &v, &t); } #ifdef EXTEND_IKASHOP_ULTIMATE void ShopInstance::HideAllEffects() { if (m_shownEffects) { m_shownEffects = false; for (auto& effect : m_AttachedEffect) { CEffectManager::instance().SelectEffectInstance(effect.id); CEffectManager::instance().ApplyAlwaysHidden(); } } } void ShopInstance::ShowAllEffects() { if (!m_shownEffects) { m_shownEffects = true; for (auto& effect : m_AttachedEffect) { CEffectManager::instance().SelectEffectInstance(effect.id); CEffectManager::instance().ReleaseAlwaysHidden(); } } } #endif } #endif CPythonIkarusShop::CPythonIkarusShop() { m_businessBoard = nullptr; #ifdef ENABLE_IKASHOP_ENTITIES m_bIsShowName = false; #endif // checking folder DWORD attr = ::GetFileAttributesA("shop"); if (attr == INVALID_FILE_ATTRIBUTES || attr != FILE_ATTRIBUTE_DIRECTORY) ::CreateDirectoryA("shop", 0); LoadFilterHistory(); #ifdef EXTEND_IKASHOP_PRO LoadPriceHistory(); #endif } void CPythonIkarusShop::SetSearchShopBoard(PyObject* poWindow) { m_searchShopBoard = poWindow; } //starts void CPythonIkarusShop::SetBusinessBoard(PyObject* poWindow) { m_businessBoard = poWindow; } PyObject* CPythonIkarusShop::GetBusinessBoard() { return m_businessBoard; } #ifdef EXTEND_IKASHOP_ULTIMATE void CPythonIkarusShop::SetShopSkinBoard(PyObject* poWindow) { m_shopSkinBoard = poWindow; } PyObject* CPythonIkarusShop::GetShopSkinBoard() { return m_shopSkinBoard; } #endif bool CPythonIkarusShop::CallOnBusinessBoard(const std::string& func, PyObject* args) { if(args == nullptr) args = PyTuple_New(0); bool ret = false; if(m_businessBoard != nullptr) PyCallClassMemberFunc(m_businessBoard, func.c_str(), args, &ret); return ret; } bool CPythonIkarusShop::CallOnSearchShopBoard(const std::string& func, PyObject* args) { if (args == nullptr) args = PyTuple_New(0); bool ret = false; if (m_searchShopBoard != nullptr) PyCallClassMemberFunc(m_searchShopBoard, func.c_str(), args, &ret); return ret; } #ifdef EXTEND_IKASHOP_ULTIMATE void CPythonIkarusShop::OpenShop(const ikashop::TShopInfo& shop, const std::vector& vec) #else void CPythonIkarusShop::OpenShop(const ikashop::TShopInfo& shop, const std::vector& vec) #endif { // making shop dict PythonSafeDict shopDict; shopDict.set("id", shop.ownerid); shopDict.set("duration", shop.duration); shopDict.set("name", shop.name); #ifdef EXTEND_IKASHOP_ULTIMATE shopDict.set("lock", shop.lock_index); shopDict.set("items", ExtractPythonShopItemViewList(vec)); #else shopDict.set("items", ExtractPythonShopItemList(vec)); #endif CallOnSearchShopBoard("OpenShopGuest", Py_BuildValue("(O)", shopDict.weakRef())); } #ifdef EXTEND_IKASHOP_ULTIMATE void CPythonIkarusShop::OpenShopOwner(const ikashop::TShopInfo& shop, const std::vector& vec) #else void CPythonIkarusShop::OpenShopOwner(const ikashop::TShopInfo& shop, const std::vector& vec) #endif { // making shop dict PythonSafeDict shopDict; shopDict.set("duration", shop.duration); #ifdef EXTEND_IKASHOP_ULTIMATE shopDict.set("lock", shop.lock_index); shopDict.set("items", ExtractPythonShopItemViewList(vec)); shopDict.set("decoration", shop.decoration); shopDict.set("decoration_time", shop.decoration_time); #else shopDict.set("items", ExtractPythonShopItemList(vec)); #endif CallOnBusinessBoard("OpenShopOwner", Py_BuildValue("(O)", shopDict.weakRef())); } void CPythonIkarusShop::OpenShopOwnerNoShop() { CallOnBusinessBoard("OpenShopOwnerEmpty" ); } void CPythonIkarusShop::ShopClose() { CallOnBusinessBoard("ShopClose" ); } void CPythonIkarusShop::ShopExpiredGuesting(DWORD ownerid) { CallOnSearchShopBoard("ShopExpiredGuesting", Py_BuildValue("(i)", ownerid)); } void CPythonIkarusShop::ShopRemoveItem(bool owner, DWORD itemid) { if(owner) CallOnBusinessBoard("ShopOwnerRemoveItem", Py_BuildValue("(i)", itemid)); else CallOnSearchShopBoard("ShopGuestRemoveItem", Py_BuildValue("(i)", itemid)); } void CPythonIkarusShop::ShopGuestEditItem(DWORD itemid, const ikashop::TPriceInfo& price) { ikashop::python::PythonSafeDict dict; dict.set("price", price.yang); #ifdef ENABLE_CHEQUE_SYSTEM dict.set("cheque", price.cheque); #endif CallOnSearchShopBoard("ShopGuestEditItem", Py_BuildValue("(iO)", itemid, dict.weakRef())); } void CPythonIkarusShop::ShopOwnerEditItem(DWORD itemid, const ikashop::TPriceInfo& price) { ikashop::python::PythonSafeDict dict; dict.set("price", price.yang); #ifdef ENABLE_CHEQUE_SYSTEM dict.set("cheque", price.cheque); #endif CallOnBusinessBoard("ShopOwnerEditItem", Py_BuildValue("(iO)", itemid, dict.weakRef())); } void CPythonIkarusShop::ShopFilterResult(const std::vector& vec) { static auto extractOne = [](const ikashop::TSearchResultInfo& data){ #ifdef EXTEND_IKASHOP_ULTIMATE auto dict = ExtractPythonDictShopItemView(data); #else auto dict = ExtractPythonDictShopItem(data); #endif dict.set("is_auction", data.auction); dict.set("seller_name", data.seller_name); dict.set("duration", data.duration); return dict; }; auto itemList = ExtractPythonListFromContainer(vec, extractOne); CallOnSearchShopBoard("SetSearchResultItems", Py_BuildValue("(O)", itemList.weakRef())); } void CPythonIkarusShop::OfferListReceived(const std::vector& offers) { static auto extractOffer = [](auto&& offer){ auto item = ExtractPythonDictShopItem(offer.item); #ifdef EXTEND_IKASHOP_ULTIMATE item.set("priceavg", offer.priceavg); #endif PythonSafeDict offerDict; offerDict.set("name", offer.shopname); offerDict.set("id", offer.offerid); offerDict.set("buyer_name", offer.buyername); offerDict.set("ownerid", offer.ownerid); offerDict.set("itemid", offer.itemid); offerDict.set("price", offer.price.yang); offerDict.set("notified", offer.notified); offerDict.set("accepted", offer.accepted); offerDict.set("item", item); offerDict.set("incoming", offer.incoming); offerDict.set("datetime", offer.datetime); return offerDict; }; auto offerList = ExtractPythonListFromContainer(offers, extractOffer); CallOnBusinessBoard("SetOffers", Py_BuildValue("(O)", offerList.weakRef())); } void CPythonIkarusShop::SafeboxRefresh(const ikashop::TValutesInfo& valute, const std::vector& items) { auto itemList = ExtractPythonPlayerItemList(items); CallOnBusinessBoard("SetupSafebox", Py_BuildValue("(KO)", valute.yang, itemList.weakRef())); } void CPythonIkarusShop::SafeboxRemoveItem(DWORD itemid) { CallOnBusinessBoard("SafeboxRemoveItem", Py_BuildValue("(i)", itemid)); } void CPythonIkarusShop::SafeboxAddItem(const ikashop::TShopPlayerItem& item) { auto itemDict = ikashop::python::ExtractPythonDictPlayerItem(item); CallOnBusinessBoard("SafeboxAddItem", Py_BuildValue("(O)", itemDict.weakRef())); } void CPythonIkarusShop::AuctionList(const std::vector& auctions) { static auto extractAuctionListElement = [](auto&& element){ auto auctionDict = ExtractPythonDictShopItem(element.auction); #ifdef EXTEND_IKASHOP_ULTIMATE auctionDict.set("priceavg", element.priceavg); #endif auctionDict.set("seller_name", element.auction.ownername); auctionDict.set("duration", element.auction.duration); auctionDict.set("price", element.actual_best.yang); auctionDict.set("is_auction", true); return auctionDict; }; auto auctionList = ExtractPythonListFromContainer(auctions, extractAuctionListElement); CallOnSearchShopBoard("SetAuctionList", Py_BuildValue("(O)", auctionList.weakRef())); } #ifdef EXTEND_IKASHOP_ULTIMATE void CPythonIkarusShop::MyAuctionOpen(const ikashop::TAuctionInfo& auction, const std::vector& offers, long long priceavg) #else void CPythonIkarusShop::MyAuctionOpen(const ikashop::TAuctionInfo& auction, const std::vector& offers) #endif { static auto extractAutionOffer = [](auto&& offer){ PythonSafeDict offerDict; offerDict.set("buyerid", offer.buyerid); offerDict.set("buyername", offer.buyername); offerDict.set("offerid", offer.ownerid); offerDict.set("price", offer.price.yang); offerDict.set("datetime", offer.datetime); return offerDict; }; auto auctionDict = ExtractPythonDictShopItem(auction); auctionDict.set("duration", auction.duration); auctionDict.set("offers", ExtractPythonListFromContainer(offers, extractAutionOffer)); #ifdef EXTEND_IKASHOP_ULTIMATE auctionDict.set("priceavg", priceavg); #endif CallOnBusinessBoard("SetupAcutionOwner", Py_BuildValue("(O)", auctionDict.weakRef())); } #ifdef EXTEND_IKASHOP_ULTIMATE void CPythonIkarusShop::AuctionOpen(const ikashop::TAuctionInfo& auction, const std::vector& offers, long long priceavg) #else void CPythonIkarusShop::AuctionOpen(const ikashop::TAuctionInfo& auction, const std::vector& offers) #endif { static auto extractAutionOffer = [](auto&& offer) { PythonSafeDict offerDict; offerDict.set("buyerid", offer.buyerid); offerDict.set("buyername", offer.buyername); offerDict.set("offerid", offer.ownerid); offerDict.set("price", offer.price.yang); offerDict.set("datetime", offer.datetime); return offerDict; }; auto auctionDict = ExtractPythonDictShopItem(auction); auctionDict.set("ownername", auction.ownername); auctionDict.set("duration", auction.duration); auctionDict.set("offers", ExtractPythonListFromContainer(offers, extractAutionOffer)); #ifdef EXTEND_IKASHOP_ULTIMATE auctionDict.set("priceavg", priceavg); #endif CallOnSearchShopBoard("OpenAuctionGuest", Py_BuildValue("(O)", auctionDict.weakRef())); } void CPythonIkarusShop::OpenMyAuctionNoAuction() { CallOnBusinessBoard("OpenCreateAuctionQuestion"); } //filter caching methods void CPythonIkarusShop::LoadFilterHistory() { // opening stream std::ifstream stream("shop/search_history.json", std::ios::in | std::ios::ate | std::ios::binary); if(stream.is_open() == false) return; // reading size auto fsize = stream.tellg(); // resetting reading point stream.seekg(0); // making string receiving file content std::string jsonString; jsonString.resize(fsize); // reading file content inside string stream.read(jsonString.data(), fsize); stream.close(); // making document rapidjson::Document jsonDoc; jsonDoc.Parse(jsonString.c_str()); // checking for parser errors if(jsonDoc.HasParseError()){ TraceError("PARSER ERROR PARSING SEARCH HISTORY FILE: %d", (int) jsonDoc.GetParseError()); return; } // checking list object if(jsonDoc.IsArray() == false){ TraceError("INVALID SEARCH HISTORY FILE: document.IsArray() == false"); return; } // reserving dimension m_filterHistory.clear(); m_filterHistory.reserve(jsonDoc.Size()); // iterating over array for(auto& member : jsonDoc.GetArray()) { auto& history = m_filterHistory.emplace_back(); // decoding info history.count = jsonHelper::getValue(member, "count"); // decoding datetime history.datetime = jsonHelper::getValue(member, "datetime"); // decoding filter name auto name = jsonHelper::getValue(member, "item_name"); snprintf(history.name, sizeof(history.name), "%s", name.c_str()); // decoding filter history.type = jsonHelper::getValue(member, "type"); history.subtype = jsonHelper::getValue(member, "subtype"); history.levelstart = jsonHelper::getValue(member, "level_start"); history.levelend = jsonHelper::getValue(member, "level_end"); history.pricestart.yang = jsonHelper::getValue(member, "price_start"); history.pricend.yang = jsonHelper::getValue(member, "price_end"); history.sashGrade = jsonHelper::getValue(member, "sash"); history.alchemyGrade = jsonHelper::getValue(member, "alchemy"); for(int i=0; i < ITEM_ATTRIBUTE_SLOT_NORM_NUM; i++){ auto& attr = history.attrs[i]; attr.bType = jsonHelper::getValue(member, fmt::format("attrtype{}", i)); attr.sValue = jsonHelper::getValue(member, fmt::format("attrvalue{}", i)); } } } void CPythonIkarusShop::SaveFilterHistory() { // creating document rapidjson::Document doc; doc.SetArray(); // reserving array size doc.GetArray().Reserve(m_filterHistory.size(), doc.GetAllocator()); // populating array for(auto& history : m_filterHistory) { rapidjson::Value member; member.SetObject(); // encoding info jsonHelper::insertValue(member, "count", static_cast(history.count), doc.GetAllocator()); // encoding datetime jsonHelper::insertValue(member, "datetime", static_cast(history.datetime), doc.GetAllocator()); // encoding filter jsonHelper::insertValue(member, "item_name", std::string(history.name), doc.GetAllocator()); jsonHelper::insertValue(member, "type", static_cast(history.type), doc.GetAllocator()); jsonHelper::insertValue(member, "subtype", static_cast(history.subtype), doc.GetAllocator()); jsonHelper::insertValue(member, "level_start", static_cast(history.levelstart), doc.GetAllocator()); jsonHelper::insertValue(member, "level_end", static_cast(history.levelend), doc.GetAllocator()); jsonHelper::insertValue(member, "price_start", static_cast(history.pricestart.yang), doc.GetAllocator()); jsonHelper::insertValue(member, "price_end", static_cast(history.pricend.yang), doc.GetAllocator()); jsonHelper::insertValue(member, "alchemy", static_cast(history.alchemyGrade), doc.GetAllocator()); jsonHelper::insertValue(member, "sash", static_cast(history.sashGrade), doc.GetAllocator()); for (int i =0; i < ITEM_ATTRIBUTE_SLOT_NORM_NUM; i++){ auto& attr = history.attrs[i]; jsonHelper::insertValue(member, fmt::format("attrtype{}", i), static_cast(attr.bType), doc.GetAllocator()); jsonHelper::insertValue(member, fmt::format("attrvalue{}", i), static_cast(attr.sValue), doc.GetAllocator()); } // pushing element inside the array doc.PushBack(member, doc.GetAllocator()); } // making json string rapidjson::StringBuffer buffer; buffer.Clear(); rapidjson::Writer StringWriter(buffer); doc.Accept(StringWriter); // opening stream std::ofstream stream("shop/search_history.json", std::ios::out | std::ios::binary); if (!stream.is_open()){ TraceError("CANNOT SAVE SEARCH HISTORY FILE!"); return; } // completing stream data stream.write(buffer.GetString(), buffer.GetSize()); stream.close(); } void CPythonIkarusShop::AddNewFilterToHistory(TFilterHistoryElement& element) { m_filterHistory.emplace_back(element); while (m_filterHistory.size() > ikashop::OFFLINESHOP_MAX_FILTER_HISTORY_SIZE) PopOldestFilterHistoryElement(); SaveFilterHistory(); } void CPythonIkarusShop::PopOldestFilterHistoryElement() { if(!m_filterHistory.empty()) m_filterHistory.erase(std::min_element(m_filterHistory.begin(), m_filterHistory.end())); } #ifdef EXTEND_IKASHOP_PRO void CPythonIkarusShop::LoadPriceHistory() { static auto loadFileIntoMap = [](const std::string& filename, auto& map){ // opening stream std::ifstream stream(filename, std::ios::in | std::ios::ate | std::ios::binary); if (stream.is_open() == false) return; // reading size auto fsize = stream.tellg(); // resetting reading point stream.seekg(0); // making string receiving file content std::string jsonString; jsonString.resize(fsize); // reading file content inside string stream.read(jsonString.data(), fsize); stream.close(); // making document rapidjson::Document jsonDoc; jsonDoc.Parse(jsonString.c_str()); // checking for parser errors if (jsonDoc.HasParseError()) { TraceError("PARSER ERROR PARSING PRICE HISTORY FILE: %d", (int)jsonDoc.GetParseError()); return; } // checking list object if (jsonDoc.IsArray() == false) { TraceError("INVALID PRICE HISTORY FILE: document.IsArray() == false"); return; } // reserving dimension map.clear(); // getting current timestamp to check expiration const auto currentTime = std::time(nullptr); // iterating over array for (auto& member : jsonDoc.GetArray()) { auto key = static_cast(jsonHelper::getValue(member, "key")); auto expiration = jsonHelper::getValue(member, "expiration"); auto price = jsonHelper::getValue(member, "price"); auto count = jsonHelper::getValue(member, "count"); #ifdef ENABLE_CHEQUE_SYSTEM auto cheque = jsonHelper::getValue(member, "cheque"); #endif // checking expiration if(expiration < currentTime) continue; auto& registerPrice = map[key]; registerPrice.expiration = expiration; registerPrice.price = price; registerPrice.count = static_cast(std::max(1, count)); #ifdef ENABLE_CHEQUE_SYSTEM registerPrice.cheque = cheque; #endif } }; loadFileIntoMap("shop/price_history_vnum.json", m_priceByVnum); loadFileIntoMap("shop/price_history_hash.json", m_priceByHash); } void CPythonIkarusShop::SavePriceHistory() { static auto saveMapToFile = [](const std::string& file, const auto& map){ // creating document rapidjson::Document doc; doc.SetArray(); // reserving array size doc.GetArray().Reserve(map.size(), doc.GetAllocator()); // populating array for (auto& [key, element] : map) { rapidjson::Value member; member.SetObject(); // encoding info jsonHelper::insertValue(member, "key", static_cast(key), doc.GetAllocator()); jsonHelper::insertValue(member, "expiration", element.expiration, doc.GetAllocator()); jsonHelper::insertValue(member, "price", element.price, doc.GetAllocator()); jsonHelper::insertValue(member, "count", static_cast(element.count), doc.GetAllocator()); #ifdef ENABLE_CHEQUE_SYSTEM jsonHelper::insertValue(member, "cheque", element.cheque, doc.GetAllocator()); #endif // pushing element inside the array doc.PushBack(member, doc.GetAllocator()); } // making json string rapidjson::StringBuffer buffer; buffer.Clear(); rapidjson::Writer StringWriter(buffer); doc.Accept(StringWriter); // opening stream std::ofstream stream(file, std::ios::out | std::ios::binary); if (!stream.is_open()) { TraceError("CANNOT SAVE PRICE HISTORY FILE!"); return; } // completing stream data stream.write(buffer.GetString(), buffer.GetSize()); stream.close(); }; saveMapToFile("shop/price_history_vnum.json", m_priceByVnum); saveMapToFile("shop/price_history_hash.json", m_priceByHash); } void CPythonIkarusShop::RegisterPriceHistory(DWORD vnum, DWORD count, DWORD hash, const ikashop::TPriceInfo& price) { // calculating info const auto expiration = static_cast(std::time(nullptr)) + PRICE_HISTORY_EXPIRATION; const auto total = price.yang; #ifdef ENABLE_CHEQUE_SYSTEM const auto cheque = price.cheque; #endif // registering by vnum m_priceByVnum[vnum] = {expiration, total, count #ifdef ENABLE_CHEQUE_SYSTEM , cheque #endif }; // registering by hash if(hash != 0) m_priceByHash[hash] = {expiration, total, count #ifdef ENABLE_CHEQUE_SYSTEM , cheque #endif }; // moving data to file SavePriceHistory(); } std::optional CPythonIkarusShop::GetPriceHistory(DWORD vnum, DWORD hash, DWORD count) { // converting yang amount to cheque + yang static auto composePrice = [](auto price, auto registerCount, auto count #ifdef ENABLE_CHEQUE_SYSTEM , auto cheque #endif ) -> ikashop::TPriceInfo { // checking if count matches if(registerCount == count) return { price #ifdef ENABLE_CHEQUE_SYSTEM , cheque #endif }; // adjusting price using count auto total = price; #ifdef ENABLE_CHEQUE_SYSTEM total += static_cast(cheque) * YANG_PER_CHEQUE; #endif total *= count; total /= registerCount; #ifdef ENABLE_CHEQUE_SYSTEM return { total % YANG_PER_CHEQUE, static_cast(total / YANG_PER_CHEQUE)}; #endif return { total }; }; // searching by hash if(hash != 0) { auto iter = m_priceByHash.find(hash); if(iter != m_priceByHash.end()) return composePrice(iter->second.price, iter->second.count, count #ifdef ENABLE_CHEQUE_SYSTEM , iter->second.cheque #endif ); } // searching by vnum auto iter = m_priceByVnum.find(vnum); if(iter != m_priceByVnum.end()) return composePrice(iter->second.price, iter->second.count, count #ifdef ENABLE_CHEQUE_SYSTEM , iter->second.cheque #endif ); // not found return std::nullopt; } #endif PythonSafeList CPythonIkarusShop::GetFilterHistory() { static auto extractFilter = [](const TFilterHistoryElement& filter){ PythonGarbageCollector collector; PythonSafeList attrlist; for (auto& attr : filter.attrs) attrlist.append(collector.makeValue("(ii)", attr.bType, attr.sValue)); PythonSafeDict filterDict; filterDict.set("datetime", filter.datetime); filterDict.set("count", filter.count); filterDict.set("type", filter.type); filterDict.set("subtype", filter.subtype); filterDict.set("name", filter.name); filterDict.set("price_min", filter.pricestart.yang); filterDict.set("price_max", filter.pricend.yang); filterDict.set("level_min", filter.levelstart); filterDict.set("level_max", filter.levelend); filterDict.set("alchemy", filter.alchemyGrade); filterDict.set("sash", filter.sashGrade); filterDict.set("level_max", filter.levelend); filterDict.set("attrs", attrlist); return filterDict; }; return ExtractPythonListFromContainer(m_filterHistory, extractFilter); } std::vector CPythonIkarusShop::GetItemNames() { // getting item map std::map nameMap; CItemManager::instance().GetItemsNameMap(nameMap); // making vector std::vector vec; vec.reserve(nameMap.size()); for(auto& [vnum, name] : nameMap) vec.emplace_back(name); return vec; } void CPythonIkarusShop::ShopBuilding_AddItem(int win, int slot) { CallOnBusinessBoard("InsertItemInSlot" , Py_BuildValue("(ii)", win, slot)); } void CPythonIkarusShop::AuctionBuilding_AddItem(int win, int slot) { CallOnBusinessBoard("AuctionInsertItemInSlot" , Py_BuildValue("(ii)", win, slot)); } #ifdef EXTEND_IKASHOP_PRO void CPythonIkarusShop::RefreshBoardCounters(int safebox, int auction, int offers, int notifications) #else void CPythonIkarusShop::RefreshBoardCounters(int safebox, int auction, int offers) #endif { CallOnBusinessBoard("SetSafeboxCounter", Py_BuildValue("(i)", safebox)); CallOnBusinessBoard("SetAuctionCounter", Py_BuildValue("(i)", auction)); CallOnBusinessBoard("SetOffersCounter", Py_BuildValue("(i)", offers)); #ifdef EXTEND_IKASHOP_PRO CallOnBusinessBoard("SetNotificationCounter", Py_BuildValue("(i)", notifications)); #endif } #ifdef EXTEND_IKASHOP_PRO void CPythonIkarusShop::RegisterNotification(const ikashop::TNotificationInfo& info) { for(auto it = m_notifications.begin(); it != m_notifications.end(); it++) { if(it->datetime < info.datetime) { m_notifications.emplace(it, info); return; } } m_notifications.emplace_back(info); } void CPythonIkarusShop::LoadNotifications() { m_notifications.clear(); // opening stream auto filename = fmt::format("shop/notifications_{}.json", CPythonPlayer::instance().GetName()); std::ifstream stream(filename, std::ios::in | std::ios::ate | std::ios::binary); if (stream.is_open() == false) return; // reading size auto fsize = stream.tellg(); // resetting reading point stream.seekg(0); // making string receiving file content std::string jsonString; jsonString.resize(fsize); // reading file content inside string stream.read(jsonString.data(), fsize); stream.close(); // making document rapidjson::Document jsonDoc; jsonDoc.Parse(jsonString.c_str()); // checking for parser errors if (jsonDoc.HasParseError()) { TraceError("PARSER ERROR PARSING NOTIFICATION FILE: %d", (int)jsonDoc.GetParseError()); return; } // checking list object if (jsonDoc.IsArray() == false) { TraceError("INVALID NOTIFICATION FILE: document.IsArray() == false"); return; } // getting current timestamp to check expiration const auto currentTime = std::time(nullptr); // iterating over array for (auto& member : jsonDoc.GetArray()) { ikashop::TNotificationInfo info{}; info.seenflag = true; info.type = static_cast(jsonHelper::getValue(member, "type")); info.what = static_cast(jsonHelper::getValue(member, "what")); info.datetime = jsonHelper::getValue(member, "datetime"); auto who = jsonHelper::getValue(member, "who"); std::strncpy(info.who, who.c_str(), sizeof(info.who)); auto format = jsonHelper::getValue(member, "format"); std::strncpy(info.format, format.c_str(), sizeof(info.format)); // checking expiration if (currentTime > info.datetime && currentTime - info.datetime > NOTIFICATION_EXPIRATION) continue; m_notifications.emplace_back(info); } } void CPythonIkarusShop::SaveNotifications() { // creating document rapidjson::Document doc; doc.SetArray(); // reserving array size doc.GetArray().Reserve(m_notifications.size(), doc.GetAllocator()); // populating array for (auto& info : m_notifications) { rapidjson::Value member; member.SetObject(); // encoding info jsonHelper::insertValue(member, "type", static_cast(info.type), doc.GetAllocator()); jsonHelper::insertValue(member, "who", info.who, doc.GetAllocator()); jsonHelper::insertValue(member, "what", static_cast(info.what), doc.GetAllocator()); jsonHelper::insertValue(member, "format", info.format, doc.GetAllocator()); jsonHelper::insertValue(member, "datetime", static_cast(info.datetime), doc.GetAllocator()); // pushing element inside the array doc.PushBack(member, doc.GetAllocator()); } // making json string rapidjson::StringBuffer buffer; buffer.Clear(); rapidjson::Writer StringWriter(buffer); doc.Accept(StringWriter); // opening stream auto filename = fmt::format("shop/notifications_{}.json", CPythonPlayer::instance().GetName()); std::ofstream stream(filename, std::ios::out | std::ios::binary); if (!stream.is_open()) { TraceError("CANNOT SAVE NOTIFICATION FILE!"); return; } // completing stream data stream.write(buffer.GetString(), buffer.GetSize()); stream.close(); } const std::deque& CPythonIkarusShop::GetNotifications() { return m_notifications; } void CPythonIkarusShop::SetNotificationList(const std::vector& notifications) { auto list = ExtractPythonListFromContainer(notifications, ExtractPythonDictNotification); CallOnBusinessBoard("SetNotifications", Py_BuildValue("(O)", list.weakRef())); } #endif #ifdef EXTEND_IKASHOP_ULTIMATE void CPythonIkarusShop::PriceAverageResponse(long long average) { CallOnBusinessBoard("SetPriceAverage", Py_BuildValue("(K)", average)); } #endif #ifdef ENABLE_IKASHOP_ENTITIES std::string GetEntityNameFormat(const char* name #ifdef EXTEND_IKASHOP_ULTIMATE , bool isAuction #endif ) { // getting localeinfo module auto pyModule = PythonReference::steal(PyImport_ImportModule("localeInfo")); if (!pyModule) return name; // getting attr name #ifdef EXTEND_IKASHOP_ULTIMATE const std::string attr = isAuction ? "IKASHOP_AUCTION_GUEST_NAME_FORMAT" : "IKASHOP_SHOP_NAME_FORMAT"; #else const std::string attr = "IKASHOP_SHOP_NAME_FORMAT"; #endif // checking module has attr if(!PyObject_HasAttrString(pyModule, attr.c_str())) return name; // getting module attribute auto pyAttr = PythonReference::steal(PyObject_GetAttrString(pyModule, attr.c_str())); if(!pyAttr) return name; // checking attribute is string if(!PyString_Check(pyAttr)) return name; // getting string from attr const auto* format = PyString_AsString(pyAttr); return fmt::format(fmt::runtime(format), name); } void CPythonIkarusShop::InsertEntity(DWORD vid, int type, const char* name, long x, long y, long z) { auto namestr = GetEntityNameFormat(name #ifdef EXTEND_IKASHOP_ULTIMATE , type == 999 #endif ); auto& shop = m_shopInstances.emplace_back(std::make_unique(type)); shop->SetVID(vid); shop->SetShopType(type); shop->SetName(namestr); CPythonBackground&rkBgMgr=CPythonBackground::Instance(); rkBgMgr.GlobalPositionToLocalPosition(x, y); z = CPythonBackground::Instance().GetHeight(x, y) + 10.0f; shop->Show(x,y,z); } void CPythonIkarusShop::RemoveEntity(DWORD vid) { for (auto it = m_shopInstances.begin(); it != m_shopInstances.end(); it++) { ikashop::ShopInstance& shop = *(*it); if (shop.GetVID() == vid) { shop.Clear(); m_shopInstances.erase(it); return; } } } void CPythonIkarusShop::RenderEntities() { #ifdef EXTEND_IKASHOP_PRO auto mainInstance = CPythonCharacterManager::instance().GetMainInstancePtr(); #endif CPythonGraphic::Instance().SetDiffuseOperation(); for (auto & iter : m_shopInstances) { #ifdef EXTEND_IKASHOP_PRO if (!mainInstance || mainInstance->GetDistance(iter->GetThingInstancePtr()->GetPosition()) > CPythonSystem::instance().GetShopRangeView()) { # ifdef EXTEND_IKASHOP_ULTIMATE iter->HideAllEffects(); # endif continue; } #endif #ifdef EXTEND_IKASHOP_ULTIMATE iter->ShowAllEffects(); #endif iter->Render(); iter->BlendRender(); } if (CPythonSystem::Instance().IsShowSalesText()) { auto& graphic = CPythonGraphic::Instance(); graphic.PushState(); graphic.SetInterfaceRenderState(); for (auto& instance : m_shopInstances){ #ifdef EXTEND_IKASHOP_PRO if (!mainInstance || mainInstance->GetDistance(instance->GetThingInstancePtr()->GetPosition()) > CPythonSystem::instance().GetShopRangeView()) continue; #endif instance->RenderText(); } graphic.PopState(); graphic.SetGameRenderState(); } } void CPythonIkarusShop::UpdateEntities() { for (auto & iter : m_shopInstances) iter->Update(); } bool CPythonIkarusShop::GetShowNameFlag() { return m_bIsShowName; } void CPythonIkarusShop::SetShowNameFlag(bool flag) { m_bIsShowName = flag; } void CPythonIkarusShop::DeleteEntities() { for (auto& iter : m_shopInstances) iter->Clear(); m_shopInstances.clear(); } bool CPythonIkarusShop::CheckPickedShopEntity(DWORD* ret) { for (auto& instance : m_shopInstances) { if (instance->IsPickable()) { if (instance->IsPicked()) { if (ret) *ret = instance->GetVID(); return true; } } } return false; } #endif void CPythonIkarusShop::DeleteSearchResult(DWORD itemid) { CallOnSearchShopBoard("DeleteSearchResultItem", Py_BuildValue("(i)", itemid)); } void CPythonIkarusShop::PopupMessage(const std::string& message) { CallOnBusinessBoard("ServerPopupMessage", Py_BuildValue("(s)", message.c_str())); } CPythonIkarusShop::~CPythonIkarusShop() { } PyObject* ikashopSendShopCreate(PyObject* poSelf, PyObject* poArgs) { CPythonNetworkStream::instance().SendIkarusShopCreateShop(); return Py_BuildNone(); } PyObject* ikashopSendForceCloseShop(PyObject* poSelf , PyObject* poArgs) { CPythonNetworkStream::instance().SendIkarusShopForceCloseShop(); return Py_BuildNone(); } PyObject* ikashopSendOpenShop(PyObject* poSelf , PyObject* poArgs) { uint32_t id = 0; if(!PyTuple_GetUnsignedInteger(poArgs, 0, &id)) return Py_BadArgument(); CPythonNetworkStream::Instance().SendIkarusShopOpenShop(id); return Py_BuildNone(); } PyObject* ikashopSendOpenShopOwner(PyObject* poSelf , PyObject* poArgs) { CPythonNetworkStream::Instance().SendIkarusShopOpenShopOwner(); return Py_BuildNone(); } PyObject* ikashopSendBuyItem(PyObject* poSelf, PyObject* poArgs) { uint32_t ownerid = 0; if(!PyTuple_GetUnsignedInteger(poArgs, 0, &ownerid)) return Py_BadArgument(); uint32_t itemid = 0; if (!PyTuple_GetUnsignedInteger(poArgs, 1, &itemid)) return Py_BadArgument(); long long seenprice = 0; if (!PyTuple_GetLongLong(poArgs, 2, &seenprice)) return Py_BadArgument(); CPythonNetworkStream::instance().SendIkarusShopBuyItem(ownerid, itemid, false, seenprice); return Py_BuildNone(); } PyObject* ikashopSendAddItem(PyObject* poSelf , PyObject* poArgs) { BYTE window = 0; if(!PyTuple_GetInteger(poArgs, 0, &window)) return Py_BadArgument(); WORD slot = 0; if(!PyTuple_GetInteger(poArgs, 1, &slot)) return Py_BadArgument(); int destpos = 0; if (!PyTuple_GetInteger(poArgs, 2, &destpos)) return Py_BadArgument(); long long yang=0; if(!PyTuple_GetLongLong(poArgs, 3, &yang)) return Py_BadArgument(); #ifdef ENABLE_CHEQUE_SYSTEM int cheque = 0; if(!PyTuple_GetInteger(poArgs, 4, &cheque)) return Py_BadArgument(); #endif ikashop::TShopItemInfo info; info.pos = {window, slot}; info.price.yang = yang; info.destpos = destpos; #ifdef ENABLE_CHEQUE_SYSTEM info.price.cheque = cheque; #endif CPythonNetworkStream::instance().SendIkarusShopAddItem(info); return Py_BuildNone(); } PyObject* ikashopSendRemoveItem(PyObject* poSelf , PyObject* poArgs) { uint32_t itemid = 0; if(!PyTuple_GetUnsignedInteger(poArgs, 0, &itemid)) return Py_BadArgument(); CPythonNetworkStream::instance().SendIkarusShopRemoveItem(itemid); return Py_BuildNone(); } PyObject* ikashopSendEditItem(PyObject* poSelf , PyObject* poArgs) { uint32_t itemid=0; if(!PyTuple_GetUnsignedInteger(poArgs, 0, &itemid)) return Py_BadArgument(); long long yang=0; if(!PyTuple_GetLongLong(poArgs, 1, &yang)) return Py_BadArgument(); #ifdef ENABLE_CHEQUE_SYSTEM int cheque = 0; if(!PyTuple_GetInteger(poArgs, 2, &cheque)) return Py_BadArgument(); #endif ikashop::TPriceInfo price; price.yang = yang; #ifdef ENABLE_CHEQUE_SYSTEM price.cheque = cheque; #endif CPythonNetworkStream::instance().SendOfflineShopEditItem(itemid, price); return Py_BuildNone(); } PyObject* ikashopSendFilterRequest(PyObject* poSelf , PyObject* poArgs) { char* name = nullptr; ikashop::TFilterInfo info; if(!PyTuple_GetString(poArgs, 0, &name)) return Py_BadArgument(); if(!PyTuple_GetInteger(poArgs, 1, &info.type)) return Py_BadArgument(); if(!PyTuple_GetInteger(poArgs, 2, &info.subtype)) return Py_BadArgument(); PyObject* prices = nullptr; if(!PyTuple_GetObject(poArgs, 3, &prices)) return Py_BadArgument(); PyObject* levels = nullptr; if(!PyTuple_GetObject(poArgs, 4, &levels)) return Py_BadArgument(); PyObject* attrs=nullptr; if(!PyTuple_GetObject(poArgs, 5, &attrs)) return Py_BadArgument(); PyObject* specials=nullptr; if(!PyTuple_GetObject(poArgs, 6, &specials)) return Py_BadArgument(); // extracting prices if(!PyTuple_GetLongLong(prices, 0, &info.pricestart.yang)) return Py_BadArgument(); if(!PyTuple_GetLongLong(prices, 1, &info.pricend.yang)) return Py_BadArgument(); // extracting levels if(!PyTuple_GetInteger(levels, 0, &info.levelstart)) return Py_BadArgument(); if(!PyTuple_GetInteger(levels, 1, &info.levelend)) return Py_BadArgument(); // extracting attrs for (int i = 0; i < ITEM_ATTRIBUTE_SLOT_NORM_NUM; i++) { PyObject* attribute = nullptr; if(!PyTuple_GetObject(attrs, i, &attribute)) return Py_BadArgument(); if(!PyTuple_GetInteger(attribute, 0, &info.attrs[i].bType)) return Py_BadArgument(); int value = 0; if(!PyTuple_GetInteger(attribute, 1, &value)) return Py_BadArgument(); info.attrs[i].sValue = static_cast(value); } // extracting specials if (!PyTuple_GetInteger(specials, 0, &info.sashGrade)) return Py_BadArgument(); if (!PyTuple_GetInteger(specials, 1, &info.alchemyGrade)) return Py_BadArgument(); // copying name strncpy(info.name, name, sizeof(info.name)); CPythonNetworkStream::instance().SendIkarusShopFilterRequest(info); return Py_BuildNone(); } PyObject* ikashopSendRandomSearchFillRequest(PyObject* poSelf, PyObject* poArgs) { CPythonNetworkStream::instance().SendIkarusShopSearchFillRequest(); return Py_BuildNone(); } PyObject* ikashopSendOfferCreate(PyObject* poSelf , PyObject* poArgs) { ikashop::TOfferInfo offer; if(!PyTuple_GetUnsignedLong(poArgs, 0, &offer.ownerid)) return Py_BadArgument(); if (!PyTuple_GetUnsignedLong(poArgs, 1, &offer.itemid)) return Py_BadArgument(); if (!PyTuple_GetLongLong(poArgs, 2, &offer.price.yang)) return Py_BadArgument(); #ifdef ENABLE_CHEQUE_SYSTEM if(!PyTuple_GetInteger(poArgs, 3, &offer.price.cheque)) return Py_BadArgument(); #endif CPythonNetworkStream::instance().SendIkarusShopOfferCreate(offer); return Py_BuildNone(); } PyObject* ikashopSendOfferAccept(PyObject* poSelf , PyObject* poArgs) { DWORD offerid=0; if(!PyTuple_GetUnsignedLong(poArgs, 0, &offerid)) return Py_BadArgument(); CPythonNetworkStream::instance().SendIkarusShopOfferAccept(offerid); return Py_BuildNone(); } PyObject* ikashopSendOfferCancel(PyObject* poSelf , PyObject* poArgs) { DWORD offerid = 0; if (!PyTuple_GetUnsignedLong(poArgs, 0, &offerid)) return Py_BadArgument(); DWORD ownerid = 0; if (!PyTuple_GetUnsignedLong(poArgs, 1, &ownerid)) return Py_BadArgument(); CPythonNetworkStream::instance().SendIkarusShopOfferCancel(offerid, ownerid); return Py_BuildNone(); } PyObject* ikashopSendOfferListRequest(PyObject* poSelf , PyObject* poArgs) { CPythonNetworkStream::instance().SendIkarusShopOfferListRequest(); return Py_BuildNone(); } PyObject* ikashopSendSafeboxOpen(PyObject* poSelf , PyObject* poArgs) { CPythonNetworkStream::instance().SendIkarusShopSafeboxOpen(); return Py_BuildNone(); } PyObject* ikashopSendSafeboxGetItem(PyObject* poSelf , PyObject* poArgs) { DWORD itemid = 0; if (!PyTuple_GetUnsignedLong(poArgs, 0, &itemid)) return Py_BadArgument(); CPythonNetworkStream::instance().SendIkarusShopSafeboxGetItem(itemid); return Py_BuildNone(); } PyObject* ikashopSendSafeboxGetValutes(PyObject* poSelf , PyObject* poArgs) { CPythonNetworkStream::instance().SendIkarusShopSafeboxGetValutes(); return Py_BuildNone(); } PyObject* ikashopSendSafeboxClose(PyObject* poSelf , PyObject* poArgs) { CPythonNetworkStream::instance().SendIkarusShopSafeboxClose(); return Py_BuildNone(); } PyObject* ikashopSendOffersListClose(PyObject* poSelf, PyObject* poArgs) { CPythonNetworkStream::instance().SendIkarusOffersListClose(); return Py_BuildNone(); } PyObject* ikashopSendCloseMyShopBoard(PyObject* poSelf, PyObject* poArgs) { CPythonNetworkStream::instance().SendIkarusMyShopCloseBoard(); return Py_BuildNone(); } PyObject* ikashopSendCloseShopGuestBoard(PyObject* poSelf, PyObject* poArgs) { CPythonNetworkStream::instance().SendIkarusCloseShopGuestBoard(); return Py_BuildNone(); } PyObject* ikashopSendAuctionListRequest(PyObject* poSelf, PyObject* poArgs) { CPythonNetworkStream::instance().SendIkarusShopAuctionListRequest(); return Py_BuildNone(); } PyObject* ikashopSendAuctionOpenAuction(PyObject* poSelf, PyObject* poArgs) { DWORD ownerid = 0; if (!PyTuple_GetUnsignedLong(poArgs, 0, &ownerid)) return Py_BadArgument(); CPythonNetworkStream::instance().SendIkarusShopAuctionOpen(ownerid); return Py_BuildNone(); } PyObject* ikashopSendAuctionAddOffer(PyObject* poSelf, PyObject* poArgs) { DWORD ownerid = 0; if (!PyTuple_GetUnsignedLong(poArgs, 0, &ownerid)) return Py_BadArgument(); ikashop::TPriceInfo price; if(!PyTuple_GetLongLong(poArgs, 1, &price.yang)) return Py_BadArgument(); #ifdef ENABLE_CHEQUE_SYSTEM if(!PyTuple_GetInteger(poArgs, 2, &price.cheque)) return Py_BadArgument(); #endif CPythonNetworkStream::instance().SendIkarusShopAuctionAddOffer(ownerid, price); return Py_BuildNone(); } PyObject* ikashopSendAuctionExitFrom(PyObject* poSelf, PyObject* poArgs) { DWORD ownerid = 0; if (!PyTuple_GetUnsignedLong(poArgs, 0, &ownerid)) return Py_BadArgument(); CPythonNetworkStream::instance().SendIkarusShopAuctionExitFrom(ownerid); return Py_BuildNone(); } PyObject* ikashopSendAuctionCreate(PyObject* poSelf, PyObject* poArgs) { TItemPos pos; if(!PyTuple_GetInteger(poArgs, 0, &pos.window_type)) return Py_BadArgument(); if(!PyTuple_GetInteger(poArgs, 1, &pos.cell)) return Py_BadArgument(); ikashop::TPriceInfo price; if(!PyTuple_GetLongLong(poArgs, 2, &price.yang)) return Py_BadArgument(); CPythonNetworkStream::instance().SendIkarusShopAuctionCreate(pos, price); return Py_BuildNone(); } PyObject* ikashopSendMyAuctionOpen(PyObject* poSelf, PyObject* poArgs) { CPythonNetworkStream::instance().SendIkarusShopMyAuctionOpen(); return Py_BuildNone(); } PyObject* ikashopSendMyAuctionClose(PyObject* poSelf, PyObject* poArgs) { CPythonNetworkStream::instance().SendIkarusShopMyAuctionClose(); return Py_BuildNone(); } PyObject* ikashopSendMyAuctionCancel(PyObject* poSelf, PyObject* poArgs) { CPythonNetworkStream::instance().SendIkarusShopMyAuctionCancel(); return Py_BuildNone(); } PyObject* SendCloseMyShopBoard(PyObject* poSelf, PyObject* poArgs) { CPythonNetworkStream::instance().SendIkarusMyShopCloseBoard(); return Py_BuildNone(); } PyObject* ikashopGetFilterHistory(PyObject* poSelf , PyObject* poArgs) { auto list = CPythonIkarusShop::instance().GetFilterHistory(); return list.incRef(); } PyObject* ikashopRegisterFilterHistory(PyObject* poSelf , PyObject* poArgs) { CPythonIkarusShop::TFilterHistoryElement element; CPythonIkarusShop::NowDatetime(element.datetime); if(!PyTuple_GetUnsignedLong(poArgs, 0, &element.count)) return Py_BadArgument(); char* name=nullptr; if(!PyTuple_GetString(poArgs, 1, &name)) return Py_BadArgument(); strncpy(element.name, name, sizeof(element.name)); if(!PyTuple_GetInteger(poArgs, 2, &element.type)) return Py_BadArgument(); if(!PyTuple_GetInteger(poArgs, 3, &element.subtype)) return Py_BadArgument(); PyObject* prices = nullptr; if (!PyTuple_GetObject(poArgs, 4, &prices)) return Py_BadArgument(); PyObject* levels = nullptr; if (!PyTuple_GetObject(poArgs, 5, &levels)) return Py_BadArgument(); PyObject* attrs = nullptr; if (!PyTuple_GetObject(poArgs, 6, &attrs)) return Py_BadArgument(); PyObject* specials = nullptr; if (!PyTuple_GetObject(poArgs, 7, &specials)) return Py_BadArgument(); // extracting prices if(!PyTuple_GetLongLong(prices, 0, &element.pricestart.yang)) return Py_BadArgument(); if(!PyTuple_GetLongLong(prices, 1, &element.pricend.yang)) return Py_BadArgument(); // extracting levels if(!PyTuple_GetInteger(levels, 0, &element.levelstart)) return Py_BadArgument(); if(!PyTuple_GetInteger(levels, 1, &element.levelend)) return Py_BadArgument(); // extracting attributes for (int i = 0; i < ITEM_ATTRIBUTE_SLOT_NORM_NUM; i++) { PyObject* attribute = nullptr; if(!PyTuple_GetObject(attrs, i, &attribute)) return Py_BadArgument(); int value = 0; if(!PyTuple_GetInteger(attribute, 0, &element.attrs[i].bType)) return Py_BadArgument(); if(!PyTuple_GetInteger(attribute, 1, &value)) return Py_BadArgument(); element.attrs[i].sValue = static_cast(value); } // extracting specials if (!PyTuple_GetInteger(specials, 0, &element.sashGrade)) return Py_BadArgument(); if (!PyTuple_GetInteger(specials, 1, &element.alchemyGrade)) return Py_BadArgument(); CPythonIkarusShop::instance().AddNewFilterToHistory(element); return Py_BuildNone(); } PyObject* ikashopGetItemNames(PyObject* poSelf, PyObject* poArgs) { auto vec = CPythonIkarusShop::instance().GetItemNames(); // converting map to dict PythonSafeList list; for(auto& name : vec) list.append(name); return list.incRef(); } PyObject* ikashopSetBusinessBoard(PyObject* poSelf , PyObject* poArgs) { PyObject* board = nullptr; if(!PyTuple_GetObject(poArgs, 0, &board)) return Py_BadArgument(); if(board == Py_None) board = nullptr; CPythonIkarusShop::instance().SetBusinessBoard(board); return Py_BuildNone(); } PyObject* ikashopSetSearchShopBoard(PyObject* poSelf , PyObject* poArgs) { PyObject* board = nullptr; if (!PyTuple_GetObject(poArgs, 0, &board)) return Py_BadArgument(); if (board == Py_None) board = nullptr; CPythonIkarusShop::instance().SetSearchShopBoard(board); return Py_BuildNone(); } PyObject* ikashopGetBusinessBoard(PyObject* poSelf , PyObject* poArgs) { PyObject* poInterface = CPythonIkarusShop::instance().GetBusinessBoard(); if(!poInterface) return Py_BuildNone(); Py_IncRef(poInterface); return poInterface; } #ifdef EXTEND_IKASHOP_ULTIMATE PyObject* ikashopSetShopSkinBoard(PyObject* poSelf, PyObject* poArgs) { PyObject* board = nullptr; if (!PyTuple_GetObject(poArgs, 0, &board)) return Py_BadArgument(); if (board == Py_None) board = nullptr; CPythonIkarusShop::instance().SetShopSkinBoard(board); return Py_BuildNone(); } PyObject* ikashopGetShopSkinBoard(PyObject* poSelf, PyObject* poArgs) { PyObject* poInterface = CPythonIkarusShop::instance().GetShopSkinBoard(); if (!poInterface) return Py_BuildNone(); Py_IncRef(poInterface); return poInterface; } #endif PyObject* ikashopShopBuilding_AddItem(PyObject* poSelf, PyObject* poArgs) { int win = 0; if(!PyTuple_GetInteger(poArgs, 0, &win)) return Py_BadArgument(); int slot = 0; if(!PyTuple_GetInteger(poArgs, 1, &slot)) return Py_BadArgument(); CPythonIkarusShop::instance().ShopBuilding_AddItem(win, slot); return Py_BuildNone(); } PyObject* ikashopAuctionBuilding_AddItem(PyObject* poSelf, PyObject* poArgs) { int win = 0; if (!PyTuple_GetInteger(poArgs, 0, &win)) return Py_BadArgument(); int slot = 0; if (!PyTuple_GetInteger(poArgs, 1, &slot)) return Py_BadArgument(); CPythonIkarusShop::instance().AuctionBuilding_AddItem(win, slot); return Py_BuildNone(); } #ifdef ENABLE_IKASHOP_ENTITIES PyObject* ikashopHideShopNames(PyObject* poSelf, PyObject* poArgs) { CPythonIkarusShop::instance().SetShowNameFlag(false); return Py_BuildNone(); } PyObject* ikashopShowShopNames(PyObject* poSelf, PyObject* poArgs) { CPythonIkarusShop::instance().SetShowNameFlag(true); return Py_BuildNone(); } #ifdef EXTEND_IKASHOP_PRO PyObject* ikashopSendMoveShopEntity(PyObject* poSelf, PyObject* poArgs) { CPythonNetworkStream::instance().SendIkarusShopMoveShopEntity(); return Py_BuildNone(); } #endif #endif PyObject* ikashopGetFirstEmptyCell(PyObject* poSelf, PyObject* poArgs) { int size = 0; if (!PyTuple_GetInteger(poArgs, 0, &size)) return Py_BadArgument(); PyObject* items = nullptr; if (!PyTuple_GetObject(poArgs, 1, &items) || !PyList_Check(items)) return Py_BadArgument(); constexpr auto width = ikashop::OFFLINESHOP_GRID_WIDTH; constexpr auto height = ikashop::OFFLINESHOP_GRID_HEIGHT; #ifdef EXTEND_IKASHOP_ULTIMATE constexpr auto pageSize = ikashop::OFFLINESHOP_PAGE_SIZE; ikashop::CShopGrid grid[ikashop::OFFLINESHOP_PAGE_COUNT]{}; #else ikashop::CShopGrid grid{}; #endif for(int i=0; i < PyList_Size(items); i++) { auto info = PyList_GetItem(items, i); if(!PyTuple_Check(info) || PyTuple_Size(info) != 2) return Py_BadArgument(); DWORD vnum = 0; if(!PyTuple_GetUnsignedLong(info, 0, &vnum)) return Py_BadArgument(); int cell = 0; if(!PyTuple_GetInteger(info, 1, &cell)) return Py_BadArgument(); CItemData* data = nullptr; if(!CItemManager::instance().GetItemDataPointer(vnum, &data)) return Py_BadArgument(); #ifdef EXTEND_IKASHOP_ULTIMATE const auto page = cell / pageSize; const auto localCell = cell % pageSize; if(page < 0 || page >= ikashop::OFFLINESHOP_PAGE_COUNT) return Py_BuildNone(); grid[page].RegisterItem(localCell, data->GetSize()); #else grid.RegisterItem(cell, data->GetSize()); #endif } #ifdef EXTEND_IKASHOP_ULTIMATE std::optional cell; int page = 0; for(; page < ikashop::OFFLINESHOP_PAGE_COUNT; page++) if((cell = grid[page].FindSpace(size))) break; #else const auto cell = grid.FindSpace(size); #endif if(!cell) return Py_BuildNone(); #ifdef EXTEND_IKASHOP_ULTIMATE const auto global = pageSize * page + *cell; return PyInt_FromLong(global); #else return PyInt_FromLong(*cell); #endif } PyObject* ikashopCheckShopSpace(PyObject* poSelf, PyObject* poArgs) { PyObject* items = nullptr; if (!PyTuple_GetObject(poArgs, 0, &items) || !PyList_Check(items)) return Py_BadArgument(); DWORD vnum = 0; if (!PyTuple_GetUnsignedLong(poArgs, 1, &vnum)) return Py_BadArgument(); int cell = 0; if (!PyTuple_GetInteger(poArgs, 2, &cell)) return Py_BadArgument(); #ifdef EXTEND_IKASHOP_ULTIMATE int lockIndex = 0; if(!PyTuple_GetInteger(poArgs, 3, &lockIndex)) return Py_BadArgument(); #endif CItemData* itemData = nullptr; if(!CItemManager::instance().GetItemDataPointer(vnum, &itemData)) return PyBool_FromLong(false); constexpr auto width = ikashop::OFFLINESHOP_GRID_WIDTH; constexpr auto height = ikashop::OFFLINESHOP_GRID_HEIGHT; #ifdef EXTEND_IKASHOP_ULTIMATE constexpr auto pageSize = ikashop::OFFLINESHOP_PAGE_SIZE; ikashop::CShopGrid grid[ikashop::OFFLINESHOP_PAGE_COUNT]{}; #else ikashop::CShopGrid grid{}; #endif // filling grids with items for(int i=0; i < PyList_Size(items); i++) { auto info = PyList_GetItem(items, i); if(!PyTuple_Check(info) || PyTuple_Size(info) != 2) return Py_BadArgument(); DWORD vnum = 0; if(!PyTuple_GetUnsignedLong(info, 0, &vnum)) return Py_BadArgument(); int cell = 0; if(!PyTuple_GetInteger(info, 1, &cell)) return Py_BadArgument(); CItemData* data = nullptr; if(!CItemManager::instance().GetItemDataPointer(vnum, &data)) return Py_BadArgument(); #ifdef EXTEND_IKASHOP_ULTIMATE const auto page = cell / pageSize; const auto localCell = cell % pageSize; if(page < 0 || page >= ikashop::OFFLINESHOP_PAGE_COUNT) return Py_BuildNone(); grid[page].RegisterItem(localCell, data->GetSize()); #else grid.RegisterItem(cell, data->GetSize()); #endif } #ifdef EXTEND_IKASHOP_ULTIMATE // locking cells for(int i=lockIndex; i < pageSize * ikashop::OFFLINESHOP_PAGE_COUNT; i++) { const auto page = i / pageSize; const auto local = i % pageSize; grid[page].RegisterItem(local, 1); } // checking space const auto page = cell / pageSize; const auto local = cell % pageSize; return PyBool_FromLong(grid[page].CheckSpace(local, itemData->GetSize())); #else return PyBool_FromLong(grid.CheckSpace(cell, itemData->GetSize())); #endif } PyObject* ikashopGetItemHash(PyObject* poSelf, PyObject* poArgs) { // extracting data DWORD vnum = 0; if (!PyTuple_GetUnsignedLong(poArgs, 0, &vnum)) return Py_BadArgument(); DWORD count = 0; if (!PyTuple_GetUnsignedLong(poArgs, 1, &count)) return Py_BadArgument(); PyObject* sockets = nullptr; if (!PyTuple_GetObject(poArgs, 2, &sockets)) return Py_BadArgument(); PyObject* attrs = nullptr; if (!PyTuple_GetObject(poArgs, 3, &attrs)) return Py_BadArgument(); PyObject* attribute = nullptr; int attrvalue = 0; ikashop::TShopPlayerItem item{}; item.vnum = vnum; item.count = count; for (int i = 0; i < ITEM_SOCKET_SLOT_MAX_NUM; i++) if (!PyTuple_GetLong(sockets, i, &item.alSockets[i])) return Py_BadArgument(); for (int i = 0; i < ITEM_ATTRIBUTE_SLOT_MAX_NUM; i++) { if (!PyTuple_GetObject(attrs, i, &attribute) || !PyTuple_GetInteger(attribute, 0, &item.aAttr[i].bType) || !PyTuple_GetInteger(attribute, 1, &attrvalue)) return Py_BadArgument(); item.aAttr[i].sValue = static_cast(attrvalue); } return PyInt_FromSize_t(static_cast(ikashop::GetItemHash(item))); } #ifdef EXTEND_IKASHOP_PRO PyObject* ikashopGetItemPriceCache(PyObject* poSelf, PyObject* poArgs) { // extracting data DWORD vnum = 0; if(!PyTuple_GetUnsignedLong(poArgs, 0, &vnum)) return Py_BadArgument(); DWORD hash = 0; if(!PyTuple_GetUnsignedLong(poArgs, 1, &hash)) return Py_BadArgument(); DWORD count = 0; if(!PyTuple_GetUnsignedLong(poArgs, 2, &count)) return Py_BadArgument(); // getting price auto price = CPythonIkarusShop::instance().GetPriceHistory(vnum, hash, count); if(!price) return Py_BuildNone(); // making return value PythonSafeDict dict; dict.set("value", price->yang); #ifdef ENABLE_CHEQUE_SYSTEM dict.set("cheque", price->cheque); #endif return dict.incRef(); } PyObject* ikashopRegisterItemPriceCache(PyObject* poSelf, PyObject* poArgs) { // extracting data DWORD vnum = 0; if (!PyTuple_GetUnsignedLong(poArgs, 0, &vnum)) return Py_BadArgument(); DWORD hash = 0; if (!PyTuple_GetUnsignedLong(poArgs, 1, &hash)) return Py_BadArgument(); DWORD count = 0; if (!PyTuple_GetUnsignedLong(poArgs, 2, &count)) return Py_BadArgument(); ikashop::TPriceInfo price; if (!PyTuple_GetLongLong(poArgs, 3, &price.yang)) return Py_BadArgument(); #ifdef ENABLE_CHEQUE_SYSTEM if (!PyTuple_GetInteger(poArgs, 4, &price.cheque)) return Py_BadArgument(); #endif CPythonIkarusShop::Instance().RegisterPriceHistory(vnum, count, hash, price); return Py_BuildNone(); } PyObject* ikashopLoadNotifications(PyObject* poSelf, PyObject* poArgs) { CPythonIkarusShop::instance().LoadNotifications(); return Py_BuildNone(); } PyObject* ikashopSendNotificationListRequest(PyObject* poSelf, PyObject* poArgs) { CPythonNetworkStream::instance().SendIkarusNotificationListRequest(); return Py_BuildNone(); } PyObject* ikashopSendNotificationListClose(PyObject* poSelf, PyObject* poArgs) { CPythonNetworkStream::instance().SendIkarusNotificationListClose(); return Py_BuildNone(); } PyObject* ikashopRegisterNotification(PyObject* poSelf, PyObject* poArgs) { ikashop::TNotificationInfo info{}; info.seenflag = true; int type = 0; if(!PyTuple_GetInteger(poArgs, 0, &type)) return Py_BadArgument(); info.type = static_cast(type); char* who = nullptr; if (!PyTuple_GetString(poArgs, 1, &who)) return Py_BadArgument(); std::strncpy(info.who, who, sizeof(info.who)); if (!PyTuple_GetUnsignedLong(poArgs, 2, &info.what)) return Py_BadArgument(); char* format = nullptr; if (!PyTuple_GetString(poArgs, 3, &format)) return Py_BadArgument(); std::strncpy(info.format, format, sizeof(info.format)); if (!PyTuple_GetLongLong(poArgs, 4, &info.datetime)) return Py_BadArgument(); bool save = false; if(!PyTuple_GetBoolean(poArgs, 5, &save)) return Py_BadArgument(); CPythonIkarusShop::instance().RegisterNotification(info); if(save) CPythonIkarusShop::instance().SaveNotifications(); return Py_BuildNone(); } PyObject* ikashopGetNotifications(PyObject* poSelf, PyObject* poArgs) { auto& notifications = CPythonIkarusShop::instance().GetNotifications(); auto list = ExtractPythonListFromContainer(notifications, ExtractPythonDictNotification); return list.incRef(); } #endif #ifdef EXTEND_IKASHOP_ULTIMATE PyObject* ikashopSendPriceAverageRequest(PyObject* poSelf, PyObject* poArgs) { DWORD vnum = 0; if (!PyTuple_GetUnsignedLong(poArgs, 0, &vnum)) return Py_BadArgument(); DWORD count = 0; if (!PyTuple_GetUnsignedLong(poArgs, 1, &count)) return Py_BadArgument(); CPythonNetworkStream::instance().SendPriceAverageRequest(vnum, count); return Py_BuildNone(); } PyObject* ikashopSendShopDecorationUse(PyObject* poSelf, PyObject* poArgs) { int index = 0; if(!PyTuple_GetInteger(poArgs, 0, &index)) return Py_BadArgument(); CPythonNetworkStream::instance().SendShopDecorationUsage(index); return Py_BuildNone(); } PyObject* ikashopSendShopMoveItem(PyObject* poSelf, PyObject* poArgs) { int srcPos = 0; if (!PyTuple_GetInteger(poArgs, 0, &srcPos)) return Py_BadArgument(); int destPos = 0; if (!PyTuple_GetInteger(poArgs, 1, &destPos)) return Py_BadArgument(); CPythonNetworkStream::instance().SendShopMoveItem(srcPos, destPos); return Py_BuildNone(); } #endif void initikashop() { static PyMethodDef s_methods[] = { //packets exchanging { "SendShopCreate", ikashopSendShopCreate, METH_VARARGS }, { "SendForceCloseShop", ikashopSendForceCloseShop, METH_VARARGS }, { "SendOpenShop", ikashopSendOpenShop, METH_VARARGS }, { "SendOpenShopOwner", ikashopSendOpenShopOwner, METH_VARARGS }, { "SendBuyItem", ikashopSendBuyItem, METH_VARARGS }, { "SendAddItem", ikashopSendAddItem, METH_VARARGS }, { "SendRemoveItem", ikashopSendRemoveItem, METH_VARARGS }, { "SendEditItem", ikashopSendEditItem, METH_VARARGS }, { "SendFilterRequest", ikashopSendFilterRequest, METH_VARARGS }, { "SendRandomSearchFillRequest", ikashopSendRandomSearchFillRequest, METH_VARARGS }, { "SendOfferCreate", ikashopSendOfferCreate, METH_VARARGS }, { "SendOfferAccept", ikashopSendOfferAccept, METH_VARARGS }, { "SendOfferCancel", ikashopSendOfferCancel, METH_VARARGS }, { "SendOfferListRequest", ikashopSendOfferListRequest, METH_VARARGS }, { "SendSafeboxOpen", ikashopSendSafeboxOpen, METH_VARARGS }, { "SendSafeboxGetItem", ikashopSendSafeboxGetItem, METH_VARARGS }, { "SendSafeboxGetValutes", ikashopSendSafeboxGetValutes, METH_VARARGS }, { "SendSafeboxClose", ikashopSendSafeboxClose, METH_VARARGS }, { "SendOffersListClose", ikashopSendOffersListClose, METH_VARARGS }, { "SendCloseMyShopBoard", ikashopSendCloseMyShopBoard, METH_VARARGS }, { "SendCloseShopGuestBoard", ikashopSendCloseShopGuestBoard, METH_VARARGS }, //AUCTION { "SendAuctionListRequest", ikashopSendAuctionListRequest, METH_VARARGS }, { "SendAuctionOpenAuction", ikashopSendAuctionOpenAuction, METH_VARARGS }, { "SendAuctionAddOffer", ikashopSendAuctionAddOffer, METH_VARARGS }, { "SendAuctionExitFrom", ikashopSendAuctionExitFrom, METH_VARARGS }, { "SendAuctionCreate", ikashopSendAuctionCreate, METH_VARARGS }, { "SendMyAuctionOpen", ikashopSendMyAuctionOpen, METH_VARARGS }, { "SendMyAuctionClose", ikashopSendMyAuctionClose, METH_VARARGS }, { "SendMyAuctionCancel", ikashopSendMyAuctionCancel, METH_VARARGS }, //interfaces methods { "GetFilterHistory", ikashopGetFilterHistory, METH_VARARGS }, { "RegisterFilterHistory", ikashopRegisterFilterHistory, METH_VARARGS }, { "GetItemNames", ikashopGetItemNames, METH_VARARGS }, { "SetSearchShopBoard", ikashopSetSearchShopBoard, METH_VARARGS }, { "SetBusinessBoard", ikashopSetBusinessBoard, METH_VARARGS }, { "GetBusinessBoard", ikashopGetBusinessBoard, METH_VARARGS }, #ifdef EXTEND_IKASHOP_ULTIMATE { "SetShopSkinBoard", ikashopSetShopSkinBoard, METH_VARARGS }, { "GetShopSkinBoard", ikashopGetShopSkinBoard, METH_VARARGS }, #endif //create shop methods { "AddItemOnShop", ikashopShopBuilding_AddItem, METH_VARARGS }, { "AddItemOnAuction", ikashopAuctionBuilding_AddItem, METH_VARARGS }, #ifdef ENABLE_IKASHOP_ENTITIES { "HideShopNames", ikashopHideShopNames, METH_VARARGS }, { "ShowShopNames", ikashopShowShopNames, METH_VARARGS }, #ifdef EXTEND_IKASHOP_PRO { "SendMoveShopEntity", ikashopSendMoveShopEntity, METH_VARARGS }, #endif #endif // helpers { "GetFirstEmptyCell", ikashopGetFirstEmptyCell, METH_VARARGS }, { "CheckShopSpace", ikashopCheckShopSpace, METH_VARARGS }, { "GetItemHash", ikashopGetItemHash, METH_VARARGS }, #ifdef EXTEND_IKASHOP_PRO // price cache { "GetItemPriceCache", ikashopGetItemPriceCache, METH_VARARGS }, { "RegisterItemPriceCache", ikashopRegisterItemPriceCache, METH_VARARGS }, { "LoadNotifications", ikashopLoadNotifications, METH_VARARGS }, { "SendNotificationListRequest", ikashopSendNotificationListRequest, METH_VARARGS }, { "SendNotificationListClose", ikashopSendNotificationListClose, METH_VARARGS }, { "RegisterNotification", ikashopRegisterNotification, METH_VARARGS }, { "GetNotifications", ikashopGetNotifications, METH_VARARGS }, #endif #ifdef EXTEND_IKASHOP_ULTIMATE { "SendPriceAverageRequest", ikashopSendPriceAverageRequest, METH_VARARGS }, { "SendShopDecorationUse", ikashopSendShopDecorationUse, METH_VARARGS }, { "SendShopMoveItem", ikashopSendShopMoveItem, METH_VARARGS }, #endif { NULL, NULL, NULL }, }; PyObject * poModule = Py_InitModule("ikashop", s_methods); PyModule_AddIntConstant(poModule, "FILTER_ATTRIBUTE_NUM", ITEM_ATTRIBUTE_SLOT_NORM_NUM); PyModule_AddIntConstant(poModule, "FILTER_NAME_MAX_LEN", CItemData::ITEM_NAME_MAX_LEN); PyModule_AddIntConstant(poModule, "SHOP_GRID_WIDTH", ikashop::OFFLINESHOP_GRID_WIDTH); PyModule_AddIntConstant(poModule, "SHOP_GRID_HEIGHT", ikashop::OFFLINESHOP_GRID_HEIGHT); PyModule_AddIntConstant(poModule, "SAFEBOX_GRID_WIDTH", ikashop::SAFEBOX_GRID_WIDTH); PyModule_AddIntConstant(poModule, "SAFEBOX_GRID_HEIGHT", ikashop::SAFEBOX_GRID_HEIGHT); PyModule_AddIntConstant(poModule, "SAFEBOX_PAGE_COUNT", ikashop::SAFEBOX_PAGE_COUNT); #ifdef ENABLE_CHEQUE_SYSTEM PyModule_AddIntConstant(poModule, "YANG_PER_CHEQUE", YANG_PER_CHEQUE); #endif #ifdef EXTEND_IKASHOP_ULTIMATE PyModule_AddIntConstant(poModule, "OFFSHOP_LOCK_INDEX_INIT", CPythonIkarusShop::OFFSHOP_LOCK_INDEX_INIT); #endif #ifdef EXTEND_IKASHOP_PRO PyModule_AddIntConstant(poModule, "NOTIFICATION_SELLER_SELLER_SOLD_ITEM", static_cast(ikashop::ENotificationType::SELLER_SOLD_ITEM)); PyModule_AddIntConstant(poModule, "NOTIFICATION_SELLER_NEW_OFFER_ON_ITEM", static_cast(ikashop::ENotificationType::SELLER_NEW_OFFER_ON_ITEM)); PyModule_AddIntConstant(poModule, "NOTIFICATION_SELLER_SHOP_EXPIRED", static_cast(ikashop::ENotificationType::SELLER_SHOP_EXPIRED)); PyModule_AddIntConstant(poModule, "NOTIFICATION_SELLER_ITEM_EXPIRED", static_cast(ikashop::ENotificationType::SELLER_ITEM_EXPIRED)); PyModule_AddIntConstant(poModule, "NOTIFICATION_SELLER_AUCTION_NEW_OFFER", static_cast(ikashop::ENotificationType::SELLER_AUCTION_NEW_OFFER)); PyModule_AddIntConstant(poModule, "NOTIFICATION_SELLER_AUCTION_EXPIRED", static_cast(ikashop::ENotificationType::SELLER_AUCTION_EXPIRED)); PyModule_AddIntConstant(poModule, "NOTIFICATION_SELLER_AUCTION_SOLD", static_cast(ikashop::ENotificationType::SELLER_AUCTION_SOLD)); PyModule_AddIntConstant(poModule, "NOTIFICATION_SELLER_OFFER_CANCELLED", static_cast(ikashop::ENotificationType::SELLER_OFFER_CANCELLED)); PyModule_AddIntConstant(poModule, "NOTIFICATION_BUYER_OFFER_DENIED", static_cast(ikashop::ENotificationType::BUYER_OFFER_DENIED)); PyModule_AddIntConstant(poModule, "NOTIFICATION_BUYER_OFFER_ACCEPTED", static_cast(ikashop::ENotificationType::BUYER_OFFER_ACCEPTED)); PyModule_AddIntConstant(poModule, "NOTIFICATION_BUYER_OFFER_EXPIRED", static_cast(ikashop::ENotificationType::BUYER_OFFER_EXPIRED)); PyModule_AddIntConstant(poModule, "NOTIFICATION_BUYER_AUCTION_BUY", static_cast(ikashop::ENotificationType::BUYER_AUCTION_BUY)); PyModule_AddIntConstant(poModule, "NOTIFICATION_BUYER_AUCTION_RAISE", static_cast(ikashop::ENotificationType::BUYER_AUCTION_RAISE)); PyModule_AddIntConstant(poModule, "NOTIFICATION_BUYER_AUCTION_LOST", static_cast(ikashop::ENotificationType::BUYER_AUCTION_LOST)); #ifdef EXTEND_IKASHOP_ULTIMATE PyModule_AddIntConstant(poModule, "NOTIFICATION_SELLER_DECORATION_EXPIRED", static_cast(ikashop::ENotificationType::SELLER_DECORATION_EXPIRED)); #endif #endif } #endif