2024-10-25 00:14:42 -05:00

440 lines
10 KiB
C++

#ifndef __INCLUDE_NEW_OFFLINESHOP_HEADER__
#define __INCLUDE_NEW_OFFLINESHOP_HEADER__
#ifdef ENABLE_IKASHOP_RENEWAL
#define __USE_PID_AS_GUESTLIST__
#include <ranges>
#include "item.h"
//copyarray
template <class T, size_t size>
void CopyArray(T (&objDest)[size] , const T (&objSrc)[size]){
if(size==0)
return;
memcpy(&objDest[0] , &objSrc[0], sizeof(T)*size);
}
template <class T>
void DeletePointersContainer(T& obj){
typename T::iterator it = obj.begin();
for(; it != obj.end(); it++)
delete(*it);
}
namespace ikashop
{
//patch 08-03-2020
inline ikashop::ExpirationType GetItemExpiration(LPITEM item) {
auto proto = item->GetProto();
for (const auto limit : proto->aLimits) {
if (limit.bType == LIMIT_REAL_TIME)
return ikashop::ExpirationType::EXPIRE_REAL_TIME;
else if (limit.bType == LIMIT_REAL_TIME_START_FIRST_USE && item->GetSocket(1) != 0)
return ikashop::ExpirationType::EXPIRE_REAL_TIME_FIRST_USE;
} return ikashop::ExpirationType::EXPIRE_NONE;
}
enum eOffshopChatPacket
{
CHAT_PACKET_CANNOT_CREATE_SHOP,
CHAT_PACKET_CANNOT_CHANGE_NAME,
CHAT_PACKET_CANNOT_FORCE_CLOSE,
CHAT_PACKET_CANNOT_OPEN_SHOP,
CHAT_PACKET_CANNOT_OPEN_SHOP_OWNER,
CHAT_PACKET_CANNOT_ADD_ITEM,
CHAT_PACKET_CANNOT_BUY_ITEM, //tofix wrong chat packet
CHAT_PACKET_CANNOT_REMOVE_ITEM,
CHAT_PACKET_CANNOT_EDIT_ITEM,
CHAT_PACKET_CANNOT_REMOVE_LAST_ITEM,
CHAT_PACKET_CANNOT_FILTER,
CHAT_PACKET_CANNOT_SEARCH_YET,
CHAT_PACKET_OFFER_CREATE,
CHAT_PACKET_CANNOT_CREATE_OFFER,
CHAT_PACKET_CANNOT_ACCEPT_OFFER,
CHAT_PACKET_CANNOT_OPEN_SAFEBOX,
CHAT_PACKET_CANNOT_SAFEBOX_GET_ITEM,
CHAT_PACKET_CANNOT_SAFEBOX_GET_VALUTES,
CHAT_PACKET_CANNOT_SAFEBOX_CLOSE,
CHAT_PACKET_RECV_ITEM_SAFEBOX,
//AUCTION
CHAT_PACKET_AUCTION_CANNOT_SEND_LIST,
CHAT_PACKET_AUCTION_CANNOT_OPEN_AUCTION,
CHAT_PACKET_AUCTION_CANNOT_CREATE_AUCTION,
CHAT_PACKET_AUCTION_CANNOT_ADD_OFFER,
//GENERAL
CHAT_PACKET_CANNOT_DO_NOW,
};
class CShopItem
{
using ItemID = DWORD;
using OwnerID = DWORD;
public:
TItemTable* GetTable() const;
LPITEM CreateItem() const;
const TPriceInfo& GetPrice() const;
void SetPrice(const TPriceInfo& price);
const TShopItem& GetInfo() const;
void SetInfo(const TShopItem& info);
ItemID GetID() const;
bool CanBuy(LPCHARACTER ch);
void SetCell(int pos);
protected:
TShopItem m_info{};
};
template<int WIDTH, int HEIGHT>
class CShopGrid
{
static constexpr auto CELL_COUNT = WIDTH*HEIGHT;
public:
void Clear()
{
m_cells = {};
}
void RegisterItem(int cell, int size)
{
const auto [col, row] = _DecomposeCell(cell);
for(int i=0; i < size; i++)
_SetCellState(_ComposeCell(col, row+i), true);
}
void UnregisterItem(int cell, int size)
{
const auto [col, row] = _DecomposeCell(cell);
for (int i = 0; i < size; i++)
_SetCellState(_ComposeCell(col, row + i), false);
}
bool CheckSpace(int cell, int size)
{
const auto [col, row] = _DecomposeCell(cell);
for(int nrow = row; nrow < row + size; nrow++)
if(_GetCellState(_ComposeCell(col, nrow)))
return false;
return true;
}
std::optional<int> FindSpace(int size)
{
for(int cell = 0; cell < CELL_COUNT; cell++)
if(CheckSpace(cell, size))
return cell;
return std::nullopt;
}
constexpr int GetCellCount(){
return WIDTH*HEIGHT;
}
private:
std::pair<int,int> _DecomposeCell(int cell){ return { cell % WIDTH, cell / WIDTH }; }
int _ComposeCell(int col, int row){ return row * WIDTH + col; }
void _SetCellState(int cell, bool state){ if(cell >= 0 && cell < CELL_COUNT) m_cells[cell] = state; }
bool _GetCellState(int cell) { return cell >= 0 && cell < CELL_COUNT ? m_cells[cell] : true; }
private:
std::array<bool, WIDTH*HEIGHT> m_cells{};
};
class ShopEntity;
class CShop
{
public:
static constexpr auto GRID_WIDTH = 15;
static constexpr auto GRID_HEIGHT = 10;
#ifdef EXTEND_IKASHOP_ULTIMATE
static constexpr auto PAGE_COUNT = 3;
static constexpr auto GRID_SIZE = GRID_WIDTH*GRID_HEIGHT;
#endif
public:
using ITEM_HANDLE = std::shared_ptr<CShopItem>;
using OFFER_HANDLE = std::shared_ptr<TOfferInfo>;
using SHOP_ITEM_MAP = std::map<DWORD, ITEM_HANDLE>;
using OFFER_MAP = std::map<DWORD, OFFER_HANDLE>;
using VECGUEST = std::set<DWORD>;
using SHOPNAME = std::string;
#ifdef ENABLE_IKASHOP_ENTITIES
using ENTITY_HANDLE = std::shared_ptr<ShopEntity>;
#endif
public:
// get const
const SHOP_ITEM_MAP& GetItems() const;
const OFFER_MAP& GetOffers() const;
const VECGUEST& GetGuests() const;
// duration
void SetDuration(DWORD duration);
void DecreaseDuration();
DWORD GetDuration() const;
// owner pid
void SetOwnerPID(DWORD ownerid);
DWORD GetOwnerPID() const;
// guests
bool AddGuest(LPCHARACTER ch);
bool RemoveGuest(LPCHARACTER ch);
void KickAllGuests();
// items
bool AddItem(const TShopItem& rItem);
bool RemoveItem(DWORD itemid);
bool ModifyItemPrice(DWORD itemid, const TPriceInfo& price);
bool BuyItem(DWORD itemid);
ITEM_HANDLE GetItem(DWORD itemid);
// offers
bool AddOffer(OFFER_HANDLE offer);
bool AcceptOffer(OFFER_HANDLE offer);
void NotifyOffers(LPCHARACTER ch);
void NotifyAcceptedOffers(LPCHARACTER ch);
void RemoveOffer(DWORD offerid);
// helpers
LPCHARACTER FindOwnerCharacter();
void Clear();
void RefreshToOwner();
void SetName(const SHOPNAME& name);
const char* GetName() const;
// grid checks
bool ReserveSpace(int cell, int size);
int GetNewOffersCounter() const;
#ifdef EXTEND_IKASHOP_ULTIMATE
void MoveItem(DWORD itemid, int destCell);
void ChangeDuration(DWORD duration);
void SetDecoration(int decoration);
void SetDecorationDuration(int decoration_time);
int GetDecoration() const;
int GetDecorationTime() const;
void SetLockIndex(int lockIndex);
int GetLockIndex() const;
void ChangeLockIndex(int lockIndex);
#endif
void SetEntity(ENTITY_HANDLE handle);
ENTITY_HANDLE GetEntity() const;
#ifdef ENABLE_IKASHOP_ENTITIES
void SetSpawn(const TShopSpawn& spawn);
const TShopSpawn& GetSpawn() const;
#endif
private:
void _RefreshViews(LPCHARACTER ch = nullptr);
void _SendNotifyOffer(LPCHARACTER ch, const TOfferInfo& offer);
#ifdef EXTEND_IKASHOP_ULTIMATE
void _RefreshGrid();
#endif
private:
ENTITY_HANDLE m_entity;
SHOP_ITEM_MAP m_items{};
OFFER_MAP m_offers{};
VECGUEST m_guests{};
DWORD m_pid{};
DWORD m_duration{};
SHOPNAME m_name{};
#ifdef EXTEND_IKASHOP_ULTIMATE
CShopGrid<GRID_WIDTH, GRID_HEIGHT> m_grid[PAGE_COUNT];
#else
CShopGrid<GRID_WIDTH, GRID_HEIGHT> m_grid;
#endif
#ifdef ENABLE_IKASHOP_ENTITIES
TShopSpawn m_spawn;
#endif
#ifdef EXTEND_IKASHOP_ULTIMATE
int m_decoration = 0;
int m_decorationTime = 0;
int m_lockIndex = 0;
#endif
};
class CShopSafebox
{
public:
static constexpr auto GRID_WIDTH = 9;
static constexpr auto GRID_HEIGHT = 11;
public:
using ITEM_HANDLE = std::shared_ptr<CShopItem>;
using ITEM_MAP = std::map<DWORD, ITEM_HANDLE>;
public:
CShopSafebox() = default;
CShopSafebox(const CShopSafebox&) = default;
CShopSafebox(LPCHARACTER chOwner);
void SetOwner(LPCHARACTER ch);
void SetValuteAmount(TValutesInfo val);
bool AddItem(const TShopPlayerItem& item);
bool RemoveItem(DWORD itemid);
void AddValute(TValutesInfo val);
bool RemoveValute(TValutesInfo val);
const ITEM_MAP& GetItems() const;
const TValutesInfo& GetValutes() const;
ITEM_HANDLE GetItem(DWORD itemid) const;
LPCHARACTER GetOwner() const;
bool RefreshToOwner(LPCHARACTER ch = nullptr);
private:
int _RegisterGridPosition(ITEM_HANDLE item);
void _UnregisterGridPosition(ITEM_HANDLE item);
private:
ITEM_MAP m_items{};
LPCHARACTER m_owner{};
TValutesInfo m_valutes{};
std::vector<CShopGrid<GRID_WIDTH, GRID_HEIGHT>> m_grids;
};
class CAuction
{
public:
using AUCTION_OFFER_HANDLE = std::shared_ptr<TAuctionOfferInfo>;
using AUCTION_OFFERVEC = std::vector<AUCTION_OFFER_HANDLE>;
using GUESTVEC = std::vector<DWORD>;
#ifdef ENABLE_IKASHOP_ENTITIES
#ifdef EXTEND_IKASHOP_ULTIMATE
using ENTITY_HANDLE = std::shared_ptr<ShopEntity>;
#endif
#endif
public:
void SetInfo(const TAuctionInfo& auction);
void SetOffers(const std::vector<TAuctionOfferInfo>& vec);
bool AddOffer(const TAuctionOfferInfo& offer, bool check = true);
bool AddGuest(LPCHARACTER ch);
bool RemoveGuest(LPCHARACTER ch);
void DecreaseDuration();
//adding 1 minute time when new offer is done in the last minute
void IncreaseDuration();
const GUESTVEC& GetGuests() const;
const DWORD GetBestBuyer() const;
const TAuctionInfo& GetInfo() const;
const AUCTION_OFFERVEC& GetOffers() const;
AUCTION_OFFER_HANDLE GetBestOffer() const;
void RefreshToOwner(LPCHARACTER ch = nullptr);
int GetNewOffersCounter() const;
#ifdef ENABLE_IKASHOP_ENTITIES
#ifdef EXTEND_IKASHOP_ULTIMATE
void SetEntity(ENTITY_HANDLE entity);
ENTITY_HANDLE GetEntity();
const TShopSpawn& GetSpawn() const;
#endif
#endif
private:
void RefreshGuestView();
bool CheckBestOffer();
private:
TAuctionInfo m_info{};
AUCTION_OFFERVEC m_offers{};
AUCTION_OFFER_HANDLE m_bestOffer;
GUESTVEC m_guests{};
#ifdef ENABLE_IKASHOP_ENTITIES
#ifdef EXTEND_IKASHOP_ULTIMATE
ENTITY_HANDLE m_entity;
#endif
#endif
};
#ifdef ENABLE_IKASHOP_ENTITIES
class ShopEntity : public CEntity
{
private:
static DWORD AllocID() {
static auto id = 0UL;
return ++id;
}
public:
using SHOP_HANDLE = std::shared_ptr<CShop>;
#ifdef EXTEND_IKASHOP_ULTIMATE
using AUCTION_HANDLE = std::shared_ptr<CAuction>;
#endif
public:
ShopEntity();
//overriding virtual CEntity methods
void EncodeInsertPacket(LPENTITY entity);
void EncodeRemovePacket(LPENTITY entity);
const char* GetShopName() const;
void SetShopName(const char* name);
int GetShopType() const;
void SetShopType(int iType);
void SetShop(SHOP_HANDLE shop);
#ifdef EXTEND_IKASHOP_ULTIMATE
void SetAuction(AUCTION_HANDLE auction);
AUCTION_HANDLE GetAuction();
#endif
SHOP_HANDLE GetShop() {return m_shop;}
void Destroy() { CEntity::Destroy(); }
DWORD GetVID() const { return m_vid; }
private:
std::string m_name{};
int m_type{};
SHOP_HANDLE m_shop{};
#ifdef EXTEND_IKASHOP_ULTIMATE
AUCTION_HANDLE m_auction{};
#endif
DWORD m_vid = AllocID();
};
#endif
}
#endif
#endif //__include