Decouple everything from globals
This commit is contained in:
24
core/buff_catalogue.gd
Normal file
24
core/buff_catalogue.gd
Normal file
@@ -0,0 +1,24 @@
|
||||
class_name BuffCatalogue
|
||||
extends Resource
|
||||
|
||||
@export var buffs: Array[GeneratorBuffData] = []
|
||||
|
||||
func get_buff_by_id(id: StringName) -> GeneratorBuffData:
|
||||
for buff in buffs:
|
||||
if buff.id == id:
|
||||
return buff
|
||||
return null
|
||||
|
||||
func get_all_ids() -> Array[StringName]:
|
||||
var ids: Array[StringName] = []
|
||||
for buff in buffs:
|
||||
if buff.id:
|
||||
ids.append(buff.id)
|
||||
return ids
|
||||
|
||||
func get_buffs_for_generator(generator_id: StringName) -> Array[GeneratorBuffData]:
|
||||
var result: Array[GeneratorBuffData] = []
|
||||
for buff in buffs:
|
||||
if buff.targets_generator(generator_id):
|
||||
result.append(buff)
|
||||
return result
|
||||
1
core/buff_catalogue.gd.uid
Normal file
1
core/buff_catalogue.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://ctc5yjlnvi0ok
|
||||
@@ -1,47 +0,0 @@
|
||||
extends Node
|
||||
|
||||
## Auto-discovers and registers all buff resources from res://docs/gyms/buffs/
|
||||
|
||||
const BUFF_DIRECTORY_PATH: String = "res://docs/gyms/buffs"
|
||||
|
||||
var _buff_by_id: Dictionary = {}
|
||||
var _initialized: bool = false
|
||||
|
||||
func _ready() -> void:
|
||||
_initialize_buff_catalog()
|
||||
|
||||
func _initialize_buff_catalog() -> void:
|
||||
if _initialized:
|
||||
return
|
||||
|
||||
_buff_by_id.clear()
|
||||
var dir: DirAccess = DirAccess.open(BUFF_DIRECTORY_PATH)
|
||||
if dir == null:
|
||||
push_warning("Unable to open buff directory: %s" % BUFF_DIRECTORY_PATH)
|
||||
_initialized = true
|
||||
return
|
||||
|
||||
dir.list_dir_begin()
|
||||
var entry_name: String = dir.get_next()
|
||||
while not entry_name.is_empty():
|
||||
if not dir.current_is_dir() and entry_name.ends_with(".tres"):
|
||||
var path: String = "%s/%s" % [BUFF_DIRECTORY_PATH, entry_name]
|
||||
var buff: GeneratorBuffData = load(path) as GeneratorBuffData
|
||||
if buff != null:
|
||||
_buff_by_id[buff.id] = buff
|
||||
GameState.register_buff(buff)
|
||||
entry_name = dir.get_next()
|
||||
dir.list_dir_end()
|
||||
|
||||
_initialized = true
|
||||
print("BuffDatabase initialized with %d buffs" % _buff_by_id.size())
|
||||
|
||||
func get_all_buffs() -> Array[GeneratorBuffData]:
|
||||
var result: Array[GeneratorBuffData] = []
|
||||
for buff in _buff_by_id.values():
|
||||
if buff is GeneratorBuffData:
|
||||
result.append(buff)
|
||||
return result
|
||||
|
||||
func get_buff(buff_id: StringName) -> GeneratorBuffData:
|
||||
return _buff_by_id.get(buff_id, null)
|
||||
@@ -1 +0,0 @@
|
||||
uid://cjm87u4xh0718
|
||||
17
core/currency/currency_catalogue.gd
Normal file
17
core/currency/currency_catalogue.gd
Normal file
@@ -0,0 +1,17 @@
|
||||
class_name CurrencyCatalogue
|
||||
extends Resource
|
||||
|
||||
@export var currencies: Array[Currency] = []
|
||||
|
||||
func get_currency_by_id(id: StringName) -> Currency:
|
||||
for currency in currencies:
|
||||
if currency.id == id:
|
||||
return currency
|
||||
return null
|
||||
|
||||
func get_all_ids() -> Array[StringName]:
|
||||
var ids: Array[StringName] = []
|
||||
for currency in currencies:
|
||||
if currency.id != &"":
|
||||
ids.append(currency.id)
|
||||
return ids
|
||||
1
core/currency/currency_catalogue.gd.uid
Normal file
1
core/currency/currency_catalogue.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://621tus0uvbrd
|
||||
@@ -1,164 +0,0 @@
|
||||
extends Node
|
||||
|
||||
#const GOLD_CURRENCY_ID: StringName = &"gold"
|
||||
#const GEMS_CURRENCY_ID: StringName = &"gems"
|
||||
#const LEGACY_CURRENCY_INDEX_TO_ID: Dictionary = {
|
||||
#0: GOLD_CURRENCY_ID,
|
||||
#1: GEMS_CURRENCY_ID,
|
||||
#}
|
||||
|
||||
const CURRENCY_DIRECTORY_PATH: String = "res://docs/gyms/currencies"
|
||||
const CURRENCY_RESOURCE_EXTENSIONS: PackedStringArray = ["tres", "res"]
|
||||
|
||||
var _currency_by_id: Dictionary = {}
|
||||
var _catalog_initialized: bool = false
|
||||
|
||||
func _ready() -> void:
|
||||
_initialize_currency_catalog()
|
||||
|
||||
func get_known_currencies() -> Array[Currency]:
|
||||
_initialize_currency_catalog_if_needed()
|
||||
|
||||
var result: Array[Currency] = []
|
||||
for raw_currency in _currency_by_id.values():
|
||||
var currency: Currency = raw_currency as Currency
|
||||
if currency != null:
|
||||
result.append(currency)
|
||||
return result
|
||||
|
||||
func get_known_currency_ids() -> Array[StringName]:
|
||||
_initialize_currency_catalog_if_needed()
|
||||
|
||||
var ids: Array[StringName] = []
|
||||
for raw_currency_id in _currency_by_id.keys():
|
||||
var currency_id: StringName = _normalize_currency_id(StringName(String(raw_currency_id)))
|
||||
if currency_id == &"":
|
||||
continue
|
||||
ids.append(currency_id)
|
||||
return ids
|
||||
|
||||
func get_currency_id(currency: Currency) -> StringName:
|
||||
if currency == null:
|
||||
return &""
|
||||
|
||||
var raw_id: Variant = currency.id
|
||||
if raw_id is StringName:
|
||||
return _normalize_currency_id(raw_id)
|
||||
return _normalize_currency_id(StringName(String(raw_id)))
|
||||
|
||||
func parse_currency_id(raw_currency: Variant) -> StringName:
|
||||
#if raw_currency is int:
|
||||
#return currency_id_from_legacy_index(raw_currency)
|
||||
|
||||
var currency_text: String = String(raw_currency).to_lower().strip_edges()
|
||||
if currency_text == "gem":
|
||||
currency_text = "gems"
|
||||
return _normalize_currency_id(StringName(currency_text))
|
||||
|
||||
#func currency_id_from_legacy_index(currency_index: int) -> StringName:
|
||||
#return LEGACY_CURRENCY_INDEX_TO_ID.get(currency_index, &"")
|
||||
|
||||
func is_known_currency_id(currency_id: StringName) -> bool:
|
||||
_initialize_currency_catalog_if_needed()
|
||||
|
||||
var normalized_currency_id: StringName = _normalize_currency_id(currency_id)
|
||||
if normalized_currency_id == &"":
|
||||
return false
|
||||
return _currency_by_id.has(normalized_currency_id)
|
||||
|
||||
func get_currency_resource(currency_id: StringName) -> Currency:
|
||||
_initialize_currency_catalog_if_needed()
|
||||
|
||||
var normalized_currency_id: StringName = _normalize_currency_id(currency_id)
|
||||
if normalized_currency_id == &"":
|
||||
return null
|
||||
|
||||
var raw_currency: Variant = _currency_by_id.get(normalized_currency_id)
|
||||
if raw_currency is Currency:
|
||||
return raw_currency
|
||||
return null
|
||||
|
||||
func get_currency_name(currency_id: StringName) -> String:
|
||||
var currency: Currency = get_currency_resource(currency_id)
|
||||
if currency != null:
|
||||
var display_name: String = String(currency.display_name).strip_edges()
|
||||
if not display_name.is_empty():
|
||||
return display_name
|
||||
return _humanize_currency_id(currency_id)
|
||||
|
||||
func get_currency_icon(currency_id: StringName) -> Texture2D:
|
||||
var currency: Resource = get_currency_resource(currency_id)
|
||||
if currency == null:
|
||||
return null
|
||||
|
||||
var raw_icon: Variant = currency.icon
|
||||
if raw_icon is Texture2D:
|
||||
return raw_icon
|
||||
return null
|
||||
|
||||
func _initialize_currency_catalog_if_needed() -> void:
|
||||
if _catalog_initialized:
|
||||
return
|
||||
_initialize_currency_catalog()
|
||||
|
||||
func _initialize_currency_catalog() -> void:
|
||||
_currency_by_id.clear()
|
||||
_catalog_initialized = true
|
||||
|
||||
var currency_resource_paths: PackedStringArray = _discover_currency_resource_paths()
|
||||
for resource_path in currency_resource_paths:
|
||||
var loaded_resource: Resource = load(resource_path)
|
||||
if loaded_resource == null:
|
||||
push_warning("Failed to load currency resource at '%s'." % resource_path)
|
||||
continue
|
||||
if not (loaded_resource is Currency):
|
||||
continue
|
||||
|
||||
var currency_id: StringName = get_currency_id(loaded_resource)
|
||||
if currency_id == &"":
|
||||
push_warning("Skipping currency with missing id: %s" % resource_path)
|
||||
continue
|
||||
if _currency_by_id.has(currency_id):
|
||||
push_warning("Duplicate currency id '%s' found at %s. Keeping first occurrence." % [String(currency_id), resource_path])
|
||||
continue
|
||||
|
||||
_currency_by_id[currency_id] = loaded_resource
|
||||
|
||||
if _currency_by_id.is_empty():
|
||||
push_warning("No currency resources discovered under %s. Ensure currency .tres files exist and are included in export presets." % CURRENCY_DIRECTORY_PATH)
|
||||
|
||||
func _discover_currency_resource_paths() -> PackedStringArray:
|
||||
var result: PackedStringArray = []
|
||||
var directory: DirAccess = DirAccess.open(CURRENCY_DIRECTORY_PATH)
|
||||
if directory == null:
|
||||
push_warning("Unable to open currency directory: %s" % CURRENCY_DIRECTORY_PATH)
|
||||
return result
|
||||
|
||||
directory.list_dir_begin()
|
||||
var entry_name: String = directory.get_next()
|
||||
while not entry_name.is_empty():
|
||||
if directory.current_is_dir() or entry_name.begins_with("."):
|
||||
entry_name = directory.get_next()
|
||||
continue
|
||||
|
||||
var extension: String = entry_name.get_extension().to_lower()
|
||||
if CURRENCY_RESOURCE_EXTENSIONS.has(extension):
|
||||
result.append("%s/%s" % [CURRENCY_DIRECTORY_PATH, entry_name])
|
||||
|
||||
entry_name = directory.get_next()
|
||||
directory.list_dir_end()
|
||||
|
||||
result.sort()
|
||||
return result
|
||||
|
||||
func _normalize_currency_id(currency_id: StringName) -> StringName:
|
||||
var normalized: String = String(currency_id).to_lower().strip_edges()
|
||||
if normalized.is_empty():
|
||||
return &""
|
||||
return StringName(normalized)
|
||||
|
||||
func _humanize_currency_id(currency_id: StringName) -> String:
|
||||
var normalized: String = String(_normalize_currency_id(currency_id))
|
||||
if normalized.is_empty():
|
||||
return "Unknown"
|
||||
return normalized.replace("_", " ").capitalize()
|
||||
@@ -1 +0,0 @@
|
||||
uid://dmv83fnq26xao
|
||||
@@ -1 +0,0 @@
|
||||
uid://d2j7tvlgxr2jp
|
||||
@@ -44,42 +44,45 @@ var _mouse_entered: bool = false
|
||||
## Time left until next click/hover grant is allowed.
|
||||
var _remaining_click_cooldown_seconds: float = 0.0
|
||||
|
||||
## Reference to LevelGameState instance.
|
||||
@onready var game_state: LevelGameState = find_parent("LevelGameState")
|
||||
|
||||
## Number of currently owned generators.
|
||||
## Backed by GameState via this generator's resolved id.
|
||||
## Backed by LevelGameState via this generator's resolved id.
|
||||
var owned: int:
|
||||
get:
|
||||
_ensure_registered()
|
||||
return GameState.get_generator_owned(_generator_id)
|
||||
return game_state.get_generator_owned(_generator_id)
|
||||
set(value):
|
||||
_ensure_registered()
|
||||
GameState.set_generator_owned(_generator_id, value)
|
||||
game_state.set_generator_owned(_generator_id, value)
|
||||
|
||||
## Lifetime purchased generators (does not decrease if ownership drops).
|
||||
var purchased_count: int:
|
||||
get:
|
||||
_ensure_registered()
|
||||
return GameState.get_generator_purchased_count(_generator_id)
|
||||
return game_state.get_generator_purchased_count(_generator_id)
|
||||
set(value):
|
||||
_ensure_registered()
|
||||
GameState.set_generator_purchased_count(_generator_id, value)
|
||||
game_state.set_generator_purchased_count(_generator_id, value)
|
||||
|
||||
## Whether this generator is unlocked for the player.
|
||||
var is_unlocked: bool:
|
||||
get:
|
||||
_ensure_registered()
|
||||
return GameState.is_generator_unlocked(_generator_id)
|
||||
return game_state.is_generator_unlocked(_generator_id)
|
||||
set(value):
|
||||
_ensure_registered()
|
||||
GameState.set_generator_unlocked(_generator_id, value)
|
||||
game_state.set_generator_unlocked(_generator_id, value)
|
||||
|
||||
## Whether this unlocked generator is currently visible/usable to the player.
|
||||
var is_available: bool:
|
||||
get:
|
||||
_ensure_registered()
|
||||
return GameState.is_generator_available(_generator_id)
|
||||
return game_state.is_generator_available(_generator_id)
|
||||
set(value):
|
||||
_ensure_registered()
|
||||
GameState.set_generator_available(_generator_id, value)
|
||||
game_state.set_generator_available(_generator_id, value)
|
||||
|
||||
## Accumulated elapsed time toward the next automatic production cycle.
|
||||
var cycle_progress_seconds: float = 0.0
|
||||
@@ -98,9 +101,10 @@ func _ready() -> void:
|
||||
_generator_id = _resolve_generator_id()
|
||||
cycle_progress_seconds = 0.0
|
||||
|
||||
GameState.currency_changed.connect(_on_currency_changed)
|
||||
GameState.generator_state_changed.connect(_on_generated_state_changed)
|
||||
GameState.goal_completed.connect(_on_goal_completed)
|
||||
if game_state:
|
||||
game_state.currency_changed.connect(_on_currency_changed)
|
||||
game_state.generator_state_changed.connect(_on_generated_state_changed)
|
||||
game_state.goal_completed.connect(_on_goal_completed)
|
||||
|
||||
_ensure_registered()
|
||||
|
||||
@@ -220,18 +224,27 @@ func buy_max() -> int:
|
||||
func get_buffs() -> Array[GeneratorBuffData]:
|
||||
if data == null:
|
||||
return []
|
||||
return GameState.get_buffs_for_generator(_generator_id)
|
||||
if game_state == null:
|
||||
return []
|
||||
return game_state.get_buffs_for_generator(_generator_id)
|
||||
|
||||
func get_buff_level(buff_id: StringName) -> int:
|
||||
_ensure_registered()
|
||||
return GameState.get_buff_level(buff_id)
|
||||
if game_state == null:
|
||||
return 0
|
||||
return game_state.get_buff_level(buff_id)
|
||||
|
||||
func is_buff_unlocked(buff_id: StringName) -> bool:
|
||||
_ensure_registered()
|
||||
return GameState.is_buff_unlocked(buff_id)
|
||||
if game_state == null:
|
||||
return false
|
||||
return game_state.is_buff_unlocked(buff_id)
|
||||
|
||||
func get_buff_cost(buff_id: StringName) -> BigNumber:
|
||||
var buff: GeneratorBuffData = GameState.get_buff(buff_id)
|
||||
if game_state == null:
|
||||
return BigNumber.from_float(0.0)
|
||||
|
||||
var buff: GeneratorBuffData = game_state.get_buff(buff_id)
|
||||
if buff == null:
|
||||
return BigNumber.from_float(0.0)
|
||||
if not is_buff_unlocked(buff.id):
|
||||
@@ -241,7 +254,10 @@ func get_buff_cost(buff_id: StringName) -> BigNumber:
|
||||
return buff.get_cost_for_level(level)
|
||||
|
||||
func get_buff_cost_currency_id(buff_id: StringName) -> StringName:
|
||||
var buff: GeneratorBuffData = GameState.get_buff(buff_id)
|
||||
if game_state == null:
|
||||
return &""
|
||||
|
||||
var buff: GeneratorBuffData = game_state.get_buff(buff_id)
|
||||
if buff == null:
|
||||
return &""
|
||||
return _resolve_buff_cost_currency_id(buff)
|
||||
@@ -250,7 +266,10 @@ func can_buy_buff(buff_id: StringName) -> bool:
|
||||
if not is_available_to_player():
|
||||
return false
|
||||
|
||||
var buff: GeneratorBuffData = GameState.get_buff(buff_id)
|
||||
if game_state == null:
|
||||
return false
|
||||
|
||||
var buff: GeneratorBuffData = game_state.get_buff(buff_id)
|
||||
if buff == null:
|
||||
return false
|
||||
|
||||
@@ -266,21 +285,24 @@ func can_buy_buff(buff_id: StringName) -> bool:
|
||||
return false
|
||||
|
||||
var cost: BigNumber = buff.get_cost_for_level(current_level)
|
||||
var current_amount: BigNumber = GameState.get_currency_amount_by_id(cost_currency_id)
|
||||
var current_amount: BigNumber = game_state.get_currency_amount_by_id(cost_currency_id)
|
||||
return current_amount.is_greater_than(cost) or current_amount.is_equal_to(cost)
|
||||
|
||||
func buy_buff(buff_id: StringName) -> bool:
|
||||
if not is_available_to_player():
|
||||
return false
|
||||
|
||||
var buff: GeneratorBuffData = GameState.get_buff(buff_id)
|
||||
if game_state == null:
|
||||
return false
|
||||
|
||||
var buff: GeneratorBuffData = game_state.get_buff(buff_id)
|
||||
if buff == null:
|
||||
return false
|
||||
|
||||
if not GameState.is_buff_unlocked(buff.id):
|
||||
if not game_state.is_buff_unlocked(buff.id):
|
||||
return false
|
||||
|
||||
var current_level: int = GameState.get_buff_level(buff.id)
|
||||
var current_level: int = game_state.get_buff_level(buff.id)
|
||||
if not buff.can_purchase_next_level(current_level):
|
||||
return false
|
||||
|
||||
@@ -294,19 +316,22 @@ func buy_buff(buff_id: StringName) -> bool:
|
||||
return false
|
||||
|
||||
var next_level: int = current_level + 1
|
||||
GameState.set_buff_level(buff.id, next_level)
|
||||
game_state.set_buff_level(buff.id, next_level)
|
||||
_apply_resource_purchase_buff(buff, next_level)
|
||||
buff_purchased.emit(buff.id, next_level, cost, cost_currency_id)
|
||||
return true
|
||||
|
||||
func is_buff_maxed(buff_id: StringName) -> bool:
|
||||
var buff: GeneratorBuffData = GameState.get_buff(buff_id)
|
||||
if game_state == null:
|
||||
return true
|
||||
|
||||
var buff: GeneratorBuffData = game_state.get_buff(buff_id)
|
||||
if buff == null:
|
||||
return true
|
||||
if not GameState.is_buff_unlocked(buff.id):
|
||||
if not game_state.is_buff_unlocked(buff.id):
|
||||
return false
|
||||
|
||||
return not buff.can_purchase_next_level(GameState.get_buff_level(buff.id))
|
||||
return not buff.can_purchase_next_level(game_state.get_buff_level(buff.id))
|
||||
|
||||
func get_automatic_production_multiplier() -> float:
|
||||
return _get_multiplier_for_buff_kind(GeneratorBuffData.BuffKind.AUTO_PRODUCTION_MULTIPLIER)
|
||||
@@ -384,13 +409,18 @@ func _grants_click_while_hovering() -> bool:
|
||||
return grants_click_while_hovering
|
||||
|
||||
func _get_prestige_multiplier() -> float:
|
||||
var manager: PrestigeManager = get_node_or_null("/root/PrestigeManager")
|
||||
if manager == null:
|
||||
if game_state == null:
|
||||
return 1.0
|
||||
if not manager.get_total_multiplier():
|
||||
|
||||
var parent: Node = get_parent()
|
||||
if parent == null:
|
||||
return 1.0
|
||||
|
||||
var raw_multiplier: Variant = manager.get_total_multiplier()
|
||||
|
||||
var prestige_manager: PrestigeManager = parent.find_child("PrestigeManager", true, false)
|
||||
if prestige_manager == null:
|
||||
return 1.0
|
||||
|
||||
var raw_multiplier: Variant = prestige_manager.get_total_multiplier()
|
||||
if raw_multiplier is float:
|
||||
return maxf(raw_multiplier, 0.0)
|
||||
if raw_multiplier is int:
|
||||
@@ -405,14 +435,16 @@ func get_generator_id() -> StringName:
|
||||
|
||||
## Returns the configured currency id.
|
||||
func get_currency_id() -> StringName:
|
||||
return GameState.get_currency_id(currency)
|
||||
if game_state == null:
|
||||
return &""
|
||||
return game_state.get_currency_id(currency)
|
||||
|
||||
func get_purchase_currency_id() -> StringName:
|
||||
var purchase_currency: Currency = _resolve_purchase_currency()
|
||||
if purchase_currency == null:
|
||||
return &""
|
||||
|
||||
return GameState.get_currency_id(purchase_currency)
|
||||
return game_state.get_currency_id(purchase_currency)
|
||||
|
||||
## True when the generator is both unlocked and available.
|
||||
func is_available_to_player() -> bool:
|
||||
@@ -424,13 +456,17 @@ func _add_currency(amount: BigNumber) -> void:
|
||||
push_error("CurrencyGenerator '%s' cannot add currency: currency resource is null." % String(name))
|
||||
return
|
||||
|
||||
GameState.add_currency(currency, amount)
|
||||
if game_state == null:
|
||||
return
|
||||
game_state.add_currency(currency, amount)
|
||||
|
||||
func _add_currency_by_id(currency_id: StringName, amount: BigNumber) -> void:
|
||||
if currency_id == &"":
|
||||
return
|
||||
|
||||
GameState.add_currency_by_id(currency_id, amount)
|
||||
if game_state == null:
|
||||
return
|
||||
game_state.add_currency_by_id(currency_id, amount)
|
||||
|
||||
## Attempts to spend target currency; returns false when insufficient.
|
||||
func _spend_currency(cost: BigNumber) -> bool:
|
||||
@@ -438,25 +474,33 @@ func _spend_currency(cost: BigNumber) -> bool:
|
||||
push_error("CurrencyGenerator '%s' cannot spend currency: currency resource is null." % String(name))
|
||||
return false
|
||||
|
||||
return GameState.spend_currency(currency, cost)
|
||||
if game_state == null:
|
||||
return false
|
||||
return game_state.spend_currency(currency, cost)
|
||||
|
||||
func _spend_currency_by_id(currency_id: StringName, cost: BigNumber) -> bool:
|
||||
if currency_id == &"":
|
||||
return false
|
||||
|
||||
return GameState.spend_currency_by_id(currency_id, cost)
|
||||
if game_state == null:
|
||||
return false
|
||||
return game_state.spend_currency_by_id(currency_id, cost)
|
||||
|
||||
## Returns the current amount for the configured currency type.
|
||||
func _get_currency_amount() -> BigNumber:
|
||||
if currency == null:
|
||||
return BigNumber.from_float(0.0)
|
||||
return GameState.get_currency_amount(currency)
|
||||
if game_state == null:
|
||||
return BigNumber.from_float(0.0)
|
||||
return game_state.get_currency_amount(currency)
|
||||
|
||||
func _get_currency_amount_by_id(currency_id: StringName) -> BigNumber:
|
||||
if currency_id == &"":
|
||||
return BigNumber.from_float(0.0)
|
||||
|
||||
return GameState.get_currency_amount_by_id(currency_id)
|
||||
if game_state == null:
|
||||
return BigNumber.from_float(0.0)
|
||||
return game_state.get_currency_amount_by_id(currency_id)
|
||||
|
||||
## Safely converts finite float values into BigNumber costs.
|
||||
func _float_to_big_number(value: float) -> BigNumber:
|
||||
@@ -484,7 +528,9 @@ func _resolve_buff_cost_currency_id(buff: GeneratorBuffData) -> StringName:
|
||||
if cost_currency == null:
|
||||
return &""
|
||||
|
||||
return GameState.get_currency_id(cost_currency)
|
||||
if game_state == null:
|
||||
return &""
|
||||
return game_state.get_currency_id(cost_currency)
|
||||
|
||||
func _resolve_purchase_currency() -> Currency:
|
||||
if data == null:
|
||||
@@ -500,10 +546,14 @@ func _resolve_buff_target_currency_id(buff: GeneratorBuffData) -> StringName:
|
||||
if target_currency == null:
|
||||
return &""
|
||||
|
||||
return GameState.get_currency_id(target_currency)
|
||||
if game_state == null:
|
||||
return &""
|
||||
return game_state.get_currency_id(target_currency)
|
||||
|
||||
func _get_multiplier_for_buff_kind(kind: GeneratorBuffData.BuffKind) -> float:
|
||||
return GameState.get_effective_multiplier(_generator_id, kind)
|
||||
if game_state == null:
|
||||
return 1.0
|
||||
return game_state.get_effective_multiplier(_generator_id, kind)
|
||||
|
||||
func _apply_resource_purchase_buff(buff: GeneratorBuffData, level: int) -> void:
|
||||
if buff == null:
|
||||
@@ -533,7 +583,7 @@ func _resolve_generator_id() -> StringName:
|
||||
|
||||
return &"generator"
|
||||
|
||||
## Ensures this generator has a state entry in GameState.
|
||||
## Ensures this generator has a state entry in LevelGameState.
|
||||
func _ensure_registered() -> void:
|
||||
if _is_registered or _is_registering:
|
||||
return
|
||||
@@ -543,8 +593,11 @@ func _ensure_registered() -> void:
|
||||
if _generator_id == &"":
|
||||
return
|
||||
|
||||
if game_state == null:
|
||||
return
|
||||
|
||||
_is_registering = true
|
||||
GameState.register_generator(
|
||||
game_state.register_generator(
|
||||
_generator_id,
|
||||
_default_unlocked_state(),
|
||||
_default_available_state(),
|
||||
@@ -555,6 +608,9 @@ func _ensure_registered() -> void:
|
||||
_is_registering = false
|
||||
|
||||
func _register_buffs() -> void:
|
||||
if game_state == null:
|
||||
return
|
||||
|
||||
for buff in get_buffs():
|
||||
if buff == null:
|
||||
continue
|
||||
@@ -564,20 +620,24 @@ func _register_buffs() -> void:
|
||||
continue
|
||||
|
||||
var buff_id: StringName = StringName(buff_id_text)
|
||||
GameState.register_buff(buff)
|
||||
game_state.register_buff(buff)
|
||||
|
||||
if not GameState.is_buff_unlocked(buff_id):
|
||||
var persisted_level: int = GameState.get_buff_level(buff_id)
|
||||
if not game_state.is_buff_unlocked(buff_id):
|
||||
var persisted_level: int = game_state.get_buff_level(buff_id)
|
||||
var starts_unlocked: bool = buff.unlocked or persisted_level > 0
|
||||
GameState.set_buff_unlocked(buff_id, starts_unlocked)
|
||||
game_state.set_buff_unlocked(buff_id, starts_unlocked)
|
||||
|
||||
_try_unlock_buff_from_goal(buff)
|
||||
|
||||
func _try_unlock_buff_from_goal(buff: GeneratorBuffData) -> void:
|
||||
GameState._try_unlock_buff_from_goal(buff)
|
||||
if game_state == null:
|
||||
return
|
||||
game_state._try_unlock_buff_from_goal(buff)
|
||||
|
||||
func _on_currency_changed(_changed_currency_id: StringName, _new_amount: BigNumber) -> void:
|
||||
GameState.evaluate_all_goals()
|
||||
if game_state == null:
|
||||
return
|
||||
game_state.evaluate_all_goals()
|
||||
|
||||
func _on_goal_completed(goal_id: StringName) -> void:
|
||||
if data == null or not data.has_unlock_goal():
|
||||
@@ -587,10 +647,12 @@ func _on_goal_completed(goal_id: StringName) -> void:
|
||||
if is_available_to_player():
|
||||
return
|
||||
|
||||
GameState.set_generator_unlocked(_generator_id, true)
|
||||
GameState.set_generator_available(_generator_id, true)
|
||||
if game_state == null:
|
||||
return
|
||||
game_state.set_generator_unlocked(_generator_id, true)
|
||||
game_state.set_generator_available(_generator_id, true)
|
||||
goal_achieved.emit(_generator_id, goal_id)
|
||||
_on_generated_state_changed(_generator_id, GameState._get_generator_state(_generator_id))
|
||||
_on_generated_state_changed(_generator_id, game_state._get_generator_state(_generator_id))
|
||||
|
||||
## Default unlocked state loaded from generator data.
|
||||
func _default_unlocked_state() -> bool:
|
||||
|
||||
@@ -58,10 +58,10 @@ func get_unlock_goal_amount() -> BigNumber:
|
||||
if unlock_goal == null:
|
||||
return BigNumber.from_float(0.0)
|
||||
|
||||
var valid_requirements: Array[GoalRequirementData] = unlock_goal.get_valid_requirements()
|
||||
if valid_requirements.is_empty():
|
||||
var requirements: Array[GoalRequirementData] = unlock_goal.get_requirements()
|
||||
if requirements.is_empty():
|
||||
return BigNumber.from_float(0.0)
|
||||
var requirement_resource: GoalRequirementData = valid_requirements[0]
|
||||
var requirement_resource: GoalRequirementData = requirements[0]
|
||||
if requirement_resource == null:
|
||||
return BigNumber.from_float(0.0)
|
||||
|
||||
@@ -75,10 +75,10 @@ func get_unlock_goal_currency() -> Currency:
|
||||
if unlock_goal == null:
|
||||
return null
|
||||
|
||||
var valid_requirements: Array[GoalRequirementData] = unlock_goal.get_valid_requirements()
|
||||
if valid_requirements.is_empty():
|
||||
var requirements: Array[GoalRequirementData] = unlock_goal.get_requirements()
|
||||
if requirements.is_empty():
|
||||
return null
|
||||
var requirement_resource: GoalRequirementData = valid_requirements[0]
|
||||
var requirement_resource: GoalRequirementData = requirements[0]
|
||||
if requirement_resource == null:
|
||||
return null
|
||||
|
||||
|
||||
@@ -37,11 +37,12 @@ func _ready() -> void:
|
||||
_generator.purchase_failed.connect(_on_generator_updated)
|
||||
_generator.buff_purchased.connect(_on_generator_updated)
|
||||
_generator.buff_purchase_failed.connect(_on_generator_updated)
|
||||
GameState.currency_changed.connect(_on_currency_changed)
|
||||
|
||||
GameState.generator_state_changed.connect(_on_generator_state_changed)
|
||||
GameState.generator_buff_level_changed.connect(_on_generator_buff_level_changed)
|
||||
GameState.generator_buff_unlocked_changed.connect(_on_generator_buff_unlocked_changed)
|
||||
|
||||
if _generator.game_state:
|
||||
_generator.game_state.currency_changed.connect(_on_currency_changed)
|
||||
_generator.game_state.generator_state_changed.connect(_on_generator_state_changed)
|
||||
_generator.game_state.generator_buff_level_changed.connect(_on_generator_buff_level_changed)
|
||||
_generator.game_state.generator_buff_unlocked_changed.connect(_on_generator_buff_unlocked_changed)
|
||||
|
||||
_name_label.text = _generator.data.name if _generator.data != null else "Generator"
|
||||
_build_buff_rows()
|
||||
@@ -123,9 +124,9 @@ func _refresh_buff_rows(can_interact: bool) -> void:
|
||||
if not buff_unlocked:
|
||||
var locked_hint: String = "Locked"
|
||||
var unlock_goal_currency: Resource = buff.get_unlock_goal_currency()
|
||||
if buff.has_unlock_goal() and unlock_goal_currency != null:
|
||||
var goal_currency_id: StringName = GameState.get_currency_id(unlock_goal_currency)
|
||||
var currency_name: String = GameState.get_currency_name(goal_currency_id)
|
||||
if buff.has_unlock_goal() and unlock_goal_currency != null and _generator.game_state:
|
||||
var goal_currency_id: StringName = _generator.game_state.get_currency_id(unlock_goal_currency)
|
||||
var currency_name: String = _generator.game_state.get_currency_name(goal_currency_id)
|
||||
var required_text: String = buff.get_unlock_goal_amount().to_string_suffix(2)
|
||||
locked_hint = "Unlock at %s %s" % [required_text, currency_name]
|
||||
|
||||
@@ -141,7 +142,7 @@ func _refresh_buff_rows(can_interact: bool) -> void:
|
||||
|
||||
var cost: BigNumber = _generator.get_buff_cost(buff.id)
|
||||
var cost_currency_id: StringName = _generator.get_buff_cost_currency_id(buff.id)
|
||||
var currency_label: String = GameState.get_currency_name(cost_currency_id)
|
||||
var currency_label: String = _generator.game_state.get_currency_name(cost_currency_id) if _generator.game_state else "Unknown"
|
||||
var cost_text: String = "%s %s" % [cost.to_string_suffix(2), currency_label]
|
||||
var can_buy: bool = can_interact and _generator.can_buy_buff(buff.id)
|
||||
row.tile.set_runtime(level, effect_text, cost_text, can_buy, false)
|
||||
@@ -161,7 +162,7 @@ func _refresh_generator_ui() -> void:
|
||||
_owned_value.text = str(_generator.owned)
|
||||
if can_interact:
|
||||
var purchase_currency_id: StringName = _generator.get_purchase_currency_id()
|
||||
var purchase_currency_name: String = GameState.get_currency_name(purchase_currency_id)
|
||||
var purchase_currency_name: String = _generator.game_state.get_currency_name(purchase_currency_id) if _generator.game_state else "Unknown"
|
||||
if purchase_currency_name.is_empty():
|
||||
purchase_currency_name = "Unconfigured"
|
||||
_next_cost_value.text = "%s %s" % [_generator.get_next_cost().to_string_suffix(2), purchase_currency_name]
|
||||
|
||||
17
core/goal_catalogue.gd
Normal file
17
core/goal_catalogue.gd
Normal file
@@ -0,0 +1,17 @@
|
||||
class_name GoalCatalogue
|
||||
extends Resource
|
||||
|
||||
@export var goals: Array[GoalData] = []
|
||||
|
||||
func get_goal_by_id(id: StringName) -> GoalData:
|
||||
for goal in goals:
|
||||
if goal.id == id:
|
||||
return goal
|
||||
return null
|
||||
|
||||
func get_all_ids() -> Array[StringName]:
|
||||
var ids: Array[StringName] = []
|
||||
for goal in goals:
|
||||
if goal.has_id():
|
||||
ids.append(goal.id)
|
||||
return ids
|
||||
1
core/goal_catalogue.gd.uid
Normal file
1
core/goal_catalogue.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bfbp4mo8ys5p8
|
||||
@@ -38,12 +38,13 @@ enum UnlockBehavior {
|
||||
### Methods
|
||||
|
||||
```gdscript
|
||||
func is_valid() -> bool # Has id and valid requirements
|
||||
func is_met() -> bool # All requirements satisfied
|
||||
func get_progress() -> float # 0.0 to 1.0 based on closest requirement
|
||||
func get_first_requirement_summary() -> String # "100 Gold" format
|
||||
func has_id() -> bool # Has non-empty id
|
||||
func is_valid() -> bool # Has valid id and requirements
|
||||
func get_requirements() -> Array[GoalRequirementData] # Access requirements
|
||||
```
|
||||
|
||||
**Note:** State-dependent methods (`is_met()`, `get_progress()`, `get_summary_text()`) have been moved to `LevelGameState` for proper decoupling.
|
||||
|
||||
## GoalRequirementData
|
||||
|
||||
Single condition within a goal.
|
||||
@@ -62,12 +63,13 @@ extends Resource
|
||||
### Methods
|
||||
|
||||
```gdscript
|
||||
func get_currency() -> Currency # Currency to track
|
||||
func get_amount() -> BigNumber # Required amount
|
||||
func is_met() -> bool # Current >= required
|
||||
func get_progress() -> float # Log-scaled 0.0-1.0
|
||||
func get_summary_text() -> String # "100 Gold" format
|
||||
func has_valid_amount() -> bool # Amount is non-negative
|
||||
```
|
||||
|
||||
**Note:** State-dependent methods (`is_met()`, `get_progress()`, `get_summary_text()`) have been moved to `LevelGameState` for proper decoupling.
|
||||
|
||||
### Progress Calculation
|
||||
|
||||
Uses **logarithmic scaling** for better visual feedback on huge numbers:
|
||||
@@ -87,18 +89,18 @@ This means reaching 50% progress on a 1e100 goal requires ~1e50 currency.
|
||||
|
||||
### Automatic Checking
|
||||
|
||||
`GameState` evaluates goals whenever currency changes:
|
||||
`LevelGameState` evaluates goals whenever currency changes:
|
||||
|
||||
```gdscript
|
||||
func _on_currency_changed(currency_id, new_amount):
|
||||
GameState.evaluate_all_goals()
|
||||
game_state.evaluate_all_goals()
|
||||
```
|
||||
|
||||
### Completion Flow
|
||||
|
||||
1. Currency updated → signal emitted
|
||||
2. `GameState.evaluate_all_goals()` called
|
||||
3. Each uncompleted goal checked via `is_met()`
|
||||
2. `LevelGameState.evaluate_all_goals()` called
|
||||
3. Each uncompleted goal checked via `is_goal_met(goal)`
|
||||
4. If met → `goal_completed` signal emitted
|
||||
5. Buffs with unlock goals checked → unlocked if goal complete
|
||||
|
||||
@@ -110,6 +112,16 @@ Goals control their own unlock behavior via `unlock_behavior`:
|
||||
|
||||
Generators with `unlock_goal` automatically unlock when the goal completes.
|
||||
|
||||
### Goal Methods in LevelGameState
|
||||
|
||||
```gdscript
|
||||
func is_goal_requirement_met(requirement: GoalRequirementData) -> bool
|
||||
func get_goal_requirement_progress(requirement: GoalRequirementData) -> float
|
||||
func get_goal_requirement_summary(requirement: GoalRequirementData) -> String
|
||||
func is_goal_met(goal: GoalData) -> bool
|
||||
func get_goal_progress(goal: GoalData) -> float
|
||||
```
|
||||
|
||||
## Usage Example
|
||||
|
||||
### Defining a Goal
|
||||
|
||||
@@ -13,53 +13,22 @@ enum UnlockBehavior {
|
||||
func has_id() -> bool:
|
||||
return not String(id).strip_edges().is_empty()
|
||||
|
||||
func get_valid_requirements() -> Array[GoalRequirementData]:
|
||||
var result: Array[GoalRequirementData] = []
|
||||
for requirement_resource in requirements:
|
||||
if requirement_resource == null:
|
||||
continue
|
||||
if not bool(requirement_resource.is_valid()):
|
||||
continue
|
||||
|
||||
result.append(requirement_resource)
|
||||
|
||||
return result
|
||||
func get_requirements() -> Array[GoalRequirementData]:
|
||||
return requirements.duplicate()
|
||||
|
||||
func is_valid() -> bool:
|
||||
if not has_id():
|
||||
return false
|
||||
|
||||
return not get_valid_requirements().is_empty()
|
||||
|
||||
func is_met() -> bool:
|
||||
var valid_requirements: Array[GoalRequirementData] = get_valid_requirements()
|
||||
if valid_requirements.is_empty():
|
||||
|
||||
if requirements.is_empty():
|
||||
return false
|
||||
|
||||
for requirement_resource in valid_requirements:
|
||||
if not bool(requirement_resource.is_met()):
|
||||
return false
|
||||
|
||||
return true
|
||||
|
||||
func get_first_requirement_summary() -> String:
|
||||
var valid_requirements: Array[GoalRequirementData] = get_valid_requirements()
|
||||
if valid_requirements.is_empty():
|
||||
return ""
|
||||
return String(valid_requirements[0].get_summary_text())
|
||||
|
||||
func get_progress() -> float:
|
||||
var valid_requirements: Array[GoalRequirementData] = get_valid_requirements()
|
||||
if valid_requirements.is_empty():
|
||||
return 0.0
|
||||
|
||||
var min_progress: float = 1.0
|
||||
for requirement in valid_requirements:
|
||||
if requirement == null or not requirement.is_valid():
|
||||
for req in requirements:
|
||||
if req == null:
|
||||
continue
|
||||
if req.get_currency() == null:
|
||||
continue
|
||||
if not req.has_valid_amount():
|
||||
continue
|
||||
|
||||
var requirement_progress: float = requirement.get_progress()
|
||||
if requirement_progress < min_progress:
|
||||
min_progress = requirement_progress
|
||||
|
||||
return min_progress
|
||||
return true
|
||||
|
||||
@@ -5,63 +5,11 @@ extends Resource
|
||||
@export var amount_mantissa: float = 0.0
|
||||
@export var amount_exponent: int = 0
|
||||
|
||||
func get_currency_id() -> StringName:
|
||||
if currency == null:
|
||||
return &""
|
||||
|
||||
return GameState.get_currency_id(currency)
|
||||
func get_currency() -> Currency:
|
||||
return currency
|
||||
|
||||
func get_amount() -> BigNumber:
|
||||
return BigNumber.new(amount_mantissa, amount_exponent)
|
||||
|
||||
func has_valid_currency() -> bool:
|
||||
var currency_id: StringName = get_currency_id()
|
||||
if currency_id == &"":
|
||||
return false
|
||||
|
||||
return GameState.is_known_currency_id(currency_id)
|
||||
|
||||
func has_valid_amount() -> bool:
|
||||
return get_amount().mantissa >= 0.0
|
||||
|
||||
func is_valid() -> bool:
|
||||
return has_valid_currency() and has_valid_amount()
|
||||
|
||||
func is_met() -> bool:
|
||||
if not is_valid():
|
||||
return false
|
||||
|
||||
var total_amount: BigNumber = GameState.get_total_currency_acquired_by_id(get_currency_id())
|
||||
return not total_amount.is_less_than(get_amount())
|
||||
|
||||
func get_summary_text() -> String:
|
||||
if not is_valid():
|
||||
return ""
|
||||
|
||||
var currency_name: String = GameState.get_currency_name(get_currency_id())
|
||||
return "%s %s" % [get_amount().to_string_suffix(2), currency_name]
|
||||
|
||||
func get_progress() -> float:
|
||||
if not is_valid():
|
||||
return 0.0
|
||||
|
||||
var current_amount: BigNumber = GameState.get_total_currency_acquired_by_id(get_currency_id())
|
||||
var required_amount: BigNumber = get_amount()
|
||||
|
||||
if required_amount.mantissa <= 0.0:
|
||||
return 1.0
|
||||
|
||||
if current_amount.is_greater_than(required_amount) or current_amount.is_equal_to(required_amount):
|
||||
return 1.0
|
||||
|
||||
if current_amount.mantissa <= 0.0:
|
||||
return 0.0
|
||||
|
||||
var current_log: float = log(maxf(current_amount.mantissa, 0.0001)) / log(10) + float(current_amount.exponent)
|
||||
var required_log: float = log(maxf(required_amount.mantissa, 0.0001)) / log(10) + float(required_amount.exponent)
|
||||
|
||||
if required_log <= 0.0:
|
||||
return 1.0
|
||||
|
||||
var progress: float = current_log / required_log
|
||||
return clampf(progress, 0.0, 1.0)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
class_name LevelGameState
|
||||
extends Node
|
||||
# This script is added as an Autoload named 'GameState'
|
||||
|
||||
# ==========================================
|
||||
# SIGNALS
|
||||
@@ -13,6 +13,14 @@ signal buff_unlocked_changed(buff_id: StringName, unlocked: bool)
|
||||
signal goal_completed(goal_id: StringName)
|
||||
signal goal_progress_changed(goal_id: StringName, progress: float)
|
||||
|
||||
# ==========================================
|
||||
# EXPORTED REFERENCES
|
||||
# ==========================================
|
||||
@export var currency_catalogue: CurrencyCatalogue
|
||||
@export var buff_catalogue: BuffCatalogue
|
||||
@export var goal_catalogue: GoalCatalogue
|
||||
@export var save_file_path: String = "user://level_save.json"
|
||||
|
||||
# ==========================================
|
||||
# STATE VARIABLES
|
||||
# ==========================================
|
||||
@@ -33,12 +41,11 @@ var _buff_active: Dictionary = {}
|
||||
var _goal_definitions: Dictionary = {}
|
||||
var _goal_completed: Dictionary = {}
|
||||
|
||||
var last_save_time: int = 0 # Unix timestamp
|
||||
var last_save_time: int = 0
|
||||
|
||||
# ==========================================
|
||||
# Save / Load
|
||||
# ==========================================
|
||||
static var file_name: String = "user://idle_save.json"
|
||||
const SAVE_FORMAT_VERSION_KEY: String = "save_format_version"
|
||||
const CURRENT_SAVE_FORMAT_VERSION: int = 3
|
||||
const GENERATOR_OWNED_KEY: String = "owned"
|
||||
@@ -62,51 +69,56 @@ const LAST_SAVE_TIME_KEY: String = "last_save_time"
|
||||
|
||||
func _ready() -> void:
|
||||
_initialize_currency_maps()
|
||||
_initialize_goals()
|
||||
_initialize_catalogues()
|
||||
_load_catalogue_goals()
|
||||
load_game()
|
||||
_try_unlock_all_buffs_from_goals()
|
||||
|
||||
# ==========================================
|
||||
# STATE MODIFIERS
|
||||
# ==========================================
|
||||
#func add_gold(amount: BigNumber) -> void:
|
||||
#add_currency_by_id(GOLD_CURRENCY_ID, amount)
|
||||
#
|
||||
#func spend_gold(cost: BigNumber) -> bool:
|
||||
#return spend_currency_by_id(GOLD_CURRENCY_ID, cost)
|
||||
#
|
||||
#func add_gems(amount: BigNumber) -> void:
|
||||
#add_currency_by_id(GEMS_CURRENCY_ID, amount)
|
||||
#
|
||||
#func spend_gems(cost: BigNumber) -> bool:
|
||||
#return spend_currency_by_id(GEMS_CURRENCY_ID, cost)
|
||||
|
||||
func get_known_currencies() -> Array[Currency]:
|
||||
return CurrencyDatabase.get_known_currencies()
|
||||
|
||||
func get_currency_id(currency: Resource) -> StringName:
|
||||
return CurrencyDatabase.get_currency_id(currency)
|
||||
return _normalize_currency_id(currency.id if currency else &"")
|
||||
|
||||
func parse_currency_id(raw_currency: Variant) -> StringName:
|
||||
return CurrencyDatabase.parse_currency_id(raw_currency)
|
||||
var currency_text: String = String(raw_currency).to_lower().strip_edges()
|
||||
if currency_text == "gem":
|
||||
currency_text = "gems"
|
||||
return _normalize_currency_id(StringName(currency_text))
|
||||
|
||||
func is_known_currency_id(currency_id: StringName) -> bool:
|
||||
return CurrencyDatabase.is_known_currency_id(currency_id)
|
||||
if not currency_catalogue:
|
||||
return false
|
||||
var ids: Array[StringName] = currency_catalogue.get_all_ids()
|
||||
return ids.has(_normalize_currency_id(currency_id))
|
||||
|
||||
func get_currency_resource(currency_id: StringName) -> Resource:
|
||||
return CurrencyDatabase.get_currency_resource(currency_id)
|
||||
func get_currency_resource(currency_id: StringName) -> Currency:
|
||||
if not currency_catalogue:
|
||||
return null
|
||||
return currency_catalogue.get_currency_by_id(_normalize_currency_id(currency_id))
|
||||
|
||||
func get_currency_name(currency_id: StringName) -> String:
|
||||
return CurrencyDatabase.get_currency_name(currency_id)
|
||||
var currency: Currency = get_currency_resource(currency_id)
|
||||
if currency != null:
|
||||
var display_name: String = String(currency.display_name).strip_edges()
|
||||
if not display_name.is_empty():
|
||||
return display_name
|
||||
return _humanize_currency_id(currency_id)
|
||||
|
||||
func get_currency_icon(currency_id: StringName) -> Texture2D:
|
||||
return CurrencyDatabase.get_currency_icon(currency_id)
|
||||
var currency: Resource = get_currency_resource(currency_id)
|
||||
if currency == null:
|
||||
return null
|
||||
var raw_icon: Variant = currency.icon
|
||||
if raw_icon is Texture2D:
|
||||
return raw_icon
|
||||
return null
|
||||
|
||||
func add_currency(currency: Resource, amount: BigNumber) -> void:
|
||||
var currency_id: StringName = get_currency_id(currency)
|
||||
if currency_id == &"":
|
||||
push_warning("Attempted to add currency with an invalid Currency resource.")
|
||||
return
|
||||
|
||||
add_currency_by_id(currency_id, amount)
|
||||
|
||||
func spend_currency(currency: Resource, cost: BigNumber) -> bool:
|
||||
@@ -114,7 +126,6 @@ func spend_currency(currency: Resource, cost: BigNumber) -> bool:
|
||||
if currency_id == &"":
|
||||
push_warning("Attempted to spend currency with an invalid Currency resource.")
|
||||
return false
|
||||
|
||||
return spend_currency_by_id(currency_id, cost)
|
||||
|
||||
func add_currency_by_id(currency_id: StringName, amount: BigNumber) -> void:
|
||||
@@ -387,6 +398,9 @@ func get_generators_targeted_by(buff_id: StringName) -> Array[StringName]:
|
||||
return buff.get_target_generators()
|
||||
|
||||
func get_buffs_for_generator(generator_id: StringName) -> Array[GeneratorBuffData]:
|
||||
if buff_catalogue:
|
||||
return buff_catalogue.get_buffs_for_generator(generator_id)
|
||||
|
||||
var result: Array[GeneratorBuffData] = []
|
||||
for buff in _buff_definitions.values():
|
||||
if buff is GeneratorBuffData and buff.targets_generator(generator_id):
|
||||
@@ -475,6 +489,10 @@ func emit_currency_changed_for_all() -> void:
|
||||
# PERSISTENCE (Save/Load)
|
||||
# ==========================================
|
||||
func save_game() -> void:
|
||||
if save_file_path.is_empty():
|
||||
push_warning("LevelGameState: save_file_path is empty; skipping save.")
|
||||
return
|
||||
|
||||
var save_data = {
|
||||
SAVE_FORMAT_VERSION_KEY: CURRENT_SAVE_FORMAT_VERSION,
|
||||
CURRENCIES_KEY: _serialize_currency_balances(),
|
||||
@@ -497,15 +515,17 @@ func save_game() -> void:
|
||||
|
||||
save_data[key] = payload
|
||||
|
||||
var file: FileAccess = FileAccess.open(file_name, FileAccess.WRITE)
|
||||
var file: FileAccess = FileAccess.open(save_file_path, FileAccess.WRITE)
|
||||
if file:
|
||||
file.store_string(JSON.stringify(save_data))
|
||||
else:
|
||||
push_error("LevelGameState: Failed to open save file: %s" % save_file_path)
|
||||
|
||||
func load_game() -> void:
|
||||
if not FileAccess.file_exists(file_name):
|
||||
if not FileAccess.file_exists(save_file_path):
|
||||
return
|
||||
|
||||
var file: FileAccess = FileAccess.open(file_name, FileAccess.READ)
|
||||
var file: FileAccess = FileAccess.open(save_file_path, FileAccess.READ)
|
||||
if file:
|
||||
var parsed: Variant = JSON.parse_string(file.get_as_text())
|
||||
if parsed is Dictionary:
|
||||
@@ -624,21 +644,147 @@ func _collect_currency_ids_for_save() -> Array[StringName]:
|
||||
continue
|
||||
ids.append(normalized_currency_id)
|
||||
|
||||
for known_currency_id in CurrencyDatabase.get_known_currency_ids():
|
||||
var normalized_currency_id: StringName = _normalize_currency_id(known_currency_id)
|
||||
if normalized_currency_id == &"" or ids.has(normalized_currency_id):
|
||||
continue
|
||||
ids.append(normalized_currency_id)
|
||||
if currency_catalogue:
|
||||
for known_currency_id in currency_catalogue.get_all_ids():
|
||||
var normalized_currency_id: StringName = _normalize_currency_id(known_currency_id)
|
||||
if normalized_currency_id == &"" or ids.has(normalized_currency_id):
|
||||
continue
|
||||
ids.append(normalized_currency_id)
|
||||
|
||||
return ids
|
||||
|
||||
func _initialize_currency_maps() -> void:
|
||||
for currency_id in CurrencyDatabase.get_known_currency_ids():
|
||||
if currency_id == &"":
|
||||
if currency_catalogue:
|
||||
for currency_id in currency_catalogue.get_all_ids():
|
||||
if currency_id == &"":
|
||||
continue
|
||||
_set_current_currency(currency_id, BigNumber.from_float(0.0))
|
||||
_set_total_currency(currency_id, BigNumber.from_float(0.0))
|
||||
_set_all_time_currency(currency_id, BigNumber.from_float(0.0))
|
||||
|
||||
func _initialize_catalogues() -> void:
|
||||
if currency_catalogue:
|
||||
for currency in currency_catalogue.currencies:
|
||||
if currency == null:
|
||||
continue
|
||||
|
||||
if buff_catalogue:
|
||||
for buff in buff_catalogue.buffs:
|
||||
if buff == null:
|
||||
continue
|
||||
register_buff(buff)
|
||||
|
||||
if goal_catalogue:
|
||||
for goal in goal_catalogue.goals:
|
||||
if goal == null:
|
||||
continue
|
||||
register_goal(goal)
|
||||
|
||||
func _load_catalogue_goals() -> void:
|
||||
if goal_catalogue:
|
||||
for goal in goal_catalogue.goals:
|
||||
if goal == null:
|
||||
continue
|
||||
if not goal.has_id():
|
||||
continue
|
||||
if _goal_definitions.has(goal.id):
|
||||
continue
|
||||
_goal_definitions[goal.id] = goal
|
||||
_goal_completed[goal.id] = false
|
||||
|
||||
func is_goal_requirement_met(requirement: GoalRequirementData) -> bool:
|
||||
if requirement == null:
|
||||
return false
|
||||
|
||||
var currency: Currency = requirement.get_currency()
|
||||
if currency == null:
|
||||
return false
|
||||
|
||||
var currency_id: StringName = get_currency_id(currency)
|
||||
if currency_id == &"":
|
||||
return false
|
||||
|
||||
var total_amount: BigNumber = get_total_currency_acquired_by_id(currency_id)
|
||||
var required_amount: BigNumber = requirement.get_amount()
|
||||
|
||||
return not total_amount.is_less_than(required_amount)
|
||||
|
||||
func get_goal_requirement_progress(requirement: GoalRequirementData) -> float:
|
||||
if requirement == null:
|
||||
return 0.0
|
||||
|
||||
var currency: Currency = requirement.get_currency()
|
||||
if currency == null:
|
||||
return 0.0
|
||||
|
||||
var currency_id: StringName = get_currency_id(currency)
|
||||
if currency_id == &"":
|
||||
return 0.0
|
||||
|
||||
var current_amount: BigNumber = get_total_currency_acquired_by_id(currency_id)
|
||||
var required_amount: BigNumber = requirement.get_amount()
|
||||
|
||||
if required_amount.mantissa <= 0.0:
|
||||
return 1.0
|
||||
|
||||
if current_amount.is_greater_than(required_amount) or current_amount.is_equal_to(required_amount):
|
||||
return 1.0
|
||||
|
||||
if current_amount.mantissa <= 0.0:
|
||||
return 0.0
|
||||
|
||||
var current_log: float = log(maxf(current_amount.mantissa, 0.0001)) / log(10) + float(current_amount.exponent)
|
||||
var required_log: float = log(maxf(required_amount.mantissa, 0.0001)) / log(10) + float(required_amount.exponent)
|
||||
|
||||
if required_log <= 0.0:
|
||||
return 1.0
|
||||
|
||||
var progress: float = current_log / required_log
|
||||
return clampf(progress, 0.0, 1.0)
|
||||
|
||||
func get_goal_requirement_summary(requirement: GoalRequirementData) -> String:
|
||||
if requirement == null:
|
||||
return ""
|
||||
|
||||
var currency: Currency = requirement.get_currency()
|
||||
if currency == null:
|
||||
return ""
|
||||
|
||||
var currency_id: StringName = get_currency_id(currency)
|
||||
if currency_id == &"":
|
||||
return ""
|
||||
|
||||
var currency_name: String = get_currency_name(currency_id)
|
||||
return "%s %s" % [requirement.get_amount().to_string_suffix(2), currency_name]
|
||||
|
||||
func is_goal_met(goal: GoalData) -> bool:
|
||||
if goal == null:
|
||||
return false
|
||||
|
||||
for req in goal.get_requirements():
|
||||
if not is_goal_requirement_met(req):
|
||||
return false
|
||||
|
||||
return true
|
||||
|
||||
func get_goal_progress(goal: GoalData) -> float:
|
||||
if goal == null:
|
||||
return 0.0
|
||||
|
||||
var requirements: Array[GoalRequirementData] = goal.get_requirements()
|
||||
if requirements.is_empty():
|
||||
return 0.0
|
||||
|
||||
var min_progress: float = 1.0
|
||||
for req in requirements:
|
||||
if req == null:
|
||||
continue
|
||||
_set_current_currency(currency_id, BigNumber.from_float(0.0))
|
||||
_set_total_currency(currency_id, BigNumber.from_float(0.0))
|
||||
_set_all_time_currency(currency_id, BigNumber.from_float(0.0))
|
||||
|
||||
var req_progress: float = get_goal_requirement_progress(req)
|
||||
if req_progress < min_progress:
|
||||
min_progress = req_progress
|
||||
|
||||
return min_progress
|
||||
|
||||
func _normalize_currency_id(currency_id: StringName) -> StringName:
|
||||
var normalized: String = String(currency_id).to_lower().strip_edges()
|
||||
@@ -794,7 +940,6 @@ func _sanitize_generator_buff_unlocked(raw_unlocked: Dictionary) -> Dictionary:
|
||||
if buff_key.is_empty():
|
||||
continue
|
||||
|
||||
# Save format only stores true values, but keep parser tolerant.
|
||||
var is_unlocked: bool = _to_bool(raw_unlocked.get(buff_key_variant, false), false)
|
||||
if not is_unlocked:
|
||||
continue
|
||||
@@ -1010,57 +1155,6 @@ func _deserialize_buff_states(parsed_data: Dictionary) -> void:
|
||||
# ==========================================
|
||||
# GOALS
|
||||
# ==========================================
|
||||
func _initialize_goals() -> void:
|
||||
_goal_definitions.clear()
|
||||
_goal_completed.clear()
|
||||
|
||||
var goal_paths: PackedStringArray = _discover_goal_paths()
|
||||
for goal_path in goal_paths:
|
||||
var goal_resource: Resource = load(goal_path)
|
||||
if goal_resource == null:
|
||||
push_warning("Failed to load goal resource at '%s'." % goal_path)
|
||||
continue
|
||||
if not (goal_resource is GoalData):
|
||||
continue
|
||||
|
||||
var goal: GoalData = goal_resource
|
||||
if not goal.has_id():
|
||||
push_warning("Skipping goal with missing id: %s" % goal_path)
|
||||
continue
|
||||
if _goal_definitions.has(goal.id):
|
||||
push_warning("Duplicate goal id '%s' found at %s. Keeping first occurrence." % [String(goal.id), goal_path])
|
||||
continue
|
||||
|
||||
_goal_definitions[goal.id] = goal
|
||||
_goal_completed[goal.id] = false
|
||||
|
||||
func _discover_goal_paths() -> PackedStringArray:
|
||||
var result: PackedStringArray = []
|
||||
const GOAL_DIRECTORY_PATH: String = "res://docs/gyms/goals"
|
||||
const GOAL_RESOURCE_EXTENSIONS: PackedStringArray = ["tres", "res"]
|
||||
|
||||
var directory: DirAccess = DirAccess.open(GOAL_DIRECTORY_PATH)
|
||||
if directory == null:
|
||||
push_warning("Unable to open goals directory: %s" % GOAL_DIRECTORY_PATH)
|
||||
return result
|
||||
|
||||
directory.list_dir_begin()
|
||||
var entry_name: String = directory.get_next()
|
||||
while not entry_name.is_empty():
|
||||
if directory.current_is_dir() or entry_name.begins_with("."):
|
||||
entry_name = directory.get_next()
|
||||
continue
|
||||
|
||||
var extension: String = entry_name.get_extension().to_lower()
|
||||
if GOAL_RESOURCE_EXTENSIONS.has(extension):
|
||||
result.append("%s/%s" % [GOAL_DIRECTORY_PATH, entry_name])
|
||||
|
||||
entry_name = directory.get_next()
|
||||
directory.list_dir_end()
|
||||
|
||||
result.sort()
|
||||
return result
|
||||
|
||||
func register_goal(goal: GoalData) -> void:
|
||||
if goal == null:
|
||||
return
|
||||
@@ -1086,11 +1180,11 @@ func get_all_goals() -> Array[GoalData]:
|
||||
func is_goal_completed(goal_id: StringName) -> bool:
|
||||
return _goal_completed.get(goal_id, false)
|
||||
|
||||
func get_goal_progress(goal_id: StringName) -> float:
|
||||
func get_goal_progress_by_id(goal_id: StringName) -> float:
|
||||
var goal: GoalData = get_goal(goal_id)
|
||||
if goal == null:
|
||||
return 0.0
|
||||
return goal.get_progress()
|
||||
return get_goal_progress(goal)
|
||||
|
||||
func evaluate_all_goals() -> void:
|
||||
for goal_id in _goal_completed.keys():
|
||||
@@ -1098,6 +1192,8 @@ func evaluate_all_goals() -> void:
|
||||
_try_complete_goal(goal_id)
|
||||
|
||||
_try_unlock_all_buffs_from_goals()
|
||||
|
||||
goal_progress_changed.emit(&"", 0.0)
|
||||
|
||||
func _try_complete_goal(goal_id: StringName) -> void:
|
||||
var goal: GoalData = _goal_definitions.get(goal_id, null)
|
||||
@@ -1105,7 +1201,7 @@ func _try_complete_goal(goal_id: StringName) -> void:
|
||||
return
|
||||
if _goal_completed[goal_id]:
|
||||
return
|
||||
if goal.is_met():
|
||||
if is_goal_met(goal):
|
||||
if goal.unlock_behavior == GoalData.UnlockBehavior.MANUAL:
|
||||
return
|
||||
_goal_completed[goal_id] = true
|
||||
@@ -1117,7 +1213,7 @@ func _complete_goal_manually(goal_id: StringName) -> void:
|
||||
return
|
||||
if _goal_completed.get(goal_id, false):
|
||||
return
|
||||
if not goal.is_met():
|
||||
if not is_goal_met(goal):
|
||||
return
|
||||
_goal_completed[goal_id] = true
|
||||
goal_completed.emit(goal_id)
|
||||
@@ -1161,11 +1257,7 @@ func _migrate_goals_from_version_2(parsed_data: Dictionary) -> void:
|
||||
if not state.get(GENERATOR_UNLOCKED_KEY, false):
|
||||
continue
|
||||
|
||||
var generator_data: CurrencyGeneratorData = _load_generator_data_from_id(gen_id)
|
||||
if generator_data == null or not generator_data.has_unlock_goal():
|
||||
continue
|
||||
|
||||
var goal_id: StringName = generator_data.get_unlock_goal_id()
|
||||
var goal_id: StringName = _get_unlock_goal_id_for_generator(gen_id)
|
||||
if not goal_id.is_empty():
|
||||
_goal_completed[goal_id] = true
|
||||
|
||||
@@ -1173,32 +1265,27 @@ func _migrate_goals_from_version_2(parsed_data: Dictionary) -> void:
|
||||
if not _goal_completed.has(goal_id):
|
||||
_goal_completed[goal_id] = false
|
||||
|
||||
func _load_generator_data_from_id(generator_id: String) -> CurrencyGeneratorData:
|
||||
const GENERATORS_DIRECTORY_PATH: String = "res://docs/gyms/generators"
|
||||
const GENERATOR_RESOURCE_EXTENSIONS: PackedStringArray = ["tres", "res"]
|
||||
func _get_unlock_goal_id_for_generator(generator_id: String) -> StringName:
|
||||
if goal_catalogue == null:
|
||||
return &""
|
||||
|
||||
var directory: DirAccess = DirAccess.open(GENERATORS_DIRECTORY_PATH)
|
||||
if directory == null:
|
||||
return null
|
||||
|
||||
directory.list_dir_begin()
|
||||
var entry_name: String = directory.get_next()
|
||||
while not entry_name.is_empty():
|
||||
if directory.current_is_dir() or entry_name.begins_with("."):
|
||||
entry_name = directory.get_next()
|
||||
for goal in goal_catalogue.goals:
|
||||
if goal == null or not goal.has_id():
|
||||
continue
|
||||
|
||||
var extension: String = entry_name.get_extension().to_lower()
|
||||
if GENERATOR_RESOURCE_EXTENSIONS.has(extension):
|
||||
var generator_path: String = "%s/%s" % [GENERATORS_DIRECTORY_PATH, entry_name]
|
||||
var generator_resource: Resource = load(generator_path)
|
||||
if generator_resource is CurrencyGeneratorData:
|
||||
var gen_data: CurrencyGeneratorData = generator_resource
|
||||
if String(gen_data.id) == generator_id:
|
||||
directory.list_dir_end()
|
||||
return gen_data
|
||||
|
||||
entry_name = directory.get_next()
|
||||
directory.list_dir_end()
|
||||
var goal_id: StringName = goal.id
|
||||
var requirements: Array[GoalRequirementData] = goal.get_requirements()
|
||||
for req in requirements:
|
||||
if req == null or req.get_currency() == null:
|
||||
continue
|
||||
|
||||
if String(req.get_currency().id) == generator_id:
|
||||
return goal_id
|
||||
|
||||
return null
|
||||
return &""
|
||||
|
||||
func _humanize_currency_id(currency_id: StringName) -> String:
|
||||
var normalized: String = String(_normalize_currency_id(currency_id))
|
||||
if normalized.is_empty():
|
||||
return "Unknown"
|
||||
return normalized.replace("_", " ").capitalize()
|
||||
1
core/level_game_state.gd.uid
Normal file
1
core/level_game_state.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cv2132o4hi7q3
|
||||
@@ -1,3 +1,4 @@
|
||||
class_name PrestigeManager
|
||||
extends Node
|
||||
|
||||
signal prestige_state_changed(total_prestige: BigNumber, pending_gain: BigNumber)
|
||||
@@ -23,6 +24,7 @@ const MULTIPLIER_MODE_ADDITIVE: int = 0
|
||||
const MULTIPLIER_MODE_MULTIPLICATIVE_POWER: int = 1
|
||||
|
||||
@export var config: Resource
|
||||
@export var game_state: LevelGameState
|
||||
|
||||
var total_prestige_earned: BigNumber = BigNumber.from_float(0.0)
|
||||
var current_prestige_unspent: BigNumber = BigNumber.from_float(0.0)
|
||||
@@ -33,13 +35,17 @@ var last_reset_time: int = 0
|
||||
|
||||
func _ready() -> void:
|
||||
if config == null:
|
||||
config = load("res://docs/gyms/prestige/primary_prestige.tres") as Resource
|
||||
config = load("res://docs/gyms/tiny_sword/prestige/primary_prestige.tres") as Resource
|
||||
|
||||
if not _is_config_valid():
|
||||
push_warning("PrestigeManager has invalid or missing config; prestige is disabled.")
|
||||
return
|
||||
|
||||
var loaded_state: Dictionary = GameState.get_external_save_data(SAVE_KEY)
|
||||
if game_state == null:
|
||||
push_warning("PrestigeManager: game_state reference is not set.")
|
||||
return
|
||||
|
||||
var loaded_state: Dictionary = game_state.get_external_save_data(SAVE_KEY)
|
||||
if loaded_state.is_empty():
|
||||
_initialize_run_tracking_from_current_state()
|
||||
else:
|
||||
@@ -47,7 +53,7 @@ func _ready() -> void:
|
||||
_validate_loaded_run_tracking()
|
||||
_save_state_to_game_state()
|
||||
|
||||
GameState.currency_changed.connect(_on_currency_changed)
|
||||
game_state.currency_changed.connect(_on_currency_changed)
|
||||
prestige_state_changed.emit(get_total_prestige(), calculate_pending_gain())
|
||||
prestige_threshold_changed.emit(get_next_prestige_threshold())
|
||||
|
||||
@@ -134,13 +140,16 @@ func perform_prestige() -> bool:
|
||||
prestige_resets_count += 1
|
||||
last_reset_time = Time.get_unix_time_from_system()
|
||||
|
||||
GameState.reset_for_prestige(true, false)
|
||||
if game_state:
|
||||
game_state.reset_for_prestige(true, false)
|
||||
_reset_all_buff_levels()
|
||||
_reinitialize_generators_after_prestige_reset()
|
||||
GameState.emit_currency_changed_for_all()
|
||||
if game_state:
|
||||
game_state.emit_currency_changed_for_all()
|
||||
_initialize_run_tracking_from_current_state()
|
||||
_save_state_to_game_state()
|
||||
GameState.save_game()
|
||||
if game_state:
|
||||
game_state.save_game()
|
||||
|
||||
var total: BigNumber = get_total_prestige()
|
||||
var next_threshold: BigNumber = get_next_prestige_threshold()
|
||||
@@ -261,9 +270,12 @@ func _get_basis_value() -> BigNumber:
|
||||
if source_currency_id == &"":
|
||||
return BigNumber.from_float(0.0)
|
||||
|
||||
if game_state == null:
|
||||
return BigNumber.from_float(0.0)
|
||||
|
||||
match _get_config_int("basis", BASIS_LIFETIME_TOTAL):
|
||||
BASIS_RUN_TOTAL:
|
||||
var lifetime_now: BigNumber = GameState.get_total_currency_acquired_by_id(source_currency_id)
|
||||
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:
|
||||
return BigNumber.from_float(0.0)
|
||||
@@ -271,7 +283,7 @@ func _get_basis_value() -> BigNumber:
|
||||
BASIS_RUN_MAX:
|
||||
return _copy_big_number(run_peak_source_currency)
|
||||
_:
|
||||
return _copy_big_number(GameState.get_total_currency_acquired_by_id(source_currency_id))
|
||||
return _copy_big_number(game_state.get_total_currency_acquired_by_id(source_currency_id))
|
||||
|
||||
func _initialize_run_tracking_from_current_state() -> void:
|
||||
if config == null:
|
||||
@@ -283,8 +295,13 @@ func _initialize_run_tracking_from_current_state() -> void:
|
||||
run_peak_source_currency = BigNumber.from_float(0.0)
|
||||
return
|
||||
|
||||
run_start_total_source_currency = _copy_big_number(GameState.get_total_currency_acquired_by_id(source_currency_id))
|
||||
run_peak_source_currency = _copy_big_number(GameState.get_currency_amount_by_id(source_currency_id))
|
||||
if game_state == null:
|
||||
run_start_total_source_currency = BigNumber.from_float(0.0)
|
||||
run_peak_source_currency = BigNumber.from_float(0.0)
|
||||
return
|
||||
|
||||
run_start_total_source_currency = _copy_big_number(game_state.get_total_currency_acquired_by_id(source_currency_id))
|
||||
run_peak_source_currency = _copy_big_number(game_state.get_currency_amount_by_id(source_currency_id))
|
||||
_save_state_to_game_state()
|
||||
|
||||
func _validate_loaded_run_tracking() -> void:
|
||||
@@ -297,11 +314,14 @@ func _validate_loaded_run_tracking() -> void:
|
||||
run_peak_source_currency = BigNumber.from_float(0.0)
|
||||
return
|
||||
|
||||
var current_currency: BigNumber = GameState.get_currency_amount_by_id(source_currency_id)
|
||||
if game_state == null:
|
||||
return
|
||||
|
||||
var current_currency: BigNumber = game_state.get_currency_amount_by_id(source_currency_id)
|
||||
if current_currency.is_greater_than(run_peak_source_currency):
|
||||
run_peak_source_currency = _copy_big_number(current_currency)
|
||||
|
||||
var lifetime_now: BigNumber = GameState.get_total_currency_acquired_by_id(source_currency_id)
|
||||
var lifetime_now: BigNumber = game_state.get_total_currency_acquired_by_id(source_currency_id)
|
||||
if run_start_total_source_currency.is_greater_than(lifetime_now):
|
||||
run_start_total_source_currency = _copy_big_number(lifetime_now)
|
||||
|
||||
@@ -327,12 +347,16 @@ func _deserialize_state(raw_state: Dictionary) -> void:
|
||||
current_prestige_unspent = _copy_big_number(total_prestige_earned)
|
||||
|
||||
func _save_state_to_game_state() -> void:
|
||||
GameState.set_external_save_data(SAVE_KEY, _serialize_state())
|
||||
if game_state:
|
||||
game_state.set_external_save_data(SAVE_KEY, _serialize_state())
|
||||
|
||||
func _reset_all_buff_levels() -> void:
|
||||
for buff_id in GameState._buff_levels.keys():
|
||||
GameState.set_buff_level(buff_id, 0)
|
||||
GameState.set_buff_unlocked(buff_id, false)
|
||||
if game_state == null:
|
||||
return
|
||||
|
||||
for buff_id in game_state._buff_levels.keys():
|
||||
game_state.set_buff_level(buff_id, 0)
|
||||
game_state.set_buff_unlocked(buff_id, false)
|
||||
|
||||
func _reinitialize_generators_after_prestige_reset() -> void:
|
||||
var scene_root: Node = get_tree().current_scene
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
class_name PrestigePanel
|
||||
extends PanelContainer
|
||||
|
||||
@export var game_state: LevelGameState
|
||||
|
||||
@onready var _total_value: Label = $MarginContainer/VBoxContainer/StatsGrid/TotalValue
|
||||
@onready var _pending_value: Label = $MarginContainer/VBoxContainer/StatsGrid/PendingValue
|
||||
@onready var _multiplier_value: Label = $MarginContainer/VBoxContainer/StatsGrid/MultiplierValue
|
||||
@@ -18,8 +20,8 @@ func _ready() -> void:
|
||||
manager.prestige_state_changed.connect(_on_prestige_state_changed)
|
||||
if manager != null and manager.has_signal("prestige_performed"):
|
||||
manager.prestige_performed.connect(_on_prestige_performed)
|
||||
if not GameState.currency_changed.is_connected(_on_currency_changed):
|
||||
GameState.currency_changed.connect(_on_currency_changed)
|
||||
if game_state and not game_state.currency_changed.is_connected(_on_currency_changed):
|
||||
game_state.currency_changed.connect(_on_currency_changed)
|
||||
|
||||
_refresh_ui()
|
||||
|
||||
@@ -33,7 +35,7 @@ func _on_reset_button_pressed() -> void:
|
||||
|
||||
var pending: BigNumber = manager.call("calculate_pending_gain")
|
||||
var source_currency_id: StringName = manager.call("get_source_currency_id")
|
||||
var source_currency_name: String = GameState.get_currency_name(source_currency_id)
|
||||
var source_currency_name: String = game_state.get_currency_name(source_currency_id) if game_state else ""
|
||||
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]
|
||||
@@ -43,7 +45,8 @@ func _on_reset_button_pressed() -> void:
|
||||
_confirm_dialog.popup_centered_ratio(0.4)
|
||||
|
||||
func _on_save_button_pressed() -> void:
|
||||
GameState.save_game()
|
||||
if game_state:
|
||||
game_state.save_game()
|
||||
|
||||
func _on_prestige_state_changed(_total: BigNumber, _pending: BigNumber) -> void:
|
||||
_refresh_ui()
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
[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"]
|
||||
[ext_resource type="Resource" uid="uid://dwmfvmusfskk6" path="res://docs/gyms/prestige/primary_prestige.tres" id="3_r8h5p"]
|
||||
[ext_resource type="Resource" uid="uid://dwmfvmusfskk6" path="res://docs/gyms/tiny_sword/prestige/primary_prestige.tres" id="3_r8h5p"]
|
||||
|
||||
[node name="PrestigePanel" type="PanelContainer" unique_id=789062217]
|
||||
offset_right = 420.0
|
||||
|
||||
Reference in New Issue
Block a user