Improve prestige

This commit is contained in:
2026-04-08 08:18:10 +02:00
parent ee374a3d74
commit 6c031aa381
7 changed files with 212 additions and 43 deletions

View File

@@ -21,8 +21,8 @@ PrestigeManager (autoload node)
├── Calculates pending gain ├── Calculates pending gain
├── Applies multipliers to generators ├── Applies multipliers to generators
└── PrestigePanel (UI) └── PrestigePanel (UI)
├── Shows current/pending prestige ├── Shows current/pending prestige
└── Trigger reset button └── Trigger reset button
``` ```
## PrestigeConfig ## PrestigeConfig
@@ -33,23 +33,23 @@ Resource defining prestige rules.
```gdscript ```gdscript
enum BasisType { enum BasisType {
LIFETIME_TOTAL, # All-time currency acquired LIFETIME_TOTAL, # All-time currency acquired
RUN_TOTAL, # Currency this run RUN_TOTAL, # Currency this run
RUN_MAX # Peak currency this run RUN_MAX # Peak currency this run
} }
enum FormulaType { enum FormulaType {
POWER, # gain = scale * (ratio^exponent) POWER, # gain = scale * (ratio^exponent)
TRIANGULAR_INVERSE # gain based on triangular number inverse TRIANGULAR_INVERSE # gain based on triangular number inverse
} }
enum RoundingMode { enum RoundingMode {
FLOOR, ROUND, CEIL FLOOR, ROUND, CEIL
} }
enum MultiplierMode { enum MultiplierMode {
ADDITIVE, # +X per prestige ADDITIVE, # +X per prestige
MULTIPLICATIVE_POWER # x^(multiplier_per_prestige) MULTIPLICATIVE_POWER # x^(multiplier_per_prestige)
} }
``` ```
@@ -119,7 +119,7 @@ raw_gain = scale * (ratio^exponent) + flat_bonus
# Cumulative basis subtracts already earned # Cumulative basis subtracts already earned
if basis == LIFETIME_TOTAL: if basis == LIFETIME_TOTAL:
gain = raw_gain - total_prestige_earned gain = raw_gain - total_prestige_earned
``` ```
**Triangular Inverse Formula**: **Triangular Inverse Formula**:
@@ -129,7 +129,7 @@ k = basis_value / threshold
target_total = (sqrt(1 + 8k) - 1) * 0.5 target_total = (sqrt(1 + 8k) - 1) * 0.5
if basis == LIFETIME_TOTAL: if basis == LIFETIME_TOTAL:
gain = target_total - total_prestige_earned gain = target_total - total_prestige_earned
``` ```
### Multiplier Application ### Multiplier Application
@@ -185,13 +185,13 @@ Generators apply prestige multipliers automatically:
```gdscript ```gdscript
func get_effective_auto_run_multiplier() -> float: func get_effective_auto_run_multiplier() -> float:
return run_multiplier * buff_multiplier * _get_prestige_multiplier() return run_multiplier * buff_multiplier * _get_prestige_multiplier()
func _get_prestige_multiplier() -> float: func _get_prestige_multiplier() -> float:
var manager = get_node_or_null("/root/PrestigeManager") var manager = get_node_or_null("/root/PrestigeManager")
if manager: if manager:
return manager.get_total_multiplier() return manager.get_total_multiplier()
return 1.0 return 1.0
``` ```
## Save Integration ## Save Integration
@@ -201,12 +201,12 @@ Prestige state stored in `GameState` external save:
```json ```json
{ {
"prestige": { "prestige": {
"total_prestige_earned": {"m": 10.0, "e": 0}, "total_prestige_earned": {"m": 10.0, "e": 0},
"current_prestige_unspent": {"m": 5.0, "e": 0}, "current_prestige_unspent": {"m": 5.0, "e": 0},
"prestige_resets_count": 3, "prestige_resets_count": 3,
"run_start_total_source_currency": {"m": 1000.0, "e": 0}, "run_start_total_source_currency": {"m": 1000.0, "e": 0},
"run_peak_source_currency": {"m": 5000.0, "e": 0}, "run_peak_source_currency": {"m": 5000.0, "e": 0},
"last_reset_time": 1234567890 "last_reset_time": 1234567890
} }
} }
``` ```

