refactor item ids
This commit is contained in:
@@ -89,7 +89,7 @@ def _load_auxiliaries() -> tuple[Dict[int, Auxiliary], Dict[str, Auxiliary]]:
|
||||
realm = Realm.Qi_Refinement
|
||||
|
||||
a = Auxiliary(
|
||||
id=get_int(row, "id"),
|
||||
id=get_int(row, "item_id"),
|
||||
name=get_str(row, "name"),
|
||||
realm=realm,
|
||||
desc=get_str(row, "desc"),
|
||||
@@ -100,6 +100,10 @@ def _load_auxiliaries() -> tuple[Dict[int, Auxiliary], Dict[str, Auxiliary]]:
|
||||
auxiliaries_by_id[a.id] = a
|
||||
auxiliaries_by_name[a.name] = a
|
||||
|
||||
# 注册到全局注册表
|
||||
from src.classes.item_registry import ItemRegistry
|
||||
ItemRegistry.register(a.id, a)
|
||||
|
||||
return auxiliaries_by_id, auxiliaries_by_name
|
||||
|
||||
|
||||
|
||||
@@ -166,7 +166,7 @@ def _load_elixirs() -> tuple[Dict[int, Elixir], Dict[str, List[Elixir]]]:
|
||||
effect_desc = format_effects_to_text(effects)
|
||||
|
||||
elixir = Elixir(
|
||||
id=elixir_id,
|
||||
id=get_int(row, "item_id"),
|
||||
name=name,
|
||||
realm=realm,
|
||||
type=elixir_type,
|
||||
@@ -176,12 +176,16 @@ def _load_elixirs() -> tuple[Dict[int, Elixir], Dict[str, List[Elixir]]]:
|
||||
effect_desc=effect_desc
|
||||
)
|
||||
|
||||
elixirs_by_id[elixir_id] = elixir
|
||||
elixirs_by_id[elixir.id] = elixir
|
||||
|
||||
if name not in elixirs_by_name:
|
||||
elixirs_by_name[name] = []
|
||||
elixirs_by_name[name].append(elixir)
|
||||
|
||||
# 注册到全局注册表
|
||||
from src.classes.item_registry import ItemRegistry
|
||||
ItemRegistry.register(elixir.id, elixir)
|
||||
|
||||
return elixirs_by_id, elixirs_by_name
|
||||
|
||||
|
||||
|
||||
24
src/classes/item_registry.py
Normal file
24
src/classes/item_registry.py
Normal file
@@ -0,0 +1,24 @@
|
||||
from typing import Dict, Type, TYPE_CHECKING, Optional
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from src.classes.item import Item
|
||||
|
||||
class ItemRegistry:
|
||||
"""全局物品注册表"""
|
||||
|
||||
_items_by_id: Dict[int, "Item"] = {}
|
||||
|
||||
@classmethod
|
||||
def register(cls, item_id: int, item: "Item"):
|
||||
if item_id in cls._items_by_id:
|
||||
# 允许重复注册(覆盖),但在开发环境中最好打印警告
|
||||
pass
|
||||
cls._items_by_id[item_id] = item
|
||||
|
||||
@classmethod
|
||||
def get(cls, item_id: int) -> Optional["Item"]:
|
||||
return cls._items_by_id.get(item_id)
|
||||
|
||||
@classmethod
|
||||
def get_all(cls) -> Dict[int, "Item"]:
|
||||
return cls._items_by_id
|
||||
@@ -215,19 +215,11 @@ class CultivateRegion(Region):
|
||||
@dataclass(eq=False)
|
||||
class CityRegion(Region, StoreMixin):
|
||||
"""城市区域"""
|
||||
sell_items: str = field(default="[]")
|
||||
sell_item_ids: list[int] = field(default_factory=list)
|
||||
|
||||
def __post_init__(self):
|
||||
super().__post_init__()
|
||||
try:
|
||||
import ast
|
||||
items_list = ast.literal_eval(self.sell_items)
|
||||
if isinstance(items_list, list):
|
||||
self.init_store(items_list)
|
||||
else:
|
||||
self.init_store([])
|
||||
except Exception:
|
||||
self.init_store([])
|
||||
self.init_store(self.sell_item_ids)
|
||||
|
||||
def get_region_type(self) -> str:
|
||||
return "city"
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
from collections import defaultdict
|
||||
from typing import Any, List
|
||||
from typing import Any, List, Union
|
||||
|
||||
from src.utils.resolution import resolve_query
|
||||
from src.classes.elixir import Elixir
|
||||
from src.classes.weapon import Weapon
|
||||
from src.classes.auxiliary import Auxiliary
|
||||
from src.classes.prices import prices
|
||||
from src.classes.item_registry import ItemRegistry
|
||||
|
||||
class StoreMixin:
|
||||
"""
|
||||
@@ -13,18 +14,23 @@ class StoreMixin:
|
||||
赋予区域售卖物品的能力
|
||||
"""
|
||||
|
||||
def init_store(self, item_names: list[str]):
|
||||
def init_store(self, item_ids: list[int]):
|
||||
"""
|
||||
初始化商店物品
|
||||
:param item_names: 物品名称列表
|
||||
:param item_ids: 物品ID列表
|
||||
"""
|
||||
self.store_items = []
|
||||
if not item_names:
|
||||
if not item_ids:
|
||||
return
|
||||
|
||||
for name in item_names:
|
||||
# 期望类型:丹药、武器、辅助
|
||||
res = resolve_query(name, expected_types=[Elixir, Weapon, Auxiliary])
|
||||
for item_id in item_ids:
|
||||
item = ItemRegistry.get(item_id)
|
||||
if item:
|
||||
self.store_items.append(item)
|
||||
else:
|
||||
# 兼容旧逻辑:如果列表中混入了字符串名称(虽然根据迁移脚本不应该发生)
|
||||
if isinstance(item_id, str):
|
||||
res = resolve_query(item_id, expected_types=[Elixir, Weapon, Auxiliary])
|
||||
if res.is_valid and res.obj:
|
||||
self.store_items.append(res.obj)
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ def _load_weapons() -> tuple[Dict[int, Weapon], Dict[str, Weapon]]:
|
||||
realm = Realm.Qi_Refinement
|
||||
|
||||
w = Weapon(
|
||||
id=get_int(row, "id"),
|
||||
id=get_int(row, "item_id"),
|
||||
name=get_str(row, "name"),
|
||||
weapon_type=weapon_type,
|
||||
realm=realm,
|
||||
@@ -105,6 +105,10 @@ def _load_weapons() -> tuple[Dict[int, Weapon], Dict[str, Weapon]]:
|
||||
weapons_by_id[w.id] = w
|
||||
weapons_by_name[w.name] = w
|
||||
|
||||
# 注册到全局注册表
|
||||
from src.classes.item_registry import ItemRegistry
|
||||
ItemRegistry.register(w.id, w)
|
||||
|
||||
return weapons_by_id, weapons_by_name
|
||||
|
||||
|
||||
|
||||
@@ -105,9 +105,16 @@ def _load_and_assign_regions(game_map: Map, region_coords: dict[int, list[tuple[
|
||||
params["essence_type"] = EssenceType.from_str(get_str(row, "root_type"))
|
||||
params["essence_density"] = get_int(row, "root_density")
|
||||
elif type_tag == "city":
|
||||
sell_items_str = get_str(row, "sell_items")
|
||||
if sell_items_str:
|
||||
params["sell_items"] = sell_items_str
|
||||
sell_ids_str = get_str(row, "sell_item_ids")
|
||||
if sell_ids_str:
|
||||
try:
|
||||
import ast
|
||||
ids = ast.literal_eval(sell_ids_str)
|
||||
if isinstance(ids, list):
|
||||
params["sell_item_ids"] = ids
|
||||
except Exception as e:
|
||||
print(f"Error parsing sell_item_ids for city {rid}: {e}")
|
||||
|
||||
elif type_tag == "sect":
|
||||
sect_id = get_int(row, "sect_id")
|
||||
params["sect_id"] = sect_id
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
id,name,grade,desc,effects
|
||||
item_id,name,grade,desc,effects
|
||||
,名称,等级(练气/筑基/金丹/元婴),描述/提示词,JSON形式(支持宽松格式,见effects.py说明)
|
||||
2001,木灵甲,筑基,以灵木纤维编织,生机盎然,防御尚可.,{damage_reduction: 0.08}
|
||||
2002,血菩提,筑基,生于火麒麟滴血之处,重伤必治,无伤增功.,{extra_hp_recovery_rate: 0.3}
|
||||
@@ -11,18 +11,18 @@ id,name,grade,desc,effects
|
||||
2009,金丝软甲,筑基,刀枪不入,水火不侵,贴身软甲.,"{extra_max_hp: 100, damage_reduction: 0.05}"
|
||||
2010,寒玉床,筑基,古墓派至宝,在此床上修炼,事半功倍,且无心魔之虞.,{cultivate_duration_reduction: 0.2}
|
||||
2011,无相面具,筑基,千人千面,不仅掩盖容貌,更能掩盖气息.,{extra_plunder_multiplier: 0.5}
|
||||
3001,神风舟,金丹,飞行法器,速度极快,居家旅行杀人越货必备.,"{extra_move_step: 2, extra_escape_success_rate: 0.15}"
|
||||
3002,昆仑镜,金丹,上古神器,拥有穿梭时空之力,此为仿品,仅能窥探远方.,{extra_observation_radius: 2}
|
||||
3003,掌天瓶,元婴,夺天地之造化,聚日月之精华,催熟万物.,"{extra_cultivate_exp: 150, cultivate_duration_reduction: 0.2}"
|
||||
3004,龙凤呈祥戒,金丹,龙凤和鸣,心意相通,双修进境一日千里.,{extra_dual_cultivation_exp: 100}
|
||||
3005,隐形披风,金丹,披上后身形尽隐,连神识也难以察觉.,"{extra_move_step: 1, extra_escape_success_rate: 0.2}"
|
||||
3006,御兽环,金丹,套在妖兽颈上,任其凶焰滔天,也要乖乖听命.,{extra_catch_success_rate: 0.1}
|
||||
3007,太虚甲,金丹,太虚幻境所化,万法不沾,防御力惊人.,"{damage_reduction: 0.2, extra_max_hp: 200}"
|
||||
3008,八卦炉,金丹,仿太上老君炼丹炉,丹成九转,药效倍增.,"{extra_hp_recovery_rate: 0.5, extra_refine_success_rate: 0.15}"
|
||||
3009,聚宝盆,金丹,放入一文,取出万贯,财源滚滚.,"{extra_item_sell_price_multiplier: 0.2, extra_fortune_probability: 0.01, shop_buy_price_reduction: 0.2}"
|
||||
3010,天地烘炉,金丹,以天地为炉,造化为工,炼制万物.,"{extra_weapon_upgrade_chance: 0.15, extra_cast_success_rate: 0.1, extra_refine_success_rate: 0.1}"
|
||||
3011,六道剑匣,金丹,背负六道,剑出轮回,悟剑良伴.,"{extra_breakthrough_success_rate: 0.2, extra_cultivate_exp: 100}"
|
||||
3012,传国玉玺,元婴,受命于天,既寿永昌。皇威浩荡,震慑宵小.,{realm_suppression_bonus: 0.15}
|
||||
3013,灵眼之泉,金丹,可移动的灵气之源,随身携带的洞天福地.,"{cultivate_duration_reduction: 0.3, extra_cultivate_exp: 50}"
|
||||
3014,万魂幡,元婴,血海不枯,冥河不死。极度邪恶的掠夺法宝.,"{legal_actions: ['DevourMortals'], extra_plunder_multiplier: 1.0, realm_suppression_bonus: 0.15, extra_battle_strength_points: 'avatar.auxiliary.special_data.get(""devoured_souls"", 0) // 100 * 0.1'}"
|
||||
3015,神木王鼎,元婴,木系至宝,不仅可炼制神丹,鼎中更自成一界,可催熟灵药。,"{extra_refine_success_rate: 0.25, cultivate_duration_reduction: 0.15}"
|
||||
2051,神风舟,金丹,飞行法器,速度极快,居家旅行杀人越货必备.,"{extra_move_step: 2, extra_escape_success_rate: 0.15}"
|
||||
2052,昆仑镜,金丹,上古神器,拥有穿梭时空之力,此为仿品,仅能窥探远方.,{extra_observation_radius: 2}
|
||||
2053,掌天瓶,元婴,夺天地之造化,聚日月之精华,催熟万物.,"{extra_cultivate_exp: 150, cultivate_duration_reduction: 0.2}"
|
||||
2054,龙凤呈祥戒,金丹,龙凤和鸣,心意相通,双修进境一日千里.,{extra_dual_cultivation_exp: 100}
|
||||
2055,隐形披风,金丹,披上后身形尽隐,连神识也难以察觉.,"{extra_move_step: 1, extra_escape_success_rate: 0.2}"
|
||||
2056,御兽环,金丹,套在妖兽颈上,任其凶焰滔天,也要乖乖听命.,{extra_catch_success_rate: 0.1}
|
||||
2057,太虚甲,金丹,太虚幻境所化,万法不沾,防御力惊人.,"{damage_reduction: 0.2, extra_max_hp: 200}"
|
||||
2058,八卦炉,金丹,仿太上老君炼丹炉,丹成九转,药效倍增.,"{extra_hp_recovery_rate: 0.5, extra_refine_success_rate: 0.15}"
|
||||
2059,聚宝盆,金丹,放入一文,取出万贯,财源滚滚.,"{extra_item_sell_price_multiplier: 0.2, extra_fortune_probability: 0.01, shop_buy_price_reduction: 0.2}"
|
||||
2060,天地烘炉,金丹,以天地为炉,造化为工,炼制万物.,"{extra_weapon_upgrade_chance: 0.15, extra_cast_success_rate: 0.1, extra_refine_success_rate: 0.1}"
|
||||
2061,六道剑匣,金丹,背负六道,剑出轮回,悟剑良伴.,"{extra_breakthrough_success_rate: 0.2, extra_cultivate_exp: 100}"
|
||||
2062,传国玉玺,元婴,受命于天,既寿永昌。皇威浩荡,震慑宵小.,{realm_suppression_bonus: 0.15}
|
||||
2063,灵眼之泉,金丹,可移动的灵气之源,随身携带的洞天福地.,"{cultivate_duration_reduction: 0.3, extra_cultivate_exp: 50}"
|
||||
2064,万魂幡,元婴,血海不枯,冥河不死。极度邪恶的掠夺法宝.,"{legal_actions: ['DevourMortals'], extra_plunder_multiplier: 1.0, realm_suppression_bonus: 0.15, extra_battle_strength_points: 'avatar.auxiliary.special_data.get(""devoured_souls"", 0) // 100 * 0.1'}"
|
||||
2065,神木王鼎,元婴,木系至宝,不仅可炼制神丹,鼎中更自成一界,可催熟灵药。,"{extra_refine_success_rate: 0.25, cultivate_duration_reduction: 0.15}"
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
id,name,desc,sell_items
|
||||
id,name,desc,sell_item_ids
|
||||
ID必须以3开头,,,
|
||||
301,青云城,繁华都市,人烟稠密,商贾云集。此地是交易天材地宝、寻找机缘的重要场所。,"['练气破境丹', '练气长生丹']"
|
||||
302,沙月城,沙漠绿洲中的贸易重镇,各路商队在此集结,是修士补给和交流的重要据点。,"['练气燃血丹', '练气回春丹']"
|
||||
303,翠林城,森林深处的修仙重镇,众多修士在此栖居,是修炼和炼宝的理想之地。,"['练气剑', '练气刀', '练气枪']"
|
||||
304,沧澜城,坐落于大河入海口的三角洲,百川归海,水运昌隆,是水系修士往来最为频繁的宝地。,"['练气棍', '练气扇', '练气鞭']"
|
||||
305,揽月城,屹立于连绵群山之巅,终年云雾缭绕,灵气纯净,是苦修之士感悟天道的绝佳场所。,"['练气琴', '练气笛', '练气暗器']"
|
||||
301,青云城,繁华都市,人烟稠密,商贾云集。此地是交易天材地宝、寻找机缘的重要场所。,"[3001, 3005]"
|
||||
302,沙月城,沙漠绿洲中的贸易重镇,各路商队在此集结,是修士补给和交流的重要据点。,"[3009, 3013]"
|
||||
303,翠林城,森林深处的修仙重镇,众多修士在此栖居,是修炼和炼宝的理想之地。,"[1001, 1002, 1003]"
|
||||
304,沧澜城,坐落于大河入海口的三角洲,百川归海,水运昌隆,是水系修士往来最为频繁的宝地。,"[1004, 1005, 1006]"
|
||||
305,揽月城,屹立于连绵群山之巅,终年云雾缭绕,灵气纯净,是苦修之士感悟天道的绝佳场所。,"[1007, 1008, 1009]"
|
||||
|
||||
|
@@ -1,17 +1,17 @@
|
||||
id,name,realm,type,desc,price,effects
|
||||
item_id,name,realm,type,desc,price,effects
|
||||
,名称,境界(练气/筑基/金丹/元婴),类型(Breakthrough/Lifespan/BurnBlood/Heal),描述,价格,JSON形式Effects
|
||||
1,练气破境丹,练气,Breakthrough,凝聚灵气,辅助练气期修士突破瓶颈的丹药(药效5年)。,50,"{duration_month: 60, extra_breakthrough_success_rate: 0.1}"
|
||||
2,筑基破境丹,筑基,Breakthrough,蕴含筑基真意,辅助筑基期修士突破瓶颈的灵丹(药效5年)。,200,"{duration_month: 60, extra_breakthrough_success_rate: 0.1}"
|
||||
3,金丹破境丹,金丹,Breakthrough,凝结金丹之气,辅助金丹期修士碎丹成婴(药效5年)。,500,"{duration_month: 60, extra_breakthrough_success_rate: 0.1}"
|
||||
5,练气长生丹,练气,Lifespan,采用凡间珍草炼制,略微延缓衰老(限服一颗)。,100,"{extra_max_lifespan: 5}"
|
||||
6,筑基长生丹,筑基,Lifespan,取天地灵草炼制,可延寿十载(限服一颗)。,500,"{extra_max_lifespan: 10}"
|
||||
7,金丹长生丹,金丹,Lifespan,夺天地造化,凡人服之立毙,金丹修士服之延寿半甲子(限服一颗)。,200,"{extra_max_lifespan: 30}"
|
||||
8,元婴长生丹,元婴,Lifespan,蕴含一丝长生之气,元婴老怪以此续命(限服一颗)。,5000,"{extra_max_lifespan: 100}"
|
||||
9,练气燃血丹,练气,BurnBlood,燃烧精血换取短暂爆发。3年内战力提升,但10年内经脉受损战力下降。,50,"[{duration_month: 36, extra_battle_strength_points: 3}, {duration_month: 120, extra_battle_strength_points: -1}]"
|
||||
10,筑基燃血丹,筑基,BurnBlood,激发潜能的猛药。3年内战力大增,但10年内虚弱。,100,"[{duration_month: 36, extra_battle_strength_points: 5}, {duration_month: 120, extra_battle_strength_points: -2}]"
|
||||
11,金丹燃血丹,金丹,BurnBlood,金丹修士拼命时的选择。3年内战力暴涨,但10年内重伤。,200,"[{duration_month: 36, extra_battle_strength_points: 7}, {duration_month: 120, extra_battle_strength_points: -3}]"
|
||||
12,元婴燃血丹,元婴,BurnBlood,燃烧元婴本源。3年内获得毁天灭地的力量,但10年内几乎废人。,300,"[{duration_month: 36, extra_battle_strength_points: 10}, {duration_month: 120, extra_battle_strength_points: -5}]"
|
||||
13,练气回春丹,练气,Heal,普通的疗伤丹药,可恢复练气期修士的伤势(持续5年)。,20,"{duration_month: 60, extra_hp_recovery_rate: 0.5}"
|
||||
14,筑基回春丹,筑基,Heal,药力温和醇厚,能快速愈合筑基期修士的肉身损伤(持续5年)。,50,"{duration_month: 60, extra_hp_recovery_rate: 1.0}"
|
||||
15,金丹回春丹,金丹,Heal,蕴含生机之力,疗伤圣药(持续5年)。,100,"{duration_month: 60, extra_hp_recovery_rate: 2.0}"
|
||||
16,元婴回春丹,元婴,Heal,蕴含造化生机,肉身修复极快(持续5年)。,200,"{duration_month: 60, extra_hp_recovery_rate: 5.0}"
|
||||
3001,练气破境丹,练气,Breakthrough,凝聚灵气,辅助练气期修士突破瓶颈的丹药(药效5年)。,50,"{duration_month: 60, extra_breakthrough_success_rate: 0.1}"
|
||||
3002,筑基破境丹,筑基,Breakthrough,蕴含筑基真意,辅助筑基期修士突破瓶颈的灵丹(药效5年)。,200,"{duration_month: 60, extra_breakthrough_success_rate: 0.1}"
|
||||
3003,金丹破境丹,金丹,Breakthrough,凝结金丹之气,辅助金丹期修士碎丹成婴(药效5年)。,500,"{duration_month: 60, extra_breakthrough_success_rate: 0.1}"
|
||||
3005,练气长生丹,练气,Lifespan,采用凡间珍草炼制,略微延缓衰老(限服一颗)。,100,{extra_max_lifespan: 5}
|
||||
3006,筑基长生丹,筑基,Lifespan,取天地灵草炼制,可延寿十载(限服一颗)。,500,{extra_max_lifespan: 10}
|
||||
3007,金丹长生丹,金丹,Lifespan,夺天地造化,凡人服之立毙,金丹修士服之延寿半甲子(限服一颗)。,200,{extra_max_lifespan: 30}
|
||||
3008,元婴长生丹,元婴,Lifespan,蕴含一丝长生之气,元婴老怪以此续命(限服一颗)。,5000,{extra_max_lifespan: 100}
|
||||
3009,练气燃血丹,练气,BurnBlood,燃烧精血换取短暂爆发。3年内战力提升,但10年内经脉受损战力下降。,50,"[{duration_month: 36, extra_battle_strength_points: 3}, {duration_month: 120, extra_battle_strength_points: -1}]"
|
||||
3010,筑基燃血丹,筑基,BurnBlood,激发潜能的猛药。3年内战力大增,但10年内虚弱。,100,"[{duration_month: 36, extra_battle_strength_points: 5}, {duration_month: 120, extra_battle_strength_points: -2}]"
|
||||
3011,金丹燃血丹,金丹,BurnBlood,金丹修士拼命时的选择。3年内战力暴涨,但10年内重伤。,200,"[{duration_month: 36, extra_battle_strength_points: 7}, {duration_month: 120, extra_battle_strength_points: -3}]"
|
||||
3012,元婴燃血丹,元婴,BurnBlood,燃烧元婴本源。3年内获得毁天灭地的力量,但10年内几乎废人。,300,"[{duration_month: 36, extra_battle_strength_points: 10}, {duration_month: 120, extra_battle_strength_points: -5}]"
|
||||
3013,练气回春丹,练气,Heal,普通的疗伤丹药,可恢复练气期修士的伤势(持续5年)。,20,"{duration_month: 60, extra_hp_recovery_rate: 0.5}"
|
||||
3014,筑基回春丹,筑基,Heal,药力温和醇厚,能快速愈合筑基期修士的肉身损伤(持续5年)。,50,"{duration_month: 60, extra_hp_recovery_rate: 1.0}"
|
||||
3015,金丹回春丹,金丹,Heal,蕴含生机之力,疗伤圣药(持续5年)。,100,"{duration_month: 60, extra_hp_recovery_rate: 2.0}"
|
||||
3016,元婴回春丹,元婴,Heal,蕴含造化生机,肉身修复极快(持续5年)。,200,"{duration_month: 60, extra_hp_recovery_rate: 5.0}"
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
id,name,weapon_type,grade,desc,effects
|
||||
item_id,name,weapon_type,grade,desc,effects
|
||||
,名称,兵器类型,等级(练气/筑基/金丹/元婴),描述/提示词,JSON形式(支持宽松格式,见effects.py说明)
|
||||
1001,练气剑,剑,练气,市井铁匠铺打造的铁剑,勉强能用。,{extra_battle_strength_points: 1}
|
||||
1002,练气刀,刀,练气,厚背砍刀,寻常武夫的最爱。,{extra_battle_strength_points: 1}
|
||||
@@ -9,27 +9,27 @@ id,name,weapon_type,grade,desc,effects
|
||||
1007,练气琴,琴,练气,桐木制成的古琴,音色尚可。,{extra_battle_strength_points: 1}
|
||||
1008,练气笛,笛,练气,紫竹削制,声音清脆。,{extra_battle_strength_points: 1}
|
||||
1009,练气暗器,暗器,练气,随处可见的铁制暗器。,{extra_battle_strength_points: 1}
|
||||
2001,青霜剑,剑,筑基,剑气森寒。,{extra_battle_strength_points: 2}
|
||||
2002,井中月,刀,筑基,刀光如井中映月,虚实难测。,{extra_battle_strength_points: 2}
|
||||
2003,火尖枪,枪,筑基,枪头隐有火光,能引动凡火。,"{extra_battle_strength_points: 2, extra_max_hp: 50}"
|
||||
2004,囚龙棒,棍,筑基,精铁铸造,重达千斤,力大者可用。,"{extra_battle_strength_points: 2, extra_max_hp: 50}"
|
||||
2005,桃花扇,扇,筑基,桃花影落飞神剑,扇面绘有桃花,暗藏杀机。,"{extra_battle_strength_points: 2, extra_observation_radius: 1}"
|
||||
2006,打神鞭,鞭,筑基,仿品,虽无打神之能,却可伤人神魂。,{extra_battle_strength_points: 2}
|
||||
2007,天魔琴,琴,筑基,琴音魔性,扰乱心智。,"{extra_battle_strength_points: 2, cultivate_duration_reduction: 0.1}"
|
||||
2008,鬼笛陈情,笛,筑基,据说能以此笛操控尸傀。,"{extra_battle_strength_points: 2, cultivate_duration_reduction: 0.1}"
|
||||
2009,无影针,暗器,筑基,细若牛毛,来去无影,防不胜防。,{extra_battle_strength_points: 2}
|
||||
2010,万兽笛,笛,筑基,百兽宗秘制,笛声可安抚或激怒野兽。,"[{extra_battle_strength_points: 1}, {when: 'avatar.spirit_animal is not None', extra_battle_strength_points: 2}]"
|
||||
2011,血饮狂刀,刀,筑基,刀身赤红,似渴望饮血。,{extra_battle_strength_points: 2}
|
||||
2012,玄铁重剑,剑,筑基,重剑无锋,大巧不工,独孤求败。,"{extra_battle_strength_points: 2, extra_max_hp: 100}"
|
||||
2013,紫薇软剑,剑,筑基,软若束带,动若灵蛇。,"{extra_battle_strength_points: 2, extra_escape_success_rate: 0.1}"
|
||||
2014,水火囚龙棍,棍,筑基,镇魂宗制式兵器,水火相济,困敌锁魂。,{extra_battle_strength_points: 2}
|
||||
3001,青竹蜂云剑,剑,金丹,成套飞剑,内蕴辟邪神雷,克制天下邪祟。,{extra_battle_strength_points: 3}
|
||||
3002,随心铁杆兵,棍,金丹,六耳猕猴的兵器,随心变化,大小如意。,"{extra_battle_strength_points: 3, extra_observation_radius: 1}"
|
||||
3003,五火七禽扇,扇,金丹,扇面有空中火、石中火、木中火等五火,一扇灰飞烟灭。,"{extra_battle_strength_points: 3, extra_observation_radius: 2}"
|
||||
3004,弑神枪,枪,元婴,杀气滔天,曾染魔神之血,枪出无回。,{extra_battle_strength_points: '3 + avatar.weapon_proficiency * 0.02'}
|
||||
3005,赤锋矛,枪,元婴,赤锋矛,不朽盾,斩尽仙王灭九天。,"[{extra_battle_strength_points: 3}, {when: 'avatar.cultivation_progress.level >= 30', extra_battle_strength_points: 2, realm_suppression_bonus: 0.1}]"
|
||||
3006,斩仙飞刀,暗器,金丹,红葫芦内藏一线毫光,有眉有目。请宝贝转身,神鬼难逃。,"{extra_battle_strength_points: 3, extra_observation_radius: 1, extra_escape_success_rate: 0.15}"
|
||||
3007,诛仙剑,剑,元婴,非铜非铁亦非钢,曾在须弥山下藏。利气直透九重天。,"{extra_battle_strength_points: 4, realm_suppression_bonus: 0.1}"
|
||||
3008,干将莫邪,剑,金丹,挚情之剑,一雌一雄,分则为杀,合则为情。,"{extra_battle_strength_points: 3, extra_max_hp: 150}"
|
||||
3009,芭蕉扇,扇,金丹,太阴之精叶,一扇息火,二扇生风,三扇下雨。,"{extra_battle_strength_points: 3, extra_observation_radius: 2, extra_move_step: 1}"
|
||||
3010,紫金降魔杵,棍,金丹,韦护的兵器,虽然轻灵,打在人身却重如泰山。,"{extra_battle_strength_points: 3, damage_reduction: 0.1}"
|
||||
1021,青霜剑,剑,筑基,剑气森寒。,{extra_battle_strength_points: 2}
|
||||
1022,井中月,刀,筑基,刀光如井中映月,虚实难测。,{extra_battle_strength_points: 2}
|
||||
1023,火尖枪,枪,筑基,枪头隐有火光,能引动凡火。,"{extra_battle_strength_points: 2, extra_max_hp: 50}"
|
||||
1024,囚龙棒,棍,筑基,精铁铸造,重达千斤,力大者可用。,"{extra_battle_strength_points: 2, extra_max_hp: 50}"
|
||||
1025,桃花扇,扇,筑基,桃花影落飞神剑,扇面绘有桃花,暗藏杀机。,"{extra_battle_strength_points: 2, extra_observation_radius: 1}"
|
||||
1026,打神鞭,鞭,筑基,仿品,虽无打神之能,却可伤人神魂。,{extra_battle_strength_points: 2}
|
||||
1027,天魔琴,琴,筑基,琴音魔性,扰乱心智。,"{extra_battle_strength_points: 2, cultivate_duration_reduction: 0.1}"
|
||||
1028,鬼笛陈情,笛,筑基,据说能以此笛操控尸傀。,"{extra_battle_strength_points: 2, cultivate_duration_reduction: 0.1}"
|
||||
1029,无影针,暗器,筑基,细若牛毛,来去无影,防不胜防。,{extra_battle_strength_points: 2}
|
||||
1030,万兽笛,笛,筑基,百兽宗秘制,笛声可安抚或激怒野兽。,"[{extra_battle_strength_points: 1}, {when: 'avatar.spirit_animal is not None', extra_battle_strength_points: 2}]"
|
||||
1031,血饮狂刀,刀,筑基,刀身赤红,似渴望饮血。,{extra_battle_strength_points: 2}
|
||||
1032,玄铁重剑,剑,筑基,重剑无锋,大巧不工,独孤求败。,"{extra_battle_strength_points: 2, extra_max_hp: 100}"
|
||||
1033,紫薇软剑,剑,筑基,软若束带,动若灵蛇。,"{extra_battle_strength_points: 2, extra_escape_success_rate: 0.1}"
|
||||
1034,水火囚龙棍,棍,筑基,镇魂宗制式兵器,水火相济,困敌锁魂。,{extra_battle_strength_points: 2}
|
||||
1051,青竹蜂云剑,剑,金丹,成套飞剑,内蕴辟邪神雷,克制天下邪祟。,{extra_battle_strength_points: 3}
|
||||
1052,随心铁杆兵,棍,金丹,六耳猕猴的兵器,随心变化,大小如意。,"{extra_battle_strength_points: 3, extra_observation_radius: 1}"
|
||||
1053,五火七禽扇,扇,金丹,扇面有空中火、石中火、木中火等五火,一扇灰飞烟灭。,"{extra_battle_strength_points: 3, extra_observation_radius: 2}"
|
||||
1054,弑神枪,枪,元婴,杀气滔天,曾染魔神之血,枪出无回。,{extra_battle_strength_points: '3 + avatar.weapon_proficiency * 0.02'}
|
||||
1055,赤锋矛,枪,元婴,赤锋矛,不朽盾,斩尽仙王灭九天。,"[{extra_battle_strength_points: 3}, {when: 'avatar.cultivation_progress.level >= 30', extra_battle_strength_points: 2, realm_suppression_bonus: 0.1}]"
|
||||
1056,斩仙飞刀,暗器,金丹,红葫芦内藏一线毫光,有眉有目。请宝贝转身,神鬼难逃。,"{extra_battle_strength_points: 3, extra_observation_radius: 1, extra_escape_success_rate: 0.15}"
|
||||
1057,诛仙剑,剑,元婴,非铜非铁亦非钢,曾在须弥山下藏。利气直透九重天。,"{extra_battle_strength_points: 4, realm_suppression_bonus: 0.1}"
|
||||
1058,干将莫邪,剑,金丹,挚情之剑,一雌一雄,分则为杀,合则为情。,"{extra_battle_strength_points: 3, extra_max_hp: 150}"
|
||||
1059,芭蕉扇,扇,金丹,太阴之精叶,一扇息火,二扇生风,三扇下雨。,"{extra_battle_strength_points: 3, extra_observation_radius: 2, extra_move_step: 1}"
|
||||
1060,紫金降魔杵,棍,金丹,韦护的兵器,虽然轻灵,打在人身却重如泰山。,"{extra_battle_strength_points: 3, damage_reduction: 0.1}"
|
||||
|
||||
|
151
tests/test_item_registry.py
Normal file
151
tests/test_item_registry.py
Normal file
@@ -0,0 +1,151 @@
|
||||
import pytest
|
||||
from src.classes.item import Item
|
||||
from src.classes.item_registry import ItemRegistry
|
||||
from src.classes.weapon import Weapon
|
||||
from src.classes.auxiliary import Auxiliary
|
||||
from src.classes.elixir import Elixir
|
||||
from src.classes.store import StoreMixin
|
||||
from src.classes.cultivation import Realm
|
||||
from src.classes.weapon_type import WeaponType
|
||||
from src.classes.elixir import ElixirType
|
||||
|
||||
# Mock concrete implementations for testing
|
||||
class MockItem(Item):
|
||||
def __init__(self, id, name):
|
||||
self.id = id
|
||||
self.name = name
|
||||
|
||||
# --- Test Item Registry ---
|
||||
|
||||
def test_registry_registration():
|
||||
"""Test that items can be registered and retrieved."""
|
||||
# Clear registry for test isolation (though usually not exposed, we access _items_by_id)
|
||||
original_registry = ItemRegistry._items_by_id.copy()
|
||||
ItemRegistry._items_by_id.clear()
|
||||
|
||||
try:
|
||||
item1 = MockItem(1001, "TestItem1")
|
||||
item2 = MockItem(1002, "TestItem2")
|
||||
|
||||
ItemRegistry.register(item1.id, item1)
|
||||
ItemRegistry.register(item2.id, item2)
|
||||
|
||||
assert ItemRegistry.get(1001) == item1
|
||||
assert ItemRegistry.get(1002) == item2
|
||||
assert ItemRegistry.get(9999) is None
|
||||
|
||||
all_items = ItemRegistry.get_all()
|
||||
assert len(all_items) == 2
|
||||
assert 1001 in all_items
|
||||
assert 1002 in all_items
|
||||
|
||||
finally:
|
||||
# Restore registry
|
||||
ItemRegistry._items_by_id = original_registry
|
||||
|
||||
def test_registry_overwrite():
|
||||
"""Test that registering an ID again overwrites the previous item."""
|
||||
original_registry = ItemRegistry._items_by_id.copy()
|
||||
ItemRegistry._items_by_id.clear()
|
||||
|
||||
try:
|
||||
item1 = MockItem(1001, "ItemV1")
|
||||
item2 = MockItem(1001, "ItemV2")
|
||||
|
||||
ItemRegistry.register(1001, item1)
|
||||
assert ItemRegistry.get(1001).name == "ItemV1"
|
||||
|
||||
ItemRegistry.register(1001, item2)
|
||||
assert ItemRegistry.get(1001).name == "ItemV2"
|
||||
|
||||
finally:
|
||||
ItemRegistry._items_by_id = original_registry
|
||||
|
||||
# --- Test Store Mixin with Item IDs ---
|
||||
|
||||
class MockShop(StoreMixin):
|
||||
def __init__(self):
|
||||
self.name = "TestShop"
|
||||
|
||||
def test_store_init_with_ids(mock_item_data):
|
||||
"""Test initializing a store with item IDs."""
|
||||
original_registry = ItemRegistry._items_by_id.copy()
|
||||
ItemRegistry._items_by_id.clear()
|
||||
|
||||
try:
|
||||
# Setup registry
|
||||
weapon = mock_item_data["obj_weapon"] # ID 201
|
||||
elixir = mock_item_data["obj_elixir"] # ID 1
|
||||
|
||||
ItemRegistry.register(weapon.id, weapon)
|
||||
ItemRegistry.register(elixir.id, elixir)
|
||||
|
||||
# Init shop
|
||||
shop = MockShop()
|
||||
shop.init_store([weapon.id, elixir.id])
|
||||
|
||||
assert len(shop.store_items) == 2
|
||||
assert any(i.name == weapon.name for i in shop.store_items)
|
||||
assert any(i.name == elixir.name for i in shop.store_items)
|
||||
|
||||
# Test store info
|
||||
info = shop.get_store_info()
|
||||
assert "出售:" in info
|
||||
assert weapon.name in info
|
||||
assert elixir.name in info
|
||||
|
||||
finally:
|
||||
ItemRegistry._items_by_id = original_registry
|
||||
|
||||
def test_store_init_mixed_ids_and_names(mock_item_data):
|
||||
"""Test backward compatibility: store init with both IDs and names."""
|
||||
original_registry = ItemRegistry._items_by_id.copy()
|
||||
ItemRegistry._items_by_id.clear()
|
||||
|
||||
try:
|
||||
# We need `resolve_query` to work for names, which relies on
|
||||
# weapons_by_name etc. populated in conftest or manually here.
|
||||
# Since we are mocking, we might need to patch resolve_query or ensure global dicts are populated.
|
||||
# For simplicity, we assume `resolve_query` logic works if global dicts are set.
|
||||
# But `mock_item_data` objects are fresh and NOT in global dicts by default unless we put them there.
|
||||
|
||||
weapon = mock_item_data["obj_weapon"]
|
||||
weapon_id = weapon.id
|
||||
|
||||
# Register weapon by ID
|
||||
ItemRegistry.register(weapon_id, weapon)
|
||||
|
||||
# Prepare an item for Name lookup (not in Registry)
|
||||
# We need to mock `src.utils.resolution.resolve_query` or make `resolve_query` find it.
|
||||
# Ideally, `StoreMixin` uses `resolve_query` for strings.
|
||||
|
||||
from src.classes.weapon import weapons_by_name
|
||||
weapons_by_name[weapon.name] = weapon
|
||||
|
||||
shop = MockShop()
|
||||
# Init with ID for weapon, and Name for weapon (redundant but testing logic)
|
||||
shop.init_store([weapon_id, weapon.name])
|
||||
|
||||
# Should contain two instances of the same weapon (one found by ID, one by Name)
|
||||
assert len(shop.store_items) == 2
|
||||
assert shop.store_items[0] == weapon
|
||||
assert shop.store_items[1] == weapon
|
||||
|
||||
finally:
|
||||
ItemRegistry._items_by_id = original_registry
|
||||
|
||||
# --- Test Item Instantiation ---
|
||||
|
||||
def test_item_instantiation():
|
||||
"""Test the Item.instantiate() method."""
|
||||
original = MockItem(1, "Original")
|
||||
original.some_attr = [1, 2, 3]
|
||||
|
||||
clone = original.instantiate()
|
||||
|
||||
assert clone is not original
|
||||
assert clone.id == original.id
|
||||
assert clone.name == original.name
|
||||
assert clone.some_attr == original.some_attr
|
||||
assert clone.some_attr is not original.some_attr # Deep copy check
|
||||
|
||||
Reference in New Issue
Block a user