update treasure to weapon and auxiliary
This commit is contained in:
@@ -17,9 +17,33 @@ class NurtureWeapon(TimedAction):
|
||||
duration_months = 3
|
||||
|
||||
def _execute(self) -> None:
|
||||
from src.classes.equipment_grade import EquipmentGrade
|
||||
from src.classes.weapon import get_treasure_weapon
|
||||
|
||||
# 温养兵器增加较多熟练度(5-10)
|
||||
proficiency_gain = random.uniform(5.0, 10.0)
|
||||
self.avatar.increase_weapon_proficiency(proficiency_gain)
|
||||
|
||||
# 如果是普通兵器,有5%概率升级为宝物
|
||||
if self.avatar.weapon and self.avatar.weapon.grade == EquipmentGrade.COMMON:
|
||||
if random.random() < 0.05:
|
||||
treasure_weapon = get_treasure_weapon(self.avatar.weapon.weapon_type)
|
||||
if treasure_weapon:
|
||||
import copy
|
||||
old_weapon_name = self.avatar.weapon.name
|
||||
old_proficiency = self.avatar.weapon_proficiency
|
||||
# 深拷贝宝物兵器并更换(会重新计算长期效果)
|
||||
new_weapon = copy.deepcopy(treasure_weapon)
|
||||
self.avatar.change_weapon(new_weapon)
|
||||
# 恢复熟练度(change_weapon 会归零,需要手动恢复)
|
||||
self.avatar.weapon_proficiency = old_proficiency
|
||||
# 记录升华事件
|
||||
from src.classes.event import Event
|
||||
self.avatar.world.add_event(Event(
|
||||
self.avatar.world.month_stamp,
|
||||
f"{self.avatar.name} 温养{old_weapon_name}时,兵器灵性大增,升华为{treasure_weapon.name}!",
|
||||
related_avatars=[self.avatar.id]
|
||||
))
|
||||
|
||||
def can_start(self) -> tuple[bool, str]:
|
||||
# 任何时候都可以温养兵器
|
||||
@@ -36,6 +60,7 @@ class NurtureWeapon(TimedAction):
|
||||
def finish(self) -> list[Event]:
|
||||
weapon_name = self.avatar.weapon.name if self.avatar.weapon else "兵器"
|
||||
proficiency = self.avatar.weapon_proficiency
|
||||
# 注意:升华事件已经在_execute中添加,这里只添加完成事件
|
||||
return [
|
||||
Event(
|
||||
self.world.month_stamp,
|
||||
|
||||
@@ -146,23 +146,10 @@ class Avatar(AvatarSaveMixin, AvatarLoadMixin):
|
||||
from src.classes.alignment import Alignment as _Alignment
|
||||
self.alignment = random.choice(list(_Alignment))
|
||||
|
||||
# 兵器初始化:如果无兵器,分配一个普通兵器
|
||||
# 有宗门且宗门有倾向兵器时,80%概率使用宗门兵器,否则随机
|
||||
if self.weapon is None:
|
||||
if self.sect is not None and self.sect.preferred_weapon:
|
||||
# 有宗门倾向兵器,80%概率使用
|
||||
if random.random() < 0.8:
|
||||
# 尝试根据宗门倾向兵器类型获取
|
||||
for wt in WeaponType:
|
||||
if wt.value == self.sect.preferred_weapon:
|
||||
self.weapon = get_common_weapon(wt)
|
||||
break
|
||||
# 如果还没有兵器(无宗门、无倾向、或20%随机),随机分配
|
||||
if self.weapon is None:
|
||||
weapon_type = random.choice(list(WeaponType))
|
||||
self.weapon = get_common_weapon(weapon_type)
|
||||
|
||||
# effects 改为实时属性,不在此初始化
|
||||
|
||||
# 初始化时计算所有长期效果(HP/MP等)
|
||||
self.recalc_effects()
|
||||
|
||||
@property
|
||||
def effects(self) -> dict[str, object]:
|
||||
@@ -388,9 +375,11 @@ class Avatar(AvatarSaveMixin, AvatarLoadMixin):
|
||||
self.cultivation_progress.level = new_level
|
||||
self.cultivation_progress.realm = self.cultivation_progress.get_realm(new_level)
|
||||
|
||||
# 如果境界提升了,更新寿命期望
|
||||
# 如果境界提升了,更新寿命期望和长期效果
|
||||
if self.cultivation_progress.realm != old_realm:
|
||||
self.age.update_realm(self.cultivation_progress.realm)
|
||||
# 境界变化会影响 HP/MP 基础值,需要重新计算
|
||||
self.recalc_effects()
|
||||
# 如果有宗门,检查是否需要晋升职位
|
||||
from src.classes.sect_ranks import check_and_promote_sect_rank
|
||||
check_and_promote_sect_rank(self, old_realm, self.cultivation_progress.realm)
|
||||
@@ -734,15 +723,65 @@ class Avatar(AvatarSaveMixin, AvatarLoadMixin):
|
||||
"""
|
||||
return self.cultivation_progress.get_move_step()
|
||||
|
||||
def recalc_effects(self) -> None:
|
||||
"""
|
||||
重新计算所有长期效果
|
||||
在装备更换、突破境界等情况下调用
|
||||
|
||||
说明:
|
||||
- self.effects 是 @property,每次访问都会重新 merge 所有来源的 effects
|
||||
- 包括:宗门、功法、灵根、特质、兵器、辅助装备、灵兽
|
||||
- 也会重新计算动态表达式(如 eval(...))
|
||||
|
||||
当前包括:
|
||||
- HP/MP 最大值
|
||||
- 将来可能还有其他长期 effects
|
||||
"""
|
||||
# 计算基础最大值(基于境界)
|
||||
base_max_hp = HP_MAX_BY_REALM.get(self.cultivation_progress.realm, 100)
|
||||
base_max_mp = MP_MAX_BY_REALM.get(self.cultivation_progress.realm, 100)
|
||||
|
||||
# 访问 self.effects 会触发 @property,重新 merge 所有 effects
|
||||
effects = self.effects
|
||||
extra_max_hp = int(effects.get("extra_max_hp", 0))
|
||||
extra_max_mp = int(effects.get("extra_max_mp", 0))
|
||||
|
||||
# 计算新的最大值
|
||||
new_max_hp = base_max_hp + extra_max_hp
|
||||
new_max_mp = base_max_mp + extra_max_mp
|
||||
|
||||
# 更新最大值
|
||||
self.hp.max = new_max_hp
|
||||
self.mp.max = new_max_mp
|
||||
|
||||
# 调整当前值(不超过新的最大值)
|
||||
if self.hp.cur > new_max_hp:
|
||||
self.hp.cur = new_max_hp
|
||||
if self.mp.cur > new_max_mp:
|
||||
self.mp.cur = new_max_mp
|
||||
|
||||
# 将来这里可以添加其他长期 effects 的计算
|
||||
|
||||
def change_weapon(self, new_weapon: Weapon) -> None:
|
||||
"""
|
||||
更换兵器,熟练度归零
|
||||
更换兵器,熟练度归零,并重新计算长期效果
|
||||
|
||||
Args:
|
||||
new_weapon: 新的兵器
|
||||
"""
|
||||
self.weapon = new_weapon
|
||||
self.weapon_proficiency = 0.0
|
||||
self.recalc_effects()
|
||||
|
||||
def change_auxiliary(self, new_auxiliary: Optional[Auxiliary]) -> None:
|
||||
"""
|
||||
更换辅助装备,并重新计算长期效果
|
||||
|
||||
Args:
|
||||
new_auxiliary: 新的辅助装备(可为 None 表示卸下)
|
||||
"""
|
||||
self.auxiliary = new_auxiliary
|
||||
self.recalc_effects()
|
||||
|
||||
def increase_weapon_proficiency(self, amount: float) -> None:
|
||||
"""
|
||||
|
||||
@@ -26,6 +26,22 @@ EXTRA_BATTLE_STRENGTH_POINTS = "extra_battle_strength_points"
|
||||
说明: 直接增加角色的战斗力数值
|
||||
"""
|
||||
|
||||
EXTRA_MAX_HP = "extra_max_hp"
|
||||
"""
|
||||
额外最大生命值
|
||||
类型: int
|
||||
结算: src/classes/avatar.py (__post_init__)
|
||||
说明: 增加角色的最大生命值上限
|
||||
"""
|
||||
|
||||
EXTRA_MAX_MP = "extra_max_mp"
|
||||
"""
|
||||
额外最大灵力值
|
||||
类型: int
|
||||
结算: src/classes/avatar.py (__post_init__)
|
||||
说明: 增加角色的最大灵力值上限
|
||||
"""
|
||||
|
||||
EXTRA_OBSERVATION_RADIUS = "extra_observation_radius"
|
||||
"""
|
||||
额外观察半径
|
||||
@@ -155,6 +171,8 @@ Effects 通过 src/classes/effect.py 中的 _merge_effects() 函数合并。
|
||||
ALL_EFFECTS = [
|
||||
# 战斗相关
|
||||
"extra_battle_strength_points", # int - 额外战斗力
|
||||
"extra_max_hp", # int - 额外最大生命值
|
||||
"extra_max_mp", # int - 额外最大灵力值
|
||||
"extra_observation_radius", # int - 额外观察半径
|
||||
|
||||
# 修炼相关
|
||||
|
||||
@@ -428,7 +428,7 @@ async def try_trigger_fortune(avatar: Avatar) -> list[Event]:
|
||||
kind = FortuneKind.TECHNIQUE
|
||||
theme = _pick_theme(kind)
|
||||
else:
|
||||
avatar.weapon = weapon
|
||||
avatar.change_weapon(weapon)
|
||||
res_text = f"{avatar.name} 获得{weapon.grade}兵器『{weapon.name}』"
|
||||
|
||||
if kind == FortuneKind.AUXILIARY:
|
||||
@@ -438,7 +438,7 @@ async def try_trigger_fortune(avatar: Avatar) -> list[Event]:
|
||||
kind = FortuneKind.TECHNIQUE
|
||||
theme = _pick_theme(kind)
|
||||
else:
|
||||
avatar.auxiliary = auxiliary
|
||||
avatar.change_auxiliary(auxiliary)
|
||||
res_text = f"{avatar.name} 获得{auxiliary.grade}辅助装备『{auxiliary.name}』"
|
||||
|
||||
if kind == FortuneKind.TECHNIQUE:
|
||||
|
||||
@@ -117,3 +117,12 @@ def get_common_weapon(weapon_type: WeaponType) -> Optional[Weapon]:
|
||||
weapon_name = f"普通{weapon_type.value}"
|
||||
return weapons_by_name.get(weapon_name)
|
||||
|
||||
|
||||
def get_treasure_weapon(weapon_type: WeaponType) -> Optional[Weapon]:
|
||||
"""获取指定类型的宝物级兵器"""
|
||||
from src.classes.equipment_grade import EquipmentGrade
|
||||
for weapon in weapons_by_id.values():
|
||||
if weapon.weapon_type == weapon_type and weapon.grade == EquipmentGrade.TREASURE:
|
||||
return weapon
|
||||
return None
|
||||
|
||||
|
||||
@@ -63,6 +63,63 @@ def random_gender() -> Gender:
|
||||
return Gender.MALE if random.random() < 0.5 else Gender.FEMALE
|
||||
|
||||
|
||||
def _assign_initial_weapon(avatar: Avatar) -> None:
|
||||
"""
|
||||
为新角色分配初始兵器
|
||||
- 根据宗门倾向(80%概率)或随机选择兵器类型
|
||||
- 1%概率获得法宝(优先宗门相关)
|
||||
- 5%概率获得宝物
|
||||
- 94%概率获得普通兵器
|
||||
"""
|
||||
from src.classes.weapon import get_common_weapon, get_treasure_weapon, weapons_by_id, weapons_by_sect_id
|
||||
from src.classes.weapon_type import WeaponType
|
||||
from src.classes.equipment_grade import EquipmentGrade
|
||||
import copy
|
||||
|
||||
# 1. 确定兵器类型:宗门倾向或随机
|
||||
weapon_type = None
|
||||
if avatar.sect is not None and avatar.sect.preferred_weapon:
|
||||
if random.random() < 0.8:
|
||||
for wt in WeaponType:
|
||||
if wt.value == avatar.sect.preferred_weapon:
|
||||
weapon_type = wt
|
||||
break
|
||||
if weapon_type is None:
|
||||
weapon_type = random.choice(list(WeaponType))
|
||||
|
||||
# 2. 确定品质并分配兵器
|
||||
roll = random.random()
|
||||
|
||||
if roll < 0.01:
|
||||
# 尝试获得法宝(优先宗门相关)
|
||||
artifact_weapon = None
|
||||
if avatar.sect is not None and avatar.sect.id in weapons_by_sect_id:
|
||||
candidate = weapons_by_sect_id[avatar.sect.id]
|
||||
if candidate.grade == EquipmentGrade.ARTIFACT:
|
||||
artifact_weapon = candidate
|
||||
|
||||
# 如果没有宗门相关法宝,从所有同类型法宝中选择
|
||||
if artifact_weapon is None:
|
||||
artifact_candidates = [w for w in weapons_by_id.values()
|
||||
if w.grade == EquipmentGrade.ARTIFACT and w.weapon_type == weapon_type]
|
||||
if artifact_candidates:
|
||||
artifact_weapon = random.choice(artifact_candidates)
|
||||
|
||||
if artifact_weapon is not None:
|
||||
avatar.weapon = copy.deepcopy(artifact_weapon)
|
||||
return
|
||||
|
||||
if roll < 0.06: # 0.01 + 0.05
|
||||
# 获得宝物
|
||||
treasure_weapon = get_treasure_weapon(weapon_type)
|
||||
if treasure_weapon:
|
||||
avatar.weapon = copy.deepcopy(treasure_weapon)
|
||||
return
|
||||
|
||||
# 获得普通兵器
|
||||
avatar.weapon = get_common_weapon(weapon_type)
|
||||
|
||||
|
||||
def get_new_avatar_from_mortal(world: World, current_month_stamp: MonthStamp, name: str, age: Age) -> Avatar:
|
||||
"""
|
||||
从凡人中来的新修士:先规划宗门/关系,再生成实际角色;不分配宗门法宝。
|
||||
@@ -213,6 +270,9 @@ def build_mortal_from_plan(world: World, current_month_stamp: MonthStamp, *, nam
|
||||
# 分配宗门职位(根据境界)
|
||||
_assign_sect_rank(avatar, world)
|
||||
|
||||
# 初始兵器分配(必须在 Avatar.__post_init__ 之前)
|
||||
_assign_initial_weapon(avatar)
|
||||
|
||||
# 写关系(父母/师徒);不发放宗门法宝
|
||||
if plan.parent_avatar is not None:
|
||||
plan.parent_avatar.set_relation(avatar, Relation.PARENT)
|
||||
@@ -435,8 +495,9 @@ def build_avatars_from_plan(
|
||||
if sect is not None:
|
||||
avatar.alignment = sect.alignment
|
||||
avatar.technique = get_technique_by_sect(sect)
|
||||
# 每个宗门只分配一个法宝级兵器给最强者(但不在这里分配,而是让奇遇系统处理)
|
||||
# 宗门成员初始都是普通兵器
|
||||
|
||||
# 初始兵器分配(必须在 Avatar.__post_init__ 之前)
|
||||
_assign_initial_weapon(avatar)
|
||||
|
||||
if avatar.technique is not None:
|
||||
mapped = attribute_to_root(avatar.technique.attribute)
|
||||
|
||||
@@ -12,4 +12,13 @@ id,name,weapon_type,grade,sect_id,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, ""cultivation_speed_rate"": 1.1}"
|
||||
2008,凤鸣笛,笛,宝物,,笛声如凤鸣九天,清心宁神。,"{""extra_battle_strength_points"": 2, ""cultivation_speed_rate"": 1.1}"
|
||||
2009,追魂刺,暗器,宝物,,暗器如影随形,取人性命于无声。,"{""extra_battle_strength_points"": 2}"
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user