This commit is contained in:
Michele Rossi
2026-03-13 00:36:52 +01:00
parent e019b4b90a
commit 246cf6a05f
12 changed files with 549 additions and 126 deletions

View File

@@ -1,49 +1,5 @@
extends Control extends Control
@onready var _generator: CurrencyGenerator = $VBoxContainer2/HBoxContainerGenerators/BuyOneButton
@onready var _name_label: Label = $VBoxContainer2/Label
@onready var _owned_value: Label = $VBoxContainer2/GeneratorStatsGrid/OwnedValue
@onready var _next_cost_value: Label = $VBoxContainer2/GeneratorStatsGrid/NextCostValue
@onready var _production_value: Label = $VBoxContainer2/GeneratorStatsGrid/ProductionValue
func _ready() -> void: func _ready() -> void:
_generator.purchase_completed.connect(_on_generator_updated) pass
_generator.production_tick.connect(_on_generator_updated)
_generator.purchase_failed.connect(_on_generator_updated)
match _generator.currency:
GameState.CurrencyType.gold:
GameState.gold_changed.connect(_on_currency_changed)
GameState.CurrencyType.gems:
GameState.gems_changed.connect(_on_currency_changed)
_name_label.text = _generator.data.name
_refresh_generator_ui()
func _on_buy_max_pressed() -> void:
_generator.buy_max()
_refresh_generator_ui()
func _on_debug_income_pressed() -> void:
_generator.grant_currency(BigNumber.from_float(100.0))
_refresh_generator_ui()
func _on_currency_changed(_new_value: BigNumber) -> void:
_refresh_generator_ui()
func _on_generator_updated(_a = null, _b = null, _c = null, _d = null) -> void:
_refresh_generator_ui()
func _refresh_generator_ui() -> void:
_owned_value.text = str(_generator.owned)
_next_cost_value.text = _generator.get_next_cost().to_string_suffix(2)
var production_per_second: float = 0.0
if _generator.data != null:
production_per_second = _generator.data.production_per_second(
_generator.owned,
_generator.run_multiplier,
_generator.purchased_count
)
_production_value.text = BigNumber.from_float(production_per_second).to_string_suffix(2)

View File

