From 3aa4c482e932a2a7d79bb7041de2da46112d9d79 Mon Sep 17 00:00:00 2001 From: shenlei Date: Wed, 30 Sep 2026 17:55:36 +0900 Subject: [PATCH] =?UTF-8?q?tools/server:=20shop-item-time=20patch=20?= =?UTF-8?q?=E2=80=94=20NPC=20shop=20items=20carry=20a=20new=20item's=20tim?= =?UTF-8?q?e=20sockets?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- tools/server/rebuild.sh | 5 +- tools/server/shop-item-time/README.md | 13 ++++ tools/server/shop-item-time/server.patch | 96 ++++++++++++++++++++++++ 3 files changed, 112 insertions(+), 2 deletions(-) create mode 100644 tools/server/shop-item-time/README.md create mode 100644 tools/server/shop-item-time/server.patch diff --git a/tools/server/rebuild.sh b/tools/server/rebuild.sh index 8b3165be..ca8e8c2f 100644 --- a/tools/server/rebuild.sh +++ b/tools/server/rebuild.sh @@ -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 diff --git a/tools/server/shop-item-time/README.md b/tools/server/shop-item-time/README.md new file mode 100644 index 00000000..326a3f79 --- /dev/null +++ b/tools/server/shop-item-time/README.md @@ -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` 自动打补丁并编译。 diff --git a/tools/server/shop-item-time/server.patch b/tools/server/shop-item-time/server.patch new file mode 100644 index 00000000..76ef3987 --- /dev/null +++ b/tools/server/shop-item-time/server.patch @@ -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));