1.修复被错误删除的炼金配方查看插件类2.新增更多装备与配方3.新增闪烁粉尘用于合成共鸣粉末

This commit is contained in:
2025-11-14 00:34:03 +08:00
parent 5a8eb6cbd8
commit d80bfe28d5
4 changed files with 389 additions and 24 deletions

View File

@@ -1321,5 +1321,201 @@ class WPSAlchemyGame(WPSAPI):
) )
class WPSAlchemyRecipeLookup(WPSAPI):
def __init__(self) -> None:
super().__init__()
self._alchemy: Optional[WPSAlchemyGame] = None
self._backpack: Optional[WPSBackpackSystem] = None
def get_guide_subtitle(self) -> str:
return "查询指定物品涉及的炼金配方"
def collect_command_entries(self) -> Sequence[GuideEntry]:
return (
{
"title": "炼金配方",
"identifier": "炼金配方",
"description": "展示物品作为材料、成功产物或失败产物的所有配方。",
"metadata": {"别名": "alchemy_recipe"},
},
)
def collect_guide_entries(self) -> Sequence[GuideEntry]:
return (
{
"title": "查询格式",
"description": "`炼金配方 <物品ID>` 或 `炼金配方 <物品名称>`,忽略大小写。",
},
{
"title": "输出结构",
"description": "结果按材料/成功/失败三类分组,列出配方材料与成功率。",
},
)
def dependencies(self) -> List[type]:
return [WPSAlchemyGame, WPSBackpackSystem]
def is_enable_plugin(self) -> bool:
return True
def wake_up(self) -> None:
self._alchemy = Architecture.Get(WPSAlchemyGame)
self._backpack = Architecture.Get(WPSBackpackSystem)
self.register_plugin("炼金配方")
self.register_plugin("alchemy_recipe")
logger.Log(
"Info",
f"{ConsoleFrontColor.GREEN}WPSAlchemyRecipeLookup 插件已加载{ConsoleFrontColor.RESET}",
)
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(self._help_text(), chat_id, user_id)
backpack = self._backpack or Architecture.Get(WPSBackpackSystem)
definition = self._resolve_definition(payload, backpack)
if definition is None:
return await self.send_markdown_message(
f"❌ 未找到物品 `{payload}`,请确认输入的物品 ID 或名称。",
chat_id,
user_id,
)
alchemy = self._alchemy or Architecture.Get(WPSAlchemyGame)
material_recipes = alchemy.get_recipes_using_item(definition.item_id)
produce_map = alchemy.get_recipes_producing_item(definition.item_id)
success_recipes = produce_map["success"]
fail_recipes = produce_map["fail"]
message_text = self._format_markdown(
definition,
material_recipes,
success_recipes,
fail_recipes,
backpack,
)
return await self.send_markdown_message(message_text, chat_id, user_id)
def _resolve_definition(
self, identifier: str, backpack: WPSBackpackSystem
) -> Optional[BackpackItemDefinition]:
lowered = identifier.strip().lower()
cursor = get_db().conn.cursor()
cursor.execute(
f"""
SELECT item_id
FROM {WPSBackpackSystem.ITEMS_TABLE}
WHERE lower(item_id) = ? OR lower(name) = ?
LIMIT 1
""",
(lowered, lowered),
)
row = cursor.fetchone()
item_id = row["item_id"] if row else identifier.strip()
try:
return backpack._get_definition(item_id) # noqa: SLF001
except Exception:
return None
def _format_markdown(
self,
target: BackpackItemDefinition,
material_recipes: List[AlchemyRecipe],
success_recipes: List[AlchemyRecipe],
fail_recipes: List[AlchemyRecipe],
backpack: WPSBackpackSystem,
) -> str:
lines = [
f"# 🔍 炼金配方查询|{target.name}",
f"- 物品 ID`{target.item_id}`",
"---",
]
lines.append("## 作为配方材料")
lines.extend(
self._format_recipe_entries(material_recipes, backpack)
or ["- 暂无记录"]
)
lines.append("\n## 作为成功产物")
lines.extend(
self._format_recipe_entries(success_recipes, backpack, role="success")
or ["- 暂无记录"]
)
lines.append("\n## 作为失败产物")
lines.extend(
self._format_recipe_entries(fail_recipes, backpack, role="fail")
or ["- 暂无记录"]
)
return "\n".join(lines)
def _format_recipe_entries(
self,
recipes: List[AlchemyRecipe],
backpack: WPSBackpackSystem,
*,
role: str = "material",
) -> List[str]:
if not recipes:
return []
entries: List[str] = []
for recipe in recipes:
materials = self._summarize_materials(recipe, backpack)
success_name = self._resolve_item_name(recipe.success_item_id, backpack)
fail_name = self._resolve_item_name(recipe.fail_item_id, backpack)
rate = f"{recipe.base_success_rate:.0%}"
if role == "material":
entry = (
f"- 材料:{materials}|成功产物:`{success_name}`"
f"失败产物:`{fail_name}`|成功率:{rate}"
)
elif role == "success":
entry = (
f"- 材料:{materials}|成功率:{rate}"
f"失败产物:`{fail_name}`"
)
else:
entry = (
f"- 材料:{materials}|成功率:{rate}"
f"成功产物:`{success_name}`"
)
entries.append(entry)
return entries
def _summarize_materials(
self, recipe: AlchemyRecipe, backpack: WPSBackpackSystem
) -> str:
counter = Counter(recipe.materials)
parts: List[str] = []
for item_id, count in sorted(counter.items()):
name = self._resolve_item_name(item_id, backpack)
if count == 1:
parts.append(f"`{name}`")
else:
parts.append(f"`{name}` × {count}")
return " + ".join(parts)
def _resolve_item_name(
self, item_id: str, backpack: WPSBackpackSystem
) -> str:
try:
definition = backpack._get_definition(item_id) # noqa: SLF001
return definition.name
except Exception:
return item_id
def _help_text(self) -> str:
return (
"# ⚗️ 炼金配方查询帮助\n"
"- `炼金配方 <物品ID>`\n"
"- `炼金配方 <物品名称>`\n"
"> 输入需要精确匹配注册物品,名称不区分大小写。\n"
"> 积分炼金费用将进入奖池,根据挡位概率抽取奖池奖励;部分挡位会额外掉落普通物品。"
)
__all__ = ["WPSAlchemyGame", "WPSAlchemyRecipeLookup"] __all__ = ["WPSAlchemyGame", "WPSAlchemyRecipeLookup"]