@@ -1,9 +1,8 @@
[gd_scene format=3 uid="uid://b11eevc8qj18p"] [gd_scene format=3 uid="uid://b11eevc8qj18p"]
[ext_resource type="Script" uid="uid://dtbxopw6ulhl8" path="res://generator/currency_generator.gd" id="1_h2bxk"]
[ext_resource type="Script" uid="uid://coasop1lyw5rh" path="res://big_number_museum.gd" id="1_muwei"] [ext_resource type="Script" uid="uid://coasop1lyw5rh" path="res://big_number_museum.gd" id="1_muwei"]
[ext_resource type="Script" uid="uid://sp67wcb6s5nw" path="res://currency_label.gd" id="2_a7k0t"] [ext_resource type="PackedScene" uid="uid://btkxru2gdjsgc" path="res://currency_tile.tscn" id="2_a7k0t"]
[ext_resource type="Resource" uid="uid://co0mcc2kvcpo5" path="res://generator/primary_generator.tres" id="3_m5m0g"] [ext_resource type="PackedScene" uid="uid://ckos7f22pnmyh" path="res://generator_container.tscn" id="2_h2bxk"]
[node name="BigNumberMuseum" type="Control" unique_id=1249411984] [node name="BigNumberMuseum" type="Control" unique_id=1249411984]
layout_mode = 3 layout_mode = 3
@@ -14,81 +13,37 @@ grow_horizontal = 2
grow_vertical = 2 grow_vertical = 2
script = ExtResource("1_muwei") script = ExtResource("1_muwei")
[node name="VBoxContainer" type="VBoxContainer" parent="." unique_id=1937517070] [node name="CurrencyTile" parent="." unique_id=1440583137 instance=ExtResource("2_a7k0t")]
layout_mode = 0 layout_mode = 0
offset_right = 404.0 offset_right = 404.0
offset_bottom = 267.0 offset_bottom = 31.0
[node name="HBoxContainerCurrency" type="HBoxContainer" parent="VBoxContainer" unique_id=93448794] [node name="GoldGeneratorContainer" parent="." unique_id=1129190041 instance=ExtResource("2_h2bxk")]
layout_mode = 2
theme_override_constants/separation = 12
[node name="Label" type="Label" parent="VBoxContainer/HBoxContainerCurrency" unique_id=1951729878]
layout_mode = 2
text = "Gold:"
[node name="CurrencyValueLabel" type="Label" parent="VBoxContainer/HBoxContainerCurrency" unique_id=1036299287]
layout_mode = 2
text = "0"
script = ExtResource("2_a7k0t")
[node name="DebugIncomeButton" type="Button" parent="VBoxContainer/HBoxContainerCurrency" unique_id=780351266]
layout_mode = 2
text = "+100 Gold"
[node name="VBoxContainer2" type="VBoxContainer" parent="." unique_id=1163554471]
layout_mode = 0 layout_mode = 0
offset_left = 2.0 anchors_preset = 0
offset_top = 138.0 anchor_left = 0.0
offset_right = 266.0 anchor_top = 0.0
offset_bottom = 303.0 anchor_right = 0.0
anchor_bottom = 0.0
offset_left = 0.0
offset_top = 81.0
offset_right = 264.0
offset_bottom = 246.0
grow_horizontal = 1
grow_vertical = 1
[node name="Label" type="Label" parent="VBoxContainer2" unique_id=2116890422] [node name="GemsGeneratorContainer" parent="." unique_id=1519618562 instance=ExtResource("2_h2bxk")]
layout_mode = 2 layout_mode = 0
text = "Generator" anchors_preset = 0
anchor_left = 0.0
anchor_top = 0.0
anchor_right = 0.0
anchor_bottom = 0.0
offset_left = 0.0
offset_top = 246.0
offset_right = 264.0
offset_bottom = 411.0
grow_horizontal = 1
grow_vertical = 1
[node name="HBoxContainerGenerators" type="HBoxContainer" parent="VBoxContainer2" unique_id=1759912851] [editable path="GemsGeneratorContainer"]
layout_mode = 2
theme_override_constants/separation = 8
[node name="BuyOneButton" type="Button" parent="VBoxContainer2/HBoxContainerGenerators" unique_id=2126082317]
layout_mode = 2
text = "Buy x1"
script = ExtResource("1_h2bxk")
data = ExtResource("3_m5m0g")
[node name="BuyMaxButton" type="Button" parent="VBoxContainer2/HBoxContainerGenerators" unique_id=171532995]
layout_mode = 2
text = "Buy Max"
[node name="GeneratorStatsGrid" type="GridContainer" parent="VBoxContainer2" unique_id=88353659]
layout_mode = 2
columns = 2
[node name="OwnedTitle" type="Label" parent="VBoxContainer2/GeneratorStatsGrid" unique_id=1743705746]
layout_mode = 2
text = "Owned"
[node name="OwnedValue" type="Label" parent="VBoxContainer2/GeneratorStatsGrid" unique_id=890804662]
layout_mode = 2
text = "0"
[node name="NextCostTitle" type="Label" parent="VBoxContainer2/GeneratorStatsGrid" unique_id=990792129]
layout_mode = 2
text = "Next Cost"
[node name="NextCostValue" type="Label" parent="VBoxContainer2/GeneratorStatsGrid" unique_id=1296617914]
layout_mode = 2
text = "0"
[node name="ProductionTitle" type="Label" parent="VBoxContainer2/GeneratorStatsGrid" unique_id=698748759]
layout_mode = 2
text = "Production / sec"
[node name="ProductionValue" type="Label" parent="VBoxContainer2/GeneratorStatsGrid" unique_id=1059520776]
layout_mode = 2
text = "0"
[connection signal="pressed" from="VBoxContainer/HBoxContainerCurrency/DebugIncomeButton" to="." method="_on_debug_income_pressed"]
[connection signal="pressed" from="VBoxContainer2/HBoxContainerGenerators/BuyOneButton" to="VBoxContainer2/HBoxContainerGenerators/BuyOneButton" method="_on_pressed"]
[connection signal="pressed" from="VBoxContainer2/HBoxContainerGenerators/BuyMaxButton" to="." method="_on_buy_max_pressed"]

View File

@@ -1,9 +1,15 @@
class_name CurrencyLabel class_name CurrencyTile
extends Label extends HBoxContainer
@export var currency: GameState.CurrencyType @export var currency: GameState.CurrencyType
@export var data: CurrencyGeneratorData
@onready var _label: Label = $Label
@onready var _currency_label: Label = $CurrencyValueLabel
@onready var _debug_button: Button = $DebugIncomeButton
func _ready() -> void: func _ready() -> void:
_label.text = data.name
match currency: match currency:
GameState.CurrencyType.gold: GameState.CurrencyType.gold:
GameState.gold_changed.connect(_on_currency_changed) GameState.gold_changed.connect(_on_currency_changed)
@@ -11,6 +17,7 @@ func _ready() -> void:
GameState.gems_changed.connect(_on_currency_changed) GameState.gems_changed.connect(_on_currency_changed)
func _on_currency_changed(currency: BigNumber) -> void: func _on_currency_changed(currency: BigNumber) -> void:
text = currency.to_string_suffix(2) _currency_label.text = currency.to_string_suffix(2)
func _on_debug_income_button_pressed() -> void:
GameState.add_gold(BigNumber.from_float(100))

