fix bug
This commit is contained in:
@@ -86,7 +86,7 @@
|
||||
- [ ] 兽潮
|
||||
|
||||
### ⚔️ 战斗系统
|
||||
- [ ] 战斗方式设计
|
||||
- [ ] 战斗方式设计(灵根影响技能与战斗风格)
|
||||
- [ ] 优劣互克关系
|
||||
- ✅ 胜率计算系统(简单)
|
||||
- [ ] 战斗规则引擎
|
||||
|
||||
@@ -6,7 +6,7 @@ import json
|
||||
import inspect
|
||||
|
||||
from src.classes.essence import Essence, EssenceType
|
||||
from src.classes.root import Root, get_essence_types_for_root
|
||||
from src.classes.root import Root, get_essence_types_for_root, extra_breakthrough_success_rate
|
||||
from src.classes.region import Region, CultivateRegion, NormalRegion, CityRegion
|
||||
from src.classes.event import Event, NULL_EVENT
|
||||
from src.classes.item import Item, items_by_name
|
||||
@@ -335,16 +335,21 @@ class Cultivate(DefineAction, ActualActionMixin):
|
||||
@long_action(step_month=1)
|
||||
class Breakthrough(DefineAction, ActualActionMixin):
|
||||
"""
|
||||
突破境界
|
||||
突破境界。
|
||||
成功率由 `CultivationProgress.get_breakthrough_success_rate()` 决定;
|
||||
失败时按 `CultivationProgress.get_breakthrough_fail_reduce_lifespan()` 减少寿元(年)。
|
||||
"""
|
||||
COMMENT = "尝试突破境界"
|
||||
COMMENT = "尝试突破境界(成功增加寿元上限,失败折损寿元上限;境界越高,成功率越低。)"
|
||||
DOABLES_REQUIREMENTS = "角色处于瓶颈时"
|
||||
PARAMS = {}
|
||||
def calc_success_rate(self) -> float:
|
||||
"""
|
||||
计算突破境界的成功率
|
||||
计算突破境界的成功率(由修为进度给出)
|
||||
"""
|
||||
return 0.5
|
||||
base = self.avatar.cultivation_progress.get_breakthrough_success_rate()
|
||||
bonus = extra_breakthrough_success_rate[self.avatar.root]
|
||||
# 夹紧到 [0, 1]
|
||||
return max(0.0, min(1.0, base + bonus))
|
||||
|
||||
def _execute(self) -> None:
|
||||
"""
|
||||
@@ -360,6 +365,12 @@ class Breakthrough(DefineAction, ActualActionMixin):
|
||||
# 突破成功时更新HP和MP的最大值
|
||||
if new_realm != old_realm:
|
||||
self._update_hp_mp_on_breakthrough(new_realm)
|
||||
# 成功:确保最大寿元至少达到新境界的基线
|
||||
self.avatar.age.ensure_max_lifespan_at_least_realm_base(new_realm)
|
||||
else:
|
||||
# 突破失败:减少最大寿元上限
|
||||
reduce_years = self.avatar.cultivation_progress.get_breakthrough_fail_reduce_lifespan()
|
||||
self.avatar.age.decrease_max_lifespan(reduce_years)
|
||||
|
||||
def _update_hp_mp_on_breakthrough(self, new_realm):
|
||||
"""
|
||||
@@ -487,18 +498,24 @@ class Harvest(DefineAction, ActualActionMixin):
|
||||
COMMENT = "在当前区域采集植物,获取植物材料"
|
||||
DOABLES_REQUIREMENTS = "在有植物的普通区域,且avatar的境界必须大于等于植物的境界"
|
||||
PARAMS = {}
|
||||
|
||||
def get_available_plants(self) -> list[Plant]:
|
||||
"""
|
||||
获取avatar境界足够的植物
|
||||
"""
|
||||
region = self.avatar.tile.region
|
||||
avatar_realm = self.avatar.cultivation_progress.realm
|
||||
return [plant for plant in region.plants if avatar_realm >= plant.realm]
|
||||
|
||||
def _execute(self) -> None:
|
||||
"""
|
||||
执行采集动作
|
||||
"""
|
||||
region = self.avatar.tile.region
|
||||
success_rate = self.get_success_rate()
|
||||
|
||||
available_plants = self.get_available_plants()
|
||||
|
||||
if random.random() < success_rate:
|
||||
# 成功采集,从avatar境界足够的植物中随机选择一种
|
||||
avatar_realm = self.avatar.cultivation_progress.realm
|
||||
available_plants = [plant for plant in region.plants if avatar_realm >= plant.realm]
|
||||
target_plant = random.choice(available_plants)
|
||||
# 随机选择该植物的一种物品
|
||||
item = random.choice(target_plant.items)
|
||||
@@ -523,15 +540,12 @@ class Harvest(DefineAction, ActualActionMixin):
|
||||
判断是否可以采集:必须在有植物的普通区域,且avatar的境界必须大于等于植物的境界
|
||||
"""
|
||||
region = self.avatar.tile.region
|
||||
if not isinstance(region, NormalRegion) or len(region.plants) == 0:
|
||||
if not isinstance(region, NormalRegion):
|
||||
return False
|
||||
|
||||
# 检查avatar的境界是否足够采集区域内的植物
|
||||
avatar_realm = self.avatar.cultivation_progress.realm
|
||||
for plant in region.plants:
|
||||
if avatar_realm >= plant.realm:
|
||||
return True
|
||||
return False
|
||||
avaliable_plants = self.get_available_plants()
|
||||
if len(avaliable_plants) == 0:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
@long_action(step_month=1)
|
||||
|
||||
@@ -9,42 +9,68 @@ class Age:
|
||||
"""
|
||||
|
||||
# 各境界的基础期望寿命(年)
|
||||
# REALM_LIFESPAN = {
|
||||
# Realm.Qi_Refinement: 100, # 练气期:100年
|
||||
# Realm.Foundation_Establishment: 200, # 筑基期:200年
|
||||
# Realm.Core_Formation: 500, # 金丹期:500年
|
||||
# Realm.Nascent_Soul: 1000, # 元婴期:1000年
|
||||
# }
|
||||
REALM_LIFESPAN = {
|
||||
Realm.Qi_Refinement: 50, # 练气期:100年
|
||||
Realm.Foundation_Establishment: 60, # 筑基期:200年
|
||||
Realm.Core_Formation: 70, # 金丹期:500年
|
||||
Realm.Nascent_Soul: 80, # 元婴期:1000年
|
||||
Realm.Qi_Refinement: 80, # 练气期:100年
|
||||
Realm.Foundation_Establishment: 120, # 筑基期:200年
|
||||
Realm.Core_Formation: 200, # 金丹期:500年
|
||||
Realm.Nascent_Soul: 500, # 元婴期:1000年
|
||||
}
|
||||
|
||||
|
||||
def __init__(self, age: int):
|
||||
def __init__(self, age: int, realm: Realm):
|
||||
self.age = age
|
||||
# 最大理论寿元(年),初始化为 max(境界基线, 当前年龄+1)
|
||||
self.max_lifespan: int = max(self.get_base_expected_lifespan(realm), self.age + 1)
|
||||
|
||||
def get_age(self) -> int:
|
||||
"""获取当前年龄"""
|
||||
return self.age
|
||||
|
||||
def get_expected_lifespan(self, realm: Realm) -> int:
|
||||
"""获取期望寿命"""
|
||||
"""获取期望寿命(即当前最大寿元上限)。"""
|
||||
return self.max_lifespan
|
||||
|
||||
def get_base_expected_lifespan(self, realm: Realm) -> int:
|
||||
"""获取境界对应的基线期望寿命(不受max_lifespan影响)。"""
|
||||
return self.REALM_LIFESPAN.get(realm, 100)
|
||||
|
||||
def set_initial_max_lifespan(self, realm: Realm) -> None:
|
||||
"""构造时已设置最大寿元,此处保持与构造策略一致。"""
|
||||
base = self.get_base_expected_lifespan(realm)
|
||||
self.max_lifespan = max(base, self.age + 1)
|
||||
|
||||
def ensure_max_lifespan_at_least_realm_base(self, realm: Realm) -> None:
|
||||
"""确保最大寿元至少达到 max(该境界基线, 当前年龄+1)。"""
|
||||
base = self.get_base_expected_lifespan(realm)
|
||||
floor_value = max(base, self.age + 1)
|
||||
if self.max_lifespan < floor_value:
|
||||
self.max_lifespan = floor_value
|
||||
|
||||
def increase_max_lifespan(self, years: int) -> None:
|
||||
"""提升最大寿元上限。"""
|
||||
if years <= 0:
|
||||
return
|
||||
self.max_lifespan = (self.max_lifespan or 0) + years
|
||||
|
||||
def decrease_max_lifespan(self, years: int) -> None:
|
||||
"""降低最大寿元上限(可以低于当前年龄)。"""
|
||||
if years <= 0:
|
||||
return
|
||||
self.max_lifespan = self.max_lifespan - years
|
||||
|
||||
def get_death_probability(self, realm: Realm) -> float:
|
||||
def get_death_probability(self, realm: Realm | None = None) -> float:
|
||||
"""
|
||||
计算当月老死的概率
|
||||
|
||||
返回:
|
||||
老死概率,范围0.0-0.1
|
||||
"""
|
||||
if self.age < self.get_expected_lifespan(realm):
|
||||
expected = self.max_lifespan if realm is None else self.get_expected_lifespan(realm)
|
||||
if self.age < expected:
|
||||
return 0.0
|
||||
|
||||
# 超过期望寿命的年数
|
||||
years_over_lifespan = self.age - self.get_expected_lifespan(realm)
|
||||
years_over_lifespan = self.age - expected
|
||||
|
||||
# 基础概率:每超过1年增加0.01的概率
|
||||
death_probability = min(years_over_lifespan * 0.01, 0.1)
|
||||
@@ -78,9 +104,19 @@ class Age:
|
||||
"""
|
||||
self.age = self.calculate_age(current_month_stamp, birth_month_stamp)
|
||||
|
||||
def get_lifespan_progress(self, realm: Realm | None = None) -> tuple[int, int]:
|
||||
"""返回 (当前年龄, 期望寿命)。realm为空时使用当前最大寿元。"""
|
||||
expected = self.max_lifespan if realm is None else self.get_expected_lifespan(realm)
|
||||
return self.age, expected
|
||||
|
||||
def is_elderly(self, realm: Realm | None = None) -> bool:
|
||||
"""是否超过期望寿命。realm为空时使用当前最大寿元。"""
|
||||
expected = self.max_lifespan if realm is None else self.get_expected_lifespan(realm)
|
||||
return self.age >= expected
|
||||
|
||||
def __str__(self) -> str:
|
||||
"""返回年龄的字符串表示"""
|
||||
return str(self.age)
|
||||
max_str = str(self.max_lifespan)
|
||||
return f"{self.age}/{max_str}"
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""返回年龄的详细字符串表示"""
|
||||
|
||||
@@ -83,6 +83,8 @@ class Avatar:
|
||||
max_mp = MP_MAX_BY_REALM.get(self.cultivation_progress.realm, 100)
|
||||
self.hp = HP(max_hp, max_hp)
|
||||
self.mp = MP(max_mp, max_mp)
|
||||
|
||||
# 最大寿元已在 Age 构造时基于境界初始化
|
||||
|
||||
# 如果personas列表为空,则随机分配两个不互斥的persona
|
||||
if not self.personas:
|
||||
@@ -182,6 +184,7 @@ class Avatar:
|
||||
action_name, _ = pair
|
||||
action = self.create_action(action_name)
|
||||
doable = action.is_doable
|
||||
assert isinstance(doable, bool)
|
||||
return doable
|
||||
|
||||
async def act(self) -> List[Event]:
|
||||
@@ -356,7 +359,7 @@ class Avatar:
|
||||
# 构建personas的提示词信息
|
||||
personas_prompts = []
|
||||
for i, persona in enumerate(self.personas, 1):
|
||||
personas_prompts.append(f"其个性{i}:{persona.prompt}")
|
||||
personas_prompts.append(f"个性{i}:{persona.prompt}")
|
||||
personas_info = "\n".join(personas_prompts)
|
||||
|
||||
# 添加灵石信息
|
||||
|
||||
@@ -185,10 +185,13 @@ class CultivationProgress:
|
||||
|
||||
def is_in_bottleneck(self) -> bool:
|
||||
"""
|
||||
检查是否可以突破
|
||||
其实就是再瓶颈期间。
|
||||
是否处于瓶颈期。
|
||||
如果级别在LEVEL_TO_BREAK_THROUGH中,同时realm不是该级别对应的realm,则处于瓶颈期。
|
||||
"""
|
||||
return self.level in LEVEL_TO_BREAK_THROUGH.keys()
|
||||
for level_threshold, realm in LEVEL_TO_BREAK_THROUGH.items():
|
||||
if self.level == level_threshold and self.realm != realm:
|
||||
return True
|
||||
return False
|
||||
|
||||
def can_break_through(self) -> bool:
|
||||
"""
|
||||
@@ -213,6 +216,12 @@ class CultivationProgress:
|
||||
def __str__(self) -> str:
|
||||
return f"{self.realm.value}{self.stage.value}({self.level}级)。在瓶颈期:{self.is_in_bottleneck()}"
|
||||
|
||||
def get_breakthrough_success_rate(self) -> float:
|
||||
return breakthrough_success_rate_by_realm[self.realm]
|
||||
|
||||
def get_breakthrough_fail_reduce_lifespan(self) -> int:
|
||||
return breakthrough_fail_reduce_lifespan_by_realm[self.realm]
|
||||
|
||||
|
||||
|
||||
breakthrough_success_rate_by_realm = {
|
||||
@@ -223,8 +232,8 @@ breakthrough_success_rate_by_realm = {
|
||||
}
|
||||
|
||||
breakthrough_fail_reduce_lifespan_by_realm = {
|
||||
Realm.Qi_Refinement: 10,
|
||||
Realm.Foundation_Establishment: 20,
|
||||
Realm.Core_Formation: 30,
|
||||
Realm.Nascent_Soul: 40,
|
||||
Realm.Qi_Refinement: 5,
|
||||
Realm.Foundation_Establishment: 10,
|
||||
Realm.Core_Formation: 15,
|
||||
Realm.Nascent_Soul: 20,
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
"""
|
||||
from enum import Enum
|
||||
from typing import List, Tuple
|
||||
from collections import defaultdict
|
||||
|
||||
from src.classes.essence import EssenceType
|
||||
|
||||
@@ -76,15 +77,7 @@ def get_essence_types_for_root(root: Root) -> List[EssenceType]:
|
||||
"""
|
||||
return [_essence_by_element[e] for e in root.elements]
|
||||
|
||||
roots = {
|
||||
"金": Root.GOLD,
|
||||
"木": Root.WOOD,
|
||||
"水": Root.WATER,
|
||||
"火": Root.FIRE,
|
||||
"土": Root.EARTH,
|
||||
"雷": Root.THUNDER,
|
||||
"冰": Root.ICE,
|
||||
"风": Root.WIND,
|
||||
"暗": Root.DARK,
|
||||
"天": Root.HEAVEN,
|
||||
}
|
||||
extra_breakthrough_success_rate = {
|
||||
Root.HEAVEN: 0.1,
|
||||
}
|
||||
extra_breakthrough_success_rate = defaultdict(lambda: 0, extra_breakthrough_success_rate)
|
||||
@@ -59,8 +59,8 @@ def make_avatars(world: World, count: int = 12, current_month_stamp: MonthStamp
|
||||
level = random.randint(0, 120)
|
||||
cultivation_progress = CultivationProgress(level)
|
||||
|
||||
# 创建Age实例,传入年龄
|
||||
age = Age(age_years)
|
||||
# 创建Age实例,传入年龄与当前境界
|
||||
age = Age(age_years, cultivation_progress.realm)
|
||||
|
||||
# 找一个非海域的出生点
|
||||
for _ in range(200):
|
||||
|
||||
@@ -3,6 +3,7 @@ import random
|
||||
from src.classes.calendar import Month, Year, MonthStamp
|
||||
from src.classes.avatar import Avatar, get_new_avatar_from_ordinary, Gender
|
||||
from src.classes.age import Age
|
||||
from src.classes.cultivation import Realm
|
||||
from src.classes.world import World
|
||||
from src.classes.event import Event, is_null_event
|
||||
from src.classes.ai import llm_ai, rule_ai
|
||||
@@ -54,7 +55,9 @@ class Simulator:
|
||||
|
||||
# 结算角色行为
|
||||
for avatar_id, avatar in self.world.avatar_manager.avatars.items():
|
||||
new_events = await avatar.act()
|
||||
new_events = []
|
||||
if avatar.is_next_action_doable():
|
||||
new_events = await avatar.act()
|
||||
if new_events:
|
||||
events.extend(new_events)
|
||||
if avatar.death_by_old_age():
|
||||
@@ -72,7 +75,7 @@ class Simulator:
|
||||
age = random.randint(16, 60)
|
||||
gender = random.choice(list(Gender))
|
||||
name = get_random_name(gender)
|
||||
new_avatar = get_new_avatar_from_ordinary(self.world, self.world.month_stamp, name, Age(age))
|
||||
new_avatar = get_new_avatar_from_ordinary(self.world, self.world.month_stamp, name, Age(age, Realm.Qi_Refinement))
|
||||
self.world.avatar_manager.avatars[new_avatar.id] = new_avatar
|
||||
event = Event(self.world.month_stamp, f"{new_avatar.name}晋升为修士了。")
|
||||
events.append(event)
|
||||
|
||||
@@ -12,7 +12,7 @@ ai:
|
||||
max_decide_num: 3
|
||||
|
||||
game:
|
||||
init_npc_num: 2
|
||||
init_npc_num: 3
|
||||
npc_birth_rate_per_month: 0.001
|
||||
|
||||
df:
|
||||
|
||||
@@ -19,4 +19,4 @@
|
||||
|
||||
要求与约束:
|
||||
- 若需要先移动再修炼,请将 "MoveToRegion" 放在前面,随后接 "Cultivate"。
|
||||
- 若当前可突破,可在合适时机插入 "Breakthrough"。
|
||||
- thought可从侧面体现出角色个性
|
||||
@@ -4,6 +4,7 @@ from src.classes.calendar import Month, Year, MonthStamp, create_month_stamp
|
||||
from src.classes.world import World
|
||||
from src.classes.tile import Map, TileType
|
||||
from src.classes.age import Age
|
||||
from src.classes.cultivation import Realm
|
||||
from src.utils.names import get_random_name
|
||||
|
||||
def test_basic():
|
||||
@@ -22,7 +23,7 @@ def test_basic():
|
||||
name=get_random_name(Gender.MALE),
|
||||
id=get_avatar_id(),
|
||||
birth_month_stamp=create_month_stamp(Year(2000), Month.JANUARY),
|
||||
age=Age(20),
|
||||
age=Age(20, Realm.Qi_Refinement),
|
||||
gender=Gender.MALE
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user