Fix research xp generation
This commit is contained in:
@@ -108,4 +108,4 @@ The `CurrencyCatalogue` is a resource that holds all defined currencies and is a
|
||||
|
||||
</content>
|
||||
<parameter=filePath>
|
||||
/home/mikymod/work/jmp/idle/core/currency/README.md
|
||||
/home/mikymod/work/jmp/idle/core/currency/README.md
|
||||
|
||||
@@ -149,12 +149,17 @@ func _grant_cycle_income(cycle_count: int) -> void:
|
||||
production_tick.emit(produced, cycle_count, owned)
|
||||
|
||||
if data != null and data.research_data != null:
|
||||
if not _is_research_active(data.research_data.id):
|
||||
return
|
||||
|
||||
var amount_float: float = produced.mantissa * pow(10.0, float(produced.exponent))
|
||||
var research_xp_amount: BigNumber = BigNumber.from_float(data.research_data.xp_per_currency_produced * amount_float)
|
||||
if game_state != null and research_xp_amount.mantissa > 0.0:
|
||||
var tracker: ResearchXPTracker = game_state.research_tracker as ResearchXPTracker
|
||||
if tracker:
|
||||
tracker.add_xp_with_buffs(data.research_data.id, research_xp_amount)
|
||||
else:
|
||||
game_state.add_research_xp(data.research_data.id, research_xp_amount)
|
||||
|
||||
## Convenience helper for the next single-unit purchase cost.
|
||||
func get_next_cost() -> BigNumber:
|
||||
@@ -359,6 +364,29 @@ func get_research_multiplier() -> float:
|
||||
return 1.0
|
||||
return game_state.get_research_multiplier(data.research_data.id)
|
||||
|
||||
func _is_research_active(research_id: StringName) -> bool:
|
||||
if game_state == null:
|
||||
return true
|
||||
|
||||
var research_panel: Node = null
|
||||
var parent: Node = get_parent()
|
||||
while parent != null and parent != game_state.get_tree().root:
|
||||
if parent.has_method("is_research_active"):
|
||||
research_panel = parent
|
||||
break
|
||||
parent = parent.get_parent()
|
||||
|
||||
if research_panel == null:
|
||||
research_panel = game_state.find_child("ResearchPanel", true, false)
|
||||
|
||||
if research_panel == null:
|
||||
return true
|
||||
|
||||
if research_panel.has_method("is_research_active"):
|
||||
return research_panel.is_research_active(research_id)
|
||||
|
||||
return true
|
||||
|
||||
func reset_runtime_state_for_prestige() -> void:
|
||||
_is_registered = false
|
||||
_is_registering = false
|
||||
@@ -405,17 +433,23 @@ func _try_grant_click_currency() -> void:
|
||||
|
||||
var click_value: BigNumber = _get_click_value()
|
||||
_add_currency(click_value)
|
||||
|
||||
|
||||
_remaining_click_cooldown_seconds = _get_click_cooldown_seconds()
|
||||
|
||||
# Grant research XP for manual clicks
|
||||
if data.research_data != null and click_value.mantissa > 0.0:
|
||||
if not _is_research_active(data.research_data.id):
|
||||
return
|
||||
|
||||
var amount_float: float = click_value.mantissa * pow(10.0, float(click_value.exponent))
|
||||
var research_xp_amount: BigNumber = BigNumber.from_float(data.research_data.xp_per_currency_produced * amount_float)
|
||||
if game_state != null and research_xp_amount.mantissa > 0.0:
|
||||
var tracker: ResearchXPTracker = game_state.research_tracker as ResearchXPTracker
|
||||
if tracker:
|
||||
tracker.add_xp_with_buffs(data.research_data.id, research_xp_amount)
|
||||
else:
|
||||
game_state.add_research_xp(data.research_data.id, research_xp_amount)
|
||||
|
||||
_remaining_click_cooldown_seconds = _get_click_cooldown_seconds()
|
||||
|
||||
## Resolves click reward from data.
|
||||
func _get_click_value() -> BigNumber:
|
||||
|
||||
@@ -440,14 +440,6 @@ func get_effective_multiplier(generator_id: StringName, kind: int) -> float:
|
||||
return multiplier
|
||||
|
||||
func _initialize_research() -> void:
|
||||
research_tracker = Node.new()
|
||||
research_tracker.set_script(load("res://core/research/research_xp_tracker.gd"))
|
||||
add_child(research_tracker)
|
||||
|
||||
var tracker: ResearchXPTracker = research_tracker as ResearchXPTracker
|
||||
if tracker:
|
||||
tracker.game_state = self
|
||||
|
||||
if research_catalogue:
|
||||
for research in research_catalogue.get_all_research():
|
||||
register_research(research.id)
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
## Overview
|
||||
|
||||
The `research/` subfolder implements a production-based research system where generator output earns research XP, automatically leveling up to provide production multipliers. Research tracks are tied to specific generators and can be enhanced with purchasable buffs that increase XP gain.
|
||||
The `research/` subfolder implements a production-based research system where generator output earns
|
||||
research XP, automatically leveling up to provide production multipliers. Research tracks are tied to
|
||||
specific generators and can be enhanced with purchasable buffs that increase XP gain.
|
||||
|
||||
## Files
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ const RESEARCH_ROW_SCENE: PackedScene = preload("res://core/research/research_ro
|
||||
|
||||
var _game_state: LevelGameState
|
||||
var _research_rows: Dictionary = {}
|
||||
var _active_research_id: StringName = &""
|
||||
|
||||
func _ready() -> void:
|
||||
_game_state = find_parent("LevelGameState")
|
||||
@@ -25,13 +26,17 @@ func _build_research_rows() -> void:
|
||||
for child in _research_rows_container.get_children():
|
||||
child.queue_free()
|
||||
_research_rows.clear()
|
||||
_active_research_id = &""
|
||||
|
||||
if _game_state.research_catalogue:
|
||||
for research in _game_state.research_catalogue.get_all_research():
|
||||
var row: ResearchRow = RESEARCH_ROW_SCENE.instantiate()
|
||||
_research_rows_container.add_child(row)
|
||||
row.setup(research)
|
||||
row.active_changed.connect(_on_research_active_changed.bind(research.id))
|
||||
_research_rows[research.id] = row
|
||||
|
||||
_load_active_research_state()
|
||||
|
||||
func _refresh_all() -> void:
|
||||
for row in _research_rows.values():
|
||||
@@ -58,3 +63,49 @@ func _on_research_xp_changed(research_id: StringName, _new_xp: BigNumber) -> voi
|
||||
func _on_research_level_up(research_id: StringName, _old_level: int, _new_level: int) -> void:
|
||||
if _research_rows.has(research_id):
|
||||
_refresh_row(_research_rows[research_id])
|
||||
|
||||
func _on_research_active_changed(is_active: bool, research_id: StringName) -> void:
|
||||
if is_active:
|
||||
if _active_research_id != &"" and _active_research_id != research_id:
|
||||
var existing_row: ResearchRow = _research_rows.get(_active_research_id)
|
||||
if existing_row != null:
|
||||
existing_row.set_active(false, false)
|
||||
_active_research_id = research_id
|
||||
_save_active_research_state()
|
||||
else:
|
||||
if _active_research_id == research_id:
|
||||
_active_research_id = &""
|
||||
_save_active_research_state()
|
||||
|
||||
func _load_active_research_state() -> void:
|
||||
if _game_state == null:
|
||||
return
|
||||
|
||||
var save_data: Dictionary = _game_state.get_external_save_data("research_active")
|
||||
if save_data.has("active_research_id"):
|
||||
var loaded_id: String = String(save_data.get("active_research_id", ""))
|
||||
if not loaded_id.is_empty():
|
||||
_active_research_id = StringName(loaded_id)
|
||||
var row: ResearchRow = _research_rows.get(_active_research_id)
|
||||
if row != null:
|
||||
row.set_active(true, false)
|
||||
|
||||
func _save_active_research_state() -> void:
|
||||
if _game_state == null:
|
||||
return
|
||||
|
||||
var save_data: Dictionary = {}
|
||||
if _active_research_id != &"":
|
||||
save_data["active_research_id"] = String(_active_research_id)
|
||||
_game_state.set_external_save_data("research_active", save_data)
|
||||
|
||||
func get_active_research_id() -> StringName:
|
||||
return _active_research_id
|
||||
|
||||
func is_research_active(research_id: StringName) -> bool:
|
||||
return _active_research_id == research_id
|
||||
|
||||
func activate_research(research_id: StringName) -> void:
|
||||
if _research_rows.has(research_id):
|
||||
var row: ResearchRow = _research_rows[research_id]
|
||||
row.set_active(true)
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
class_name ResearchRow
|
||||
extends HBoxContainer
|
||||
|
||||
signal active_changed(is_active: bool)
|
||||
|
||||
@onready var _name_label: Label = $VBoxContainer/NameLabel
|
||||
@onready var _level_label: Label = $VBoxContainer/HBoxContainer/LevelLabel
|
||||
@onready var _progress_bar: ProgressBar = $VBoxContainer/HBoxContainer/ProgressBar
|
||||
@onready var _multiplier_label: Label = $VBoxContainer/HBoxContainer/MultiplierLabel
|
||||
@onready var _buff_label: Label = $VBoxContainer/HBoxContainer/BuffLabel
|
||||
@onready var _check_button: CheckButton = $CheckButton
|
||||
|
||||
var _research: ResearchData
|
||||
var _game_state: LevelGameState
|
||||
var _is_active: bool = false
|
||||
|
||||
func _ready() -> void:
|
||||
_game_state = find_parent("LevelGameState")
|
||||
@@ -18,6 +22,7 @@ func _ready() -> void:
|
||||
|
||||
_game_state.research_xp_changed.connect(_on_research_xp_changed)
|
||||
_game_state.research_level_up.connect(_on_research_level_up)
|
||||
_check_button.toggled.connect(_on_check_button_toggled)
|
||||
|
||||
func setup(research: ResearchData) -> void:
|
||||
_research = research
|
||||
@@ -72,3 +77,22 @@ func _update_from_state() -> void:
|
||||
var xp_needed: BigNumber = _research.get_xp_required_for_level_big(level + 1)
|
||||
|
||||
update_display(level, progress, multiplier, xp_current, xp_needed)
|
||||
|
||||
func _on_check_button_toggled(toggled_on: bool) -> void:
|
||||
if toggled_on != _is_active:
|
||||
_is_active = toggled_on
|
||||
active_changed.emit(_is_active)
|
||||
|
||||
func set_active(is_active: bool, emit_signal: bool = true) -> void:
|
||||
_is_active = is_active
|
||||
_check_button.button_pressed = is_active
|
||||
if emit_signal:
|
||||
active_changed.emit(is_active)
|
||||
|
||||
func is_research_active() -> bool:
|
||||
return _is_active
|
||||
|
||||
func get_research_id_public() -> StringName:
|
||||
if _research == null:
|
||||
return &""
|
||||
return _research.id
|
||||
|
||||
@@ -36,3 +36,7 @@ text = "+0%"
|
||||
|
||||
[node name="BuffLabel" type="Label" parent="VBoxContainer/HBoxContainer" unique_id=2124734446]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="CheckButton" type="CheckButton" parent="." unique_id=3456789012]
|
||||
layout_mode = 2
|
||||
text = "Active"
|
||||
|
||||
@@ -31,6 +31,9 @@ func _on_generator_produced(generator_id: StringName, _amount: Variant) -> void:
|
||||
if research == null:
|
||||
return
|
||||
|
||||
if not _is_research_active(research.id):
|
||||
return
|
||||
|
||||
var amount_big: BigNumber = _amount
|
||||
var amount_float: float = amount_big.mantissa * pow(10.0, float(amount_big.exponent))
|
||||
if amount_float <= 0.0:
|
||||
@@ -46,3 +49,24 @@ func _get_research_for_generator(generator_id: StringName) -> ResearchData:
|
||||
if game_state == null or game_state.research_catalogue == null:
|
||||
return null
|
||||
return game_state.research_catalogue.get_research_by_generator_id(generator_id)
|
||||
|
||||
func _is_research_active(research_id: StringName) -> bool:
|
||||
if game_state == null:
|
||||
return false
|
||||
|
||||
var research_panel: Node = game_state.find_child("ResearchPanel", true, false)
|
||||
if research_panel == null:
|
||||
return true
|
||||
|
||||
if research_panel.has_method("is_research_active"):
|
||||
return research_panel.is_research_active(research_id)
|
||||
|
||||
return true
|
||||
|
||||
func activate_research(research_id: StringName) -> void:
|
||||
if game_state == null:
|
||||
return
|
||||
|
||||
var research_panel: Node = game_state.find_child("ResearchPanel", true, false)
|
||||
if research_panel != null and research_panel.has_method("activate_research"):
|
||||
research_panel.activate_research(research_id)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
[gd_resource type="Resource" script_class="CurrencyGeneratorData" format=3 uid="uid://d08h51y0pnsnf"]
|
||||
|
||||
[ext_resource type="Resource" uid="uid://50yq2hl3wfwq" path="res://docs/gyms/tiny_sword/research/farm_research.tres" id="2_hprai"]
|
||||
[ext_resource type="Resource" uid="uid://dfxk30o34qe2s" path="res://docs/gyms/tiny_sword/currencies/worker.tres" id="3_bbypn"]
|
||||
[ext_resource type="Script" uid="uid://b00tqsuhxdy0d" path="res://core/generator/currency_generator_data.gd" id="4_0kvfm"]
|
||||
[ext_resource type="Resource" uid="uid://cts0407h130d6" path="res://docs/gyms/tiny_sword/goals/gold_total_1300_goal.tres" id="5_qiy1b"]
|
||||
@@ -16,4 +17,5 @@ unlock_goal = ExtResource("5_qiy1b")
|
||||
initial_cost = 1.0
|
||||
coefficient = 1.0
|
||||
initial_productivity = 20.0
|
||||
research_data = ExtResource("2_hprai")
|
||||
metadata/_custom_type_script = "uid://b00tqsuhxdy0d"
|
||||
|
||||
13
docs/gyms/tiny_sword/buildings/forestry/forestry.gd
Normal file
13
docs/gyms/tiny_sword/buildings/forestry/forestry.gd
Normal file
@@ -0,0 +1,13 @@
|
||||
extends Node2D
|
||||
|
||||
@onready var _generator_container: GeneratorPanel = $GeneratorContainer
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready() -> void:
|
||||
_generator_container.visible = false
|
||||
|
||||
func _on_area_2d_mouse_entered() -> void:
|
||||
_generator_container.visible = true
|
||||
|
||||
func _on_area_2d_mouse_exited() -> void:
|
||||
_generator_container.visible = false
|
||||
1
docs/gyms/tiny_sword/buildings/forestry/forestry.gd.uid
Normal file
1
docs/gyms/tiny_sword/buildings/forestry/forestry.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cckf4nacd4qcr
|
||||
@@ -1,6 +1,7 @@
|
||||
[gd_scene format=3 uid="uid://cf01wvy3f17i"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://jeoiinukrrsp" path="res://core/generator/currency_generator.tscn" id="1_7j1xc"]
|
||||
[ext_resource type="Script" uid="uid://cckf4nacd4qcr" path="res://docs/gyms/tiny_sword/buildings/forestry/forestry.gd" id="1_l4bxt"]
|
||||
[ext_resource type="Resource" uid="uid://bgsk8h4w80h45" path="res://docs/gyms/tiny_sword/currencies/wood.tres" id="2_23x2t"]
|
||||
[ext_resource type="Resource" uid="uid://v6hjoa2vky5k" path="res://docs/gyms/tiny_sword/buildings/forestry/forestry_generator.tres" id="3_pby1g"]
|
||||
[ext_resource type="Texture2D" uid="uid://doxauaa3vn3lm" path="res://docs/gyms/tiny_sword/buildings/forestry/House3.png" id="4_5yp33"]
|
||||
@@ -10,6 +11,7 @@
|
||||
size = Vector2(123, 157)
|
||||
|
||||
[node name="Forestry" type="Node2D" unique_id=726284577]
|
||||
script = ExtResource("1_l4bxt")
|
||||
|
||||
[node name="CurrencyGenerator" parent="." unique_id=967969064 node_paths=PackedStringArray("info_generator_container") instance=ExtResource("1_7j1xc")]
|
||||
currency = ExtResource("2_23x2t")
|
||||
@@ -27,8 +29,12 @@ position = Vector2(0.5, -2.5)
|
||||
shape = SubResource("RectangleShape2D_v4aq3")
|
||||
|
||||
[node name="GeneratorContainer" parent="." unique_id=1451609580 node_paths=PackedStringArray("_generator") instance=ExtResource("5_rh3m6")]
|
||||
visible = false
|
||||
offset_left = 128.0
|
||||
offset_top = -100.0
|
||||
offset_right = 392.0
|
||||
offset_bottom = 110.0
|
||||
_generator = NodePath("../CurrencyGenerator")
|
||||
|
||||
[connection signal="mouse_entered" from="Area2D" to="." method="_on_area_2d_mouse_entered"]
|
||||
[connection signal="mouse_exited" from="Area2D" to="." method="_on_area_2d_mouse_exited"]
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
[gd_resource type="Resource" script_class="CurrencyGeneratorData" format=3 uid="uid://v6hjoa2vky5k"]
|
||||
|
||||
[ext_resource type="Resource" uid="uid://dfxk30o34qe2s" path="res://docs/gyms/tiny_sword/currencies/worker.tres" id="2_fs80u"]
|
||||
[ext_resource type="Resource" uid="uid://cvow4sj6a5h23" path="res://docs/gyms/tiny_sword/research/forestry_research.tres" id="2_n4bxc"]
|
||||
[ext_resource type="Resource" uid="uid://bo463s6jt0ep7" path="res://docs/gyms/tiny_sword/goals/gold_total_13k_goal.tres" id="4_mgk3v"]
|
||||
[ext_resource type="Script" uid="uid://b00tqsuhxdy0d" path="res://core/generator/currency_generator_data.gd" id="4_rij12"]
|
||||
|
||||
@@ -16,4 +17,5 @@ unlock_goal = ExtResource("4_mgk3v")
|
||||
initial_cost = 1.0
|
||||
coefficient = 1.0
|
||||
initial_productivity = 20.0
|
||||
research_data = ExtResource("2_n4bxc")
|
||||
metadata/_custom_type_script = "uid://b00tqsuhxdy0d"
|
||||
|
||||
BIN
docs/gyms/tiny_sword/buildings/monastery/Monastery.png
Normal file
BIN
docs/gyms/tiny_sword/buildings/monastery/Monastery.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
@@ -0,0 +1,40 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://dlmjd2berkb6v"
|
||||
path="res://.godot/imported/Monastery.png-5f49b9547f0b0c767155d570a4d6cc55.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://docs/gyms/tiny_sword/buildings/monastery/Monastery.png"
|
||||
dest_files=["res://.godot/imported/Monastery.png-5f49b9547f0b0c767155d570a4d6cc55.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
|
||||
14
docs/gyms/tiny_sword/buildings/monastery/monastery.gd
Normal file
14
docs/gyms/tiny_sword/buildings/monastery/monastery.gd
Normal file
@@ -0,0 +1,14 @@
|
||||
extends Node2D
|
||||
|
||||
@onready var _research_panel: ResearchPanel = $ResearchPanel
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready() -> void:
|
||||
_research_panel.visible = false
|
||||
|
||||
func _on_area_2d_mouse_entered() -> void:
|
||||
_research_panel.visible = true
|
||||
|
||||
|
||||
func _on_area_2d_mouse_exited() -> void:
|
||||
_research_panel.visible = false
|
||||
@@ -0,0 +1 @@
|
||||
uid://cj0sxoceqqyrm
|
||||
30
docs/gyms/tiny_sword/buildings/monastery/monastery.tscn
Normal file
30
docs/gyms/tiny_sword/buildings/monastery/monastery.tscn
Normal file
@@ -0,0 +1,30 @@
|
||||
[gd_scene format=3 uid="uid://bf8lqbexvnx6e"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://cj0sxoceqqyrm" path="res://docs/gyms/tiny_sword/buildings/monastery/monastery.gd" id="1_e17qd"]
|
||||
[ext_resource type="Texture2D" uid="uid://dlmjd2berkb6v" path="res://docs/gyms/tiny_sword/buildings/monastery/Monastery.png" id="1_yyw6r"]
|
||||
[ext_resource type="PackedScene" uid="uid://dd8roif0mqirl" path="res://core/research/research_panel.tscn" id="3_c6gi6"]
|
||||
|
||||
[sub_resource type="RectangleShape2D" id="RectangleShape2D_yyw6r"]
|
||||
size = Vector2(160, 254)
|
||||
|
||||
[node name="Monastery" type="Node2D" unique_id=1545930496]
|
||||
script = ExtResource("1_e17qd")
|
||||
|
||||
[node name="Sprite2D" type="Sprite2D" parent="." unique_id=2097167417]
|
||||
texture = ExtResource("1_yyw6r")
|
||||
|
||||
[node name="Area2D" type="Area2D" parent="." unique_id=926221537]
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="Area2D" unique_id=1198096629]
|
||||
position = Vector2(1, 16)
|
||||
shape = SubResource("RectangleShape2D_yyw6r")
|
||||
|
||||
[node name="ResearchPanel" parent="." unique_id=1105274967 instance=ExtResource("3_c6gi6")]
|
||||
visible = false
|
||||
offset_left = 78.0
|
||||
offset_top = -98.0
|
||||
offset_right = 478.0
|
||||
offset_bottom = 128.0
|
||||
|
||||
[connection signal="mouse_entered" from="Area2D" to="." method="_on_area_2d_mouse_entered"]
|
||||
[connection signal="mouse_exited" from="Area2D" to="." method="_on_area_2d_mouse_exited"]
|
||||
@@ -0,0 +1,7 @@
|
||||
[gd_resource type="Resource" script_class="CurrencyGeneratorData" format=3 uid="uid://56bnik1oe3ao"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://b00tqsuhxdy0d" path="res://core/generator/currency_generator_data.gd" id="1_mnd3i"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_mnd3i")
|
||||
metadata/_custom_type_script = "uid://b00tqsuhxdy0d"
|
||||
13
docs/gyms/tiny_sword/research/farm_research.tres
Normal file
13
docs/gyms/tiny_sword/research/farm_research.tres
Normal file
@@ -0,0 +1,13 @@
|
||||
[gd_resource type="Resource" script_class="ResearchData" format=3 uid="uid://50yq2hl3wfwq"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://bgtt3wu43tajh" path="res://icon.svg" id="1_supp3"]
|
||||
[ext_resource type="Script" uid="uid://m7baywrfnpn0" path="res://core/research/research_data.gd" id="2_rgx73"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("2_rgx73")
|
||||
id = &"farm_research"
|
||||
generator_id = &"farm"
|
||||
name = "Farm Research"
|
||||
description = "Research that improves farm production"
|
||||
icon = ExtResource("1_supp3")
|
||||
metadata/_custom_type_script = "uid://m7baywrfnpn0"
|
||||
13
docs/gyms/tiny_sword/research/forestry_research.tres
Normal file
13
docs/gyms/tiny_sword/research/forestry_research.tres
Normal file
@@ -0,0 +1,13 @@
|
||||
[gd_resource type="Resource" script_class="ResearchData" format=3 uid="uid://cvow4sj6a5h23"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://bgtt3wu43tajh" path="res://icon.svg" id="1_qvnpw"]
|
||||
[ext_resource type="Script" uid="uid://m7baywrfnpn0" path="res://core/research/research_data.gd" id="2_6lndp"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("2_6lndp")
|
||||
id = &"forestry_research"
|
||||
generator_id = &"forestry"
|
||||
name = "Forestry Research"
|
||||
description = "Research that improves forestry production"
|
||||
icon = ExtResource("1_qvnpw")
|
||||
metadata/_custom_type_script = "uid://m7baywrfnpn0"
|
||||
@@ -5,14 +5,9 @@
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_yn72k")
|
||||
id = &"gold_research"
|
||||
id = &"gold_mine_research"
|
||||
generator_id = &"goldmine"
|
||||
name = "Gold Mine Research"
|
||||
description = "Research that improves gold mine production"
|
||||
icon = ExtResource("1_2tci1")
|
||||
xp_per_currency_produced = 0.01
|
||||
base_xp_required = 100.0
|
||||
xp_growth_multiplier = 1.5
|
||||
base_multiplier = 1.0
|
||||
multiplier_per_level = 0.1
|
||||
metadata/_custom_type_script = "uid://m7baywrfnpn0"
|
||||
|
||||
@@ -3,8 +3,10 @@
|
||||
[ext_resource type="Script" uid="uid://m7baywrfnpn0" path="res://core/research/research_data.gd" id="1_wscpr"]
|
||||
[ext_resource type="Resource" uid="uid://dif6w6kesmw6u" path="res://docs/gyms/tiny_sword/research/gold_mine_research.tres" id="2_migxn"]
|
||||
[ext_resource type="Script" uid="uid://d2v6t6w2todfy" path="res://core/research/research_catalogue.gd" id="2_yh8dx"]
|
||||
[ext_resource type="Resource" uid="uid://50yq2hl3wfwq" path="res://docs/gyms/tiny_sword/research/farm_research.tres" id="3_pdfmu"]
|
||||
[ext_resource type="Resource" uid="uid://cvow4sj6a5h23" path="res://docs/gyms/tiny_sword/research/forestry_research.tres" id="4_jnaqq"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("2_yh8dx")
|
||||
research_entries = Array[ExtResource("1_wscpr")]([ExtResource("2_migxn")])
|
||||
research_entries = Array[ExtResource("1_wscpr")]([ExtResource("2_migxn"), ExtResource("3_pdfmu"), ExtResource("4_jnaqq")])
|
||||
metadata/_custom_type_script = "uid://d2v6t6w2todfy"
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
[ext_resource type="Script" uid="uid://srkiu4qe8s2m" path="res://core/prestige/prestige_manager.gd" id="5_x77df"]
|
||||
[ext_resource type="Resource" uid="uid://dwmfvmusfskk6" path="res://docs/gyms/tiny_sword/prestige/primary_prestige.tres" id="6_xnhlc"]
|
||||
[ext_resource type="PackedScene" uid="uid://btkxru2gdjsgc" path="res://currency_tile.tscn" id="7_0cs5o"]
|
||||
[ext_resource type="Script" uid="uid://bv3a4utlnn2fg" path="res://core/research/research_xp_tracker.gd" id="8_no27p"]
|
||||
[ext_resource type="Resource" uid="uid://w4u1hddplb4e" path="res://docs/gyms/tiny_sword/currencies/gold.tres" id="9_1363k"]
|
||||
[ext_resource type="PackedScene" uid="uid://djedqovgngrx5" path="res://docs/gyms/tiny_sword/buildings/farm/farm.tscn" id="10_1lv5i"]
|
||||
[ext_resource type="Resource" uid="uid://dfxk30o34qe2s" path="res://docs/gyms/tiny_sword/currencies/worker.tres" id="10_i1cck"]
|
||||
@@ -17,9 +18,9 @@
|
||||
[ext_resource type="Resource" uid="uid://bxg2au0ijp242" path="res://docs/gyms/tiny_sword/currencies/food.tres" id="11_hskcg"]
|
||||
[ext_resource type="PackedScene" uid="uid://cf01wvy3f17i" path="res://docs/gyms/tiny_sword/buildings/forestry/forestry.tscn" id="11_pyqyw"]
|
||||
[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="Resource" uid="uid://bfrb0ayrljac2" path="res://docs/gyms/tiny_sword/currencies/ascension.tres" id="15_ascension"]
|
||||
[ext_resource type="PackedScene" uid="uid://dd8roif0mqirl" path="res://core/research/research_panel.tscn" id="21_no27p"]
|
||||
|
||||
[node name="TinySwords" type="Node" unique_id=498237642]
|
||||
|
||||
@@ -36,6 +37,10 @@ script = ExtResource("5_x77df")
|
||||
config = ExtResource("6_xnhlc")
|
||||
game_state = NodePath("..")
|
||||
|
||||
[node name="ResearchXpTracker" type="Node" parent="LevelGameState" unique_id=229654635 node_paths=PackedStringArray("game_state")]
|
||||
script = ExtResource("8_no27p")
|
||||
game_state = NodePath("..")
|
||||
|
||||
[node name="World" type="Node2D" parent="LevelGameState" unique_id=2118297724]
|
||||
|
||||
[node name="ForestProps" type="Node2D" parent="LevelGameState/World" unique_id=649424542]
|
||||
@@ -82,6 +87,9 @@ position = Vector2(380, 684)
|
||||
[node name="Forestry" parent="LevelGameState/World" unique_id=726284577 instance=ExtResource("11_pyqyw")]
|
||||
position = Vector2(825, 915)
|
||||
|
||||
[node name="Monastery" parent="LevelGameState/World" unique_id=1545930496 instance=ExtResource("13_no27p")]
|
||||
position = Vector2(105, 920)
|
||||
|
||||
[node name="UI" type="Control" parent="LevelGameState" unique_id=1299828389]
|
||||
layout_mode = 3
|
||||
anchors_preset = 0
|
||||
@@ -133,15 +141,3 @@ offset_left = 1275.0
|
||||
offset_top = 4.0
|
||||
offset_right = 1913.0
|
||||
offset_bottom = 263.0
|
||||
|
||||
[node name="ResearchPanel" parent="LevelGameState/UI" unique_id=2145420920 instance=ExtResource("21_no27p")]
|
||||
custom_minimum_size = Vector2(350, 100)
|
||||
layout_mode = 1
|
||||
anchors_preset = -1
|
||||
anchor_left = 7.4500003
|
||||
anchor_right = 16.2
|
||||
anchor_bottom = 3.1750002
|
||||
offset_right = 0.0
|
||||
offset_bottom = -7.6293945e-06
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
||||
@@ -6,10 +6,7 @@ var _game_root: Node = null
|
||||
|
||||
func _ready():
|
||||
await run()
|
||||
if failed == 0:
|
||||
get_tree().quit(0)
|
||||
else:
|
||||
get_tree().quit(1)
|
||||
# Don't quit here - let test_runner handle it
|
||||
|
||||
func run():
|
||||
print("\n=== TEST: Gold Mine Click ===\n")
|
||||
|
||||
@@ -7,9 +7,9 @@ var _game_root: Node = null
|
||||
func _ready():
|
||||
await run()
|
||||
if failed == 0:
|
||||
get_tree().quit(0)
|
||||
# get_tree().quit(0) // Let test_runner handle it
|
||||
else:
|
||||
get_tree().quit(1)
|
||||
# get_tree().quit(1) // Let test_runner handle it
|
||||
|
||||
func run():
|
||||
print("\n=== TEST: Prestige Mechanics ===\n")
|
||||
|
||||
159
tests/test_research_activation.gd
Normal file
159
tests/test_research_activation.gd
Normal file
@@ -0,0 +1,159 @@
|
||||
extends SceneTree
|
||||
|
||||
var passed: int = 0
|
||||
var failed: int = 0
|
||||
var _game_root: Node = null
|
||||
var _local_passed: int = 0
|
||||
var _local_failed: int = 0
|
||||
|
||||
func _init():
|
||||
await run()
|
||||
|
||||
func run():
|
||||
print("\n=== TEST: Research Activation ===\n")
|
||||
TestUtils.set_test_name("research_activation")
|
||||
|
||||
var scene = load("res://docs/gyms/tiny_sword/tiny_sword.tscn")
|
||||
_game_root = scene.instantiate()
|
||||
root.add_child(_game_root)
|
||||
|
||||
await _wait()
|
||||
|
||||
var game_state: LevelGameState = _game_root.find_child("LevelGameState")
|
||||
var research_panel: ResearchPanel = _game_root.find_child("ResearchPanel") as ResearchPanel
|
||||
|
||||
if game_state == null or research_panel == null:
|
||||
print("[ERROR] Missing LevelGameState or ResearchPanel node")
|
||||
_print_summary()
|
||||
quit(1)
|
||||
return
|
||||
|
||||
var gold_mine_node = game_state.find_child("GoldMine")
|
||||
var gold_mine: CurrencyGenerator = gold_mine_node.find_child("CurrencyGenerator") as CurrencyGenerator if gold_mine_node else null
|
||||
|
||||
if gold_mine == null:
|
||||
print("[ERROR] GoldMine node not found")
|
||||
_print_summary()
|
||||
quit(1)
|
||||
return
|
||||
|
||||
# Test 1: Verify initial state - no research should be active
|
||||
print("[TARGET] initial_active_research_id: %s" % research_panel.get_active_research_id())
|
||||
TestUtils.assert_true(
|
||||
research_panel.get_active_research_id() == &"",
|
||||
"No research active initially"
|
||||
)
|
||||
|
||||
# Test 2: Verify gold mine research exists and is linked to goldmine generator
|
||||
var gold_research = game_state.research_catalogue.get_research_by_id(&"gold_research")
|
||||
TestUtils.assert_not_null(
|
||||
gold_research,
|
||||
"Gold research exists in catalogue"
|
||||
)
|
||||
|
||||
if gold_research != null:
|
||||
TestUtils.assert_true(
|
||||
gold_research.generator_id == &"goldmine",
|
||||
"Gold research is linked to goldmine generator"
|
||||
)
|
||||
|
||||
# Test 3: Activate gold research
|
||||
research_panel.activate_research(&"gold_research")
|
||||
await _wait()
|
||||
|
||||
print("[TARGET] active_after_gold_activation: %s" % research_panel.get_active_research_id())
|
||||
TestUtils.assert_true(
|
||||
research_panel.get_active_research_id() == &"gold_research",
|
||||
"Gold research is active after activation"
|
||||
)
|
||||
|
||||
TestUtils.assert_true(
|
||||
research_panel.is_research_active(&"gold_research"),
|
||||
"is_research_active returns true for gold_research"
|
||||
)
|
||||
|
||||
# Test 4: Verify research XP is granted when research is active
|
||||
var initial_gold_research_xp = game_state.get_research_xp(&"gold_research")
|
||||
print("[TARGET] initial_gold_research_xp: %s" % initial_gold_research_xp.to_string_suffix(2))
|
||||
|
||||
# Simulate gold mine production (gold mine grants XP to gold_research)
|
||||
gold_mine._on_pressed()
|
||||
await _wait()
|
||||
|
||||
var final_gold_research_xp_active = game_state.get_research_xp(&"gold_research")
|
||||
print("[TARGET] final_gold_research_xp_active: %s" % final_gold_research_xp_active.to_string_suffix(2))
|
||||
|
||||
TestUtils.assert_true(
|
||||
final_gold_research_xp_active.mantissa > initial_gold_research_xp.mantissa,
|
||||
"Gold research XP increases when active (gold mine produces)"
|
||||
)
|
||||
|
||||
# Test 5: Deactivate gold research by activating another research
|
||||
var farm_research = game_state.research_catalogue.get_research_by_id(&"farm_research")
|
||||
TestUtils.assert_not_null(
|
||||
farm_research,
|
||||
"Farm research exists in catalogue"
|
||||
)
|
||||
|
||||
if farm_research != null:
|
||||
# Activate farm research (should deactivate gold research)
|
||||
research_panel.activate_research(&"farm_research")
|
||||
await _wait()
|
||||
|
||||
print("[TARGET] active_after_farm_activation: %s" % research_panel.get_active_research_id())
|
||||
TestUtils.assert_true(
|
||||
research_panel.get_active_research_id() == &"farm_research",
|
||||
"Farm research is active after activation"
|
||||
)
|
||||
|
||||
TestUtils.assert_false(
|
||||
research_panel.is_research_active(&"gold_research"),
|
||||
"Gold research is deactivated when farm is activated"
|
||||
)
|
||||
|
||||
# Test 6: Verify research XP is NOT granted when research is inactive
|
||||
var initial_gold_research_xp_inactive = game_state.get_research_xp(&"gold_research")
|
||||
print("[TARGET] initial_gold_research_xp_inactive: %s" % initial_gold_research_xp_inactive.to_string_suffix(2))
|
||||
|
||||
# Simulate gold mine production (gold mine should NOT grant XP to inactive gold_research)
|
||||
gold_mine._on_pressed()
|
||||
await _wait()
|
||||
|
||||
var final_gold_research_xp_inactive = game_state.get_research_xp(&"gold_research")
|
||||
print("[TARGET] final_gold_research_xp_inactive: %s" % final_gold_research_xp_inactive.to_string_suffix(2))
|
||||
|
||||
TestUtils.assert_equals(
|
||||
final_gold_research_xp_inactive.mantissa,
|
||||
initial_gold_research_xp_inactive.mantissa,
|
||||
"Gold research XP does not increase when inactive (gold mine produces)"
|
||||
)
|
||||
|
||||
# Test 7: Test mutual exclusivity with multiple activations
|
||||
research_panel.activate_research(&"gold_research")
|
||||
await _wait()
|
||||
research_panel.activate_research(&"farm_research")
|
||||
await _wait()
|
||||
research_panel.activate_research(&"gold_research")
|
||||
await _wait()
|
||||
|
||||
print("[TARGET] final_active_research_id: %s" % research_panel.get_active_research_id())
|
||||
TestUtils.assert_true(
|
||||
research_panel.get_active_research_id() == &"gold_research",
|
||||
"Only one research can be active at a time"
|
||||
)
|
||||
|
||||
_print_summary()
|
||||
if failed == 0:
|
||||
quit(0)
|
||||
else:
|
||||
quit(1)
|
||||
|
||||
func _wait() -> void:
|
||||
await create_timer(0.5).timeout
|
||||
|
||||
func _print_summary():
|
||||
TestUtils.print_result()
|
||||
_local_passed = TestUtils.get_passed()
|
||||
_local_failed = TestUtils.get_failed()
|
||||
passed = _local_passed
|
||||
failed = _local_failed
|
||||
1
tests/test_research_activation.gd.uid
Normal file
1
tests/test_research_activation.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cf23bjqannrog
|
||||
@@ -1,18 +1,18 @@
|
||||
extends Node
|
||||
extends SceneTree
|
||||
|
||||
var test_scripts: Array[String] = []
|
||||
var test_index: int = 0
|
||||
var total_passed: int = 0
|
||||
var total_failed: int = 0
|
||||
|
||||
func _ready():
|
||||
func _init():
|
||||
print("\n=== GODOT TEST RUNNER ===\n")
|
||||
_discover_tests()
|
||||
|
||||
if test_scripts.is_empty():
|
||||
print("[ERROR] No test scripts found in res://tests/")
|
||||
print("[RESULT] FAIL")
|
||||
get_tree().quit(1)
|
||||
quit(1)
|
||||
return
|
||||
|
||||
print("Found %d test(s): %s\n" % [test_scripts.size(), str(test_scripts)])
|
||||
@@ -25,10 +25,10 @@ func _ready():
|
||||
|
||||
if total_failed == 0:
|
||||
print("[OVERALL_RESULT] PASS")
|
||||
get_tree().quit(0)
|
||||
quit(0)
|
||||
else:
|
||||
print("[OVERALL_RESULT] FAIL")
|
||||
get_tree().quit(1)
|
||||
quit(1)
|
||||
|
||||
func _discover_tests() -> void:
|
||||
var dir = DirAccess.open("res://tests")
|
||||
@@ -53,11 +53,26 @@ func _run_next_test() -> void:
|
||||
|
||||
# Load and run test
|
||||
var test_instance = load(test_script).new()
|
||||
add_child(test_instance)
|
||||
await test_instance.run()
|
||||
get_root().add_child(test_instance)
|
||||
|
||||
total_passed += test_instance.get_passed()
|
||||
total_failed += test_instance.get_failed()
|
||||
# Check if test has run() method (new pattern) or uses _ready() (old pattern)
|
||||
if test_instance.has_method("run"):
|
||||
await test_instance.run()
|
||||
# Clean up test instance
|
||||
test_instance.queue_free()
|
||||
else:
|
||||
# For old pattern, wait a bit for _ready() to complete
|
||||
await create_timer(0.2).timeout
|
||||
# Clean up test instance
|
||||
test_instance.queue_free()
|
||||
|
||||
# Get results if available
|
||||
if test_instance.has_method("get_passed"):
|
||||
total_passed += test_instance.get_passed()
|
||||
total_failed += test_instance.get_failed()
|
||||
|
||||
# Wait for cleanup
|
||||
await create_timer(0.1).timeout
|
||||
|
||||
print("")
|
||||
test_index += 1
|
||||
|
||||
Reference in New Issue
Block a user