21
currency_tile.tscn Normal file
View File

@@ -0,0 +1,21 @@
[gd_scene format=3 uid="uid://btkxru2gdjsgc"]
[ext_resource type="Script" uid="uid://sp67wcb6s5nw" path="res://currency_label.gd" id="1_0hv07"]
[node name="CurrencyTile" type="HBoxContainer" unique_id=1440583137]
theme_override_constants/separation = 12
script = ExtResource("1_0hv07")
[node name="Label" type="Label" parent="." unique_id=89234840]
layout_mode = 2
text = "Gold:"
[node name="CurrencyValueLabel" type="Label" parent="." unique_id=1469960585]
layout_mode = 2
text = "0"
[node name="DebugIncomeButton" type="Button" parent="." unique_id=662695248]
layout_mode = 2
text = "+100 Gold"
[connection signal="pressed" from="DebugIncomeButton" to="." method="_on_debug_income_button_pressed"]

View File

@@ -6,6 +6,7 @@ extends Node
# ========================================== # ==========================================
signal gold_changed(new_amount: BigNumber) signal gold_changed(new_amount: BigNumber)
signal gems_changed(new_amount: BigNumber) signal gems_changed(new_amount: BigNumber)
signal generator_state_changed(generator_id: StringName, state: Dictionary)
enum CurrencyType { gold, gems } enum CurrencyType { gold, gems }
@@ -14,11 +15,17 @@ enum CurrencyType { gold, gems }
# ========================================== # ==========================================
var gold: BigNumber = BigNumber.from_float(0.0) var gold: BigNumber = BigNumber.from_float(0.0)
var gems: BigNumber = BigNumber.from_float(0.0) var gems: BigNumber = BigNumber.from_float(0.0)
var generator_states: Dictionary = {}
var last_save_time: int = 0 # Unix timestamp var last_save_time: int = 0 # Unix timestamp
static var file_name: String = "user://idle_save.json" static var file_name: String = "user://idle_save.json"
const GENERATOR_OWNED_KEY: String = "owned"
const GENERATOR_PURCHASED_COUNT_KEY: String = "purchased_count"
const GENERATOR_UNLOCKED_KEY: String = "unlocked"
const GENERATOR_AVAILABLE_KEY: String = "available"
func _ready() -> void: func _ready() -> void:
load_game() load_game()
@@ -49,6 +56,76 @@ func spend_gems(cost: BigNumber) -> bool:
return true return true
return false return false
func register_generator(generator_id: StringName, unlocked: bool = false, available: bool = false) -> void:
var key: String = String(generator_id)
if key.is_empty():
return
if generator_states.has(key):
var existing_raw: Variant = generator_states.get(key)
if existing_raw is Dictionary:
generator_states[key] = _sanitize_generator_state(existing_raw, unlocked, available)
return
var new_state: Dictionary = _default_generator_state(unlocked, available)
generator_states[key] = new_state
generator_state_changed.emit(StringName(key), new_state.duplicate(true))
func get_generator_state(generator_id: StringName) -> Dictionary:
return _get_generator_state(generator_id).duplicate(true)
func get_generator_owned(generator_id: StringName) -> int:
var state: Dictionary = _get_generator_state(generator_id)
return int(state.get(GENERATOR_OWNED_KEY, 0))
func set_generator_owned(generator_id: StringName, value: int) -> void:
var state: Dictionary = _get_generator_state(generator_id)
var next_owned: int = maxi(value, 0)
if int(state.get(GENERATOR_OWNED_KEY, 0)) == next_owned:
return
state[GENERATOR_OWNED_KEY] = next_owned
state[GENERATOR_PURCHASED_COUNT_KEY] = maxi(int(state.get(GENERATOR_PURCHASED_COUNT_KEY, 0)), next_owned)
_set_generator_state(generator_id, state)
func get_generator_purchased_count(generator_id: StringName) -> int:
var state: Dictionary = _get_generator_state(generator_id)
return int(state.get(GENERATOR_PURCHASED_COUNT_KEY, 0))
func set_generator_purchased_count(generator_id: StringName, value: int) -> void:
var state: Dictionary = _get_generator_state(generator_id)
var min_purchased: int = int(state.get(GENERATOR_OWNED_KEY, 0))
var next_purchased: int = maxi(value, min_purchased)
if int(state.get(GENERATOR_PURCHASED_COUNT_KEY, 0)) == next_purchased:
return
state[GENERATOR_PURCHASED_COUNT_KEY] = next_purchased
_set_generator_state(generator_id, state)
func is_generator_unlocked(generator_id: StringName) -> bool:
var state: Dictionary = _get_generator_state(generator_id)
return bool(state.get(GENERATOR_UNLOCKED_KEY, false))
func set_generator_unlocked(generator_id: StringName, value: bool) -> void:
var state: Dictionary = _get_generator_state(generator_id)
if bool(state.get(GENERATOR_UNLOCKED_KEY, false)) == value:
return
state[GENERATOR_UNLOCKED_KEY] = value
_set_generator_state(generator_id, state)
func is_generator_available(generator_id: StringName) -> bool:
var state: Dictionary = _get_generator_state(generator_id)
return bool(state.get(GENERATOR_AVAILABLE_KEY, false))
func set_generator_available(generator_id: StringName, value: bool) -> void:
var state: Dictionary = _get_generator_state(generator_id)
if bool(state.get(GENERATOR_AVAILABLE_KEY, false)) == value:
return
state[GENERATOR_AVAILABLE_KEY] = value
_set_generator_state(generator_id, state)
# ========================================== # ==========================================
# PERSISTENCE (Save/Load) # PERSISTENCE (Save/Load)
# ========================================== # ==========================================
@@ -56,6 +133,7 @@ func save_game() -> void:
var save_data = { var save_data = {
"gold": gold.serialize(), "gold": gold.serialize(),
"gems": gems.serialize(), "gems": gems.serialize(),
"generator_states": _serialize_generator_states(),
"last_save_time": Time.get_unix_time_from_system() "last_save_time": Time.get_unix_time_from_system()
} }
@@ -73,4 +151,123 @@ func load_game() -> void:
if parsed is Dictionary: if parsed is Dictionary:
gold = BigNumber.deserialize(parsed.get("gold", {})) gold = BigNumber.deserialize(parsed.get("gold", {}))
gems = BigNumber.deserialize(parsed.get("gems", {})) gems = BigNumber.deserialize(parsed.get("gems", {}))
generator_states = _deserialize_generator_states(parsed.get("generator_states", {}))
last_save_time = parsed.get("last_save_time", Time.get_unix_time_from_system()) last_save_time = parsed.get("last_save_time", Time.get_unix_time_from_system())
func _default_generator_state(unlocked: bool, available: bool) -> Dictionary:
return {
GENERATOR_OWNED_KEY: 0,
GENERATOR_PURCHASED_COUNT_KEY: 0,
GENERATOR_UNLOCKED_KEY: unlocked,
GENERATOR_AVAILABLE_KEY: available,
}
func _get_generator_state(generator_id: StringName) -> Dictionary:
var key: String = String(generator_id)
if key.is_empty():
return _default_generator_state(false, false)
if not generator_states.has(key):
register_generator(generator_id)
var existing_raw: Variant = generator_states.get(key, _default_generator_state(false, false))
if existing_raw is Dictionary:
var state: Dictionary = existing_raw
var sanitized: Dictionary = _sanitize_generator_state(state, false, false)
generator_states[key] = sanitized
return sanitized
var fallback: Dictionary = _default_generator_state(false, false)
generator_states[key] = fallback
return fallback
func _set_generator_state(generator_id: StringName, state: Dictionary) -> void:
var key: String = String(generator_id)
if key.is_empty():
return
var sanitized: Dictionary = _sanitize_generator_state(state, false, false)
generator_states[key] = sanitized
generator_state_changed.emit(StringName(key), sanitized.duplicate(true))
func _serialize_generator_states() -> Dictionary:
var result: Dictionary = {}
for key_variant in generator_states.keys():
var key: String = String(key_variant)
if key.is_empty():
continue
var value: Variant = generator_states.get(key_variant)
if value is Dictionary:
result[key] = _serialize_generator_state_entry(value)
return result
func _deserialize_generator_states(raw_value: Variant) -> Dictionary:
var result: Dictionary = {}
if not (raw_value is Dictionary):
return result
for key_variant in raw_value.keys():
var key: String = String(key_variant)
if key.is_empty():
continue
var entry: Variant = raw_value.get(key_variant)
if entry is Dictionary:
result[key] = _deserialize_generator_state_entry(entry)
return result
func _serialize_generator_state_entry(raw_state: Dictionary) -> Dictionary:
var owned_value: int = _to_non_negative_int(raw_state.get(GENERATOR_OWNED_KEY, 0), 0)
var purchased_value: int = _to_non_negative_int(raw_state.get(GENERATOR_PURCHASED_COUNT_KEY, owned_value), owned_value)
var serialized_state: Dictionary = {
GENERATOR_OWNED_KEY: owned_value,
GENERATOR_PURCHASED_COUNT_KEY: maxi(purchased_value, owned_value),
}
if raw_state.has(GENERATOR_UNLOCKED_KEY) and raw_state.get(GENERATOR_UNLOCKED_KEY) is bool:
serialized_state[GENERATOR_UNLOCKED_KEY] = raw_state.get(GENERATOR_UNLOCKED_KEY)
if raw_state.has(GENERATOR_AVAILABLE_KEY) and raw_state.get(GENERATOR_AVAILABLE_KEY) is bool:
serialized_state[GENERATOR_AVAILABLE_KEY] = raw_state.get(GENERATOR_AVAILABLE_KEY)
return serialized_state
func _deserialize_generator_state_entry(raw_state: Dictionary) -> Dictionary:
var owned_value: int = _to_non_negative_int(raw_state.get(GENERATOR_OWNED_KEY, 0), 0)
var purchased_value: int = _to_non_negative_int(raw_state.get(GENERATOR_PURCHASED_COUNT_KEY, owned_value), owned_value)
var parsed_state: Dictionary = {
GENERATOR_OWNED_KEY: owned_value,
GENERATOR_PURCHASED_COUNT_KEY: maxi(purchased_value, owned_value),
}
if raw_state.has(GENERATOR_UNLOCKED_KEY) and raw_state.get(GENERATOR_UNLOCKED_KEY) is bool:
parsed_state[GENERATOR_UNLOCKED_KEY] = raw_state.get(GENERATOR_UNLOCKED_KEY)
if raw_state.has(GENERATOR_AVAILABLE_KEY) and raw_state.get(GENERATOR_AVAILABLE_KEY) is bool:
parsed_state[GENERATOR_AVAILABLE_KEY] = raw_state.get(GENERATOR_AVAILABLE_KEY)
return parsed_state
func _sanitize_generator_state(raw_state: Dictionary, default_unlocked: bool, default_available: bool) -> Dictionary:
var owned_value: int = _to_non_negative_int(raw_state.get(GENERATOR_OWNED_KEY, 0), 0)
var purchased_value: int = _to_non_negative_int(raw_state.get(GENERATOR_PURCHASED_COUNT_KEY, owned_value), owned_value)
return {
GENERATOR_OWNED_KEY: owned_value,
GENERATOR_PURCHASED_COUNT_KEY: maxi(purchased_value, owned_value),
GENERATOR_UNLOCKED_KEY: _to_bool(raw_state.get(GENERATOR_UNLOCKED_KEY, default_unlocked), default_unlocked),
GENERATOR_AVAILABLE_KEY: _to_bool(raw_state.get(GENERATOR_AVAILABLE_KEY, default_available), default_available),
}
func _to_non_negative_int(value: Variant, fallback: int = 0) -> int:
if value is int:
return maxi(value, 0)
if value is float:
return maxi(int(value), 0)
return maxi(fallback, 0)
func _to_bool(value: Variant, fallback: bool) -> bool:
if value is bool:
return value
return fallback

