nyairobi 2 years ago
parent
commit
b42ec34a0f
100 changed files with 7488 additions and 0 deletions
  1. 2 0
      .gitattributes
  2. 6 0
      .gitignore
  3. 1 0
      README.md
  4. 21 0
      addons/fake_parallax/fake_parallax.gd
  5. BIN
      addons/fake_parallax/icon.png
  6. 7 0
      addons/fake_parallax/plugin.cfg
  7. 8 0
      addons/fake_parallax/plugin.gd
  8. 73 0
      default_bus_layout.tres
  9. 68 0
      export_presets.cfg
  10. 1 0
      icon.svg
  11. 210 0
      project.godot
  12. BIN
      res/asteroid.png
  13. BIN
      res/bullet.png
  14. BIN
      res/carrot_body_0.png
  15. BIN
      res/carrot_body_1.png
  16. BIN
      res/carrot_gun.png
  17. BIN
      res/carrot_icon.png
  18. BIN
      res/carrot_icon_1.png
  19. BIN
      res/circle.png
  20. BIN
      res/cucumber.png
  21. BIN
      res/dragonfruit.png
  22. BIN
      res/fg.png
  23. BIN
      res/fgo.png
  24. BIN
      res/fork.png
  25. BIN
      res/missdemandrake.png
  26. BIN
      res/missdemandrake_eyes.png
  27. BIN
      res/missdemandrake_hair.png
  28. BIN
      res/missdemandrake_icon.png
  29. BIN
      res/nothing.png
  30. BIN
      res/pbar.png
  31. BIN
      res/pbar2.png
  32. BIN
      res/shallot.png
  33. BIN
      res/slot.png
  34. BIN
      res/star.png
  35. BIN
      res/tree.png
  36. BIN
      res/uoh.png
  37. BIN
      res/wheat.png
  38. BIN
      res/witch_ufo.png
  39. BIN
      res/witch_ufo_bot.png
  40. BIN
      res/witch_ufo_top.png
  41. 72 0
      scene/core/camera.gd
  42. 25 0
      scene/core/economy.gd
  43. 26 0
      scene/core/main.gd
  44. 314 0
      scene/core/main.tscn
  45. 86 0
      scene/core/main_menu.tscn
  46. 1609 0
      scene/core/main_menu_thenme.tres
  47. 62 0
      scene/core/outline.gdshader
  48. 5 0
      scene/core/pc1.gd
  49. 5 0
      scene/core/restart_button.gd
  50. 33 0
      scene/core/root.gd
  51. 41 0
      scene/core/root.tscn
  52. 55 0
      scene/core/selected_item.gd
  53. 29 0
      scene/core/slot.gd
  54. 20 0
      scene/core/slot.tscn
  55. 29 0
      scene/core/slot_array.gd
  56. 377 0
      scene/core/ui.tscn
  57. 63 0
      scene/core/wave.gd
  58. 6 0
      scene/core/wave.tscn
  59. 46 0
      scene/core/wave_manager.gd
  60. 37 0
      scene/entity/aoe.tscn
  61. 139 0
      scene/entity/base_plant.gd
  62. 13 0
      scene/entity/big_tree.tscn
  63. 41 0
      scene/entity/bullet.gd
  64. 19 0
      scene/entity/bullet.tscn
  65. 9 0
      scene/entity/carrot.gd
  66. 47 0
      scene/entity/carrot.tscn
  67. 49 0
      scene/entity/carrot2.tscn
  68. 49 0
      scene/entity/carrot3.tscn
  69. 45 0
      scene/entity/carrot4.tscn
  70. 28 0
      scene/entity/carrot_gun.gd
  71. 10 0
      scene/entity/cucumber.gd
  72. 10 0
      scene/entity/dragon.gd
  73. 14 0
      scene/entity/missdemandrake.gd
  74. 48 0
      scene/entity/missdemandrake.tscn
  75. 16 0
      scene/entity/onion.gd
  76. 5 0
      scene/entity/pc.gd
  77. 16 0
      scene/entity/range_indicator.gd
  78. 10 0
      scene/entity/ri.tscn
  79. 192 0
      scene/entity/ufo.gd
  80. 97 0
      scene/entity/ufo_1.tscn
  81. 91 0
      scene/entity/ufo_2.tscn
  82. 105 0
      scene/entity/ufo_2_big.tscn
  83. 89 0
      scene/entity/ufo_3.tscn
  84. 96 0
      scene/entity/ufo_4.tscn
  85. 36 0
      scene/entity/ufo_ast.gd
  86. 94 0
      scene/entity/ufo_ast.tscn
  87. 16 0
      scene/entity/wheat.gd
  88. 39 0
      scene/entity/wheat.tscn
  89. 22 0
      scene/pause_menu/pause_menu.gd
  90. 2463 0
      scene/pause_menu/pause_menu.tscn
  91. 15 0
      scene/pause_menu/vol.gd
  92. 14 0
      scene/pause_menu/vsync.gd
  93. 22 0
      scene/pause_menu/window_mode.gd
  94. 19 0
      scene/snd/snd_listener.tscn
  95. 20 0
      scene/ui/plant_button.gd
  96. 69 0
      scene/ui/plant_button.tscn
  97. 37 0
      scene/ui/plant_button_root.gd
  98. 30 0
      scene/ui/speedrun_timer.gd
  99. 17 0
      scene/ui/speedrun_timer.tscn
  100. 0 0
      snd/mus/ld52-001.ogg

+ 2 - 0
.gitattributes

@@ -0,0 +1,2 @@
+# Normalize EOL for all files that Git considers text files.
+* text=auto eol=lf

+ 6 - 0
.gitignore

@@ -0,0 +1,6 @@
+# Godot 4+ specific ignores
+.godot/
+working/
+server/
+export/
+*.import

+ 1 - 0
README.md

@@ -1,2 +1,3 @@
 # ld52-growin-ballistic
 
+https://ldjam.com/events/ludum-dare/52/growin-ballistic

+ 21 - 0
addons/fake_parallax/fake_parallax.gd

@@ -0,0 +1,21 @@
+@tool
+class_name FakeParallax
+extends Node2D
+
+@export  var rate = 0.0
+@onready var base_position = get_position()
+@onready var camera = get_tree().get_root().find_child("Camera", true, false)
+var notifier: VisibleOnScreenNotifier2D = VisibleOnScreenNotifier2D.new()
+
+func _ready():
+    if camera and !Engine.is_editor_hint():
+        notifier.set_rect(Rect2(Vector2(-1920.0, -1080.0), Vector2(3840.0, 2160.0)))
+        add_child(notifier)
+        camera.connect("camera_moved", _update)
+        _update(true)
+
+func _update(force: bool = false):
+    if force or notifier.is_on_screen():
+        if camera:
+            var delta = camera.get_screen_center_position() - base_position 
+            set_position(base_position + delta * rate)

BIN
addons/fake_parallax/icon.png


+ 7 - 0
addons/fake_parallax/plugin.cfg

@@ -0,0 +1,7 @@
+[plugin]
+
+name="Fake Parallax"
+description=""
+author="nairobi"
+version="1.0"
+script="plugin.gd"

+ 8 - 0
addons/fake_parallax/plugin.gd

@@ -0,0 +1,8 @@
+@tool
+extends EditorPlugin
+
+func _enter_tree():
+    add_custom_type("FakeParallax", "Node2D", preload("fake_parallax.gd"), preload("icon.png"))
+
+func _exit_tree():
+    remove_custom_type("FakeParallax")

+ 73 - 0
default_bus_layout.tres

@@ -0,0 +1,73 @@
+[gd_resource type="AudioBusLayout" load_steps=5 format=3 uid="uid://bg21bj1tf25p0"]
+
+[sub_resource type="AudioEffectReverb" id="AudioEffectReverb_dawug"]
+resource_name = "Reverb"
+room_size = 0.3
+wet = 0.28
+
+[sub_resource type="AudioEffectStereoEnhance" id="AudioEffectStereoEnhance_db7bl"]
+resource_name = "StereoEnhance"
+pan_pullout = 1.42
+surround = 0.1
+
+[sub_resource type="AudioEffectPhaser" id="AudioEffectPhaser_v6n8b"]
+resource_name = "Phaser"
+feedback = 0.4
+
+[sub_resource type="AudioEffectStereoEnhance" id="AudioEffectStereoEnhance_xnnxb"]
+resource_name = "StereoEnhance"
+pan_pullout = 1.24
+surround = 0.34
+
+[resource]
+bus/0/volume_db = -5.04224
+bus/1/name = &"SFX"
+bus/1/solo = false
+bus/1/mute = false
+bus/1/bypass_fx = false
+bus/1/volume_db = -0.912641
+bus/1/send = &"Master"
+bus/2/name = &"Music"
+bus/2/solo = false
+bus/2/mute = false
+bus/2/bypass_fx = false
+bus/2/volume_db = -0.708218
+bus/2/send = &"Master"
+bus/3/name = &"Voice"
+bus/3/solo = false
+bus/3/mute = false
+bus/3/bypass_fx = false
+bus/3/volume_db = 0.00504494
+bus/3/send = &"Master"
+bus/4/name = &"Music0"
+bus/4/solo = false
+bus/4/mute = false
+bus/4/bypass_fx = false
+bus/4/volume_db = 0.0
+bus/4/send = &"Music"
+bus/4/effect/0/effect = SubResource("AudioEffectReverb_dawug")
+bus/4/effect/0/enabled = true
+bus/5/name = &"Music1"
+bus/5/solo = false
+bus/5/mute = false
+bus/5/bypass_fx = false
+bus/5/volume_db = 0.0
+bus/5/send = &"Music"
+bus/5/effect/0/effect = SubResource("AudioEffectStereoEnhance_db7bl")
+bus/5/effect/0/enabled = true
+bus/6/name = &"Music2"
+bus/6/solo = false
+bus/6/mute = false
+bus/6/bypass_fx = false
+bus/6/volume_db = 0.0
+bus/6/send = &"Music"
+bus/6/effect/0/effect = SubResource("AudioEffectPhaser_v6n8b")
+bus/6/effect/0/enabled = true
+bus/7/name = &"Music3"
+bus/7/solo = false
+bus/7/mute = false
+bus/7/bypass_fx = false
+bus/7/volume_db = 0.0
+bus/7/send = &"Music"
+bus/7/effect/0/effect = SubResource("AudioEffectStereoEnhance_xnnxb")
+bus/7/effect/0/enabled = true

+ 68 - 0
export_presets.cfg

@@ -0,0 +1,68 @@
+[preset.0]
+
+name="Web"
+platform="Web"
+runnable=true
+custom_features=""
+export_filter="all_resources"
+include_filter=""
+exclude_filter=""
+export_path="export/html/ld52.html"
+encryption_include_filters=""
+encryption_exclude_filters=""
+encrypt_pck=false
+encrypt_directory=false
+script_export_mode=1
+script_encryption_key=""
+
+[preset.0.options]
+
+custom_template/debug=""
+custom_template/release=""
+variant/extensions_support=false
+vram_texture_compression/for_desktop=true
+vram_texture_compression/for_mobile=false
+html/export_icon=true
+html/custom_html_shell=""
+html/head_include=""
+html/canvas_resize_policy=2
+html/focus_canvas_on_start=true
+html/experimental_virtual_keyboard=false
+progressive_web_app/enabled=false
+progressive_web_app/offline_page=""
+progressive_web_app/display=1
+progressive_web_app/orientation=0
+progressive_web_app/icon_144x144=""
+progressive_web_app/icon_180x180=""
+progressive_web_app/icon_512x512=""
+progressive_web_app/background_color=Color(0, 0, 0, 1)
+
+[preset.1]
+
+name="Linux/X11"
+platform="Linux/X11"
+runnable=true
+custom_features=""
+export_filter="all_resources"
+include_filter=""
+exclude_filter=""
+export_path="export/ln/ld52.x86_64"
+encryption_include_filters=""
+encryption_exclude_filters=""
+encrypt_pck=false
+encrypt_directory=false
+script_export_mode=1
+script_encryption_key=""
+
+[preset.1.options]
+
+custom_template/debug=""
+custom_template/release=""
+debug/export_console_script=0
+binary_format/embed_pck=false
+texture_format/bptc=false
+texture_format/s3tc=true
+texture_format/etc=false
+texture_format/etc2=false
+texture_format/no_bptc_fallbacks=true
+binary_format/architecture="x86_64"

File diff suppressed because it is too large
+ 1 - 0
icon.svg


+ 210 - 0
project.godot

@@ -0,0 +1,210 @@
+; Engine configuration file.
+; It's best edited using the editor UI and not directly,
+; since the parameters that go here are not all obvious.
+;
+; Format:
+;   [section] ; section goes between []
+;   param=value ; assign values to parameters
+
+config_version=5
+
+_global_script_classes=[{
+"base": "CharacterBody2D",
+"class": &"Bullet",
+"language": &"GDScript",
+"path": "res://scene/entity/bullet.gd"
+}, {
+"base": "Node2D",
+"class": &"FakeParallax",
+"language": &"GDScript",
+"path": "res://addons/fake_parallax/fake_parallax.gd"
+}, {
+"base": "Sprite2D",
+"class": &"Gun",
+"language": &"GDScript",
+"path": "res://scene/entity/carrot_gun.gd"
+}, {
+"base": "Plant",
+"class": &"Mandrake",
+"language": &"GDScript",
+"path": "res://scene/entity/missdemandrake.gd"
+}, {
+"base": "CharacterBody2D",
+"class": &"Plant",
+"language": &"GDScript",
+"path": "res://scene/entity/base_plant.gd"
+}, {
+"base": "Area2D",
+"class": &"Slot",
+"language": &"GDScript",
+"path": "res://scene/core/slot.gd"
+}, {
+"base": "CharacterBody2D",
+"class": &"UFO",
+"language": &"GDScript",
+"path": "res://scene/entity/ufo.gd"
+}, {
+"base": "Node2D",
+"class": &"Wave",
+"language": &"GDScript",
+"path": "res://scene/core/wave.gd"
+}, {
+"base": "Node2D",
+"class": &"WaveManager",
+"language": &"GDScript",
+"path": "res://scene/core/wave_manager.gd"
+}]
+_global_script_class_icons={
+"Bullet": "",
+"FakeParallax": "",
+"Gun": "",
+"Mandrake": "",
+"Plant": "",
+"Slot": "",
+"UFO": "",
+"Wave": "",
+"WaveManager": ""
+}
+
+[application]
+
+config/name="ld52"
+run/main_scene="res://scene/core/root.tscn"
+config/features=PackedStringArray("4.0", "GL Compatibility")
+config/icon="res://icon.svg"
+
+[debug]
+
+gdscript/warnings/unused_parameter=0
+
+[editor_plugins]
+
+enabled=PackedStringArray("res://addons/fake_parallax/plugin.cfg")
+
+[input]
+
+ui_accept={
+"deadzone": 0.5,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194309,"physical_keycode":0,"unicode":4194309,"echo":false,"script":null)
+, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194310,"physical_keycode":0,"unicode":4194310,"echo":false,"script":null)
+, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":32,"physical_keycode":0,"unicode":32,"echo":false,"script":null)
+, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":0,"pressure":0.0,"pressed":true,"script":null)
+]
+}
+ui_select={
+"deadzone": 0.5,
+"events": [Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":3,"pressure":0.0,"pressed":false,"script":null)
+, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":32,"physical_keycode":0,"unicode":32,"echo":false,"script":null)
+, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":0,"pressure":0.0,"pressed":true,"script":null)
+]
+}
+ui_cancel={
+"deadzone": 0.5,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194305,"physical_keycode":0,"unicode":4194305,"echo":false,"script":null)
+, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":1,"pressure":0.0,"pressed":true,"script":null)
+]
+}
+ui_left={
+"deadzone": 0.5,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194319,"physical_keycode":0,"unicode":4194319,"echo":false,"script":null)
+, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":13,"pressure":0.0,"pressed":false,"script":null)
+, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":0,"axis_value":-1.0,"script":null)
+]
+}
+ui_right={
+"deadzone": 0.5,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194321,"physical_keycode":0,"unicode":0,"echo":false,"script":null)
+, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":14,"pressure":0.0,"pressed":false,"script":null)
+, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":0,"axis_value":1.0,"script":null)
+]
+}
+ui_up={
+"deadzone": 0.5,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194320,"physical_keycode":0,"unicode":4194320,"echo":false,"script":null)
+, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":11,"pressure":0.0,"pressed":false,"script":null)
+, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":1,"axis_value":-1.0,"script":null)
+]
+}
+ui_down={
+"deadzone": 0.5,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194322,"physical_keycode":0,"unicode":4194322,"echo":false,"script":null)
+, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":12,"pressure":0.0,"pressed":false,"script":null)
+, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":1,"axis_value":1.0,"script":null)
+]
+}
+pause={
+"deadzone": 0.5,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194305,"unicode":0,"echo":false,"script":null)
+, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":6,"pressure":0.0,"pressed":false,"script":null)
+]
+}
+zoom_in={
+"deadzone": 0.5,
+"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":4,"pressed":false,"double_click":false,"script":null)
+]
+}
+zoom_out={
+"deadzone": 0.5,
+"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":5,"pressed":false,"double_click":false,"script":null)
+]
+}
+screen_drag={
+"deadzone": 0.5,
+"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":3,"pressed":false,"double_click":false,"script":null)
+, Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":2,"pressed":false,"double_click":false,"script":null)
+]
+}
+lmb={
+"deadzone": 0.5,
+"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":1,"pressed":false,"double_click":false,"script":null)
+]
+}
+rmb={
+"deadzone": 0.5,
+"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":2,"pressed":false,"double_click":false,"script":null)
+]
+}
+cash_cheat={
+"deadzone": 0.5,
+"events": [null, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":67,"unicode":0,"echo":false,"script":null)
+]
+}
+wave_cheat={
+"deadzone": 0.5,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":125,"unicode":0,"echo":false,"script":null)
+]
+}
+hk1={
+"deadzone": 0.5,
+"events": []
+}
+hk2={
+"deadzone": 0.5,
+"events": []
+}
+hk3={
+"deadzone": 0.5,
+"events": []
+}
+hk4={
+"deadzone": 0.5,
+"events": []
+}
+hk6={
+"deadzone": 0.5,
+"events": []
+}
+hk5={
+"deadzone": 0.5,
+"events": []
+}
+
+[rendering]
+
+renderer/rendering_method="gl_compatibility"
+anti_aliasing/screen_space_roughness_limiter/amount=0.6
+environment/defaults/default_clear_color=Color(0.498039, 0.172549, 0.172549, 1)
+anti_aliasing/quality/msaa_2d=3
+anti_aliasing/quality/screen_space_aa=1
+anti_aliasing/quality/use_taa=true
+anti_aliasing/quality/use_debanding=true

