UserInterface
1. defines.h
Add:
#define ENABLE_ITEMSHOP
2. Packet.h
Search:
HEADER_CG_TIME_SYNC = 0xfc,
HEADER_CG_PONG = 0xfe,
Add above:
#ifdef ENABLE_ITEMSHOP
HEADER_CG_BUY_ITEMSHOP_ITEM = 240,
HEADER_CG_PROMOTION = 241,
#endif
Search:
HEADER_GC_HANDSHAKE_OK = 0xfc,
HEADER_GC_PHASE = 0xfd,
Add above:
#ifdef ENABLE_ITEMSHOP
HEADER_GC_ITEMSHOP = 240,
#endif
Add to end of file above #pragma pack(pop):
#ifdef ENABLE_ITEMSHOP
enum
{
ITEMSHOP_CATEGORY_MAX_LEN = 24,
ITEMSHOP_ICON_MAX_LEN = 24,
ITEMSHOP_HASH_MAX_LEN = 32,
PROMOTION_CODE_MAX_LEN = 48,
};
typedef struct SItemshopCategoryInfo
{
char category[ITEMSHOP_CATEGORY_MAX_LEN + 1];
char icon[ITEMSHOP_ICON_MAX_LEN + 1];
}TItemshopCategoryInfo;
typedef struct SPacketGCitemshopCategorySize
{
DWORD size;
} TPacketGCitemshopCategorySize;
typedef struct SPacketGCItemshopItemSize
{
DWORD size;
} TPacketGCItemshopItemSize;
typedef struct SPacketGCItemshopInfo
{
BYTE header;
DWORD subheader;
} TPacketGCItemshopInfo;
enum
{
SUBHEADER_ITEMSHOP_REFRESH_ITEMS,
SUBHEADER_ITEMSHOP_REFRESH_COINS,
SUBHEADER_ITEMSHOP_REFRESH_SINGLE_ITEM,
SUBHEADER_ITEMSHOP_REMOVE_SINGLE_ITEM,
SUBHEADER_ITEMSHOP_ADD_SINGLE_ITEM,
SUBHEADER_PROMOTION_CODE_REWARDS,
};
typedef struct SItemshopItemTable
{
char hash[ITEMSHOP_HASH_MAX_LEN + 1];
unsigned long long ullPrice;
BYTE byDiscountPercent;
long long llLimitCount;
BYTE byCategory;
DWORD dwVnum;
WORD wCount;
time_t end_time;
long alSockets[ITEM_SOCKET_SLOT_MAX_NUM];
TPlayerItemAttribute aAttr[ITEM_ATTRIBUTE_SLOT_MAX_NUM];
BYTE weight;
} TItemshopItemTable;
typedef struct SPromotionItemTable
{
DWORD dwVnum;
WORD wCount;
long alSockets[ITEM_SOCKET_SLOT_MAX_NUM];
TPlayerItemAttribute aAttr[ITEM_ATTRIBUTE_SLOT_MAX_NUM];
} TPromotionItemTable;
typedef struct SPacketCGBuyItemshopItem
{
BYTE header;
char hash[ITEMSHOP_HASH_MAX_LEN + 1];
WORD wCount;
} TPacketCGBuyItemshopItem;
typedef struct SPacketCGRedeemPromotionCode
{
BYTE header;
char promotion_code[PROMOTION_CODE_MAX_LEN + 1];
} TPacketCGRedeemPromotionCode;
#endif
3. PythonApplication.cpp
Search:
time_t CPythonApplication::GetServerTimeStamp()
{
return (time(0) - m_tLocalStartTime) + m_tServerTime;
}
Add:
#ifdef ENABLE_ITEMSHOP
time_t CPythonApplication::GetUNIX()
{
return time(0);
}
#endif
4. PythonApplication.h
Search:
time_t GetServerTimeStamp();
Add:
#ifdef ENABLE_ITEMSHOP
time_t GetUNIX();
#endif
5. PythonApplicationModule.cpp
Search:
PyObject * appGetGlobalTimeStamp(PyObject * poSelf, PyObject * poArgs)
{
return Py_BuildValue("i", CPythonApplication::Instance().GetServerTimeStamp());
}
Add:
#ifdef ENABLE_ITEMSHOP
PyObject* appGetUNIX(PyObject* poSelf, PyObject* poArgs)
{
return Py_BuildValue("i", CPythonApplication::Instance().GetUNIX());
}
#endif
Search:
{ "GetGlobalTimeStamp", appGetGlobalTimeStamp, METH_VARARGS },
Add:
#ifdef ENABLE_ITEMSHOP
{ "GetUNIX", appGetUNIX, METH_VARARGS },
#endif
Add to end of file above }:
#ifdef ENABLE_ITEMSHOP
PyModule_AddIntConstant(poModule, "ENABLE_ITEMSHOP", 1);
#else
PyModule_AddIntConstant(poModule, "ENABLE_ITEMSHOP", 0);
#endif
6. PythonItemModule.cpp
Search:
PyModule_AddIntConstant(poModule, "ITEM_FLAG_CONFIRM_WHEN_USE", CItemData::ITEM_FLAG_CONFIRM_WHEN_USE);
Add:
#ifdef ENABLE_ITEMSHOP
PyModule_AddIntConstant(poModule, "ITEM_FLAG_STACKABLE", CItemData::ITEM_FLAG_STACKABLE);
#endif
7. PythonNetworkStream.cpp
Search:
public:
CMainPacketHeaderMap()
{
Add:
#ifdef ENABLE_ITEMSHOP
Set(HEADER_GC_ITEMSHOP, CNetworkPacketHeaderMap::TPacketType(sizeof(TPacketGCItemshopInfo), STATIC_SIZE_PACKET));
#endif
8. PythonNetworkStream.h
Search:
bool RecvMallOpenPacket();
bool RecvMallItemSetPacket();
bool RecvMallItemDelPacket();
Add above:
#ifdef ENABLE_ITEMSHOP
bool RecvItemshopPacket();
bool SendBuyItemshopItemPacket(const char* hash, WORD wCount);
bool SendRedeemPromotionCodePacket(const char* promotion_code);
#endif
9. PythonNetworkStreamModule.cpp
Search:
void initnet()
Add above:
#ifdef ENABLE_ITEMSHOP
PyObject* netSendBuyItemshopItemPacket(PyObject* poSelf, PyObject* poArgs)
{
char* szHash;
if (!PyTuple_GetString(poArgs, 0, &szHash))
return Py_BuildException();
int count;
if (!PyTuple_GetInteger(poArgs, 1, &count))
return Py_BuildException();
CPythonNetworkStream::Instance().SendBuyItemshopItemPacket(szHash, count);
return Py_BuildNone();
}
PyObject* netSendRedeemPromotionCodePacket(PyObject* poSelf, PyObject* poArgs)
{
char* szCode;
if (!PyTuple_GetString(poArgs, 0, &szCode))
return Py_BuildException();
if (!strcmp(szCode, ""))
return Py_BuildNone();
if (strlen(szCode) <= 0)
return Py_BuildNone();
CPythonNetworkStream::Instance().SendRedeemPromotionCodePacket(szCode);
return Py_BuildNone();
}
#endif
Search:
void initnet()
{
static PyMethodDef s_methods[] =
{
Add:
#ifdef ENABLE_ITEMSHOP
{ "SendBuyItemshopItemPacket", netSendBuyItemshopItemPacket, METH_VARARGS },
{ "SendRedeemPromotionCodePacket", netSendRedeemPromotionCodePacket, METH_VARARGS },
#endif
10. PythonNetworkStreamPhaseGame.cpp
Search:
default:
ret = RecvDefaultPacket(header);
break;
Add above:
#ifdef ENABLE_ITEMSHOP
case HEADER_GC_ITEMSHOP:
ret = RecvItemshopPacket();
break;
#endif
Add to end of file:
#ifdef ENABLE_ITEMSHOP
bool CPythonNetworkStream::SendBuyItemshopItemPacket(const char* hash, WORD wCount)
{
TPacketCGBuyItemshopItem p;
p.header = HEADER_CG_BUY_ITEMSHOP_ITEM;
p.wCount = wCount;
strncpy(p.hash, hash, sizeof(p.hash));
if (!Send(sizeof(p), &p))
{
return false;
}
return true;
}
bool CPythonNetworkStream::SendRedeemPromotionCodePacket(const char* promotion_code)
{
TPacketCGRedeemPromotionCode p;
p.header = HEADER_CG_PROMOTION;
strncpy(p.promotion_code, promotion_code, sizeof(p.promotion_code) - 1);
if (!Send(sizeof(p), &p))
{
return false;
}
return true;
}
bool CPythonNetworkStream::RecvItemshopPacket()
{
TPacketGCItemshopInfo packet;
if (!Recv(sizeof(packet), &packet))
return false;
DWORD subHeader = packet.subheader;
switch (subHeader)
{
case SUBHEADER_ITEMSHOP_REFRESH_ITEMS:
{
TPacketGCitemshopCategorySize itemshop_category_size;
if (!Recv(sizeof(itemshop_category_size), &itemshop_category_size))
return false;
std::map<BYTE, TItemshopCategoryInfo> itemshop_categories;
BYTE key = 0;
TItemshopCategoryInfo category_info;
for (int i = 0; i < itemshop_category_size.size; i++)
{
if (!Recv(sizeof(BYTE), &key))
return false;
if (!Recv(sizeof(category_info), &category_info))
return false;
itemshop_categories.insert(std::pair(key, category_info));
}
TPacketGCItemshopItemSize itemshop_item_size;
if (!Recv(sizeof(itemshop_item_size), &itemshop_item_size))
return false;
std::map<BYTE, std::vector<TItemshopItemTable>> itemshop_items;
size_t vec_size = 0;
TItemshopItemTable table{};
for (int i = 0; i < itemshop_item_size.size; i++) {
if (!Recv(sizeof(BYTE), &key)) {
return false;
}
if (!Recv(sizeof(size_t), &vec_size)) {
return false;
}
std::vector<TItemshopItemTable> itemVec;
itemVec.resize(vec_size);
if (!Recv(sizeof(TItemshopItemTable) * vec_size, itemVec.data()))
{
return false;
}
itemshop_items[key] = itemVec;
}
// NOTE: Sort items in categories
for (auto& vec_item : itemshop_items)
{
std::sort(vec_item.second.begin(), vec_item.second.end(), [](TItemshopItemTable const& f, TItemshopItemTable const& s) {
return f.end_time > s.end_time || f.end_time == s.end_time &&
(f.llLimitCount > s.llLimitCount || f.llLimitCount == s.llLimitCount &&
(f.byDiscountPercent > s.byDiscountPercent || f.byDiscountPercent == s.byDiscountPercent &&
(f.weight > s.weight || f.weight == s.weight &&
(f.dwVnum > s.dwVnum))));
}
);
}
PyObject* py_itemshop_infos = PyList_New(0);
for (const auto& [key, cat] : itemshop_items)
{
PyObject* py_itemshop_category = PyDict_New();
PyDict_SetItem(py_itemshop_category, PyString_FromString("index"), PyInt_FromLong(key));
PyDict_SetItem(py_itemshop_category, PyString_FromString("category"), PyString_FromString(itemshop_categories.at(key).category));
PyDict_SetItem(py_itemshop_category, PyString_FromString("icon"), PyString_FromString(itemshop_categories.at(key).icon));
PyObject* py_itemshop_items = PyList_New(0);
for (const auto& item : cat)
{
PyObject* py_itemshop_item = PyDict_New();
PyDict_SetItem(py_itemshop_item, PyString_FromString("vnum"), PyInt_FromLong(item.dwVnum));
PyObject* sockets = PyList_New(0);
for (int socket = 0; socket < ITEM_SOCKET_SLOT_MAX_NUM; socket++)
{
PyList_Append(sockets, PyInt_FromLong(item.alSockets[socket]));
}
PyDict_SetItem(py_itemshop_item, PyString_FromString("sockets"), sockets);
PyObject* attrList = PyList_New(0);
for (const auto& attr : item.aAttr)
{
PyList_Append(attrList, Py_BuildValue("ii", attr.bType, attr.sValue));
}
PyDict_SetItem(py_itemshop_item, PyString_FromString("attr"), attrList);
PyDict_SetItem(py_itemshop_item, PyString_FromString("price"), PyInt_FromLong(item.ullPrice));
PyDict_SetItem(py_itemshop_item, PyString_FromString("count"), PyInt_FromLong(item.wCount));
PyDict_SetItem(py_itemshop_item, PyString_FromString("hash"), PyString_FromString(item.hash));
PyDict_SetItem(py_itemshop_item, PyString_FromString("discount"), PyInt_FromLong(item.byDiscountPercent));
PyDict_SetItem(py_itemshop_item, PyString_FromString("limitCount"), PyInt_FromLong(item.llLimitCount));
PyDict_SetItem(py_itemshop_item, PyString_FromString("endTime"), PyInt_FromLong(item.end_time));
PyList_Append(py_itemshop_items, py_itemshop_item);
}
PyDict_SetItem(py_itemshop_category, PyString_FromString("items"), py_itemshop_items);
PyList_Append(py_itemshop_infos, py_itemshop_category);
}
PyCallClassMemberFunc(m_apoPhaseWnd[PHASE_WINDOW_GAME], "BINARY_UPDATE_ITEMSHOP_ITEMS", Py_BuildValue("(O)", py_itemshop_infos));
}
break;
case SUBHEADER_ITEMSHOP_REFRESH_SINGLE_ITEM:
{
TItemshopItemTable item;
if (!Recv(sizeof(item), &item))
return false;
PyObject* py_itemshop_item = PyDict_New();
PyDict_SetItem(py_itemshop_item, PyString_FromString("vnum"), PyInt_FromLong(item.dwVnum));
PyObject* sockets = PyList_New(0);
for (int socket = 0; socket < ITEM_SOCKET_SLOT_MAX_NUM; socket++)
{
PyList_Append(sockets, PyInt_FromLong(item.alSockets[socket]));
}
PyDict_SetItem(py_itemshop_item, PyString_FromString("sockets"), sockets);
PyObject* attrList = PyList_New(0);
for (int attr = 0; attr < ITEM_ATTRIBUTE_SLOT_MAX_NUM; attr++)
{
PyList_Append(attrList, Py_BuildValue("ii", item.aAttr[attr].bType, item.aAttr[attr].sValue));
}
PyDict_SetItem(py_itemshop_item, PyString_FromString("attr"), attrList);
PyDict_SetItem(py_itemshop_item, PyString_FromString("price"), PyInt_FromLong(item.ullPrice));
PyDict_SetItem(py_itemshop_item, PyString_FromString("count"), PyInt_FromLong(item.wCount));
PyDict_SetItem(py_itemshop_item, PyString_FromString("hash"), PyString_FromString(item.hash));
PyDict_SetItem(py_itemshop_item, PyString_FromString("discount"), PyInt_FromLong(item.byDiscountPercent));
PyDict_SetItem(py_itemshop_item, PyString_FromString("limitCount"), PyInt_FromLong(item.llLimitCount));
PyDict_SetItem(py_itemshop_item, PyString_FromString("endTime"), PyInt_FromLong(item.end_time));
PyCallClassMemberFunc(m_apoPhaseWnd[PHASE_WINDOW_GAME], "BINARY_UPDATE_ITEMSHOP_ITEM", Py_BuildValue("(O)", py_itemshop_item));
}
break;
case SUBHEADER_ITEMSHOP_REFRESH_COINS:
{
unsigned long long ullCoins;
if (!Recv(sizeof(unsigned long long), &ullCoins))
return false;
PyCallClassMemberFunc(m_apoPhaseWnd[PHASE_WINDOW_GAME], "BINARY_UPDATE_ITEMSHOP_COINS", Py_BuildValue("(L)", ullCoins));
}
break;
case SUBHEADER_ITEMSHOP_REMOVE_SINGLE_ITEM:
{
TItemshopItemTable item;
if (!Recv(sizeof(item), &item))
return false;
PyCallClassMemberFunc(m_apoPhaseWnd[PHASE_WINDOW_GAME], "BINARY_REMOVE_ITEMSHOP_ITEM", Py_BuildValue("(s)", item.hash));
}
break;
case SUBHEADER_ITEMSHOP_ADD_SINGLE_ITEM:
{
TItemshopCategoryInfo category_info;
if (!Recv(sizeof(category_info), &category_info))
return false;
TItemshopItemTable item;
if (!Recv(sizeof(item), &item))
return false;
PyObject* py_itemshop_category = PyDict_New();
PyDict_SetItem(py_itemshop_category, PyString_FromString("index"), PyInt_FromLong(item.byCategory));
PyDict_SetItem(py_itemshop_category, PyString_FromString("category"), PyString_FromString(category_info.category));
PyDict_SetItem(py_itemshop_category, PyString_FromString("icon"), PyString_FromString(category_info.icon));
PyObject* py_itemshop_items = PyList_New(0);
PyObject* py_itemshop_item = PyDict_New();
PyDict_SetItem(py_itemshop_item, PyString_FromString("vnum"), PyInt_FromLong(item.dwVnum));
PyObject* sockets = PyList_New(0);
for (int socket = 0; socket < ITEM_SOCKET_SLOT_MAX_NUM; socket++)
{
PyList_Append(sockets, PyInt_FromLong(item.alSockets[socket]));
}
PyDict_SetItem(py_itemshop_item, PyString_FromString("sockets"), sockets);
PyObject* attrList = PyList_New(0);
for (const auto& attr : item.aAttr)
{
PyList_Append(attrList, Py_BuildValue("ii", attr.bType, attr.sValue));
}
PyDict_SetItem(py_itemshop_item, PyString_FromString("attr"), attrList);
PyDict_SetItem(py_itemshop_item, PyString_FromString("price"), PyInt_FromLong(item.ullPrice));
PyDict_SetItem(py_itemshop_item, PyString_FromString("count"), PyInt_FromLong(item.wCount));
PyDict_SetItem(py_itemshop_item, PyString_FromString("hash"), PyString_FromString(item.hash));
PyDict_SetItem(py_itemshop_item, PyString_FromString("discount"), PyInt_FromLong(item.byDiscountPercent));
PyDict_SetItem(py_itemshop_item, PyString_FromString("limitCount"), PyInt_FromLong(item.llLimitCount));
PyDict_SetItem(py_itemshop_item, PyString_FromString("endTime"), PyInt_FromLong(item.end_time));
PyList_Append(py_itemshop_items, py_itemshop_item);
PyDict_SetItem(py_itemshop_category, PyString_FromString("items"), py_itemshop_items);
PyCallClassMemberFunc(m_apoPhaseWnd[PHASE_WINDOW_GAME], "BINARY_ADD_ITEMSHOP_ITEM", Py_BuildValue("(O)", py_itemshop_category));
}
break;
case SUBHEADER_PROMOTION_CODE_REWARDS:
{
BYTE answer;
if (!Recv(sizeof(BYTE), &answer))
return false;
size_t size;
if (!Recv(sizeof(size_t), &size))
return false;
std::vector <TPromotionItemTable> items;
items.clear();
items.resize(size);
if (size && !Recv(sizeof(TPromotionItemTable) * size, &items[0]))
return false;
PyObject* py_itemshop_items = PyList_New(0);
for (const auto& item : items)
{
PyObject* py_itemshop_item = PyDict_New();
PyDict_SetItem(py_itemshop_item, PyString_FromString("vnum"), PyInt_FromLong(item.dwVnum));
PyObject* sockets = PyList_New(0);
for (int socket = 0; socket < ITEM_SOCKET_SLOT_MAX_NUM; socket++)
{
PyList_Append(sockets, PyInt_FromLong(item.alSockets[socket]));
}
PyDict_SetItem(py_itemshop_item, PyString_FromString("sockets"), sockets);
PyObject* attrList = PyList_New(0);
for (int attr = 0; attr < ITEM_ATTRIBUTE_SLOT_MAX_NUM; attr++)
{
PyList_Append(attrList, Py_BuildValue("ii", item.aAttr[attr].bType, item.aAttr[attr].sValue));
}
PyDict_SetItem(py_itemshop_item, PyString_FromString("attr"), attrList);
PyDict_SetItem(py_itemshop_item, PyString_FromString("count"), PyInt_FromLong(item.wCount));
PyList_Append(py_itemshop_items, py_itemshop_item);
}
PyCallClassMemberFunc(m_apoPhaseWnd[PHASE_WINDOW_GAME], "BINARY_PROMOTION_CODE_REWARDS", Py_BuildValue("(iO)", answer, py_itemshop_items));
}
break;
}
return true;
}
#endif