From 1b2ee1a0765c968dfb736eab4e1e51f2c42e7402 Mon Sep 17 00:00:00 2001
From: Ategon <benjamin@barbeau.net>
Date: Mon, 7 Oct 2024 13:07:46 -0400
Subject: [PATCH] Add creature dragging

---
 Main.tscn                         |   7 ----
 MouseSignals.tscn                 |   6 +++
 NoCreMouseSignals.tscn            |   6 +++
 components/Cursor/cursor.gd       |  63 +++++++++++++++++++++++++++---
 components/Triggerer/triggerer.gd |   6 ++-
 main.gd                           |  14 +++++--
 no_cre_build_signals.gd           |  22 +++++++++++
 parts/zones/images/forest.png     | Bin 667 -> 1350 bytes
 project.godot                     |   1 +
 src/BuildWindow.tscn              |  31 ++++++++++++++-
 src/CreatureWindow.tscn           |  16 ++++++++
 src/UIButtons.tscn                |   2 +-
 src/Zone.tscn                     |   6 ++-
 src/build_window.gd               |  38 +++++++++++++++++-
 src/creature.gd                   |  11 ++----
 src/creature_window.gd            |  43 ++++++++++++++++++++
 src/mouse_signals.gd              |  37 ++++++++++++++++++
 src/zone.gd                       |   5 ---
 18 files changed, 280 insertions(+), 34 deletions(-)
 create mode 100644 MouseSignals.tscn
 create mode 100644 NoCreMouseSignals.tscn
 create mode 100644 no_cre_build_signals.gd
 create mode 100644 src/CreatureWindow.tscn
 create mode 100644 src/creature_window.gd
 create mode 100644 src/mouse_signals.gd

diff --git a/Main.tscn b/Main.tscn
index bb604ab..43bef61 100644
--- a/Main.tscn
+++ b/Main.tscn
@@ -18,14 +18,7 @@ position = Vector2(156, 90)
 texture = ExtResource("3_kjcur")
 
 [node name="Timer" type="Timer" parent="."]
-wait_time = 3.0
-one_shot = true
-autostart = true
-
-[node name="Timer2" type="Timer" parent="."]
-wait_time = 3.0
 one_shot = true
 autostart = true
 
 [connection signal="timeout" from="Timer" to="." method="_on_timer_timeout"]
-[connection signal="timeout" from="Timer2" to="." method="_on_timer_timeout"]
diff --git a/MouseSignals.tscn b/MouseSignals.tscn
new file mode 100644
index 0000000..c977361
--- /dev/null
+++ b/MouseSignals.tscn
@@ -0,0 +1,6 @@
+[gd_scene load_steps=2 format=3 uid="uid://dcmh5yv0fjmsb"]
+
+[ext_resource type="Script" path="res://src/mouse_signals.gd" id="1_mpp7j"]
+
+[node name="MouseSignals" type="Node2D" groups=["mouse_signals"]]
+script = ExtResource("1_mpp7j")
diff --git a/NoCreMouseSignals.tscn b/NoCreMouseSignals.tscn
new file mode 100644
index 0000000..95527ee
--- /dev/null
+++ b/NoCreMouseSignals.tscn
@@ -0,0 +1,6 @@
+[gd_scene load_steps=2 format=3 uid="uid://5g4mecc4tb6f"]
+
+[ext_resource type="Script" path="res://no_cre_build_signals.gd" id="1_bgmgm"]
+
+[node name="MouseSignals" type="Node2D"]
+script = ExtResource("1_bgmgm")
diff --git a/components/Cursor/cursor.gd b/components/Cursor/cursor.gd
index ea68741..115298a 100644
--- a/components/Cursor/cursor.gd
+++ b/components/Cursor/cursor.gd
@@ -7,25 +7,72 @@ extends Base
 const CURSOR_UI = preload("res://components/Cursor/hover-1.png")
 const CURSOR_HOLD = preload("res://components/Cursor/grab-1.png")
 const CURSOR = preload("res://components/Cursor/normal-1.png")
+const CREATURE = preload("res://src/Creature.tscn")
 var rotation_tween
 
 var cursor_tween
 var hovered_objects = 0
 var holding = false
-var held_item
+var grabbed_creature
+var signal_object
+var original_window
+var original_position
+var timer = 0
+var hover_timer = 0
 
 func _ready() -> void:
 	Persister.data_persisted.connect(_on_data_persisted)
 	Triggerer.listen("grab_creature", _on_grab_creature)
