tools/server: shop-item-time patch — NPC shop items carry a new item's time sockets

40250 game zeroes alSockets for NPC (shop.cpp) and extended (shopEx.cpp) shop items, so
uitooltip shows 'remaining 0 min' for mounts and item-mall time items. MT_GetNewItemSockets
fills them with ITEM_MANAGER::CreateItem's rules (UNIQUE remain time, auto potions,
LIMIT_REAL_TIME, LIMIT_TIMER_BASED_ON_WEAR). Deployed on 203; mount shop 20368 verified.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
shenlei
2026-09-30 17:55:36 +09:00
co-authored by Claude Opus 5.5
parent f9be09d2c2
commit 3aa4c482e9
3 changed files with 112 additions and 2 deletions
+3 -2
View File
@@ -11,12 +11,13 @@
# Patches, in order (each is a patch -p1 against /usr/metin2/src, saved byte-exact):
# inventory-5-pages 5-page inventory; needs its DB migration once (inventory-5-pages/README.md)
# hunt-set quest item.set_attribute, free items in extended shops
# shop-item-time NPC shop items carry a new item's time sockets (tooltip shows the duration)
set -eu
SRC=${SRC:-/usr/metin2/src}
SERVER=${SERVER:-/usr/metin2/server}
HERE=$(cd "$(dirname "$0")" && pwd)
PATCHES="inventory-5-pages hunt-set"
PATCHES="inventory-5-pages hunt-set shop-item-time"
TS=$(date +%Y%m%d-%H%M%S)
patch_state() {
@@ -90,7 +91,7 @@ data)
start_server
;;
*)
sed -n '2,15p' "$0" >&2
sed -n '2,16p' "$0" >&2
exit 2
;;
esac
+13
View File
@@ -0,0 +1,13 @@
# NPC 商店物品显示剩余时间(203 服务端)
40250 服务端发商店物品列表时,NPC 商店(`shop.cpp` 的 `StartShop`/`UpdateItem`)和扩展多页商店
(`shopEx.cpp`,如百店老板娘 9010)把物品的 socket 全部清零。客户端 `uitooltip.py` 用 socket 算剩余时间
(UNIQUE 取 `socket[2]` 分钟数,LIMIT_REAL_TIME 取 `socket[0]` 到期时间戳),于是坐骑、百货店的限时物品
在商店里都显示「剩余时间 : 0分」,买下后才正常。
`server.patch` 在 `shop.cpp` 加 `MT_GetNewItemSockets(vnum, alSockets)`:按 `ITEM_MANAGER::CreateItem`
给新物品设 socket 的同一套规则(UNIQUE 剩余时间、自动药水、LIMIT_REAL_TIME、LIMIT_TIMER_BASED_ON_WEAR)
填商店包里的 socket。玩家个人商店(有实际物品)不变,仍发物品自身的 socket。只影响显示,买到的物品照旧由
`CreateItem` 生成。
在 hunt-set 之后打(`shopEx.cpp` 上下文依赖它)。`sh rebuild.sh build` 自动打补丁并编译。
+96
View File
@@ -0,0 +1,96 @@
--- a/server/game/src/shop.cpp
+++ b/server/game/src/shop.cpp
@@ -18,7 +18,55 @@
#include "monarch.h"
#include "mob_manager.h"
#include "locale_service.h"
+#include "unique_item.h"
+
+// MT: the sockets ITEM_MANAGER::CreateItem gives a new item of this vnum (its remaining time), sent
+// with an NPC shop's items so the client tooltip shows how long a bought one lasts instead of 0.
+void MT_GetNewItemSockets(DWORD dwVnum, long* alSockets)
+{
+ memset(alSockets, 0, sizeof(long) * ITEM_SOCKET_MAX_NUM);
+
+ const TItemTable* table = ITEM_MANAGER::instance().GetTable(dwVnum);
+ if (!table)
+ return;
+
+ if (table->bType == ITEM_UNIQUE)
+ {
+ if (table->alValues[2] == 0)
+ alSockets[ITEM_SOCKET_UNIQUE_REMAIN_TIME] = table->alValues[0];
+ else
+ alSockets[ITEM_SOCKET_UNIQUE_REMAIN_TIME] = get_global_time() + table->alValues[0];
+ }
+
+ switch (dwVnum)
+ {
+ case ITEM_AUTO_HP_RECOVERY_S:
+ case ITEM_AUTO_HP_RECOVERY_M:
+ case ITEM_AUTO_HP_RECOVERY_L:
+ case ITEM_AUTO_HP_RECOVERY_X:
+ case ITEM_AUTO_SP_RECOVERY_S:
+ case ITEM_AUTO_SP_RECOVERY_M:
+ case ITEM_AUTO_SP_RECOVERY_L:
+ case ITEM_AUTO_SP_RECOVERY_X:
+ case REWARD_BOX_ITEM_AUTO_SP_RECOVERY_XS:
+ case REWARD_BOX_ITEM_AUTO_SP_RECOVERY_S:
+ case REWARD_BOX_ITEM_AUTO_HP_RECOVERY_XS:
+ case REWARD_BOX_ITEM_AUTO_HP_RECOVERY_S:
+ case FUCKING_BRAZIL_ITEM_AUTO_SP_RECOVERY_S:
+ case FUCKING_BRAZIL_ITEM_AUTO_HP_RECOVERY_S:
+ alSockets[2] = table->alValues[0];
+ break;
+ }
+ for (int i = 0; i < ITEM_LIMIT_MAX_NUM; ++i)
+ {
+ if (LIMIT_REAL_TIME == table->aLimits[i].bType)
+ alSockets[0] = time(0) + (table->aLimits[i].lValue ? table->aLimits[i].lValue : 60*60*24*7);
+ else if (LIMIT_TIMER_BASED_ON_WEAR == table->aLimits[i].bType)
+ alSockets[0] = table->aLimits[i].lValue ? table->aLimits[i].lValue : 60 * 60 * 10;
+ }
+}
+
/* ------------------------------------------------------------------------------------ */
CShop::CShop()
: m_dwVnum(0), m_dwNPCVnum(0), m_pkPC(NULL)
@@ -467,6 +515,8 @@
thecore_memcpy(pack2.items[i].alSockets, item.pkItem->GetSockets(), sizeof(pack2.items[i].alSockets));
thecore_memcpy(pack2.items[i].aAttr, item.pkItem->GetAttributes(), sizeof(pack2.items[i].aAttr));
}
+ else
+ MT_GetNewItemSockets(item.vnum, pack2.items[i].alSockets);
}
pack.size = sizeof(pack) + sizeof(pack2);
@@ -537,7 +587,7 @@
}
else
{
- memset(pack2.item.alSockets, 0, sizeof(pack2.item.alSockets));
+ MT_GetNewItemSockets(m_itemVector[pos].vnum, pack2.item.alSockets);
memset(pack2.item.aAttr, 0, sizeof(pack2.item.aAttr));
}
}
--- a/server/game/src/shopEx.cpp
+++ b/server/game/src/shopEx.cpp
@@ -18,6 +18,8 @@
#include "monarch.h"
#include "mob_manager.h"
#include "locale_service.h"
+
+void MT_GetNewItemSockets(DWORD dwVnum, long* alSockets);
#include "desc_client.h"
#include "shopEx.h"
#include "group_text_parse_tree.h"
@@ -96,7 +98,7 @@
break;
}
memset(pack_tab.items[i].aAttr, 0, sizeof(pack_tab.items[i].aAttr));
- memset(pack_tab.items[i].alSockets, 0, sizeof(pack_tab.items[i].alSockets));
+ MT_GetNewItemSockets(shop_tab.items[i].vnum, pack_tab.items[i].alSockets);
}
memcpy(buf, &pack_tab, sizeof(pack_tab));