View File

@@ -358,6 +358,42 @@ SKILL_REGISTRY: Dict[str, SkillDefinition] = {
cooldown=3, cooldown=3,
icon="✝️" icon="✝️"
), ),
"skill_bastion_guard": SkillDefinition(
skill_id="skill_bastion_guard",
name="圣壁",
description="召唤防御之墙立即获得80点护盾并提升25%防御力3回合",
effects=[
{"type": "shield", "value": 80},
{"type": "buff", "target": "self", "stat": "DEF", "value": 0.25, "duration": 3}
],
cooldown=5,
icon="🛡️"
),
"skill_tempest_step": SkillDefinition(
skill_id="skill_tempest_step",
name="星辰疾行",
description="化作疾风必定先手并提升30%速度2回合",
effects=[
{"type": "special", "effect": "priority"},
{"type": "buff", "target": "self", "stat": "SPD", "value": 0.3, "duration": 2}
],
cooldown=4,
icon="🌠"
),
"skill_sanctuary_guard": SkillDefinition(
skill_id="skill_sanctuary_guard",
name="庇护",
description="赐下防护光辉回复40点生命并获得60点护盾",
effects=[
{"type": "heal", "value": 40},
{"type": "shield", "value": 60}
],
cooldown=4,
icon="🕊️"
),
} }
# 虚拟装备(提供默认技能) # 虚拟装备(提供默认技能)
@@ -487,6 +523,36 @@ EQUIPMENT_REGISTRY: Dict[str, EquipmentDefinition] = {
skill_ids=["skill_iron_wall"], skill_ids=["skill_iron_wall"],
description="厚重的全身板甲" description="厚重的全身板甲"
), ),
"combat_armor_sentinel": EquipmentDefinition(
item_id="combat_armor_sentinel",
name="圣卫重甲",
tier=BackpackItemTier.EPIC,
slot="armor",
attributes={"HP": 160, "DEF": 60, "ATK": 15},
skill_ids=["skill_iron_wall"],
description="经多次锻造强化的重甲,为传说防具的前置形态"
),
"combat_armor_dragonheart": EquipmentDefinition(
item_id="combat_armor_dragonheart",
name="龙心护甲",
tier=BackpackItemTier.LEGENDARY,
slot="armor",
attributes={"HP": 200, "DEF": 75, "ATK": 20},
skill_ids=["skill_bastion_guard"],
description="蕴含龙心之力的护甲,距离传说防具仅一步之遥"
),
"combat_armor_guardian": EquipmentDefinition(
item_id="combat_armor_guardian",
name="星辉壁垒",
tier=BackpackItemTier.LEGENDARY,
slot="armor",
attributes={"HP": 240, "DEF": 90, "ATK": 20, "CRIT": 5},
skill_ids=["skill_bastion_guard"],
description="传说级防御护甲,通过多阶段炼金与锻造而成"
),
# ===== 鞋子 ===== # ===== 鞋子 =====
"combat_boots_leather": EquipmentDefinition( "combat_boots_leather": EquipmentDefinition(
@@ -508,6 +574,36 @@ EQUIPMENT_REGISTRY: Dict[str, EquipmentDefinition] = {
skill_ids=["skill_swift_move"], skill_ids=["skill_swift_move"],
description="蕴含风之力的靴子" description="蕴含风之力的靴子"
), ),
"combat_boots_rapid": EquipmentDefinition(
item_id="combat_boots_rapid",
name="迅捷行者",
tier=BackpackItemTier.RARE,
slot="boots",
attributes={"SPD": 15, "DEF": 5},
skill_ids=[],
description="注入矿石与木材的轻便靴,是速度链的第一步"
),
"combat_boots_tempest": EquipmentDefinition(
item_id="combat_boots_tempest",
name="暴风逐影",
tier=BackpackItemTier.EPIC,
slot="boots",
attributes={"SPD": 28, "DEF": 12},
skill_ids=["skill_swift_move"],
description="融合水晶之力的靴子,进一步提升疾风步的效率"
),
"combat_boots_starlight": EquipmentDefinition(
item_id="combat_boots_starlight",
name="星辉疾靴",
tier=BackpackItemTier.LEGENDARY,
slot="boots",
attributes={"SPD": 38, "DEF": 14, "CRIT": 5},
skill_ids=["skill_tempest_step"],
description="传说级速度之靴,通过多段炼金融合获得"
),
# ===== 饰品 ===== # ===== 饰品 =====
"combat_accessory_ring_str": EquipmentDefinition( "combat_accessory_ring_str": EquipmentDefinition(
@@ -529,8 +625,40 @@ EQUIPMENT_REGISTRY: Dict[str, EquipmentDefinition] = {
skill_ids=["skill_protect"], skill_ids=["skill_protect"],
description="守护佩戴者的神秘护符" description="守护佩戴者的神秘护符"
), ),
"combat_accessory_barrier": EquipmentDefinition(
item_id="combat_accessory_barrier",
name="壁垒护符",
tier=BackpackItemTier.RARE,
slot="accessory",
attributes={"HP": 60, "DEF": 15},
skill_ids=[],
description="以宝石与木材铸成的护符,是传说饰品的起点"
),
"combat_accessory_sanctum": EquipmentDefinition(
item_id="combat_accessory_sanctum",
name="圣域结界",
tier=BackpackItemTier.EPIC,
slot="accessory",
attributes={"HP": 90, "DEF": 25, "CRIT": 5},
skill_ids=["skill_protect"],
description="蕴含水晶能量的护符,提供更强防护"
),
"combat_accessory_aegis": EquipmentDefinition(
item_id="combat_accessory_aegis",
name="星辉守护",
tier=BackpackItemTier.LEGENDARY,
slot="accessory",
attributes={"HP": 130, "DEF": 35, "CRIT": 5, "CRIT_DMG": 20},
skill_ids=["skill_sanctuary_guard"],
description="传说级守护饰品,散发星辉防护力量"
),
} }
SPARK_DUST_ITEM_ID = "alchemy_spark_dust"
# 果酒buff映射 # 果酒buff映射
WINE_BUFFS: Dict[str, Dict[str, float]] = { WINE_BUFFS: Dict[str, Dict[str, float]] = {
# 普通草药果酒 # 普通草药果酒
@@ -567,6 +695,7 @@ ADVENTURE_MATERIALS: Dict[str, Tuple[str, BackpackItemTier, str]] = {
"combat_material_gem": ("宝石", BackpackItemTier.RARE, "闪亮的宝石,适合在高级制作或兑换时使用。"), "combat_material_gem": ("宝石", BackpackItemTier.RARE, "闪亮的宝石,适合在高级制作或兑换时使用。"),
"combat_material_crystal": ("水晶", BackpackItemTier.EPIC, "蕴含魔力的晶体,是强化装备的稀有素材。"), "combat_material_crystal": ("水晶", BackpackItemTier.EPIC, "蕴含魔力的晶体,是强化装备的稀有素材。"),
"combat_material_essence": ("精华", BackpackItemTier.LEGENDARY, "远古战场遗留的精华,可构筑传说装备核心。"), "combat_material_essence": ("精华", BackpackItemTier.LEGENDARY, "远古战场遗留的精华,可构筑传说装备核心。"),
SPARK_DUST_ITEM_ID: ("闪烁粉尘", BackpackItemTier.COMMON, "炼金失败后残留的粉尘。"),
} }
# 纪念品item_id -> (name, tier, sell_price, description) # 纪念品item_id -> (name, tier, sell_price, description)

View File

@@ -2,14 +2,13 @@
from __future__ import annotations from __future__ import annotations
from typing import Dict, List, Type, Union from PWF.Convention.Runtime.Architecture import *
from PWF.Convention.Runtime.Architecture import Architecture
from PWF.Convention.Runtime.GlobalConfig import ConsoleFrontColor, ProjectConfig from PWF.Convention.Runtime.GlobalConfig import ConsoleFrontColor, ProjectConfig
from PWF.CoreModules.plugin_interface import DatabaseModel from PWF.CoreModules.plugin_interface import DatabaseModel
from Plugins.WPSAPI import GuideEntry, GuideSection, WPSAPI from Plugins.WPSAPI import GuideEntry, GuideSection, WPSAPI
from Plugins.WPSBackpackSystem import BackpackItemTier, WPSBackpackSystem from Plugins.WPSBackpackSystem import BackpackItemTier, WPSBackpackSystem
from Plugins.WPSAlchemyGame import WPSAlchemyGame
from Plugins.WPSStoreSystem import WPSStoreSystem from Plugins.WPSStoreSystem import WPSStoreSystem
from Plugins.WPSConfigSystem import WPSConfigAPI from Plugins.WPSConfigSystem import WPSConfigAPI
from Plugins.WPSFortuneSystem import WPSFortuneSystem from Plugins.WPSFortuneSystem import WPSFortuneSystem
@@ -21,21 +20,17 @@ from .combat_models import (
COMBAT_POTIONS, COMBAT_POTIONS,
EQUIPMENT_REGISTRY, EQUIPMENT_REGISTRY,
SKILL_REGISTRY, SKILL_REGISTRY,
SPARK_DUST_ITEM_ID,
EquipmentDefinition, EquipmentDefinition,
get_combat_db_models, get_combat_db_models,
) )
from .combat_service import CombatService, get_combat_service from .combat_service import CombatService, get_combat_service
# 尝试导入菜园系统(可选依赖) from Plugins.WPSGardenSystem import (
try: GardenCropDefinition,
from Plugins.WPSGardenSystem import ( GardenExtraReward,
GardenCropDefinition, register_crop,
GardenExtraReward, )
register_crop,
)
GARDEN_SYSTEM_AVAILABLE = True
except ImportError:
GARDEN_SYSTEM_AVAILABLE = False
logger: ProjectConfig = Architecture.Get(ProjectConfig) logger: ProjectConfig = Architecture.Get(ProjectConfig)
@@ -326,7 +321,7 @@ class WPSCombatBase(WPSAPI):
WPSBackpackSystem, WPSBackpackSystem,
WPSStoreSystem, WPSStoreSystem,
WPSFortuneSystem, WPSFortuneSystem,
# 注:不强制依赖 WPSGardenSystem果酒buff配置在 combat_models.py 中 WPSAlchemyGame,
] ]
def register_db_model(self) -> List[DatabaseModel]: def register_db_model(self) -> List[DatabaseModel]:
@@ -389,9 +384,10 @@ class WPSCombatBase(WPSAPI):
self._safe_register_item(backpack, item_id, name, tier, desc) self._safe_register_item(backpack, item_id, name, tier, desc)
# 种子只能通过冒险获得 # 种子只能通过冒险获得
# 5.1. 注册冒险种子到菜园系统(如果可用) # 5.1. 注册冒险种子到菜园系统
if GARDEN_SYSTEM_AVAILABLE: self._register_adventure_seeds_to_garden()
self._register_adventure_seeds_to_garden()
self._register_legendary_alchemy_recipes()
# 6. 恢复过期任务和超时战斗 # 6. 恢复过期任务和超时战斗
try: try:
@@ -492,7 +488,7 @@ class WPSCombatBase(WPSAPI):
return " | ".join(parts) if parts else equipment.description return " | ".join(parts) if parts else equipment.description
def _calculate_equipment_price(self, equipment) -> int: def _calculate_equipment_price(self, equipment: EquipmentDefinition) -> int:
"""根据装备品质和属性计算价格""" """根据装备品质和属性计算价格"""
# 基础价格 # 基础价格
base_prices = { base_prices = {
@@ -514,9 +510,6 @@ class WPSCombatBase(WPSAPI):
def _register_adventure_seeds_to_garden(self) -> None: def _register_adventure_seeds_to_garden(self) -> None:
"""注册冒险种子到菜园系统""" """注册冒险种子到菜园系统"""
if not GARDEN_SYSTEM_AVAILABLE:
return
try: try:
backpack: WPSBackpackSystem = Architecture.Get(WPSBackpackSystem) backpack: WPSBackpackSystem = Architecture.Get(WPSBackpackSystem)
@@ -584,5 +577,36 @@ class WPSCombatBase(WPSAPI):
f"{ConsoleFrontColor.YELLOW}注册冒险种子到菜园系统时出错: {e}{ConsoleFrontColor.RESET}" f"{ConsoleFrontColor.YELLOW}注册冒险种子到菜园系统时出错: {e}{ConsoleFrontColor.RESET}"
) )
def _register_legendary_alchemy_recipes(self) -> None:
"""注册传说装备的炼金链条"""
alchemy: WPSAlchemyGame = Architecture.Get(WPSAlchemyGame)
recipe_definitions = (
# 护甲链
(("combat_material_ore", "garden_wood_maple", "combat_armor_chain"), "combat_armor_plate", 0.70),
(("combat_material_gem", "combat_material_crystal", "combat_armor_plate"), "combat_armor_sentinel", 0.50),
(("combat_armor_sentinel", "garden_wood_sakura", "combat_material_crystal"), "combat_armor_dragonheart", 0.30),
(("combat_armor_dragonheart", "combat_material_essence", "combat_armor_plate"), "combat_armor_guardian", 0.10),
# 鞋子链
(("combat_material_ore", "garden_wood_ginkgo", "combat_boots_leather"), "combat_boots_rapid", 0.70),
(("combat_boots_rapid", "combat_material_gem", "combat_material_crystal"), "combat_boots_wind", 0.50),
(("combat_boots_wind", "combat_material_crystal", "garden_wood_ginkgo"), "combat_boots_tempest", 0.30),
(("combat_boots_tempest", "combat_material_essence", "garden_wine_maple"), "combat_boots_starlight", 0.10),
# 饰品链
(("combat_accessory_ring_str", "combat_material_gem", "garden_wood_sakura"), "combat_accessory_barrier", 0.70),
(("combat_accessory_barrier", "combat_material_crystal", "garden_wood_sakura"), "combat_accessory_amulet", 0.50),
(("combat_accessory_amulet", "combat_material_crystal", "garden_wine_sakura"), "combat_accessory_sanctum", 0.30),
(("combat_accessory_sanctum", "combat_material_essence", "combat_souvenir_relic"), "combat_accessory_aegis", 0.10),
)
for materials, success_item_id, success_rate in recipe_definitions:
try:
alchemy.register_recipe(materials, success_item_id, SPARK_DUST_ITEM_ID, success_rate)
except Exception as exc:
logger.Log(
"Warning",
f"{ConsoleFrontColor.YELLOW}注册炼金配方 {materials} -> {success_item_id} 失败: {exc}{ConsoleFrontColor.RESET}",
)
__all__ = ["WPSCombatBase"] __all__ = ["WPSCombatBase"]

