Fix alchemy tower

This commit is contained in:
2026-04-23 12:46:01 +02:00
parent a10f2f02d7
commit 0064e61389
35 changed files with 792 additions and 19 deletions

View File

@@ -24,3 +24,4 @@ When reading files/JSON, always guard `FileAccess.open(...)` and validate parsed
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.
Avoid trivial one-line wrapper/helper functions that only forward or repack data. Inline the logic at the real call site unless the wrapper adds meaningful abstraction or is reused enough to justify it.
Resource type safety: Use the specific resource. Avoid as much as possible explicit `Resource` usage.

View File

@@ -150,7 +150,7 @@ func _ready() -> void:
# CURRENCY API
# ==============================================================================
## Returns the normalized ID from a Currency resource.
func get_currency_id(currency: Resource) -> StringName:
func get_currency_id(currency: Currency) -> StringName:
return _normalize_currency_id(currency.id if currency else &"")
## Parses and normalizes a currency ID from raw input (handles special cases like "gem" -> "gems").
@@ -193,7 +193,7 @@ func get_currency_icon(currency_id: StringName) -> Texture2D:
return null
## Adds currency from a Currency resource. Emits [signal currency_changed] on success.
func add_currency(currency: Resource, amount: BigNumber) -> void:
func add_currency(currency: Currency, 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.")
@@ -201,7 +201,7 @@ func add_currency(currency: Resource, amount: BigNumber) -> void:
add_currency_by_id(currency_id, amount)
## Spends currency from a Currency resource. Returns false if insufficient funds.
func spend_currency(currency: Resource, cost: BigNumber) -> bool:
func spend_currency(currency: Currency, cost: BigNumber) -> bool:
var currency_id: StringName = get_currency_id(currency)
if currency_id == &"":
push_warning("Attempted to spend currency with an invalid Currency resource.")
@@ -237,7 +237,7 @@ func spend_currency_by_id(currency_id: StringName, cost: BigNumber) -> bool:
return false
## Returns the current balance for a Currency resource.
func get_currency_amount(currency: Resource) -> BigNumber:
func get_currency_amount(currency: Currency) -> BigNumber:
return get_currency_amount_by_id(get_currency_id(currency))
## Returns the current balance for a currency ID.
@@ -245,7 +245,7 @@ func get_currency_amount_by_id(currency_id: StringName) -> BigNumber:
return _get_current_currency_ref(currency_id)
## Returns the total acquired this run for a Currency resource.
func get_total_currency_acquired(currency: Resource) -> BigNumber:
func get_total_currency_acquired(currency: Currency) -> BigNumber:
return get_total_currency_acquired_by_id(get_currency_id(currency))
## Returns the total acquired this run for a currency ID (resets on prestige).
@@ -253,7 +253,7 @@ func get_total_currency_acquired_by_id(currency_id: StringName) -> BigNumber:
return _get_total_currency_ref(currency_id)
## Returns the all-time total for a Currency resource.
func get_all_time_currency_acquired(currency: Resource) -> BigNumber:
func get_all_time_currency_acquired(currency: Currency) -> BigNumber:
return get_all_time_currency_acquired_by_id(get_currency_id(currency))
## Returns the all-time total for a currency ID (never resets).

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

View File

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cieg8i3c8hca6"
path="res://.godot/imported/Tower.png-89ae300c234cff5100d7ac69a9b9290c.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://docs/gyms/tiny_sword/buildings/alchemy_tower/Tower.png"
dest_files=["res://.godot/imported/Tower.png-89ae300c234cff5100d7ac69a9b9290c.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

View File

@@ -0,0 +1,81 @@
class_name AlchemyCraftableTile
extends HBoxContainer
signal craft_button_pressed(recipe: Variant)
@onready var _name_label: Label = $NameLabel
@onready var _balance_label: Label = $BalanceLabel
@onready var _cost_label: Label = $CostLabel
@onready var _button: Button = $Button
var _recipe: Variant
var _game_state: LevelGameState
var _initialized: bool = false
func _ready() -> void:
_game_state = find_parent("LevelGameState")
_game_state.ready.connect(_on_game_state_ready)
if not _button.pressed.is_connected(_on_button_pressed):
_button.pressed.connect(_on_button_pressed)
_initialized = true
func setup(recipe: AlchemyCraftRecipe) -> void:
_recipe = recipe
func _on_game_state_ready() -> void:
# Validate labels before use
if _name_label == null:
push_error("AlchemyCraftableTile: _name_label is null in setup")
return
# Set up display
_name_label.text = str(_recipe.output_currency.display_name) if _recipe.output_currency else "Unknown"
_update_cost_display()
# Connect to currency changes for balance updates
if _game_state != null:
_game_state.currency_changed.connect(_on_currency_changed)
# Initial balance update
_update_balance()
func _update_cost_display() -> void:
if _cost_label == null or _recipe == null:
return
if _recipe.cost_entries.is_empty():
_cost_label.text = "No cost"
return
var cost_text: String = ""
for entry in _recipe.cost_entries:
if entry == null:
continue
if not cost_text.is_empty():
cost_text += " + "
cost_text += "%d %s" % [entry.amount, entry.currency.display_name]
_cost_label.text = cost_text
func _update_balance() -> void:
if _balance_label == null or _recipe == null or _game_state == null:
return
var balance: BigNumber = _game_state.get_currency_amount(_recipe.output_currency)
_balance_label.text = balance.to_string_suffix(0)
func _on_button_pressed() -> void:
if _recipe == null:
push_warning("AlchemyCraftableTile: No recipe configured")
return
craft_button_pressed.emit(_recipe)
func _on_currency_changed(currency_id: StringName, _amount: BigNumber) -> void:
# Update balance if this currency changed
if _recipe != null:
var output_currency_id: StringName = _recipe.output_currency.id if _recipe.output_currency else &""
if currency_id == output_currency_id:
_update_balance()

View File

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

View File

@@ -0,0 +1,31 @@
[gd_scene format=3 uid="uid://cxusq0tunvjlb"]
[ext_resource type="Script" uid="uid://c63g772y4kxwm" path="res://docs/gyms/tiny_sword/buildings/alchemy_tower/alchemy_craftable_panel_tile.gd" id="1_hw1b0"]
[node name="AlchemyCraftableTile" type="HBoxContainer" unique_id=1715275035]
offset_left = 10.0
offset_top = 10.0
offset_right = 280.0
offset_bottom = 41.0
script = ExtResource("1_hw1b0")
[node name="NameLabel" type="Label" parent="." unique_id=2031343677]
layout_mode = 2
size_flags_horizontal = 8
text = "Currency"
[node name="BalanceLabel" type="Label" parent="." unique_id=1367089480]
layout_mode = 2
size_flags_horizontal = 8
text = "0"
[node name="CostLabel" type="Label" parent="." unique_id=1649255694]
layout_mode = 2
size_flags_horizontal = 8
text = "10 Magic Gold"
[node name="Button" type="Button" parent="." unique_id=1649255693]
layout_mode = 2
text = "Craft"
[connection signal="pressed" from="Button" to="." method="_on_button_pressed"]

View File

@@ -0,0 +1,161 @@
class_name AlchemyCurrenciesPanel
extends PanelContainer
signal craft_requested(recipe: Variant)
signal alchemy_workers_changed(count: int)
# Currency used to pay crafts (magic gold)
@export var currency: Currency
# The list of crafts available to alchemy tower
@export var craft_recipes: AlchemyCraftCatalogue
@onready var _tile_scene: PackedScene = preload("res://docs/gyms/tiny_sword/buildings/alchemy_tower/alchemy_craftable_panel_tile.tscn")
@onready var _craft_list: VBoxContainer = $VBoxContainer/CraftList
@onready var _currency_name_label: Label = $VBoxContainer/HBoxCurrency/NameLabel
@onready var _progress_bar: ProgressBar = $VBoxContainer/HBoxCurrency/ProgressBar
@onready var _balance_label: Label = $VBoxContainer/HBoxCurrency/AmountLabel
@onready var _worker_label: Label = $VBoxContainer/HBoxWorker/WorkerLabel
@onready var _assign_button: Button = $VBoxContainer/HBoxWorker/AssignButton
var _alchemy_tower: AlchemyTower
var _game_state: LevelGameState
var _alchemy_worker_count: int = 0
func _ready() -> void:
assert(craft_recipes != null, "Craft recipes cannot be null")
_game_state = find_parent("LevelGameState")
if _game_state == null:
push_error("AlchemyCurrenciesPanel: Could not find LevelGameState")
return
# Find AlchemyTower in parent
_alchemy_tower = _find_alchemy_tower()
# Set up UI labels
_currency_name_label.text = currency.display_name if currency else "Magic Gold"
# Connect to tower signals
if _alchemy_tower:
_alchemy_tower.production_progress_updated.connect(_on_production_progress)
_alchemy_tower.magic_gold_balance_updated.connect(_on_magic_gold_changed)
_alchemy_tower.production_completed.connect(_on_production_completed)
# Connect worker button
if _assign_button:
_assign_button.pressed.connect(_on_assign_button_pressed)
# Initialize displays
_update_magic_gold_display()
_update_production_progress(0.0)
_update_worker_display()
# Connect to worker currency changes
_game_state.currency_changed.connect(_on_currency_changed)
# Clear and populate craft tiles
for child in _craft_list.get_children():
child.queue_free()
for recipe in craft_recipes.recipes:
var instance: AlchemyCraftableTile = _tile_scene.instantiate() as AlchemyCraftableTile
instance.setup(recipe)
instance.craft_button_pressed.connect(_on_craft_button_pressed)
_craft_list.add_child(instance)
func _find_alchemy_tower() -> AlchemyTower:
var parent: Node = get_parent()
while parent != null:
if parent is AlchemyTower:
return parent as AlchemyTower
parent = parent.get_parent()
return null
func _update_magic_gold_display() -> void:
if _alchemy_tower == null or _game_state == null:
return
var magic_gold_currency: Currency = _get_magic_gold_currency()
if magic_gold_currency == null:
_balance_label.text = "0"
return
var balance: BigNumber = _game_state.get_currency_amount(magic_gold_currency)
_balance_label.text = balance.to_string_suffix(2)
func _update_production_progress(progress: float) -> void:
if _progress_bar == null:
return
_progress_bar.value = progress * 100.0
func _update_worker_display() -> void:
if _worker_label == null:
return
_worker_label.text = "Alchemy Workers: %d" % _alchemy_worker_count
if _assign_button != null:
var worker_currency: Currency = _get_worker_currency()
var can_assign: bool = false
if worker_currency != null and _alchemy_worker_count < 10:
var worker_balance: BigNumber = _game_state.get_currency_amount(worker_currency)
can_assign = worker_balance.mantissa >= 1.0
_assign_button.disabled = not can_assign
_assign_button.text = "Assign Worker" if can_assign else "No Workers Available"
func _get_magic_gold_currency() -> Currency:
if _game_state == null or _game_state.currency_catalogue == null:
return null
for currency in _game_state.currency_catalogue.currencies:
if currency == null:
continue
if currency.id == &"magic_gold":
return currency
return null
func _get_worker_currency() -> Currency:
if _game_state == null or _game_state.currency_catalogue == null:
return null
for currency in _game_state.currency_catalogue.currencies:
if currency == null:
continue
if currency.id == &"worker":
return currency
return null
func _on_production_progress(progress: float) -> void:
_update_production_progress(progress)
func _on_magic_gold_changed(amount: BigNumber) -> void:
_update_magic_gold_display()
_update_worker_display()
func _on_production_completed(_amount: BigNumber) -> void:
_update_magic_gold_display()
func _on_currency_changed(currency_id: StringName, _amount: BigNumber) -> void:
if currency_id == &"worker":
_update_worker_display()
func _on_assign_button_pressed() -> void:
if _alchemy_tower == null or _game_state == null:
return
var worker_currency: Currency = _get_worker_currency()
if worker_currency == null:
return
# Spend a worker
if _game_state.spend_currency(worker_currency, BigNumber.from_float(1.0)):
_alchemy_worker_count += 1
_update_worker_display()
alchemy_workers_changed.emit(_alchemy_worker_count)
func _on_craft_button_pressed(recipe: Variant) -> void:
craft_requested.emit(recipe)

View File

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

View File

@@ -0,0 +1,40 @@
[gd_scene format=3 uid="uid://cbp6vpth8x4rw"]
[ext_resource type="Script" uid="uid://do1i3hrd0ueb6" path="res://docs/gyms/tiny_sword/buildings/alchemy_tower/alchemy_currencies_panel.gd" id="1_script"]
[node name="AlchemyCurrenciesPanel" type="PanelContainer" unique_id=1000001]
custom_minimum_size = Vector2(400, 300)
script = ExtResource("1_script")
[node name="VBoxContainer" type="VBoxContainer" parent="." unique_id=1115194594]
layout_mode = 2
[node name="HBoxWorker" type="HBoxContainer" parent="VBoxContainer" unique_id=1415354976]
layout_mode = 2
[node name="WorkerLabel" type="Label" parent="VBoxContainer/HBoxWorker" unique_id=4000008]
layout_mode = 2
text = "Alchemy Workers: 0"
[node name="AssignButton" type="Button" parent="VBoxContainer/HBoxWorker" unique_id=4000009]
layout_mode = 2
text = "Assign Worker"
[node name="HBoxCurrency" type="HBoxContainer" parent="VBoxContainer" unique_id=1815331819]
layout_mode = 2
[node name="NameLabel" type="Label" parent="VBoxContainer/HBoxCurrency" unique_id=4000005]
layout_mode = 2
text = "Magic Gold"
[node name="ProgressBar" type="ProgressBar" parent="VBoxContainer/HBoxCurrency" unique_id=4000006]
custom_minimum_size = Vector2(200, 0)
layout_mode = 2
[node name="AmountLabel" type="Label" parent="VBoxContainer/HBoxCurrency" unique_id=4000007]
layout_mode = 2
text = "0"
[node name="CraftList" type="VBoxContainer" parent="VBoxContainer" unique_id=3000005]
layout_mode = 2
size_flags_vertical = 8

View File

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

View File

@@ -0,0 +1,196 @@
class_name AlchemyTower
extends Node2D
## Emitted when production progress changes (0.0 to 1.0)
signal production_progress_updated(progress: float)
## Emitted when magic gold balance changes
signal magic_gold_balance_updated(amount: BigNumber)
## Emitted when a production cycle completes
signal production_completed(amount: BigNumber)
## Configuration data for this tower
@export var data: AlchemyTowerData
## Available craft recipes
@export var craft_recipes: AlchemyCraftCatalogue
## Reference to game state
@onready var game_state: LevelGameState = find_parent("LevelGameState")
## Current production state
var production_time_elapsed: float = 0.0
var current_production_time: float
var cycle_count: int = 0
## Number of workers assigned to this tower
var _worker_count: int = 0
## UI panel reference
@onready var alchemy_panel: AlchemyCurrenciesPanel = $AlchemyCurrenciesPanel
func _ready() -> void:
assert(data != null, "AlchemyTowerData is required")
assert(craft_recipes != null, "Craft recipes catalogue is required")
assert(game_state != null, "LevelGameState is required")
# Initialize production time
current_production_time = data.base_production_time_seconds
# Register this tower as an available generator
game_state.set_generator_available(get_generator_id(), true)
# Connect to magic gold balance changes
game_state.currency_changed.connect(_on_currency_changed)
# Connect panel signals if available
if alchemy_panel:
alchemy_panel.craft_requested.connect(_on_craft_requested)
alchemy_panel.alchemy_workers_changed.connect(_on_alchemy_workers_changed)
# Initial progress update
production_progress_updated.emit(0.0)
func _process(delta: float) -> void:
if not _is_production_active():
return
var speed_multiplier: float = _get_worker_speed_multiplier()
# Add elapsed time scaled by worker count
production_time_elapsed += delta * speed_multiplier
# Update progress bar every frame
production_progress_updated.emit(_get_production_progress())
# Check if production is complete
if production_time_elapsed >= current_production_time:
_try_complete_production()
func _is_production_active() -> bool:
if not game_state.is_generator_available(get_generator_id()):
return false
return _get_worker_count() > 0
func _try_complete_production() -> void:
# Calculate how many cycles completed
var completed_cycles: int = floori(production_time_elapsed / current_production_time)
if completed_cycles <= 0:
return
# Reset elapsed time
production_time_elapsed -= current_production_time * float(completed_cycles)
# Calculate output
var output_per_cycle: BigNumber = BigNumber.from_float(data.magic_gold_per_cycle)
var total_output: BigNumber = output_per_cycle.multiply(BigNumber.from_float(float(completed_cycles)))
# Apply worker speed bonus (affects output, not time)
var worker_multiplier: float = _get_worker_speed_multiplier()
if worker_multiplier > 1.0:
total_output = total_output.multiply(BigNumber.from_float(worker_multiplier))
# Add magic gold
_add_magic_gold(total_output)
# Increment cycle count
cycle_count += completed_cycles
# Increase production time (mild exponential growth)
current_production_time *= pow(data.production_time_growth_multiplier, float(completed_cycles))
# Emit signals
production_completed.emit(total_output)
production_progress_updated.emit(_get_production_progress())
func _add_magic_gold(amount: BigNumber) -> void:
if data == null or game_state == null:
return
var magic_gold_currency: Currency = _get_magic_gold_currency()
if magic_gold_currency == null:
push_error("AlchemyTower: Could not find magic gold currency")
return
game_state.add_currency(magic_gold_currency, amount)
func _get_magic_gold_currency() -> Currency:
# Find magic gold in the currency catalogue
if game_state == null or game_state.currency_catalogue == null:
return null
for currency in game_state.currency_catalogue.currencies:
if currency == null:
continue
if currency.id == &"magic_gold":
return currency
return null
func _get_worker_count() -> int:
return mini(_worker_count, data.max_workers)
func _get_worker_speed_multiplier() -> float:
if game_state == null:
return 1.0
var worker_count: int = _get_worker_count()
var multiplier: float = 1.0 + (float(worker_count) * data.base_worker_speed_bonus)
return multiplier
func _get_worker_currency() -> Currency:
if game_state == null or game_state.currency_catalogue == null:
return null
for currency in game_state.currency_catalogue.currencies:
if currency == null:
continue
if currency.id == &"worker":
return currency
return null
func _get_production_progress() -> float:
if current_production_time <= 0.0:
return 1.0
var progress: float = production_time_elapsed / current_production_time
return clampf(progress, 0.0, 1.0)
func get_generator_id() -> StringName:
return data.id
func craft_item(recipe: Variant) -> bool:
if recipe == null:
return false
# Check and pay all costs
for entry in recipe.cost_entries:
if entry == null or entry.currency == null:
continue
if not game_state.spend_currency(entry.currency, BigNumber.from_float(float(entry.amount))):
return false
# Success - add output
game_state.add_currency(recipe.output_currency, BigNumber.from_float(float(recipe.output_amount)))
return true
func _on_currency_changed(currency_id: StringName, _amount: BigNumber) -> void:
if currency_id == &"magic_gold":
magic_gold_balance_updated.emit(_amount)
func _on_alchemy_workers_changed(count: int) -> void:
_worker_count = count
production_progress_updated.emit(_get_production_progress())
func _on_craft_requested(recipe: Variant) -> void:
if recipe == null:
return
var success: bool = craft_item(recipe)
if not success:
push_warning("AlchemyTower: Failed to craft %s - insufficient funds" % recipe.output_currency.display_name)

View File

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

View File

@@ -0,0 +1,33 @@
[gd_scene format=3 uid="uid://bp5ng4vu4ot4a"]
[ext_resource type="Texture2D" uid="uid://cieg8i3c8hca6" path="res://docs/gyms/tiny_sword/buildings/alchemy_tower/Tower.png" id="1_vbhae"]
[ext_resource type="PackedScene" uid="uid://cbp6vpth8x4rw" path="res://docs/gyms/tiny_sword/buildings/alchemy_tower/alchemy_currencies_panel.tscn" id="2_8pntr"]
[ext_resource type="Script" uid="uid://bddaaj76msmvj" path="res://docs/gyms/tiny_sword/buildings/alchemy_tower/alchemy_tower.gd" id="3_tower"]
[ext_resource type="Resource" path="res://docs/gyms/tiny_sword/buildings/alchemy_tower/alchemy_tower_data.tres" id="4_data"]
[ext_resource type="Resource" uid="uid://diboykfbbxpfs" path="res://docs/gyms/tiny_sword/buildings/alchemy_tower/recipes/alchemy_craft_catalogue.tres" id="5_recipes"]
[ext_resource type="Resource" uid="uid://dpbndqxvsffa0" path="res://docs/gyms/tiny_sword/currencies/magic_gold.tres" id="7_b8p5n"]
[sub_resource type="RectangleShape2D" id="RectangleShape2D_8pntr"]
size = Vector2(109, 182)
[node name="AlchemyTower" type="Node2D" unique_id=51852160]
script = ExtResource("3_tower")
data = ExtResource("4_data")
craft_recipes = ExtResource("5_recipes")
[node name="Sprite2D" type="Sprite2D" parent="." unique_id=1160485854]
texture = ExtResource("1_vbhae")
[node name="Area2D" type="Area2D" parent="." unique_id=911128362]
[node name="CollisionShape2D" type="CollisionShape2D" parent="Area2D" unique_id=1059910507]
position = Vector2(0.5, 11)
shape = SubResource("RectangleShape2D_8pntr")
[node name="AlchemyCurrenciesPanel" parent="." unique_id=731368154 instance=ExtResource("2_8pntr")]
offset_left = 65.0
offset_top = -75.0
offset_right = 65.0
offset_bottom = -75.0
currency = ExtResource("7_b8p5n")
craft_recipes = ExtResource("5_recipes")

View File

@@ -0,0 +1,23 @@
class_name AlchemyTowerData
extends Resource
@export_group("Identification")
@export var id: StringName = &"alchemy_tower"
@export var name: String = "Alchemy Tower"
@export_group("Production")
## Base time to produce one magic gold (first production)
@export var base_production_time_seconds: float = 5.0
## Multiplier applied to production time each cycle (1.2 = 20% increase)
@export var production_time_growth_multiplier: float = 1.2
## Amount of magic gold produced per cycle
@export var magic_gold_per_cycle: float = 1.0
@export_group("Workers")
## Speed bonus per alchemy worker (0.1 = +10% speed per worker)
@export var base_worker_speed_bonus: float = 0.1
## Maximum workers that can be assigned
@export var max_workers: int = 10

View File

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

View File

@@ -0,0 +1,14 @@
[gd_resource type="Resource" script_class="AlchemyTowerData" format=3 uid="uid://alchemy_tower_data"]
[ext_resource type="Script" path="res://docs/gyms/tiny_sword/buildings/alchemy_tower/alchemy_tower_data.gd" id="1_data"]
[resource]
script = ExtResource("1_data")
id = &"alchemy_tower"
name = "Alchemy Tower"
base_production_time_seconds = 5.0
production_time_growth_multiplier = 1.2
magic_gold_per_cycle = 1.0
base_worker_speed_bonus = 0.1
max_workers = 10
metadata/_custom_type_script = "res://docs/gyms/tiny_sword/buildings/alchemy_tower/alchemy_tower_data.gd"

View File

@@ -0,0 +1,18 @@
class_name AlchemyCraftCatalogue
extends Resource
## Catalogue of alchemy craft recipes
@export var recipes: Array = []
func get_recipe_by_id(id: StringName) -> Variant:
for recipe in recipes:
if recipe != null and recipe.id == id:
return recipe
return null
func get_all_ids() -> Array[StringName]:
var ids: Array[StringName] = []
for recipe in recipes:
if recipe != null and recipe.id != &"":
ids.append(recipe.id)
return ids

View File

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

View File

@@ -0,0 +1,9 @@
[gd_resource type="Resource" script_class="AlchemyCraftCatalogue" format=3 uid="uid://diboykfbbxpfs"]
[ext_resource type="Script" uid="uid://biljlhsxr3rsc" path="res://docs/gyms/tiny_sword/buildings/alchemy_tower/recipes/alchemy_craft_catalogue.gd" id="1_cat"]
[ext_resource type="Resource" path="res://docs/gyms/tiny_sword/buildings/alchemy_tower/recipes/mana_stone_recipe.tres" id="2_mana_recipe"]
[ext_resource type="Resource" uid="uid://dliibkgb2mom0" path="res://docs/gyms/tiny_sword/buildings/alchemy_tower/recipes/cognite_recipe.tres" id="3_cognite_recipe"]
[resource]
script = ExtResource("1_cat")
recipes = [ExtResource("2_mana_recipe"), ExtResource("3_cognite_recipe")]

View File

@@ -0,0 +1,10 @@
class_name AlchemyCraftRecipe
extends Resource
## Recipe for crafting currencies at the Alchemy Tower
@export var id: StringName = &""
@export var output_currency: Currency
@export var output_amount: int = 1
## Multi-currency cost to perform this craft
@export var cost_entries: Array = []

View File

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

View File

@@ -0,0 +1,10 @@
[gd_resource type="Resource" script_class="CurrencyCatalogue" format=3]
[ext_resource type="Script" uid="uid://621tus0uvbrd" path="res://core/currency/currency_catalogue.gd" id="1_cat"]
[ext_resource type="Resource" path="res://docs/gyms/tiny_sword/buildings/alchemy_tower/recipes/mana_stone_recipe.tres" id="2_mana_recipe"]
[ext_resource type="Resource" uid="uid://dliibkgb2mom0" path="res://docs/gyms/tiny_sword/buildings/alchemy_tower/recipes/cognite_recipe.tres" id="3_cognite_recipe"]
[resource]
script = ExtResource("1_cat")
currencies = [ExtResource("2_mana_recipe"), ExtResource("3_cognite_recipe")]
metadata/_custom_type_script = "uid://catalogue_script"

View File

@@ -0,0 +1,10 @@
[gd_resource type="Resource" script_class="CurrencyCostEntry" format=3]
[ext_resource type="Script" uid="uid://ba8e403mb7hp0" path="res://docs/gyms/tiny_sword/buildings/alchemy_tower/recipes/currency_cost_entry.gd" id="1_cost"]
[ext_resource type="Resource" uid="uid://dpbndqxvsffa0" path="res://docs/gyms/tiny_sword/currencies/magic_gold.tres" id="2_magic_gold"]
[resource]
script = ExtResource("1_cost")
currency = ExtResource("2_magic_gold")
amount = 25
metadata/_custom_type_script = "res://docs/gyms/tiny_sword/buildings/alchemy_tower/currency_cost_entry.gd"

View File

@@ -0,0 +1,11 @@
[gd_resource type="Resource" script_class="AlchemyCraftRecipe" format=3 uid="uid://dliibkgb2mom0"]
[ext_resource type="Script" uid="uid://ddlnlpb0p750q" path="res://docs/gyms/tiny_sword/buildings/alchemy_tower/recipes/alchemy_craft_recipe.gd" id="1_recipe"]
[ext_resource type="Resource" uid="uid://t6du7gm2ywbi" path="res://docs/gyms/tiny_sword/currencies/cognite.tres" id="2_xltlj"]
[ext_resource type="Resource" path="res://docs/gyms/tiny_sword/buildings/alchemy_tower/recipes/cognite_cost_entry.tres" id="3_cost"]
[resource]
script = ExtResource("1_recipe")
id = &"cognite_recipe"
output_currency = ExtResource("2_xltlj")
cost_entries = [ExtResource("3_cost")]

View File

@@ -0,0 +1,6 @@
class_name CurrencyCostEntry
extends Resource
## Entry for multi-currency cost in alchemy recipes
@export var currency: Currency
@export var amount: int = 1

View File

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

View File

@@ -0,0 +1,10 @@
[gd_resource type="Resource" script_class="CurrencyCostEntry" format=3]
[ext_resource type="Script" uid="uid://ba8e403mb7hp0" path="res://docs/gyms/tiny_sword/buildings/alchemy_tower/recipes/currency_cost_entry.gd" id="1_cost"]
[ext_resource type="Resource" uid="uid://dpbndqxvsffa0" path="res://docs/gyms/tiny_sword/currencies/magic_gold.tres" id="2_magic_gold"]
[resource]
script = ExtResource("1_cost")
currency = ExtResource("2_magic_gold")
amount = 10
metadata/_custom_type_script = "res://docs/gyms/tiny_sword/buildings/alchemy_tower/currency_cost_entry.gd"

View File

@@ -0,0 +1,13 @@
[gd_resource type="Resource" script_class="AlchemyCraftRecipe" format=3]
[ext_resource type="Script" uid="uid://ddlnlpb0p750q" path="res://docs/gyms/tiny_sword/buildings/alchemy_tower/recipes/alchemy_craft_recipe.gd" id="1_recipe"]
[ext_resource type="Resource" uid="uid://brctmnpmhjas6" path="res://docs/gyms/tiny_sword/currencies/mana_stone.tres" id="2_mana_stone"]
[ext_resource type="Resource" path="res://docs/gyms/tiny_sword/buildings/alchemy_tower/recipes/mana_stone_cost_entry.tres" id="3_cost"]
[resource]
script = ExtResource("1_recipe")
id = &"mana_stone_recipe"
output_currency = ExtResource("2_mana_stone")
output_amount = 1
cost_entries = [ExtResource("3_cost")]
metadata/_custom_type_script = "res://docs/gyms/tiny_sword/buildings/alchemy_tower/alchemy_craft_recipe.gd"

View File

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

View File

@@ -0,0 +1,11 @@
[gd_resource type="Resource" script_class="Currency" format=3 uid="uid://t6du7gm2ywbi"]
[ext_resource type="Texture2D" uid="uid://c1gnh8jgctrcx" path="res://sandbox/tiny_swords/UI Elements/UI Elements/Icons/Icon_07.png" id="1_axihf"]
[ext_resource type="Script" uid="uid://dtgqjf3bl7pm8" path="res://core/currency/currency.gd" id="2_fxby5"]
[resource]
script = ExtResource("2_fxby5")
id = &"cognite"
display_name = "Cognite"
icon = ExtResource("1_axihf")
metadata/_custom_type_script = "uid://dtgqjf3bl7pm8"

View File

@@ -0,0 +1,11 @@
[gd_resource type="Resource" script_class="Currency" format=3 uid="uid://dpbndqxvsffa0"]
[ext_resource type="Script" uid="uid://dtgqjf3bl7pm8" path="res://core/currency/currency.gd" id="1_v6rd4"]
[ext_resource type="Texture2D" uid="uid://c1gnh8jgctrcx" path="res://sandbox/tiny_swords/UI Elements/UI Elements/Icons/Icon_07.png" id="1_wi1w3"]
[resource]
script = ExtResource("1_v6rd4")
id = &"magic_gold"
display_name = "Magic Gold"
icon = ExtResource("1_wi1w3")
metadata/_custom_type_script = "uid://dtgqjf3bl7pm8"

View File

@@ -0,0 +1,11 @@
[gd_resource type="Resource" script_class="Currency" format=3 uid="uid://brctmnpmhjas6"]
[ext_resource type="Texture2D" uid="uid://c1gnh8jgctrcx" path="res://sandbox/tiny_swords/UI Elements/UI Elements/Icons/Icon_07.png" id="1_c7yxi"]
[ext_resource type="Script" uid="uid://dtgqjf3bl7pm8" path="res://core/currency/currency.gd" id="1_fahg0"]
[resource]
script = ExtResource("1_fahg0")
id = &"mana_stone"
display_name = "Mana Stone"
icon = ExtResource("1_c7yxi")
metadata/_custom_type_script = "uid://dtgqjf3bl7pm8"

View File

@@ -7,8 +7,11 @@
[ext_resource type="Resource" uid="uid://bxg2au0ijp242" path="res://docs/gyms/tiny_sword/currencies/food.tres" id="4_c77gh"]
[ext_resource type="Resource" uid="uid://bgsk8h4w80h45" path="res://docs/gyms/tiny_sword/currencies/wood.tres" id="5_gyp05"]
[ext_resource type="Resource" uid="uid://bfrb0ayrljac2" path="res://docs/gyms/tiny_sword/currencies/ascension.tres" id="6_ascension"]
[ext_resource type="Resource" uid="uid://dpbndqxvsffa0" path="res://docs/gyms/tiny_sword/currencies/magic_gold.tres" id="7_vu05v"]
[ext_resource type="Resource" uid="uid://brctmnpmhjas6" path="res://docs/gyms/tiny_sword/currencies/mana_stone.tres" id="8_p3urk"]
[ext_resource type="Resource" uid="uid://t6du7gm2ywbi" path="res://docs/gyms/tiny_sword/currencies/cognite.tres" id="9_ejnoj"]
[resource]
script = ExtResource("2_hmju3")
currencies = Array[ExtResource("1_501l6")]([ExtResource("2_ucsji"), ExtResource("3_7hx6u"), ExtResource("4_c77gh"), ExtResource("5_gyp05"), ExtResource("6_ascension")])
currencies = Array[ExtResource("1_501l6")]([ExtResource("2_ucsji"), ExtResource("3_7hx6u"), ExtResource("4_c77gh"), ExtResource("5_gyp05"), ExtResource("6_ascension"), ExtResource("7_vu05v"), ExtResource("8_p3urk"), ExtResource("9_ejnoj")])
metadata/_custom_type_script = "uid://621tus0uvbrd"

View File

@@ -19,7 +19,10 @@
[ext_resource type="Resource" uid="uid://bgsk8h4w80h45" path="res://docs/gyms/tiny_sword/currencies/wood.tres" id="12_l6a68"]
[ext_resource type="PackedScene" uid="uid://bf8lqbexvnx6e" path="res://docs/gyms/tiny_sword/buildings/monastery/monastery.tscn" id="13_no27p"]
[ext_resource type="PackedScene" uid="uid://rejxvjwybkll" path="res://sandbox/tiny_swords/Terrain/Resources/Wood/Trees/tree_1.tscn" id="14_0cs5o"]
[ext_resource type="PackedScene" uid="uid://bp5ng4vu4ot4a" path="res://docs/gyms/tiny_sword/buildings/alchemy_tower/alchemy_tower.tscn" id="14_hum8s"]
[ext_resource type="Resource" uid="uid://bfrb0ayrljac2" path="res://docs/gyms/tiny_sword/currencies/ascension.tres" id="15_ascension"]
[ext_resource type="Resource" uid="uid://dpbndqxvsffa0" path="res://docs/gyms/tiny_sword/currencies/magic_gold.tres" id="20_no27p"]
[ext_resource type="Resource" uid="uid://brctmnpmhjas6" path="res://docs/gyms/tiny_sword/currencies/mana_stone.tres" id="22_rbyxa"]
[node name="TinySwords" type="Node" unique_id=498237642]
@@ -58,18 +61,6 @@ position = Vector2(1568, 656)
[node name="Tree6" parent="LevelGameState/World/ForestProps" unique_id=894701042 instance=ExtResource("14_0cs5o")]
position = Vector2(1665, 650)
[node name="Tree7" parent="LevelGameState/World/ForestProps" unique_id=1661458508 instance=ExtResource("14_0cs5o")]
position = Vector2(1362, 792)
[node name="Tree8" parent="LevelGameState/World/ForestProps" unique_id=2029836975 instance=ExtResource("14_0cs5o")]
position = Vector2(1452, 790)
[node name="Tree9" parent="LevelGameState/World/ForestProps" unique_id=1580665442 instance=ExtResource("14_0cs5o")]
position = Vector2(1557, 793)
[node name="Tree10" parent="LevelGameState/World/ForestProps" unique_id=1295721315 instance=ExtResource("14_0cs5o")]
position = Vector2(1644, 822)
[node name="GoldMine" parent="LevelGameState/World" unique_id=341660167 instance=ExtResource("2_2j2oc")]
position = Vector2(274, 429)
@@ -85,6 +76,9 @@ position = Vector2(825, 915)
[node name="Monastery" parent="LevelGameState/World" unique_id=1545930496 instance=ExtResource("13_no27p")]
position = Vector2(105, 920)
[node name="AlchemyTower" parent="LevelGameState/World" unique_id=51852160 instance=ExtResource("14_hum8s")]
position = Vector2(1239, 775)
[node name="UI" type="Control" parent="LevelGameState" unique_id=1299828389]
layout_mode = 3
anchors_preset = 0
@@ -130,6 +124,23 @@ offset_bottom = 156.0
currency = ExtResource("15_ascension")
game_state = NodePath("../..")
[node name="MagicGoldTile" parent="LevelGameState/UI" unique_id=707573446 node_paths=PackedStringArray("game_state") instance=ExtResource("7_0cs5o")]
layout_mode = 0
offset_top = 152.0
offset_right = 203.0
offset_bottom = 183.0
currency = ExtResource("20_no27p")
game_state = NodePath("../..")
[node name="ManaStoneTile" parent="LevelGameState/UI" unique_id=1333819600 node_paths=PackedStringArray("game_state") instance=ExtResource("7_0cs5o")]
layout_mode = 0
offset_left = 1.0
offset_top = 178.0
offset_right = 204.0
offset_bottom = 209.0
currency = ExtResource("22_rbyxa")
game_state = NodePath("../..")
[node name="GoalsDebugUI" parent="LevelGameState/UI" unique_id=1494700185 instance=ExtResource("10_qifrv")]
layout_mode = 1
offset_left = 1275.0