feat: 修炼循环闭环——升层/瓶颈突破(按层概率)+管理界面修为进度+面板放大
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
## 修炼管理器(Autoload 单例)。
|
||||
## 负责弟子修为的每日结算与境界推进(D5:修为逐日增长 + 自动升层 + 瓶颈突破判定)。
|
||||
extends Node
|
||||
|
||||
## 境界变化信号(突破后发出,供详情面板刷新)。
|
||||
signal realm_changed(d: Disciple)
|
||||
## 修炼日志文本(控制台打印,后续日志系统接入)。
|
||||
signal cultivation_log(text: String)
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
# 每日推进时结算全体已入宗弟子的修为与境界
|
||||
TimeSystem.day_passed.connect(_on_day_passed)
|
||||
|
||||
## 每日结算:仅结算已入宗名录(候选池不修炼)。
|
||||
func _on_day_passed(_year: int, _month: int, _day: int) -> void:
|
||||
for d in DiscipleManager.disciples:
|
||||
_gain_exp(d)
|
||||
_check_breakthrough(d)
|
||||
|
||||
## 按公式累计一日修为。
|
||||
## 速度 = 基础速度 × 资质倍率 × 灵根容量 × 天灵根加成 × 灵气浓度
|
||||
## 练气圆满(13 层)后修为封顶,不再增长。
|
||||
## @param d: 已入宗弟子
|
||||
func _gain_exp(d: Disciple) -> void:
|
||||
# 练气圆满(13 层)后修为封顶,不再增长
|
||||
if d.realm_index != 0 or d.sub_realm_index >= GameConfig.level_thresholds.size():
|
||||
return
|
||||
var speed := GameConfig.cultivation_base_speed
|
||||
speed *= GameConfig.aptitude_speed[d.aptitude]
|
||||
speed *= d.get_root_count_capacity()
|
||||
if d.is_heavenly:
|
||||
speed *= GameConfig.heavenly_bonus
|
||||
speed *= GameConfig.qi_concentration
|
||||
d.cultivation_exp += speed
|
||||
|
||||
## 突破判定:修为满当前层门槛时推进境界。
|
||||
## 非瓶颈目标层自动升层;瓶颈目标层掷骰(成功率来自配置),失败扣 20% 修为。
|
||||
## 每日最多推进一层。
|
||||
## @param d: 已入宗弟子
|
||||
func _check_breakthrough(d: Disciple) -> void:
|
||||
if d.realm_index != 0:
|
||||
return
|
||||
var layer := d.sub_realm_index + 1
|
||||
# 13 层圆满:无更高门槛,不再判定
|
||||
if layer > GameConfig.level_thresholds.size():
|
||||
return
|
||||
if d.cultivation_exp < GameConfig.level_thresholds[layer - 1]:
|
||||
return
|
||||
if GameConfig.bottleneck_levels.has(layer + 1):
|
||||
# 成功率按目标层从配置取(与 bottleneck_levels 一一对应)
|
||||
var idx := maxi(0, GameConfig.bottleneck_levels.find(layer + 1))
|
||||
if randf() < GameConfig.bottleneck_chances[idx]:
|
||||
_advance_layer(d)
|
||||
else:
|
||||
d.cultivation_exp *= 0.8
|
||||
_log("%s 冲关 %s 失败,修为损耗两成" % [d.name, d.get_realm_text()])
|
||||
else:
|
||||
_advance_layer(d)
|
||||
|
||||
## 推进一层境界:扣除本层门槛修为(余量带入下一层)并发信号。
|
||||
## @param d: 已入宗弟子
|
||||
func _advance_layer(d: Disciple) -> void:
|
||||
var threshold := GameConfig.level_thresholds[d.sub_realm_index]
|
||||
d.cultivation_exp -= threshold
|
||||
d.sub_realm_index += 1
|
||||
realm_changed.emit(d)
|
||||
_log("%s 突破至 %s" % [d.name, d.get_realm_text()])
|
||||
|
||||
## 输出修炼日志(控制台打印 + 信号广播)。
|
||||
## @param text: 日志文本
|
||||
func _log(text: String) -> void:
|
||||
cultivation_log.emit(text)
|
||||
print(text)
|
||||
@@ -0,0 +1 @@
|
||||
uid://q4pk0n21oawr
|
||||
@@ -28,6 +28,7 @@ var join_month: int = 0 # 入宗月份
|
||||
var join_day: int = 0 # 入宗日
|
||||
var realm_index: int = 0 # 大境界索引(0=练气)
|
||||
var sub_realm_index: int = 0 # 小境界索引(练气层数-1)
|
||||
var cultivation_exp: float = 0.0 # 修为(float 可积累小数,D5 每日结算)
|
||||
|
||||
# —— 辅助函数:把数据翻译成给人看的文本 ——
|
||||
func get_aptitude_name() -> String:
|
||||
@@ -57,3 +58,12 @@ func get_join_date_text() -> String:
|
||||
if join_year <= 0:
|
||||
return ""
|
||||
return "%d年%d月%d日" % [join_year, join_month, join_day]
|
||||
|
||||
## 本层修炼进度文本,如 "1234 / 2000"(当前修为 / 本层门槛)。
|
||||
## 练气圆满(13 层)返回"练气圆满";非练气期返回空串。
|
||||
func get_cultivation_progress_text() -> String:
|
||||
if realm_index != 0:
|
||||
return ""
|
||||
if sub_realm_index >= GameConfig.level_thresholds.size():
|
||||
return "练气圆满"
|
||||
return "%d / %d" % [int(cultivation_exp), int(GameConfig.level_thresholds[sub_realm_index])]
|
||||
|
||||
@@ -31,6 +31,12 @@ var qi_concentration := 1.0
|
||||
var aptitude_speed: Array[float] = [0.6, 1.0, 1.5, 2.0]
|
||||
## 天灵根额外修炼速度倍率。
|
||||
var heavenly_bonus := 1.5
|
||||
## 各瓶颈层突破成功率(与 bottleneck_levels 一一对应:升4层/7层/10层/13层)。
|
||||
var bottleneck_chances: Array[float] = [0.85, 0.8, 0.75, 0.6]
|
||||
## 练气期各层升级所需修为(练气 1→2 到 12→13,共 12 项)。
|
||||
var level_thresholds: Array[float] = [100.0, 200.0, 350.0, 550.0, 800.0, 1100.0, 1500.0, 2000.0, 2600.0, 3300.0, 4100.0, 5000.0]
|
||||
## 瓶颈目标层(升到这些层需突破判定)。
|
||||
var bottleneck_levels: Array[int] = [4, 7, 10, 13]
|
||||
|
||||
# —— UI 通用(对应 cfg 的 [ui] 节)——
|
||||
## HUD 字体大小。
|
||||
@@ -69,6 +75,24 @@ func _load_config() -> void:
|
||||
cultivation_base_speed = cfg.get_value("cultivation", "base_speed", cultivation_base_speed)
|
||||
qi_concentration = cfg.get_value("cultivation", "qi_concentration", qi_concentration)
|
||||
heavenly_bonus = cfg.get_value("cultivation", "heavenly_bonus", heavenly_bonus)
|
||||
var bc_raw: Variant = cfg.get_value("cultivation", "breakthrough_chances", [])
|
||||
if bc_raw is Array and bc_raw.size() == bottleneck_chances.size():
|
||||
var arr_bc: Array[float] = []
|
||||
for v in bc_raw:
|
||||
arr_bc.append(float(v))
|
||||
bottleneck_chances = arr_bc
|
||||
var th_raw: Variant = cfg.get_value("cultivation", "level_thresholds", [])
|
||||
if th_raw is Array and th_raw.size() == level_thresholds.size():
|
||||
var arr_th: Array[float] = []
|
||||
for v in th_raw:
|
||||
arr_th.append(float(v))
|
||||
level_thresholds = arr_th
|
||||
var bn_raw: Variant = cfg.get_value("cultivation", "bottleneck_levels", [])
|
||||
if bn_raw is Array and bn_raw.size() == bottleneck_levels.size():
|
||||
var arr_bn: Array[int] = []
|
||||
for v in bn_raw:
|
||||
arr_bn.append(int(v))
|
||||
bottleneck_levels = arr_bn
|
||||
# UI 通用
|
||||
hud_font_size = cfg.get_value("ui", "hud_font_size", hud_font_size)
|
||||
var apt_raw: Variant = cfg.get_value("cultivation", "aptitude_speed", [])
|
||||
|
||||
@@ -66,7 +66,7 @@ theme_override_colors/font_color = Color(0.82, 0.95, 0.88, 1)
|
||||
text = "弟子名录"
|
||||
|
||||
[node name="ScrollContainer" type="ScrollContainer" parent="CenterContainer/Panel/MarginContainer/VBoxContainer" unique_id=780000008]
|
||||
custom_minimum_size = Vector2(640, 340)
|
||||
custom_minimum_size = Vector2(1280, 680)
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
|
||||
|
||||
@@ -14,12 +14,13 @@ func _ready() -> void:
|
||||
## @param d: 要展示的弟子
|
||||
func show_detail(d: Disciple) -> void:
|
||||
title_label.text = d.name + ("(天灵根)" if d.is_heavenly else "")
|
||||
info_label.text = "名字:%s\n资质:%s\n年龄:%d岁\n灵根:%s\n境界:%s\n入宗时间:%s" % [
|
||||
info_label.text = "名字:%s\n资质:%s\n年龄:%d岁\n灵根:%s\n境界:%s\n修为:%s\n入宗时间:%s" % [
|
||||
d.name,
|
||||
d.get_aptitude_name(),
|
||||
d.age,
|
||||
d.get_roots_text(),
|
||||
d.get_realm_text(),
|
||||
d.get_cultivation_progress_text(),
|
||||
d.get_join_date_text(),
|
||||
]
|
||||
visible = true
|
||||
|
||||
@@ -58,19 +58,19 @@ func _add_entry(d: Disciple) -> void:
|
||||
|
||||
var name_label := Label.new()
|
||||
name_label.text = d.name
|
||||
name_label.custom_minimum_size = Vector2(90, 0)
|
||||
name_label.custom_minimum_size = Vector2(180, 0)
|
||||
row.add_child(name_label)
|
||||
|
||||
var aptitude_label := Label.new()
|
||||
aptitude_label.text = d.get_aptitude_name() + ("·天灵根" if d.is_heavenly else "")
|
||||
if APTITUDE_COLORS.has(d.aptitude):
|
||||
aptitude_label.add_theme_color_override("font_color", APTITUDE_COLORS[d.aptitude])
|
||||
aptitude_label.custom_minimum_size = Vector2(130, 0)
|
||||
aptitude_label.custom_minimum_size = Vector2(260, 0)
|
||||
row.add_child(aptitude_label)
|
||||
|
||||
var roots_label := Label.new()
|
||||
roots_label.text = d.get_roots_text() + "灵根"
|
||||
roots_label.custom_minimum_size = Vector2(160, 0)
|
||||
roots_label.custom_minimum_size = Vector2(320, 0)
|
||||
row.add_child(roots_label)
|
||||
|
||||
var realm_label := Label.new()
|
||||
@@ -78,6 +78,11 @@ func _add_entry(d: Disciple) -> void:
|
||||
realm_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
row.add_child(realm_label)
|
||||
|
||||
var progress_label := Label.new()
|
||||
progress_label.text = d.get_cultivation_progress_text()
|
||||
progress_label.custom_minimum_size = Vector2(220, 0)
|
||||
row.add_child(progress_label)
|
||||
|
||||
var detail_button := Button.new()
|
||||
detail_button.text = "详情"
|
||||
detail_button.button_up.connect(_on_detail_button_up.bind(d))
|
||||
|
||||
Reference in New Issue
Block a user