View File

@@ -2,6 +2,7 @@ extends Node
signal prestige_state_changed(total_prestige: BigNumber, pending_gain: BigNumber) signal prestige_state_changed(total_prestige: BigNumber, pending_gain: BigNumber)
signal prestige_performed(gain: BigNumber, total_prestige: BigNumber) signal prestige_performed(gain: BigNumber, total_prestige: BigNumber)
signal prestige_threshold_changed(next_threshold: BigNumber)
const SAVE_KEY: String = "prestige_state" const SAVE_KEY: String = "prestige_state"
const TOTAL_PRESTIGE_KEY: String = "total_prestige_earned" const TOTAL_PRESTIGE_KEY: String = "total_prestige_earned"
@@ -48,6 +49,10 @@ func _ready() -> void:
GameState.currency_changed.connect(_on_currency_changed) GameState.currency_changed.connect(_on_currency_changed)
prestige_state_changed.emit(get_total_prestige(), calculate_pending_gain()) prestige_state_changed.emit(get_total_prestige(), calculate_pending_gain())
prestige_threshold_changed.emit(get_next_prestige_threshold())
func get_config() -> Resource:
return config
func get_source_currency_id() -> StringName: func get_source_currency_id() -> StringName:
if not _is_config_valid(): if not _is_config_valid():
@@ -138,10 +143,24 @@ func perform_prestige() -> bool:
GameState.save_game() GameState.save_game()
var total: BigNumber = get_total_prestige() var total: BigNumber = get_total_prestige()
var next_threshold: BigNumber = get_next_prestige_threshold()
prestige_performed.emit(gain, total) prestige_performed.emit(gain, total)
prestige_state_changed.emit(total, calculate_pending_gain()) prestige_state_changed.emit(total, calculate_pending_gain())
prestige_threshold_changed.emit(next_threshold)
return true return true
func get_next_prestige_threshold() -> BigNumber:
if not _is_config_valid():
return BigNumber.from_float(0.0)
match _get_config_int("basis", BASIS_LIFETIME_TOTAL):
BASIS_RUN_TOTAL:
return _get_config_threshold()
_:
var current_total: float = _big_number_to_float(total_prestige_earned)
var next_target: float = _calculate_target_for_prestige(current_total + 1.0)
return BigNumber.from_float(next_target)
func get_basis_value_for_display() -> BigNumber: func get_basis_value_for_display() -> BigNumber:
return _get_basis_value() return _get_basis_value()
@@ -171,7 +190,36 @@ func _on_currency_changed(changed_currency_id: StringName, new_amount: BigNumber
run_peak_source_currency = _copy_big_number(new_amount) run_peak_source_currency = _copy_big_number(new_amount)
_save_state_to_game_state() _save_state_to_game_state()
var next_threshold: BigNumber = get_next_prestige_threshold()
prestige_state_changed.emit(get_total_prestige(), calculate_pending_gain()) prestige_state_changed.emit(get_total_prestige(), calculate_pending_gain())
prestige_threshold_changed.emit(next_threshold)
func _calculate_target_for_prestige(prestige_level: float) -> float:
if config == null:
return 0.0
var threshold_value: float = _big_number_to_float(_get_config_threshold())
if threshold_value <= 0.0:
return 0.0
match _get_config_int("formula", FORMULA_POWER):
FORMULA_TRIANGULAR_INVERSE:
var target_total: float = prestige_level
var k: float = target_total * (target_total + 1.0) * 0.5
return k * threshold_value
_:
var scale: float = maxf(_get_config_float("scale", 1.0), 0.0001)
var exponent: float = maxf(_get_config_float("exponent", 1.0), 0.0001)
var flat_bonus: float = _get_config_float("flat_bonus", 0.0)
if scale <= 0.0:
scale = 0.0001
if exponent <= 0.0:
exponent = 0.0001
var ratio: float = pow((prestige_level - flat_bonus) / scale, 1.0 / exponent)
if ratio <= 0.0:
return threshold_value
return ratio * threshold_value
func _calculate_raw_gain_float(basis_value: BigNumber) -> float: func _calculate_raw_gain_float(basis_value: BigNumber) -> float:
if config == null: if config == null:

View File

@@ -5,6 +5,7 @@ extends PanelContainer
@onready var _pending_value: Label = $MarginContainer/VBoxContainer/StatsGrid/PendingValue @onready var _pending_value: Label = $MarginContainer/VBoxContainer/StatsGrid/PendingValue
@onready var _multiplier_value: Label = $MarginContainer/VBoxContainer/StatsGrid/MultiplierValue @onready var _multiplier_value: Label = $MarginContainer/VBoxContainer/StatsGrid/MultiplierValue
@onready var _basis_label: Label = $MarginContainer/VBoxContainer/StatsGrid/BasisValue @onready var _basis_label: Label = $MarginContainer/VBoxContainer/StatsGrid/BasisValue
@onready var _progress_bar: Node = $MarginContainer/VBoxContainer/PrestigeProgressBar
@onready var _reset_button: Button = $MarginContainer/VBoxContainer/Buttons/ResetButton @onready var _reset_button: Button = $MarginContainer/VBoxContainer/Buttons/ResetButton
@onready var _save_button: Button = $MarginContainer/VBoxContainer/Buttons/SaveButton @onready var _save_button: Button = $MarginContainer/VBoxContainer/Buttons/SaveButton
@onready var _confirm_dialog: ConfirmationDialog = $ConfirmDialog @onready var _confirm_dialog: ConfirmationDialog = $ConfirmDialog

View File

@@ -1,76 +1,81 @@
[gd_scene load_steps=2 format=3] [gd_scene format=3 uid="uid://dlidx2x0otpjg"]
[ext_resource type="Script" path="res://core/prestige/prestige_panel.gd" id="1_7fdwq"] [ext_resource type="Script" uid="uid://dmsmmgtbrul1t" path="res://core/prestige/prestige_panel.gd" id="1_panel"]
[ext_resource type="PackedScene" path="res://core/prestige/prestige_progress_bar.tscn" id="2_7b6yg"]
[node name="PrestigePanel" type="PanelContainer"] [node name="PrestigePanel" type="PanelContainer" unique_id=789062217]
offset_right = 420.0 offset_right = 420.0
offset_bottom = 206.0 offset_bottom = 206.0
script = ExtResource("1_7fdwq") script = ExtResource("1_panel")
[node name="MarginContainer" type="MarginContainer" parent="."] [node name="MarginContainer" type="MarginContainer" parent="." unique_id=1133221945]
layout_mode = 2 layout_mode = 2
theme_override_constants/margin_left = 10 theme_override_constants/margin_left = 10
theme_override_constants/margin_top = 10 theme_override_constants/margin_top = 10
theme_override_constants/margin_right = 10 theme_override_constants/margin_right = 10
theme_override_constants/margin_bottom = 10 theme_override_constants/margin_bottom = 10
[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"] [node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer" unique_id=1014101412]
layout_mode = 2 layout_mode = 2
theme_override_constants/separation = 8 theme_override_constants/separation = 8
[node name="Title" type="Label" parent="MarginContainer/VBoxContainer"] [node name="Title" type="Label" parent="MarginContainer/VBoxContainer" unique_id=738033951]
layout_mode = 2 layout_mode = 2
text = "Prestige" text = "Prestige"
[node name="StatsGrid" type="GridContainer" parent="MarginContainer/VBoxContainer"] [node name="StatsGrid" type="GridContainer" parent="MarginContainer/VBoxContainer" unique_id=1121463897]
layout_mode = 2 layout_mode = 2
columns = 2 columns = 2
[node name="TotalTitle" type="Label" parent="MarginContainer/VBoxContainer/StatsGrid"] [node name="TotalTitle" type="Label" parent="MarginContainer/VBoxContainer/StatsGrid" unique_id=1462148351]
layout_mode = 2 layout_mode = 2
text = "Total" text = "Total"
[node name="TotalValue" type="Label" parent="MarginContainer/VBoxContainer/StatsGrid"] [node name="TotalValue" type="Label" parent="MarginContainer/VBoxContainer/StatsGrid" unique_id=1607797034]
layout_mode = 2 layout_mode = 2
text = "0" text = "0"
[node name="PendingTitle" type="Label" parent="MarginContainer/VBoxContainer/StatsGrid"] [node name="PendingTitle" type="Label" parent="MarginContainer/VBoxContainer/StatsGrid" unique_id=1999999111]
layout_mode = 2 layout_mode = 2
text = "Pending" text = "Pending"
[node name="PendingValue" type="Label" parent="MarginContainer/VBoxContainer/StatsGrid"] [node name="PendingValue" type="Label" parent="MarginContainer/VBoxContainer/StatsGrid" unique_id=1731674897]
layout_mode = 2 layout_mode = 2
text = "0" text = "0"
[node name="MultiplierTitle" type="Label" parent="MarginContainer/VBoxContainer/StatsGrid"] [node name="MultiplierTitle" type="Label" parent="MarginContainer/VBoxContainer/StatsGrid" unique_id=1338227256]
layout_mode = 2 layout_mode = 2
text = "Multiplier" text = "Multiplier"
[node name="MultiplierValue" type="Label" parent="MarginContainer/VBoxContainer/StatsGrid"] [node name="MultiplierValue" type="Label" parent="MarginContainer/VBoxContainer/StatsGrid" unique_id=1407185183]
layout_mode = 2 layout_mode = 2
text = "x1.00" text = "x1.00"
[node name="BasisTitle" type="Label" parent="MarginContainer/VBoxContainer/StatsGrid"] [node name="BasisTitle" type="Label" parent="MarginContainer/VBoxContainer/StatsGrid" unique_id=1092652344]
layout_mode = 2 layout_mode = 2
text = "Basis" text = "Basis"
[node name="BasisValue" type="Label" parent="MarginContainer/VBoxContainer/StatsGrid"] [node name="BasisValue" type="Label" parent="MarginContainer/VBoxContainer/StatsGrid" unique_id=1421212102]
layout_mode = 2 layout_mode = 2
text = "-" text = "-"
[node name="Buttons" type="HBoxContainer" parent="MarginContainer/VBoxContainer"] [node name="PrestigeProgressBar" parent="MarginContainer/VBoxContainer" unique_id=619882824 instance=ExtResource("2_7b6yg")]
layout_mode = 2
[node name="Buttons" type="HBoxContainer" parent="MarginContainer/VBoxContainer" unique_id=634533362]
layout_mode = 2 layout_mode = 2
theme_override_constants/separation = 8 theme_override_constants/separation = 8
[node name="ResetButton" type="Button" parent="MarginContainer/VBoxContainer/Buttons"] [node name="ResetButton" type="Button" parent="MarginContainer/VBoxContainer/Buttons" unique_id=379577642]
layout_mode = 2 layout_mode = 2
text = "Prestige Reset" text = "Prestige Reset"
[node name="SaveButton" type="Button" parent="MarginContainer/VBoxContainer/Buttons"] [node name="SaveButton" type="Button" parent="MarginContainer/VBoxContainer/Buttons" unique_id=1151017798]
layout_mode = 2 layout_mode = 2
text = "Save" text = "Save"
[node name="ConfirmDialog" type="ConfirmationDialog" parent="."] [node name="ConfirmDialog" type="ConfirmationDialog" parent="." unique_id=1893210048]
oversampling_override = 1.0
title = "Prestige Reset" title = "Prestige Reset"
ok_button_text = "Prestige" ok_button_text = "Prestige"
dialog_text = "Reset this run?" dialog_text = "Reset this run?"

View File

@@ -0,0 +1,92 @@
extends HBoxContainer
@export var config: PrestigeConfig
@onready var _label_start = $LabelStart
@onready var _label_end = $LabelEnd
@onready var _progress_bar = $ProgressBar
var _basis_value: BigNumber
var _next_threshold: BigNumber
var _manager: Node
var _connected: bool = false
func _ready() -> void:
_manager = get_node_or_null("/root/PrestigeManager")
if _manager == null:
push_warning("PrestigeProgressBar '%s' cannot find PrestigeManager; progress bar disabled." % String(name))
visible = false
return
if not _manager.has_signal("prestige_state_changed"):
push_warning("PrestigeManager does not have 'prestige_state_changed' signal; progress bar will not update.")
visible = false
return
if config == null:
if _manager.has_method("get_config"):
config = _manager.get_config()
if config == null:
push_warning("PrestigeProgressBar '%s' has no config; progress bar disabled." % String(name))
visible = false
return
if _manager.has_signal("prestige_threshold_changed"):
_manager.prestige_threshold_changed.connect(_on_prestige_threshold_changed)
_manager.prestige_state_changed.connect(_on_prestige_state_changed)
_connected = true
_update_progress()
func _on_prestige_state_changed(_total: BigNumber, _pending: BigNumber) -> void:
_update_progress()
func _on_prestige_threshold_changed(_threshold: BigNumber) -> void:
_update_progress()
func _update_progress() -> void:
if not _connected:
return
if _manager == null or config == null:
return
_basis_value = _manager.call("get_basis_value_for_display")
if _manager.has_method("get_next_prestige_threshold"):
_next_threshold = _manager.call("get_next_prestige_threshold")
else:
_next_threshold = _get_threshold_from_config()
var basis_float: float = _big_number_to_float(_basis_value)
var threshold_float: float = _big_number_to_float(_next_threshold)
if threshold_float > 0.0 and basis_float >= 0.0:
var ratio: float = minf(basis_float / threshold_float, 1.0)
_progress_bar.value = ratio * 100.0
else:
_progress_bar.value = 0.0
_label_start.text = _basis_value.to_string_suffix(2)
_label_end.text = _next_threshold.to_string_suffix(2)
func _get_threshold_from_config() -> BigNumber:
if config == null:
return BigNumber.from_float(0.0)
if not config.has_method("get_threshold"):
return BigNumber.from_float(0.0)
var threshold = config.call("get_threshold")
if threshold is BigNumber:
return threshold
return BigNumber.from_float(0.0)
func _big_number_to_float(value: BigNumber) -> float:
if value.mantissa <= 0.0:
return 0.0
if value.exponent > 308:
return INF
if value.exponent < -308:
return 0.0
return value.mantissa * pow(10.0, float(value.exponent))

View File

@@ -0,0 +1 @@
uid://dsq8yix7kkyaj

View File

@@ -0,0 +1,22 @@
[gd_scene format=3]
[ext_resource type="Script" path="res://core/prestige/prestige_progress_bar.gd" id="1_pbg"]
[node name="PrestigeProgressBar" type="HBoxContainer"]
offset_right = 298.0
offset_bottom = 49.0
alignment = 1
script = ExtResource("1_pbg")
[node name="LabelStart" type="Label" parent="."]
layout_mode = 2
text = "0"
[node name="ProgressBar" type="ProgressBar" parent="."]
custom_minimum_size = Vector2(200, 0)
layout_mode = 2
show_percentage = true
[node name="LabelEnd" type="Label" parent="."]
layout_mode = 2
text = "0"