From e53a1dd7b5281e37d1a52d2cb6e8a88627d69894 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Qui=C3=B1ones?= Date: Tue, 24 Mar 2026 10:37:23 -0300 Subject: [PATCH 01/12] InteractArea: Emit signal when characters start/stop seeing it Maintain an array of CharacterSight areas and emit the signal when the array changes. --- .../props/character_sight/character_sight.gd | 11 +++++++- .../props/interact_area/interact_area.gd | 26 +++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/scenes/game_elements/props/character_sight/character_sight.gd b/scenes/game_elements/props/character_sight/character_sight.gd index d2bf17474..9edbdb2f6 100644 --- a/scenes/game_elements/props/character_sight/character_sight.gd +++ b/scenes/game_elements/props/character_sight/character_sight.gd @@ -22,7 +22,16 @@ signal interact_area_changed var is_looking_from_right: bool = false ## The area that the character is currently observing. -var interact_area: InteractArea +var interact_area: InteractArea: + set = _set_interact_area + + +func _set_interact_area(new_interact_area: InteractArea) -> void: + if interact_area: + interact_area.remove_observer(self) + interact_area = new_interact_area + if new_interact_area: + interact_area.add_observer(self) func _ready() -> void: diff --git a/scenes/game_elements/props/interact_area/interact_area.gd b/scenes/game_elements/props/interact_area/interact_area.gd index 0144f3a1a..1b595d054 100644 --- a/scenes/game_elements/props/interact_area/interact_area.gd +++ b/scenes/game_elements/props/interact_area/interact_area.gd @@ -17,6 +17,9 @@ extends Area2D signal interaction_started(player: Player, from_right: bool) signal interaction_ended +## Emitted when characters start or stop seeing this area for interaction. +signal observers_changed + const EXAMPLE_INTERACTION_FONT = preload("uid://c3bb7lmvdqc5e") const EXAMPLE_INTERACTION_FONT_SIZE = 34 @@ -33,6 +36,13 @@ var interact_label_position: Vector2: set_collision_layer_value(Enums.CollisionLayers.INTERACTABLE, not disabled) @export var action: String = "Talk" +## Whether this area is being observed by one or more characters. +## That is, if a [CharacterSight] area is seeing this area for interaction. +var is_being_observed: bool: + get = _get_is_being_observed + +var _observers: Array[CharacterSight] = [] + func start_interaction(player: Player, from_right: bool) -> void: interaction_started.emit(player, from_right) @@ -46,6 +56,22 @@ func get_global_interact_label_position() -> Vector2: return to_global(interact_label_position) +## A [CharacterSight] calls this when it starts seeing this area. +func add_observer(character_sight: CharacterSight) -> void: + _observers.append(character_sight) + observers_changed.emit() + + +## A [CharacterSight] calls this when it stops seeing this area. +func remove_observer(character_sight: CharacterSight) -> void: + _observers.erase(character_sight) + observers_changed.emit() + + +func _get_is_being_observed() -> bool: + return bool(_observers.size()) + + func _ready() -> void: collision_layer = 0 collision_mask = 0 From c48735e3cd2ddb0cb633c396bc1e8a3dc6f71302 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Qui=C3=B1ones?= Date: Fri, 20 Mar 2026 11:21:00 -0300 Subject: [PATCH 02/12] Add powerup for abilities The powerup scene gives one ability when picked upon interaction. It displays a dialogue telling the player about the new ability. The default dialogue just says "new ability: ABILITY NAME". It has a collected signal that can be used to display input hints for the corresponding ability. Or doing other side effects, like zooming out the camera when the longer thread powerup is picked. It has a ripple effect that can be colored, so we can have color codes for the abilities. The asset is a SpriteFrames that is proxied so it can be customized. --- .../components/default_powerup.dialogue | 5 + .../default_powerup.dialogue.import | 16 +++ .../props/powerup/components/powerup.aseprite | 3 + .../props/powerup/components/powerup.gd | 115 ++++++++++++++++++ .../props/powerup/components/powerup.gd.uid | 1 + .../props/powerup/components/powerup.png | 3 + .../powerup/components/powerup.png.import | 40 ++++++ .../powerup/components/powerup_highlight.png | 3 + .../components/powerup_highlight.png.import | 40 ++++++ .../powerup/components/ripple_effect.gdshader | 40 ++++++ .../components/ripple_effect.gdshader.uid | 1 + .../game_elements/props/powerup/powerup.tscn | 77 ++++++++++++ 12 files changed, 344 insertions(+) create mode 100644 scenes/game_elements/props/powerup/components/default_powerup.dialogue create mode 100644 scenes/game_elements/props/powerup/components/default_powerup.dialogue.import create mode 100644 scenes/game_elements/props/powerup/components/powerup.aseprite create mode 100644 scenes/game_elements/props/powerup/components/powerup.gd create mode 100644 scenes/game_elements/props/powerup/components/powerup.gd.uid create mode 100644 scenes/game_elements/props/powerup/components/powerup.png create mode 100644 scenes/game_elements/props/powerup/components/powerup.png.import create mode 100644 scenes/game_elements/props/powerup/components/powerup_highlight.png create mode 100644 scenes/game_elements/props/powerup/components/powerup_highlight.png.import create mode 100644 scenes/game_elements/props/powerup/components/ripple_effect.gdshader create mode 100644 scenes/game_elements/props/powerup/components/ripple_effect.gdshader.uid create mode 100644 scenes/game_elements/props/powerup/powerup.tscn diff --git a/scenes/game_elements/props/powerup/components/default_powerup.dialogue b/scenes/game_elements/props/powerup/components/default_powerup.dialogue new file mode 100644 index 000000000..8dbaa4848 --- /dev/null +++ b/scenes/game_elements/props/powerup/components/default_powerup.dialogue @@ -0,0 +1,5 @@ +# SPDX-FileCopyrightText: The Threadbare Authors +# SPDX-License-Identifier: MPL-2.0 +~ start +[wave amp=25 freq=5]You got a new ability! [b]{{ability_name}}[/b][/wave] +=> END diff --git a/scenes/game_elements/props/powerup/components/default_powerup.dialogue.import b/scenes/game_elements/props/powerup/components/default_powerup.dialogue.import new file mode 100644 index 000000000..100b7ee40 --- /dev/null +++ b/scenes/game_elements/props/powerup/components/default_powerup.dialogue.import @@ -0,0 +1,16 @@ +[remap] + +importer="dialogue_manager" +importer_version=15 +type="Resource" +uid="uid://cj0i5jwlv8idi" +path="res://.godot/imported/default_powerup.dialogue-7b4f95958377611890379db90e1904ef.tres" + +[deps] + +source_file="res://scenes/game_elements/props/powerup/components/default_powerup.dialogue" +dest_files=["res://.godot/imported/default_powerup.dialogue-7b4f95958377611890379db90e1904ef.tres"] + +[params] + +defaults=true diff --git a/scenes/game_elements/props/powerup/components/powerup.aseprite b/scenes/game_elements/props/powerup/components/powerup.aseprite new file mode 100644 index 000000000..6ebc3d7d1 --- /dev/null +++ b/scenes/game_elements/props/powerup/components/powerup.aseprite @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:85521554f47d1985edb2fa23d6e55702f4f909b28564985522f73ac2cb2cdf9b +size 955 diff --git a/scenes/game_elements/props/powerup/components/powerup.gd b/scenes/game_elements/props/powerup/components/powerup.gd new file mode 100644 index 000000000..85aa79952 --- /dev/null +++ b/scenes/game_elements/props/powerup/components/powerup.gd @@ -0,0 +1,115 @@ +# SPDX-FileCopyrightText: The Threadbare Authors +# SPDX-License-Identifier: MPL-2.0 +@tool +extends Node2D +## A powerup that, when interacted, enables a player ability. +## +## By default it also displays a dialogue telling the player that an ability +## has been obtained. + +## Emitted when this powerup is collected. +signal collected + +## The player ability to enable. +@export var ability: Enums.PlayerAbilities = Enums.PlayerAbilities.ABILITY_A + +## Name for the ability to display if using the default dialogue. +@export var ability_name: String + +## Text to display in the label when the player gets close to interact with this powerup. +@export var interact_action: String: + set = _set_interact_action + +## Asset of this powerup. +@export var sprite_frames: SpriteFrames: + set = _set_sprite_frames + +## The powerup shines with this color through a shader. +@export var highlight_color: Color = Color.WHITE: + set = _set_highlight_color + +## Dialogue to display when collecting the powerup. +@export var dialogue: DialogueResource = preload("uid://cj0i5jwlv8idi") + +var _tween: Tween + +@onready var interact_area: InteractArea = %InteractArea +@onready var highlight_effect: Sprite2D = %HighlightEffect +@onready var sprite: AnimatedSprite2D = %Sprite +@onready var interact_collision: CollisionShape2D = %InteractCollision +@onready var ground_collision: CollisionShape2D = %GroundCollision + + +func _set_interact_action(new_interact_action: String) -> void: + interact_action = new_interact_action + if is_node_ready(): + interact_area.action = interact_action + + +func _set_sprite_frames(new_sprite_frames: SpriteFrames) -> void: + sprite_frames = new_sprite_frames + if is_node_ready(): + sprite.sprite_frames = sprite_frames + sprite.play("default") + + +func _set_highlight_color(new_highlight_color: Color) -> void: + highlight_color = new_highlight_color + if is_node_ready(): + highlight_effect.modulate = highlight_color + + +func _ready() -> void: + _set_interact_action(interact_action) + _set_sprite_frames(sprite_frames) + _set_highlight_color(highlight_color) + if Engine.is_editor_hint(): + return + GameState.abilities_changed.connect(_on_abilities_changed) + _on_abilities_changed() + + +func _notification(what: int) -> void: + match what: + NOTIFICATION_EDITOR_PRE_SAVE: + # Since this is a tool script that plays the animations in the + # editor, reset the frame progress before saving the scene. + sprite.frame_progress = 0 + + +func _on_abilities_changed() -> void: + var has_ability := GameState.has_ability(ability) + ground_collision.disabled = has_ability + interact_collision.disabled = has_ability + highlight_effect.visible = not has_ability + var alpha: float = 0.5 if has_ability else 1.0 + sprite.modulate = Color(Color.WHITE, alpha) + _set_highlight_color(highlight_color) + var highlight_material := highlight_effect.material as ShaderMaterial + if highlight_material: + highlight_material.set_shader_parameter(&"width", 0.4) + + +func _on_interact_area_interaction_started( + _player: Player, _from_right: bool, source: InteractArea +) -> void: + if _tween: + _tween.kill() + _tween = create_tween() + _tween.tween_property(highlight_effect, "modulate", Color.WHITE, 0.5) + _tween.tween_property(highlight_effect, "material:shader_parameter/width", 1.0, 1.0) + await _tween.finished + if dialogue: + DialogueManager.show_dialogue_balloon(dialogue, "", [self]) + await DialogueManager.dialogue_ended + source.end_interaction() + GameState.set_ability(ability, true) + collected.emit() + + +func _on_interact_area_observers_changed() -> void: + if _tween: + _tween.kill() + _tween = create_tween() + var width: float = 0.8 if interact_area.is_being_observed else 0.4 + _tween.tween_property(highlight_effect, "material:shader_parameter/width", width, 1.0) diff --git a/scenes/game_elements/props/powerup/components/powerup.gd.uid b/scenes/game_elements/props/powerup/components/powerup.gd.uid new file mode 100644 index 000000000..9f7f8b35d --- /dev/null +++ b/scenes/game_elements/props/powerup/components/powerup.gd.uid @@ -0,0 +1 @@ +uid://bhmae3daygmqh diff --git a/scenes/game_elements/props/powerup/components/powerup.png b/scenes/game_elements/props/powerup/components/powerup.png new file mode 100644 index 000000000..9a25def33 --- /dev/null +++ b/scenes/game_elements/props/powerup/components/powerup.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5646b743efe7b14a3ff63d54302b17d29e958d917c4bfa05924dc7b2b2784617 +size 1022 diff --git a/scenes/game_elements/props/powerup/components/powerup.png.import b/scenes/game_elements/props/powerup/components/powerup.png.import new file mode 100644 index 000000000..d886e85b7 --- /dev/null +++ b/scenes/game_elements/props/powerup/components/powerup.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dr1cdu5ien6jq" +path="res://.godot/imported/powerup.png-a4ee45e73209b83508bc25ff7865937f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://scenes/game_elements/props/powerup/components/powerup.png" +dest_files=["res://.godot/imported/powerup.png-a4ee45e73209b83508bc25ff7865937f.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/scenes/game_elements/props/powerup/components/powerup_highlight.png b/scenes/game_elements/props/powerup/components/powerup_highlight.png new file mode 100644 index 000000000..c2849789b --- /dev/null +++ b/scenes/game_elements/props/powerup/components/powerup_highlight.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c4163dde57282bfac63c54e2b59797735028d6289aae4135120c8695a2851b1b +size 6231 diff --git a/scenes/game_elements/props/powerup/components/powerup_highlight.png.import b/scenes/game_elements/props/powerup/components/powerup_highlight.png.import new file mode 100644 index 000000000..352ba026c --- /dev/null +++ b/scenes/game_elements/props/powerup/components/powerup_highlight.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bbo1nd3usbxnr" +path="res://.godot/imported/powerup_highlight.png-deef463ba3599bc39e64667d2828727c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://scenes/game_elements/props/powerup/components/powerup_highlight.png" +dest_files=["res://.godot/imported/powerup_highlight.png-deef463ba3599bc39e64667d2828727c.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/scenes/game_elements/props/powerup/components/ripple_effect.gdshader b/scenes/game_elements/props/powerup/components/ripple_effect.gdshader new file mode 100644 index 000000000..0a9b274a7 --- /dev/null +++ b/scenes/game_elements/props/powerup/components/ripple_effect.gdshader @@ -0,0 +1,40 @@ +/** + * Ripple effect + * + * This shader expects the CanvasItem to be a gradient asset that goes from white to transparent. + * It adjusts the alpha to create a ripple effect of a certain width. + * + * SPDX-FileCopyrightText: The Threadbare Authors + * SPDX-License-Identifier: MPL-2.0 + */ +shader_type canvas_item; +render_mode blend_add; + +/** + * How smooth or sharp are the ripples. + */ +uniform float ease: hint_range(0.0, 2.0) = 2.0; + +/** + * This is perceived as the amount of ripples. + */ +uniform float modulo_width: hint_range(0.0, 1.0) = 0.2; + +/** + * The ripple width. + */ +uniform float width: hint_range(0.0, 1.0) = 0.4; + +/** + * The ripple speed. + */ +uniform float speed: hint_range(0.0, 2.0) = 0.2; + +void fragment() { + float sdf_alpha = mod(TIME * speed + COLOR.a, modulo_width); + float front_ease = smoothstep(0, ease, sdf_alpha); + float easeAmount = front_ease * modulo_width; + float brightness = COLOR.a - sdf_alpha + easeAmount; + + COLOR.a = smoothstep(1.0 - width, width+(1.0 - width), brightness); +} diff --git a/scenes/game_elements/props/powerup/components/ripple_effect.gdshader.uid b/scenes/game_elements/props/powerup/components/ripple_effect.gdshader.uid new file mode 100644 index 000000000..ca946bacf --- /dev/null +++ b/scenes/game_elements/props/powerup/components/ripple_effect.gdshader.uid @@ -0,0 +1 @@ +uid://v56tvdvw22lj diff --git a/scenes/game_elements/props/powerup/powerup.tscn b/scenes/game_elements/props/powerup/powerup.tscn new file mode 100644 index 000000000..35205f63b --- /dev/null +++ b/scenes/game_elements/props/powerup/powerup.tscn @@ -0,0 +1,77 @@ +[gd_scene format=3 uid="uid://dmevaymmt6wco"] + +[ext_resource type="Script" uid="uid://bhmae3daygmqh" path="res://scenes/game_elements/props/powerup/components/powerup.gd" id="1_5vrqc"] +[ext_resource type="Texture2D" uid="uid://dr1cdu5ien6jq" path="res://scenes/game_elements/props/powerup/components/powerup.png" id="2_bq5to"] +[ext_resource type="Script" uid="uid://du8wfijr35r35" path="res://scenes/game_elements/props/interact_area/interact_area.gd" id="2_q7xhf"] +[ext_resource type="Texture2D" uid="uid://bbo1nd3usbxnr" path="res://scenes/game_elements/props/powerup/components/powerup_highlight.png" id="4_bq5to"] +[ext_resource type="Shader" uid="uid://v56tvdvw22lj" path="res://scenes/game_elements/props/powerup/components/ripple_effect.gdshader" id="4_vllb8"] + +[sub_resource type="SpriteFrames" id="SpriteFrames_bq5to"] +animations = [{ +"frames": [{ +"duration": 1.0, +"texture": ExtResource("2_bq5to") +}], +"loop": true, +"name": &"default", +"speed": 10.0 +}] + +[sub_resource type="CircleShape2D" id="CircleShape2D_5vrqc"] +radius = 50.0 + +[sub_resource type="CapsuleShape2D" id="CapsuleShape2D_bq5to"] +radius = 16.0 +height = 68.0 + +[sub_resource type="ShaderMaterial" id="ShaderMaterial_spw1e"] +shader = ExtResource("4_vllb8") +shader_parameter/ease = 2.0 +shader_parameter/modulo_width = 0.2 +shader_parameter/width = 0.4 +shader_parameter/speed = 0.2 + +[node name="Powerup" type="Node2D" unique_id=1795462717] +script = ExtResource("1_5vrqc") +ability_name = "Repel" +interact_action = "Collect Repel" +sprite_frames = SubResource("SpriteFrames_bq5to") + +[node name="InteractArea" type="Area2D" parent="." unique_id=1443651205] +unique_name_in_owner = true +collision_layer = 32 +collision_mask = 0 +script = ExtResource("2_q7xhf") +interact_label_position = Vector2(0, -142) +action = "Collect Repel" + +[node name="InteractCollision" type="CollisionShape2D" parent="InteractArea" unique_id=1651676696] +unique_name_in_owner = true +position = Vector2(0, -33) +shape = SubResource("CircleShape2D_5vrqc") +debug_color = Color(0.600391, 0.54335, 0, 0.42) + +[node name="StaticBody2D" type="StaticBody2D" parent="." unique_id=21266648] +collision_mask = 0 + +[node name="GroundCollision" type="CollisionShape2D" parent="StaticBody2D" unique_id=1403567890] +unique_name_in_owner = true +rotation = -1.5707964 +shape = SubResource("CapsuleShape2D_bq5to") +debug_color = Color(0.976711, 0, 0.409753, 0.42) + +[node name="HighlightEffect" type="Sprite2D" parent="." unique_id=1449487876] +unique_name_in_owner = true +visible = false +material = SubResource("ShaderMaterial_spw1e") +position = Vector2(0, -34) +texture = ExtResource("4_bq5to") + +[node name="Sprite" type="AnimatedSprite2D" parent="." unique_id=682377422] +unique_name_in_owner = true +position = Vector2(0, -34) +sprite_frames = SubResource("SpriteFrames_bq5to") +autoplay = "default" + +[connection signal="interaction_started" from="InteractArea" to="." method="_on_interact_area_interaction_started" flags=18] +[connection signal="observers_changed" from="InteractArea" to="." method="_on_interact_area_observers_changed"] From 413a7bcbab0b2a2e202fecb9041cad40e7cc76a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Qui=C3=B1ones?= Date: Tue, 24 Mar 2026 15:35:31 -0300 Subject: [PATCH 03/12] Use powerup in lore and template quests - Add Repel powerup to ink_combat_round_1 and NO_EDIT_combat. And display the input hints when collected. - Add Grapple powerup to grappling_hook_start. And display the input hints when collected, instead of from cinematic dialogue. - Replace longer thread powerup in grappling_hook_powerup with this new component. --- .../components/ink_combat_round_1.gd | 8 ++- .../2_ink_combat/ink_combat_round_1.tscn | 8 +++ .../components/grappling_hook_powerup.gd | 4 +- .../components/grappling_hook_start.gd | 4 ++ .../grappling_hook_powerup.tscn | 57 +++---------------- .../grappling_hook_start.tscn | 9 +++ .../2_grappling_hook/intro_start.dialogue | 1 - .../2_NO_EDIT_combat/NO_EDIT_combat.tscn | 5 ++ 8 files changed, 42 insertions(+), 54 deletions(-) diff --git a/scenes/quests/lore_quests/quest_001/2_ink_combat/components/ink_combat_round_1.gd b/scenes/quests/lore_quests/quest_001/2_ink_combat/components/ink_combat_round_1.gd index afbe30506..e56492c62 100644 --- a/scenes/quests/lore_quests/quest_001/2_ink_combat/components/ink_combat_round_1.gd +++ b/scenes/quests/lore_quests/quest_001/2_ink_combat/components/ink_combat_round_1.gd @@ -2,6 +2,12 @@ # SPDX-License-Identifier: MPL-2.0 extends Node2D +@onready var input_hints: HBoxContainer = %InputHints + func _ready() -> void: - GameState.set_ability(Enums.PlayerAbilities.ABILITY_A, true) + input_hints.visible = false + + +func _on_repel_powerup_collected() -> void: + input_hints.visible = true diff --git a/scenes/quests/lore_quests/quest_001/2_ink_combat/ink_combat_round_1.tscn b/scenes/quests/lore_quests/quest_001/2_ink_combat/ink_combat_round_1.tscn index 2067b8b9d..4d58765e0 100644 --- a/scenes/quests/lore_quests/quest_001/2_ink_combat/ink_combat_round_1.tscn +++ b/scenes/quests/lore_quests/quest_001/2_ink_combat/ink_combat_round_1.tscn @@ -25,6 +25,7 @@ [ext_resource type="AudioStream" uid="uid://bbnj2fog3rdy8" path="res://assets/first_party/sounds/throwing_enemy/Spray.wav" id="14_7ekah"] [ext_resource type="PackedScene" uid="uid://c5jedlvvnnbi0" path="res://scenes/game_elements/props/projectile/ink_blob_projectile.tscn" id="16_k65js"] [ext_resource type="PackedScene" uid="uid://dkx3dgc1br3b4" path="res://scenes/ui_elements/input_hints/repel_hint.tscn" id="22_8me22"] +[ext_resource type="PackedScene" uid="uid://dmevaymmt6wco" path="res://scenes/game_elements/props/powerup/powerup.tscn" id="26_a4lwd"] [sub_resource type="Animation" id="Animation_nlryc"] resource_name = "goal_completed" @@ -211,9 +212,15 @@ scale = Vector2(1.00063, 0.911434) position = Vector2(674, 32) scale = Vector2(0.95, 0.95) +[node name="RepelPowerup" parent="OnTheGround" unique_id=1795462717 instance=ExtResource("26_a4lwd")] +position = Vector2(236, 428) +highlight_color = Color(0, 0, 1, 1) + [node name="ScreenOverlay" type="CanvasLayer" parent="." unique_id=127644403] [node name="InputHints" type="HBoxContainer" parent="ScreenOverlay" unique_id=367368380] +unique_name_in_owner = true +visible = false anchors_preset = 2 anchor_top = 1.0 anchor_bottom = 1.0 @@ -237,3 +244,4 @@ editor_draw_limits = true [connection signal="cinematic_finished" from="Cinematic" to="FillGameLogic" method="start"] [connection signal="goal_reached" from="FillGameLogic" to="FillGameLogic/LevelCompletedAnimation" method="play" binds= ["goal_completed"]] +[connection signal="collected" from="OnTheGround/RepelPowerup" to="." method="_on_repel_powerup_collected"] diff --git a/scenes/quests/lore_quests/quest_002/2_grappling_hook/components/grappling_hook_powerup.gd b/scenes/quests/lore_quests/quest_002/2_grappling_hook/components/grappling_hook_powerup.gd index 9c8950fbb..e9c849eaf 100644 --- a/scenes/quests/lore_quests/quest_002/2_grappling_hook/components/grappling_hook_powerup.gd +++ b/scenes/quests/lore_quests/quest_002/2_grappling_hook/components/grappling_hook_powerup.gd @@ -3,9 +3,7 @@ extends Node2D -func _on_button_item_collected() -> void: - GameState.set_ability(Enums.PlayerAbilities.ABILITY_B_MODIFIER_1, true) - +func _on_longer_thread_powerup_collected() -> void: # Zoom out the camera when collecting the powerup, because now the player # can throw a longer thread: var camera: Camera2D = get_viewport().get_camera_2d() diff --git a/scenes/quests/lore_quests/quest_002/2_grappling_hook/components/grappling_hook_start.gd b/scenes/quests/lore_quests/quest_002/2_grappling_hook/components/grappling_hook_start.gd index 6d98e4db2..2bff84eac 100644 --- a/scenes/quests/lore_quests/quest_002/2_grappling_hook/components/grappling_hook_start.gd +++ b/scenes/quests/lore_quests/quest_002/2_grappling_hook/components/grappling_hook_start.gd @@ -23,3 +23,7 @@ func _on_spawn_point_from_powerup_player_teleported() -> void: await ready void_patrolling.visible = false animation_player.play(&"eat_floor") + + +func _on_grapple_powerup_collected() -> void: + animation_player.play(&"show_input_hints") diff --git a/scenes/quests/lore_quests/quest_002/2_grappling_hook/grappling_hook_powerup.tscn b/scenes/quests/lore_quests/quest_002/2_grappling_hook/grappling_hook_powerup.tscn index 25dc0dd36..ea92780b0 100644 --- a/scenes/quests/lore_quests/quest_002/2_grappling_hook/grappling_hook_powerup.tscn +++ b/scenes/quests/lore_quests/quest_002/2_grappling_hook/grappling_hook_powerup.tscn @@ -18,51 +18,15 @@ [ext_resource type="TileSet" uid="uid://bdc7ucso7bx0s" path="res://tiles/shadows.tres" id="8_iu48k"] [ext_resource type="PackedScene" uid="uid://cfcgrfvtn04yp" path="res://scenes/ui_elements/hud/hud.tscn" id="11_7v23v"] [ext_resource type="PackedScene" uid="uid://cokul8w425pja" path="res://scenes/quests/lore_quests/quest_002/1_void_runner/components/void_spreading_enemy.tscn" id="12_ptg16"] -[ext_resource type="Texture2D" uid="uid://dnwfhdpvdl0gi" path="res://scenes/game_elements/props/button_item/components/button-blue.png" id="13_7gbyj"] [ext_resource type="Script" uid="uid://csev4hv57utxv" path="res://scenes/game_logic/walk_behaviors/character_speeds.gd" id="13_vodlh"] [ext_resource type="PackedScene" uid="uid://lgu7aeqa7o3r" path="res://scenes/game_elements/props/door/door.tscn" id="15_rlnni"] +[ext_resource type="PackedScene" uid="uid://dmevaymmt6wco" path="res://scenes/game_elements/props/powerup/powerup.tscn" id="17_a36ca"] [ext_resource type="PackedScene" uid="uid://7873qa54birk" path="res://scenes/game_elements/props/tree/tree.tscn" id="20_exmm1"] [ext_resource type="SpriteFrames" uid="uid://2ek86nvw6y28" path="res://scenes/game_elements/props/tree/components/tree_spriteframes_yellow.tres" id="21_y6p0v"] [ext_resource type="PackedScene" uid="uid://crqjcicx0vdu" path="res://scenes/game_elements/props/decoration/bush/bush.tscn" id="22_iu48k"] [ext_resource type="SpriteFrames" uid="uid://bapks76u4hipj" path="res://scenes/game_elements/props/decoration/bush/components/bush_spriteframes_green_small.tres" id="23_b7aom"] [ext_resource type="Script" uid="uid://hqdquinbimce" path="res://scenes/game_elements/props/teleporter/teleporter.gd" id="25_iu48k"] -[sub_resource type="AtlasTexture" id="AtlasTexture_rup4f"] -atlas = ExtResource("13_7gbyj") -region = Rect2(0, 0, 64, 64) - -[sub_resource type="AtlasTexture" id="AtlasTexture_ptg16"] -atlas = ExtResource("13_7gbyj") -region = Rect2(64, 0, 64, 64) - -[sub_resource type="AtlasTexture" id="AtlasTexture_vodlh"] -atlas = ExtResource("13_7gbyj") -region = Rect2(128, 0, 64, 64) - -[sub_resource type="AtlasTexture" id="AtlasTexture_rlnni"] -atlas = ExtResource("13_7gbyj") -region = Rect2(192, 0, 64, 64) - -[sub_resource type="SpriteFrames" id="SpriteFrames_g2ubw"] -animations = [{ -"frames": [{ -"duration": 1.0, -"texture": SubResource("AtlasTexture_rup4f") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_ptg16") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_vodlh") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_rlnni") -}], -"loop": true, -"name": &"default", -"speed": 10.0 -}] - [sub_resource type="Resource" id="Resource_rlnni"] script = ExtResource("13_vodlh") metadata/_custom_type_script = "uid://csev4hv57utxv" @@ -257,15 +221,12 @@ position = Vector2(837, -280) position = Vector2(-1581, 1616) text = "Go!" -[node name="LongerStringPowerUp" parent="OnTheGround" unique_id=987233957 instance=ExtResource("7_rlnni")] -position = Vector2(-555, 727) -scale = Vector2(2, 2) - -[node name="ButtonSprite" parent="OnTheGround/LongerStringPowerUp/ButtonItem" parent_id_path=PackedInt32Array(987233957, 1967107361) index="0" unique_id=1194360136] -sprite_frames = SubResource("SpriteFrames_g2ubw") - -[node name="HookableArea" parent="OnTheGround/LongerStringPowerUp" index="2" unique_id=1267513436] -weight = 0.3 +[node name="LongerThreadPowerup" parent="OnTheGround" unique_id=1795462717 instance=ExtResource("17_a36ca")] +position = Vector2(-549, 805) +ability = 32 +ability_name = "Longer Thread" +interact_action = "Collect Longer Thread" +highlight_color = Color(0.8910073, 0.7227245, 0, 1) [node name="VoidPatrolling" parent="OnTheGround" unique_id=2124322919 node_paths=PackedStringArray("void_layer", "idle_patrol_path") instance=ExtResource("12_ptg16")] position = Vector2(-1099, 1758) @@ -399,8 +360,6 @@ shape = SubResource("RectangleShape2D_s7yva") [node name="HUD" parent="." unique_id=1267842834 instance=ExtResource("11_7v23v")] -[connection signal="collected" from="OnTheGround/LongerStringPowerUp/ButtonItem" to="." method="_on_button_item_collected"] +[connection signal="collected" from="OnTheGround/LongerThreadPowerup" to="." method="_on_longer_thread_powerup_collected"] -[editable path="OnTheGround/LongerStringPowerUp"] -[editable path="OnTheGround/LongerStringPowerUp/ButtonItem"] [editable path="OnTheGround/VoidPatrolling"] diff --git a/scenes/quests/lore_quests/quest_002/2_grappling_hook/grappling_hook_start.tscn b/scenes/quests/lore_quests/quest_002/2_grappling_hook/grappling_hook_start.tscn index ae579d93a..8ff3ad58a 100644 --- a/scenes/quests/lore_quests/quest_002/2_grappling_hook/grappling_hook_start.tscn +++ b/scenes/quests/lore_quests/quest_002/2_grappling_hook/grappling_hook_start.tscn @@ -24,6 +24,7 @@ [ext_resource type="PackedScene" uid="uid://crqjcicx0vdu" path="res://scenes/game_elements/props/decoration/bush/bush.tscn" id="18_wv4km"] [ext_resource type="SpriteFrames" uid="uid://bapks76u4hipj" path="res://scenes/game_elements/props/decoration/bush/components/bush_spriteframes_green_small.tres" id="19_6n4qp"] [ext_resource type="Script" uid="uid://hqdquinbimce" path="res://scenes/game_elements/props/teleporter/teleporter.gd" id="20_wv4km"] +[ext_resource type="PackedScene" uid="uid://dmevaymmt6wco" path="res://scenes/game_elements/props/powerup/powerup.tscn" id="21_6n4qp"] [ext_resource type="PackedScene" uid="uid://cqkly1vjd6xhy" path="res://scenes/ui_elements/input_hints/aim_input_hint.tscn" id="23_wv4km"] [sub_resource type="Animation" id="Animation_w67qe"] @@ -340,6 +341,13 @@ sprite_frames = ExtResource("19_6n4qp") [node name="Bush14" parent="OnTheGround/Bushes" unique_id=391246514 instance=ExtResource("18_wv4km")] position = Vector2(261, 440) +[node name="GrapplePowerup" parent="OnTheGround" unique_id=1795462717 instance=ExtResource("21_6n4qp")] +position = Vector2(933, 689) +ability = 16 +ability_name = "Grapple" +interact_action = "Collect Grapple" +highlight_color = Color(0.8910073, 0.7227245, 0, 1) + [node name="Teleporter" type="Area2D" parent="." unique_id=579212473] position = Vector2(2704, 1216) collision_layer = 4 @@ -396,6 +404,7 @@ layout_mode = 2 [node name="HUD" parent="." unique_id=1590862536 instance=ExtResource("11_p44d7")] +[connection signal="collected" from="OnTheGround/GrapplePowerup" to="." method="_on_grapple_powerup_collected"] [connection signal="player_teleported" from="SpawnPointFromPowerup" to="." method="_on_spawn_point_from_powerup_player_teleported"] [editable path="OnTheGround/VoidPatrolling"] diff --git a/scenes/quests/lore_quests/quest_002/2_grappling_hook/intro_start.dialogue b/scenes/quests/lore_quests/quest_002/2_grappling_hook/intro_start.dialogue index f5d5174b7..dc7be6821 100644 --- a/scenes/quests/lore_quests/quest_002/2_grappling_hook/intro_start.dialogue +++ b/scenes/quests/lore_quests/quest_002/2_grappling_hook/intro_start.dialogue @@ -7,5 +7,4 @@ do animation_player.animation_finished Moss the Monk: Oh, look! The Void is blooming fast here. Moss the Monk: You’ll need a [b]grappling hook[/b] to get to LinenVille. Take mine. do GameState.set_ability(Enums.PlayerAbilities.ABILITY_B, true) -do animation_player.play(&"show_input_hints") => END diff --git a/scenes/quests/template_quests/NO_EDIT/2_NO_EDIT_combat/NO_EDIT_combat.tscn b/scenes/quests/template_quests/NO_EDIT/2_NO_EDIT_combat/NO_EDIT_combat.tscn index d0980d4d4..7554ce328 100644 --- a/scenes/quests/template_quests/NO_EDIT/2_NO_EDIT_combat/NO_EDIT_combat.tscn +++ b/scenes/quests/template_quests/NO_EDIT/2_NO_EDIT_combat/NO_EDIT_combat.tscn @@ -13,6 +13,7 @@ [ext_resource type="Script" uid="uid://bgmwplmj3bfls" path="res://scenes/globals/game_state/inventory/inventory_item.gd" id="11_4lmqk"] [ext_resource type="PackedScene" uid="uid://b82nsrh332syj" path="res://scenes/game_elements/characters/enemies/throwing_enemy/throwing_enemy.tscn" id="11_64btt"] [ext_resource type="PackedScene" uid="uid://y8ha8abfyap2" path="res://scenes/game_elements/props/filling_barrel/filling_barrel.tscn" id="12_2eyq6"] +[ext_resource type="PackedScene" uid="uid://dmevaymmt6wco" path="res://scenes/game_elements/props/powerup/powerup.tscn" id="14_6xf5p"] [ext_resource type="PackedScene" uid="uid://cfcgrfvtn04yp" path="res://scenes/ui_elements/hud/hud.tscn" id="14_ttfgd"] [sub_resource type="Resource" id="Resource_a51xm"] @@ -105,6 +106,10 @@ item = SubResource("Resource_a51xm") collected_dialogue = ExtResource("2_3qn31") dialogue_title = &"well_done" +[node name="RepelPowerup" parent="OnTheGround" unique_id=1795462717 instance=ExtResource("14_6xf5p")] +position = Vector2(114, 488) +highlight_color = Color(0, 0, 1, 1) + [node name="ScreenOverlay" type="CanvasLayer" parent="." unique_id=1277924950] [node name="HUD" parent="." unique_id=1216951978 instance=ExtResource("14_ttfgd")] From da1ccc982d4ad733decc237e10093cdb1e6c4cb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Qui=C3=B1ones?= Date: Wed, 25 Mar 2026 18:11:35 -0300 Subject: [PATCH 04/12] Projectile: Export hit speed The speed after the projectile gets hit. --- .../game_elements/props/projectile/components/projectile.gd | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scenes/game_elements/props/projectile/components/projectile.gd b/scenes/game_elements/props/projectile/components/projectile.gd index 9e27e4494..9e8d5a07e 100644 --- a/scenes/game_elements/props/projectile/components/projectile.gd +++ b/scenes/game_elements/props/projectile/components/projectile.gd @@ -37,6 +37,9 @@ extends RigidBody2D ## The speed of the initial impulse and the bouncing impulse. @export_range(10., 100., 5., "or_greater", "or_less", "suffix:m/s") var speed: float = 30.0 +## The speed after the projectile gets hit. +@export_range(10., 100., 5., "or_greater", "or_less", "suffix:m/s") var hit_speed: float = 100.0 + ## The initial direction. @export var direction: Vector2 = Vector2(0, -1): set = _set_direction @@ -153,7 +156,6 @@ func _on_body_entered(body: Node2D) -> void: func got_hit(player: Player) -> void: add_small_fx() duration_timer.start() - var hit_speed := 100.0 var hit_vector: Vector2 = player.global_position.direction_to(global_position) * hit_speed hit_sound.play() animated_sprite_2d.speed_scale = 2 From d8cc4c4b59d9bdf01049b4556bb0163c5f934c2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Qui=C3=B1ones?= Date: Wed, 25 Mar 2026 18:14:05 -0300 Subject: [PATCH 05/12] unify_abilities_test: Add powerups and improve test level Add the 2 powerups needed. Make the level a bit easier by using a projectile scene with the hit speed set to a low value. Also: - Use lore assets: ink drinker character, ink blob, inkwell. - Remove unneeded HUD and sign post. - Use the new elevation_2 tileset and repaint it as terrain. - Paint Void tiles as terrain, so they have the embroidery. - Add more Void tiles around to constrain the player. - Make the island at the north a 3x2 tiles (was a 2x2 square) so the player has more space for aiming. --- .../components/unify_abilities_test.tscn | 54 +++++++++-------- .../unify_abilities_test_projectile.tscn | 59 +++++++++++++++++++ 2 files changed, 88 insertions(+), 25 deletions(-) create mode 100644 scenes/game_elements/characters/player/components/unify_abilities_test_projectile.tscn diff --git a/scenes/game_elements/characters/player/components/unify_abilities_test.tscn b/scenes/game_elements/characters/player/components/unify_abilities_test.tscn index c48dfbacf..8e164e679 100644 --- a/scenes/game_elements/characters/player/components/unify_abilities_test.tscn +++ b/scenes/game_elements/characters/player/components/unify_abilities_test.tscn @@ -6,15 +6,17 @@ [ext_resource type="Script" uid="uid://d1ly6uhh500xu" path="res://scenes/quests/lore_quests/quest_002/1_void_runner/components/tile_map_cover.gd" id="4_vodlh"] [ext_resource type="SpriteFrames" uid="uid://dtoylirwywk0j" path="res://scenes/game_elements/characters/components/sprite_frames/storyweaver_blue.tres" id="5_7gbyj"] [ext_resource type="TileSet" uid="uid://ciq5guijvlyb0" path="res://tiles/void_chromakey.tres" id="6_8xu72"] +[ext_resource type="TileSet" uid="uid://b778cuoftt88r" path="res://tiles/elevation_2.tres" id="6_g4p32"] [ext_resource type="PackedScene" uid="uid://evb46lm6ssu2" path="res://scenes/game_elements/props/hookable_pin/hookable_pin.tscn" id="6_vodlh"] -[ext_resource type="TileSet" uid="uid://dfp36ffpanjq2" path="res://tiles/elevation.tres" id="8_exmm1"] -[ext_resource type="PackedScene" uid="uid://covsdqqsd6rsy" path="res://scenes/game_elements/props/sign/sign.tscn" id="8_g2ubw"] [ext_resource type="TileSet" uid="uid://bdc7ucso7bx0s" path="res://tiles/shadows.tres" id="8_iu48k"] -[ext_resource type="PackedScene" uid="uid://cfcgrfvtn04yp" path="res://scenes/ui_elements/hud/hud.tscn" id="11_7v23v"] +[ext_resource type="PackedScene" uid="uid://xbgo0b3f50mw" path="res://scenes/game_elements/characters/player/components/unify_abilities_test_projectile.tscn" id="13_g4p32"] +[ext_resource type="SpriteFrames" uid="uid://b3r84ksew5djp" path="res://scenes/game_elements/characters/enemies/throwing_enemy/components/ink_drinker_frames_purple.tres" id="13_w66m4"] +[ext_resource type="AudioStream" uid="uid://qf2d38rabx8o" path="res://assets/third_party/sounds/characters/enemies/throwing_enemy/Wings.ogg" id="14_nev3j"] +[ext_resource type="AudioStream" uid="uid://bbnj2fog3rdy8" path="res://assets/first_party/sounds/throwing_enemy/Spray.wav" id="15_4vuok"] [ext_resource type="Script" uid="uid://cp54mgi54nywo" path="res://scenes/game_logic/fill_game_logic.gd" id="17_b7aom"] +[ext_resource type="PackedScene" uid="uid://dmevaymmt6wco" path="res://scenes/game_elements/props/powerup/powerup.tscn" id="17_w66m4"] [ext_resource type="PackedScene" uid="uid://b82nsrh332syj" path="res://scenes/game_elements/characters/enemies/throwing_enemy/throwing_enemy.tscn" id="18_iu48k"] [ext_resource type="PackedScene" uid="uid://y8ha8abfyap2" path="res://scenes/game_elements/props/filling_barrel/filling_barrel.tscn" id="19_a36ca"] -[ext_resource type="SpriteFrames" uid="uid://c50725q5ey5j5" path="res://scenes/quests/template_quests/NO_EDIT/2_NO_EDIT_combat/NO_EDIT_combat_components/NO_EDIT_target_spriteframes.tres" id="20_11qsc"] [node name="Testeo" type="Node2D" unique_id=80760666] @@ -24,22 +26,20 @@ tile_map_data = PackedByteArray("AAABABMAAQABAAEAAAABABIAAQABAAEAAAABABEAAQABAAEAAAABABAAAQABAAEAAAABAA8AAQABAAEAAAABAA4AAQABAAEAAAABAA0AAQABAAEAAAABAAwAAQABAAEAAAAAABMAAQABAAEAAAAAABIAAQABAAEAAAAAABEAAQABAAEAAAAAABAAAQABAAEAAAAAAA8AAQABAAEAAAAAAA4AAQABAAEAAAAAAA0AAQABAAEAAAAAAAwAAQABAAEAAAD//xMAAQABAAEAAAD//xIAAQABAAEAAAD//xEAAQABAAEAAAD//xAAAQABAAEAAAD//w8AAQABAAEAAAD//w4AAQABAAEAAAD//w0AAQABAAEAAAD//wwAAQABAAEAAAD+/xMAAQABAAEAAAD+/xIAAQABAAEAAAD+/xEAAQABAAEAAAD+/xAAAQABAAEAAAD+/w8AAQABAAEAAAD+/w4AAQABAAEAAAD+/w0AAQABAAEAAAD+/wwAAQABAAEAAAD9/xMAAQABAAEAAAD9/xIAAQABAAEAAAD9/xEAAQABAAEAAAD9/xAAAQABAAEAAAD9/w8AAQABAAEAAAD9/w4AAQABAAEAAAD9/w0AAQABAAEAAAD9/wwAAQABAAEAAAABABwAAQABAAEAAAABABsAAQABAAEAAAABABoAAQABAAEAAAABABkAAQABAAEAAAABABgAAQABAAEAAAABABcAAQABAAEAAAABABYAAQABAAEAAAABABUAAQABAAEAAAABABQAAQABAAEAAAAAABwAAQABAAEAAAAAABsAAQABAAEAAAAAABoAAQABAAEAAAAAABkAAQABAAEAAAAAABgAAQABAAEAAAAAABcAAQABAAEAAAAAABYAAQABAAEAAAAAABUAAQABAAEAAAAAABQAAQABAAEAAAD//xwAAQABAAEAAAD//xsAAQABAAEAAAD//xoAAQABAAEAAAD//xkAAQABAAEAAAD//xgAAQABAAEAAAD//xcAAQABAAEAAAD//xYAAQABAAEAAAD//xUAAQABAAEAAAD//xQAAQABAAEAAAD+/xwAAQABAAEAAAD+/xsAAQABAAEAAAD+/xoAAQABAAEAAAD+/xkAAQABAAEAAAD+/xgAAQABAAEAAAD+/xcAAQABAAEAAAD+/xYAAQABAAEAAAD+/xUAAQABAAEAAAD+/xQAAQABAAEAAAD9/xwAAQABAAEAAAD9/xsAAQABAAEAAAD9/xoAAQABAAEAAAD9/xkAAQABAAEAAAD9/xgAAQABAAEAAAD9/xcAAQABAAEAAAD9/xYAAQABAAEAAAD9/xUAAQABAAEAAAD9/xQAAQABAAEAAAABAB4AAQABAAEAAAABAB0AAQABAAEAAAAAAB4AAQABAAEAAAAAAB0AAQABAAEAAAD//x4AAQABAAEAAAD//x0AAQABAAEAAAD+/x4AAQABAAEAAAD+/x0AAQABAAEAAAD9/x4AAQABAAEAAAD9/x0AAQABAAEAAAD8/x4AAQABAAEAAAD8/x0AAQABAAEAAAD8/xwAAQABAAEAAAD8/xsAAQABAAEAAAD8/xoAAQABAAEAAAD8/xkAAQABAAEAAAD8/xgAAQABAAEAAAD8/xcAAQABAAEAAAD8/xYAAQABAAEAAAD8/xUAAQABAAEAAAD8/xQAAQABAAEAAAD8/xMAAQABAAEAAAD7/x4AAQABAAEAAAD7/x0AAQABAAEAAAD7/xwAAQABAAEAAAD7/xsAAQABAAEAAAD7/xoAAQABAAEAAAD7/xkAAQABAAEAAAD7/xgAAQABAAEAAAD7/xcAAQABAAEAAAD7/xYAAQABAAEAAAD7/xUAAQABAAEAAAD7/xQAAQABAAEAAAD7/xMAAQABAAEAAAD6/x4AAQABAAEAAAD6/x0AAQABAAEAAAD6/xwAAQABAAEAAAD6/xsAAQABAAEAAAD6/xoAAQABAAEAAAD6/xkAAQABAAEAAAD6/xgAAQABAAEAAAD6/xcAAQABAAEAAAD5/x4AAQABAAEAAAD5/x0AAQABAAEAAAD5/xwAAQABAAEAAAD5/xsAAQABAAEAAAD5/xoAAQABAAEAAAD5/xkAAQABAAEAAAD5/xgAAQABAAEAAAD5/xcAAQABAAEAAAD4/x4AAQABAAEAAAD4/x0AAQABAAEAAAD4/xwAAQABAAEAAAD4/xsAAQABAAEAAAD4/xoAAQABAAEAAAD4/xkAAQABAAEAAAD4/xgAAQABAAEAAAD4/xcAAQABAAEAAAD3/x4AAQABAAEAAAD3/x0AAQABAAEAAAD3/xwAAQABAAEAAAD3/xsAAQABAAEAAAD3/xoAAQABAAEAAAD3/xkAAQABAAEAAAD3/xgAAQABAAEAAAD3/xcAAQABAAEAAAD2/x4AAQABAAEAAAD2/x0AAQABAAEAAAD2/xwAAQABAAEAAAD2/xsAAQABAAEAAAD2/xoAAQABAAEAAAD2/xkAAQABAAEAAAD2/xgAAQABAAEAAAD2/xcAAQABAAEAAAD1/x4AAQABAAEAAAD1/x0AAQABAAEAAAD1/xwAAQABAAEAAAD1/xsAAQABAAEAAAD1/xoAAQABAAEAAAD1/xkAAQABAAEAAAD1/xgAAQABAAEAAAD1/xcAAQABAAEAAAD0/x4AAQABAAEAAAD0/x0AAQABAAEAAAD0/xwAAQABAAEAAAD0/xsAAQABAAEAAAD0/xoAAQABAAEAAAD0/xkAAQABAAEAAAD0/xgAAQABAAEAAAD0/xcAAQABAAEAAADz/x4AAQABAAEAAADz/x0AAQABAAEAAADz/xwAAQABAAEAAADz/xsAAQABAAEAAADz/xoAAQABAAEAAADz/xkAAQABAAEAAADy/x4AAQABAAEAAADy/x0AAQABAAEAAADy/xwAAQABAAEAAADy/xsAAQABAAEAAADy/xoAAQABAAEAAADy/xkAAQABAAEAAADx/x4AAQABAAEAAADx/x0AAQABAAEAAADx/xwAAQABAAEAAADx/xsAAQABAAEAAADx/xoAAQABAAEAAADx/xkAAQABAAEAAADw/x4AAQABAAEAAADw/x0AAQABAAEAAADw/xwAAQABAAEAAADw/xsAAQABAAEAAADw/xoAAQABAAEAAADw/xkAAQABAAEAAADw/xEAAQABAAEAAADw/xAAAQABAAEAAADw/w8AAQABAAEAAADw/w4AAQABAAEAAADw/w0AAQABAAEAAADv/x4AAQABAAEAAADv/x0AAQABAAEAAADv/xwAAQABAAEAAADv/xsAAQABAAEAAADv/xoAAQABAAEAAADv/xkAAQABAAEAAADv/xEAAQABAAEAAADv/xAAAQABAAEAAADv/w8AAQABAAEAAADv/w4AAQABAAEAAADv/w0AAQABAAEAAADu/x4AAQABAAEAAADu/x0AAQABAAEAAADu/xwAAQABAAEAAADu/xsAAQABAAEAAADu/xoAAQABAAEAAADu/xkAAQABAAEAAADu/xEAAQABAAEAAADu/xAAAQABAAEAAADu/w8AAQABAAEAAADu/w4AAQABAAEAAADu/w0AAQABAAEAAADt/x4AAQABAAEAAADt/x0AAQABAAEAAADt/xwAAQABAAEAAADt/xsAAQABAAEAAADt/xoAAQABAAEAAADt/xkAAQABAAEAAADt/xEAAQABAAEAAADt/xAAAQABAAEAAADt/w8AAQABAAEAAADt/w4AAQABAAEAAADt/w0AAQABAAEAAADs/x4AAQABAAEAAADs/x0AAQABAAEAAADs/xwAAQABAAEAAADs/xsAAQABAAEAAADs/xoAAQABAAEAAADs/xkAAQABAAEAAADs/xEAAQABAAEAAADs/xAAAQABAAEAAADs/w8AAQABAAEAAADs/w4AAQABAAEAAADs/w0AAQABAAEAAADr/x4AAQABAAEAAADr/x0AAQABAAEAAADr/xwAAQABAAEAAADr/xsAAQABAAEAAADr/xoAAQABAAEAAADr/xkAAQABAAEAAADr/xEAAQABAAEAAADr/xAAAQABAAEAAADr/w8AAQABAAEAAADr/w4AAQABAAEAAADr/w0AAQABAAEAAADq/x4AAQABAAEAAADq/x0AAQABAAEAAADq/xwAAQABAAEAAADq/xsAAQABAAEAAADq/xoAAQABAAEAAADq/xkAAQABAAEAAADq/xEAAQABAAEAAADq/xAAAQABAAEAAADq/w8AAQABAAEAAADq/w4AAQABAAEAAADq/w0AAQABAAEAAADp/x4AAQABAAEAAADp/x0AAQABAAEAAADp/xwAAQABAAEAAADp/xsAAQABAAEAAADp/xoAAQABAAEAAADp/xkAAQABAAEAAADp/xgAAQABAAEAAADp/xcAAQABAAEAAADp/xYAAQABAAEAAADp/xUAAQABAAEAAADp/xQAAQABAAEAAADp/xMAAQABAAEAAADp/xIAAQABAAEAAADp/xEAAQABAAEAAADp/xAAAQABAAEAAADp/w8AAQABAAEAAADp/w4AAQABAAEAAADp/w0AAQABAAEAAADo/x4AAQABAAEAAADo/x0AAQABAAEAAADo/xwAAQABAAEAAADo/xsAAQABAAEAAADo/xoAAQABAAEAAADo/xkAAQABAAEAAADo/xgAAQABAAEAAADo/xcAAQABAAEAAADo/xYAAQABAAEAAADo/xUAAQABAAEAAADo/xQAAQABAAEAAADo/xMAAQABAAEAAADo/xIAAQABAAEAAADo/xEAAQABAAEAAADo/xAAAQABAAEAAADo/w8AAQABAAEAAADo/w4AAQABAAEAAADo/w0AAQABAAEAAADn/x4AAQABAAEAAADn/x0AAQABAAEAAADn/xwAAQABAAEAAADn/xsAAQABAAEAAADn/xoAAQABAAEAAADn/xkAAQABAAEAAADn/xgAAQABAAEAAADn/xcAAQABAAEAAADn/xYAAQABAAEAAADn/xUAAQABAAEAAADn/xQAAQABAAEAAADn/xMAAQABAAEAAADn/xIAAQABAAEAAADn/xEAAQABAAEAAADn/xAAAQABAAEAAADn/w8AAQABAAEAAADn/w4AAQABAAEAAADn/w0AAQABAAEAAADm/x4AAQABAAEAAADm/x0AAQABAAEAAADm/xwAAQABAAEAAADm/xsAAQABAAEAAADm/xoAAQABAAEAAADm/xkAAQABAAEAAADm/xgAAQABAAEAAADm/xcAAQABAAEAAADm/xYAAQABAAEAAADm/xUAAQABAAEAAADm/xQAAQABAAEAAADm/xMAAQABAAEAAADm/xIAAQABAAEAAADm/xEAAQABAAEAAADm/xAAAQABAAEAAADm/w8AAQABAAEAAADm/w4AAQABAAEAAADm/w0AAQABAAEAAADl/x4AAQABAAEAAADl/x0AAQABAAEAAADl/xwAAQABAAEAAADl/xsAAQABAAEAAADl/xoAAQABAAEAAADl/xkAAQABAAEAAADl/xgAAQABAAEAAADl/xcAAQABAAEAAADl/xYAAQABAAEAAADl/xUAAQABAAEAAADl/xQAAQABAAEAAADl/xMAAQABAAEAAADl/xIAAQABAAEAAADl/xEAAQABAAEAAADl/xAAAQABAAEAAADl/w8AAQABAAEAAADl/w4AAQABAAEAAADl/w0AAQABAAEAAADk/x4AAQABAAEAAADk/x0AAQABAAEAAADk/xwAAQABAAEAAADk/xsAAQABAAEAAADk/xoAAQABAAEAAADk/xkAAQABAAEAAADk/xgAAQABAAEAAADk/xcAAQABAAEAAADk/xYAAQABAAEAAADk/xUAAQABAAEAAADk/xQAAQABAAEAAADk/xMAAQABAAEAAADk/xIAAQABAAEAAADk/xEAAQABAAEAAADk/xAAAQABAAEAAADk/w8AAQABAAEAAADk/w4AAQABAAEAAADk/w0AAQABAAEAAADw/wwAAQABAAEAAADv/wwAAQABAAEAAADu/wwAAQABAAEAAADt/wwAAQABAAEAAADs/wwAAQABAAEAAADr/wwAAQABAAEAAADq/wwAAQABAAEAAADp/wwAAQABAAEAAADo/wwAAQABAAEAAADn/wwAAQABAAEAAADm/wwAAQABAAEAAADl/wwAAQABAAEAAADk/wwAAQABAAEAAADj/x4AAQABAAEAAADj/x0AAQABAAEAAADj/xwAAQABAAEAAADj/xsAAQABAAEAAADj/xoAAQABAAEAAADj/xkAAQABAAEAAADj/xgAAQABAAEAAADi/x4AAQABAAEAAADi/x0AAQABAAEAAADi/xwAAQABAAEAAADi/xsAAQABAAEAAADi/xoAAQABAAEAAADi/xkAAQABAAEAAADi/xgAAQABAAEAAADh/x4AAQAAAAEAAADh/x0AAQAAAAEAAADh/xwAAQAAAAEAAADh/xsAAQAAAAEAAADh/xoAAQAAAAEAAADh/xkAAQAAAAEAAADh/xgAAQAAAAEAAADj/xcAAQABAAEAAADj/xYAAQABAAEAAADj/xUAAQABAAEAAADj/xQAAQABAAEAAADj/xMAAQABAAEAAADj/xIAAQABAAEAAADj/xEAAQABAAEAAADj/xAAAQABAAEAAADj/w8AAQABAAEAAADj/w4AAQABAAEAAADj/w0AAQABAAEAAADj/wwAAQABAAEAAADi/xcAAQABAAEAAADi/xYAAQABAAEAAADi/xUAAQABAAEAAADi/xQAAQABAAEAAADi/xMAAQABAAEAAADi/xIAAQABAAEAAADi/xEAAQABAAEAAADi/xAAAQABAAEAAADi/w8AAQABAAEAAADi/w4AAQABAAEAAADi/w0AAQABAAEAAADi/wwAAQABAAEAAADh/xcAAQAAAAEAAADh/xYAAQAAAAEAAADh/xUAAQAAAAEAAADh/xQAAQAAAAEAAADh/xMAAQAAAAEAAADh/xIAAQAAAAEAAADh/xEAAQAAAAEAAADh/xAAAQAAAAEAAADh/w8AAQAAAAEAAADh/w4AAQAAAAEAAADh/w0AAQAAAAEAAADh/wwAAQAAAAEAAAD7/wwAAQABAAEAAAD7/w0AAQABAAEAAAD7/w4AAQABAAEAAAD7/w8AAQABAAEAAAD7/xAAAQABAAEAAAD7/xEAAQABAAEAAAD7/xIAAQABAAEAAAD8/wwAAQABAAEAAAD8/w0AAQABAAEAAAD8/w4AAQABAAEAAAD8/w8AAQABAAEAAAD8/xAAAQABAAEAAAD8/xEAAQABAAEAAADx/wwAAQABAAEAAADx/w0AAQABAAEAAADx/w4AAQABAAEAAADx/w8AAQABAAEAAADx/xAAAQABAAEAAADx/xEAAQABAAEAAADy/wwAAQABAAEAAADy/w0AAQABAAEAAADy/w4AAQABAAEAAADy/w8AAQABAAEAAADy/xAAAQABAAEAAADy/xEAAQABAAEAAADz/wwAAQABAAEAAADz/w0AAQABAAEAAADz/w4AAQABAAEAAADz/w8AAQABAAEAAADz/xAAAQABAAEAAADz/xEAAQABAAEAAAD0/wwAAQABAAEAAAD0/w0AAQABAAEAAAD0/w4AAQABAAEAAAD0/w8AAQABAAEAAAD0/xAAAQABAAEAAAD0/xEAAQABAAEAAAD0/xIAAQABAAEAAAD0/xMAAQABAAEAAAD0/xQAAQABAAEAAAD0/xUAAQABAAEAAAD0/xYAAQABAAEAAAD1/wwAAQABAAEAAAD1/w0AAQABAAEAAAD1/w4AAQABAAEAAAD1/w8AAQABAAEAAAD1/xAAAQABAAEAAAD1/xEAAQABAAEAAAD1/xIAAQABAAEAAAD1/xMAAQABAAEAAAD1/xQAAQABAAEAAAD1/xUAAQABAAEAAAD1/xYAAQABAAEAAAD2/wwAAQABAAEAAAD2/w0AAQABAAEAAAD2/w4AAQABAAEAAAD2/w8AAQABAAEAAAD2/xAAAQABAAEAAAD2/xEAAQABAAEAAAD2/xIAAQABAAEAAAD2/xMAAQABAAEAAAD2/xQAAQABAAEAAAD2/xUAAQABAAEAAAD2/xYAAQABAAEAAAD3/wwAAQABAAEAAAD3/w0AAQABAAEAAAD3/w4AAQABAAEAAAD3/w8AAQABAAEAAAD3/xAAAQABAAEAAAD3/xEAAQABAAEAAAD3/xIAAQABAAEAAAD3/xMAAQABAAEAAAD3/xQAAQABAAEAAAD3/xUAAQABAAEAAAD3/xYAAQABAAEAAAD4/wwAAQABAAEAAAD4/w0AAQABAAEAAAD4/w4AAQABAAEAAAD4/w8AAQABAAEAAAD4/xAAAQABAAEAAAD4/xEAAQABAAEAAAD4/xIAAQABAAEAAAD4/xMAAQABAAEAAAD4/xQAAQABAAEAAAD4/xUAAQABAAEAAAD4/xYAAQABAAEAAAD5/wwAAQABAAEAAAD5/w0AAQABAAEAAAD5/w4AAQABAAEAAAD5/w8AAQABAAEAAAD5/xAAAQABAAEAAAD5/xEAAQABAAEAAAD5/xIAAQABAAEAAAD5/xMAAQABAAEAAAD5/xQAAQABAAEAAAD5/xUAAQABAAEAAAD5/xYAAQABAAEAAAD6/wwAAQABAAEAAAD6/w0AAQABAAEAAAD6/w4AAQABAAEAAAD6/w8AAQABAAEAAAD6/xAAAQABAAEAAAD6/xEAAQABAAEAAAD6/xIAAQABAAEAAAD6/xMAAQABAAEAAAD6/xQAAQABAAEAAAD6/xUAAQABAAEAAAD6/xYAAQABAAEAAADq/xIAAQABAAEAAADq/xMAAQABAAEAAADq/xQAAQABAAEAAADq/xUAAQABAAEAAADq/xYAAQABAAEAAADq/xcAAQABAAEAAADq/xgAAQABAAEAAADr/xIAAQABAAEAAADr/xMAAQABAAEAAADr/xQAAQABAAEAAADr/xUAAQABAAEAAADr/xYAAQABAAEAAADr/xcAAQABAAEAAADr/xgAAQABAAEAAADs/xIAAQABAAEAAADs/xMAAQABAAEAAADs/xQAAQABAAEAAADs/xUAAQABAAEAAADs/xYAAQABAAEAAADs/xcAAQABAAEAAADs/xgAAQABAAEAAADt/xIAAQABAAEAAADt/xMAAQABAAEAAADt/xQAAQABAAEAAADt/xUAAQABAAEAAADt/xYAAQABAAEAAADt/xcAAQABAAEAAADt/xgAAQABAAEAAADu/xIAAQABAAEAAADu/xMAAQABAAEAAADu/xQAAQABAAEAAADu/xUAAQABAAEAAADu/xYAAQABAAEAAADu/xcAAQABAAEAAADu/xgAAQABAAEAAADv/xIAAQABAAEAAADv/xMAAQABAAEAAADv/xQAAQABAAEAAADv/xUAAQABAAEAAADv/xYAAQABAAEAAADv/xcAAQABAAEAAADv/xgAAQABAAEAAADw/xIAAQABAAEAAADw/xMAAQABAAEAAADw/xQAAQABAAEAAADw/xUAAQABAAEAAADw/xYAAQABAAEAAADw/xcAAQABAAEAAADw/xgAAQABAAEAAADx/xIAAQABAAEAAADx/xMAAQABAAEAAADx/xQAAQABAAEAAADx/xUAAQABAAEAAADx/xYAAQABAAEAAADx/xcAAQABAAEAAADx/xgAAQABAAEAAADy/xIAAQABAAEAAADy/xMAAQABAAEAAADy/xQAAQABAAEAAADy/xUAAQABAAEAAADy/xYAAQABAAEAAADy/xcAAQABAAEAAADy/xgAAQABAAEAAADz/xIAAQABAAEAAADz/xMAAQABAAEAAADz/xQAAQABAAEAAADz/xUAAQABAAEAAADz/xYAAQABAAEAAADz/xcAAQABAAEAAADz/xgAAQABAAEAAAA=") tile_set = ExtResource("4_7v23v") -[node name="Patches" type="TileMapLayer" parent="TileMapLayers" unique_id=1419115144] -tile_set = ExtResource("4_7v23v") - [node name="Void" type="TileMapLayer" parent="TileMapLayers" unique_id=1056472020] texture_filter = 1 material = ExtResource("2_hx14g") -tile_map_data = PackedByteArray("AAABABMADQABAAEAAAABABIADQABAAEAAAABABEADQABAAEAAAABAA8ADQABAAEAAAABAA4ADQABAAEAAAABAA0ADQABAAEAAAABAAwADQABAAEAAAAAABMADQABAAEAAAAAABEADQABAAEAAAAAABAADQABAAEAAAAAAA8ADQABAAEAAAAAAA4ADQABAAEAAAAAAA0ADQABAAEAAAAAAAwADQABAAEAAAD//xMADQABAAEAAAD//xEADQABAAEAAAD//xAADQABAAEAAAD//w8ADQABAAEAAAD//w4ADQABAAEAAAD//w0ADQABAAEAAAD//wwADQABAAEAAAD+/xMADQABAAEAAAD+/xIADQABAAEAAAD+/xEADQABAAEAAAD+/xAADQABAAEAAAD+/w8ADQABAAEAAAD+/w4ADQABAAEAAAD+/w0ADQABAAEAAAD+/wwADQABAAEAAAD9/xMADQABAAEAAAD9/xIADQABAAEAAAD9/xEADQABAAEAAAD9/xAADQABAAEAAAD9/w8ADQABAAEAAAD9/w4ADQABAAEAAAD9/w0ADQABAAEAAAD9/wwADQABAAEAAAABABcADQABAAEAAAABABYADQABAAEAAAABABUADQABAAEAAAABABgADQABAAEAAAAAABgADQABAAEAAAAAABcADQABAAEAAAAAABYADQABAAEAAAD//xgADQABAAIAAAD//xcADQABAAEAAAD//xYADQABAAEAAAD+/xgADQABAAIAAAD+/xcADQABAAEAAAD+/xYADQABAAEAAAD9/xgADQABAAIAAAD9/xcADQABAAEAAAD9/xYADQABAAEAAAABABQADQABAAEAAAAAABUADQABAAEAAAAAABQADQABAAEAAAD//xUADQABAAEAAAD//xQADQABAAEAAAD+/xUADQABAAEAAAD+/xQADQABAAEAAAD9/xUADQABAAEAAAD9/xQADQABAAEAAAABAB4ADQABAAEAAAABAB0ADQABAAEAAAABABwADQABAAEAAAABABsADQABAAEAAAABABoADQABAAEAAAABABkADQABAAEAAAAAAB4ADQABAAEAAAAAAB0ADQABAAEAAAAAABwADQAAAAEAAAAAABsADQAAAAEAAAAAABoADQAAAAEAAAAAABkADQAAAAEAAAD//x4ADQABAAEAAAD//x0ADQABAAAAAAD+/x4ADQABAAEAAAD+/x0ADQABAAAAAAD9/x4ADQABAAEAAAD9/x0ADQABAAAAAAD8/xgADQABAAIAAAD8/xcADQABAAEAAAD8/xYADQABAAEAAAD8/xUADQABAAEAAAD8/xQADQABAAEAAAD8/xMADQABAAEAAAD8/xIADQABAAEAAAD8/xEADQABAAEAAAD8/xAADQABAAEAAAD8/w8ADQABAAEAAAD8/w4ADQABAAEAAAD8/w0ADQABAAEAAAD8/wwADQABAAEAAAD7/xgADQABAAIAAAD7/xcADQABAAEAAAD7/xYADQABAAEAAAD7/xUADQABAAEAAAD7/wwADQABAAEAAAD6/xgADQABAAIAAAD6/xcADQABAAEAAAD6/xYADQABAAEAAAD5/xgADQABAAIAAAD5/xcADQABAAEAAAD5/xYADQABAAEAAAD4/xgADQABAAIAAAD4/xcADQABAAEAAAD4/xYADQABAAEAAAD3/xcADQABAAEAAAD3/xYADQABAAEAAAD2/xgADQABAAIAAAD2/xcADQABAAEAAAD2/xYADQABAAEAAAD1/xgADQABAAIAAAD1/xcADQABAAEAAAD1/xYADQABAAEAAAD0/xgADQABAAIAAAD0/xcADQABAAEAAAD0/xYADQABAAEAAAD0/xUADQABAAEAAAD0/wwADQABAAEAAADz/xgADQABAAIAAADz/xcADQABAAEAAADz/xQADQABAAEAAADz/xMADQABAAEAAADz/xIADQABAAEAAADz/xEADQABAAEAAADz/w4ADQABAAEAAADz/w0ADQABAAEAAADz/wwADQABAAEAAADy/xgADQABAAIAAADy/xcADQABAAEAAADy/xQADQABAAEAAADy/xMADQABAAEAAADy/xIADQABAAEAAADy/xEADQABAAEAAADy/w4ADQABAAEAAADy/w0ADQABAAEAAADy/wwADQABAAEAAADx/xgADQABAAIAAADx/xcADQABAAEAAADx/xYADQABAAEAAADx/xUADQABAAEAAADx/xQADQABAAEAAADx/xMADQABAAEAAADx/xIADQABAAEAAADx/xEADQABAAEAAADx/xAADQABAAEAAADx/w8ADQABAAEAAADx/w4ADQABAAEAAADx/w0ADQABAAEAAADx/wwADQABAAEAAADw/xgADQABAAIAAADw/xcADQABAAEAAADw/xYADQABAAEAAADw/xUADQABAAEAAADw/xQADQABAAEAAADw/xMADQABAAEAAADw/xIADQABAAEAAADw/xEADQABAAEAAADw/xAADQABAAEAAADw/w8ADQABAAEAAADw/w4ADQABAAEAAADw/w0ADQABAAEAAADw/wwADQABAAEAAADv/xgADQABAAIAAADv/xcADQABAAEAAADv/xYADQABAAEAAADv/xUADQABAAEAAADv/xQADQABAAEAAADv/xMADQABAAEAAADv/xIADQABAAEAAADv/xEADQABAAEAAADv/w4ADQABAAEAAADv/w0ADQABAAEAAADv/wwADQABAAEAAADu/xgADQABAAEAAADu/xcADQABAAEAAADu/xYADQABAAEAAADu/xUADQABAAEAAADu/xQADQABAAEAAADu/xMADQABAAEAAADu/xIADQABAAEAAADu/xEADQABAAEAAADu/w4ADQABAAEAAADu/w0ADQABAAEAAADu/wwADQABAAEAAADt/xgADQABAAEAAADt/xcADQABAAEAAADt/xYADQABAAEAAADt/xUADQABAAEAAADt/xQADQABAAEAAADt/xMADQABAAEAAADt/xIADQABAAEAAADt/xEADQABAAEAAADt/w4ADQABAAEAAADt/w0ADQABAAEAAADt/wwADQABAAEAAADs/xgADQABAAEAAADs/xcADQABAAEAAADs/xYADQABAAEAAADs/xUADQABAAEAAADs/xQADQABAAEAAADs/xMADQABAAEAAADs/xIADQABAAEAAADs/xEADQABAAEAAADs/w4ADQABAAEAAADs/w0ADQABAAEAAADs/wwADQABAAEAAADr/xgADQABAAEAAADr/xcADQABAAEAAADr/xYADQABAAEAAADr/xUADQABAAEAAADr/xQADQABAAEAAADr/xMADQABAAEAAADr/xIADQABAAEAAADr/xEADQABAAEAAADr/xAADQABAAEAAADr/w8ADQABAAEAAADr/w4ADQABAAEAAADr/w0ADQABAAEAAADr/wwADQABAAEAAADq/xgADQABAAEAAADq/xcADQABAAEAAADq/xYADQABAAEAAADq/xUADQABAAEAAADq/xQADQABAAEAAADq/xMADQABAAEAAADq/xIADQABAAEAAADq/xEADQABAAEAAADq/xAADQABAAEAAADq/w8ADQABAAEAAADq/w4ADQABAAEAAADq/w0ADQABAAEAAADq/wwADQABAAEAAADp/xgADQABAAEAAADp/xcADQABAAEAAADp/xYADQABAAEAAADp/xUADQABAAEAAADp/xQADQABAAEAAADp/xMADQABAAEAAADp/xIADQABAAEAAADp/xEADQABAAEAAADp/xAADQABAAEAAADp/w8ADQABAAEAAADp/w4ADQABAAEAAADp/w0ADQABAAEAAADp/wwADQABAAEAAADo/xgADQABAAIAAADo/xcADQABAAEAAADo/xYADQABAAEAAADo/xUADQABAAEAAADo/xQADQABAAEAAADo/xMADQABAAEAAADo/xIADQABAAEAAADo/xEADQABAAEAAADo/xAADQABAAEAAADo/w8ADQABAAEAAADo/w4ADQABAAEAAADo/w0ADQABAAEAAADo/wwADQABAAEAAADn/xgADQABAAIAAADn/xcADQABAAEAAADn/xYADQABAAEAAADn/xUADQABAAEAAADn/xQADQABAAEAAADn/xMADQABAAEAAADn/xIADQABAAEAAADn/xEADQABAAEAAADn/xAADQABAAEAAADn/w8ADQABAAEAAADn/w4ADQABAAEAAADn/w0ADQABAAEAAADn/wwADQABAAEAAAD8/x4ADQABAAEAAAD8/x0ADQABAAAAAAD7/x4ADQABAAEAAAD7/x0ADQABAAAAAAD6/x4ADQABAAEAAAD6/x0ADQABAAAAAAD5/x4ADQABAAEAAAD5/x0ADQABAAAAAAD4/x4ADQABAAEAAAD4/x0ADQABAAAAAAD3/x4ADQABAAEAAAD3/x0ADQABAAAAAAD2/x4ADQABAAEAAAD2/x0ADQABAAAAAAD1/x4ADQABAAEAAAD1/x0ADQABAAAAAAD0/x4ADQABAAEAAAD0/x0ADQABAAAAAADz/x4ADQABAAEAAADz/x0ADQABAAAAAADy/x4ADQABAAEAAADy/x0ADQABAAAAAADx/x4ADQABAAEAAADx/x0ADQABAAAAAADw/x4ADQABAAEAAADw/x0ADQABAAAAAADv/x4ADQABAAEAAADv/x0ADQABAAAAAADu/x4ADQABAAEAAADu/x0ADQABAAEAAADt/x4ADQABAAEAAADt/x0ADQABAAEAAADs/x4ADQABAAEAAADs/x0ADQABAAEAAADr/x4ADQABAAEAAADr/x0ADQABAAEAAADq/x4ADQABAAEAAADq/x0ADQABAAEAAADp/x4ADQABAAEAAADp/x0ADQABAAEAAADo/x4ADQABAAEAAADo/x0ADQABAAAAAADn/x4ADQABAAEAAADn/x0ADQABAAAAAADu/xwADQACAAEAAADu/xsADQACAAEAAADu/xoADQACAAEAAADu/xkADQACAAEAAADt/xwADQABAAEAAADt/xsADQABAAEAAADt/xoADQABAAEAAADt/xkADQABAAEAAADs/xwADQABAAEAAADs/xsADQABAAEAAADs/xoADQABAAEAAADs/xkADQABAAEAAADm/xgADQABAAIAAADm/xcADQABAAEAAADm/xYADQABAAEAAADm/xUADQABAAEAAADm/xQADQABAAEAAADm/xMADQABAAEAAADm/xIADQABAAEAAADm/xEADQABAAEAAADm/xAADQABAAEAAADm/w8ADQABAAEAAADm/w4ADQABAAEAAADl/xgADQABAAIAAADl/xcADQABAAEAAADl/xYADQABAAEAAADl/xUADQABAAEAAADl/xQADQABAAEAAADl/xMADQABAAEAAADl/xIADQABAAEAAADl/xEADQABAAEAAADl/xAADQABAAEAAADl/w8ADQABAAEAAADl/w4ADQABAAEAAADk/xgADQABAAIAAADk/xcADQABAAEAAADk/xYADQABAAEAAADk/xUADQABAAEAAADk/xQADQABAAEAAADk/xMADQABAAEAAADk/xIADQABAAEAAADk/xEADQABAAEAAADk/xAADQABAAEAAADk/w8ADQABAAEAAADk/w4ADQABAAEAAADj/xgADQABAAIAAADj/xcADQABAAEAAADj/xYADQABAAEAAADj/xUADQABAAEAAADj/xQADQABAAEAAADj/xMADQABAAEAAADj/xIADQABAAEAAADj/xEADQABAAEAAADj/xAADQABAAEAAADj/w8ADQABAAEAAADj/w4ADQABAAEAAADi/xgADQABAAIAAADi/xcADQABAAEAAADi/xYADQABAAEAAADi/xUADQABAAEAAADi/xQADQABAAEAAADi/xMADQABAAEAAADi/xIADQABAAEAAADi/xEADQABAAEAAADi/xAADQABAAEAAADi/w8ADQABAAEAAADi/w4ADQABAAEAAADh/xgADQABAAIAAADh/xcADQABAAEAAADh/xYADQABAAEAAADh/xUADQABAAEAAADh/xQADQABAAEAAADh/xMADQABAAEAAADh/xIADQABAAEAAADh/xEADQABAAEAAADh/xAADQABAAEAAADh/w8ADQABAAEAAADh/w4ADQABAAEAAADg/xgADQABAAIAAADg/xcADQABAAEAAADg/xYADQABAAEAAADg/xUADQABAAEAAADg/xQADQABAAEAAADg/xMADQABAAEAAADg/xIADQABAAEAAADg/xEADQABAAEAAADg/xAADQABAAEAAADg/w8ADQABAAEAAADg/w4ADQABAAEAAADf/xgADQAAAAIAAADf/xcADQAAAAEAAADf/xYADQAAAAEAAADf/xUADQAAAAEAAADf/xQADQAAAAEAAADf/xMADQAAAAEAAADf/xIADQAAAAEAAADf/xEADQAAAAEAAADf/xAADQAAAAEAAADf/w8ADQAAAAEAAADf/w4ADQAAAAEAAADm/x4ADQABAAEAAADm/x0ADQABAAAAAADl/x4ADQABAAEAAADl/x0ADQABAAAAAADk/x4ADQABAAEAAADk/x0ADQABAAAAAADj/x4ADQABAAEAAADj/x0ADQABAAAAAADi/x4ADQABAAEAAADi/x0ADQABAAAAAADh/x4ADQABAAEAAADh/x0ADQABAAAAAADg/x4ADQABAAEAAADg/x0ADQABAAAAAADf/x4ADQAAAAEAAADf/x0ADQAAAAAAAADm/w0ADQABAAEAAADm/wwADQABAAEAAADl/w0ADQABAAEAAADl/wwADQABAAEAAADk/w0ADQABAAEAAADk/wwADQABAAEAAADj/w0ADQABAAEAAADj/wwADQABAAEAAADi/w0ADQABAAEAAADi/wwADQABAAEAAADh/w0ADQABAAEAAADh/wwADQABAAEAAADg/w0ADQABAAEAAADg/wwADQABAAEAAADf/w0ADQAAAAEAAADf/wwADQAAAAEAAAD7/xQADQABAAEAAAD7/xMADQABAAEAAAD6/xUADQABAAEAAAD6/xQADQABAAEAAAD6/xMADQABAAEAAAD5/xUADQABAAEAAAD5/xQADQABAAEAAAD5/xMADQABAAEAAAD1/xUADQABAAEAAAD1/xQADQABAAEAAAD0/xQADQABAAEAAAD7/xIADQABAAEAAAD6/xIADQABAAEAAAD7/xEADQABAAEAAAD7/xAADQABAAEAAAD7/w8ADQABAAEAAAD7/w4ADQABAAEAAAD7/w0ADQABAAEAAAD6/wwADQABAAEAAAD3/xgADQABAAIAAAD4/xQADQABAAEAAAD3/xQADQABAAEAAAD3/xUADQABAAEAAAD2/xUADQABAAEAAAD2/xQADQABAAEAAAD4/xUADQABAAEAAAD0/w0ADQABAAEAAAD0/w4ADQABAAEAAAD0/w8ADQABAAEAAAD0/xAADQABAAEAAAD0/xEADQABAAEAAAD1/wwADQABAAEAAAD1/w0ADQABAAEAAAD1/w4ADQABAAEAAAD1/w8ADQABAAEAAAD1/xAADQABAAEAAAD1/xEADQABAAEAAAD2/wwADQABAAEAAAD2/w0ADQABAAEAAAD2/w4ADQABAAEAAAD2/w8ADQABAAEAAAD2/xAADQABAAEAAAD2/xEADQABAAEAAAD2/xIADQABAAEAAAD2/xMADQABAAEAAAD3/wwADQABAAEAAAD3/w0ADQABAAEAAAD3/w4ADQABAAEAAAD3/w8ADQABAAEAAAD3/xAADQABAAEAAAD3/xEADQABAAEAAAD3/xIADQABAAEAAAD3/xMADQABAAEAAAD4/wwADQABAAEAAAD4/w0ADQABAAEAAAD4/w4ADQABAAEAAAD4/w8ADQABAAEAAAD4/xAADQABAAEAAAD4/xEADQABAAEAAAD4/xIADQABAAEAAAD4/xMADQABAAEAAAD5/wwADQABAAEAAAD5/w0ADQABAAEAAAD5/w4ADQABAAEAAAD5/w8ADQABAAEAAAD5/xAADQABAAEAAAD5/xEADQABAAEAAAD5/xIADQABAAEAAAD6/w0ADQABAAEAAAD6/w4ADQABAAEAAAD6/w8ADQABAAEAAAD6/xAADQABAAEAAAD6/xEADQABAAEAAAD//xIADQABAAEAAAAAABIADQABAAEAAAABABAADQABAAEAAAA=") +tile_map_data = PackedByteArray("AAABABMADQABAAEAAAABABIADQABAAEAAAABABEADQABAAEAAAABAA8ADQABAAEAAAABAA4ADQABAAEAAAABAA0ADQABAAEAAAABAAwADQABAAEAAAAAABMADQABAAEAAAAAABEADQABAAEAAAAAABAADQABAAEAAAAAAA8ADQABAAEAAAAAAA4ADQABAAEAAAAAAA0ADQABAAEAAAAAAAwADQABAAEAAAD//xMADQABAAEAAAD//xEADQABAAEAAAD//xAADQABAAEAAAD//w8ADQABAAEAAAD//w4ADQABAAEAAAD//w0ADQABAAEAAAD//wwADQABAAEAAAD+/xMADQABAAEAAAD+/xIADQABAAEAAAD+/xEADQABAAEAAAD+/xAADQABAAEAAAD+/w8ADQABAAEAAAD+/w4ADQABAAEAAAD+/w0ADQABAAEAAAD+/wwADQABAAEAAAD9/xMADQABAAEAAAD9/xIADQABAAEAAAD9/xEADQABAAEAAAD9/xAADQABAAEAAAD9/w8ADQABAAEAAAD9/w4ADQABAAEAAAD9/w0ADQABAAEAAAD9/wwADQABAAEAAAABABcADQABAAEAAAABABYADQABAAEAAAABABUADQABAAEAAAABABgADQABAAEAAAAAABgADQABAAEAAAAAABcADQABAAEAAAAAABYADQABAAEAAAD//xgADQABAAEAAAD//xcADQABAAEAAAD//xYADQABAAEAAAD+/xgADQABAAEAAAD+/xcADQABAAEAAAD+/xYADQABAAEAAAD9/xgADQABAAEAAAD9/xcADQABAAEAAAD9/xYADQABAAEAAAABABQADQABAAEAAAAAABUADQABAAEAAAAAABQADQABAAEAAAD//xUADQABAAEAAAD//xQADQABAAEAAAD+/xUADQABAAEAAAD+/xQADQABAAEAAAD9/xUADQABAAEAAAD9/xQADQABAAEAAAABAB4ADQABAAEAAAABAB0ADQABAAEAAAABABwADQABAAEAAAABABsADQABAAEAAAABABoADQABAAEAAAABABkADQABAAEAAAAAAB4ADQABAAEAAAAAAB0ADQABAAEAAAAAABwADQABAAEAAAAAABsADQABAAEAAAAAABoADQABAAEAAAAAABkADQABAAEAAAD//x4ADQABAAEAAAD//x0ADQABAAEAAAD+/x4ADQABAAEAAAD+/x0ADQABAAEAAAD9/x4ADQABAAEAAAD9/x0ADQABAAEAAAD8/xgADQABAAEAAAD8/xcADQABAAEAAAD8/xYADQABAAEAAAD8/xUADQABAAEAAAD8/xQADQABAAEAAAD8/xMADQABAAEAAAD8/xIADQABAAEAAAD8/xEADQABAAEAAAD8/xAADQABAAEAAAD8/w8ADQABAAEAAAD8/w4ADQABAAEAAAD8/w0ADQABAAEAAAD8/wwADQABAAEAAAD7/xgADQABAAIAAAD7/xcADQABAAEAAAD7/xYADQABAAEAAAD7/xUADQABAAEAAAD7/wwADQABAAEAAAD6/xgADQABAAIAAAD6/xcADQABAAEAAAD6/xYADQABAAEAAAD5/xgADQABAAIAAAD5/xcADQABAAEAAAD5/xYADQABAAEAAAD4/xgADQABAAIAAAD4/xcADQABAAEAAAD4/xYADQABAAEAAAD3/xcADQABAAEAAAD3/xYADQABAAEAAAD2/xgADQABAAIAAAD2/xcADQABAAEAAAD2/xYADQABAAEAAAD1/xgADQABAAIAAAD1/xcADQABAAEAAAD1/xYADQABAAEAAAD0/xgADQABAAIAAAD0/xcADQABAAEAAAD0/xYADQAAAAEAAAD0/xUADQAAAAEAAAD0/wwADQABAAEAAADz/xgADQABAAIAAADz/xcADQABAAAAAADz/xQADQABAAIAAADz/xMADQACAAEAAADz/xIADQACAAEAAADz/xEADQABAAAAAADz/w4ADQABAAIAAADz/w0ADQABAAEAAADz/wwADQABAAEAAADy/xgADQABAAIAAADy/xcADQABAAAAAADy/xQADQABAAIAAADy/xMADQABAAEAAADy/xIADQABAAEAAADy/xEADQABAAAAAADy/w4ADQABAAIAAADy/w0ADQABAAEAAADy/wwADQABAAEAAADx/xgADQABAAIAAADx/xcADQABAAEAAADx/xYADQACAAEAAADx/xUADQACAAEAAADx/xQADQABAAEAAADx/xMADQABAAEAAADx/xIADQABAAEAAADx/xEADQABAAEAAADx/xAADQACAAEAAADx/w8ADQACAAEAAADx/w4ADQABAAEAAADx/w0ADQABAAEAAADx/wwADQABAAEAAADw/xgADQABAAIAAADw/xcADQABAAEAAADw/xYADQABAAEAAADw/xUADQABAAEAAADw/xQADQABAAEAAADw/xMADQABAAEAAADw/xIADQAAAAEAAADw/xEADQAAAAEAAADw/xAADQAAAAEAAADw/w8ADQAAAAEAAADw/w4ADQAAAAEAAADw/w0ADQABAAEAAADw/wwADQABAAEAAADv/xgADQABAAIAAADv/xcADQABAAEAAADv/xYADQABAAEAAADv/xUADQABAAEAAADv/xQADQABAAEAAADv/xMADQABAAAAAADv/w0ADQABAAIAAADv/wwADQABAAEAAADu/xgADQABAAEAAADu/xcADQABAAEAAADu/xYADQABAAEAAADu/xUADQABAAEAAADu/xQADQABAAEAAADu/xMADQABAAAAAADu/xEADQACAAIAAADu/w0ADQABAAIAAADu/wwADQABAAEAAADt/xgADQABAAEAAADt/xcADQABAAEAAADt/xYADQABAAEAAADt/xUADQABAAEAAADt/xQADQABAAEAAADt/xMADQABAAAAAADt/xEADQABAAIAAADt/w0ADQABAAIAAADt/wwADQABAAEAAADs/xgADQABAAEAAADs/xcADQABAAEAAADs/xYADQABAAEAAADs/xUADQABAAEAAADs/xQADQABAAEAAADs/xMADQABAAAAAADs/xEADQAAAAMAAADs/w0ADQABAAIAAADs/wwADQABAAEAAADr/xgADQABAAIAAADr/xcADQABAAEAAADr/xYADQABAAEAAADr/xUADQABAAEAAADr/xQADQABAAEAAADr/xMADQABAAAAAADr/w0ADQABAAIAAADr/wwADQABAAEAAADq/xgADQABAAIAAADq/xcADQABAAEAAADq/xYADQABAAEAAADq/xUADQABAAEAAADq/xQADQABAAEAAADq/xMADQABAAEAAADq/xIADQACAAEAAADq/xEADQACAAEAAADq/xAADQACAAEAAADq/w8ADQACAAEAAADq/w4ADQACAAEAAADq/w0ADQABAAEAAADq/wwADQABAAEAAADp/xgADQABAAIAAADp/xcADQABAAEAAADp/xYADQABAAEAAADp/xUADQABAAEAAADp/xQADQABAAEAAADp/xMADQABAAEAAADp/xIADQABAAEAAADp/xEADQABAAEAAADp/xAADQABAAEAAADp/w8ADQABAAEAAADp/w4ADQABAAEAAADp/w0ADQABAAEAAADp/wwADQABAAEAAADo/xgADQABAAIAAADo/xcADQABAAEAAADo/xYADQABAAEAAADo/xUADQABAAEAAADo/xQADQABAAEAAADo/xMADQABAAEAAADo/xIADQABAAEAAADo/xEADQABAAEAAADo/xAADQABAAEAAADo/w8ADQABAAEAAADo/w4ADQABAAEAAADo/w0ADQABAAEAAADo/wwADQABAAEAAADn/xgADQABAAIAAADn/xcADQABAAEAAADn/xYADQABAAEAAADn/xUADQABAAEAAADn/xQADQABAAEAAADn/xMADQABAAEAAADn/xIADQABAAEAAADn/xEADQABAAEAAADn/xAADQABAAEAAADn/w8ADQABAAEAAADn/w4ADQABAAEAAADn/w0ADQABAAEAAADn/wwADQABAAEAAAD8/x4ADQABAAEAAAD8/x0ADQABAAEAAAD7/x4ADQABAAEAAAD7/x0ADQABAAEAAAD6/x4ADQABAAEAAAD6/x0ADQABAAEAAAD5/x4ADQABAAEAAAD5/x0ADQABAAEAAAD4/x4ADQABAAEAAAD4/x0ADQABAAEAAAD3/x4ADQABAAEAAAD3/x0ADQABAAEAAAD2/x4ADQABAAEAAAD2/x0ADQABAAEAAAD1/x4ADQABAAEAAAD1/x0ADQABAAEAAAD0/x4ADQABAAEAAAD0/x0ADQABAAEAAADz/x4ADQABAAEAAADz/x0ADQABAAEAAADy/x4ADQABAAEAAADy/x0ADQABAAEAAADx/x4ADQABAAEAAADx/x0ADQABAAEAAADw/x4ADQABAAEAAADw/x0ADQABAAEAAADv/x4ADQABAAEAAADv/x0ADQABAAEAAADu/x4ADQABAAEAAADu/x0ADQABAAEAAADt/x4ADQABAAEAAADt/x0ADQABAAEAAADs/x4ADQABAAEAAADs/x0ADQABAAEAAADr/x4ADQABAAEAAADr/x0ADQABAAEAAADq/x4ADQABAAEAAADq/x0ADQABAAEAAADp/x4ADQABAAEAAADp/x0ADQABAAEAAADo/x4ADQABAAEAAADo/x0ADQABAAEAAADn/x4ADQABAAEAAADn/x0ADQABAAEAAADu/xwADQABAAEAAADu/xsADQACAAEAAADu/xoADQACAAEAAADu/xkADQACAAEAAADt/xwADQABAAEAAADt/xsADQABAAEAAADt/xoADQABAAEAAADt/xkADQABAAEAAADs/xwADQABAAEAAADs/xsADQAAAAEAAADs/xoADQAAAAEAAADs/xkADQAAAAEAAADm/xgADQABAAIAAADm/xcADQABAAEAAADm/xYADQABAAEAAADm/xUADQABAAEAAADm/xQADQABAAEAAADm/xMADQABAAEAAADm/xIADQABAAEAAADm/xEADQABAAEAAADm/xAADQABAAEAAADm/w8ADQABAAEAAADm/w4ADQABAAEAAADl/xgADQABAAIAAADl/xcADQABAAEAAADl/xYADQABAAEAAADl/xUADQABAAEAAADl/xQADQABAAEAAADl/xMADQABAAEAAADl/xIADQABAAEAAADl/xEADQABAAEAAADl/xAADQABAAEAAADl/w8ADQABAAEAAADl/w4ADQABAAEAAADk/xgADQABAAIAAADk/xcADQABAAEAAADk/xYADQABAAEAAADk/xUADQABAAEAAADk/xQADQABAAEAAADk/xMADQABAAEAAADk/xIADQABAAEAAADk/xEADQABAAEAAADk/xAADQABAAEAAADk/w8ADQABAAEAAADk/w4ADQABAAEAAADj/xgADQABAAIAAADj/xcADQABAAEAAADj/xYADQABAAEAAADj/xUADQABAAEAAADj/xQADQABAAEAAADj/xMADQABAAEAAADj/xIADQABAAEAAADj/xEADQABAAEAAADj/xAADQABAAEAAADj/w8ADQABAAEAAADj/w4ADQABAAEAAADi/xgADQABAAIAAADi/xcADQABAAEAAADi/xYADQABAAEAAADi/xUADQABAAEAAADi/xQADQABAAEAAADi/xMADQABAAEAAADi/xIADQABAAEAAADi/xEADQABAAEAAADi/xAADQABAAEAAADi/w8ADQABAAEAAADi/w4ADQABAAEAAADh/xgADQABAAEAAADh/xcADQABAAEAAADh/xYADQABAAEAAADh/xUADQABAAEAAADh/xQADQABAAEAAADh/xMADQABAAEAAADh/xIADQABAAEAAADh/xEADQABAAEAAADh/xAADQABAAEAAADh/w8ADQABAAEAAADh/w4ADQABAAEAAADg/xgADQABAAEAAADg/xcADQABAAEAAADg/xYADQABAAEAAADg/xUADQABAAEAAADg/xQADQABAAEAAADg/xMADQABAAEAAADg/xIADQABAAEAAADg/xEADQABAAEAAADg/xAADQABAAEAAADg/w8ADQABAAEAAADg/w4ADQABAAEAAADf/xgADQAAAAEAAADf/xcADQAAAAEAAADf/xYADQAAAAEAAADf/xUADQAAAAEAAADf/xQADQAAAAEAAADf/xMADQAAAAEAAADf/xIADQAAAAEAAADf/xEADQAAAAEAAADf/xAADQAAAAEAAADf/w8ADQAAAAEAAADf/w4ADQAAAAEAAADm/x4ADQABAAEAAADm/x0ADQABAAEAAADl/x4ADQABAAEAAADl/x0ADQABAAEAAADk/x4ADQABAAEAAADk/x0ADQABAAEAAADj/x4ADQABAAEAAADj/x0ADQABAAEAAADi/x4ADQABAAEAAADi/x0ADQABAAEAAADh/x4ADQABAAEAAADh/x0ADQABAAEAAADg/x4ADQABAAEAAADg/x0ADQABAAEAAADf/x4ADQAAAAEAAADf/x0ADQAAAAEAAADm/w0ADQABAAEAAADm/wwADQABAAEAAADl/w0ADQABAAEAAADl/wwADQABAAEAAADk/w0ADQABAAEAAADk/wwADQABAAEAAADj/w0ADQABAAEAAADj/wwADQABAAEAAADi/w0ADQABAAEAAADi/wwADQABAAEAAADh/w0ADQABAAEAAADh/wwADQABAAEAAADg/w0ADQABAAEAAADg/wwADQABAAEAAADf/w0ADQAAAAEAAADf/wwADQAAAAEAAAD7/xQADQABAAEAAAD7/xMADQABAAEAAAD6/xUADQABAAEAAAD6/xQADQABAAEAAAD6/xMADQABAAEAAAD5/xUADQABAAEAAAD5/xQADQABAAEAAAD5/xMADQABAAEAAAD1/xUADQABAAEAAAD1/xQADQABAAAAAAD0/xQADQABAAAAAAD7/xIADQABAAEAAAD6/xIADQABAAEAAAD7/xEADQABAAEAAAD7/xAADQABAAEAAAD7/w8ADQABAAEAAAD7/w4ADQABAAEAAAD7/w0ADQABAAEAAAD6/wwADQABAAEAAAD3/xgADQABAAIAAAD4/xQADQABAAEAAAD3/xQADQABAAEAAAD3/xUADQABAAEAAAD2/xUADQABAAEAAAD2/xQADQABAAEAAAD4/xUADQABAAEAAAD0/w0ADQABAAEAAAD0/w4ADQABAAIAAAD0/xEADQABAAMAAAD1/wwADQABAAEAAAD1/w0ADQABAAEAAAD1/w4ADQABAAEAAAD1/w8ADQAAAAEAAAD1/xAADQAAAAEAAAD1/xEADQABAAIAAAD2/wwADQABAAEAAAD2/w0ADQABAAEAAAD2/w4ADQABAAEAAAD2/w8ADQABAAEAAAD2/xAADQABAAEAAAD2/xEADQABAAEAAAD2/xIADQAAAAEAAAD2/xMADQAAAAEAAAD3/wwADQABAAEAAAD3/w0ADQABAAEAAAD3/w4ADQABAAEAAAD3/w8ADQABAAEAAAD3/xAADQABAAEAAAD3/xEADQABAAEAAAD3/xIADQABAAEAAAD3/xMADQABAAEAAAD4/wwADQABAAEAAAD4/w0ADQABAAEAAAD4/w4ADQABAAEAAAD4/w8ADQABAAEAAAD4/xAADQABAAEAAAD4/xEADQABAAEAAAD4/xIADQABAAEAAAD4/xMADQABAAEAAAD5/wwADQABAAEAAAD5/w0ADQABAAEAAAD5/w4ADQABAAEAAAD5/w8ADQABAAEAAAD5/xAADQABAAEAAAD5/xEADQABAAEAAAD5/xIADQABAAEAAAD6/w0ADQABAAEAAAD6/w4ADQABAAEAAAD6/w8ADQABAAEAAAD6/xAADQABAAEAAAD6/xEADQABAAEAAAD//xIADQABAAEAAAAAABIADQABAAEAAAABABAADQABAAEAAAD9/xkADQABAAEAAAD9/xoADQABAAEAAAD9/xsADQABAAEAAAD9/xwADQABAAEAAAD+/xkADQABAAEAAAD+/xoADQABAAEAAAD+/xsADQABAAEAAAD+/xwADQABAAEAAAD//xoADQABAAEAAAD//xkADQABAAEAAAD//xsADQABAAEAAAD//xwADQABAAEAAADg/xkADQABAAEAAADg/xoADQABAAEAAADg/xsADQABAAEAAADg/xwADQABAAEAAADf/xoADQAAAAEAAADf/xkADQAAAAEAAADf/xsADQAAAAEAAADf/xwADQAAAAEAAADv/xwADQABAAAAAADw/xwADQABAAAAAADx/xwADQABAAAAAADy/xwADQABAAAAAADz/xwADQABAAAAAAD0/xwADQABAAAAAAD1/xwADQABAAAAAAD2/xwADQABAAAAAAD3/xwADQABAAAAAAD4/xwADQABAAAAAAD5/xwADQABAAAAAAD6/xwADQABAAAAAAD7/xwADQABAAAAAAD8/xwADQABAAEAAADh/xwADQABAAEAAADi/xwADQABAAAAAADj/xwADQABAAAAAADk/xwADQABAAAAAADl/xwADQABAAAAAADm/xwADQABAAAAAADn/xwADQABAAAAAADo/xwADQABAAAAAADr/xwADQABAAAAAADq/xwADQABAAAAAADp/xwADQABAAAAAAD8/xkADQAAAAEAAAD8/xoADQAAAAEAAAD8/xsADQAAAAEAAADh/xkADQACAAEAAADh/xoADQACAAEAAADh/xsADQACAAEAAAA=") tile_set = ExtResource("6_8xu72") script = ExtResource("4_vodlh") [node name="Shadows" type="TileMapLayer" parent="TileMapLayers" unique_id=20993245] +tile_map_data = PackedByteArray("AADv/w4AAAAAAAAAAADu/w4AAAAAAAAAAADt/w4AAAAAAAAAAADs/w4AAAAAAAAAAADr/w4AAAAAAAAAAADr/w8AAAAAAAAAAADr/xAAAAAAAAAAAADr/xEAAAAAAAAAAADr/xIAAAAAAAAAAADs/xIAAAAAAAAAAADt/xIAAAAAAAAAAADu/xIAAAAAAAAAAADv/xIAAAAAAAAAAAA=") tile_set = ExtResource("8_iu48k") [node name="Elevation" type="TileMapLayer" parent="TileMapLayers" unique_id=498357614] -tile_map_data = PackedByteArray("AADt/xIABAABAAMAAADs/xIABAABAAMAAADt/xEABAABAAIAAADr/xEABAAAAAIAAADs/xEABAABAAIAAADr/xIABAAAAAMAAADr/xAABAAAAAEAAADr/w8ABAAAAAEAAADr/w4ABAAAAAAAAADs/w4ABAABAAAAAADt/w4ABAABAAEAAADu/xIABAABAAMAAADu/xEABAABAAIAAADu/w4ABAACAAAAAADv/xIABAACAAMAAADv/xEABAACAAIAAADv/w4ABAACAAAAAAA=") -tile_set = ExtResource("8_exmm1") +tile_map_data = PackedByteArray("AADv/xEABAACAAQAAADu/xEABAABAAQAAADt/xEABAABAAQAAADs/xEABAABAAQAAADr/xEABAAAAAIAAADr/xAABAADAAEAAADr/w8ABAADAAEAAADr/w4ABAADAAEAAADr/w0ABAAAAAAAAADs/w0ABAABAAQAAADt/w0ABAABAAQAAADu/w0ABAABAAQAAADv/w0ABAACAAQAAAA=") +tile_set = ExtResource("6_g4p32") [node name="Floor2" type="TileMapLayer" parent="TileMapLayers" unique_id=672172997] tile_set = ExtResource("4_7v23v") @@ -58,9 +58,6 @@ sprite_frames = ExtResource("5_7gbyj") y_sort_enabled = true position = Vector2(-837, 1438) -[node name="HookablePin" parent="OnTheGround/NeedlesPinsB" unique_id=1043726156 instance=ExtResource("6_vodlh")] -position = Vector2(-474, 385) - [node name="HookablePin2" parent="OnTheGround/NeedlesPinsB" unique_id=21265584 instance=ExtResource("6_vodlh")] position = Vector2(135, -212) @@ -73,10 +70,6 @@ position = Vector2(21, 262) [node name="HookablePin6" parent="OnTheGround/NeedlesPinsB" unique_id=1707194744 instance=ExtResource("6_vodlh")] position = Vector2(9, -402) -[node name="Sign" parent="OnTheGround" unique_id=221941568 instance=ExtResource("8_g2ubw")] -position = Vector2(-1581, 1616) -text = "Go!" - [node name="FillGameLogic" type="Node" parent="OnTheGround" unique_id=318969364] script = ExtResource("17_b7aom") autostart = true @@ -86,18 +79,29 @@ metadata/_custom_type_script = "uid://cp54mgi54nywo" position = Vector2(-1341, 1682) motion_mode = 0 autostart = true +sprite_frames = ExtResource("13_w66m4") +idle_sound_stream = ExtResource("14_nev3j") +attack_sound_stream = ExtResource("15_4vuok") +projectile_scene = ExtResource("13_g4p32") +projectile_duration = 30.0 [node name="Target" parent="OnTheGround" unique_id=1861594411 instance=ExtResource("19_a36ca")] -position = Vector2(-1215, 1066.0001) -scale = Vector2(-2.4189885, 2.343902) -sprite_frames = ExtResource("20_11qsc") -needed_amount = 1 -label = "" -color = Color(1, 1, 1, 1) +position = Vector2(-1197, 1032) +label = "Cyan" +color = Color(0, 1, 1, 1) -[node name="ScreenOverlay" type="CanvasLayer" parent="." unique_id=1976326993] +[node name="RepelPowerup" parent="OnTheGround" unique_id=1795462717 instance=ExtResource("17_w66m4")] +position = Vector2(-307, 1622) +highlight_color = Color(0, 0, 1, 1) + +[node name="GrapplePowerup" parent="OnTheGround" unique_id=1564118198 instance=ExtResource("17_w66m4")] +position = Vector2(-307, 1770) +ability = 16 +ability_name = "Grapple" +interact_action = "Collect Grapple" +highlight_color = Color(0.8910073, 0.7227245, 0, 1) -[node name="HUD" parent="." unique_id=1267842834 instance=ExtResource("11_7v23v")] +[node name="ScreenOverlay" type="CanvasLayer" parent="." unique_id=1976326993] [node name="Camera2D" type="Camera2D" parent="." unique_id=1997394979] position = Vector2(-1111, 1490) diff --git a/scenes/game_elements/characters/player/components/unify_abilities_test_projectile.tscn b/scenes/game_elements/characters/player/components/unify_abilities_test_projectile.tscn new file mode 100644 index 000000000..916b59073 --- /dev/null +++ b/scenes/game_elements/characters/player/components/unify_abilities_test_projectile.tscn @@ -0,0 +1,59 @@ +[gd_scene format=3 uid="uid://xbgo0b3f50mw"] + +[ext_resource type="Script" uid="uid://bofv3bcwj3rx2" path="res://scenes/game_elements/props/projectile/components/projectile.gd" id="1_6uc4b"] +[ext_resource type="PackedScene" uid="uid://clgisducnnh0a" path="res://scenes/game_elements/fx/liquid_small_splat/liquid_small_splat.tscn" id="2_3cevt"] +[ext_resource type="PackedScene" uid="uid://b4qu6wml5gd7a" path="res://scenes/game_elements/fx/liquid_big_splat/liquid_big_splat.tscn" id="3_vc4n7"] +[ext_resource type="PackedScene" uid="uid://bgce3qns72g3m" path="res://scenes/game_elements/fx/liquid_trail.tscn" id="4_kxf4x"] +[ext_resource type="SpriteFrames" uid="uid://bhamin2pby7tq" path="res://scenes/game_elements/props/projectile/components/inkblob_spriteframes.tres" id="5_tb5uj"] +[ext_resource type="AudioStream" uid="uid://7jlv4wqpihl7" path="res://scenes/game_elements/props/projectile/components/blob_hit.wav" id="6_lff8h"] + +[sub_resource type="PhysicsMaterial" id="PhysicsMaterial_tbgi4"] +friction = 0.0 +bounce = 1.0 + +[sub_resource type="RectangleShape2D" id="RectangleShape2D_o6xl0"] +size = Vector2(44, 44) + +[node name="InkBlobProjectile" type="RigidBody2D" unique_id=1611529190 groups=["projectiles"]] +collision_layer = 256 +collision_mask = 80 +mass = 0.3 +physics_material_override = SubResource("PhysicsMaterial_tbgi4") +gravity_scale = 0.0 +lock_rotation = true +continuous_cd = 2 +contact_monitor = true +max_contacts_reported = 1 +script = ExtResource("1_6uc4b") +hit_speed = 40.0 +duration = 30.0 +small_fx_scene = ExtResource("2_3cevt") +big_fx_scene = ExtResource("3_vc4n7") +trail_fx_scene = ExtResource("4_kxf4x") + +[node name="CollisionShape2D" type="CollisionShape2D" parent="." unique_id=1499726276] +shape = SubResource("RectangleShape2D_o6xl0") + +[node name="VisibleThings" type="Node2D" parent="." unique_id=1129773837] +unique_name_in_owner = true +position = Vector2(-3, 0) + +[node name="AnimatedSprite2D" type="AnimatedSprite2D" parent="VisibleThings" unique_id=1816818143] +unique_name_in_owner = true +sprite_frames = ExtResource("5_tb5uj") +autoplay = "default" + +[node name="TrailFXMarker" type="Marker2D" parent="VisibleThings" unique_id=771420475] +unique_name_in_owner = true +position = Vector2(-40, 0) + +[node name="DurationTimer" type="Timer" parent="." unique_id=259732970] +unique_name_in_owner = true + +[node name="HitSound" type="AudioStreamPlayer2D" parent="." unique_id=1862098516] +unique_name_in_owner = true +stream = ExtResource("6_lff8h") +bus = &"SFX" + +[connection signal="body_entered" from="." to="." method="_on_body_entered"] +[connection signal="timeout" from="DurationTimer" to="." method="_on_duration_timer_timeout"] From 7f1c2455e14757d6ef9723451c11f246294b0c89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Qui=C3=B1ones?= Date: Thu, 26 Mar 2026 09:46:52 -0300 Subject: [PATCH 06/12] fixup! unify_abilities_test: Add powerups and improve test level --- .../characters/player/components/unify_abilities_test.tscn | 1 - 1 file changed, 1 deletion(-) diff --git a/scenes/game_elements/characters/player/components/unify_abilities_test.tscn b/scenes/game_elements/characters/player/components/unify_abilities_test.tscn index 8e164e679..8460487d8 100644 --- a/scenes/game_elements/characters/player/components/unify_abilities_test.tscn +++ b/scenes/game_elements/characters/player/components/unify_abilities_test.tscn @@ -77,7 +77,6 @@ metadata/_custom_type_script = "uid://cp54mgi54nywo" [node name="ThrowingNPC" parent="OnTheGround" unique_id=1243855514 instance=ExtResource("18_iu48k")] position = Vector2(-1341, 1682) -motion_mode = 0 autostart = true sprite_frames = ExtResource("13_w66m4") idle_sound_stream = ExtResource("14_nev3j") From 55220c91ebcf070fe824fd604355ec13ade0b024 Mon Sep 17 00:00:00 2001 From: Will Thompson Date: Fri, 27 Mar 2026 10:51:29 +0000 Subject: [PATCH 07/12] fixup! Add powerup for abilities --- scenes/game_elements/props/powerup/powerup.tscn | 1 + 1 file changed, 1 insertion(+) diff --git a/scenes/game_elements/props/powerup/powerup.tscn b/scenes/game_elements/props/powerup/powerup.tscn index 35205f63b..7548f7a0e 100644 --- a/scenes/game_elements/props/powerup/powerup.tscn +++ b/scenes/game_elements/props/powerup/powerup.tscn @@ -25,6 +25,7 @@ radius = 16.0 height = 68.0 [sub_resource type="ShaderMaterial" id="ShaderMaterial_spw1e"] +resource_local_to_scene = true shader = ExtResource("4_vllb8") shader_parameter/ease = 2.0 shader_parameter/modulo_width = 0.2 From 676f3daadf6977c594db9214d3aa33b0df918006 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Qui=C3=B1ones?= Date: Fri, 27 Mar 2026 11:15:46 -0300 Subject: [PATCH 08/12] fixup! Use powerup in lore and template quests --- .../lore_quests/quest_002/2_grappling_hook/intro_start.dialogue | 1 - 1 file changed, 1 deletion(-) diff --git a/scenes/quests/lore_quests/quest_002/2_grappling_hook/intro_start.dialogue b/scenes/quests/lore_quests/quest_002/2_grappling_hook/intro_start.dialogue index dc7be6821..3332b26d4 100644 --- a/scenes/quests/lore_quests/quest_002/2_grappling_hook/intro_start.dialogue +++ b/scenes/quests/lore_quests/quest_002/2_grappling_hook/intro_start.dialogue @@ -6,5 +6,4 @@ do animation_player.play(&"eat_floor") do animation_player.animation_finished Moss the Monk: Oh, look! The Void is blooming fast here. Moss the Monk: You’ll need a [b]grappling hook[/b] to get to LinenVille. Take mine. -do GameState.set_ability(Enums.PlayerAbilities.ABILITY_B, true) => END From a6a64624e504d9df5759cc53ed92bb73ccc8ce79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Qui=C3=B1ones?= Date: Fri, 27 Mar 2026 11:19:57 -0300 Subject: [PATCH 09/12] Make Repel powerup highlight lighter --- .../characters/player/components/unify_abilities_test.tscn | 2 +- .../lore_quests/quest_001/2_ink_combat/ink_combat_round_1.tscn | 2 +- .../NO_EDIT/2_NO_EDIT_combat/NO_EDIT_combat.tscn | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/scenes/game_elements/characters/player/components/unify_abilities_test.tscn b/scenes/game_elements/characters/player/components/unify_abilities_test.tscn index 8460487d8..7f0b0cb2d 100644 --- a/scenes/game_elements/characters/player/components/unify_abilities_test.tscn +++ b/scenes/game_elements/characters/player/components/unify_abilities_test.tscn @@ -91,7 +91,7 @@ color = Color(0, 1, 1, 1) [node name="RepelPowerup" parent="OnTheGround" unique_id=1795462717 instance=ExtResource("17_w66m4")] position = Vector2(-307, 1622) -highlight_color = Color(0, 0, 1, 1) +highlight_color = Color(0, 0.4392157, 1, 1) [node name="GrapplePowerup" parent="OnTheGround" unique_id=1564118198 instance=ExtResource("17_w66m4")] position = Vector2(-307, 1770) diff --git a/scenes/quests/lore_quests/quest_001/2_ink_combat/ink_combat_round_1.tscn b/scenes/quests/lore_quests/quest_001/2_ink_combat/ink_combat_round_1.tscn index 4d58765e0..3eeabd7c2 100644 --- a/scenes/quests/lore_quests/quest_001/2_ink_combat/ink_combat_round_1.tscn +++ b/scenes/quests/lore_quests/quest_001/2_ink_combat/ink_combat_round_1.tscn @@ -214,7 +214,7 @@ scale = Vector2(0.95, 0.95) [node name="RepelPowerup" parent="OnTheGround" unique_id=1795462717 instance=ExtResource("26_a4lwd")] position = Vector2(236, 428) -highlight_color = Color(0, 0, 1, 1) +highlight_color = Color(0, 0.4392157, 1, 1) [node name="ScreenOverlay" type="CanvasLayer" parent="." unique_id=127644403] diff --git a/scenes/quests/template_quests/NO_EDIT/2_NO_EDIT_combat/NO_EDIT_combat.tscn b/scenes/quests/template_quests/NO_EDIT/2_NO_EDIT_combat/NO_EDIT_combat.tscn index 7554ce328..645239fbf 100644 --- a/scenes/quests/template_quests/NO_EDIT/2_NO_EDIT_combat/NO_EDIT_combat.tscn +++ b/scenes/quests/template_quests/NO_EDIT/2_NO_EDIT_combat/NO_EDIT_combat.tscn @@ -108,7 +108,7 @@ dialogue_title = &"well_done" [node name="RepelPowerup" parent="OnTheGround" unique_id=1795462717 instance=ExtResource("14_6xf5p")] position = Vector2(114, 488) -highlight_color = Color(0, 0, 1, 1) +highlight_color = Color(0, 0.4392157, 1, 1) [node name="ScreenOverlay" type="CanvasLayer" parent="." unique_id=1277924950] From 0ed1ec0279cc9a168698186e9fda47c3a6b16a42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Qui=C3=B1ones?= Date: Fri, 27 Mar 2026 11:45:31 -0300 Subject: [PATCH 10/12] Make powerup hookable Change it to a CharacterBody2D and add a HookableArea. --- .../props/powerup/components/powerup.gd | 4 +- .../game_elements/props/powerup/powerup.tscn | 47 ++++++++++++++----- .../grappling_hook_powerup.tscn | 2 +- 3 files changed, 38 insertions(+), 15 deletions(-) diff --git a/scenes/game_elements/props/powerup/components/powerup.gd b/scenes/game_elements/props/powerup/components/powerup.gd index 85aa79952..45440dccc 100644 --- a/scenes/game_elements/props/powerup/components/powerup.gd +++ b/scenes/game_elements/props/powerup/components/powerup.gd @@ -1,7 +1,7 @@ # SPDX-FileCopyrightText: The Threadbare Authors # SPDX-License-Identifier: MPL-2.0 @tool -extends Node2D +extends CharacterBody2D ## A powerup that, when interacted, enables a player ability. ## ## By default it also displays a dialogue telling the player that an ability @@ -38,6 +38,7 @@ var _tween: Tween @onready var sprite: AnimatedSprite2D = %Sprite @onready var interact_collision: CollisionShape2D = %InteractCollision @onready var ground_collision: CollisionShape2D = %GroundCollision +@onready var hookable_collision: CollisionShape2D = %HookableCollision func _set_interact_action(new_interact_action: String) -> void: @@ -81,6 +82,7 @@ func _on_abilities_changed() -> void: var has_ability := GameState.has_ability(ability) ground_collision.disabled = has_ability interact_collision.disabled = has_ability + hookable_collision.disabled = has_ability highlight_effect.visible = not has_ability var alpha: float = 0.5 if has_ability else 1.0 sprite.modulate = Color(Color.WHITE, alpha) diff --git a/scenes/game_elements/props/powerup/powerup.tscn b/scenes/game_elements/props/powerup/powerup.tscn index 7548f7a0e..ee465a633 100644 --- a/scenes/game_elements/props/powerup/powerup.tscn +++ b/scenes/game_elements/props/powerup/powerup.tscn @@ -5,6 +5,7 @@ [ext_resource type="Script" uid="uid://du8wfijr35r35" path="res://scenes/game_elements/props/interact_area/interact_area.gd" id="2_q7xhf"] [ext_resource type="Texture2D" uid="uid://bbo1nd3usbxnr" path="res://scenes/game_elements/props/powerup/components/powerup_highlight.png" id="4_bq5to"] [ext_resource type="Shader" uid="uid://v56tvdvw22lj" path="res://scenes/game_elements/props/powerup/components/ripple_effect.gdshader" id="4_vllb8"] +[ext_resource type="Script" uid="uid://dabvr3pqmyya4" path="res://scenes/game_elements/props/hookable_area/components/hookable_area.gd" id="6_spw1e"] [sub_resource type="SpriteFrames" id="SpriteFrames_bq5to"] animations = [{ @@ -17,13 +18,13 @@ animations = [{ "speed": 10.0 }] -[sub_resource type="CircleShape2D" id="CircleShape2D_5vrqc"] -radius = 50.0 - [sub_resource type="CapsuleShape2D" id="CapsuleShape2D_bq5to"] radius = 16.0 height = 68.0 +[sub_resource type="CircleShape2D" id="CircleShape2D_5vrqc"] +radius = 50.0 + [sub_resource type="ShaderMaterial" id="ShaderMaterial_spw1e"] resource_local_to_scene = true shader = ExtResource("4_vllb8") @@ -32,12 +33,23 @@ shader_parameter/modulo_width = 0.2 shader_parameter/width = 0.4 shader_parameter/speed = 0.2 -[node name="Powerup" type="Node2D" unique_id=1795462717] +[sub_resource type="RectangleShape2D" id="RectangleShape2D_spw1e"] +size = Vector2(90, 90) + +[node name="Powerup" type="CharacterBody2D" unique_id=297202740] +collision_layer = 512 +collision_mask = 0 script = ExtResource("1_5vrqc") ability_name = "Repel" interact_action = "Collect Repel" sprite_frames = SubResource("SpriteFrames_bq5to") +[node name="GroundCollision" type="CollisionShape2D" parent="." unique_id=1403567890] +unique_name_in_owner = true +rotation = -1.5707964 +shape = SubResource("CapsuleShape2D_bq5to") +debug_color = Color(0.976711, 0, 0.409753, 0.42) + [node name="InteractArea" type="Area2D" parent="." unique_id=1443651205] unique_name_in_owner = true collision_layer = 32 @@ -52,15 +64,6 @@ position = Vector2(0, -33) shape = SubResource("CircleShape2D_5vrqc") debug_color = Color(0.600391, 0.54335, 0, 0.42) -[node name="StaticBody2D" type="StaticBody2D" parent="." unique_id=21266648] -collision_mask = 0 - -[node name="GroundCollision" type="CollisionShape2D" parent="StaticBody2D" unique_id=1403567890] -unique_name_in_owner = true -rotation = -1.5707964 -shape = SubResource("CapsuleShape2D_bq5to") -debug_color = Color(0.976711, 0, 0.409753, 0.42) - [node name="HighlightEffect" type="Sprite2D" parent="." unique_id=1449487876] unique_name_in_owner = true visible = false @@ -74,5 +77,23 @@ position = Vector2(0, -34) sprite_frames = SubResource("SpriteFrames_bq5to") autoplay = "default" +[node name="HookableArea" type="Area2D" parent="." unique_id=1984587489 node_paths=PackedStringArray("controlled_entity", "anchor_point")] +collision_layer = 4096 +collision_mask = 0 +script = ExtResource("6_spw1e") +controlled_entity = NodePath("..") +anchor_point = NodePath("Marker2D") +weight = 0.1 +metadata/_custom_type_script = "uid://dabvr3pqmyya4" + +[node name="HookableCollision" type="CollisionShape2D" parent="HookableArea" unique_id=567802370] +unique_name_in_owner = true +position = Vector2(0, -33) +shape = SubResource("RectangleShape2D_spw1e") +debug_color = Color(0.689707, 0.288376, 1, 0.42) + +[node name="Marker2D" type="Marker2D" parent="HookableArea" unique_id=1698747164] +position = Vector2(0, -33) + [connection signal="interaction_started" from="InteractArea" to="." method="_on_interact_area_interaction_started" flags=18] [connection signal="observers_changed" from="InteractArea" to="." method="_on_interact_area_observers_changed"] diff --git a/scenes/quests/lore_quests/quest_002/2_grappling_hook/grappling_hook_powerup.tscn b/scenes/quests/lore_quests/quest_002/2_grappling_hook/grappling_hook_powerup.tscn index ea92780b0..bd3291248 100644 --- a/scenes/quests/lore_quests/quest_002/2_grappling_hook/grappling_hook_powerup.tscn +++ b/scenes/quests/lore_quests/quest_002/2_grappling_hook/grappling_hook_powerup.tscn @@ -222,7 +222,7 @@ position = Vector2(-1581, 1616) text = "Go!" [node name="LongerThreadPowerup" parent="OnTheGround" unique_id=1795462717 instance=ExtResource("17_a36ca")] -position = Vector2(-549, 805) +position = Vector2(-549, 689) ability = 32 ability_name = "Longer Thread" interact_action = "Collect Longer Thread" From fbedc1009a5cdff73daccb0d6c29504bcb383894 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Qui=C3=B1ones?= Date: Fri, 27 Mar 2026 11:49:43 -0300 Subject: [PATCH 11/12] void_grappling_round_2: Use powerup --- .../components/void_grapping_round_2.gd | 4 +- .../void_grappling_round_2.tscn | 56 +++---------------- 2 files changed, 8 insertions(+), 52 deletions(-) diff --git a/scenes/quests/lore_quests/quest_002/3_void_grappling/components/void_grapping_round_2.gd b/scenes/quests/lore_quests/quest_002/3_void_grappling/components/void_grapping_round_2.gd index 971327e28..4fc47378f 100644 --- a/scenes/quests/lore_quests/quest_002/3_void_grappling/components/void_grapping_round_2.gd +++ b/scenes/quests/lore_quests/quest_002/3_void_grappling/components/void_grapping_round_2.gd @@ -6,9 +6,7 @@ extends Node2D @onready var void_chasing: CharacterBody2D = %VoidChasing -func _on_button_item_collected() -> void: - GameState.set_ability(Enums.PlayerAbilities.ABILITY_B_MODIFIER_1, true) - +func _on_longer_thread_powerup_collected() -> void: # Zoom out the camera when collecting the powerup, because now the player # can throw a longer thread: var camera: Camera2D = get_viewport().get_camera_2d() diff --git a/scenes/quests/lore_quests/quest_002/3_void_grappling/void_grappling_round_2.tscn b/scenes/quests/lore_quests/quest_002/3_void_grappling/void_grappling_round_2.tscn index 33a1cd132..c110734de 100644 --- a/scenes/quests/lore_quests/quest_002/3_void_grappling/void_grappling_round_2.tscn +++ b/scenes/quests/lore_quests/quest_002/3_void_grappling/void_grappling_round_2.tscn @@ -15,8 +15,7 @@ [ext_resource type="PackedScene" uid="uid://dohb701lxbe5s" path="res://scenes/game_elements/props/hookable_needle/hookable_needle.tscn" id="13_6fnam"] [ext_resource type="Script" uid="uid://dagrhfrj0f33i" path="res://scenes/game_logic/camera_behaviors/frame_camera_behavior.gd" id="13_xwjev"] [ext_resource type="PackedScene" uid="uid://evb46lm6ssu2" path="res://scenes/game_elements/props/hookable_pin/hookable_pin.tscn" id="14_4tdqi"] -[ext_resource type="PackedScene" uid="uid://dvj15pnuqr2ua" path="res://scenes/game_elements/props/hookable_button_item/hookable_button_item.tscn" id="14_lmmn3"] -[ext_resource type="Texture2D" uid="uid://dnwfhdpvdl0gi" path="res://scenes/game_elements/props/button_item/components/button-blue.png" id="15_johb0"] +[ext_resource type="PackedScene" uid="uid://dmevaymmt6wco" path="res://scenes/game_elements/props/powerup/powerup.tscn" id="16_bkul7"] [ext_resource type="PackedScene" uid="uid://dv4f232y8w8dv" path="res://scenes/game_elements/props/decoration/water_rock/water_rock.tscn" id="20_q1v2m"] [ext_resource type="PackedScene" uid="uid://7873qa54birk" path="res://scenes/game_elements/props/tree/tree.tscn" id="21_gvlvr"] [ext_resource type="SpriteFrames" uid="uid://2ek86nvw6y28" path="res://scenes/game_elements/props/tree/components/tree_spriteframes_yellow.tres" id="22_siwq5"] @@ -74,42 +73,6 @@ _data = { } point_count = 5 -[sub_resource type="AtlasTexture" id="AtlasTexture_rup4f"] -atlas = ExtResource("15_johb0") -region = Rect2(0, 0, 64, 64) - -[sub_resource type="AtlasTexture" id="AtlasTexture_ptg16"] -atlas = ExtResource("15_johb0") -region = Rect2(64, 0, 64, 64) - -[sub_resource type="AtlasTexture" id="AtlasTexture_vodlh"] -atlas = ExtResource("15_johb0") -region = Rect2(128, 0, 64, 64) - -[sub_resource type="AtlasTexture" id="AtlasTexture_rlnni"] -atlas = ExtResource("15_johb0") -region = Rect2(192, 0, 64, 64) - -[sub_resource type="SpriteFrames" id="SpriteFrames_vbdam"] -animations = [{ -"frames": [{ -"duration": 1.0, -"texture": SubResource("AtlasTexture_rup4f") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_ptg16") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_vodlh") -}, { -"duration": 1.0, -"texture": SubResource("AtlasTexture_rlnni") -}], -"loop": true, -"name": &"default", -"speed": 10.0 -}] - [sub_resource type="NavigationPolygon" id="NavigationPolygon_c2723"] vertices = PackedVector2Array(2921.961, 2408.0469, 2928.9375, 3614.9766, -1572.9609, 3609.0078, -1559.0313, 112, 3734.039, 116.99219, 3742.961, 2105.039) polygons = Array[PackedInt32Array]([PackedInt32Array(0, 1, 2, 3), PackedInt32Array(0, 3, 4, 5)]) @@ -246,15 +209,12 @@ scale = Vector2(2.219653, 2.219653) curve = SubResource("Curve2D_nm3ku") metadata/_edit_group_ = true -[node name="LongerStringPowerUp" parent="OnTheGround" unique_id=1151446514 instance=ExtResource("14_lmmn3")] +[node name="LongerThreadPowerup" parent="OnTheGround" unique_id=297202740 instance=ExtResource("16_bkul7")] position = Vector2(2048, 576) -scale = Vector2(2, 2) - -[node name="ButtonSprite" parent="OnTheGround/LongerStringPowerUp/ButtonItem" parent_id_path=PackedInt32Array(1151446514, 1967107361) index="0" unique_id=1194360136] -sprite_frames = SubResource("SpriteFrames_vbdam") - -[node name="HookableArea" parent="OnTheGround/LongerStringPowerUp" index="2" unique_id=1267513436] -weight = 0.3 +ability = 32 +ability_name = "Longer Thread" +interact_action = "Collect Longer Thread" +highlight_color = Color(0.8910073, 0.7227245, 0, 1) [node name="PinsAndNeedles" type="Node2D" parent="OnTheGround" unique_id=478811176] y_sort_enabled = true @@ -687,9 +647,7 @@ position = Vector2(0, 23) shape = SubResource("RectangleShape2D_rk3po") [connection signal="body_entered" from="EnemyDefeatTrigger" to="OnTheGround/VoidChasing" method="defeat" unbinds=1] -[connection signal="collected" from="OnTheGround/LongerStringPowerUp/ButtonItem" to="." method="_on_button_item_collected"] +[connection signal="collected" from="OnTheGround/LongerThreadPowerup" to="." method="_on_longer_thread_powerup_collected"] [editable path="OnTheGround/VoidPatrolling"] [editable path="OnTheGround/VoidChasing"] -[editable path="OnTheGround/LongerStringPowerUp"] -[editable path="OnTheGround/LongerStringPowerUp/ButtonItem"] From b7d88cb7c2686d586cc9e8dfcfb73d14dfe4a464 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Qui=C3=B1ones?= Date: Fri, 27 Mar 2026 13:29:16 -0300 Subject: [PATCH 12/12] fixup! void_grappling_round_2: Use powerup --- .../components/grappling_hook_powerup.gd | 21 +++++++++++---- .../grappling_hook_powerup.tscn | 2 -- .../components/void_grapping_round_2.gd | 27 +++++++++++++++---- 3 files changed, 38 insertions(+), 12 deletions(-) diff --git a/scenes/quests/lore_quests/quest_002/2_grappling_hook/components/grappling_hook_powerup.gd b/scenes/quests/lore_quests/quest_002/2_grappling_hook/components/grappling_hook_powerup.gd index e9c849eaf..0bc9debd2 100644 --- a/scenes/quests/lore_quests/quest_002/2_grappling_hook/components/grappling_hook_powerup.gd +++ b/scenes/quests/lore_quests/quest_002/2_grappling_hook/components/grappling_hook_powerup.gd @@ -2,10 +2,21 @@ # SPDX-License-Identifier: MPL-2.0 extends Node2D +var zoom_tween: Tween -func _on_longer_thread_powerup_collected() -> void: - # Zoom out the camera when collecting the powerup, because now the player - # can throw a longer thread: + +func _ready() -> void: + GameState.abilities_changed.connect(_on_abilities_changed) + _on_abilities_changed() + + +func _on_abilities_changed() -> void: + var has_longer_thread := GameState.has_ability(Enums.PlayerAbilities.ABILITY_B_MODIFIER_1) + var camera_zoom := Vector2(0.5, 0.5) if has_longer_thread else Vector2(1.0, 1.0) + # Zoom out when the player can throw a longer thread: var camera: Camera2D = get_viewport().get_camera_2d() - var zoom_tween := create_tween() - zoom_tween.tween_property(camera, "zoom", Vector2(0.8, 0.8), 1.0) + if camera.zoom != camera_zoom: + if zoom_tween: + zoom_tween.kill() + zoom_tween = create_tween() + zoom_tween.tween_property(camera, "zoom", camera_zoom, 1.0) diff --git a/scenes/quests/lore_quests/quest_002/2_grappling_hook/grappling_hook_powerup.tscn b/scenes/quests/lore_quests/quest_002/2_grappling_hook/grappling_hook_powerup.tscn index bd3291248..5598c2ed4 100644 --- a/scenes/quests/lore_quests/quest_002/2_grappling_hook/grappling_hook_powerup.tscn +++ b/scenes/quests/lore_quests/quest_002/2_grappling_hook/grappling_hook_powerup.tscn @@ -360,6 +360,4 @@ shape = SubResource("RectangleShape2D_s7yva") [node name="HUD" parent="." unique_id=1267842834 instance=ExtResource("11_7v23v")] -[connection signal="collected" from="OnTheGround/LongerThreadPowerup" to="." method="_on_longer_thread_powerup_collected"] - [editable path="OnTheGround/VoidPatrolling"] diff --git a/scenes/quests/lore_quests/quest_002/3_void_grappling/components/void_grapping_round_2.gd b/scenes/quests/lore_quests/quest_002/3_void_grappling/components/void_grapping_round_2.gd index 4fc47378f..9d77960b1 100644 --- a/scenes/quests/lore_quests/quest_002/3_void_grappling/components/void_grapping_round_2.gd +++ b/scenes/quests/lore_quests/quest_002/3_void_grappling/components/void_grapping_round_2.gd @@ -2,14 +2,31 @@ # SPDX-License-Identifier: MPL-2.0 extends Node2D +var zoom_tween: Tween + @onready var player: Player = %Player @onready var void_chasing: CharacterBody2D = %VoidChasing -func _on_longer_thread_powerup_collected() -> void: - # Zoom out the camera when collecting the powerup, because now the player - # can throw a longer thread: +func _ready() -> void: + GameState.abilities_changed.connect(_on_abilities_changed) + + # TODO: This level removes the longer thread modifier when started. + # Otherwise the Void chase can't be triggered. + GameState.set_ability(Enums.PlayerAbilities.ABILITY_B_MODIFIER_1, false) + + +func _on_abilities_changed() -> void: + var has_longer_thread := GameState.has_ability(Enums.PlayerAbilities.ABILITY_B_MODIFIER_1) + var camera_zoom := Vector2(0.5, 0.5) if has_longer_thread else Vector2(1.0, 1.0) + # Zoom out when the player can throw a longer thread: var camera: Camera2D = get_viewport().get_camera_2d() - var zoom_tween := create_tween() - zoom_tween.tween_property(camera, "zoom", Vector2(0.5, 0.5), 1.0) + if camera.zoom != camera_zoom: + if zoom_tween: + zoom_tween.kill() + zoom_tween = create_tween() + zoom_tween.tween_property(camera, "zoom", camera_zoom, 1.0) + + +func _on_longer_thread_powerup_collected() -> void: void_chasing.start(player)