rename item -> material & refactor buying action
This commit is contained in:
@@ -26,7 +26,7 @@ from src.classes.event import Event
|
||||
from src.classes.action_runtime import ActionPlan, ActionInstance
|
||||
from src.classes.alignment import Alignment
|
||||
from src.classes.persona import Persona, get_random_compatible_personas
|
||||
from src.classes.item import Item
|
||||
from src.classes.material import Material
|
||||
from src.classes.weapon import Weapon
|
||||
from src.classes.auxiliary import Auxiliary
|
||||
from src.classes.magic_stone import MagicStone
|
||||
@@ -96,7 +96,7 @@ class Avatar(
|
||||
short_term_objective: str = ""
|
||||
long_term_objective: Optional[LongTermObjective] = None
|
||||
magic_stone: MagicStone = field(default_factory=lambda: MagicStone(0))
|
||||
items: dict[Item, int] = field(default_factory=dict)
|
||||
materials: dict[Material, int] = field(default_factory=dict)
|
||||
hp: HP = field(default_factory=lambda: HP(0, 0))
|
||||
relations: dict["Avatar", Relation] = field(default_factory=dict)
|
||||
alignment: Alignment | None = None
|
||||
|
||||
@@ -50,7 +50,7 @@ def get_avatar_info(avatar: "Avatar", detailed: bool = False) -> dict:
|
||||
technique_info = avatar.technique.get_detailed_info() if avatar.technique is not None else "无"
|
||||
cultivation_info = avatar.cultivation_progress.get_detailed_info()
|
||||
personas_info = ", ".join([p.get_detailed_info() for p in avatar.personas]) if avatar.personas else "无"
|
||||
items_info = ",".join([f"{item.get_detailed_info()}x{quantity}" for item, quantity in avatar.items.items()]) if avatar.items else "无"
|
||||
materials_info = ",".join([f"{mat.get_detailed_info()}x{quantity}" for mat, quantity in avatar.materials.items()]) if avatar.materials else "无"
|
||||
appearance_info = avatar.appearance.get_detailed_info(avatar.gender)
|
||||
spirit_animal_info = avatar.spirit_animal.get_info() if avatar.spirit_animal is not None else "无"
|
||||
else:
|
||||
@@ -63,7 +63,7 @@ def get_avatar_info(avatar: "Avatar", detailed: bool = False) -> dict:
|
||||
technique_info = avatar.technique.get_info() if avatar.technique is not None else "无"
|
||||
cultivation_info = avatar.cultivation_progress.get_info()
|
||||
personas_info = ", ".join([p.get_detailed_info() for p in avatar.personas]) if avatar.personas else "无"
|
||||
items_info = ",".join([f"{item.get_info()}x{quantity}" for item, quantity in avatar.items.items()]) if avatar.items else "无"
|
||||
materials_info = ",".join([f"{mat.get_info()}x{quantity}" for mat, quantity in avatar.materials.items()]) if avatar.materials else "无"
|
||||
appearance_info = avatar.appearance.get_info()
|
||||
spirit_animal_info = avatar.spirit_animal.get_info() if avatar.spirit_animal is not None else "无"
|
||||
|
||||
@@ -81,7 +81,7 @@ def get_avatar_info(avatar: "Avatar", detailed: bool = False) -> dict:
|
||||
"功法": technique_info,
|
||||
"境界": cultivation_info,
|
||||
"特质": personas_info,
|
||||
"物品": items_info,
|
||||
"材料": materials_info,
|
||||
"外貌": appearance_info,
|
||||
"兵器": weapon_info,
|
||||
"辅助装备": auxiliary_info,
|
||||
@@ -185,13 +185,13 @@ def get_avatar_structured_info(avatar: "Avatar") -> dict:
|
||||
else:
|
||||
info["auxiliary"] = None
|
||||
|
||||
# 5. 物品 (Items)
|
||||
items_list = []
|
||||
for item, count in avatar.items.items():
|
||||
i_info = item.get_structured_info()
|
||||
i_info["count"] = count
|
||||
items_list.append(i_info)
|
||||
info["items"] = items_list
|
||||
# 5. 材料 (Materials)
|
||||
materials_list = []
|
||||
for material, count in avatar.materials.items():
|
||||
m_info = material.get_structured_info()
|
||||
m_info["count"] = count
|
||||
materials_list.append(m_info)
|
||||
info["materials"] = materials_list
|
||||
|
||||
# 6. 关系 (Relations)
|
||||
relations_list = []
|
||||
|
||||
@@ -3,73 +3,74 @@ Avatar 物品与装备管理 Mixin
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
from typing import TYPE_CHECKING, Optional, Any, Union
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from src.classes.avatar.core import Avatar
|
||||
from src.classes.item import Item
|
||||
from src.classes.material import Material
|
||||
from src.classes.weapon import Weapon
|
||||
from src.classes.auxiliary import Auxiliary
|
||||
from src.classes.elixir import Elixir
|
||||
|
||||
|
||||
class InventoryMixin:
|
||||
"""物品与装备管理相关方法"""
|
||||
|
||||
def add_item(self: "Avatar", item: "Item", quantity: int = 1) -> None:
|
||||
def add_material(self: "Avatar", material: "Material", quantity: int = 1) -> None:
|
||||
"""
|
||||
添加物品到背包
|
||||
|
||||
Args:
|
||||
item: 要添加的物品
|
||||
material: 要添加的物品
|
||||
quantity: 添加数量,默认为1
|
||||
"""
|
||||
if quantity <= 0:
|
||||
return
|
||||
|
||||
if item in self.items:
|
||||
self.items[item] += quantity
|
||||
if material in self.materials:
|
||||
self.materials[material] += quantity
|
||||
else:
|
||||
self.items[item] = quantity
|
||||
self.materials[material] = quantity
|
||||
|
||||
def remove_item(self: "Avatar", item: "Item", quantity: int = 1) -> bool:
|
||||
def remove_material(self: "Avatar", material: "Material", quantity: int = 1) -> bool:
|
||||
"""
|
||||
从背包移除物品
|
||||
从背包移除材料
|
||||
|
||||
Args:
|
||||
item: 要移除的物品
|
||||
material: 要移除的材料
|
||||
quantity: 移除数量,默认为1
|
||||
|
||||
Returns:
|
||||
bool: 是否成功移除(如果物品不足则返回False)
|
||||
bool: 是否成功移除(如果材料不足则返回False)
|
||||
"""
|
||||
if quantity <= 0:
|
||||
return True
|
||||
|
||||
if item not in self.items:
|
||||
if material not in self.materials:
|
||||
return False
|
||||
|
||||
if self.items[item] < quantity:
|
||||
if self.materials[material] < quantity:
|
||||
return False
|
||||
|
||||
self.items[item] -= quantity
|
||||
self.materials[material] -= quantity
|
||||
|
||||
# 如果数量为0,从字典中移除该物品
|
||||
if self.items[item] == 0:
|
||||
del self.items[item]
|
||||
if self.materials[material] == 0:
|
||||
del self.materials[material]
|
||||
|
||||
return True
|
||||
|
||||
def get_item_quantity(self: "Avatar", item: "Item") -> int:
|
||||
def get_material_quantity(self: "Avatar", material: "Material") -> int:
|
||||
"""
|
||||
获取指定物品的数量
|
||||
获取指定材料的数量
|
||||
|
||||
Args:
|
||||
item: 要查询的物品
|
||||
material: 要查询的材料
|
||||
|
||||
Returns:
|
||||
int: 物品数量,如果没有该物品则返回0
|
||||
int: 材料数量,如果没有该材料则返回0
|
||||
"""
|
||||
return self.items.get(item, 0)
|
||||
return self.materials.get(material, 0)
|
||||
|
||||
def change_weapon(self: "Avatar", new_weapon: "Weapon") -> None:
|
||||
"""
|
||||
@@ -106,20 +107,20 @@ class InventoryMixin:
|
||||
|
||||
# ==================== 出售接口 ====================
|
||||
|
||||
def sell_item(self: "Avatar", item: "Item", quantity: int = 1) -> int:
|
||||
def sell_material(self: "Avatar", material: "Material", quantity: int = 1) -> int:
|
||||
"""
|
||||
出售材料物品,返回获得的灵石数量。
|
||||
应用 extra_item_sell_price_multiplier 效果。
|
||||
"""
|
||||
from src.classes.prices import prices
|
||||
|
||||
if quantity <= 0 or self.get_item_quantity(item) < quantity:
|
||||
if quantity <= 0 or self.get_material_quantity(material) < quantity:
|
||||
return 0
|
||||
|
||||
self.remove_item(item, quantity)
|
||||
self.remove_material(material, quantity)
|
||||
|
||||
# 使用统一的卖出价格接口(包含所有加成逻辑)
|
||||
unit_price = prices.get_selling_price(item, self)
|
||||
unit_price = prices.get_selling_price(material, self)
|
||||
total = unit_price * quantity
|
||||
|
||||
self.magic_stone = self.magic_stone + total
|
||||
@@ -155,3 +156,132 @@ class InventoryMixin:
|
||||
self.magic_stone = self.magic_stone + total
|
||||
return total
|
||||
|
||||
def sell_elixir(self: "Avatar", elixir: "Elixir") -> int:
|
||||
"""
|
||||
出售丹药,返回获得的灵石数量。
|
||||
"""
|
||||
from src.classes.prices import prices
|
||||
|
||||
# 使用统一的卖出价格接口
|
||||
total = prices.get_selling_price(elixir, self)
|
||||
self.magic_stone = self.magic_stone + total
|
||||
return total
|
||||
|
||||
# ==================== 购买接口 ====================
|
||||
|
||||
def can_buy_item(self: "Avatar", obj: Any) -> tuple[bool, str]:
|
||||
"""
|
||||
检查是否可以购买指定物品。
|
||||
涵盖价格检查、境界限制、耐药性等。
|
||||
"""
|
||||
from src.classes.elixir import Elixir
|
||||
from src.classes.prices import prices
|
||||
from src.classes.cultivation import Realm
|
||||
|
||||
# 1. 检查价格
|
||||
price = prices.get_buying_price(obj, self)
|
||||
if self.magic_stone < price:
|
||||
return False, f"灵石不足 (需要 {price})"
|
||||
|
||||
# 2. 丹药特殊检查
|
||||
if isinstance(obj, Elixir):
|
||||
# 商店业务规则:当前仅开放练气期丹药购买
|
||||
if obj.realm != Realm.Qi_Refinement:
|
||||
return False, "当前仅开放练气期丹药购买"
|
||||
|
||||
# 境界限制
|
||||
if obj.realm > self.cultivation_progress.realm:
|
||||
return False, f"境界不足,无法承受药力 ({obj.realm.value})"
|
||||
|
||||
# 耐药性/生效中检查
|
||||
for consumed in self.elixirs:
|
||||
if consumed.elixir.id == obj.id:
|
||||
if not consumed.is_completely_expired(int(self.world.month_stamp)):
|
||||
return False, "药效尚存,无法重复服用"
|
||||
|
||||
return True, ""
|
||||
|
||||
def buy_item(self: "Avatar", obj: Any) -> dict:
|
||||
"""
|
||||
执行购买逻辑。
|
||||
包括扣款、获得物品(服用/入包/装备)、以旧换新。
|
||||
返回交易报告 dict。
|
||||
"""
|
||||
import copy
|
||||
from src.classes.elixir import Elixir
|
||||
from src.classes.weapon import Weapon
|
||||
from src.classes.auxiliary import Auxiliary
|
||||
from src.classes.material import Material
|
||||
from src.classes.prices import prices
|
||||
|
||||
report = {
|
||||
"success": True,
|
||||
"cost": 0,
|
||||
"action_type": "store", # store, consume, equip
|
||||
"sold_item_name": None,
|
||||
"sold_item_refund": 0
|
||||
}
|
||||
|
||||
# 1. 扣款
|
||||
price = prices.get_buying_price(obj, self)
|
||||
self.magic_stone -= price
|
||||
report["cost"] = price
|
||||
|
||||
# 2. 交付
|
||||
if isinstance(obj, Elixir):
|
||||
# 购买即服用
|
||||
self.consume_elixir(obj)
|
||||
report["action_type"] = "consume"
|
||||
|
||||
elif isinstance(obj, Material):
|
||||
# 放入背包
|
||||
self.add_material(obj)
|
||||
report["action_type"] = "store"
|
||||
|
||||
elif isinstance(obj, (Weapon, Auxiliary)):
|
||||
# 装备需要深拷贝
|
||||
new_equip = copy.deepcopy(obj)
|
||||
|
||||
# 尝试卖出旧装备并换上新装备
|
||||
sold_name, refund = self._equip_and_trade_in(new_equip)
|
||||
|
||||
report["action_type"] = "equip"
|
||||
if sold_name:
|
||||
report["sold_item_name"] = sold_name
|
||||
report["sold_item_refund"] = refund
|
||||
|
||||
return report
|
||||
|
||||
def _equip_and_trade_in(self: "Avatar", new_equip: Union["Weapon", "Auxiliary"]) -> tuple[str | None, int]:
|
||||
"""
|
||||
内部方法:装备新物品,并尝试卖出旧物品(如果有)。
|
||||
返回: (旧物品名称, 卖出金额)
|
||||
"""
|
||||
from src.classes.weapon import Weapon
|
||||
from src.classes.auxiliary import Auxiliary
|
||||
|
||||
sold_name = None
|
||||
refund = 0
|
||||
|
||||
if isinstance(new_equip, Weapon):
|
||||
# 检查是否有旧兵器
|
||||
if self.weapon:
|
||||
sold_name = self.weapon.name
|
||||
# sell_weapon 会把旧兵器加到 circulation 并加钱给 avatar
|
||||
# 注意:sell_weapon 不会 clear self.weapon,也不会 deepcopy(因为是直接把引用给 circulation)
|
||||
# 这是正确的,旧对象给系统,新对象上身
|
||||
refund = self.sell_weapon(self.weapon)
|
||||
|
||||
# 换上新兵器 (覆盖 self.weapon)
|
||||
self.change_weapon(new_equip)
|
||||
|
||||
elif isinstance(new_equip, Auxiliary):
|
||||
# 检查是否有旧法宝
|
||||
if self.auxiliary:
|
||||
sold_name = self.auxiliary.name
|
||||
refund = self.sell_auxiliary(self.auxiliary)
|
||||
|
||||
# 换上新法宝
|
||||
self.change_auxiliary(new_equip)
|
||||
|
||||
return sold_name, refund
|
||||
|
||||
Reference in New Issue
Block a user