View File

@@ -12,21 +12,59 @@ const HUGE_COST_EXPONENT: int = 1000000
@export var is_automatic: bool = true @export var is_automatic: bool = true
@export var press_buys_generator: bool = true @export var press_buys_generator: bool = true
@export var run_multiplier: float = 1.0 @export var run_multiplier: float = 1.0
@export var starts_unlocked: bool = true
@export var starts_available: bool = true
## Manual click fallback when no data is assigned. ## Manual click fallback when no data is assigned.
@export var click_mantissa: float = 1.0 @export var click_mantissa: float = 1.0
@export var click_exponent: int = 0 @export var click_exponent: int = 0
var owned: int = 0 var owned: int:
var purchased_count: int = 0 get:
_ensure_registered()
return GameState.get_generator_owned(_generator_id)
set(value):
_ensure_registered()
GameState.set_generator_owned(_generator_id, value)
var purchased_count: int:
get:
_ensure_registered()
return GameState.get_generator_purchased_count(_generator_id)
set(value):
_ensure_registered()
GameState.set_generator_purchased_count(_generator_id, value)
var is_unlocked: bool:
get:
_ensure_registered()
return GameState.is_generator_unlocked(_generator_id)
set(value):
_ensure_registered()
GameState.set_generator_unlocked(_generator_id, value)
var is_available: bool:
get:
_ensure_registered()
return GameState.is_generator_available(_generator_id)
set(value):
_ensure_registered()
GameState.set_generator_available(_generator_id, value)
var cycle_progress_seconds: float = 0.0 var cycle_progress_seconds: float = 0.0
var _generator_id: StringName = &""
var _is_registered: bool = false
func _ready() -> void: func _ready() -> void:
_generator_id = _resolve_generator_id()
_ensure_registered()
cycle_progress_seconds = 0.0 cycle_progress_seconds = 0.0
func _process(delta: float) -> void: func _process(delta: float) -> void:
if not is_automatic: if not is_automatic:
return return
if not is_available_to_player():
return
if data == null or owned <= 0: if data == null or owned <= 0:
return return
@@ -63,6 +101,9 @@ func get_cost_for_amount(amount: int = 1) -> BigNumber:
return _float_to_big_number(raw_cost) return _float_to_big_number(raw_cost)
func can_buy(amount: int = 1) -> bool: func can_buy(amount: int = 1) -> bool:
if not is_available_to_player():
return false
var cost: BigNumber = get_cost_for_amount(amount) var cost: BigNumber = get_cost_for_amount(amount)
var current: BigNumber = _get_currency_amount() var current: BigNumber = _get_currency_amount()
return current.is_greater_than(cost) or current.is_equal_to(cost) return current.is_greater_than(cost) or current.is_equal_to(cost)
@@ -70,6 +111,8 @@ func can_buy(amount: int = 1) -> bool:
func buy(amount: int = 1) -> bool: func buy(amount: int = 1) -> bool:
if data == null: if data == null:
return false return false
if not is_available_to_player():
return false
var safe_amount: int = maxi(amount, 1) var safe_amount: int = maxi(amount, 1)
var total_cost: BigNumber = get_cost_for_amount(safe_amount) var total_cost: BigNumber = get_cost_for_amount(safe_amount)
@@ -85,6 +128,8 @@ func buy(amount: int = 1) -> bool:
func buy_max() -> int: func buy_max() -> int:
if data == null: if data == null:
return 0 return 0
if not is_available_to_player():
return 0
var available_currency: float = _big_number_to_float(_get_currency_amount()) var available_currency: float = _big_number_to_float(_get_currency_amount())
var estimated_max: int = data.max_affordable(owned, available_currency) var estimated_max: int = data.max_affordable(owned, available_currency)
@@ -108,6 +153,9 @@ func buy_max() -> int:
return best if buy(best) else 0 return best if buy(best) else 0
func _on_pressed() -> void: func _on_pressed() -> void:
if not is_available_to_player():
return
if data != null and press_buys_generator: if data != null and press_buys_generator:
buy(1) buy(1)
return return
@@ -117,6 +165,13 @@ func _on_pressed() -> void:
func grant_currency(amount: BigNumber) -> void: func grant_currency(amount: BigNumber) -> void:
_add_currency(amount) _add_currency(amount)
func get_generator_id() -> StringName:
_ensure_registered()
return _generator_id
func is_available_to_player() -> bool:
return is_unlocked and is_available
func _add_currency(amount: BigNumber) -> void: func _add_currency(amount: BigNumber) -> void:
match currency: match currency:
GameState.CurrencyType.gold: GameState.CurrencyType.gold:
@@ -160,3 +215,36 @@ func _big_number_to_float(value: BigNumber) -> float:
if value.exponent < -308: if value.exponent < -308:
return 0.0 return 0.0
return value.mantissa * pow(10.0, float(value.exponent)) return value.mantissa * pow(10.0, float(value.exponent))
func _resolve_generator_id() -> StringName:
if data != null:
var data_id: String = String(data.id)
if not data_id.is_empty():
return StringName(data_id)
if not String(name).is_empty():
return StringName(String(name))
return &"generator"
func _ensure_registered() -> void:
if _is_registered:
return
if _generator_id == &"":
_generator_id = _resolve_generator_id()
if _generator_id == &"":
return
GameState.register_generator(_generator_id, _default_unlocked_state(), _default_available_state())
_is_registered = true
func _default_unlocked_state() -> bool:
if data != null:
return data.starts_unlocked
return starts_unlocked
func _default_available_state() -> bool:
if data != null:
return data.starts_available
return starts_available

