From aba445f438defddfefdf08e6d583c28721c03486 Mon Sep 17 00:00:00 2001 From: ninemine <1371605831@qq.com> Date: Mon, 10 Nov 2025 22:30:16 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=9F=A5=E7=9C=8B=E6=8C=87?= =?UTF-8?q?=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .cursor/rules/core.mdc | 2 + .tasks/2025-11-10_1_backpack.md | 35 +++++ Plugins/WPSAlchemyGame.py | 2 + Plugins/WPSBackpackSystem.py | 145 ++++++++++++++++-- Plugins/WPSCombatSystem/combat_models.py | 53 +++++-- Plugins/WPSCombatSystem/combat_plugin_base.py | 25 +-- Plugins/WPSCombatSystem/combat_service.py | 2 +- Plugins/WPSGardenSystem/garden_models.py | 1 + Plugins/WPSGardenSystem/garden_plugin_base.py | 14 +- 9 files changed, 240 insertions(+), 39 deletions(-) create mode 100644 .tasks/2025-11-10_1_backpack.md diff --git a/.cursor/rules/core.mdc b/.cursor/rules/core.mdc index 1d7e0ef..dfee703 100644 --- a/.cursor/rules/core.mdc +++ b/.cursor/rules/core.mdc @@ -10,6 +10,8 @@ alwaysApply: true 语言设置:除非用户另有指示,所有常规交互响应都应该使用中文。然而,模式声明(例如\[MODE: RESEARCH\])和特定格式化输出(例如代码块、清单等)应保持英文,以确保格式一致性。 +工具调用: 你应该使用工具调用而不是通过命令行编辑文件 + 你必须完全理解这个项目, 并明白文件夹PWF里的文件你没有权力更改 你必须熟读 WPSAPI.py 和 plugin_interface.py 才有可能不犯错误 diff --git a/.tasks/2025-11-10_1_backpack.md b/.tasks/2025-11-10_1_backpack.md new file mode 100644 index 0000000..da46acf --- /dev/null +++ b/.tasks/2025-11-10_1_backpack.md @@ -0,0 +1,35 @@ +## 背景 +文件名: 2025-11-10_1_backpack.md +创建于: 2025-11-10_21:56:37 +创建者: ASUS +主分支: main +任务分支: 未创建 +Yolo模式: Off + +## 任务描述 +为背包系统新增物品详情查看指令,输出物品基础信息及描述。 + +## 项目概览 +PWF 插件框架下的 `WPSBackpackSystem` 负责物品注册、存取与跨插件接口,`WPSAPI` 提供消息发送能力,其余插件通过该系统注册物品。 + +## 分析 +背包物品目前仅保存 ID、名称与稀有度,无法展示描述信息;战斗与菜园等插件在注册物品时缺失描述字段。纪念品具备系统售价但未暴露,菜园果实售卖价格由作物配置计算。需要在背包数据库扩充描述列并统一缓存,补全各注册调用的描述来源,最后提供独立指令查询详情与售卖信息。 + +## 提议的解决方案 +1. 扩展 `backpack_items` 表与缓存结构,持久化物品描述;补全注册、缓存加载与查询流程。 +2. 调整战斗、菜园、炼金等插件的物品注册逻辑,补添加描述文本及系统售卖数据。 +3. 实现 `WPSItemDescription` 插件,解析“查看”指令并输出物品基础信息、描述与系统售价。 + +## 当前执行步骤:"4. 实现详情指令" + +## 任务进度 +2025-11-10_22:17:07 +- 已修改: Plugins/WPSBackpackSystem.py Plugins/WPSCombatSystem/combat_models.py Plugins/WPSCombatSystem/combat_plugin_base.py Plugins/WPSCombatSystem/combat_service.py Plugins/WPSGardenSystem/garden_models.py Plugins/WPSGardenSystem/garden_plugin_base.py Plugins/WPSAlchemyGame.py +- 更改: 新增背包物品描述字段与缓存,补全战斗/菜园/炼金物品注册描述,实装“查看”指令输出详情及系统售价 +- 原因: 支持物品详情查询并展示描述及出售信息 +- 阻碍因素: 无 +- 状态: 未确认 + +## 最终审查 + + diff --git a/Plugins/WPSAlchemyGame.py b/Plugins/WPSAlchemyGame.py index 3110294..0b0c5a0 100644 --- a/Plugins/WPSAlchemyGame.py +++ b/Plugins/WPSAlchemyGame.py @@ -78,6 +78,7 @@ class WPSAlchemyGame(WPSAPI): self.ASH_ITEM_ID, self.ASH_ITEM_NAME, BackpackItemTier.COMMON, + "炼金失败时残留的炉灰,可作为低阶材料或出售。", ) except Exception as exc: logger.Log( @@ -102,6 +103,7 @@ class WPSAlchemyGame(WPSAPI): self.SLAG_ITEM_ID, self.SLAG_ITEM_NAME, BackpackItemTier.COMMON, + "经高温提炼后的炉渣,可在特殊任务中使用。", ) except Exception as exc: logger.Log( diff --git a/Plugins/WPSBackpackSystem.py b/Plugins/WPSBackpackSystem.py index 18ed6b9..f5f1909 100644 --- a/Plugins/WPSBackpackSystem.py +++ b/Plugins/WPSBackpackSystem.py @@ -2,7 +2,7 @@ from __future__ import annotations from dataclasses import dataclass from enum import Enum -from typing import Dict, List, Optional, Tuple, override +from typing import Dict, List, Optional, override from PWF.Convention.Runtime.Architecture import Architecture from PWF.Convention.Runtime.GlobalConfig import ConsoleFrontColor, ProjectConfig @@ -41,6 +41,7 @@ class BackpackItemDefinition: item_id: str name: str tier: BackpackItemTier + description: str @dataclass(frozen=True) @@ -72,13 +73,14 @@ class WPSBackpackSystem(WPSAPI): def register_db_model(self): from PWF.CoreModules.plugin_interface import DatabaseModel - return [ + models = [ DatabaseModel( table_name=self.ITEMS_TABLE, column_defs={ "item_id": "TEXT PRIMARY KEY", "name": "TEXT NOT NULL", "tier": "TEXT NOT NULL", + "description": "TEXT NOT NULL DEFAULT ''", }, ), DatabaseModel( @@ -91,9 +93,12 @@ class WPSBackpackSystem(WPSAPI): }, ), ] + return models @override def wake_up(self) -> None: + db = get_db() + db.define_column(self.ITEMS_TABLE, "description", "TEXT NOT NULL DEFAULT ''") logger.Log( "Info", f"{ConsoleFrontColor.GREEN}WPSBackpackSystem 插件已加载{ConsoleFrontColor.RESET}", @@ -105,15 +110,17 @@ class WPSBackpackSystem(WPSAPI): def _warm_item_cache(self) -> None: cursor = get_db().conn.cursor() cursor.execute( - f"SELECT item_id, name, tier FROM {self.ITEMS_TABLE}" + f"SELECT item_id, name, tier, description FROM {self.ITEMS_TABLE}" ) rows = cursor.fetchall() for row in rows: tier = BackpackItemTier.from_string(row["tier"]) + description = row["description"] or "" self._item_cache[row["item_id"]] = BackpackItemDefinition( item_id=row["item_id"], name=row["name"], tier=tier, + description=description, ) # region 对外接口 @@ -123,22 +130,29 @@ class WPSBackpackSystem(WPSAPI): item_id: str, name: str, tier: BackpackItemTier, + description: str, ) -> None: if not item_id or not name: raise ValueError("item_id and name must be provided") cursor = get_db().conn.cursor() cursor.execute( f""" - INSERT INTO {self.ITEMS_TABLE} (item_id, name, tier) - VALUES (?, ?, ?) + INSERT INTO {self.ITEMS_TABLE} (item_id, name, tier, description) + VALUES (?, ?, ?, ?) ON CONFLICT(item_id) DO UPDATE SET name = excluded.name, - tier = excluded.tier + tier = excluded.tier, + description = excluded.description """, - (item_id, name, tier.name), + (item_id, name, tier.name, description or ""), ) get_db().conn.commit() - self._item_cache[item_id] = BackpackItemDefinition(item_id, name, tier) + self._item_cache[item_id] = BackpackItemDefinition( + item_id=item_id, + name=name, + tier=tier, + description=description or "", + ) def add_item( self, @@ -191,7 +205,7 @@ class WPSBackpackSystem(WPSAPI): cursor = get_db().conn.cursor() cursor.execute( f""" - SELECT ui.item_id, ui.quantity, i.name, i.tier + SELECT ui.item_id, ui.quantity, i.name, i.tier, i.description FROM {self.USER_ITEMS_TABLE} ui JOIN {self.ITEMS_TABLE} i ON ui.item_id = i.item_id WHERE ui.user_id = ? AND ui.quantity > 0 @@ -209,6 +223,7 @@ class WPSBackpackSystem(WPSAPI): item_id=row["item_id"], name=row["name"], tier=BackpackItemTier.from_string(row["tier"]), + description=row["description"] or "", ) except ValueError: continue @@ -228,7 +243,7 @@ class WPSBackpackSystem(WPSAPI): return self._item_cache[item_id] cursor = get_db().conn.cursor() cursor.execute( - f"SELECT item_id, name, tier FROM {self.ITEMS_TABLE} WHERE item_id = ?", + f"SELECT item_id, name, tier, description FROM {self.ITEMS_TABLE} WHERE item_id = ?", (item_id,), ) row = cursor.fetchone() @@ -238,6 +253,7 @@ class WPSBackpackSystem(WPSAPI): item_id=row["item_id"], name=row["name"], tier=BackpackItemTier.from_string(row["tier"]), + description=row["description"] or "", ) self._item_cache[item_id] = definition return definition @@ -301,5 +317,112 @@ class WPSBackpackSystem(WPSAPI): return None -__all__ = ["WPSBackpackSystem", "BackpackItemTier", "BackpackItemDefinition"] +class WPSItemDescription(WPSAPI): + @override + def dependencies(self) -> List[type]: + return [WPSBackpackSystem] + + @override + def is_enable_plugin(self) -> bool: + return True + + def __init__(self) -> None: + super().__init__() + from Plugins.WPSCombatSystem.combat_models import ADVENTURE_SOUVENIRS + from Plugins.WPSGardenSystem.garden_models import GARDEN_CROPS + from Plugins.WPSGardenSystem.garden_service import GardenConfig + + self._backpack: Optional[WPSBackpackSystem] = None + self._souvenir_prices: Dict[str, int] = { + item_id: sell_price + for item_id, (_, __, sell_price, ___) in ADVENTURE_SOUVENIRS.items() + } + self._garden_crops = GARDEN_CROPS + self._garden_sale_multiplier = GardenConfig.load().sale_multiplier + + @override + def wake_up(self) -> None: + self._backpack = Architecture.Get(WPSBackpackSystem) + self.register_plugin("查看") + self.register_plugin("view") + + async def callback(self, message: str, chat_id: int, user_id: int) -> Optional[str]: + payload = self.parse_message_after_at(message).strip() + if not payload: + return await self.send_markdown_message("❌ 指令格式:`查看 <物品ID或名称>`", chat_id, user_id) + + definition = self._resolve_definition(payload) + if not definition: + return await self.send_markdown_message("❌ 未找到对应物品,请确认输入是否正确", chat_id, user_id) + + sale_info = self._get_sale_info(definition.item_id) + markdown = self._format_markdown(definition, sale_info) + return await self.send_markdown_message(markdown, chat_id, user_id) + + def _resolve_definition(self, identifier: str) -> Optional[BackpackItemDefinition]: + lowered = identifier.strip().lower() + db = get_db().conn.cursor() + db.execute( + f""" + SELECT item_id + FROM {WPSBackpackSystem.ITEMS_TABLE} + WHERE lower(item_id) = ? OR lower(name) = ? + LIMIT 1 + """, + (lowered, lowered), + ) + row = db.fetchone() + item_id = row["item_id"] if row else identifier.strip() + backpack = self._backpack or Architecture.Get(WPSBackpackSystem) + try: + return backpack._get_definition(item_id) + except Exception: + return None + + def _get_sale_info(self, item_id: str) -> Optional[Dict[str, str]]: + if item_id in self._souvenir_prices: + price = self._souvenir_prices[item_id] + return { + "category": "战斗纪念品", + "price": f"{price} 分/个", + "note": "在战斗系统中出售可立即换取积分。", + } + + for crop in self._garden_crops.values(): + if crop.fruit_id == item_id: + price = crop.seed_price * self._garden_sale_multiplier + return { + "category": "菜园果实", + "price": f"{price} 分/个", + "note": "可通过 `菜园 售出 <果实> <数量>` 换取积分。", + } + return None + + def _format_markdown( + self, + definition: BackpackItemDefinition, + sale_info: Optional[Dict[str, str]], + ) -> str: + tier_label = definition.tier.to_markdown_label(definition.tier.display_name) + lines = [ + "# 🔍 物品详情", + f"- 名称:{definition.name}", + f"- ID:`{definition.item_id}`", + f"- 稀有度:{tier_label}", + f"- 描述:{definition.description or '(暂无描述)'}", + ] + if sale_info: + lines.append(f"- 分类:{sale_info['category']}") + lines.append(f"- 系统售价:{sale_info['price']}") + note = sale_info.get("note") + if note: + lines.append(f"- 提示:{note}") + return "\n".join(lines) + +__all__ = [ + "WPSBackpackSystem", + "BackpackItemTier", + "BackpackItemDefinition", + "WPSItemDescription", +] diff --git a/Plugins/WPSCombatSystem/combat_models.py b/Plugins/WPSCombatSystem/combat_models.py index a174de8..03aff62 100644 --- a/Plugins/WPSCombatSystem/combat_models.py +++ b/Plugins/WPSCombatSystem/combat_models.py @@ -561,19 +561,34 @@ WINE_BUFFS: Dict[str, Dict[str, float]] = { }, } -# 冒险材料(item_id -> (name, tier)) -ADVENTURE_MATERIALS: Dict[str, Tuple[str, BackpackItemTier]] = { - "combat_material_ore": ("矿石", BackpackItemTier.COMMON), - "combat_material_gem": ("宝石", BackpackItemTier.RARE), - "combat_material_crystal": ("水晶", BackpackItemTier.EPIC), - "combat_material_essence": ("精华", BackpackItemTier.LEGENDARY), +# 冒险材料(item_id -> (name, tier, description)) +ADVENTURE_MATERIALS: Dict[str, Tuple[str, BackpackItemTier, str]] = { + "combat_material_ore": ("矿石", BackpackItemTier.COMMON, "常见矿石,可用于基础锻造与委托交付。"), + "combat_material_gem": ("宝石", BackpackItemTier.RARE, "闪亮的宝石,适合在高级制作或兑换时使用。"), + "combat_material_crystal": ("水晶", BackpackItemTier.EPIC, "蕴含魔力的晶体,是强化装备的稀有素材。"), + "combat_material_essence": ("精华", BackpackItemTier.LEGENDARY, "远古战场遗留的精华,可构筑传说装备核心。"), } -# 纪念品(item_id -> (name, tier, sell_price)) -ADVENTURE_SOUVENIRS: Dict[str, Tuple[str, BackpackItemTier, int]] = { - "combat_souvenir_medal": ("英雄勋章", BackpackItemTier.RARE, 500), - "combat_souvenir_trophy": ("战斗奖杯", BackpackItemTier.EPIC, 1500), - "combat_souvenir_relic": ("远古遗物", BackpackItemTier.LEGENDARY, 5000), +# 纪念品(item_id -> (name, tier, sell_price, description)) +ADVENTURE_SOUVENIRS: Dict[str, Tuple[str, BackpackItemTier, int, str]] = { + "combat_souvenir_medal": ( + "英雄勋章", + BackpackItemTier.RARE, + 500, + "记录战斗荣誉的勋章,系统回收可获得积分。", + ), + "combat_souvenir_trophy": ( + "战斗奖杯", + BackpackItemTier.EPIC, + 1500, + "沉甸甸的奖杯,象征卓越胜利,可高价出售给系统。", + ), + "combat_souvenir_relic": ( + "远古遗物", + BackpackItemTier.LEGENDARY, + 5000, + "来自远古文明的神秘遗物,系统收购可换取大量积分。", + ), } # 药剂(item_id -> (name, tier, description)) @@ -585,10 +600,18 @@ COMBAT_POTIONS: Dict[str, Tuple[str, BackpackItemTier, str]] = { "combat_potion_def": ("防御药水", BackpackItemTier.RARE, "3回合DEF+20%"), } -# 冒险独有种子(item_id -> (name, tier)) -ADVENTURE_SEEDS: Dict[str, Tuple[str, BackpackItemTier]] = { - "combat_seed_battle_flower": ("战斗之花种子", BackpackItemTier.EPIC), - "combat_seed_victory_tree": ("胜利之树种子", BackpackItemTier.LEGENDARY), +# 冒险独有种子(item_id -> (name, tier, description)) +ADVENTURE_SEEDS: Dict[str, Tuple[str, BackpackItemTier, str]] = { + "combat_seed_battle_flower": ( + "战斗之花种子", + BackpackItemTier.EPIC, + "可在菜园培育的稀有花种,成熟后会带来战斗增益。", + ), + "combat_seed_victory_tree": ( + "胜利之树种子", + BackpackItemTier.LEGENDARY, + "象征无上荣耀的种子,只能在高难冒险中获得。", + ), } # ============================================================================ diff --git a/Plugins/WPSCombatSystem/combat_plugin_base.py b/Plugins/WPSCombatSystem/combat_plugin_base.py index 5e18f6b..0066186 100644 --- a/Plugins/WPSCombatSystem/combat_plugin_base.py +++ b/Plugins/WPSCombatSystem/combat_plugin_base.py @@ -72,24 +72,30 @@ class WPSCombatBase(WPSAPI): # 1. 注册所有装备 for equipment in EQUIPMENT_REGISTRY.values(): - self._safe_register_item(backpack, equipment.item_id, equipment.name, equipment.tier) + self._safe_register_item( + backpack, + equipment.item_id, + equipment.name, + equipment.tier, + equipment.description, + ) # 装备价格根据品质和属性计算 price = self._calculate_equipment_price(equipment) self._safe_register_store(store, equipment.item_id, price, limit=3) # 2. 注册材料 - for item_id, (name, tier) in ADVENTURE_MATERIALS.items(): - self._safe_register_item(backpack, item_id, name, tier) + for item_id, (name, tier, desc) in ADVENTURE_MATERIALS.items(): + self._safe_register_item(backpack, item_id, name, tier, desc) # 材料可以在商店出售(但不购买) # 3. 注册纪念品 - for item_id, (name, tier, sell_price) in ADVENTURE_SOUVENIRS.items(): - self._safe_register_item(backpack, item_id, name, tier) + for item_id, (name, tier, sell_price, desc) in ADVENTURE_SOUVENIRS.items(): + self._safe_register_item(backpack, item_id, name, tier, desc) # 纪念品只能出售 # 4. 注册药剂 for item_id, (name, tier, desc) in COMBAT_POTIONS.items(): - self._safe_register_item(backpack, item_id, name, tier) + self._safe_register_item(backpack, item_id, name, tier, desc) # 药剂价格根据品质 potion_prices = { BackpackItemTier.COMMON: 50, @@ -100,8 +106,8 @@ class WPSCombatBase(WPSAPI): self._safe_register_store(store, item_id, price, limit=10) # 5. 注册冒险种子 - for item_id, (name, tier) in ADVENTURE_SEEDS.items(): - self._safe_register_item(backpack, item_id, name, tier) + for item_id, (name, tier, desc) in ADVENTURE_SEEDS.items(): + self._safe_register_item(backpack, item_id, name, tier, desc) # 种子只能通过冒险获得 # 6. 恢复过期任务和超时战斗 @@ -131,10 +137,11 @@ class WPSCombatBase(WPSAPI): item_id: str, name: str, tier: BackpackItemTier, + description: str, ) -> None: """安全注册物品到背包系统""" try: - backpack.register_item(item_id, name, tier) + backpack.register_item(item_id, name, tier, description) except Exception as e: logger.Log( "Warning", diff --git a/Plugins/WPSCombatSystem/combat_service.py b/Plugins/WPSCombatSystem/combat_service.py index e3a68b3..285ac25 100644 --- a/Plugins/WPSCombatSystem/combat_service.py +++ b/Plugins/WPSCombatSystem/combat_service.py @@ -981,7 +981,7 @@ class CombatService: materials = list(ADVENTURE_MATERIALS.items()) # 高阶段有更高概率掉稀有材料 idx = min(stage // 2, len(materials) - 1) - item_id, (name, tier) = random.choice(materials[max(0, idx-1):]) + item_id, (_, tier, _) = random.choice(materials[max(0, idx-1):]) quantity = random.randint(1, 3) return {"type": "material", "item_id": item_id, "quantity": quantity} diff --git a/Plugins/WPSGardenSystem/garden_models.py b/Plugins/WPSGardenSystem/garden_models.py index ba6866b..e6a13dd 100644 --- a/Plugins/WPSGardenSystem/garden_models.py +++ b/Plugins/WPSGardenSystem/garden_models.py @@ -156,6 +156,7 @@ GARDEN_MISC_ITEMS = { "garden_item_rot_fruit": { "name": "腐败的果实", "tier": "common", + "description": "放置过久的果实,只能作为炼金失败的副产物。", } } diff --git a/Plugins/WPSGardenSystem/garden_plugin_base.py b/Plugins/WPSGardenSystem/garden_plugin_base.py index ddb83da..ac931b2 100644 --- a/Plugins/WPSGardenSystem/garden_plugin_base.py +++ b/Plugins/WPSGardenSystem/garden_plugin_base.py @@ -66,24 +66,30 @@ class WPSGardenBase(WPSAPI): seed_name = f"{crop.display_name}的种子" fruit_name = f"{crop.display_name}的果实" tier = BackpackItemTier.COMMON if crop.tier == "common" else BackpackItemTier.RARE - self._safe_register_item(backpack, crop.seed_id, seed_name, tier) - self._safe_register_item(backpack, crop.fruit_id, fruit_name, tier) + seed_desc = f"{crop.display_name}的种子,可在菜园种植获取相应作物。" + fruit_desc = f"{crop.display_name}成熟后的果实,可食用或售出换取积分。" + self._safe_register_item(backpack, crop.seed_id, seed_name, tier, seed_desc) + self._safe_register_item(backpack, crop.fruit_id, fruit_name, tier, fruit_desc) if crop.extra_reward and crop.extra_reward.kind == "item" and crop.extra_item_id: wood_name = f"{crop.display_name}的木材" + wood_desc = f"{crop.display_name}加工所得的木材,可用于特定任务或制作。" self._safe_register_item( backpack, crop.extra_item_id, wood_name, BackpackItemTier.RARE, + wood_desc, ) if crop.wine_item_id and crop.wine_tier: wine_tier = getattr(BackpackItemTier, crop.wine_tier.upper(), BackpackItemTier.RARE) wine_name = f"{crop.display_name}的果酒" + wine_desc = f"{crop.display_name}酿制的果酒,饮用后可触发战斗增益。" self._safe_register_item( backpack, crop.wine_item_id, wine_name, wine_tier, + wine_desc, ) self._safe_register_mode( @@ -107,6 +113,7 @@ class WPSGardenBase(WPSAPI): item_id, meta["name"], BackpackItemTier.COMMON, + meta.get("description", ""), ) logger.Log( @@ -121,9 +128,10 @@ class WPSGardenBase(WPSAPI): item_id: str, name: str, tier: BackpackItemTier, + description: str, ) -> None: try: - backpack.register_item(item_id, name, tier) + backpack.register_item(item_id, name, tier, description) except Exception: pass