+	Triggerer.listen("hovered", _on_hovered)
+		
+	for child in get_parent().get_children():
+		if child.is_in_group("mouse_signals"):
+			signal_object = child
+
+
+func _on_hovered(_data):
+	hover_timer = 0.125
 
 
 func _on_grab_creature(data):
-	held_item = data.creature
+	print("GRAB")
+	grabbed_creature = CREATURE.instantiate()
+	grabbed_creature.key = data.creature
+	mouse_control.add_child(grabbed_creature)
+	grabbed_creature.position = Vector2(0, 0)
 	holding = true
+	
+	original_window = data.old_window
+	original_position = data.old_position
 
+func let_go():
+	if holding and grabbed_creature:
+		if get_window().get_window_id() == 0 and not Persister.get_value("hovered"):
+			var new_creature = CREATURE.instantiate()
+			new_creature.key = grabbed_creature.key
+			new_creature.position = original_position
+			original_window.add_child(new_creature)
+		
+		if get_window().get_window_id() == 0:
+			Persister.persist_data("grabbing", false)
+		
+		if signal_object and signal_object.mouse_in_window:
+			var new_creature = CREATURE.instantiate()
+			new_creature.key = grabbed_creature.key
+			new_creature.global_position = grabbed_creature.global_position
+			get_window().add_child(new_creature)
+		grabbed_creature.queue_free()
+		grabbed_creature = null
+	
+	
+	
+	holding = false
 
 func _on_release():