View File

@@ -3,6 +3,8 @@ extends Resource
@export var id: StringName = &"" @export var id: StringName = &""
@export var name: String = "" @export var name: String = ""
@export var starts_unlocked: bool = true
@export var starts_available: bool = true
## Base cost and exponential growth (part I): cost_next = b * r^owned ## Base cost and exponential growth (part I): cost_next = b * r^owned
@export var initial_cost: float = 10.0 @export var initial_cost: float = 10.0

View File

@@ -0,0 +1,13 @@
[gd_resource type="Resource" script_class="CurrencyGeneratorData" format=3 uid="uid://04pmc034qupd"]
[ext_resource type="Script" uid="uid://b00tqsuhxdy0d" path="res://generator/currency_generator_data.gd" id="1_s3g28"]
[resource]
script = ExtResource("1_s3g28")
id = &"Gems"
name = "Gems Mine"
initial_cost = 60.0
initial_time = 3.0
initial_revenue = 60.0
initial_productivity = 20.0
metadata/_custom_type_script = "uid://b00tqsuhxdy0d"

66
generator_container.gd Normal file
View File

@@ -0,0 +1,66 @@
extends VBoxContainer
@export var _generator: CurrencyGenerator
@onready var _buy_button: Button = $HBoxContainerGenerators/BuyOneButton
@onready var _buy_max_button: Button = $HBoxContainerGenerators/BuyMaxButton
@onready var _name_label: Label = $Label
@onready var _owned_value: Label = $GeneratorStatsGrid/OwnedValue
@onready var _next_cost_value: Label = $GeneratorStatsGrid/NextCostValue
@onready var _production_value: Label = $GeneratorStatsGrid/ProductionValue
func _ready() -> void:
_generator.purchase_completed.connect(_on_generator_updated)
_generator.production_tick.connect(_on_generator_updated)
_generator.purchase_failed.connect(_on_generator_updated)
match _generator.currency:
GameState.CurrencyType.gold:
GameState.gold_changed.connect(_on_currency_changed)
GameState.CurrencyType.gems:
GameState.gems_changed.connect(_on_currency_changed)
GameState.generator_state_changed.connect(_on_generator_state_changed)
_name_label.text = _generator.data.name if _generator.data != null else "Generator"
_refresh_generator_ui()
func _on_buy_pressed() -> void:
_generator.buy(1)
_refresh_generator_ui()
func _on_buy_max_pressed() -> void:
_generator.buy_max()
_refresh_generator_ui()
func _on_debug_income_pressed() -> void:
_generator.grant_currency(BigNumber.from_float(100.0))
_refresh_generator_ui()
func _on_currency_changed(_new_value: BigNumber) -> void:
_refresh_generator_ui()
func _on_generator_updated(_a = null, _b = null, _c = null, _d = null) -> void:
_refresh_generator_ui()
func _on_generator_state_changed(generator_id: StringName, _state: Dictionary) -> void:
if generator_id == _generator.get_generator_id():
_refresh_generator_ui()
func _refresh_generator_ui() -> void:
var can_interact: bool = _generator.is_available_to_player()
_buy_button.disabled = not can_interact
_buy_max_button.disabled = not can_interact
_owned_value.text = str(_generator.owned)
_next_cost_value.text = _generator.get_next_cost().to_string_suffix(2) if can_interact else "-"
var production_per_second: float = 0.0
if _generator.data != null and can_interact:
production_per_second = _generator.data.production_per_second(
_generator.owned,
_generator.run_multiplier,
_generator.purchased_count
)
_production_value.text = BigNumber.from_float(production_per_second).to_string_suffix(2)