BIN
res/asteroid.png


BIN
res/bullet.png


BIN
res/carrot_body_0.png


BIN
res/carrot_body_1.png


BIN
res/carrot_gun.png


BIN
res/carrot_icon.png


BIN
res/carrot_icon_1.png


BIN
res/circle.png


BIN
res/cucumber.png


BIN
res/dragonfruit.png


BIN
res/fg.png


BIN
res/fgo.png


BIN
res/fork.png


BIN
res/missdemandrake.png


BIN
res/missdemandrake_eyes.png


BIN
res/missdemandrake_hair.png


BIN
res/missdemandrake_icon.png


BIN
res/nothing.png


BIN
res/pbar.png


BIN
res/pbar2.png


BIN
res/shallot.png


BIN
res/slot.png


BIN
res/star.png


BIN
res/tree.png


BIN
res/uoh.png


BIN
res/wheat.png


BIN
res/witch_ufo.png


BIN
res/witch_ufo_bot.png


BIN
res/witch_ufo_top.png


+ 72 - 0
scene/core/camera.gd

@@ -0,0 +1,72 @@
+extends Camera2D
+signal camera_moved
+
+var SPEED = 4000
+var DRAG_SPEED = 4.0
+var ZOOM_SPEED = 12.0
+
+var max_zoom = 1.0
+var min_zoom = 0.15
+var previous_mouse_position = Vector2(-1, -1)
+@onready var previous_position: Vector2 = get_screen_center_position()
+@onready var current_zoom = get_zoom().x
+
+func _ready():
+    update_sound_players()
+
+func _input(event: InputEvent):
+    if event is InputEventMouseMotion and Input.is_action_pressed("screen_drag"):
+#        if previous_mouse_position == Vector2(-1, -1):
+#            previous_mouse_position = get_viewport().get_mouse_position()
+#        Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
+        #set_screen_center_position(center - event.relative * DRAG_SPEED)
+        var pos = get_target_position() - event.relative * DRAG_SPEED
+        set_position(pos)
+        fix_borders()
+        #move_local_x(-event.relative.x * DRAG_SPEED)
+        #move_local_y(-event.relative.y * DRAG_SPEED)
+#    elif previous_mouse_position != Vector2(-1, -1):
+#        Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
+#        get_viewport().warp_mouse(previous_mouse_position)
+#        previous_mouse_position = Vector2(-1, -1)
+
+func _process(delta):
+    #print(get_screen_center_position(), " ", get_position(), " ", get_target_position())
+    var pos = get_tree().get_root().get_mouse_position()
+    if pos.x < 20:
+        #move_local_x(delta * -SPEED)
+        pass
+    
+    if Input.is_action_just_released("zoom_in"):
+        current_zoom *= (1 + delta * ZOOM_SPEED)
+        current_zoom = min(max_zoom, current_zoom)
+        set_zoom(Vector2(current_zoom, current_zoom))
+        update_sound_players()
+        fix_borders()
+    if Input.is_action_just_released("zoom_out"):
+        current_zoom *= (1 - delta * ZOOM_SPEED)
+        current_zoom = max(min_zoom, current_zoom)
+        set_zoom(Vector2(current_zoom, current_zoom))
+        update_sound_players()
+        fix_borders()
+
+    var new_position = get_screen_center_position()
+    if previous_position != new_position:
+        emit_signal("camera_moved")
+    previous_position = get_screen_center_position()
+    
+func update_sound_players():
+    var players = get_tree().get_nodes_in_group("sound_player")
+    var dist = Vector2(DisplayServer.window_get_size()) / zoom
+    for sound_player in players:
+        sound_player.set_max_distance(dist.x)
+
+# Fix the camera lock being 🌠🌠 fucking stupid 🌠🌠
+func fix_borders():
+    var pos = get_position()
+    var rect = Vector2(DisplayServer.window_get_size()) / zoom
+    pos.x = max(pos.x, limit_left + rect.x / 2.0)
+    pos.x = min(pos.x, limit_right - rect.x / 2.0)
+    pos.y = max(pos.y, limit_top + rect.y / 2.0)
+    pos.y = min(pos.y, limit_bottom - rect.y / 2.0)
+    set_position(pos)

+ 25 - 0
scene/core/economy.gd

@@ -0,0 +1,25 @@
+extends Node
+
+var wheat: int = 0
+var disable_leaderboards: bool = false
+@onready var wheat_label: Label = $"../../../UILayer/UI/Wheat/HBoxContainer/Label"
+@onready var no_time_for_signals = $"../../../UILayer/UI/Plants"
+
+func _ready():
+    disable_leaderboards = false
+    add(19)
+    
+func _input(event: InputEvent):
+    if event.is_action_pressed("cash_cheat"):
+        disable_leaderboards = true
+        add(10)
+
+func add(count: int) -> bool:
+    wheat += count
+    if wheat < 0:
+        wheat -= count
+        return false
+    wheat_label.set_text(str(wheat))
+    for i in no_time_for_signals.get_children():
+        i.updoot(wheat)
+    return true

+ 26 - 0
scene/core/main.gd

@@ -0,0 +1,26 @@
+extends Node2D
+
+var dead = false
+
+func _ready():
+    $VictoryCheckTimer.connect("timeout", victory_check)
+    $"../../UILayer/UI/DefeatScreen".hide()
+    $VictoryCheckTimer.start()
+
+func are_slots_done() -> bool:
+    for slot_array in $SlotArrays.get_children():
+        for slot in slot_array.get_children():
+            if slot.plant == null:
+                return false
+    return true
+
+func victory_check():
+    if $Plants.get_children().size() == 0:
+        dead = true
+        set_process(false)
+        $"../../UILayer/UI/DefeatScreen".show()
+        $"../../UILayer/UI/SpeedrunTimer".stop()
+    if ($Waves.is_done() and $UFOs.get_children().size() == 0) or are_slots_done():
+        set_process(false)
+        $"../../UILayer/UI/VictoryScreen".show()
+        $"../../UILayer/UI/SpeedrunTimer".stop()

File diff suppressed because it is too large
+ 314 - 0
scene/core/main.tscn


+ 86 - 0
scene/core/main_menu.tscn