-	holding = false
+	print("RElEASED %d" % [get_window().get_window_id()])
+	let_go()
+	Triggerer.trigger("released")
+	
 	var overlapping_areas = mouse_control.get_overlapping_areas()
 	overlapping_areas.sort_custom(func(a, b):
 		return a.z_index > b.z_index
@@ -85,8 +132,14 @@ func _process(delta):
 	#Input.set_mouse_mode(Input.MOUSE_MODE_HIDDEN)
 	mouse_control.position = mouse_control.get_global_mouse_position()
 	
-	if held_item:
-		held_item.position = mouse_control.position
+	if timer > 0:
+		timer -= delta
+		if timer <= 0:
+			let_go()
+	
+	if hover_timer > 0:
+		hover_timer -= delta
+		timer = 0
 	
 	if not Input.is_action_pressed("left_click"):
 		sprite_2d.rotation = move_toward(sprite_2d.rotation, 0, delta)
diff --git a/components/Triggerer/triggerer.gd b/components/Triggerer/triggerer.gd
index ada5aa0..fa6d0cf 100644
--- a/components/Triggerer/triggerer.gd
+++ b/components/Triggerer/triggerer.gd
@@ -13,15 +13,19 @@ var _connections = {}
 
 ## Trigger an event to be read in by other objects
 func trigger(key: String, data: Dictionary = {}) -> void:
-	_info("Triggered key ∧%s∧" % [key])
+	#_info("Triggered key ∧%s∧" % [key])
 	
 	data.trigger = key
 	
 	if _connections.has(key):
+		_connections[key] = _connections[key].filter(func(x): return x.is_valid())
+		
 		for callback in _connections[key]:
 			callback.call(data)
 	
 	if _connections.has("any"):
+		_connections["any"] = _connections["any"].filter(func(x): return x.is_valid())
+		
 		for callback in _connections["any"]:
 			callback.call(data)
 
diff --git a/main.gd b/main.gd
index 1fa2f3d..d58d07b 100644
--- a/main.gd
+++ b/main.gd
@@ -7,6 +7,7 @@ const ZONE = preload("res://src/Zone.tscn")
 const UI_BUTTONS = preload("res://src/UIButtons.tscn")
 const PAUSE_WINDOW = preload("res://src/PauseWindow.tscn")
 const BUILD_WINDOW = preload("res://src/BuildWindow.tscn")
+const CREATURE_WINDOW = preload("res://src/CreatureWindow.tscn")
 
 var build_object
 
@@ -41,10 +42,6 @@ func _on_spawn_window(data) -> void:
 	get_tree().root.add_child(new_window)
 
 
-func _on_timer_timeout() -> void:
-	Triggerer.trigger("spawn_window", {"key": ["farm", "desert", "lake", "forest"].pick_random()})
-
-
 func _on_quit(_data) -> void:
 	get_tree().quit()
 
@@ -58,3 +55,12 @@ func _on_build_menu(data):
 		build_object = new_window
 	else:
 		build_object.queue_free()
+
+
+func _on_timer_timeout() -> void:
+	var new_window = CREATURE_WINDOW.instantiate()
+	var new_cursor = CURSOR.instantiate()
+	new_window.add_child(new_cursor)
+	add_child(new_window)
+	
+	Triggerer.trigger("spawn_window", {"key": ["forest"].pick_random()})
diff --git a/no_cre_build_signals.gd b/no_cre_build_signals.gd
new file mode 100644
index 0000000..5e8e7e8
--- /dev/null
+++ b/no_cre_build_signals.gd
@@ -0,0 +1,22 @@
+extends Node2D
+
+var mouse_in_window
+
+func _ready() -> void:
+	Triggerer.listen("released", _on_released)
+
+
+func _on_released(_data):
+	if mouse_in_window:
+		get_window().grab_focus()
+
+
+func _notification(blah):
+	match blah:
+		NOTIFICATION_WM_MOUSE_EXIT:
+			mouse_in_window = false
+		NOTIFICATION_WM_MOUSE_ENTER:
+			mouse_in_window = true
+			
+			if not Persister.get_value("grabbing"):
+				get_window().grab_focus()
diff --git a/parts/zones/images/forest.png b/parts/zones/images/forest.png
index 7a88f8f6d4b720ebb4ffc4848ce7f3f35497f1a8..41c08dafef316c3211c2a8340919ac61e7ce77c3 100644
GIT binary patch
delta 1319
zcmV+?1=#wV1;z@HFn<K*Nkl<Zc%1EAy-wpm5FQYzQlz4xM~b4n14@%O@Ebry!4pvN
z1Qb;827UvY6Yp?}PD)Qhbw#QaT#+05^LS=<*YQt)eA3CzdOSPhot^!>c<y98qfh!l
zI1LG0pYQ&K+74A-;>^2veNOcFwmZMOB6|6#w@C~w|MKB^M1OQ*g|zm>xPw>>CGR<{
zI*dyA>5XS)+h$d7^RD$Jj}c)xU2_<n#V3dgv^MWrpYqaviAvH63453<Mrk(y^0|I*
z6P?<FKvW!ld@Dm(g2QIA7!?L?R=eM97$5U_*~a&A+h$eX$Jg*))Pa5Q5!>-7Vfj)C
zX&Ek?)oxzkJb$)2&|t}5+?FHv{<ICs$LMD}d2U<NqHuV!7*Y0nTL@vtGI_{Q`}=EK
zY3JWkUbf?P?Hb;PeQL7OUUoR2S9PC^XY|R+*kKHXi`!Arp=I#UVEZvzIAik^VB5`g
z_`9NDS{TyW+KYI;zYHqAd06)*kC1D!4Cx|ETXRUxSARAJJJiluZaF2&^EKT(tSQge
z>N(1%>i2Bb{Hi1^oC8Gq2tVInnok$8oD#kMDUTtr-c<b(GRt!gVw@6{lm70i42AK`
zUifh|wDaY(ZX6%^T;7|iKg;T2KUs{5K|){9k24||_Ven^e2mG?c^)2>E`j!LR;9ht
zcJuYnbAOUU4nq&ai$hsnLm4?Qag;Uvvac+`UPO_!WcYeKRtr&iuE|>=8WYl<e$Q_C
zJD8=ln^K|8w=R&BrHOnx$w<wjvGS=|+LQDAD6;fqF{)%X52+y?%DPraTl!;&3Hu_~
zXZ3A~-#RSP@690wCa5M%%gg#%Rv%romEZD+oPW2ap8}IhTXUEwJi>AWQb*X+&k4|*
z=QzUAT-wUeY`k1|<#|(X%+6{$@j+@_TC+ErOYfVdn{wk+?yUi{bTpU7cFj0Gw#AJ@
z`j^vs)JUMcopb3XNa5ch^3o}n?t&Zd!@WcHBKGFeU2x;nDdXAQDwpnqBd7E+D3?Bz
zEPve!mu{OI@B2Ebp;a#3Ha8}!j;ghVW9cV4a%mHdxOAJ`n6b~>l|(08x(#lO=ki^*
z$-cB^Z|__>HtROsA<@t}myXHOn54SiA<^vZl}it?M;*(h-DOF`q5P>O6w=nR)QC&B
z^}5$~NXPim>b`W-P)_CKUO&>0-uI=43V&%vXIwh<b<f*pPMtCuI_1(@h)Hg&0Yf=v
zmlONZq6WY9ICAO#*o#Yh$s;tvGEs#_SoY=Rh0eLO$Bjc=I`tb5x$hmaw>K_*C|SC*
zed*XNox154qhGW4Aor!)MDP33vEO*S8hg~CeQc@!TYlpatKYMGkZ(Nt#F0z){eO)|
zmf2x!g>>qaVQ5);uzl$+<%z1!9=SB2R@HK?ti|&D(4Zw(t2|FlTC$`~t39x|H^P#a
zZ87>~A6}gWmgmW&RdYC|x=R|7!o))4-ja{)Lsr$f4)c@IGWA!eOhd3AQb&zia{UiG
zJ#@8b6M1XUREP8Vi0ExwDAR8A)_>}u<&(;3H><L0jOWad)uK)1v7*kM!+0|*7`j?C
zRh|d!{b{Q{uv$qx3UP+Csy`8-b=uOQwa4`5*<d+KWc(ihER0(|xVVR^OZl2?+r6Au
zkCwcwMh#V$;zRN_AYE!HYk=CSF6~m@bC&1_a_N7a4J%nd73c#1000hUSRhGeO-%qQ
d00008000000002eQ<DGy002ovPDHLkV1i;JtGNIG

delta 630
zcmX@cHJf#UK|NEbr;B4q#hkZuY>N&V2((`Jsp6Uyqws{s<XfVIl+^YRk(HM&T`;iY
zF`2`-gTa@}Z-K~1sqDSlvu8@ERPNWB7-rAE<m$2t#*Bw0dS_n7%-CiY|5!7B-MQNz
z6Rve{`BiD-Equ%E_#Ue|AY;1P#>vq<;sw4hocDN}+zy<dvbX-%?=NP*t8?ZxF3erG
zFa2nJt^6tr&yvL(^~!)6_DIjaTq$~b>&{>EB>lhpAMbyWa{Z($4<F;5@1;eIdJ`i(
zvv<#6Zm2bxV8gumrgPJA_S;KZ;|0%WE{wRZB**?|$|s&PMd2aMvD^hV#&X{~%V%df
zu8DtDzHpzxbeo#ycj2e%nU$?3NZ+}x_Fq^pyLdy>PERL=Er0D;(=SbW5wyMNeM<aC
znMq==J>u2H50pnN%AVL)SbN;tBkD%E1)GZQv;-Xsv&~!n%YN-ya&+d>WEa-seWmTU
zjY>Q`qD;J*Gp23JSY412bN{0kca(RwuB^tarQU4enJXXMxEN(6X5u|Pqh43m8iy1f
z8Cwmxj~{;esq0p<shvMylhposA~3uIxZh^qN!;^hVb`(R;(OW*$Bu1|J+n5U=DgE}
zM|=O*gcQCG<vJaEamM1r<+1O$B>dm6^R3ATN?v{>9{SxU$YrtE_5_Zys6Wm3OTDy!
zA@?#y;?@7f)8oB3_8lp<61X^@TOs;Z&ECVYIxW3AcduT0rVM1g`OokmW}f2B%-Cr*
n>9$_#pKtm_=fAe96ZpgQz9>DuX=UqL1|aZs^>bP0l+XkKS9v3L

diff --git a/project.godot b/project.godot
index 6091fc3..b6b9c83 100644
--- a/project.godot
+++ b/project.godot
@@ -23,6 +23,7 @@ Triggerer="*res://components/Triggerer/Triggerer.tscn"
 Persister="*res://components/Persister/Persister.tscn"
 Achievements="*res://components/Achievements/Achievements.tscn"
 Dialogue="*res://components/Dialogue/Dialogue.tscn"
+Cursor="*res://components/Cursor/Cursor.tscn"
 
 [display]
 
diff --git a/src/BuildWindow.tscn b/src/BuildWindow.tscn
index bcf2a67..5c2552a 100644
--- a/src/BuildWindow.tscn
+++ b/src/BuildWindow.tscn
@@ -1,12 +1,17 @@
-[gd_scene load_steps=5 format=3 uid="uid://b5gq1bw4bj56b"]
+[gd_scene load_steps=8 format=3 uid="uid://rfc6w6wnl1c2"]
 
+[ext_resource type="PackedScene" uid="uid://5g4mecc4tb6f" path="res://NoCreMouseSignals.tscn" id="1_33eve"]
 [ext_resource type="Theme" uid="uid://ck7603ob4gflc" path="res://Fonts/Theme.tres" id="1_ta3q3"]
 [ext_resource type="Script" path="res://src/build_window.gd" id="1_y8qy0"]
 [ext_resource type="Script" path="res://small_wave.gd" id="3_0qyx5"]
+[ext_resource type="PackedScene" uid="uid://dykc1mgg5uopw" path="res://components/Cursor/MouseHandler.tscn" id="4_3uk60"]
 
 [sub_resource type="RichTextEffect" id="RichTextEffect_lhkb8"]
 script = ExtResource("3_0qyx5")
 
+[sub_resource type="RectangleShape2D" id="RectangleShape2D_ehvvg"]
+size = Vector2(52, 73)
+
 [node name="BuildWindow" type="Window"]
 canvas_item_default_texture_filter = 0
 position = Vector2i(0, 36)
@@ -14,6 +19,8 @@ size = Vector2i(900, 500)
 always_on_top = true
 content_scale_factor = 4.0
 
+[node name="MouseSignals" parent="." instance=ExtResource("1_33eve")]
+
 [node name="Control" type="Control" parent="."]
 layout_mode = 3
 anchors_preset = 15
@@ -94,6 +101,12 @@ offset_bottom = 86.24
 bbcode_enabled = true
 text = "[center]20G"
 
+[node name="MouseHandler" parent="Control/HBoxContainer/Upgrade" instance=ExtResource("4_3uk60")]
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Control/HBoxContainer/Upgrade/MouseHandler"]
+position = Vector2(16.5, 20)
+shape = SubResource("RectangleShape2D_ehvvg")
+
 [node name="Upgrade2" type="ColorRect" parent="Control/HBoxContainer"]
 custom_minimum_size = Vector2(32, 40)
 layout_mode = 2
@@ -119,6 +132,12 @@ offset_bottom = 86.24
 bbcode_enabled = true
 text = "[center]20G"
 
+[node name="MouseHandler2" parent="Control/HBoxContainer/Upgrade2" instance=ExtResource("4_3uk60")]
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Control/HBoxContainer/Upgrade2/MouseHandler2"]
+position = Vector2(16.5, 20)
+shape = SubResource("RectangleShape2D_ehvvg")
+
 [node name="Upgrade3" type="ColorRect" parent="Control/HBoxContainer"]
 custom_minimum_size = Vector2(32, 40)
 layout_mode = 2
@@ -143,3 +162,13 @@ offset_right = 56.38
 offset_bottom = 86.24
 bbcode_enabled = true
 text = "[center]20G"
+
+[node name="MouseHandler3" parent="Control/HBoxContainer/Upgrade3" instance=ExtResource("4_3uk60")]
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Control/HBoxContainer/Upgrade3/MouseHandler3"]
+position = Vector2(16.5, 20)
+shape = SubResource("RectangleShape2D_ehvvg")
+
+[connection signal="clicked" from="Control/HBoxContainer/Upgrade/MouseHandler" to="Control" method="_on_mouse_handler_clicked"]
+[connection signal="clicked" from="Control/HBoxContainer/Upgrade2/MouseHandler2" to="Control" method="_on_mouse_handler_2_clicked"]
+[connection signal="clicked" from="Control/HBoxContainer/Upgrade3/MouseHandler3" to="Control" method="_on_mouse_handler_3_clicked"]
diff --git a/src/CreatureWindow.tscn b/src/CreatureWindow.tscn
new file mode 100644
index 0000000..b0073d5
--- /dev/null
+++ b/src/CreatureWindow.tscn
@@ -0,0 +1,16 @@
+[gd_scene load_steps=3 format=3 uid="uid://dcaqcebxdrgu7"]
+
+[ext_resource type="Script" path="res://src/creature_window.gd" id="1_eufhm"]
+[ext_resource type="PackedScene" uid="uid://dcmh5yv0fjmsb" path="res://MouseSignals.tscn" id="2_3cu4o"]
+
+[node name="CreatureWindow" type="Window"]
+canvas_item_default_texture_filter = 0
+position = Vector2i(0, 36)
+size = Vector2i(300, 300)
+always_on_top = true
+content_scale_factor = 4.0
+
+[node name="Node2D" type="Node2D" parent="."]
+script = ExtResource("1_eufhm")
+
+[node name="MouseSignals" parent="." instance=ExtResource("2_3cu4o")]
diff --git a/src/UIButtons.tscn b/src/UIButtons.tscn
index daa1147..2ee67d2 100644
--- a/src/UIButtons.tscn
+++ b/src/UIButtons.tscn
@@ -1,4 +1,4 @@
-[gd_scene load_steps=8 format=3 uid="uid://bqd2ulwe0bsrb"]
+[gd_scene load_steps=8 format=3 uid="uid://dmsrxabynq46i"]
 
 [ext_resource type="Script" path="res://src/buttons.gd" id="1_rc6dx"]
 [ext_resource type="PackedScene" uid="uid://br46gg7k10wt2" path="res://src/ui/ActionButton.tscn" id="1_ydcg5"]
diff --git a/src/Zone.tscn b/src/Zone.tscn
index ac1a13b..cdae941 100644
--- a/src/Zone.tscn
+++ b/src/Zone.tscn
@@ -1,6 +1,7 @@
-[gd_scene load_steps=2 format=3 uid="uid://c1bqwhwmkp8aw"]
+[gd_scene load_steps=3 format=3 uid="uid://c1bqwhwmkp8aw"]
 
 [ext_resource type="Script" path="res://src/zone.gd" id="1_gihyf"]
+[ext_resource type="Script" path="res://src/mouse_signals.gd" id="2_28mh4"]
 
 [node name="Zone" type="Window"]
 canvas_item_default_texture_filter = 0
@@ -12,3 +13,6 @@ content_scale_factor = 4.0
 script = ExtResource("1_gihyf")
 
 [node name="Sprite2D" type="Sprite2D" parent="."]
+
+[node name="MouseSignals" type="Node2D" parent="." groups=["mouse_signals"]]
+script = ExtResource("2_28mh4")
diff --git a/src/build_window.gd b/src/build_window.gd
index 76ff907..837a137 100644
--- a/src/build_window.gd
+++ b/src/build_window.gd
@@ -2,7 +2,6 @@ extends Control
 
 var upgrade_pool = Data.data.upgrades.keys()
 var zone_pool = Data.data.zones.keys()
-var current_zone
 
 @onready var cards = [
 	{
@@ -19,9 +18,16 @@ var current_zone
 	}
 ]
 
+var chosen_cards = [
+	null,
+	null,
+	null
+]
+
 func _ready() -> void:
 	upgrade_pool.shuffle()
 	zone_pool.shuffle()
+	Persister.change_value("gold", 100) # TEMP
 	
 	var screen_size = DisplayServer.screen_get_size(0)
 	
@@ -40,13 +46,43 @@ func _update_card(index):
 	var cost
 	
 	if index == 2:
+		if zone_pool.size() == 0:
+			zone_pool = Data.data.zones.keys()
+			zone_pool.shuffle()
 		choice = zone_pool.pop_back()
 		card_data = Data.data.zones[choice]
 		cost = 20
 	else:
+		if upgrade_pool.size() == 0:
+			upgrade_pool = Data.data.upgrades.keys()
+			upgrade_pool.shuffle()
 		choice = upgrade_pool.pop_back()
 		card_data = Data.data.upgrades[choice]
 		cost = card_data.cost
 	
 	cards[index].title.text = "[center]%s" % [card_data.name]
 	cards[index].cost.text = "[center]%d G" % [cost]
+	card_data.key = choice
+	chosen_cards[index] = card_data
+
+
+func _on_mouse_handler_clicked() -> void:
+	_buy_upgrade(0)
+
+
+func _on_mouse_handler_2_clicked() -> void:
+	_buy_upgrade(1)
+
+
+func _on_mouse_handler_3_clicked() -> void:
+	_buy_upgrade(2)
+
+
+func _buy_upgrade(index):
+	var card_data = chosen_cards[index]
+	if Persister.get_value("gold", PersisterEnums.Scope.UNKNOWN, 0) >= (card_data.cost if card_data.has("cost") else 20):
+		Persister.change_value("gold", -(card_data.cost if card_data.has("cost") else 20))
+		_update_card(index)
+		
+		if index == 2:
+			Triggerer.trigger("spawn_window", {"key": card_data.key})
diff --git a/src/creature.gd b/src/creature.gd
index b73e515..f4d6255 100644
--- a/src/creature.gd
+++ b/src/creature.gd
@@ -7,17 +7,12 @@ var key
 
 @onready var sprite_2d: Sprite2D = $Sprite2D
 
-var grabbed = false
 
 func _ready() -> void:
 	sprite_2d.texture = image
 
 
-func _process(delta: float) -> void:
-	if Input.is_action_just_released("left_click"):
-		grabbed = false
-
-
 func _on_mouse_handler_clicked() -> void:
-	Triggerer.trigger("grab_creature", {"creature": self})
-	grabbed = true
+	Triggerer.trigger("grab_creature", {"creature": key, "old_window": get_window(), "old_position": position})
+	Persister.persist_data("grabbing", true)
+	queue_free()
diff --git a/src/creature_window.gd b/src/creature_window.gd
new file mode 100644
index 0000000..d9a4659
--- /dev/null
+++ b/src/creature_window.gd
@@ -0,0 +1,43 @@
+extends Node2D
+
+var minutes_left = 6 * 24
+var creatures_spawned = 0
+var spawn_times = []
+
+const CREATURE = preload("res://src/Creature.tscn")
+
+var mouse_in_window = false
+
+func _ready() -> void:
+	Persister.change_value("creature_amount", 4)
+	Triggerer.listen("minutes", _on_minutes)
+	Triggerer.listen("day", _on_day)
+	_generate_spawn_times()
+	
+	var screen_size = DisplayServer.screen_get_size(0)
+	
+	get_window().position = Vector2i(50, screen_size.y - 300 - 50) + DisplayServer.screen_get_position(0)
+
+
+
+func _on_minutes(_data):
+	minutes_left -= 1
+	
+	if spawn_times.has(minutes_left):
+		var new_creature = CREATURE.instantiate()
+		new_creature.position = Vector2(50, 50)
+		new_creature.key = Data.data.creatures.keys().pick_random()
+		add_child(new_creature)
+
+
+func _on_day(_data):
+	minutes_left = 6 * 24
+	creatures_spawned = 0
+	_generate_spawn_times()
+
+
+func _generate_spawn_times():
+	spawn_times = []
+	
+	for i in range(0, 4):
+		spawn_times.push_back(randi_range(2, 6 * 24 - 2))
diff --git a/src/mouse_signals.gd b/src/mouse_signals.gd
new file mode 100644
index 0000000..751ed78
--- /dev/null
+++ b/src/mouse_signals.gd
@@ -0,0 +1,37 @@
+extends Node2D
+
+var mouse_in_window
+#
+#
+#func _on_creature_window_mouse_entered() -> void:
+	#print("ENTERED")
+	#mouse_in_window = true
+#
+#
+#func _on_creature_window_mouse_exited() -> void:
+	#print("EXITED")
+	#mouse_in_window = false
+
+
+func _ready() -> void:
+	Triggerer.listen("released", _on_released)
+
+
+func _on_released(_data):
+	if mouse_in_window:
+		get_window().grab_focus()
+
+
+func _notification(blah):
+	match blah:
+		NOTIFICATION_WM_MOUSE_EXIT:
+			#print('Mouse left window')
+			mouse_in_window = false
+			Persister.change_value("hovered", -1)
+		NOTIFICATION_WM_MOUSE_ENTER:
+			#print('Mouse entered window')
+			mouse_in_window = true
+			Persister.change_value("hovered", 1)
+			
+			if not Persister.get_value("grabbing"):
+				get_window().grab_focus()
diff --git a/src/zone.gd b/src/zone.gd
index d44526d..aa3d59a 100644
--- a/src/zone.gd
+++ b/src/zone.gd
@@ -17,11 +17,6 @@ func _ready() -> void:
 	title = data.name
 	sprite_2d.texture = image
 	sprite_2d.position = Vector2(int(data.size[0]) * 12 / 2, int(data.size[1]) * 12 / 2)
-	
-	var new_creature = CREATURE.instantiate()
-	new_creature.position = Vector2(50, 50)
-	new_creature.key = "1x1-1"
-	add_child(new_creature)
 
 
 #