View File

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

64
generator_container.tscn Normal file
View File

@@ -0,0 +1,64 @@
[gd_scene format=3 uid="uid://ckos7f22pnmyh"]
[ext_resource type="Script" uid="uid://es14nqk6vrrk" path="res://generator_container.gd" id="1_8wouw"]
[node name="GeneratorContainer" type="VBoxContainer" unique_id=1129190041]
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -132.0
offset_top = -82.5
offset_right = 132.0
offset_bottom = 82.5
grow_horizontal = 2
grow_vertical = 2
script = ExtResource("1_8wouw")
[node name="Label" type="Label" parent="." unique_id=1867673612]
layout_mode = 2
text = "Generator"
[node name="HBoxContainerGenerators" type="HBoxContainer" parent="." unique_id=2033456807]
layout_mode = 2
theme_override_constants/separation = 8
[node name="BuyOneButton" type="Button" parent="HBoxContainerGenerators" unique_id=1171095139]
layout_mode = 2
text = "Buy x1"
[node name="BuyMaxButton" type="Button" parent="HBoxContainerGenerators" unique_id=871628534]
layout_mode = 2
text = "Buy Max"
[node name="GeneratorStatsGrid" type="GridContainer" parent="." unique_id=745078076]
layout_mode = 2
columns = 2
[node name="OwnedTitle" type="Label" parent="GeneratorStatsGrid" unique_id=891417119]
layout_mode = 2
text = "Owned"
[node name="OwnedValue" type="Label" parent="GeneratorStatsGrid" unique_id=549086894]
layout_mode = 2
text = "0"
[node name="NextCostTitle" type="Label" parent="GeneratorStatsGrid" unique_id=303459589]
layout_mode = 2
text = "Next Cost"
[node name="NextCostValue" type="Label" parent="GeneratorStatsGrid" unique_id=50480604]
layout_mode = 2
text = "0"
[node name="ProductionTitle" type="Label" parent="GeneratorStatsGrid" unique_id=2139535774]
layout_mode = 2
text = "Production / sec"
[node name="ProductionValue" type="Label" parent="GeneratorStatsGrid" unique_id=938669936]
layout_mode = 2
text = "0"
[connection signal="pressed" from="HBoxContainerGenerators/BuyOneButton" to="." method="_on_buy_pressed"]
[connection signal="pressed" from="HBoxContainerGenerators/BuyMaxButton" to="." method="_on_buy_max_pressed"]