View File

@@ -3,16 +3,16 @@
from __future__ import annotations from __future__ import annotations
from datetime import datetime, timezone from datetime import datetime, timezone
from typing import Dict, List, Mapping, Optional, Tuple
from PWF.Convention.Runtime.Architecture import Architecture from PWF.Convention.Runtime.Architecture import *
from PWF.Convention.Runtime.GlobalConfig import ConsoleFrontColor, ProjectConfig from PWF.Convention.Runtime.GlobalConfig import ConsoleFrontColor, ProjectConfig
from PWF.CoreModules.clock_scheduler import get_clock_scheduler from PWF.CoreModules.clock_scheduler import get_clock_scheduler
from PWF.CoreModules.plugin_interface import DatabaseModel from PWF.CoreModules.plugin_interface import DatabaseModel
from Plugins.WPSAPI import WPSAPI from Plugins.WPSAPI import GuideEntry, WPSAPI
from Plugins.WPSAlchemyGame import WPSAlchemyGame from Plugins.WPSAlchemyGame import WPSAlchemyGame
from Plugins.WPSBackpackSystem import BackpackItemTier, WPSBackpackSystem from Plugins.WPSBackpackSystem import BackpackItemTier, WPSBackpackSystem
from Plugins.WPSCombatSystem.combat_models import SPARK_DUST_ITEM_ID
from Plugins.WPSStoreSystem import WPSStoreSystem from Plugins.WPSStoreSystem import WPSStoreSystem
from Plugins.WPSGardenSystem import ( from Plugins.WPSGardenSystem import (
GardenCropDefinition, GardenCropDefinition,
@@ -32,6 +32,7 @@ from .crystal_models import (
CRYSTAL_TREE_FRUIT_ID, CRYSTAL_TREE_FRUIT_ID,
CRYSTAL_TREE_SEED_ID, CRYSTAL_TREE_SEED_ID,
CRYSTAL_TINT_POWDER_ID, CRYSTAL_TINT_POWDER_ID,
CRYSTAL_RESONANCE_POWDER_ID,
) )
from .crystal_service import get_crystal_db_models, get_crystal_service from .crystal_service import get_crystal_db_models, get_crystal_service
@@ -489,6 +490,7 @@ class WPSCrystalSystem(WPSAPI):
self._try_register_wine_recipe(alchemy, crop) self._try_register_wine_recipe(alchemy, crop)
self._register_tint_powder_recipe(alchemy) self._register_tint_powder_recipe(alchemy)
self._register_resonance_powder_recipe(alchemy)
def _safe_register_backpack_item( def _safe_register_backpack_item(
self, self,
@@ -550,6 +552,20 @@ class WPSCrystalSystem(WPSAPI):
f"{ConsoleFrontColor.YELLOW}注册 {CRYSTAL_TREE_FRUIT_ID} 炼金配方失败: {exc}{ConsoleFrontColor.RESET}", f"{ConsoleFrontColor.YELLOW}注册 {CRYSTAL_TREE_FRUIT_ID} 炼金配方失败: {exc}{ConsoleFrontColor.RESET}",
) )
def _register_resonance_powder_recipe(self, alchemy: WPSAlchemyGame) -> None:
try:
alchemy.register_recipe(
(SPARK_DUST_ITEM_ID, SPARK_DUST_ITEM_ID, SPARK_DUST_ITEM_ID),
CRYSTAL_RESONANCE_POWDER_ID,
WPSAlchemyGame.ASH_ITEM_ID,
0.45,
)
except Exception as exc: # pylint: disable=broad-except
logger.Log(
"Warning",
f"{ConsoleFrontColor.YELLOW}注册闪烁粉尘共鸣配方失败: {exc}{ConsoleFrontColor.RESET}",
)
def _item_display_name( def _item_display_name(
self, self,
item_id: str, item_id: str,