commit bd11d2c037b645e4406c857a7bae7234e46f6f21 Author: Michele Rossi Date: Sun Mar 8 10:38:30 2026 +0100 First commit diff --git a/.agents/skills/developing-godot-gdscript/SKILL.md b/.agents/skills/developing-godot-gdscript/SKILL.md new file mode 100644 index 0000000..d954436 --- /dev/null +++ b/.agents/skills/developing-godot-gdscript/SKILL.md @@ -0,0 +1,60 @@ +--- +name: developing-godot-gdscript +description: Builds and refactors Godot 4 projects with idiomatic GDScript, scene composition, signals, and autoload patterns. Use when implementing gameplay, UI, tools, or architecture changes in Godot/GDScript repositories. +--- + +# Developing Godot With GDScript + +Implements production-friendly Godot 4 changes using typed GDScript, scene composition, and low-coupling architecture. + +## Use This Skill When + +- Adding or refactoring gameplay systems, UI flows, or content pipelines in Godot. +- Debugging node lifecycle, signals, resources, or autoload behavior. +- Improving maintainability, style consistency, or data flow in GDScript code. + +## Core Rules + +1. Prefer composition over deep inheritance: split reusable behavior into scenes/resources/scripts with focused responsibilities. +2. Choose scenes for reusable node trees and editor-authored structure; choose scripts/resources for logic and data that do not need node hierarchy. +3. Use autoloads only for truly global state/services (save systems, global config, cross-scene coordinators), not as default dependency injection. +4. Favor signals over direct cross-tree mutation to reduce coupling between gameplay, UI, and services. +5. Use typed GDScript where possible: annotate variables, params, and return types for safer refactors. + +## GDScript Implementation Checklist + +1. Keep naming idiomatic: `snake_case` for vars/functions/signals, `PascalCase` for `class_name`, `UPPER_SNAKE_CASE` for constants. +2. Use `@export` for editor-facing configuration and `@onready` only for scene-dependent node lookups. +3. Respect lifecycle intent: `_init` for construction data, `_enter_tree` for tree attachment concerns, `_ready` for node wiring, `_process`/`_physics_process` for frame loops. +4. Distinguish frame loops clearly: use `_physics_process` for deterministic physics movement and `_process` for visual or non-physics updates. +5. Use `match` for clear branching on enums/states and keep functions short with early returns. + +## Data, Loading, And Error Handling + +1. Guard all file access (`FileAccess.open`) and JSON parsing before indexing into parsed values. +2. Validate dynamic data types (`is Dictionary`, `is Array`) before field access to avoid runtime surprises. +3. Use `preload` for stable, frequently used compile-time resources; use `load` for optional or dynamic runtime assets. +4. Prefer `Resource`/`RefCounted` for plain data models when node features are unnecessary. +5. Use `assert`/`push_error` for invalid states that should fail loudly during development. + +## Delivery Workflow + +1. Read `project.godot` first to identify autoloads, rendering/physics settings, and project conventions. +2. Inspect relevant `.tscn` + `.gd` pairs together before editing to preserve scene-script contracts. +3. Implement minimal, targeted changes that keep public APIs/signals stable unless change is requested. +4. Run headless validation and script checks for touched scripts; run project smoke test when feasible. +5. Summarize changed files, behavior impact, and any follow-up risks. + +## Validation Commands + +Use project-provided commands when available. Typical Godot checks: + +```bash +"$GODOT_BIN" --headless --path . --quit +"$GODOT_BIN" --headless --check-only --script res://path/to/changed_script.gd +``` + +## References + +- https://docs.godotengine.org/en/stable/tutorials/best_practices/index.html +- https://docs.godotengine.org/en/stable/tutorials/scripting/gdscript/gdscript_basics.html diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..f28239b --- /dev/null +++ b/.editorconfig @@ -0,0 +1,4 @@ +root = true + +[*] +charset = utf-8 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..8ad74f7 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Normalize EOL for all files that Git considers text files. +* text=auto eol=lf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0af181c --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +# Godot 4+ specific ignores +.godot/ +/android/ diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..7db0bb7 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,22 @@ +# AGENTS.md +Godot 4.6 idle-game prototype; code is GDScript + `.tscn` scenes + JSON data at repo root. +## Build, Lint, And Test Commands +Use `GODOT_BIN` for your local editor binary (e.g. `godot`, `godot4`, or full path). +Run project: `"$GODOT_BIN" --path .` +Headless smoke/lint parse: `"$GODOT_BIN" --headless --path . --quit` +Script syntax check (single script): `"$GODOT_BIN" --headless --check-only --script res://big_number.gd` +Tests: no test framework is currently committed (`tests/` and `addons/gut` are absent). +Single-test command: N/A right now; if GUT is added, use `"$GODOT_BIN" --headless --path . -s res://addons/gut/gut_cmdln.gd -gtest=res://tests/.gd`. +## Architecture And Structure +`project.godot` defines autoload singletons: `GameState` (runtime currency state + save/load) and `CurrencyGeneratorDatabase` (loads `generator_data.json`). +`big_number.gd` (`class_name BigNumber`) is the internal numeric API for huge-value math, comparisons, formatting, and serialization. +`big_number_museum.tscn` + `big_number_museum.gd` is the current main playable scene/prototype UI. +`currency_generator.gd`, `currency_label.gd`, and `big_number_progress_bar.gd` are UI/gameplay adapters that react to `GameState` signals. +Persistence is local JSON only: `user://idle_save.json`; there is no external DB/server/backend. +## Code Style And Conventions +Prefer typed GDScript (`var x: Type`, `func f() -> void`) and keep shared models/components as `class_name` scripts. +Naming: `snake_case` for vars/functions/signals, `PascalCase` for classes, `UPPER_SNAKE_CASE` for constants. +Follow existing Godot style: tabs/consistent indentation, early returns, and short functions grouped by purpose. +When reading files/JSON, always guard `FileAccess.open(...)` and validate parsed types before indexing. +Use signals (already in `GameState`) for UI updates instead of polling or cross-node direct mutation. +No Cursor/Claude/Windsurf/Cline/Goose/Copilot rule files were found in this repository, so this file is the canonical agent guidance. diff --git a/big_number.gd b/big_number.gd new file mode 100644 index 0000000..499bb48 --- /dev/null +++ b/big_number.gd @@ -0,0 +1,227 @@ +class_name BigNumber +extends RefCounted + +## The core value representation. +## For example, 1.5e24 is represented as mantissa = 1.5, exponent = 24. +var mantissa: float +var exponent: int + +## Pre-calculate this to avoid dividing logs constantly +const LOG10_E: float = 0.4342944819032518 + +func _init(m: float = 0.0, e: int = 0) -> void: + mantissa = m + exponent = e + _normalize() + +## Adjusts the internal representation so the mantissa is always between 1.0 and 9.99... +## or exactly 0.0. +func _normalize() -> void: + if mantissa == 0.0: + exponent = 0 + return + + var is_negative: bool = mantissa < 0.0 + var abs_m: float = abs(mantissa) + + if abs_m >= 10.0 or abs_m < 1.0: + # Calculate how many powers of 10 we need to shift + # Godot's log() is base 'e', so we multiply by log10(e) to get log10(x) + var exp_diff: int = floori(log(abs_m) * LOG10_E) + abs_m /= pow(10.0, float(exp_diff)) + exponent += exp_diff + + mantissa = abs_m if not is_negative else -abs_m + +# ========================================== +# MATH OPERATIONS +# ========================================== + +func add(other: BigNumber) -> BigNumber: + if mantissa == 0: return BigNumber.new(other.mantissa, other.exponent) + if other.mantissa == 0: return BigNumber.new(mantissa, exponent) + + var exp_diff: int = exponent - other.exponent + + # If the difference in magnitude is massive, the smaller number is insignificant + # (15 is a safe threshold for 64-bit float precision). + if exp_diff >= 15: + return BigNumber.new(mantissa, exponent) + elif exp_diff <= -15: + return BigNumber.new(other.mantissa, other.exponent) + + var new_m: float = mantissa + var new_e: int = exponent + + # Scale the smaller number down to match the larger number's exponent + if exp_diff > 0: + new_m += other.mantissa / pow(10.0, float(exp_diff)) + elif exp_diff < 0: + new_m = (mantissa / pow(10.0, float(-exp_diff))) + other.mantissa + new_e = other.exponent + else: + new_m += other.mantissa + + return BigNumber.new(new_m, new_e) + +## High-performance addition for the _process() loop. +## Modifies THIS instance instead of creating a new RefCounted object. +func add_in_place(other: BigNumber) -> void: + if other.mantissa == 0.0: return + if mantissa == 0.0: + mantissa = other.mantissa + exponent = other.exponent + return + + var exp_diff: int = exponent - other.exponent + + if exp_diff >= 15: + return # Other number is too small to matter + elif exp_diff <= -15: + # This number is effectively replaced by the larger other number + mantissa = other.mantissa + exponent = other.exponent + return + + if exp_diff > 0: + mantissa += other.mantissa / pow(10.0, float(exp_diff)) + elif exp_diff < 0: + mantissa = (mantissa / pow(10.0, float(-exp_diff))) + other.mantissa + exponent = other.exponent + else: + mantissa += other.mantissa + + # Prevent floating-point drift near zero + if abs(mantissa) < 0.0000000001: + mantissa = 0.0 + exponent = 0 + else: + _normalize() + +func subtract(other: BigNumber) -> BigNumber: + # Subtraction is just adding a negative number + var negative_other = BigNumber.new(-other.mantissa, other.exponent) + return add(negative_other) + +func multiply(other: BigNumber) -> BigNumber: + var new_m: float = mantissa * other.mantissa + var new_e: int = exponent + other.exponent + return BigNumber.new(new_m, new_e) + +func divide(other: BigNumber) -> BigNumber: + if other.mantissa == 0.0: + push_error("BigNumber: Division by zero!") + return BigNumber.new(0.0, 0) + + var new_m: float = mantissa / other.mantissa + var new_e: int = exponent - other.exponent + return BigNumber.new(new_m, new_e) + +# ========================================== +# COMPARISONS +# ========================================== + +## Returns 1 if this > other, -1 if this < other, 0 if equal +func compare_to(other: BigNumber) -> int: + if mantissa == 0.0 and other.mantissa == 0.0: return 0 + + # Handle signs + if mantissa > 0 and other.mantissa <= 0: return 1 + if mantissa < 0 and other.mantissa >= 0: return -1 + + # Both are same sign. Compare exponents first. + var sign_mult: int = 1 if mantissa > 0 else -1 + + if exponent > other.exponent: return sign_mult + if exponent < other.exponent: return -sign_mult + + # Exponents are equal, compare mantissas + if mantissa > other.mantissa: return 1 + if mantissa < other.mantissa: return -1 + + return 0 + +func is_greater_than(other: BigNumber) -> bool: + return compare_to(other) == 1 + +func is_less_than(other: BigNumber) -> bool: + return compare_to(other) == -1 + +func is_equal_to(other: BigNumber) -> bool: + return compare_to(other) == 0 + +## Calculates the progress ratio between this number and a target number. +## Returns a standard float clamped between 0.0 and 1.0 for UI progress bars. +func get_ratio(target: BigNumber) -> float: + if target.mantissa == 0.0: + return 1.0 # If the goal is 0, you've already beaten it! + if mantissa == 0.0: + return 0.0 + + var exp_diff: int = exponent - target.exponent + + # If the target is massively larger, progress is practically 0% + if exp_diff <= -15: + return 0.0 + + # If current is equal or greater, progress is 100% + if exp_diff >= 15 or is_greater_than(target) or is_equal_to(target): + return 1.0 + + # Calculate the actual float ratio + var ratio: float = (mantissa / target.mantissa) * pow(10.0, float(exp_diff)) + + # Clamp it just to be perfectly safe for UI elements + return clampf(ratio, 0.0, 1.0) + +# ========================================== +# UTILITIES +# ========================================== + +## Creates a BigNumber from a standard float or int +static func from_float(val: float) -> BigNumber: + return BigNumber.new(val, 0) + +## Outputs a UI-friendly string (e.g., "1.50e12") +func to_string_sci(decimals: int = 2) -> String: + if exponent < 3: + # For small numbers, just show the regular number + var val: float = mantissa * pow(10.0, float(exponent)) + return ("%." + str(decimals) + "f") % val + + var format_str: String = "%." + str(decimals) + "f" + return (format_str % mantissa) + "e" + str(exponent) + +## Optional: Standard idle game suffix formatting (K, M, B, T, Qa, etc.) +func to_string_suffix(decimals: int = 2) -> String: + if exponent < 3: + return to_string_sci(decimals) + + var suffixes = ["", "K", "M", "B", "T", "Qa", "Qi", "Sx", "Sp", "Oc", "No", "Dc"] + var suffix_index: int = floori(exponent / 3.0) + + if suffix_index < suffixes.size(): + var display_mantissa = mantissa * pow(10.0, float(exponent % 3)) + var format_str: String = "%." + str(decimals) + "f" + return (format_str % display_mantissa) + suffixes[suffix_index] + else: + # Fall back to scientific if we run out of suffixes + return to_string_sci(decimals) + +# ========================================== +# SAVE & LOAD (SERIALIZATION) +# ========================================== + +## Converts the BigNumber into a basic Dictionary for easy JSON saving. +func serialize() -> Dictionary: + return { + "m": mantissa, + "e": exponent + } + +## A static factory method that creates a new BigNumber from loaded Dictionary data. +static func deserialize(data: Dictionary) -> BigNumber: + # Provide fallbacks (0.0 and 0) just in case the save file is corrupted + var loaded_m: float = data.get("m", 0.0) + var loaded_e: int = data.get("e", 0) + return BigNumber.new(loaded_m, loaded_e) diff --git a/big_number.gd.uid b/big_number.gd.uid new file mode 100644 index 0000000..0d098dd --- /dev/null +++ b/big_number.gd.uid @@ -0,0 +1 @@ +uid://be4in86mvsj0q diff --git a/big_number_museum.gd b/big_number_museum.gd new file mode 100644 index 0000000..66d9de5 --- /dev/null +++ b/big_number_museum.gd @@ -0,0 +1,10 @@ +extends Control + + +# Called when the node enters the scene tree for the first time. +func _ready() -> void: + pass + +# Called every frame. 'delta' is the elapsed time since the previous frame. +func _process(delta: float) -> void: + pass diff --git a/big_number_museum.gd.uid b/big_number_museum.gd.uid new file mode 100644 index 0000000..855bebe --- /dev/null +++ b/big_number_museum.gd.uid @@ -0,0 +1 @@ +uid://coasop1lyw5rh diff --git a/big_number_museum.tscn b/big_number_museum.tscn new file mode 100644 index 0000000..be39812 --- /dev/null +++ b/big_number_museum.tscn @@ -0,0 +1,43 @@ +[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="PackedScene" uid="uid://clu4rn1tl1s8t" path="res://big_number_progress_bar.tscn" id="1_lni8d"] +[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"] + +[node name="BigNumberMuseum" type="Control" unique_id=1249411984] +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_muwei") + +[node name="VBoxContainer" type="VBoxContainer" parent="." unique_id=1937517070] +layout_mode = 0 +offset_right = 264.0 +offset_bottom = 111.0 + +[node name="Label" type="Label" parent="VBoxContainer" unique_id=1357448839] +layout_mode = 2 +text = "Primary currency" + +[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer" unique_id=1592054467] +layout_mode = 2 +theme_override_constants/separation = 126 + +[node name="Button" type="Button" parent="VBoxContainer/HBoxContainer" unique_id=2126082317] +layout_mode = 2 +text = "Get Currency" +script = ExtResource("1_h2bxk") + +[node name="Label" type="Label" parent="VBoxContainer/HBoxContainer" unique_id=1036299287] +layout_mode = 2 +text = "000" +script = ExtResource("2_a7k0t") + +[node name="HBoxContainerAuto" parent="VBoxContainer" unique_id=1174903091 instance=ExtResource("1_lni8d")] +layout_mode = 2 + +[connection signal="pressed" from="VBoxContainer/HBoxContainer/Button" to="VBoxContainer/HBoxContainer/Button" method="_on_pressed"] diff --git a/big_number_progress_bar.gd b/big_number_progress_bar.gd new file mode 100644 index 0000000..76b1f1d --- /dev/null +++ b/big_number_progress_bar.gd @@ -0,0 +1,36 @@ +extends HBoxContainer + +@export var currency: GameState.CurrencyType + +@onready var _label_start = $LabelStart +@onready var _label_end = $LabelEnd +@onready var _progress_bar = $ProgressBar + +var _start: BigNumber +var _end: BigNumber +var _current: BigNumber + +func set_limits(start: BigNumber, end: BigNumber) -> void: + _start = start + _end = end + + _label_start.text = _start.to_string_suffix(2) + _label_end.text = _end.to_string_suffix(2) + + _progress_bar.min_value = _start.get_ratio(_end) + _progress_bar.max_value = _end.get_ratio(_start) + +func _ready() -> void: + match currency: + GameState.CurrencyType.gold: + GameState.gold_changed.connect(_on_currency_changed) + _current = GameState.gold + GameState.CurrencyType.gems: + GameState.gems_changed.connect(_on_currency_changed) + _current = GameState.gems + + set_limits(_current, _current.add(BigNumber.new(1, 1))) + +func _on_currency_changed(currency: BigNumber) -> void: + _current = currency + _progress_bar.value = currency.get_ratio(_end) diff --git a/big_number_progress_bar.gd.uid b/big_number_progress_bar.gd.uid new file mode 100644 index 0000000..5c512d7 --- /dev/null +++ b/big_number_progress_bar.gd.uid @@ -0,0 +1 @@ +uid://bom3jmnv0cvon diff --git a/big_number_progress_bar.tscn b/big_number_progress_bar.tscn new file mode 100644 index 0000000..e91d66a --- /dev/null +++ b/big_number_progress_bar.tscn @@ -0,0 +1,23 @@ +[gd_scene format=3 uid="uid://clu4rn1tl1s8t"] + +[ext_resource type="Script" uid="uid://bom3jmnv0cvon" path="res://big_number_progress_bar.gd" id="1_ssa4w"] + +[node name="HBoxContainer" type="HBoxContainer" unique_id=1174903091] +offset_right = 298.0 +offset_bottom = 49.0 +alignment = 1 +script = ExtResource("1_ssa4w") + +[node name="LabelStart" type="Label" parent="." unique_id=1661715778] +layout_mode = 2 +text = "100 +" + +[node name="ProgressBar" type="ProgressBar" parent="." unique_id=577927023] +custom_minimum_size = Vector2(200, 0) +layout_mode = 2 + +[node name="LabelEnd" type="Label" parent="." unique_id=440697928] +layout_mode = 2 +text = "100 +" diff --git a/currency_generator_database.gd b/currency_generator_database.gd new file mode 100644 index 0000000..f581247 --- /dev/null +++ b/currency_generator_database.gd @@ -0,0 +1,31 @@ +extends Node + +var items: Dictionary = {} + +func _ready(): + load_item_data() + +func load_item_data(): + # 1. Open the JSON file + var file = FileAccess.open("res://generator_data.json", FileAccess.READ) + var json_text = file.get_as_text() + + # 2. Parse it into a Godot Dictionary + var parsed_data = JSON.parse_string(json_text) + + # 3. Loop through and create Custom Resources + for key in parsed_data: + var data = CurrencyGeneratorData.new() + var item_info = parsed_data[key] + + # Populate the resource + data.id = key + data.name = key + data.initial_cost = item_info["initial_cost"] + data.coefficient = item_info["coefficient"] + data.initial_time = item_info["initial_time"] + data.initial_revenue = item_info["initial_revenue"] + data.initial_productivity = item_info["initial_productivity"] + + # Store it in our database dictionary + items[key] = data diff --git a/currency_generator_database.gd.uid b/currency_generator_database.gd.uid new file mode 100644 index 0000000..b2ca685 --- /dev/null +++ b/currency_generator_database.gd.uid @@ -0,0 +1 @@ +uid://cjuinqoug01v1 diff --git a/currency_label.gd b/currency_label.gd new file mode 100644 index 0000000..2cb67ea --- /dev/null +++ b/currency_label.gd @@ -0,0 +1,16 @@ +class_name CurrencyLabel +extends Label + +@export var currency: GameState.CurrencyType + +func _ready() -> void: + match currency: + GameState.CurrencyType.gold: + GameState.gold_changed.connect(_on_currency_changed) + GameState.CurrencyType.gems: + GameState.gems_changed.connect(_on_currency_changed) + +func _on_currency_changed(currency: BigNumber) -> void: + text = currency.to_string_sci(0) + + diff --git a/currency_label.gd.uid b/currency_label.gd.uid new file mode 100644 index 0000000..1535790 --- /dev/null +++ b/currency_label.gd.uid @@ -0,0 +1 @@ +uid://sp67wcb6s5nw diff --git a/game_state.gd b/game_state.gd new file mode 100644 index 0000000..22dbdc4 --- /dev/null +++ b/game_state.gd @@ -0,0 +1,76 @@ +extends Node +# This script is added as an Autoload named 'GameState' + +# ========================================== +# SIGNALS +# ========================================== +signal gold_changed(new_amount: BigNumber) +signal gems_changed(new_amount: BigNumber) + +enum CurrencyType { gold, gems } + +# ========================================== +# STATE VARIABLES +# ========================================== +var gold: BigNumber = BigNumber.from_float(0.0) +var gems: BigNumber = BigNumber.from_float(0.0) + +var last_save_time: int = 0 # Unix timestamp + +static var file_name: String = "user://idle_save.json" + +func _ready() -> void: + load_game() + +# ========================================== +# STATE MODIFIERS +# ========================================== +func add_gold(amount: BigNumber) -> void: + gold.add_in_place(amount) + gold_changed.emit(gold) + +func spend_gold(cost: BigNumber) -> bool: + if gold.is_greater_than(cost) or gold.is_equal_to(cost): + var negative_cost = BigNumber.new(-cost.mantissa, cost.exponent) + gold.add_in_place(negative_cost) + gold_changed.emit(gold) + return true + return false + +func add_gems(amount: BigNumber) -> void: + gems.add_in_place(amount) + gems_changed.emit(gems) + +func spend_gems(cost: BigNumber) -> bool: + if gems.is_greater_than(cost) or gems.is_equal_to(cost): + var negative_cost = BigNumber.new(-cost.mantissa, cost.exponent) + gems.add_in_place(negative_cost) + gems_changed.emit(gems) + return true + return false + +# ========================================== +# PERSISTENCE (Save/Load) +# ========================================== +func save_game() -> void: + var save_data = { + "gold": gold.serialize(), + "gems": gems.serialize(), + "last_save_time": Time.get_unix_time_from_system() + } + + var file = FileAccess.open(file_name, FileAccess.WRITE) + if file: + file.store_string(JSON.stringify(save_data)) + +func load_game() -> void: + if not FileAccess.file_exists(file_name): + return + + var file = FileAccess.open(file_name, FileAccess.READ) + if file: + var parsed = JSON.parse_string(file.get_as_text()) + if parsed is Dictionary: + gold = BigNumber.deserialize(parsed.get("gold", {})) + gems = BigNumber.deserialize(parsed.get("gems", {})) + last_save_time = parsed.get("last_save_time", Time.get_unix_time_from_system()) diff --git a/game_state.gd.uid b/game_state.gd.uid new file mode 100644 index 0000000..fdee5b0 --- /dev/null +++ b/game_state.gd.uid @@ -0,0 +1 @@ +uid://d2j7tvlgxr2jp diff --git a/generator/currency_generator.gd b/generator/currency_generator.gd new file mode 100644 index 0000000..b22392f --- /dev/null +++ b/generator/currency_generator.gd @@ -0,0 +1,20 @@ +class_name CurrencyGenerator +extends Node + +@export var currency: GameState.CurrencyType +@export var data: CurrencyGeneratorData + +# Called when the node enters the scene tree for the first time. +func _ready() -> void: + pass # Replace with function body. + +# Called every frame. 'delta' is the elapsed time since the previous frame. +func _process(delta: float) -> void: + pass + +func _on_pressed() -> void: + match currency: + GameState.CurrencyType.gold: GameState.add_gold(BigNumber.new(1, 0)) + GameState.CurrencyType.gems: GameState.add_gems(BigNumber.new(1, 0)) + _: print("c") + pass diff --git a/generator/currency_generator.gd.uid b/generator/currency_generator.gd.uid new file mode 100644 index 0000000..75950a0 --- /dev/null +++ b/generator/currency_generator.gd.uid @@ -0,0 +1 @@ +uid://dtbxopw6ulhl8 diff --git a/generator/currency_generator_data.gd b/generator/currency_generator_data.gd new file mode 100644 index 0000000..b2d052a --- /dev/null +++ b/generator/currency_generator_data.gd @@ -0,0 +1,18 @@ +class_name CurrencyGeneratorData +extends Resource + +@export var id: GameState.CurrencyType +@export var name: String +@export var initial_cost: float +@export var coefficient: float +@export var initial_time: float +@export var initial_revenue: float +@export var initial_productivity: float + +## Returns cost of next generator +func cost_next(owned: int) -> float: + return initial_cost * pow(coefficient, owned) + +## Returns value produced +func production_total(owned: int, multipliers: float) -> float: + return (initial_productivity * owned) * multipliers diff --git a/generator/currency_generator_data.gd.uid b/generator/currency_generator_data.gd.uid new file mode 100644 index 0000000..74dfb56 --- /dev/null +++ b/generator/currency_generator_data.gd.uid @@ -0,0 +1 @@ +uid://b00tqsuhxdy0d diff --git a/generator_data.json b/generator_data.json new file mode 100644 index 0000000..36f8530 --- /dev/null +++ b/generator_data.json @@ -0,0 +1,37 @@ +{ + "generator_1": { + "initial_cost": 10, + "coefficient": 1.15, + "initial_time": 0.6, + "initial_revenue": 1.0, + "initial_productivity": 1.67 + }, + "generator_2": { + "initial_cost": 60.0, + "coefficient": 1.15, + "initial_time": 3.0, + "initial_revenue": 60.0, + "initial_productivity": 20.0 + }, + "generator_3": { + "initial_cost": 720.0, + "coefficient": 1.14, + "initial_time": 6.0, + "initial_revenue": 540.0, + "initial_productivity": 90.0 + }, + "generator_4": { + "initial_cost": 8640.0, + "coefficient": 1.13, + "initial_time": 12.0, + "initial_revenue": 4320.0, + "initial_productivity": 360.0 + }, + "generator_5": { + "initial_cost": 103680.0, + "coefficient": 1.12, + "initial_time": 24.0, + "initial_revenue": 51840.0, + "initial_productivity": 2160.0 + } +} diff --git a/icon.svg b/icon.svg new file mode 100644 index 0000000..c6bbb7d --- /dev/null +++ b/icon.svg @@ -0,0 +1 @@ + diff --git a/icon.svg.import b/icon.svg.import new file mode 100644 index 0000000..159893b --- /dev/null +++ b/icon.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bgtt3wu43tajh" +path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://icon.svg" +dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/project.godot b/project.godot new file mode 100644 index 0000000..2c6d2aa --- /dev/null +++ b/project.godot @@ -0,0 +1,27 @@ +; Engine configuration file. +; It's best edited using the editor UI and not directly, +; since the parameters that go here are not all obvious. +; +; Format: +; [section] ; section goes between [] +; param=value ; assign values to parameters + +config_version=5 + +[application] + +config/name="Idles" +config/features=PackedStringArray("4.6", "Forward Plus") +config/icon="res://icon.svg" + +[autoload] + +GameState="*uid://d2j7tvlgxr2jp" + +[physics] + +3d/physics_engine="Jolt Physics" + +[rendering] + +rendering_device/driver.windows="d3d12"