feat: 修炼循环闭环——升层/瓶颈突破(按层概率)+管理界面修为进度+面板放大
This commit is contained in:
+15
-13
@@ -2,7 +2,7 @@
|
||||
|
||||
> 对应开发计划表 D5(8/7):① 修为随时间增长(资质×灵气)② 境界门槛 ③ 突破判定。
|
||||
> 交付标准:弟子自动修炼,可突破。本文档只描述设计,不包含代码。
|
||||
> 状态:设计稿,待审阅通过后实现
|
||||
> 状态:①②③ 已实现(每日结算 → 修为达门槛升层 → 瓶颈掷骰判定,失败扣 20%;13 层圆满封顶);修为进度已在管理界面展示
|
||||
|
||||
---
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
## 四、突破判定(瓶颈层)
|
||||
|
||||
1. 修为 ≥ 瓶颈层门槛时,每日结算后自动尝试突破
|
||||
2. 掷骰:成功概率 = 配置 `breakthrough_chance`(默认 0.8)
|
||||
2. 掷骰:成功概率**按瓶颈层分别配置**(`breakthrough_chances`,与 `bottleneck_levels` 一一对应:升 4 层 0.85 / 升 7 层 0.8 / 升 10 层 0.75 / 升 13 层 0.6,越往上越难)
|
||||
3. **成功** → 升层,控制台打印"X 突破至 练气4层"
|
||||
4. **失败** → 修为扣减 20%(冲关损耗),次日再尝试;控制台打印失败信息
|
||||
5. 失败不连续重试(每天最多判定一次)
|
||||
@@ -105,9 +105,9 @@ base_speed=10 ; 基础修为/日
|
||||
qi_concentration=1.0 ; 宗门灵气浓度(D6 动态化)
|
||||
aptitude_speed=[0.6, 1.0, 1.5, 2.0] ; 资质倍率(下品/中品/上品/天骄)
|
||||
heavenly_bonus=1.5 ; 天灵根额外倍率
|
||||
breakthrough_chance=0.8 ; 瓶颈突破成功率(待接入)
|
||||
level_thresholds=[100, 200, 350, 550, 800, 1100, 1500, 2000, 2600, 3300, 4100, 5000] ; 待接入
|
||||
bottleneck_levels=[4, 7, 10, 13] ; 待接入
|
||||
breakthrough_chances=[0.85, 0.8, 0.75, 0.6] ; 各瓶颈层突破成功率(与 bottleneck_levels 一一对应)
|
||||
level_thresholds=[100, 200, 350, 550, 800, 1100, 1500, 2000, 2600, 3300, 4100, 5000] ; 练气 1→2 到 12→13 各层所需修为
|
||||
bottleneck_levels=[4, 7, 10, 13] ; 瓶颈目标层(升到这些层需突破判定)
|
||||
```
|
||||
|
||||
- `aptitude_speed`:与资质枚举一一对应,必须 4 项
|
||||
@@ -118,9 +118,9 @@ bottleneck_levels=[4, 7, 10, 13] ; 待接入
|
||||
|
||||
## 七、UI 接入(D4 预留区填充)
|
||||
|
||||
- **名录列表**(DisciplesPanel):条目追加"修为"列(如 "1234 / 800",当前修为/本层门槛;13 层显示"练气圆满")
|
||||
- **详情弹窗**:信息区追加"修为:1234 / 2000"(当前/本层门槛;13 层显示 练气圆满)
|
||||
- **名录列表**:境界列实时变化(realm_changed 后自动刷新,现有 disciples_changed 不触发,需详情面板监听 realm_changed)
|
||||
- 修炼日志:控制台 print(本期不做日志界面)
|
||||
- 面板打开时暂停时间,进度静态展示;修炼日志:控制台 print(本期不做日志界面)
|
||||
|
||||
---
|
||||
|
||||
@@ -138,9 +138,11 @@ bottleneck_levels=[4, 7, 10, 13] ; 待接入
|
||||
|
||||
## 九、验收清单(D5 交付标准)
|
||||
|
||||
- [ ] 挂机时弟子修为逐日增长,速度随资质/天灵根不同(下品慢、天骄快)
|
||||
- [ ] 非瓶颈层修为满自动升层,无失败
|
||||
- [ ] 瓶颈层(4/7/10/13 层)需突破判定,控制台有成败日志,失败扣 20% 修为
|
||||
- [ ] 练气 13 层圆满后修为封顶,显示"练气圆满"
|
||||
- [ ] 详情面板显示修为进度,突破后实时刷新
|
||||
- [ ] 修改配置(速度/概率/门槛)重启生效
|
||||
- [x] 挂机时弟子修为逐日增长,速度随资质/天灵根不同(下品慢、天骄快)
|
||||
- [x] 非瓶颈层修为满自动升层,无失败
|
||||
- [x] 瓶颈层(4/7/10/13 层)需突破判定,控制台有成败日志,失败扣 20% 修为
|
||||
- [x] 练气 13 层圆满后修为封顶,显示"练气圆满"
|
||||
- [x] 详情面板显示修为进度,突破后实时刷新
|
||||
- [x] 修改配置(速度/概率/门槛)重启生效
|
||||
|
||||
> 注:修为显示("当前/本层门槛")待详情面板接入(拆解第 6 步)。
|
||||
|
||||
@@ -218,7 +218,7 @@ aptitude_weights=[60, 30, 8, 2]
|
||||
|------|------|
|
||||
| 标题 | "弟子名录(N 人)",N = 当前名录人数 |
|
||||
| 列表区 | ScrollContainer 动态条目,一个弟子一行,按入宗顺序 |
|
||||
| 条目内容 | 姓名 / 资质(含天灵根标记)/ 灵根 / 境界 + "详情"按钮 |
|
||||
| 条目内容 | 姓名 / 资质(含天灵根标记)/ 灵根 / 境界 / **修为进度** + "详情"按钮 |
|
||||
| 空状态 | 名录为空时显示"暂无弟子"提示 |
|
||||
| 底部 | "关闭"按钮(也可点遮罩关闭) |
|
||||
|
||||
@@ -227,7 +227,7 @@ aptitude_weights=[60, 30, 8, 2]
|
||||
| 元素 | 说明 |
|
||||
|------|------|
|
||||
| 标题 | 弟子姓名 + 天灵根标记 |
|
||||
| 信息区 | 静态展示:名字 / 资质 / 年龄 / 灵根 / 境界 / **入宗时间** |
|
||||
| 信息区 | 静态展示:名字 / 资质 / 年龄 / 灵根 / 境界 / **修为进度** / **入宗时间** |
|
||||
| 预留区 | 修炼进度、属性面板等 D5+ 扩展位置(本期留白) |
|
||||
| 底部 | "关闭"按钮 |
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ Settings="*res://src/Core/Settings.gd"
|
||||
SectManager="*res://src/Core/SectManager.gd"
|
||||
GameConfig="*res://src/Core/GameConfig.gd"
|
||||
DiscipleManager="*res://src/Character/DiscipleManager.gd"
|
||||
CultivationManager="*res://src/Character/CultivationManager.gd"
|
||||
|
||||
[display]
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
difficulty="normal"
|
||||
opening_applicant_count=5
|
||||
opening_pick_count=3
|
||||
recruit_interval_years=0.25
|
||||
recruit_interval_years=12
|
||||
recruit_applicant_count=3
|
||||
heavenly_root_chance=0.5 ; 天灵根概率:仅天骄资质中再掷,50%
|
||||
root_count_weights=[20, 20, 20, 20, 20] ; 灵根数量权重(1根/2根/3根/4根/5根,和=100 即百分比概率)
|
||||
@@ -24,6 +24,9 @@ base_speed=10 ; 基础修为/日
|
||||
qi_concentration=1.0 ; 宗门灵气浓度
|
||||
aptitude_speed=[0.6, 1.0, 1.5, 2.0] ; 资质倍率(下品/中品/上品/天骄)
|
||||
heavenly_bonus=1.5 ; 天灵根额外修炼速度倍率
|
||||
breakthrough_chances=[0.85, 0.8, 0.75, 0.6] ; 各瓶颈层突破成功率(与 bottleneck_levels 一一对应:升4层/7层/10层/13层)
|
||||
level_thresholds=[100, 200, 350, 550, 800, 1100, 1500, 2000, 2600, 3300, 4100, 5000] ; 练气 1→2 到 12→13 各层所需修为
|
||||
bottleneck_levels=[4, 7, 10, 13] ; 瓶颈目标层(升到这些层需突破判定)
|
||||
|
||||
[ui] ; UI 通用
|
||||
hud_font_size=28 ; HUD 字体大小
|
||||
|
||||
@@ -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