53
generator_museum.tscn Normal file
View File

@@ -0,0 +1,53 @@
[gd_scene format=3 uid="uid://cfryecxmcg8hw"]
[ext_resource type="Script" uid="uid://dtbxopw6ulhl8" path="res://generator/currency_generator.gd" id="1_pl17p"]
[ext_resource type="Resource" uid="uid://co0mcc2kvcpo5" path="res://generator/primary_generator.tres" id="2_x5lt1"]
[ext_resource type="Resource" uid="uid://04pmc034qupd" path="res://generator/secondary_generator.tres" id="3_dc82g"]
[ext_resource type="PackedScene" uid="uid://ckos7f22pnmyh" path="res://generator_container.tscn" id="3_pw2a0"]
[ext_resource type="PackedScene" uid="uid://btkxru2gdjsgc" path="res://currency_tile.tscn" id="3_x5lt1"]
[node name="GeneratorMuseum" type="Node2D" unique_id=1219373683]
[node name="GoldGenerator" type="Node2D" parent="." unique_id=964187690]
script = ExtResource("1_pl17p")
data = ExtResource("2_x5lt1")
[node name="GemsGenerator" type="Node2D" parent="." unique_id=931294956]
script = ExtResource("1_pl17p")
data = ExtResource("3_dc82g")
[node name="UI" type="Control" parent="." unique_id=452530906]
layout_mode = 3
anchors_preset = 0
offset_right = 40.0
offset_bottom = 40.0
[node name="GoldCurrencyTile" parent="UI" unique_id=1440583137 instance=ExtResource("3_x5lt1")]
layout_mode = 0
offset_right = 160.0
offset_bottom = 31.0
data = ExtResource("2_x5lt1")
[node name="GemsCurrencyTile" parent="UI" unique_id=1977342362 instance=ExtResource("3_x5lt1")]
layout_mode = 0
offset_top = 28.0
offset_right = 160.0
offset_bottom = 59.0
currency = 1
data = ExtResource("3_dc82g")
[node name="GoldGeneratorContainer" parent="UI" unique_id=1129190041 node_paths=PackedStringArray("_generator") instance=ExtResource("3_pw2a0")]
layout_mode = 1
offset_left = -19.0
offset_top = 53.0
offset_right = 245.0
offset_bottom = 218.0
_generator = NodePath("../../GoldGenerator")
[node name="GemsGeneratorContainer" parent="UI" unique_id=1999544736 node_paths=PackedStringArray("_generator") instance=ExtResource("3_pw2a0")]
layout_mode = 1
offset_left = -17.0
offset_top = 215.0
offset_right = 247.0
offset_bottom = 380.0
_generator = NodePath("../../GemsGenerator")