Improve prestige and add ascension as currency
This commit is contained in:
@@ -33,9 +33,10 @@ Resource defining prestige rules.
|
||||
|
||||
```gdscript
|
||||
enum BasisType {
|
||||
LIFETIME_TOTAL, # All-time currency acquired
|
||||
RUN_TOTAL, # Currency this run
|
||||
RUN_MAX # Peak currency this run
|
||||
LIFETIME_TOTAL, # All-time currency acquired (single currency)
|
||||
RUN_TOTAL, # Currency this run (single currency)
|
||||
RUN_MAX, # Peak currency this run (single currency)
|
||||
ALL_CURRENCIES # Sum of all currencies (multi-currency tracking)
|
||||
}
|
||||
|
||||
enum FormulaType {
|
||||
@@ -59,10 +60,13 @@ enum MultiplierMode {
|
||||
@export var id: StringName = &"primary"
|
||||
@export var display_name: String = "Ascension"
|
||||
@export var prestige_currency_id: StringName = &"prestige"
|
||||
@export var source_currency_id: StringName = &"magic" # What to measure
|
||||
@export var source_currency_id: StringName = &"magic" # What to measure (ignored for ALL_CURRENCIES)
|
||||
@export var basis: BasisType = LIFETIME_TOTAL
|
||||
@export var formula: FormulaType = POWER
|
||||
|
||||
# Currency tracking
|
||||
@export var include_currency_ids: Array[StringName] = [] # Empty = all currencies (for ALL_CURRENCIES basis)
|
||||
|
||||
# Threshold: minimum source currency needed
|
||||
@export var threshold_mantissa: float = 1.0
|
||||
@export var threshold_exponent: int = 4 # 1e4 = 10,000
|
||||
@@ -132,6 +136,22 @@ if basis == LIFETIME_TOTAL:
|
||||
gain = target_total - total_prestige_earned
|
||||
```
|
||||
|
||||
**Basis Value Calculation**:
|
||||
```gdscript
|
||||
if basis == ALL_CURRENCIES:
|
||||
# Sum of all tracked currencies
|
||||
basis_value = sum(get_total_currency_acquired(currency_id) for currency_id in tracked_currencies)
|
||||
elif basis == RUN_TOTAL:
|
||||
# Currency earned since last reset
|
||||
basis_value = lifetime_total - run_start_total
|
||||
elif basis == RUN_MAX:
|
||||
# Peak currency reached this run
|
||||
basis_value = run_peak_currency
|
||||
else: # LIFETIME_TOTAL
|
||||
# All-time currency acquired
|
||||
basis_value = lifetime_total
|
||||
```
|
||||
|
||||
### Multiplier Application
|
||||
|
||||
**Additive Mode**:
|
||||
@@ -151,15 +171,20 @@ multiplier = base_multiplier * (growth_base ^ total_prestige)
|
||||
|
||||
1. Player clicks "Prestige" button
|
||||
2. `perform_prestige()` called
|
||||
3. Gain calculated and added to total
|
||||
3. Gain calculated and added to total:
|
||||
- For ALL_CURRENCIES: sum of all tracked currencies is used
|
||||
- For single-currency: source currency is used
|
||||
4. `GameState.reset_for_prestige()` called:
|
||||
- Current currencies reset to 0
|
||||
- Generator states cleared
|
||||
- Buff levels reset to 0
|
||||
- Goal completion cleared and re-initialized
|
||||
- Lifetime totals preserved
|
||||
5. Generators reinitialized
|
||||
6. Save triggered
|
||||
5. Run tracking reinitialized:
|
||||
- For ALL_CURRENCIES: sum of all currencies at reset time
|
||||
- For single-currency: source currency at reset time
|
||||
6. Generators reinitialized
|
||||
7. Save triggered
|
||||
|
||||
## PrestigePanel
|
||||
|
||||
@@ -171,7 +196,8 @@ UI component for prestige interaction.
|
||||
_total_value.text = "123.45" # Total prestige earned
|
||||
_pending_value.text = "56.78" # Gain available now
|
||||
_multiplier_value.text = "x2.34" # Current multiplier
|
||||
_basis_label.text = "Lifetime Total (1.50e6 Magic)"
|
||||
_basis_label.text = "Total Currency (1.50e6)" # For ALL_CURRENCIES basis
|
||||
# Or: "Lifetime Total (1.50e6 Magic)" # For LIFETIME_TOTAL basis
|
||||
```
|
||||
|
||||
### Buttons
|
||||
@@ -213,7 +239,7 @@ Prestige state stored in `GameState` external save:
|
||||
|
||||
## Configuration Example
|
||||
|
||||
For a typical idle game:
|
||||
For a typical idle game with single currency:
|
||||
|
||||
```gdscript
|
||||
# Primary prestige currency
|
||||
@@ -237,6 +263,33 @@ multiplier_mode = ADDITIVE
|
||||
multiplier_per_prestige = 0.10
|
||||
```
|
||||
|
||||
For multi-currency tracking (ALL_CURRENCIES):
|
||||
|
||||
```gdscript
|
||||
id = &"ascension"
|
||||
display_name = "Ascension"
|
||||
prestige_currency_id = &"ascension"
|
||||
|
||||
# Track sum of ALL currencies (gold + wood + food + etc.)
|
||||
basis = ALL_CURRENCIES
|
||||
|
||||
# Empty include_currency_ids means all currencies from catalog
|
||||
# Set specific IDs to track only those: include_currency_ids = [&"gold", &"wood"]
|
||||
include_currency_ids = []
|
||||
|
||||
# Need 1e4 total currency sum to get first prestige
|
||||
threshold_mantissa = 1.0
|
||||
threshold_exponent = 4
|
||||
|
||||
# Square root scaling
|
||||
formula = POWER
|
||||
exponent = 0.5
|
||||
|
||||
# +5% multiplier per prestige point
|
||||
multiplier_mode = ADDITIVE
|
||||
multiplier_per_prestige = 0.05
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
||||
- `core/game_state.gd` - State persistence
|
||||
|
||||
@@ -5,6 +5,7 @@ enum BasisType {
|
||||
LIFETIME_TOTAL,
|
||||
RUN_TOTAL,
|
||||
RUN_MAX,
|
||||
ALL_CURRENCIES,
|
||||
}
|
||||
|
||||
enum FormulaType {
|
||||
@@ -41,6 +42,7 @@ enum MultiplierMode {
|
||||
@export var base_multiplier: float = 1.0
|
||||
@export var multiplier_per_prestige: float = 0.05
|
||||
@export var multiplier_exponent: float = 1.0
|
||||
@export var include_currency_ids: Array[StringName] = []
|
||||
|
||||
func get_threshold() -> BigNumber:
|
||||
return BigNumber.new(threshold_mantissa, threshold_exponent)
|
||||
@@ -48,7 +50,7 @@ func get_threshold() -> BigNumber:
|
||||
func is_valid() -> bool:
|
||||
if String(id).strip_edges().is_empty():
|
||||
return false
|
||||
if String(source_currency_id).strip_edges().is_empty():
|
||||
if String(source_currency_id).strip_edges().is_empty() and basis != BasisType.ALL_CURRENCIES:
|
||||
return false
|
||||
if threshold_mantissa <= 0.0:
|
||||
return false
|
||||
|
||||
@@ -16,6 +16,7 @@ const LAST_RESET_TIME_KEY: String = "last_reset_time"
|
||||
const BASIS_LIFETIME_TOTAL: int = 0
|
||||
const BASIS_RUN_TOTAL: int = 1
|
||||
const BASIS_RUN_MAX: int = 2
|
||||
const BASIS_ALL_CURRENCIES: int = 3
|
||||
|
||||
const FORMULA_POWER: int = 0
|
||||
const FORMULA_TRIANGULAR_INVERSE: int = 1
|
||||
@@ -66,6 +67,38 @@ func get_source_currency_id() -> StringName:
|
||||
|
||||
return _normalize_currency_id(_get_config_string_name("source_currency_id", &""))
|
||||
|
||||
func get_prestige_currency_id() -> StringName:
|
||||
if not _is_config_valid():
|
||||
return &""
|
||||
|
||||
return _normalize_currency_id(_get_config_string_name("prestige_currency_id", &""))
|
||||
|
||||
func get_tracked_currency_ids() -> Array[StringName]:
|
||||
if not _is_config_valid():
|
||||
return []
|
||||
|
||||
var basis_type: int = _get_config_int("basis", BASIS_LIFETIME_TOTAL)
|
||||
|
||||
if basis_type == BASIS_ALL_CURRENCIES:
|
||||
var include_ids: Array[StringName] = _get_config_array("include_currency_ids", [])
|
||||
if not include_ids.is_empty():
|
||||
return include_ids
|
||||
if game_state and game_state.currency_catalogue:
|
||||
return game_state.currency_catalogue.get_all_ids()
|
||||
return []
|
||||
|
||||
return [get_source_currency_id()]
|
||||
|
||||
func _get_config_array(property_name: String, fallback: Array = []) -> Array:
|
||||
if config == null:
|
||||
return fallback
|
||||
|
||||
var value: Variant = config.get(property_name)
|
||||
if value is Array:
|
||||
return value
|
||||
|
||||
return fallback
|
||||
|
||||
func get_total_prestige() -> BigNumber:
|
||||
return _copy_big_number(total_prestige_earned)
|
||||
|
||||
@@ -136,12 +169,20 @@ func perform_prestige() -> bool:
|
||||
if gain.mantissa > 0.0:
|
||||
total_prestige_earned.add_in_place(gain)
|
||||
current_prestige_unspent.add_in_place(gain)
|
||||
|
||||
var prestige_currency_id: StringName = get_prestige_currency_id()
|
||||
if prestige_currency_id != &"" and game_state:
|
||||
game_state.add_currency_by_id(prestige_currency_id, gain)
|
||||
|
||||
prestige_resets_count += 1
|
||||
last_reset_time = Time.get_unix_time_from_system()
|
||||
|
||||
if game_state:
|
||||
game_state.reset_for_prestige(true, false)
|
||||
var preserve_currencies: Array[StringName] = []
|
||||
var prestige_currency_id: StringName = get_prestige_currency_id()
|
||||
if prestige_currency_id != &"":
|
||||
preserve_currencies.append(prestige_currency_id)
|
||||
game_state.reset_for_prestige(false, false, preserve_currencies)
|
||||
_reset_all_buff_levels()
|
||||
_reinitialize_generators_after_prestige_reset()
|
||||
if game_state:
|
||||
@@ -162,8 +203,10 @@ 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:
|
||||
var basis_type: int = _get_config_int("basis", BASIS_LIFETIME_TOTAL)
|
||||
|
||||
match basis_type:
|
||||
BASIS_RUN_TOTAL, BASIS_ALL_CURRENCIES:
|
||||
return _get_config_threshold()
|
||||
_:
|
||||
var current_total: float = _big_number_to_float(total_prestige_earned)
|
||||
@@ -176,28 +219,38 @@ func get_basis_value_for_display() -> BigNumber:
|
||||
func get_basis_label() -> String:
|
||||
if not _is_config_valid():
|
||||
return "-"
|
||||
|
||||
match _get_config_int("basis", BASIS_LIFETIME_TOTAL):
|
||||
|
||||
var basis_type: int = _get_config_int("basis", BASIS_LIFETIME_TOTAL)
|
||||
|
||||
match basis_type:
|
||||
BASIS_RUN_TOTAL:
|
||||
return "Run Total"
|
||||
BASIS_RUN_MAX:
|
||||
return "Run Max"
|
||||
BASIS_ALL_CURRENCIES:
|
||||
return "Total Currency"
|
||||
_:
|
||||
return "Lifetime Total"
|
||||
|
||||
func _on_currency_changed(changed_currency_id: StringName, new_amount: BigNumber) -> void:
|
||||
if config == null:
|
||||
return
|
||||
|
||||
var source_currency_id: StringName = get_source_currency_id()
|
||||
if source_currency_id == &"":
|
||||
return
|
||||
if changed_currency_id != source_currency_id:
|
||||
return
|
||||
|
||||
if new_amount.is_greater_than(run_peak_source_currency):
|
||||
run_peak_source_currency = _copy_big_number(new_amount)
|
||||
|
||||
|
||||
var basis_type: int = _get_config_int("basis", BASIS_LIFETIME_TOTAL)
|
||||
|
||||
if basis_type == BASIS_ALL_CURRENCIES:
|
||||
if new_amount.is_greater_than(run_peak_source_currency):
|
||||
run_peak_source_currency = _copy_big_number(new_amount)
|
||||
else:
|
||||
var source_currency_id: StringName = get_source_currency_id()
|
||||
if source_currency_id == &"":
|
||||
return
|
||||
if changed_currency_id != source_currency_id:
|
||||
return
|
||||
|
||||
if new_amount.is_greater_than(run_peak_source_currency):
|
||||
run_peak_source_currency = _copy_big_number(new_amount)
|
||||
|
||||
_save_state_to_game_state()
|
||||
var next_threshold: BigNumber = get_next_prestige_threshold()
|
||||
prestige_state_changed.emit(get_total_prestige(), calculate_pending_gain())
|
||||
@@ -266,15 +319,18 @@ func _get_basis_value() -> BigNumber:
|
||||
if config == null:
|
||||
return BigNumber.from_float(0.0)
|
||||
|
||||
var source_currency_id: StringName = get_source_currency_id()
|
||||
if source_currency_id == &"":
|
||||
return BigNumber.from_float(0.0)
|
||||
|
||||
if game_state == null:
|
||||
return BigNumber.from_float(0.0)
|
||||
|
||||
var basis_type: int = _get_config_int("basis", BASIS_LIFETIME_TOTAL)
|
||||
|
||||
match _get_config_int("basis", BASIS_LIFETIME_TOTAL):
|
||||
match basis_type:
|
||||
BASIS_ALL_CURRENCIES:
|
||||
return _get_total_all_currencies()
|
||||
BASIS_RUN_TOTAL:
|
||||
var source_currency_id: StringName = get_source_currency_id()
|
||||
if source_currency_id == &"":
|
||||
return BigNumber.from_float(0.0)
|
||||
var lifetime_now: BigNumber = game_state.get_total_currency_acquired_by_id(source_currency_id)
|
||||
var run_total: BigNumber = lifetime_now.subtract(run_start_total_source_currency)
|
||||
if run_total.mantissa < 0.0:
|
||||
@@ -283,11 +339,37 @@ func _get_basis_value() -> BigNumber:
|
||||
BASIS_RUN_MAX:
|
||||
return _copy_big_number(run_peak_source_currency)
|
||||
_:
|
||||
var source_currency_id: StringName = get_source_currency_id()
|
||||
if source_currency_id == &"":
|
||||
return BigNumber.from_float(0.0)
|
||||
return _copy_big_number(game_state.get_total_currency_acquired_by_id(source_currency_id))
|
||||
|
||||
func _get_total_all_currencies() -> BigNumber:
|
||||
var total: BigNumber = BigNumber.from_float(0.0)
|
||||
var currency_ids: Array[StringName] = get_tracked_currency_ids()
|
||||
|
||||
for currency_id in currency_ids:
|
||||
var currency_total: BigNumber = game_state.get_total_currency_acquired_by_id(currency_id)
|
||||
total.add_in_place(currency_total)
|
||||
|
||||
return total
|
||||
|
||||
func _initialize_run_tracking_from_current_state() -> void:
|
||||
if config == null:
|
||||
return
|
||||
|
||||
var basis_type: int = _get_config_int("basis", BASIS_LIFETIME_TOTAL)
|
||||
|
||||
if basis_type == BASIS_ALL_CURRENCIES:
|
||||
run_start_total_source_currency = _get_total_all_currencies()
|
||||
run_peak_source_currency = BigNumber.from_float(0.0)
|
||||
var currency_ids: Array[StringName] = get_tracked_currency_ids()
|
||||
for currency_id in currency_ids:
|
||||
var current: BigNumber = game_state.get_currency_amount_by_id(currency_id)
|
||||
if current.is_greater_than(run_peak_source_currency):
|
||||
run_peak_source_currency = _copy_big_number(current)
|
||||
_save_state_to_game_state()
|
||||
return
|
||||
|
||||
var source_currency_id: StringName = get_source_currency_id()
|
||||
if source_currency_id == &"":
|
||||
@@ -307,6 +389,19 @@ func _initialize_run_tracking_from_current_state() -> void:
|
||||
func _validate_loaded_run_tracking() -> void:
|
||||
if config == null:
|
||||
return
|
||||
|
||||
var basis_type: int = _get_config_int("basis", BASIS_LIFETIME_TOTAL)
|
||||
|
||||
if basis_type == BASIS_ALL_CURRENCIES:
|
||||
var currency_ids: Array[StringName] = get_tracked_currency_ids()
|
||||
var peak: BigNumber = BigNumber.from_float(0.0)
|
||||
for currency_id in currency_ids:
|
||||
var current: BigNumber = game_state.get_currency_amount_by_id(currency_id)
|
||||
if current.is_greater_than(peak):
|
||||
peak = _copy_big_number(current)
|
||||
if peak.is_greater_than(run_peak_source_currency):
|
||||
run_peak_source_currency = _copy_big_number(peak)
|
||||
return
|
||||
|
||||
var source_currency_id: StringName = get_source_currency_id()
|
||||
if source_currency_id == &"":
|
||||
@@ -427,8 +522,10 @@ func _is_config_valid() -> bool:
|
||||
func _is_cumulative_basis() -> bool:
|
||||
if config != null and config.has_method("is_cumulative_basis"):
|
||||
return bool(config.call("is_cumulative_basis"))
|
||||
|
||||
return _get_config_int("basis", BASIS_LIFETIME_TOTAL) != BASIS_RUN_TOTAL
|
||||
|
||||
var basis_type: int = _get_config_int("basis", BASIS_LIFETIME_TOTAL)
|
||||
|
||||
return basis_type != BASIS_RUN_TOTAL and basis_type != BASIS_ALL_CURRENCIES
|
||||
|
||||
func _round_gain(value: float) -> float:
|
||||
if config != null and config.has_method("round_value"):
|
||||
|
||||
@@ -33,11 +33,10 @@ func _on_reset_button_pressed() -> void:
|
||||
return
|
||||
|
||||
var pending: BigNumber = manager.call("calculate_pending_gain")
|
||||
var source_currency_id: StringName = manager.call("get_source_currency_id")
|
||||
var source_currency_name: String = game_state.get_currency_name(source_currency_id) if game_state else ""
|
||||
var basis_label: String = String(manager.call("get_basis_label"))
|
||||
var basis_value: BigNumber = manager.call("get_basis_value_for_display")
|
||||
var confirm_message: String = "Reset this run for +%s prestige?\n\nThis resets currencies, owned generators, and buff levels. Lifetime totals and prestige are kept." % pending.to_string_suffix(2)
|
||||
if not source_currency_name.is_empty():
|
||||
confirm_message = "%s\n\nBased on %s progression." % [confirm_message, source_currency_name]
|
||||
confirm_message = "%s\n\nBased on %s: %s" % [confirm_message, basis_label, basis_value.to_string_suffix(2)]
|
||||
|
||||
_confirm_dialog.dialog_text = confirm_message
|
||||
_is_waiting_for_confirm = true
|
||||
|
||||
Reference in New Issue
Block a user