@@ -0,0 +1,86 @@
+[gd_scene load_steps=2 format=3 uid="uid://b4i07ara0h5k7"]
+
+[ext_resource type="Theme" uid="uid://dswou24s4dr5e" path="res://scene/core/main_menu_thenme.tres" id="1_f7kuq"]
+
+[node name="MainMenu" type="Control"]
+layout_mode = 3
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+
+[node name="MarginContainer" type="MarginContainer" parent="."]
+anchors_preset = 1
+anchor_left = 1.0
+anchor_right = 1.0
+offset_left = -40.0
+offset_bottom = 40.0
+grow_horizontal = 0
+theme_override_constants/margin_top = 64
+theme_override_constants/margin_right = 64
+
+[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"]
+offset_top = 64.0
+offset_right = 250.0
+offset_bottom = 293.0
+
+[node name="Label" type="RichTextLabel" parent="MarginContainer/VBoxContainer"]
+custom_minimum_size = Vector2(250, 0)
+offset_right = 250.0
+offset_bottom = 159.0
+bbcode_enabled = true
+text = "[center][font size=40]GROWIN' 
+BALLISTIC
+[/font][font size=18]LD52 Compo[/font][/center]
+
+"
+fit_content_height = true
+
+[node name="Start" type="Button" parent="MarginContainer/VBoxContainer"]
+custom_minimum_size = Vector2(80, 0)
+offset_left = 85.0
+offset_top = 163.0
+offset_right = 165.0
+offset_bottom = 194.0
+size_flags_horizontal = 4
+size_flags_vertical = 4
+theme = ExtResource("1_f7kuq")
+text = "Start"
+
+[node name="Settings" type="Button" parent="MarginContainer/VBoxContainer"]
+custom_minimum_size = Vector2(80, 0)
+offset_left = 85.0
+offset_top = 198.0
+offset_right = 165.0
+offset_bottom = 229.0
+size_flags_horizontal = 4
+size_flags_vertical = 4
+theme = ExtResource("1_f7kuq")
+text = "Settings
+"
+
+[node name="MarginContainer2" type="MarginContainer" parent="."]
+anchors_preset = 2
+anchor_top = 1.0
+anchor_bottom = 1.0
+offset_top = -364.0
+offset_right = 364.0
+grow_vertical = 0
+theme_override_constants/margin_left = 64
+theme_override_constants/margin_top = 64
+theme_override_constants/margin_right = 64
+theme_override_constants/margin_bottom = 64
+
+[node name="Label" type="RichTextLabel" parent="MarginContainer2"]
+custom_minimum_size = Vector2(300, 200)
+offset_left = 64.0
+offset_top = 64.0
+offset_right = 364.0
+offset_bottom = 300.0
+bbcode_enabled = true
+text = "[center]Attention, buds![/center]
+
+The space farmers are coming for us, but fret not, for we have finally evolved biological weaponry.
+
+For thousands of years, we feared The Harvest Season for our lives. Now it's finally time for revenge!! Don't get harvested."

File diff suppressed because it is too large
+ 1609 - 0
scene/core/main_menu_thenme.tres


+ 62 - 0
scene/core/outline.gdshader

@@ -0,0 +1,62 @@
+shader_type canvas_item;
+
+uniform vec4 color : source_color = vec4(1.0);
+uniform float width : hint_range(0, 100) = 1.0;
+uniform int pattern : hint_range(0, 2) = 0; // diamond, circle, square
+uniform bool inside = false;
+uniform bool add_margins = true; // only useful when inside is false
+
+void vertex() {
+	if (add_margins) {
+		VERTEX += (UV * 2.0 - 1.0) * width;
+	}
+}
+
+bool hasContraryNeighbour(vec2 uv, vec2 texture_pixel_size, sampler2D texture) {
+	for (float i = -ceil(width); i <= ceil(width); i++) {
+		float x = abs(i) > width ? width * sign(i) : i;
+		float offset;
+		
+		if (pattern == 0) {
+			offset = width - abs(x);
+		} else if (pattern == 1) {
+			offset = floor(sqrt(pow(width + 0.5, 2) - x * x));
+		} else if (pattern == 2) {
+			offset = width;
+		}
+		
+		for (float j = -ceil(offset); j <= ceil(offset); j++) {
+			float y = abs(j) > offset ? offset * sign(j) : j;
+			vec2 xy = uv + texture_pixel_size * vec2(x, y);
+			
+			if ((xy != clamp(xy, vec2(0.0), vec2(1.0)) || texture(texture, xy).a == 0.0) == inside) {
+				return true;
+			}
+		}
+	}
+	
+	return false;
+}
+
+void fragment() {
+	vec2 uv = UV;
+	
+	if (add_margins) {
+		vec2 texture_pixel_size = vec2(1.0) / (vec2(1.0) / TEXTURE_PIXEL_SIZE + vec2(width * 2.0));
+		
+		uv = (uv - texture_pixel_size * width) * TEXTURE_PIXEL_SIZE / texture_pixel_size;
+		
+		if (uv != clamp(uv, vec2(0.0), vec2(1.0))) {
+			COLOR.a = 0.0;
+		} else {
+			COLOR = texture(TEXTURE, uv);
+		}
+	} else {
+		COLOR = texture(TEXTURE, uv);
+	}
+	
+	if ((COLOR.a > 0.0) == inside && hasContraryNeighbour(uv, TEXTURE_PIXEL_SIZE, TEXTURE)) {
+		COLOR.rgb = inside ? mix(COLOR.rgb, color.rgb, color.a) : color.rgb;
+		COLOR.a += (1.0 - COLOR.a) * color.a;
+	}
+}

+ 5 - 0
scene/core/pc1.gd

@@ -0,0 +1,5 @@
+extends AudioStreamPlayer
+
+func play(from_position: float = 0.0) -> void:
+    set_pitch_scale(randf_range(1.1, 1.4))
+    super(from_position)

+ 5 - 0
scene/core/restart_button.gd

@@ -0,0 +1,5 @@
+extends Button
+
+func _on_pressed():
+    var root = get_tree().get_root().get_child(0)
+    root.begin(true)

+ 33 - 0
scene/core/root.gd

@@ -0,0 +1,33 @@
+extends Control
+
+var main_menu_beaten: bool = false
+
+func _ready():
+    $UILayer/MainMenu.find_child("Start", true, false).connect("pressed", beat_main_menu)
+    $UILayer/MainMenu.find_child("Settings", true, false).connect("pressed", $PauseMenuLayer/PauseMenu.show)
+    begin(false)
+
+func begin(restart: bool):
+    if restart:
+        $MainLayer.remove_child($MainLayer.get_child(0))
+        $MainLayer.add_child(preload("res://scene/core/main.tscn").instantiate())
+    
+    find_child("VictoryScreen", true, false).hide()
+    find_child("DefeatScreen", true, false).hide()
+    find_child("SpeedrunTimer", true, false).reset()
+    main_menu_beaten = false
+    get_tree().paused = true
+    $"UILayer/UI".hide()
+    $UILayer/MainMenu.show()
+
+func _input(input: InputEvent):
+    if input.is_action_pressed("pause") and !get_tree().paused:
+        get_tree().paused = true
+        $PauseMenuLayer/PauseMenu.show()
+
+func beat_main_menu():
+    get_tree().paused = false
+    main_menu_beaten = true
+    $"UILayer/UI".show()
+    $UILayer/MainMenu.hide()
+    $PauseMenuLayer/PauseMenu.set_process_input(true)

+ 41 - 0
scene/core/root.tscn

@@ -0,0 +1,41 @@
+[gd_scene load_steps=6 format=3 uid="uid://clw8hc3ku4wn0"]
+
+[ext_resource type="Script" path="res://scene/core/root.gd" id="1_m2nrn"]
+[ext_resource type="PackedScene" uid="uid://blcuyr3jmgqjn" path="res://scene/core/ui.tscn" id="1_utmxi"]
+[ext_resource type="PackedScene" uid="uid://bxvkoxctllthy" path="res://scene/core/main.tscn" id="2_bmam3"]
+[ext_resource type="PackedScene" uid="uid://dibbva5y1akgv" path="res://scene/pause_menu/pause_menu.tscn" id="2_o3o64"]
+[ext_resource type="PackedScene" uid="uid://b4i07ara0h5k7" path="res://scene/core/main_menu.tscn" id="4_ui5jm"]
+
+[node name="Root" type="Control"]
+process_mode = 3
+layout_mode = 3
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+mouse_filter = 1
+script = ExtResource("1_m2nrn")
+
+[node name="MainLayer" type="CanvasLayer" parent="."]
+process_mode = 1
+layer = 0
+follow_viewport_enabled = true
+
+[node name="Main" parent="MainLayer" instance=ExtResource("2_bmam3")]
+
+[node name="UILayer" type="CanvasLayer" parent="."]
+process_mode = 1
+
+[node name="UI" parent="UILayer" instance=ExtResource("1_utmxi")]
+mouse_filter = 2
+
+[node name="MainMenu" parent="UILayer" instance=ExtResource("4_ui5jm")]
+process_mode = 2
+
+[node name="PauseMenuLayer" type="CanvasLayer" parent="."]
+process_mode = 2
+layer = 2
+
+[node name="PauseMenu" parent="PauseMenuLayer" instance=ExtResource("2_o3o64")]
+visible = false

+ 55 - 0
scene/core/selected_item.gd

@@ -0,0 +1,55 @@
+extends Node2D
+
+@onready var slots = $"../SlotArrays"
+var selected_item: Node = null
+
+func _input(event: InputEvent):
+    if event.is_action_pressed("rmb"):
+        if selected_item != null:
+            remove_child(selected_item)
+            selected_item = null
+        slots.hide()
+
+func _ready():
+    for slot_array in slots.get_children():
+        for slot in slot_array.get_children():
+            slot.connect("clicked", _on_slot_clicked)
+    slots.hide()
+    
+    # Starting carrots
+    selected_item = preload("res://scene/entity/carrot.tscn").instantiate()
+    $"../Economy".add(30)
+    _on_slot_clicked(slots.get_child(0).get_child(2))
+    _on_slot_clicked(slots.get_child(0).get_child(3))
+    _on_slot_clicked(slots.get_child(0).get_child(4))
+    selected_item = null
+
+func _process(delta):
+    if selected_item != null:
+        selected_item.set_position(get_global_mouse_position())
+        
+func _on_slot_clicked(slot: Slot):
+    if selected_item != null:
+        if slot.plant == null:
+            if $"../Economy".add(-selected_item.cost):
+                var dup = selected_item.duplicate()
+                slot.set_plant(dup)
+                dup.set_process(true)
+                dup.dead = false
+                $"../Plants".add_child(dup)
+                if dup is Mandrake:
+                    $Coin.play()
+
+func set_item(item: Node):
+    if selected_item != null and selected_item.get_class() == item.get_class():
+        remove_child(selected_item)
+        selected_item = null
+        slots.hide()
+    else:
+        if selected_item != null:
+            remove_child(selected_item)
+        selected_item = item
+        slots.show()
+        add_child(selected_item)
+        selected_item.set_process(false)
+        selected_item.dead = true

+ 29 - 0
scene/core/slot.gd

@@ -0,0 +1,29 @@
+extends Area2D
+class_name Slot
+signal clicked(slot: Slot)
+
+var i = 0
+var plant = null
+
+func _ready():
+    set_pickable(true)
+    connect("input_event", _on_input_event)
+    connect("mouse_entered", _on_mouse_entered)
+    connect("mouse_exited", _on_mouse_exited)
+
+func _on_input_event(viewport: Node, event: InputEvent, shape_idx: int):
+    if event.is_action_released("lmb"):
+        i += 1
+        if i == 2:
+            emit_signal("clicked", self)
+            i = 0
+        
+func _on_mouse_entered():
+    $Slot.set_modulate(Color(1.0, 1.0, 1.0, 1.0))
+
+func _on_mouse_exited():
+    $Slot.set_modulate(Color(1.0, 1.0, 1.0, 0.5))
+
+func set_plant(plant_: Node):
+    plant = plant_
+    plant.set_position(get_global_position())

+ 20 - 0
scene/core/slot.tscn

@@ -0,0 +1,20 @@
+[gd_scene load_steps=4 format=3 uid="uid://bxjjn0hk6y5x7"]
+
+[ext_resource type="Texture2D" uid="uid://m172by16xtq7" path="res://res/slot.png" id="1_64y0s"]
+[ext_resource type="Script" path="res://scene/core/slot.gd" id="1_xj6kk"]
+
+[sub_resource type="RectangleShape2D" id="RectangleShape2D_0c04m"]
+size = Vector2(140, 247)
+
+[node name="Slot" type="Area2D"]
+script = ExtResource("1_xj6kk")
+
+[node name="Slot" type="Sprite2D" parent="."]
+modulate = Color(1, 1, 1, 0.501961)
+z_index = 1000
+scale = Vector2(0.3, 0.3)
+texture = ExtResource("1_64y0s")
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
+position = Vector2(0, -105.5)
+shape = SubResource("RectangleShape2D_0c04m")

+ 29 - 0
scene/core/slot_array.gd

@@ -0,0 +1,29 @@
+@tool
+extends Node2D
+
+@export var count = 1: 
+    set(value):
+        count = value
+        redraw()
+@export var separation = 200:
+    set(value):
+        separation = value
+        redraw()
+@export var particles: PackedScene:
+    set(value):
+        particles = value
+        redraw()
+
+func redraw():
+    for n in get_children():
+        remove_child(n)
+    if particles != null:
+        var start_pos = 0.0
+        if count % 2 == 1:
+            start_pos = -floor(count / 2.0) * separation  
+        else:
+            start_pos = (-(count / 2.0) + 0.5) * separation
+        for i in range(0, count):
+            var child = particles.instantiate()
+            child.set_position(Vector2(start_pos + i * separation, 0))
+            add_child(child)

+ 377 - 0
scene/core/ui.tscn

@@ -0,0 +1,377 @@
+[gd_scene load_steps=25 format=3 uid="uid://blcuyr3jmgqjn"]
+
+[ext_resource type="PackedScene" uid="uid://2wtd5v2wm5ym" path="res://scene/ui/speedrun_timer.tscn" id="1_aoia5"]
+[ext_resource type="Texture2D" uid="uid://0f8gj2t81y04" path="res://res/missdemandrake_icon.png" id="2_ktgqv"]
+[ext_resource type="Texture2D" uid="uid://cankh6gqcfwh8" path="res://res/wheat.png" id="2_okcwu"]
+[ext_resource type="PackedScene" uid="uid://d0myc3w8eieve" path="res://scene/ui/plant_button.tscn" id="2_veu5b"]
+[ext_resource type="Texture2D" uid="uid://ml2fn217nq0a" path="res://res/carrot_icon.png" id="3_hykl0"]
+[ext_resource type="PackedScene" uid="uid://barkhw1dcvol6" path="res://scene/entity/carrot.tscn" id="4_qd155"]
+[ext_resource type="PackedScene" uid="uid://dhc4lumda0bk5" path="res://scene/entity/missdemandrake.tscn" id="6_benw2"]
+[ext_resource type="Texture2D" uid="uid://boqf8yjg8vjj" path="res://res/carrot_icon_1.png" id="6_laq2b"]
+[ext_resource type="PackedScene" uid="uid://7xbagi7msusx" path="res://scene/entity/carrot2.tscn" id="7_xdref"]
+[ext_resource type="Theme" uid="uid://dswou24s4dr5e" path="res://scene/core/main_menu_thenme.tres" id="8_402o7"]
+[ext_resource type="Script" path="res://scene/core/restart_button.gd" id="8_ao4uf"]
+[ext_resource type="Texture2D" uid="uid://c6g3vxs1w2cyx" path="res://res/cucumber.png" id="8_yg5q2"]
+[ext_resource type="PackedScene" uid="uid://bxrjfsowqkb86" path="res://scene/entity/carrot3.tscn" id="9_si7tt"]
+[ext_resource type="Texture2D" uid="uid://cx5md40xbjcwp" path="res://res/dragonfruit.png" id="10_vimv2"]
+[ext_resource type="PackedScene" uid="uid://bam5e7b0rnfnm" path="res://scene/entity/carrot4.tscn" id="11_t5qna"]
+[ext_resource type="Texture2D" uid="uid://qtverddtembb" path="res://res/shallot.png" id="12_12d5p"]
+[ext_resource type="PackedScene" uid="uid://b7cuabx3ghe01" path="res://scene/entity/aoe.tscn" id="13_1l6ff"]
+
+[sub_resource type="ImageTexture" id="ImageTexture_pcdim"]
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_x4eiv"]
+content_margin_left = 4.0
+content_margin_top = 4.0
+content_margin_right = 4.0
+content_margin_bottom = 4.0
+bg_color = Color(1, 1, 1, 0)
+corner_radius_top_left = 10
+corner_radius_top_right = 10
+corner_radius_bottom_right = 10
+corner_radius_bottom_left = 10
+corner_detail = 6
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_asdkn"]
+content_margin_left = 4.0
+content_margin_top = 4.0
+content_margin_right = 4.0
+content_margin_bottom = 4.0
+bg_color = Color(1, 1, 1, 0.75)
+corner_radius_top_left = 10
+corner_radius_top_right = 10
+corner_radius_bottom_right = 10
+corner_radius_bottom_left = 10
+corner_detail = 6
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_oa5x8"]
+content_margin_left = 4.0
+content_margin_top = 4.0
+content_margin_right = 4.0
+content_margin_bottom = 4.0
+bg_color = Color(0.75, 0.75, 0.75, 0.75)
+corner_radius_top_left = 10
+corner_radius_top_right = 10
+corner_radius_bottom_right = 10
+corner_radius_bottom_left = 10
+corner_detail = 6
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_tadec"]
+content_margin_left = 4.0
+content_margin_top = 4.0
+content_margin_right = 4.0
+content_margin_bottom = 4.0
+bg_color = Color(0.101961, 0.101961, 0.101961, 0)
+corner_radius_top_left = 10
+corner_radius_top_right = 10
+corner_radius_bottom_right = 10
+corner_radius_bottom_left = 10
+corner_detail = 6
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_gi33v"]
+content_margin_left = 4.0
+content_margin_top = 4.0
+content_margin_right = 4.0
+content_margin_bottom = 4.0
+bg_color = Color(1, 1, 1, 0.75)
+draw_center = false
+border_width_left = 2
+border_width_top = 2
+border_width_right = 2
+border_width_bottom = 2
+corner_radius_top_left = 3
+corner_radius_top_right = 3
+corner_radius_bottom_right = 3
+corner_radius_bottom_left = 3
+corner_detail = 5
+expand_margin_left = 2.0
+expand_margin_top = 2.0
+expand_margin_right = 2.0
+expand_margin_bottom = 2.0
+
+[sub_resource type="Theme" id="Theme_uwr4e"]
+VScrollBar/icons/decrement = SubResource("ImageTexture_pcdim")
+VScrollBar/icons/decrement_highlight = SubResource("ImageTexture_pcdim")
+VScrollBar/icons/decrement_pressed = SubResource("ImageTexture_pcdim")
+VScrollBar/icons/increment = SubResource("ImageTexture_pcdim")
+VScrollBar/icons/increment_highlight = SubResource("ImageTexture_pcdim")
+VScrollBar/icons/increment_pressed = SubResource("ImageTexture_pcdim")
+VScrollBar/styles/grabber = SubResource("StyleBoxFlat_x4eiv")
+VScrollBar/styles/grabber_highlight = SubResource("StyleBoxFlat_asdkn")
+VScrollBar/styles/grabber_pressed = SubResource("StyleBoxFlat_oa5x8")
+VScrollBar/styles/scroll = SubResource("StyleBoxFlat_tadec")
+VScrollBar/styles/scroll_focus = SubResource("StyleBoxFlat_gi33v")
+
+[node name="UI" type="Control"]
+layout_mode = 3
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+
+[node name="SpeedrunTimer" parent="." instance=ExtResource("1_aoia5")]
+anchors_preset = 3
+anchor_left = 1.0
+anchor_right = 1.0
+grow_horizontal = 0
+
+[node name="Wheat" type="MarginContainer" parent="."]
+offset_right = 40.0
+offset_bottom = 40.0
+theme_override_constants/margin_left = 30
+theme_override_constants/margin_top = 30
+
+[node name="HBoxContainer" type="HBoxContainer" parent="Wheat"]
+offset_left = 30.0
+offset_top = 30.0
+offset_right = 105.0
+offset_bottom = 88.0
+
+[node name="TextureRect" type="TextureRect" parent="Wheat/HBoxContainer"]
+custom_minimum_size = Vector2(24, 0)
+offset_right = 24.0
+offset_bottom = 58.0
+texture = ExtResource("2_okcwu")
+ignore_texture_size = true
+stretch_mode = 5
+
+[node name="Label" type="Label" parent="Wheat/HBoxContainer"]
+offset_left = 28.0
+offset_right = 75.0
+offset_bottom = 58.0
+theme_override_font_sizes/font_size = 40
+text = "nil"
+
+[node name="NextWave" type="MarginContainer" parent="."]
+anchors_preset = 1
+anchor_left = 1.0
+anchor_right = 1.0
+offset_left = -105.0
+offset_bottom = 88.0
+grow_horizontal = 0
+theme_override_constants/margin_top = 30
+theme_override_constants/margin_right = 30
+
+[node name="HB" type="HBoxContainer" parent="NextWave"]
+offset_top = 30.0
+offset_right = 132.0
+offset_bottom = 88.0
+
+[node name="Button" type="Button" parent="NextWave/HB"]
+offset_top = 13.0
+offset_right = 90.0
+offset_bottom = 44.0
+size_flags_vertical = 4
+text = "Next wave"
+
+[node name="Label" type="Label" parent="NextWave/HB"]
+offset_left = 94.0
+offset_top = 16.0
+offset_right = 132.0
+offset_bottom = 42.0
+theme_override_font_sizes/font_size = 16
+text = "in nil"
+
+[node name="Log" type="MarginContainer" parent="."]
+anchors_preset = 2
+anchor_top = 1.0
+anchor_bottom = 1.0
+offset_top = -88.0
+offset_right = 105.0
+grow_vertical = 0
+theme_override_constants/margin_left = 30
+theme_override_constants/margin_bottom = 30
+
+[node name="PC" type="PanelContainer" parent="Log"]
+offset_left = 30.0
+offset_right = 246.0
+offset_bottom = 116.0
+
+[node name="MC" type="MarginContainer" parent="Log/PC"]
+offset_right = 216.0
+offset_bottom = 116.0
+theme_override_constants/margin_left = 8
+theme_override_constants/margin_top = 8
+theme_override_constants/margin_right = 8
+theme_override_constants/margin_bottom = 8
+
+[node name="Label" type="RichTextLabel" parent="Log/PC/MC"]
+custom_minimum_size = Vector2(200, 100)
+offset_left = 8.0
+offset_top = 8.0
+offset_right = 208.0
+offset_bottom = 108.0
+theme = SubResource("Theme_uwr4e")
+bbcode_enabled = true
+text = "nil"
+scroll_following = true
+
+[node name="Plants" type="VBoxContainer" parent="."]
+anchors_preset = 6
+anchor_left = 1.0
+anchor_top = 0.5
+anchor_right = 1.0
+anchor_bottom = 0.5
+offset_left = -48.0
+offset_top = -24.0
+offset_bottom = 24.0
+grow_horizontal = 0
+grow_vertical = 2
+alignment = 1
+
+[node name="Carrot" parent="Plants" instance=ExtResource("2_veu5b")]
+offset_right = 80.0
+offset_bottom = 72.0
+description = "[center][font_size=18]METEOR CARROT (Q)[/font_size][/center][font size=14]
+This plant has evolved a machine gun for self-defense.
+[color=#8888FF]Low-range rapid-fire gun[/color]"
+icon = ExtResource("3_hykl0")
+plant = ExtResource("4_qd155")
+hotkey = 81
+
+[node name="Carrot2" parent="Plants" instance=ExtResource("2_veu5b")]
+offset_top = 76.0
+offset_right = 80.0
+offset_bottom = 148.0
+description = "[center][font_size=18]METEOR PARSLEY (W)[/font_size][/center][font size=14]
+Has a superiority complex over Meteor Carrot.
+[color=#8888FF]Medium-range rapid-fire gun[/color]"
+icon = ExtResource("6_laq2b")
+plant = ExtResource("7_xdref")
+hotkey = 87
+
+[node name="Cucumber" parent="Plants" instance=ExtResource("2_veu5b")]
+offset_top = 152.0
+offset_right = 80.0
+offset_bottom = 224.0
+description = "[center][font_size=18]CUCUMBER (E)[/font_size][/center][font size=14]
+Used to be a rock, but it turned itself into a cucumber.
+[color=#8888FF]Long-range ballista[/color]"
+icon = ExtResource("8_yg5q2")
+plant = ExtResource("9_si7tt")
+hotkey = 69
+
+[node name="Dragon" parent="Plants" instance=ExtResource("2_veu5b")]
+offset_top = 228.0
+offset_right = 80.0
+offset_bottom = 300.0
+description = "[center][font_size=18]FLAMEFRUIT (R)[/font_size][/center][font size=14]
+Said to host a miniature dragon den.
+[color=#8888FF]Short-range incinerator[/color]"
+icon = ExtResource("10_vimv2")
+plant = ExtResource("11_t5qna")
+hotkey = 82
+
+[node name="Shallot" parent="Plants" instance=ExtResource("2_veu5b")]
+offset_top = 304.0
+offset_right = 80.0
+offset_bottom = 376.0
+description = "[center][font_size=18]SHALLOT HEAD (T)[/font_size][/center][font size=14]
+[img width=14]res://res/uoh.png[/img][img width=14]res://res/uoh.png[/img][img width=14]res://res/uoh.png[/img]
+[color=#8888FF]Damages every enemy within range[/color]"
+icon = ExtResource("12_12d5p")
+plant = ExtResource("13_1l6ff")
+hotkey = 84
+
+[node name="Missdemandrake" parent="Plants" instance=ExtResource("2_veu5b")]
+offset_top = 380.0
+offset_right = 80.0
+offset_bottom = 452.0
+description = "[center][font_size=18]MISSDEMANDRAKE (Y)[/font_size][/center][font size=14]
+A curious hybrid of mandrake and electric cabbage.
+[color=#8888FF]Strikes the healthiest enemy with lightning.[/color]"
+icon = ExtResource("2_ktgqv")
+plant = ExtResource("6_benw2")
+hotkey = 89
+
+[node name="DefeatScreen" type="Control" parent="."]
+visible = false
+layout_mode = 3
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+mouse_default_cursor_shape = 3
+
+[node name="ColorRect" type="ColorRect" parent="DefeatScreen"]
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+mouse_default_cursor_shape = 3
+color = Color(0.215492, 1.05286e-07, 4.21144e-08, 0.784314)
+
+[node name="VBoxContainer" type="VBoxContainer" parent="DefeatScreen"]
+anchors_preset = 8
+anchor_left = 0.5
+anchor_top = 0.5
+anchor_right = 0.5
+anchor_bottom = 0.5
+offset_left = -93.5
+offset_top = -46.5
+offset_right = 93.5
+offset_bottom = 46.5
+grow_horizontal = 2
+grow_vertical = 2
+
+[node name="Label" type="Label" parent="DefeatScreen/VBoxContainer"]
+mouse_default_cursor_shape = 3
+theme_override_colors/font_color = Color(0.521569, 0, 0, 1)
+theme_override_font_sizes/font_size = 40
+text = "YOU DIED"
+
+[node name="Button" type="Button" parent="DefeatScreen/VBoxContainer"]
+size_flags_horizontal = 4
+size_flags_vertical = 4
+theme = ExtResource("8_402o7")
+text = "Restart"
+script = ExtResource("8_ao4uf")
+
+[node name="VictoryScreen" type="Control" parent="."]
+visible = false
+layout_mode = 3
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+
+[node name="ColorRect" type="ColorRect" parent="VictoryScreen"]
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+color = Color(0, 0, 0, 0.784314)
+
+[node name="VBoxContainer" type="VBoxContainer" parent="VictoryScreen"]
+anchors_preset = 8
+anchor_left = 0.5
+anchor_top = 0.5
+anchor_right = 0.5
+anchor_bottom = 0.5
+offset_left = -93.5
+offset_top = -46.5
+offset_right = 93.5
+offset_bottom = 46.5
+grow_horizontal = 2
+grow_vertical = 2
+
+[node name="Label" type="Label" parent="VictoryScreen/VBoxContainer"]
+mouse_default_cursor_shape = 3
+theme_override_font_sizes/font_size = 40
+text = "Victory"
+horizontal_alignment = 1
+
+[node name="Button" type="Button" parent="VictoryScreen/VBoxContainer"]
+size_flags_horizontal = 4
+size_flags_vertical = 4
+theme = ExtResource("8_402o7")
+text = "Restart"
+script = ExtResource("8_ao4uf")
+
+[connection signal="pressed" from="DefeatScreen/VBoxContainer/Button" to="DefeatScreen/VBoxContainer/Button" method="_on_pressed"]
+[connection signal="pressed" from="VictoryScreen/VBoxContainer/Button" to="VictoryScreen/VBoxContainer/Button" method="_on_pressed"]

+ 63 - 0
scene/core/wave.gd

@@ -0,0 +1,63 @@
+extends Node2D
+class_name Wave
+
+@export var title: String
+@export_multiline var description: String
+@export var duration: float = 20.0
+@export var power_level: float = 1.0
+
+@export_group("Encounters")
+var UFO1: PackedScene = preload("res://scene/entity/ufo_1.tscn")
+var UFO2: PackedScene = preload("res://scene/entity/ufo_2.tscn")
+var UFO2B: PackedScene = preload("res://scene/entity/ufo_2_big.tscn")
+var UFO3: PackedScene = preload("res://scene/entity/ufo_3.tscn")
+var UFO4: PackedScene = preload("res://scene/entity/ufo_4.tscn")
+var UFO5: PackedScene = preload("res://scene/entity/ufo_ast.tscn")
+@export var witchUFO: int
+@export var fork: int
+@export var forkB: int
+@export var star: int
+@export var boss: int
+@export var ast: int
+
+@onready var mob_target = $"../../UFOs"
+var index = 0
+var timer: Timer = Timer.new()
+
+func _ready():
+    timer.set_wait_time(0.5)
+    timer.set_one_shot(true)
+    add_child(timer)
+
+func insert(mob: PackedScene, count: int):
+    for i in range(0, count):
+        var new_mob = mob.instantiate()
+        new_mob.set_position(get_global_position() + Vector2(index * 800, 0))
+        index += 1
+        index %= 5
+        mob_target.add_child(new_mob)
+        timer.start()
+        await timer.timeout
+
+func activate():
+    insert(UFO1, witchUFO)
+    insert(UFO2, fork)
+    insert(UFO2B, forkB)
+    insert(UFO3, star)
+    insert(UFO4, boss)
+    insert(UFO5, ast)
+
+func get_log_data_per_mob(val: int, tstr: String, target: String) -> String:
+    if val > 0:
+        target += "[indent]" + str(val) + "x " + tstr + "[/indent]\n" 
+    return target
+
+func get_log_data():
+    var l = ""
+    l = get_log_data_per_mob(witchUFO, "U.W.O.", l)
+    l = get_log_data_per_mob(fork, "Farm ship", l)
+    l = get_log_data_per_mob(forkB, "Shipfork", l)
+    l = get_log_data_per_mob(star, "Morning star", l)
+    l = get_log_data_per_mob(boss, "Comically large U.W.O.", l)
+    l = get_log_data_per_mob(ast, "Asteroid", l)
+    return l

+ 6 - 0
scene/core/wave.tscn

@@ -0,0 +1,6 @@
+[gd_scene load_steps=2 format=3 uid="uid://d3pwe86nea0pc"]
+
+[ext_resource type="Script" path="res://scene/core/wave.gd" id="1_12iqf"]
+
+[node name="Wave" type="Node2D"]
+script = ExtResource("1_12iqf")

+ 46 - 0
scene/core/wave_manager.gd

@@ -0,0 +1,46 @@
+extends Node2D
+class_name WaveManager
+
+var timer: Timer = Timer.new()
+var current_wave: int = -1
+var done = false
+@onready var log = $"../../../UILayer/UI/Log/PC/MC/Label"
+@onready var time_label = $"../../../UILayer/UI/NextWave/HB/Label"
+var power_level: float = 1.0
+
+func _ready():
+    add_child(timer)
+    timer.set_one_shot(true)
+    timer.connect("timeout", next_wave)
+    log.set_text("")
+    next_wave()
+    
+    $"../../../UILayer/UI/NextWave/HB/Button".connect("pressed", next_wave)
+
+func _process(delta: float):
+    time_label.set_text("in " + str(round(timer.get_time_left())) + "s")
+
+func _input(input: InputEvent):
+    if input.is_action_pressed("wave_cheat"):
+        current_wave += 1
+        print("Skipped wave ", current_wave + 1)
+
+func next_wave():
+    current_wave += 1
+    if current_wave < get_children().size() - 1:
+        var wave = get_child(current_wave)
+        power_level = wave.power_level
+        wave.activate()
+        timer.set_wait_time(wave.duration)
+        timer.start()
+        if wave.title:
+            log.append_text("[color=#ffcccc]Wave" + str(current_wave + 1) + ":[/color] " + wave.title + "\n")
+        else:
+            log.append_text("[color=#ffcccc]Wave" + str(current_wave + 1) + "[/color] " + "\n")
+        log.append_text(wave.get_log_data())
+    else:
+        done = true
+        log.append_text("[color=#ccffcc]No waves left[/color]\n")
+
+func is_done():
+    return done

+ 37 - 0
scene/entity/aoe.tscn

@@ -0,0 +1,37 @@
+[gd_scene load_steps=7 format=3 uid="uid://b7cuabx3ghe01"]
+
+[ext_resource type="Script" path="res://scene/entity/onion.gd" id="1_4vafg"]
+[ext_resource type="Texture2D" uid="uid://qtverddtembb" path="res://res/shallot.png" id="2_wk27u"]
+[ext_resource type="PackedScene" uid="uid://cbpm6nmfyr861" path="res://scene/entity/ri.tscn" id="3_3jjw5"]
+[ext_resource type="AudioStream" uid="uid://dti0unulgsf3o" path="res://snd/sfx/laserShoot.wav" id="4_ixbct"]
+[ext_resource type="Script" path="res://scene/entity/pc.gd" id="5_ctkfa"]
+
+[sub_resource type="RectangleShape2D" id="RectangleShape2D_8s8kg"]
+size = Vector2(106.5, 108)
+
+[node name="Onion" type="CharacterBody2D"]
+collision_layer = 2
+collision_mask = 0
+script = ExtResource("1_4vafg")
+y_offset = -50.0
+grow_time = 3.0
+max_hp = 30.0
+cost = 50
+attack_rate = 3.0
+attack_range = 2000.0
+attack_damage = 12.0
+
+[node name="Body" type="Sprite2D" parent="."]
+texture = ExtResource("2_wk27u")
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
+position = Vector2(5, 10)
+shape = SubResource("RectangleShape2D_8s8kg")
+
+[node name="RI" parent="." instance=ExtResource("3_3jjw5")]
+
+[node name="Coin" type="AudioStreamPlayer2D" parent="."]
+stream = ExtResource("4_ixbct")
+volume_db = -6.0
+bus = &"SFX"
+script = ExtResource("5_ctkfa")

+ 139 - 0
scene/entity/base_plant.gd

@@ -0,0 +1,139 @@
+extends CharacterBody2D
+class_name Plant
+signal shoot(ufo: UFO)
+
+@export var y_offset: float = 0.0
+@export var height: float = 100.0
+@export_range(1.0, 30.0) var grow_time: float = 1.0 
+var growing: bool = true
+var grow_value: float = 0.0
+@export_range(0.0, 1.0) var base_scale: float = 0.5
+@onready var target_scale: float = get_scale().x
+@export_range(0.0, 1000.0) var max_hp = 100.0
+@onready var hp: float = max_hp
+var planted_position: Vector2 = Vector2(0, 0)
+var dead: bool = false
+var attackers: Array[UFO] = []
+var target_attacker: UFO = null # Used when the plant is dying
+@export var cost: int = 10
+@export var bullet_color: Color = Color(1, 1, 1, 1)
+@export var bullet_base_speed_u: int = 2000
+@export var bullet_base_speed_l: int = 1000
+
+enum TargetMode {
+    NEAREST, HIGHEST, LOWEST
+}
+
+var ufo_search_timer: Timer = Timer.new()
+var attack_timer: Timer = Timer.new()
+@onready var ufos: Node2D = get_tree().get_root().find_child("UFOs", true, false)
+var victim: UFO = null
+@export var target_mode: TargetMode = TargetMode.NEAREST
+@export var attack_rate: float = 0.1
+@export var attack_range: float = 300.0
+@export var attack_damage: float = 10.0
+
+func _ready():
+    move_local_y(y_offset)
+    planted_position = get_position()
+    ufo_search_timer.set_wait_time(0.1)
+    ufo_search_timer.set_autostart(false)
+    ufo_search_timer.set_one_shot(true)
+    ufo_search_timer.connect("timeout", _on_attack)
+    attack_timer.set_wait_time(attack_rate)
+    attack_timer.set_autostart(false)
+    attack_timer.set_one_shot(true)
+    attack_timer.connect("timeout", _on_attack)
+    add_child(ufo_search_timer)
+    add_child(attack_timer)
+    attack_timer.start()
+
+func get_class():
+    return "Plant"
+
+func _on_attack():
+    find_ufo()
+    if victim == null or victim.dead:
+        ufo_search_timer.start()
+    else:
+        emit_signal("shoot", victim)
+        attack_timer.start()
+        $Coin.play()
+
+func find_ufo():
+    victim = null
+    var all_ufos = ufos.get_children()
+    var plant_pos = get_global_position()
+    if all_ufos.size() > 0:
+        var best_ufo = all_ufos[0]
+        var best_value = 0.0
+        if target_mode == TargetMode.NEAREST: 
+            best_value = 10000000.0
+        for ufo in ufos.get_children():
+            if ufo.dead:
+                continue
+            var tested_value: float
+            if target_mode == TargetMode.NEAREST: 
+                tested_value = ufo.get_global_position().distance_to(plant_pos)
+                if tested_value <= attack_range:
+                    if tested_value < best_value:
+                        best_value = tested_value
+                        best_ufo = ufo
+                        victim = best_ufo
+            else:
+                tested_value = ufo.hp
+                if tested_value > best_value:
+                    best_value = tested_value
+                    best_ufo = ufo
+                    victim = best_ufo
+            
+
+func _process(delta):
+    if growing:
+        grow_value += delta / grow_time
+        if grow_value > 1.0:
+            grow_value = 1.0
+            growing = false
+            set_scale(Vector2(target_scale, target_scale))
+        else:
+            var new_scale = target_scale * (base_scale + grow_value * (1.0 - base_scale))
+            set_scale(Vector2(new_scale, new_scale))
+    elif dead:
+        if target_attacker == null or target_attacker.dead:
+            select_attacker()
+        if target_attacker != null:
+            velocity = target_attacker.get_global_position() - get_global_position()
+            move_and_slide()
+        var scale = get_scale().x
+        scale *= (1.0 - delta)
+        set_scale(Vector2(scale, scale))
+        set_z_index(-30)
+        rotate(delta * PI)
+        if scale < 0.1:
+            get_parent().remove_child(self)
+            queue_free()
+    else:
+        if target_attacker == null or target_attacker.dead:
+            alter_hp(delta * max_hp / 10.0)
+
+func select_attacker():
+    for attacker in attackers:
+        #if !attacker.dead:
+         target_attacker = attacker
+
+func alter_hp(delta: float):
+    hp += delta
+    hp = min(hp, max_hp)
+    set_position(Vector2(planted_position.x, planted_position.y - height * (1.0 - hp / max_hp)))
+
+func deal_damage(damage: float, attacker: UFO):
+    if dead:
+        return
+    alter_hp(-damage)
+    if attacker != null:
+        attackers.push_back(attacker)
+    if hp < 0:
+        dead = true
+
+func is_ready():
+    return !growing

+ 13 - 0
scene/entity/big_tree.tscn

@@ -0,0 +1,13 @@
+[gd_scene load_steps=3 format=3 uid="uid://dj34fwqp6hgfq"]
+
+[ext_resource type="Script" path="res://addons/fake_parallax/fake_parallax.gd" id="1_7joln"]
+[ext_resource type="Texture2D" uid="uid://cm3se3qfioli6" path="res://res/tree.png" id="2_wmtht"]
+
+[node name="BigTree" type="Node2D"]
+position = Vector2(1777, 53)
+script = ExtResource("1_7joln")
+rate = 0.1
+
+[node name="Tree" type="Sprite2D" parent="."]
+texture = ExtResource("2_wmtht")
+metadata/_edit_lock_ = true

+ 41 - 0
scene/entity/bullet.gd

@@ -0,0 +1,41 @@
+extends CharacterBody2D
+class_name Bullet
+
+var base_speed = 2000.0
+var speed_bound = 1000.0
+var speed = base_speed
+var target_node: Node2D = null
+var damage = 0
+var timeout: Timer = Timer.new()
+var last_vector: Vector2 = Vector2(0, 0)
+
+func get_class():
+    return "Bullet"
+    
+func _ready():
+    timeout.set_wait_time(10.0)
+    add_child(timeout)
+    timeout.start()
+    timeout.connect("timeout", _on_timeout)
+    speed = base_speed
+
+func _process(delta: float):
+    if target_node != null:
+        if target_node.dead:
+            target_node = null
+        else:
+            look_at(target_node.get_global_position())
+
+func _on_timeout():
+    get_parent().remove_child(self)
+    queue_free()
+
+func _physics_process(delta):
+    if target_node != null and speed > speed_bound + 1.0:
+        last_vector = Vector2(target_node.get_global_position() - get_global_position()).normalized()
+        velocity = last_vector * speed
+    else:
+        velocity = last_vector * speed
+    speed -= delta * base_speed
+    speed = max(speed, speed_bound)
+    move_and_slide()

+ 19 - 0
scene/entity/bullet.tscn

@@ -0,0 +1,19 @@
+[gd_scene load_steps=4 format=3 uid="uid://brgt28uanqske"]
+
+[ext_resource type="Texture2D" uid="uid://mm6ylqwudexe" path="res://res/bullet.png" id="1_dkvbc"]
+[ext_resource type="Script" path="res://scene/entity/bullet.gd" id="1_vrlfp"]
+
+[sub_resource type="RectangleShape2D" id="RectangleShape2D_qndjr"]
+size = Vector2(150, 106)
+
+[node name="Bullet" type="CharacterBody2D"]
+scale = Vector2(0.5, 0.5)
+collision_mask = 0
+script = ExtResource("1_vrlfp")
+
+[node name="Sprite" type="Sprite2D" parent="."]
+texture = ExtResource("1_dkvbc")
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
+position = Vector2(-1, 1)
+shape = SubResource("RectangleShape2D_qndjr")

+ 9 - 0
scene/entity/carrot.gd

@@ -0,0 +1,9 @@
+extends Plant
+
+@onready var gun: Sprite2D = $Gun
+
+func _ready():
+    super()
+ 
+func _process(delta):
+    super(delta)

+ 47 - 0
scene/entity/carrot.tscn

@@ -0,0 +1,47 @@
+[gd_scene load_steps=9 format=3 uid="uid://barkhw1dcvol6"]
+
+[ext_resource type="Script" path="res://scene/entity/carrot.gd" id="1_gju6g"]
+[ext_resource type="Texture2D" uid="uid://h6xbp2jjqyvs" path="res://res/carrot_gun.png" id="1_tdoyb"]
+[ext_resource type="Texture2D" uid="uid://bigfbiy262j6j" path="res://res/carrot_body_0.png" id="2_ptjqr"]
+[ext_resource type="Script" path="res://scene/entity/carrot_gun.gd" id="3_4132d"]
+[ext_resource type="PackedScene" uid="uid://cbpm6nmfyr861" path="res://scene/entity/ri.tscn" id="5_f2co1"]
+[ext_resource type="AudioStream" uid="uid://cpyaqxuec8i5k" path="res://snd/sfx/laserShoot(1).wav" id="6_6wdjm"]
+[ext_resource type="Script" path="res://scene/entity/pc.gd" id="7_5wvmf"]
+
+[sub_resource type="RectangleShape2D" id="RectangleShape2D_kuiqv"]
+size = Vector2(200, 1000)
+
+[node name="Carrot" type="CharacterBody2D"]
+scale = Vector2(0.3, 0.3)
+collision_layer = 2
+collision_mask = 0
+script = ExtResource("1_gju6g")
+y_offset = 75.0
+height = 300.0
+base_scale = 0.4
+max_hp = 60.0
+bullet_color = Color(0.878431, 0.160784, 0.478431, 1)
+attack_rate = 0.25
+attack_range = 1800.0
+attack_damage = 3.0
+
+[node name="Gun" type="Sprite2D" parent="."]
+position = Vector2(0, -430)
+texture = ExtResource("1_tdoyb")
+centered = false
+offset = Vector2(-200, -327)
+script = ExtResource("3_4132d")
+
+[node name="Body" type="Sprite2D" parent="."]
+texture = ExtResource("2_ptjqr")
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
+shape = SubResource("RectangleShape2D_kuiqv")
+
+[node name="RI" parent="." instance=ExtResource("5_f2co1")]
+
+[node name="Coin" type="AudioStreamPlayer2D" parent="."]
+stream = ExtResource("6_6wdjm")
+volume_db = -6.0
+bus = &"SFX"
+script = ExtResource("7_5wvmf")

+ 49 - 0
scene/entity/carrot2.tscn

@@ -0,0 +1,49 @@
+[gd_scene load_steps=9 format=3 uid="uid://7xbagi7msusx"]
+
+[ext_resource type="Script" path="res://scene/entity/carrot.gd" id="1_hssk5"]
+[ext_resource type="Texture2D" uid="uid://h6xbp2jjqyvs" path="res://res/carrot_gun.png" id="2_olill"]
+[ext_resource type="Script" path="res://scene/entity/carrot_gun.gd" id="3_bcjtw"]
+[ext_resource type="Texture2D" uid="uid://cwl8co2omg20p" path="res://res/carrot_body_1.png" id="4_18hj0"]
+[ext_resource type="PackedScene" uid="uid://cbpm6nmfyr861" path="res://scene/entity/ri.tscn" id="5_fijcn"]
+[ext_resource type="AudioStream" uid="uid://cpyaqxuec8i5k" path="res://snd/sfx/laserShoot(1).wav" id="6_dfteh"]
+[ext_resource type="Script" path="res://scene/entity/pc.gd" id="7_qhdbr"]
+
+[sub_resource type="RectangleShape2D" id="RectangleShape2D_8s8kg"]
+size = Vector2(200, 1000)
+
+[node name="Carrot" type="CharacterBody2D"]
+scale = Vector2(0.3, 0.3)
+collision_layer = 2
+collision_mask = 0
+script = ExtResource("1_hssk5")
+y_offset = 75.0
+height = 300.0
+grow_time = 2.0
+base_scale = 0.4
+max_hp = 90.0
+cost = 20
+bullet_color = Color(0.917647, 0.917647, 0.917647, 1)
+attack_rate = 0.25
+attack_range = 2500.0
+attack_damage = 8.0
+
+[node name="Gun" type="Sprite2D" parent="."]
+position = Vector2(0, -430)
+texture = ExtResource("2_olill")
+centered = false
+offset = Vector2(-200, -327)
+script = ExtResource("3_bcjtw")
+
+[node name="Body" type="Sprite2D" parent="."]
+texture = ExtResource("4_18hj0")
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
+shape = SubResource("RectangleShape2D_8s8kg")
+
+[node name="RI" parent="." instance=ExtResource("5_fijcn")]
+
+[node name="Coin" type="AudioStreamPlayer2D" parent="."]
+stream = ExtResource("6_dfteh")
+volume_db = -6.0
+bus = &"SFX"
+script = ExtResource("7_qhdbr")

+ 49 - 0
scene/entity/carrot3.tscn

@@ -0,0 +1,49 @@
+[gd_scene load_steps=8 format=3 uid="uid://bxrjfsowqkb86"]
+
+[ext_resource type="Script" path="res://scene/entity/cucumber.gd" id="1_uqaq7"]
+[ext_resource type="Texture2D" uid="uid://c6g3vxs1w2cyx" path="res://res/cucumber.png" id="2_4sjmf"]
+[ext_resource type="Script" path="res://scene/entity/carrot_gun.gd" id="3_w3gkv"]
+[ext_resource type="PackedScene" uid="uid://cbpm6nmfyr861" path="res://scene/entity/ri.tscn" id="4_g83oq"]
+[ext_resource type="AudioStream" uid="uid://cpyaqxuec8i5k" path="res://snd/sfx/laserShoot(1).wav" id="5_qk2b2"]
+[ext_resource type="Script" path="res://scene/entity/pc.gd" id="6_3efot"]
+
+[sub_resource type="RectangleShape2D" id="RectangleShape2D_8s8kg"]
+size = Vector2(103, 143)
+
+[node name="Cucumber" type="CharacterBody2D"]
+scale = Vector2(1.2, 1.2)
+collision_layer = 2
+collision_mask = 0
+script = ExtResource("1_uqaq7")
+y_offset = -30.0
+cost = 20
+bullet_base_speed_u = 4000
+bullet_base_speed_l = 3000
+attack_rate = 1.0
+attack_range = 4000.0
+attack_damage = 30.0
+
+[node name="Gun" type="Sprite2D" parent="."]
+position = Vector2(23.3333, -72.5)
+texture = ExtResource("2_4sjmf")
+offset = Vector2(-27.5, 64.1667)
+script = ExtResource("3_w3gkv")
+
+[node name="Body" type="Sprite2D" parent="."]
+visible = false
+position = Vector2(145, 245)
+texture = ExtResource("2_4sjmf")
+centered = false
+offset = Vector2(-200, -327)
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
+position = Vector2(-3.5, -9.5)
+shape = SubResource("RectangleShape2D_8s8kg")
+
+[node name="RI" parent="." instance=ExtResource("4_g83oq")]
+
+[node name="Coin" type="AudioStreamPlayer2D" parent="."]
+stream = ExtResource("5_qk2b2")
+volume_db = -6.0
+bus = &"SFX"
+script = ExtResource("6_3efot")

+ 45 - 0
scene/entity/carrot4.tscn

@@ -0,0 +1,45 @@
+[gd_scene load_steps=9 format=3 uid="uid://bam5e7b0rnfnm"]
+
+[ext_resource type="Script" path="res://scene/entity/dragon.gd" id="1_b2xkh"]
+[ext_resource type="Texture2D" uid="uid://duevuku5wklwt" path="res://res/nothing.png" id="2_701be"]
+[ext_resource type="Script" path="res://scene/entity/carrot_gun.gd" id="3_tixck"]
+[ext_resource type="Texture2D" uid="uid://cx5md40xbjcwp" path="res://res/dragonfruit.png" id="4_sfyf4"]
+[ext_resource type="PackedScene" uid="uid://cbpm6nmfyr861" path="res://scene/entity/ri.tscn" id="5_5dxu3"]
+[ext_resource type="AudioStream" uid="uid://cpyaqxuec8i5k" path="res://snd/sfx/laserShoot(1).wav" id="6_6s2xr"]
+[ext_resource type="Script" path="res://scene/entity/pc.gd" id="7_b6qiy"]
+
+[sub_resource type="RectangleShape2D" id="RectangleShape2D_8s8kg"]
+size = Vector2(106.5, 108)
+
+[node name="Dragon" type="CharacterBody2D"]
+collision_layer = 2
+collision_mask = 0
+script = ExtResource("1_b2xkh")
+y_offset = -60.0
+cost = 30
+bullet_color = Color(0.490196, 0.0901961, 0.270588, 1)
+bullet_base_speed_u = 8000
+bullet_base_speed_l = 4000
+attack_range = 1100.0
+attack_damage = 7.0
+
+[node name="Gun" type="Sprite2D" parent="."]
+position = Vector2(-2, -49)
+texture = ExtResource("2_701be")
+centered = false
+script = ExtResource("3_tixck")
+
+[node name="Body" type="Sprite2D" parent="."]
+texture = ExtResource("4_sfyf4")
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
+position = Vector2(5, 10)
+shape = SubResource("RectangleShape2D_8s8kg")
+
+[node name="RI" parent="." instance=ExtResource("5_5dxu3")]
+
+[node name="Coin" type="AudioStreamPlayer2D" parent="."]
+stream = ExtResource("6_6s2xr")
+volume_db = -6.0
+bus = &"SFX"
+script = ExtResource("7_b6qiy")

+ 28 - 0
scene/entity/carrot_gun.gd

@@ -0,0 +1,28 @@
+extends Sprite2D
+class_name Gun
+
+var Bullet = preload("res://scene/entity/bullet.tscn")
+var should_rotate = true
+
+func _ready():
+    $"..".connect("shoot", _on_shoot)
+
+func _process(delta):
+    var victim = $"..".victim
+    if $"..".dead or victim == null or victim.dead:
+        set_rotation(0)
+    elif victim != null and should_rotate:
+        look_at(victim.get_global_position())
+        rotate(PI/2)
+
+func _on_shoot(victim: UFO):
+    if victim != null and not $"..".dead:
+        var bullet: Bullet = Bullet.instantiate()
+        bullet.target_node = victim
+        bullet.set_position(get_global_position())
+        bullet.set_modulate($"..".bullet_color)
+        bullet.set_scale(Vector2(0.2, 0.2))
+        bullet.damage = $"..".attack_damage
+        bullet.base_speed = $"..".bullet_base_speed_u
+        bullet.speed_bound = $"..".bullet_base_speed_l
+        $"../../../Bullets".add_child(bullet)

+ 10 - 0
scene/entity/cucumber.gd

@@ -0,0 +1,10 @@
+extends Plant
+
+@onready var gun: Gun = $Gun
+
+func _ready():
+    super()
+    gun.should_rotate = true#false
+ 
+func _process(delta):
+    super(delta)

+ 10 - 0
scene/entity/dragon.gd

@@ -0,0 +1,10 @@
+extends Plant
+
+@onready var gun: Gun = $Gun
+
+func _ready():
+    super()
+    gun.should_rotate = false
+ 
+func _process(delta):
+    super(delta)

+ 14 - 0
scene/entity/missdemandrake.gd

@@ -0,0 +1,14 @@
+extends Plant
+class_name Mandrake
+
+func _ready():
+    super()
+    connect("shoot", _on_shoot)
+
+func _process(delta):
+    super(delta)
+    $Eyes.set_modulate(Color(1, 1, 1, 1.0 - (attack_timer.get_time_left() / 10.0)))
+    
+func _on_shoot(victim: UFO):
+    if victim != null and not dead:
+        victim.deal_damage(attack_damage)

+ 48 - 0
scene/entity/missdemandrake.tscn

@@ -0,0 +1,48 @@
+[gd_scene load_steps=9 format=3 uid="uid://dhc4lumda0bk5"]
+
+[ext_resource type="Texture2D" uid="uid://c6u8y8ibxug4h" path="res://res/missdemandrake.png" id="1_173wg"]
+[ext_resource type="Script" path="res://scene/entity/missdemandrake.gd" id="1_dk8rq"]
+[ext_resource type="Texture2D" uid="uid://ce7vdid4dqde7" path="res://res/missdemandrake_eyes.png" id="2_ymoub"]
+[ext_resource type="Texture2D" uid="uid://c1epyp0arqif4" path="res://res/missdemandrake_hair.png" id="3_ykh0b"]
+[ext_resource type="PackedScene" uid="uid://cbpm6nmfyr861" path="res://scene/entity/ri.tscn" id="5_4xega"]
+[ext_resource type="AudioStream" uid="uid://b2jdpvwntw5g" path="res://snd/sfx/manor.wav" id="6_5sihn"]
+[ext_resource type="Script" path="res://scene/core/pc1.gd" id="7_nfty0"]
+
+[sub_resource type="RectangleShape2D" id="RectangleShape2D_q4evg"]
+size = Vector2(143.333, 163.333)
+
+[node name="Missdemandrake" type="CharacterBody2D"]
+scale = Vector2(0.8, 0.8)
+script = ExtResource("1_dk8rq")
+y_offset = -70.0
+cost = 100
+target_mode = 1
+attack_rate = 10.0
+attack_range = 10000.0
+attack_damage = 10000.0
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
+shape = SubResource("RectangleShape2D_q4evg")
+
+[node name="Head" type="Sprite2D" parent="."]
+z_index = -4
+texture = ExtResource("1_173wg")
+
+[node name="Eyes" type="Sprite2D" parent="."]
+modulate = Color(1, 1, 1, 0)
+z_index = 99
+position = Vector2(-26.6667, 23.3333)
+texture = ExtResource("2_ymoub")
+
+[node name="Hair" type="Sprite2D" parent="."]
+z_index = 100
+position = Vector2(-16.6667, 26.6667)
+texture = ExtResource("3_ykh0b")
+
+[node name="RI" parent="." instance=ExtResource("5_4xega")]
+
+[node name="Coin" type="AudioStreamPlayer" parent="."]
+stream = ExtResource("6_5sihn")
+volume_db = -6.0
+bus = &"SFX"
+script = ExtResource("7_nfty0")

+ 16 - 0
scene/entity/onion.gd

@@ -0,0 +1,16 @@
+extends Plant
+
+@onready var all_ufos = $"../../UFOs"
+
+func _ready():
+    super()
+    connect("shoot", _on_shoot)
+ 
+func _process(delta):
+    super(delta)
+    
+func _on_shoot(_victim):
+    for ufo in all_ufos.get_children():
+        if ufo.get_global_position().distance_to(get_global_position()) <= attack_range:
+            ufo.deal_damage(attack_damage)
+ 

+ 5 - 0
scene/entity/pc.gd

@@ -0,0 +1,5 @@
+extends AudioStreamPlayer2D
+
+func play(from_position: float = 0.0) -> void:
+    set_pitch_scale(randf_range(0.8, 1.2))
+    super(from_position)

+ 16 - 0
scene/entity/range_indicator.gd

@@ -0,0 +1,16 @@
+extends Area2D
+
+func _ready():
+    add_child($"../CollisionShape2D".duplicate())
+    connect("mouse_entered", do_show)
+    connect("mouse_exited", dont_show)
+    $C.set_modulate(Color($"..".bullet_color, 0.3))
+    $C.hide()
+
+func do_show():
+    var sc = $"..".attack_range / 256 / $"..".get_scale().x
+    $C.set_scale(Vector2(sc, sc))
+    $C.show()
+
+func dont_show():
+    $C.hide()

+ 10 - 0
scene/entity/ri.tscn

@@ -0,0 +1,10 @@
+[gd_scene load_steps=3 format=3 uid="uid://cbpm6nmfyr861"]
+
+[ext_resource type="Script" path="res://scene/entity/range_indicator.gd" id="1_qojkq"]
+[ext_resource type="Texture2D" uid="uid://b5qcub6t5thrn" path="res://res/circle.png" id="2_0lisv"]
+
+[node name="RI" type="Area2D"]
+script = ExtResource("1_qojkq")
+
+[node name="C" type="Sprite2D" parent="."]
+texture = ExtResource("2_0lisv")

+ 192 - 0
scene/entity/ufo.gd

@@ -0,0 +1,192 @@
+extends CharacterBody2D
+class_name UFO
+
+@export var movement_speed: float = 800.0
+@export var radius: float = 150.0
+var max_velocity: float = movement_speed
+@onready var navigation_agent: NavigationAgent2D = $NavigationAgent2D
+@onready var plants: Node = $"../../Plants"
+var target: Plant = null
+var target2: Plant = null
+var announce_self: bool = false
+var dead = false
+@export_range(1.0, 1000.0) var dps: float = 10.0
+@export var max_hp = 100.0
+var hp: float
+var dead_timer: Timer = Timer.new()
+@export var wheat_out: int = 3
+var Wheat = preload("res://scene/entity/wheat.tscn")
+@export var should_rotate: bool = true
+@onready var ray = $Plx/Ray
+@onready var ray2 = find_child("Ray2")
+var attack_range = 1000.0
+var second_player = find_child("AudioStreamPlayer2D2")
+@onready var power_level: float = $"../../Waves".power_level
+
+func _ready():
+    call_deferred("actor_setup")
+    navigation_agent.connect("velocity_computed", move)
+    
+    max_hp *= power_level
+    dps *= power_level * sqrt(power_level)
+    
+    $RerollTimer.connect("timeout", roll_movement_target)
+    $DamageTimer.connect("timeout", damage_target)
+    
+    navigation_agent.set_path_desired_distance(10.0)
+    navigation_agent.set_target_desired_distance(attack_range)
+    navigation_agent.set_path_max_distance(40.0)
+    navigation_agent.set_avoidance_enabled(true)
+    navigation_agent.set_radius(radius)
+    navigation_agent.set_neighbor_distance(movement_speed * 2)
+    navigation_agent.set_max_speed(movement_speed)
+    
+    $AudioStreamPlayer2D.set_bus("Music" + str(randi_range(0, 3)))
+    $AudioStreamPlayer2D.play($"../../HomeSound".get_playback_position())
+    
+    if second_player != null:
+        second_player.set_bus("Music" + str(randi_range(0, 3)))
+        second_player.play($"../../HomeSound".get_playback_position())
+        
+    hp = max_hp
+    $Plx/HP.set_max(max_hp)
+    $Plx/HP.set_value(max_hp)
+    
+func _process(delta):
+    if dead:
+        _process_dead(delta)
+    if navigation_agent.is_target_reached() and target != null:
+        enable_ray(ray, target)
+        if ray2 != null:
+            if target2 == null or target2.dead:
+                target2 = roll_aux_target()
+            if target2 != null:
+                enable_ray(ray2, target2)
+            else:
+                hide_ray(ray2)
+        if $DamageTimer.is_stopped():
+            $DamageTimer.start()
+        if target.dead:
+            if target2 != null:
+                target = target2
+                target2 = null
+            else:
+                target = roll_movement_target()
+                hide_ray(ray)
+    else:
+        hide_ray(ray)
+        hide_ray(ray2)
+        $DamageTimer.stop()
+
+func _process_dead(delta: float):
+    var time_left = dead_timer.get_time_left() * 3.0
+    var scale = ease(time_left, 5)
+    set_scale(Vector2(scale, scale))
+    $AudioStreamPlayer2D.set_volume_db($AudioStreamPlayer2D.get_volume_db() - delta * 30.0)
+    if second_player != null:
+        second_player.set_volume_db(second_player.get_volume_db() - delta * 30.0)
+    if time_left == 0.0:
+        get_parent().remove_child(self)
+        queue_free() 
+
+func _physics_process(delta):
+    if navigation_agent.is_target_reached():
+        var new_speed = velocity.length() - delta * movement_speed * 2.0
+        velocity = velocity.normalized() * new_speed
+        move_and_slide()
+    else:
+        var current_agent_position: Vector2 = global_transform.origin
+        var next_path_position: Vector2 = navigation_agent.get_next_location()
+        var new_velocity: Vector2 = next_path_position - current_agent_position
+        new_velocity = new_velocity.normalized()
+        new_velocity = new_velocity * movement_speed
+        navigation_agent.set_velocity(new_velocity)
+
+func actor_setup():
+    await get_tree().physics_frame
+    target = roll_movement_target()
+
+func roll_movement_target():
+    var all_plants = plants.get_children()
+    var count = all_plants.size()
+    announce_self = true
+    var res: UFO = null
+    if count == 0:
+        $RerollTimer.start()
+    else:
+        var i = 0
+        while (res == null or res.dead) and i < 10:
+            res = all_plants[randi_range(0, count - 1)]
+            i += 1
+        if i == 10:
+            res = null
+            $RerollTimer.start()
+        else:
+            navigation_agent.set_target_location(res.get_global_position())
+    return res
+    
+func roll_aux_target():
+    var all_plants = plants.get_children()
+    for plant in all_plants:
+        if plant != target and plant.get_global_position().distance_to(get_global_position()) <= attack_range:
+            return plant
+    return null
+
+func damage_target():
+    if target != null:
+        target.deal_damage(dps / 20.0, self if announce_self else null)
+    if target2 != null:
+        target2.deal_damage(dps / 20.0, self if announce_self else null)
+
+func move(velocity_: Vector2):
+    velocity = velocity_
+    move_and_slide()
+    if should_rotate:
+        var top = find_child("Top")
+        top.set_rotation(lerp_angle(top.get_rotation(), velocity.angle(), 10.0 * get_physics_process_delta_time()))
+
+func _on_area_2d_body_entered(body):
+    if body.get_class() == "Bullet":
+        deal_damage(body.damage)
+        body.get_parent().remove_child(body)
+        body.queue_free()
+        
+func deal_damage(damage):
+    hp -= damage
+    $Plx/HP.set_value(hp)
+    if hp <= 0 and not dead:
+        dead = true
+        $Coin.play()
+        set_collision_layer_value(1, false)
+        set_collision_mask_value(1, false)
+        $Plx/HP.hide()
+        dead_timer.set_wait_time(0.333)
+        dead_timer.set_one_shot(true)
+        add_child(dead_timer)
+        dead_timer.start()
+        $DamageTimer.stop()
+        hide_ray(ray)
+        hide_ray(ray2)
+        call_deferred("spawn_wheat")
+
+func spawn_wheat():
+    for i in range(0, wheat_out):
+        var wheat = Wheat.instantiate()
+        wheat.rotate(randf_range(-PI, PI))
+        wheat.set_position(get_global_position())
+        $"../../Wheat".add_child(wheat)
+
+func enable_ray(ray, target: Node2D):
+    if ray != null:
+        var diff = target.get_global_position() - get_global_position()
+        var poly = ray.get_polygon()
+        poly[1] = diff + Vector2(-80.0, target.height / 1.5 + target.y_offset)
+        poly[2] = diff + Vector2(80.0, target.height / 1.5 + target.y_offset)
+        ray.set_polygon(poly)
+        ray.show()
+
+func hide_ray(r):
+    if r != null:
+        r.hide()
+        
+    

+ 97 - 0
scene/entity/ufo_1.tscn

@@ -0,0 +1,97 @@
+[gd_scene load_steps=12 format=3 uid="uid://mfhn7mohmimt"]
+
+[ext_resource type="Script" path="res://scene/entity/ufo.gd" id="1_3oxp2"]
+[ext_resource type="Script" path="res://addons/fake_parallax/fake_parallax.gd" id="2_6l42y"]
+[ext_resource type="Texture2D" uid="uid://csqk7vyq6ecpl" path="res://res/witch_ufo_bot.png" id="3_qpday"]
+[ext_resource type="Texture2D" uid="uid://baacv2khh4ef8" path="res://res/witch_ufo_top.png" id="4_q1mhr"]
+[ext_resource type="Texture2D" uid="uid://dil0tx0ab553l" path="res://res/pbar.png" id="5_cf3a7"]
+[ext_resource type="Texture2D" uid="uid://b5jrxsko40vge" path="res://res/pbar2.png" id="6_pofdg"]
+[ext_resource type="AudioStream" uid="uid://vto0qax0wsf1" path="res://snd/mus/ld52-001.ogg" id="7_ls50j"]
+[ext_resource type="AudioStream" uid="uid://d1rxdiuhw4kfy" path="res://snd/mus/ld52-003.ogg" id="8_en80a"]
+[ext_resource type="AudioStream" uid="uid://b78r3yehfioyu" path="res://snd/sfx/explosion.wav" id="9_sft0k"]
+[ext_resource type="Script" path="res://scene/entity/pc.gd" id="10_nswe8"]
+
+[sub_resource type="CircleShape2D" id="CircleShape2D_maxop"]
+radius = 223.258
+
+[node name="WitchUfo" type="CharacterBody2D"]
+collision_mask = 0
+motion_mode = 1
+script = ExtResource("1_3oxp2")
+wheat_out = 4
+should_rotate = false
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
+position = Vector2(-2, -1)
+shape = SubResource("CircleShape2D_maxop")
+
+[node name="NavigationAgent2D" type="NavigationAgent2D" parent="."]
+process_mode = 3
+path_desired_distance = 5.0
+target_desired_distance = 100.0
+path_max_distance = 40.0
+avoidance_enabled = true
+radius = 150.0
+neighbor_distance = 1600.0
+max_speed = 800.0
+
+[node name="Plx" type="Node2D" parent="."]
+script = ExtResource("2_6l42y")
+rate = 0.03
+
+[node name="Bot" type="Sprite2D" parent="Plx"]
+position = Vector2(-44, 73)
+texture = ExtResource("3_qpday")
+
+[node name="Ray" type="Polygon2D" parent="Plx"]
+color = Color(0.360784, 0, 0.356863, 0.196078)
+antialiased = true
+polygon = PackedVector2Array(-19, 88, -171, 527, 88, 525, 19, 86)
+
+[node name="Top" type="Sprite2D" parent="Plx"]
+texture = ExtResource("4_q1mhr")
+
+[node name="HP" type="TextureProgressBar" parent="Plx"]
+custom_minimum_size = Vector2(100, 0)
+anchors_preset = 5
+anchor_left = 0.5
+anchor_right = 0.5
+offset_left = -32.0
+offset_top = -150.0
+offset_right = 118.0
+offset_bottom = -120.0
+grow_horizontal = 2
+value = 100.0
+texture_under = ExtResource("5_cf3a7")
+texture_progress = ExtResource("6_pofdg")
+texture_progress_offset = Vector2(11, 0)
+
+[node name="RerollTimer" type="Timer" parent="."]
+wait_time = 0.1
+one_shot = true
+
+[node name="DamageTimer" type="Timer" parent="."]
+wait_time = 0.05
+
+[node name="AudioStreamPlayer2D" type="AudioStreamPlayer2D" parent="." groups=["sound_player"]]
+stream = ExtResource("7_ls50j")
+panning_strength = 1.5
+bus = &"Music"
+
+[node name="AudioStreamPlayer2D2" type="AudioStreamPlayer2D" parent="." groups=["sound_player"]]
+stream = ExtResource("8_en80a")
+panning_strength = 1.5
+bus = &"Music"
+
+[node name="Area2D" type="Area2D" parent="."]
+
+[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="Area2D"]
+polygon = PackedVector2Array(80.5, -98.7, 80.5, -93.6, 105.5, -55.5, 105.5, -45.6, 94.8, -18.1, 80.7, -20.8, 86.6, -1.2, 167.5, 36.1, 167.5, 40.4, 185.5, 66.4, 185.5, 92.5, 182.4, 92.5, 30.2, 105.5, -131.9, 105.5, -185.5, 94.4, -185.5, 57.6, -81.6, -1.4, -15.4, -87.5, -12.6, -87.5, 13.4, -105.5, 60.6, -105.5)
+
+[node name="Coin" type="AudioStreamPlayer2D" parent="."]
+stream = ExtResource("9_sft0k")
+volume_db = -6.0
+bus = &"SFX"
+script = ExtResource("10_nswe8")
+
+[connection signal="body_entered" from="Area2D" to="." method="_on_area_2d_body_entered"]

+ 91 - 0
scene/entity/ufo_2.tscn

@@ -0,0 +1,91 @@
+[gd_scene load_steps=10 format=3 uid="uid://cr2u5xgg7yhdw"]
+
+[ext_resource type="Script" path="res://scene/entity/ufo.gd" id="1_o7w36"]
+[ext_resource type="Script" path="res://addons/fake_parallax/fake_parallax.gd" id="2_2jwu5"]
+[ext_resource type="Texture2D" uid="uid://bs2pgbdbsf3ey" path="res://res/fork.png" id="3_hvlfv"]
+[ext_resource type="Texture2D" uid="uid://dil0tx0ab553l" path="res://res/pbar.png" id="5_5d2mv"]
+[ext_resource type="AudioStream" uid="uid://d30ydgok76ii6" path="res://snd/mus/ld52-004.ogg" id="6_2yd02"]
+[ext_resource type="Texture2D" uid="uid://b5jrxsko40vge" path="res://res/pbar2.png" id="6_ds0xw"]
+[ext_resource type="AudioStream" uid="uid://dmqxlbrefsbty" path="res://snd/sfx/explosion(1).wav" id="7_po7jr"]
+[ext_resource type="Script" path="res://scene/entity/pc.gd" id="8_c1ur1"]
+
+[sub_resource type="CircleShape2D" id="CircleShape2D_heucv"]
+radius = 99.0454
+
+[node name="ForkUfo" type="CharacterBody2D"]
+collision_mask = 0
+motion_mode = 1
+script = ExtResource("1_o7w36")
+movement_speed = 1400.0
+radius = 30.0
+dps = 4.0
+max_hp = 30.0
+wheat_out = 1
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
+position = Vector2(-2, -1)
+shape = SubResource("CircleShape2D_heucv")
+
+[node name="NavigationAgent2D" type="NavigationAgent2D" parent="."]
+process_mode = 3
+path_desired_distance = 5.0
+target_desired_distance = 100.0
+path_max_distance = 40.0
+avoidance_enabled = true
+radius = 150.0
+neighbor_distance = 1600.0
+max_speed = 800.0
+
+[node name="Plx" type="Node2D" parent="."]
+script = ExtResource("2_2jwu5")
+rate = 0.03
+
+[node name="Ray" type="Polygon2D" parent="Plx"]
+position = Vector2(35, -75)
+color = Color(0.360784, 0, 0.356863, 0.196078)
+antialiased = true
+polygon = PackedVector2Array(-45, 76, 249, 120, 249, 37, -24, 76)
+
+[node name="Top" type="Sprite2D" parent="Plx"]
+texture = ExtResource("3_hvlfv")
+
+[node name="HP" type="TextureProgressBar" parent="Plx"]
+custom_minimum_size = Vector2(100, 0)
+anchors_preset = 5
+anchor_left = 0.5
+anchor_right = 0.5
+offset_left = -75.0
+offset_top = -150.0
+offset_right = 75.0
+offset_bottom = -120.0
+grow_horizontal = 2
+value = 100.0
+texture_under = ExtResource("5_5d2mv")
+texture_progress = ExtResource("6_ds0xw")
+texture_progress_offset = Vector2(11, 0)
+
+[node name="RerollTimer" type="Timer" parent="."]
+wait_time = 0.1
+one_shot = true
+
+[node name="DamageTimer" type="Timer" parent="."]
+wait_time = 0.05
+
+[node name="AudioStreamPlayer2D" type="AudioStreamPlayer2D" parent="." groups=["sound_player"]]
+stream = ExtResource("6_2yd02")
+volume_db = -4.952
+panning_strength = 1.5
+bus = &"Music"
+
+[node name="Area2D" type="Area2D" parent="."]
+
+[node name="CollisionPolygon2D2" type="CollisionPolygon2D" parent="Area2D"]
+polygon = PackedVector2Array(44.5, -42.2, 35.5, -30.5, -4.5, -30.5, -4.5, -17.2, 34.5, -11.2, 34.5, -9.8, 44.5, -5.3, 44.5, 4.5, 33.1, 11.5, 27.8, 11.5, -4.5, 17.2, -4.5, 30.5, 30.2, 30.5, 35.5, 28.7, 35.5, 31.5, 40.5, 35.5, 40.5, 37.9, 44.5, 45.3, 44.5, 49.5, -30.1, 49.5, -40.5, 42.6, -40.5, 14.1, -44.5, 8.1, -44.5, -6.7, -40.5, -14, -40.5, -43.5, -38.1, -43.5, -28.7, -49.5, 44.5, -49.5)
+
+[node name="Coin" type="AudioStreamPlayer2D" parent="."]
+stream = ExtResource("7_po7jr")
+volume_db = -6.0
+bus = &"SFX"
+script = ExtResource("8_c1ur1")
+
+[connection signal="body_entered" from="Area2D" to="." method="_on_area_2d_body_entered"]

+ 105 - 0
scene/entity/ufo_2_big.tscn

@@ -0,0 +1,105 @@
+[gd_scene load_steps=11 format=3 uid="uid://cv3bq4qcu0r6k"]
+
+[ext_resource type="Script" path="res://scene/entity/ufo.gd" id="1_nf0xj"]
+[ext_resource type="Script" path="res://addons/fake_parallax/fake_parallax.gd" id="2_hsc4o"]
+[ext_resource type="Texture2D" uid="uid://bs2pgbdbsf3ey" path="res://res/fork.png" id="3_i6xja"]
+[ext_resource type="Texture2D" uid="uid://dil0tx0ab553l" path="res://res/pbar.png" id="4_2yfhy"]
+[ext_resource type="Texture2D" uid="uid://b5jrxsko40vge" path="res://res/pbar2.png" id="5_arfur"]
+[ext_resource type="AudioStream" uid="uid://d30ydgok76ii6" path="res://snd/mus/ld52-004.ogg" id="6_1ke6q"]
+[ext_resource type="AudioStream" uid="uid://ckjujaa5v1xl7" path="res://snd/mus/ld52-009.ogg" id="7_vbddy"]
+[ext_resource type="AudioStream" uid="uid://dmqxlbrefsbty" path="res://snd/sfx/explosion(1).wav" id="8_uoxbc"]
+[ext_resource type="Script" path="res://scene/entity/pc.gd" id="9_6r16m"]
+
+[sub_resource type="CircleShape2D" id="CircleShape2D_3w70t"]
+radius = 99.0454
+
+[node name="ForkUfo" type="CharacterBody2D"]
+collision_mask = 0
+motion_mode = 1
+script = ExtResource("1_nf0xj")
+movement_speed = 1400.0
+radius = 30.0
+dps = 4.0
+max_hp = 70.0
+wheat_out = 1
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
+position = Vector2(-2, -1)
+shape = SubResource("CircleShape2D_3w70t")
+
+[node name="NavigationAgent2D" type="NavigationAgent2D" parent="."]
+process_mode = 3
+path_desired_distance = 5.0
+target_desired_distance = 100.0
+path_max_distance = 40.0
+avoidance_enabled = true
+radius = 150.0
+neighbor_distance = 1600.0
+max_speed = 800.0
+
+[node name="Plx" type="Node2D" parent="."]
+script = ExtResource("2_hsc4o")
+rate = 0.03
+
+[node name="Ray" type="Polygon2D" parent="Plx"]
+position = Vector2(82, -103)
+color = Color(0.360784, 0, 0.356863, 0.196078)
+antialiased = true
+polygon = PackedVector2Array(-45, 76, 249, 120, 249, 37, -24, 76)
+
+[node name="Ray2" type="Polygon2D" parent="Plx"]
+position = Vector2(-15, -102)
+color = Color(0.360784, 0, 0.356863, 0.196078)
+antialiased = true
+polygon = PackedVector2Array(-45, 76, 249, 120, 249, 37, -24, 76)
+
+[node name="Top" type="Sprite2D" parent="Plx"]
+scale = Vector2(1.3, 1.3)
+texture = ExtResource("3_i6xja")
+
+[node name="HP" type="TextureProgressBar" parent="Plx"]
+custom_minimum_size = Vector2(100, 0)
+anchors_preset = 5
+anchor_left = 0.5
+anchor_right = 0.5
+offset_left = -75.0
+offset_top = -150.0
+offset_right = 75.0
+offset_bottom = -120.0
+grow_horizontal = 2
+value = 100.0
+texture_under = ExtResource("4_2yfhy")
+texture_progress = ExtResource("5_arfur")
+texture_progress_offset = Vector2(11, 0)
+
+[node name="RerollTimer" type="Timer" parent="."]
+wait_time = 0.1
+one_shot = true
+
+[node name="DamageTimer" type="Timer" parent="."]
+wait_time = 0.05
+
+[node name="AudioStreamPlayer2D" type="AudioStreamPlayer2D" parent="." groups=["sound_player"]]
+stream = ExtResource("6_1ke6q")
+volume_db = -4.952
+panning_strength = 1.5
+bus = &"Music"
+
+[node name="AudioStreamPlayer2D2" type="AudioStreamPlayer2D" parent="." groups=["sound_player"]]
+stream = ExtResource("7_vbddy")
+volume_db = -4.952
+panning_strength = 1.5
+bus = &"Music"
+
+[node name="Area2D" type="Area2D" parent="."]
+
+[node name="CollisionPolygon2D2" type="CollisionPolygon2D" parent="Area2D"]
+polygon = PackedVector2Array(44.5, -42.2, 35.5, -30.5, -4.5, -30.5, -4.5, -17.2, 34.5, -11.2, 34.5, -9.8, 44.5, -5.3, 44.5, 4.5, 33.1, 11.5, 27.8, 11.5, -4.5, 17.2, -4.5, 30.5, 30.2, 30.5, 35.5, 28.7, 35.5, 31.5, 40.5, 35.5, 40.5, 37.9, 44.5, 45.3, 44.5, 49.5, -30.1, 49.5, -40.5, 42.6, -40.5, 14.1, -44.5, 8.1, -44.5, -6.7, -40.5, -14, -40.5, -43.5, -38.1, -43.5, -28.7, -49.5, 44.5, -49.5)
+
+[node name="Coin" type="AudioStreamPlayer2D" parent="."]
+stream = ExtResource("8_uoxbc")
+volume_db = -6.0
+bus = &"SFX"
+script = ExtResource("9_6r16m")
+
+[connection signal="body_entered" from="Area2D" to="." method="_on_area_2d_body_entered"]

+ 89 - 0
scene/entity/ufo_3.tscn

@@ -0,0 +1,89 @@
+[gd_scene load_steps=10 format=3 uid="uid://cp63rvykkii0v"]
+
+[ext_resource type="Script" path="res://scene/entity/ufo.gd" id="1_cms35"]
+[ext_resource type="Script" path="res://addons/fake_parallax/fake_parallax.gd" id="2_psv2f"]
+[ext_resource type="Texture2D" uid="uid://skwe3cc7xbuh" path="res://res/star.png" id="3_aax7u"]
+[ext_resource type="Texture2D" uid="uid://dil0tx0ab553l" path="res://res/pbar.png" id="5_fidyk"]
+[ext_resource type="AudioStream" uid="uid://duh6bj2qs0pni" path="res://snd/mus/ld52-005.ogg" id="6_8tq0x"]
+[ext_resource type="Texture2D" uid="uid://b5jrxsko40vge" path="res://res/pbar2.png" id="6_k58jn"]
+[ext_resource type="AudioStream" uid="uid://dmqxlbrefsbty" path="res://snd/sfx/explosion(1).wav" id="7_qj3sr"]
+[ext_resource type="Script" path="res://scene/entity/pc.gd" id="8_3cgvt"]
+
+[sub_resource type="CircleShape2D" id="CircleShape2D_prh1k"]
+radius = 127.063
+
+[node name="Star" type="CharacterBody2D"]
+collision_mask = 0
+motion_mode = 1
+script = ExtResource("1_cms35")
+dps = 30.0
+max_hp = 10.0
+wheat_out = 10
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
+position = Vector2(-2, -1)
+shape = SubResource("CircleShape2D_prh1k")
+
+[node name="NavigationAgent2D" type="NavigationAgent2D" parent="."]
+process_mode = 3
+path_desired_distance = 5.0
+target_desired_distance = 100.0
+path_max_distance = 40.0
+avoidance_enabled = true
+radius = 150.0
+neighbor_distance = 1600.0
+max_speed = 800.0
+
+[node name="Plx" type="Node2D" parent="."]
+script = ExtResource("2_psv2f")
+rate = 0.03
+
+[node name="Ray" type="Polygon2D" parent="Plx"]
+position = Vector2(-1, -89)
+color = Color(0.360784, 0, 0.356863, 0.745098)
+antialiased = true
+polygon = PackedVector2Array(-19, 88, -113, 529, 88, 525, 19, 86)
+
+[node name="Top" type="Sprite2D" parent="Plx"]
+texture = ExtResource("3_aax7u")
+
+[node name="HP" type="TextureProgressBar" parent="Plx"]
+custom_minimum_size = Vector2(100, 0)
+anchors_preset = 5
+anchor_left = 0.5
+anchor_right = 0.5
+offset_left = -75.0
+offset_top = -150.0
+offset_right = 75.0
+offset_bottom = -120.0
+grow_horizontal = 2
+value = 100.0
+texture_under = ExtResource("5_fidyk")
+texture_progress = ExtResource("6_k58jn")
+texture_progress_offset = Vector2(11, 0)
+
+[node name="RerollTimer" type="Timer" parent="."]
+wait_time = 0.1
+one_shot = true
+
+[node name="DamageTimer" type="Timer" parent="."]
+wait_time = 0.05
+
+[node name="AudioStreamPlayer2D" type="AudioStreamPlayer2D" parent="." groups=["sound_player"]]
+stream = ExtResource("6_8tq0x")
+panning_strength = 1.5
+bus = &"Music"
+
+[node name="Area2D" type="Area2D" parent="."]
+
+[node name="CollisionShape2D2" type="CollisionShape2D" parent="Area2D"]
+position = Vector2(-2, -1)
+shape = SubResource("CircleShape2D_prh1k")
+
+[node name="Coin" type="AudioStreamPlayer2D" parent="."]
+stream = ExtResource("7_qj3sr")
+volume_db = -6.0
+bus = &"SFX"
+script = ExtResource("8_3cgvt")
+
+[connection signal="body_entered" from="Area2D" to="." method="_on_area_2d_body_entered"]

+ 96 - 0
scene/entity/ufo_4.tscn

@@ -0,0 +1,96 @@
+[gd_scene load_steps=11 format=3 uid="uid://gxcd2x6nw0i"]
+
+[ext_resource type="Script" path="res://scene/entity/ufo.gd" id="1_1w43w"]
+[ext_resource type="Script" path="res://addons/fake_parallax/fake_parallax.gd" id="2_gm1b8"]
+[ext_resource type="Texture2D" uid="uid://csqk7vyq6ecpl" path="res://res/witch_ufo_bot.png" id="3_g4i2j"]
+[ext_resource type="Texture2D" uid="uid://baacv2khh4ef8" path="res://res/witch_ufo_top.png" id="4_mdvt5"]
+[ext_resource type="Texture2D" uid="uid://dil0tx0ab553l" path="res://res/pbar.png" id="5_7xohd"]
+[ext_resource type="Texture2D" uid="uid://b5jrxsko40vge" path="res://res/pbar2.png" id="6_88oiw"]
+[ext_resource type="AudioStream" uid="uid://b012jhb83jo30" path="res://snd/mus/ld52-006.ogg" id="7_t5ir7"]
+[ext_resource type="AudioStream" uid="uid://dmqxlbrefsbty" path="res://snd/sfx/explosion(1).wav" id="8_yj32d"]
+[ext_resource type="Script" path="res://scene/entity/pc.gd" id="9_3wuwx"]
+
+[sub_resource type="CircleShape2D" id="CircleShape2D_ne4oq"]
+radius = 223.258
+
+[node name="WitchUfo" type="CharacterBody2D"]
+scale = Vector2(3, 3)
+collision_mask = 0
+motion_mode = 1
+script = ExtResource("1_1w43w")
+movement_speed = 200.0
+radius = 450.0
+dps = 150.0
+max_hp = 20000.0
+wheat_out = 100
+should_rotate = false
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
+position = Vector2(-2, -1)
+shape = SubResource("CircleShape2D_ne4oq")
+
+[node name="NavigationAgent2D" type="NavigationAgent2D" parent="."]
+process_mode = 3
+path_desired_distance = 5.0
+target_desired_distance = 100.0
+path_max_distance = 40.0
+avoidance_enabled = true
+radius = 150.0
+neighbor_distance = 1600.0
+max_speed = 800.0
+
+[node name="Plx" type="Node2D" parent="."]
+script = ExtResource("2_gm1b8")
+rate = 0.03
+
+[node name="Bot" type="Sprite2D" parent="Plx"]
+position = Vector2(-44, 73)
+texture = ExtResource("3_g4i2j")
+
+[node name="Ray" type="Polygon2D" parent="Plx"]
+color = Color(0.360784, 0, 0.356863, 0.745098)
+antialiased = true
+polygon = PackedVector2Array(-19, 88, -171, 527, 88, 525, 19, 86)
+
+[node name="Top" type="Sprite2D" parent="Plx"]
+texture = ExtResource("4_mdvt5")
+
+[node name="HP" type="TextureProgressBar" parent="Plx"]
+custom_minimum_size = Vector2(100, 0)
+anchors_preset = 5
+anchor_left = 0.5
+anchor_right = 0.5
+offset_left = -75.0
+offset_top = -150.0
+offset_right = 75.0
+offset_bottom = -120.0
+grow_horizontal = 2
+value = 100.0
+texture_under = ExtResource("5_7xohd")
+texture_progress = ExtResource("6_88oiw")
+texture_progress_offset = Vector2(11, 0)
+
+[node name="RerollTimer" type="Timer" parent="."]
+wait_time = 0.1
+one_shot = true
+
+[node name="DamageTimer" type="Timer" parent="."]
+wait_time = 0.05
+
+[node name="AudioStreamPlayer2D" type="AudioStreamPlayer2D" parent="." groups=["sound_player"]]
+stream = ExtResource("7_t5ir7")
+panning_strength = 1.5
+bus = &"Music"
+
+[node name="Area2D" type="Area2D" parent="."]
+
+[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="Area2D"]
+polygon = PackedVector2Array(80.5, -98.7, 80.5, -93.6, 105.5, -55.5, 105.5, -45.6, 94.8, -18.1, 80.7, -20.8, 86.6, -1.2, 167.5, 36.1, 167.5, 40.4, 185.5, 66.4, 185.5, 92.5, 182.4, 92.5, 30.2, 105.5, -131.9, 105.5, -185.5, 94.4, -185.5, 57.6, -81.6, -1.4, -15.4, -87.5, -12.6, -87.5, 13.4, -105.5, 60.6, -105.5)
+
+[node name="Coin" type="AudioStreamPlayer2D" parent="."]
+stream = ExtResource("8_yj32d")
+volume_db = -6.0
+bus = &"SFX"
+script = ExtResource("9_3wuwx")
+
+[connection signal="body_entered" from="Area2D" to="." method="_on_area_2d_body_entered"]

+ 36 - 0
scene/entity/ufo_ast.gd

@@ -0,0 +1,36 @@
+extends UFO
+
+var speed = 200.0
+var damage = 0
+var timeout: Timer = Timer.new()
+var last_vector: Vector2 = Vector2(0, 0)
+
+func _ready():
+    super()
+    $NavigationAgent2D.set_target_desired_distance(0)
+    $NavigationAgent2D.set_avoidance_enabled(false)
+    timeout.set_wait_time(1000.0)
+    add_child(timeout)
+    timeout.start()
+    timeout.connect("timeout", _on_timeout)
+   
+func _physics_process(delta: float):
+    if target != null:
+        var dist = target.get_global_position() - get_global_position()
+        if dist.length() < 60.0:
+            target.deal_damage(dps, null)
+            get_parent().remove_child(self)
+            queue_free()
+        last_vector = dist.normalized()
+        velocity = last_vector * speed
+    else:
+        get_parent().remove_child(self)
+        queue_free()
+    $Plx/Top.rotate(delta)
+    move_and_slide()
+
+func _on_timeout():
+    get_parent().remove_child(self)
+    queue_free()
+
+

+ 94 - 0
scene/entity/ufo_ast.tscn

@@ -0,0 +1,94 @@
+[gd_scene load_steps=11 format=3 uid="uid://d0pommw62g8b3"]
+
+[ext_resource type="Script" path="res://scene/entity/ufo_ast.gd" id="1_nr72r"]
+[ext_resource type="Script" path="res://addons/fake_parallax/fake_parallax.gd" id="2_g6yg3"]
+[ext_resource type="Texture2D" uid="uid://drlwbga1aayn1" path="res://res/asteroid.png" id="3_gf2i4"]
+[ext_resource type="Texture2D" uid="uid://dil0tx0ab553l" path="res://res/pbar.png" id="4_grruk"]
+[ext_resource type="Texture2D" uid="uid://b5jrxsko40vge" path="res://res/pbar2.png" id="5_tifoi"]
+[ext_resource type="AudioStream" uid="uid://dcm0d3mgf156b" path="res://snd/mus/ld52-007.ogg" id="6_axe7p"]
+[ext_resource type="AudioStream" uid="uid://b4rii15t0tfro" path="res://snd/mus/ld52-008.ogg" id="7_mrp4u"]
+[ext_resource type="AudioStream" uid="uid://dmqxlbrefsbty" path="res://snd/sfx/explosion(1).wav" id="8_f61qb"]
+[ext_resource type="Script" path="res://scene/entity/pc.gd" id="9_rg678"]
+
+[sub_resource type="CircleShape2D" id="CircleShape2D_prh1k"]
+radius = 127.063
+
+[node name="Asteroid" type="CharacterBody2D"]
+collision_mask = 0
+motion_mode = 1
+script = ExtResource("1_nr72r")
+movement_speed = 200.0
+dps = 60.0
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
+position = Vector2(-2, -1)
+shape = SubResource("CircleShape2D_prh1k")
+
+[node name="NavigationAgent2D" type="NavigationAgent2D" parent="."]
+process_mode = 3
+path_desired_distance = 5.0
+target_desired_distance = 100.0
+path_max_distance = 40.0
+avoidance_enabled = true
+radius = 150.0
+neighbor_distance = 1600.0
+max_speed = 800.0
+
+[node name="Plx" type="Node2D" parent="."]
+script = ExtResource("2_g6yg3")
+rate = 0.03
+
+[node name="Ray" type="Polygon2D" parent="Plx"]
+position = Vector2(-1, -89)
+color = Color(0.360784, 0, 0.356863, 0.745098)
+antialiased = true
+polygon = PackedVector2Array(-19, 88, -113, 529, 88, 525, 19, 86)
+
+[node name="Top" type="Sprite2D" parent="Plx"]
+texture = ExtResource("3_gf2i4")
+
+[node name="HP" type="TextureProgressBar" parent="Plx"]
+custom_minimum_size = Vector2(100, 0)
+anchors_preset = 5
+anchor_left = 0.5
+anchor_right = 0.5
+offset_left = -75.0
+offset_top = -150.0
+offset_right = 75.0
+offset_bottom = -120.0
+grow_horizontal = 2
+value = 100.0
+texture_under = ExtResource("4_grruk")
+texture_progress = ExtResource("5_tifoi")
+texture_progress_offset = Vector2(11, 0)
+
+[node name="RerollTimer" type="Timer" parent="."]
+wait_time = 0.1
+one_shot = true
+
+[node name="DamageTimer" type="Timer" parent="."]
+wait_time = 0.05
+
+[node name="AudioStreamPlayer2D" type="AudioStreamPlayer2D" parent="." groups=["sound_player"]]
+stream = ExtResource("6_axe7p")
+panning_strength = 1.5
+bus = &"Music"
+
+[node name="AudioStreamPlayer2D2" type="AudioStreamPlayer2D" parent="." groups=["sound_player"]]
+stream = ExtResource("7_mrp4u")
+panning_strength = 1.5
+bus = &"Music"
+
+[node name="Area2D" type="Area2D" parent="."]
+
+[node name="CollisionShape2D2" type="CollisionShape2D" parent="Area2D"]
+position = Vector2(-2, -1)
+shape = SubResource("CircleShape2D_prh1k")
+
+[node name="Coin" type="AudioStreamPlayer2D" parent="."]
+stream = ExtResource("8_f61qb")
+volume_db = -6.0
+bus = &"SFX"
+script = ExtResource("9_rg678")
+
+[connection signal="body_entered" from="Area2D" to="." method="_on_area_2d_body_entered"]

+ 16 - 0
scene/entity/wheat.gd

@@ -0,0 +1,16 @@
+extends RigidBody2D
+
+var SPEED = 300.0
+var gravity = ProjectSettings.get_setting("physics/2d/default_gravity")
+
+func _ready():
+    var angle = get_rotation()
+    linear_velocity = Vector2(cos(angle) * SPEED, sin(angle) * SPEED)
+
+
+func _on_capture_area_mouse_entered():
+    $"../../Economy".add(1)
+    $Coin.play()
+    hide()
+    await $Coin.finished
+    get_parent().remove_child(self)

+ 39 - 0
scene/entity/wheat.tscn

@@ -0,0 +1,39 @@
+[gd_scene load_steps=7 format=3 uid="uid://ccsytlw2xbxan"]
+
+[ext_resource type="Texture2D" uid="uid://cankh6gqcfwh8" path="res://res/wheat.png" id="1_8mf82"]
+[ext_resource type="Script" path="res://scene/entity/wheat.gd" id="1_r6usw"]
+[ext_resource type="AudioStream" uid="uid://cymt7xlvjplx7" path="res://snd/sfx/coin.wav" id="3_pykee"]
+[ext_resource type="Script" path="res://scene/entity/pc.gd" id="4_feb1a"]
+
+[sub_resource type="RectangleShape2D" id="RectangleShape2D_tt0m1"]
+size = Vector2(9, 152)
+
+[sub_resource type="RectangleShape2D" id="RectangleShape2D_0qtwq"]
+size = Vector2(316.5, 289)
+
+[node name="Wheat" type="RigidBody2D"]
+collision_layer = 0
+collision_mask = 4
+script = ExtResource("1_r6usw")
+
+[node name="Sprite2D" type="Sprite2D" parent="."]
+modulate = Color(0.670588, 0.380392, 0, 1)
+texture = ExtResource("1_8mf82")
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
+position = Vector2(-0.5, 0)
+shape = SubResource("RectangleShape2D_tt0m1")
+
+[node name="CaptureArea" type="Area2D" parent="."]
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="CaptureArea"]
+position = Vector2(1, -1)
+shape = SubResource("RectangleShape2D_0qtwq")
+
+[node name="Coin" type="AudioStreamPlayer2D" parent="."]
+stream = ExtResource("3_pykee")
+volume_db = -6.0
+bus = &"SFX"
+script = ExtResource("4_feb1a")
+
+[connection signal="mouse_entered" from="CaptureArea" to="." method="_on_capture_area_mouse_entered"]

+ 22 - 0
scene/pause_menu/pause_menu.gd

@@ -0,0 +1,22 @@
+extends Control
+
+@onready var root = get_tree().get_root().get_child(0)
+var queue_unpause = false
+
+func _input(input: InputEvent):
+    if input.is_action_pressed("pause"):
+        queue_unpause = true
+
+func _process(_delta: float):
+    if queue_unpause:
+        unpause()
+        queue_unpause = false
+
+func unpause():
+    if root.main_menu_beaten:
+        get_tree().paused = false
+    hide()
+
+func _on_visibility_changed():
+    if Input.get_connected_joypads().size() > 0:
+        $"CenterContainer/Buttons/WindowMode/CenterContainer/OptionButton".grab_focus()

File diff suppressed because it is too large
+ 2463 - 0
scene/pause_menu/pause_menu.tscn


+ 15 - 0
scene/pause_menu/vol.gd

@@ -0,0 +1,15 @@
+extends HBoxContainer
+
+@export var bus: int = 0
+
+# Called when the node enters the scene tree for the first time.
+func _ready():
+    find_child("Button").connect("value_changed", pls)
+
+func pls(val: float):
+    if val < 50:
+        AudioServer.set_bus_volume_db(bus, -5 + (100 - val) / 2 * -1)
+    if val > 50:
+        AudioServer.set_bus_volume_db(bus, -5 + (100 - val) / 10)
+    #print(AudioServer.get_bus_volume_db(bus))
+    #print(val, " ", 100 - val)

+ 14 - 0
scene/pause_menu/vsync.gd

@@ -0,0 +1,14 @@
+extends Button
+
+var vsync_on: bool = true
+
+func _ready():
+    update_vsync()
+
+func _on_pressed():
+    vsync_on = !vsync_on
+    update_vsync()
+
+func update_vsync():
+    DisplayServer.window_set_vsync_mode(vsync_on)
+    set_text("on" if vsync_on else "off")

+ 22 - 0
scene/pause_menu/window_mode.gd

@@ -0,0 +1,22 @@
+extends Button
+
+var window_mode: int = 0
+
+func _ready():
+    update_window()
+
+func _on_item_selected(index: int):
+    if index == 0:
+        window_mode = 0
+    elif index == 1:
+        window_mode = 3
+    else:
+        window_mode = 4
+    update_window()
+
+func update_window():
+    DisplayServer.window_set_mode(window_mode)
+    if window_mode != 0:
+        $"../../../Rez".hide()
+    else:
+        $"../../../Rez".show()

+ 19 - 0
scene/snd/snd_listener.tscn

@@ -0,0 +1,19 @@
+[gd_scene load_steps=2 format=3 uid="uid://cj5nsarco218p"]
+
+[ext_resource type="AudioStream" uid="uid://vto0qax0wsf1" path="res://snd/mus/ld52-001.ogg" id="1_q1r30"]
+
+[node name="Node2D" type="Node2D"]
+
+[node name="AudioListener2D" type="AudioListener2D" parent="."]
+position = Vector2(351, 255)
+current = true
+
+[node name="AudioStreamPlayer2D" type="AudioStreamPlayer2D" parent="." groups=["sound_player"]]
+position = Vector2(616, 261)
+stream = ExtResource("1_q1r30")
+volume_db = -0.929
+autoplay = true
+max_distance = 5000.0
+attenuation = 2.82843
+panning_strength = 3.0
+bus = &"Music"

+ 20 - 0
scene/ui/plant_button.gd

@@ -0,0 +1,20 @@
+extends Control
+
+@onready var button_root = $"../.."
+@onready var tooltip = $"../../Tooltip"
+
+func _ready():
+    connect("mouse_entered", _on_mouse_entered)
+    connect("mouse_exited", _on_mouse_exited)
+    connect("pressed", _on_pressed)
+
+func _on_mouse_entered():
+    tooltip.show()
+
+func _on_mouse_exited():
+    tooltip.hide()
+
+func _on_pressed():
+    var selector = get_tree().get_root().find_child("SelectedItem", true, false)
+    tooltip.hide()
+    selector.set_item(button_root.plant.instantiate())

+ 69 - 0
scene/ui/plant_button.tscn

@@ -0,0 +1,69 @@
+[gd_scene load_steps=4 format=3 uid="uid://d0myc3w8eieve"]
+
+[ext_resource type="Texture2D" uid="uid://0f8gj2t81y04" path="res://res/missdemandrake_icon.png" id="1_f73da"]
+[ext_resource type="Script" path="res://scene/ui/plant_button.gd" id="1_g4acw"]
+[ext_resource type="Script" path="res://scene/ui/plant_button_root.gd" id="1_hg7q7"]
+
+[node name="PlantButton" type="Control"]
+custom_minimum_size = Vector2(80, 72)
+layout_mode = 3
+anchors_preset = 0
+script = ExtResource("1_hg7q7")
+
+[node name="MarginContainer" type="MarginContainer" parent="."]
+anchors_preset = 8
+anchor_left = 0.5
+anchor_top = 0.5
+anchor_right = 0.5
+anchor_bottom = 0.5
+offset_left = -40.0
+offset_top = -36.0
+offset_right = 40.0
+offset_bottom = 36.0
+grow_horizontal = 2
+grow_vertical = 2
+theme_override_constants/margin_left = 8
+theme_override_constants/margin_top = 4
+theme_override_constants/margin_right = 8
+theme_override_constants/margin_bottom = 4
+
+[node name="Button" type="Button" parent="MarginContainer"]
+custom_minimum_size = Vector2(64, 64)
+offset_left = 8.0
+offset_top = 4.0
+offset_right = 72.0
+offset_bottom = 68.0
+focus_mode = 0
+icon = ExtResource("1_f73da")
+expand_icon = true
+script = ExtResource("1_g4acw")
+
+[node name="Tooltip" type="MarginContainer" parent="."]
+visible = false
+anchors_preset = -1
+anchor_top = 0.5
+anchor_bottom = 0.5
+grow_horizontal = 0
+grow_vertical = 2
+theme_override_constants/margin_right = 32
+
+[node name="Tooltip2" type="PanelContainer" parent="Tooltip"]
+offset_right = 266.0
+offset_bottom = 16.0
+
+[node name="Tooltip3" type="MarginContainer" parent="Tooltip/Tooltip2"]
+theme_override_constants/margin_left = 8
+theme_override_constants/margin_top = 8
+theme_override_constants/margin_right = 8
+theme_override_constants/margin_bottom = 8
+
+[node name="VBoxContainer" type="VBoxContainer" parent="Tooltip/Tooltip2/Tooltip3"]
+offset_left = 8.0
+offset_top = 8.0
+offset_right = 258.0
+offset_bottom = 8.0
+
+[node name="Label" type="RichTextLabel" parent="Tooltip/Tooltip2/Tooltip3/VBoxContainer"]
+custom_minimum_size = Vector2(250, 0)
+bbcode_enabled = true
+fit_content_height = true

+ 37 - 0
scene/ui/plant_button_root.gd

@@ -0,0 +1,37 @@
+extends Control
+
+@export_multiline var description = ""
+@export var icon: Texture
+@export var plant: PackedScene
+@export var hotkey: int
+var t_cost: int = -1
+var shown: bool = false
+
+func _input(ev):
+    var b = $MarginContainer/Button
+    if ev is InputEventKey and ev.keycode == hotkey and !ev.pressed and !b.disabled:
+        b._on_pressed()
+
+func _ready():
+    var p = plant.instantiate()
+    description += "\n[color=#88FFFF]Root strength: " + str(p.max_hp) + "[/color]"
+    description += "\n[color=#FF8888]Base damage: " + str(p.attack_damage) + "[/color]"
+    description += "\n[color=#88FF88]Fire rate: " + str(p.attack_rate) + "s [/color]"
+    description += "\n[color=#FFFF88]Cost: " + str(p.cost) + "[/color]"
+    description += "[/font]"
+    t_cost = p.cost
+    find_child("Label").set_text("[center][font_size=18]???[/font_size][/center]")
+    find_child("Button").set_button_icon(icon)
+    updoot(19)
+
+func updoot(money: int):
+    if t_cost >= 0 and money >= t_cost:
+        set_modulate(Color(1.0, 1.0, 1.0, 1.0))
+        $MarginContainer/Button.set_disabled(false)
+    else:
+        set_modulate(Color(0.4, 0.4, 0.4, 1.0))
+        $MarginContainer/Button.set_disabled(true)
+        
+    if t_cost >= 0 and shown == false and money >= t_cost - 10:
+        find_child("Label").set_text(description)
+        shown = true

+ 30 - 0
scene/ui/speedrun_timer.gd

@@ -0,0 +1,30 @@
+extends Control
+
+var time: float;
+var secs_previous: int;
+var dead: bool = false
+
+func _ready():
+    reset()
+
+func _process(delta):
+    if !dead:
+        time += delta
+    var secs_raw: int = int(time) % 60;
+    if secs_raw != secs_previous:
+        secs_previous = secs_raw
+        var secs: String = str(int(time) % 60);
+        var mins: String = str(int(time / 60.0));
+        if mins.length() == 1:
+            mins = "0" + mins;
+        if secs.length() == 1:
+            secs = "0" + secs;
+        $Label.set_text("%s:%s" % [mins, secs]);
+
+func stop():
+    dead = true
+
+func reset():
+    time = 0.0
+    secs_previous = -1
+    dead = false

+ 17 - 0
scene/ui/speedrun_timer.tscn

@@ -0,0 +1,17 @@
+[gd_scene load_steps=2 format=3 uid="uid://2wtd5v2wm5ym"]
+
+[ext_resource type="Script" path="res://scene/ui/speedrun_timer.gd" id="1_bcnba"]
+
+[node name="SpeedrunTimer" type="Control"]
+layout_mode = 3
+anchors_preset = 2
+anchor_top = 1.0
+anchor_bottom = 1.0
+grow_vertical = 0
+script = ExtResource("1_bcnba")
+
+[node name="Label" type="Label" parent="."]
+offset_left = -41.0
+offset_top = -26.0
+text = "00:00"
+vertical_alignment = 2

+ 0 - 0
snd/mus/ld52-001.ogg


Some files were not shown because too many files changed in this diff