102 lines
3.8 KiB
GDScript
102 lines
3.8 KiB
GDScript
## 修炼管理器(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:
|
|
_settle_food()
|
|
for d in DiscipleManager.disciples:
|
|
_gain_exp(d)
|
|
_check_breakthrough(d)
|
|
|
|
## 每日口粮结算:练气弟子人均消耗灵米(筑基+辟谷豁免)。
|
|
## 食物充足 → 扣减并饥饿清零;食物不足 → 归零并全员饥饿天数 +1;
|
|
## 饥饿天数 ≥ 阈值(配置 hunger_threshold_days)→ 弟子离宗,从名录移除。
|
|
func _settle_food() -> void:
|
|
var eaters: Array[Disciple] = []
|
|
for d in DiscipleManager.disciples:
|
|
if d.realm_index == 0:
|
|
eaters.append(d)
|
|
var need := eaters.size() * GameConfig.food_consumption_per_disciple
|
|
if SectManager.food >= need:
|
|
SectManager.remove_food(need)
|
|
for d in eaters:
|
|
d.hunger_days = 0
|
|
return
|
|
SectManager.remove_food(SectManager.food)
|
|
var leavers: Array[Disciple] = []
|
|
for d in eaters:
|
|
d.hunger_days += 1
|
|
if d.hunger_days >= GameConfig.hunger_threshold_days:
|
|
leavers.append(d)
|
|
for d in leavers:
|
|
_log("%s 断粮日久,离宗而去" % d.name)
|
|
DiscipleManager.remove_disciple(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
|
|
if d.hunger_days > 0:
|
|
speed *= GameConfig.hunger_speed_multiplier
|
|
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)
|