feat: completing tutorial
This commit is contained in:
+1
-1
@@ -8,7 +8,7 @@ custom_features=""
|
|||||||
export_filter="all_resources"
|
export_filter="all_resources"
|
||||||
include_filter=""
|
include_filter=""
|
||||||
exclude_filter=""
|
exclude_filter=""
|
||||||
export_path="build/tekton_armageddon_v2.1.2.exe"
|
export_path="build/tekton_armageddon_v2.1.3.exe"
|
||||||
patches=PackedStringArray()
|
patches=PackedStringArray()
|
||||||
patch_delta_encoding=false
|
patch_delta_encoding=false
|
||||||
patch_delta_compression_level_zstd=19
|
patch_delta_compression_level_zstd=19
|
||||||
|
|||||||
+2
-1
@@ -1156,6 +1156,7 @@ text = "NOT CONNECTED"
|
|||||||
horizontal_alignment = 1
|
horizontal_alignment = 1
|
||||||
|
|
||||||
[node name="VersionLabel" type="Label" parent="." unique_id=351711152]
|
[node name="VersionLabel" type="Label" parent="." unique_id=351711152]
|
||||||
|
visible = false
|
||||||
layout_mode = 1
|
layout_mode = 1
|
||||||
anchors_preset = 3
|
anchors_preset = 3
|
||||||
anchor_left = 1.0
|
anchor_left = 1.0
|
||||||
@@ -1170,5 +1171,5 @@ grow_horizontal = 0
|
|||||||
grow_vertical = 0
|
grow_vertical = 0
|
||||||
theme_override_colors/font_color = Color(0.6, 0.6, 0.6, 0.6)
|
theme_override_colors/font_color = Color(0.6, 0.6, 0.6, 0.6)
|
||||||
theme_override_font_sizes/font_size = 11
|
theme_override_font_sizes/font_size = 11
|
||||||
text = "v0.1.0 ALPHA"
|
text = "v.2.1.3"
|
||||||
horizontal_alignment = 2
|
horizontal_alignment = 2
|
||||||
|
|||||||
+6
-2
@@ -1727,7 +1727,7 @@ expand_icon = true
|
|||||||
|
|
||||||
[node name="PauseMenu" type="CanvasLayer" parent="." unique_id=181131829]
|
[node name="PauseMenu" type="CanvasLayer" parent="." unique_id=181131829]
|
||||||
process_mode = 3
|
process_mode = 3
|
||||||
layer = 10
|
layer = 1002
|
||||||
visible = false
|
visible = false
|
||||||
|
|
||||||
[node name="Background" type="ColorRect" parent="PauseMenu" unique_id=412985431]
|
[node name="Background" type="ColorRect" parent="PauseMenu" unique_id=412985431]
|
||||||
@@ -2007,9 +2007,11 @@ layout_mode = 2
|
|||||||
text = "Back"
|
text = "Back"
|
||||||
|
|
||||||
[node name="TopMenuUI" type="CanvasLayer" parent="." unique_id=1234567890]
|
[node name="TopMenuUI" type="CanvasLayer" parent="." unique_id=1234567890]
|
||||||
layer = 2
|
layer = 102
|
||||||
|
|
||||||
[node name="HelpBtn" type="Button" parent="TopMenuUI" unique_id=833886895]
|
[node name="HelpBtn" type="Button" parent="TopMenuUI" unique_id=833886895]
|
||||||
|
top_level = true
|
||||||
|
z_index = 2000
|
||||||
anchors_preset = 1
|
anchors_preset = 1
|
||||||
anchor_left = 1.0
|
anchor_left = 1.0
|
||||||
anchor_right = 1.0
|
anchor_right = 1.0
|
||||||
@@ -2024,6 +2026,8 @@ icon = ExtResource("37_pibwh")
|
|||||||
flat = true
|
flat = true
|
||||||
|
|
||||||
[node name="SettingsBtn" type="Button" parent="TopMenuUI" unique_id=1964422444]
|
[node name="SettingsBtn" type="Button" parent="TopMenuUI" unique_id=1964422444]
|
||||||
|
top_level = true
|
||||||
|
z_index = 2000
|
||||||
anchors_preset = 1
|
anchors_preset = 1
|
||||||
anchor_left = 1.0
|
anchor_left = 1.0
|
||||||
anchor_right = 1.0
|
anchor_right = 1.0
|
||||||
|
|||||||
@@ -68,6 +68,9 @@ shape = SubResource("SphereShape3D_3oo5r")
|
|||||||
[node name="Name" type="Label3D" parent="." unique_id=848046946]
|
[node name="Name" type="Label3D" parent="." unique_id=848046946]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.0281162, 0)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.0281162, 0)
|
||||||
billboard = 1
|
billboard = 1
|
||||||
|
no_depth_test = true
|
||||||
|
render_priority = 2
|
||||||
|
outline_render_priority = 1
|
||||||
text = "username"
|
text = "username"
|
||||||
font = ExtResource("8_y4r1p")
|
font = ExtResource("8_y4r1p")
|
||||||
font_size = 48
|
font_size = 48
|
||||||
@@ -78,6 +81,9 @@ autowrap_mode = 2
|
|||||||
[node name="Position" type="Label3D" parent="." unique_id=482425681]
|
[node name="Position" type="Label3D" parent="." unique_id=482425681]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.537, 0)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.537, 0)
|
||||||
billboard = 1
|
billboard = 1
|
||||||
|
no_depth_test = true
|
||||||
|
render_priority = 2
|
||||||
|
outline_render_priority = 1
|
||||||
modulate = Color(0.32, 0.614667, 1, 1)
|
modulate = Color(0.32, 0.614667, 1, 1)
|
||||||
text = "1st"
|
text = "1st"
|
||||||
font = ExtResource("8_y4r1p")
|
font = ExtResource("8_y4r1p")
|
||||||
@@ -114,6 +120,7 @@ script = ExtResource("7_botctrl")
|
|||||||
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, -1, 0, 1, -4.371139e-08, 0, 1.5653763, 0)
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, -1, 0, 1, -4.371139e-08, 0, 1.5653763, 0)
|
||||||
visible = false
|
visible = false
|
||||||
billboard = 1
|
billboard = 1
|
||||||
|
render_priority = 3
|
||||||
sprite_frames = ExtResource("10_y4r1p")
|
sprite_frames = ExtResource("10_y4r1p")
|
||||||
animation = &"freeze-initiator"
|
animation = &"freeze-initiator"
|
||||||
frame = 149
|
frame = 149
|
||||||
@@ -123,6 +130,7 @@ frame_progress = 1.0
|
|||||||
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, -1, 0, 1, -4.371139e-08, 0, 1.5653763, 0)
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, -1, 0, 1, -4.371139e-08, 0, 1.5653763, 0)
|
||||||
visible = false
|
visible = false
|
||||||
billboard = 1
|
billboard = 1
|
||||||
|
render_priority = 3
|
||||||
sprite_frames = ExtResource("10_y4r1p")
|
sprite_frames = ExtResource("10_y4r1p")
|
||||||
animation = &"ghost-initiator"
|
animation = &"ghost-initiator"
|
||||||
frame = 149
|
frame = 149
|
||||||
@@ -132,6 +140,7 @@ frame_progress = 1.0
|
|||||||
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, -1, 0, 1, -4.371139e-08, 0, 1.5653763, 0)
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, -1, 0, 1, -4.371139e-08, 0, 1.5653763, 0)
|
||||||
visible = false
|
visible = false
|
||||||
billboard = 1
|
billboard = 1
|
||||||
|
render_priority = 3
|
||||||
sprite_frames = ExtResource("10_y4r1p")
|
sprite_frames = ExtResource("10_y4r1p")
|
||||||
animation = &"speed-initator"
|
animation = &"speed-initator"
|
||||||
frame = 149
|
frame = 149
|
||||||
@@ -141,6 +150,7 @@ frame_progress = 1.0
|
|||||||
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, -1, 0, 1, -4.371139e-08, 0, 1.5653763, 0)
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, -1, 0, 1, -4.371139e-08, 0, 1.5653763, 0)
|
||||||
visible = false
|
visible = false
|
||||||
billboard = 1
|
billboard = 1
|
||||||
|
render_priority = 3
|
||||||
sprite_frames = ExtResource("10_y4r1p")
|
sprite_frames = ExtResource("10_y4r1p")
|
||||||
animation = &"wall-initiator"
|
animation = &"wall-initiator"
|
||||||
|
|
||||||
@@ -148,6 +158,7 @@ animation = &"wall-initiator"
|
|||||||
transform = Transform3D(0.5, 0, 0, 0, 0.5, 1.509958e-07, 0, -1.509958e-07, 0.5, 0, 1.5475016, 0.012766336)
|
transform = Transform3D(0.5, 0, 0, 0, 0.5, 1.509958e-07, 0, -1.509958e-07, 0.5, 0, 1.5475016, 0.012766336)
|
||||||
visible = false
|
visible = false
|
||||||
billboard = 1
|
billboard = 1
|
||||||
|
render_priority = 3
|
||||||
sprite_frames = ExtResource("10_y4r1p")
|
sprite_frames = ExtResource("10_y4r1p")
|
||||||
animation = &"scatter_knock"
|
animation = &"scatter_knock"
|
||||||
frame = 59
|
frame = 59
|
||||||
@@ -157,6 +168,7 @@ frame_progress = 1.0
|
|||||||
transform = Transform3D(0.5, 0, 0, 0, -0.5, -7.54979e-08, 0, 7.54979e-08, -0.5, 0, 1.4714267, 0.02553294)
|
transform = Transform3D(0.5, 0, 0, 0, -0.5, -7.54979e-08, 0, 7.54979e-08, -0.5, 0, 1.4714267, 0.02553294)
|
||||||
visible = false
|
visible = false
|
||||||
billboard = 1
|
billboard = 1
|
||||||
|
render_priority = 3
|
||||||
sprite_frames = ExtResource("10_y4r1p")
|
sprite_frames = ExtResource("10_y4r1p")
|
||||||
animation = &"floor_spawn_top"
|
animation = &"floor_spawn_top"
|
||||||
frame = 23
|
frame = 23
|
||||||
@@ -165,6 +177,7 @@ frame_progress = 1.0
|
|||||||
[node name="floor_spawn_bot" type="AnimatedSprite3D" parent="." unique_id=169253263]
|
[node name="floor_spawn_bot" type="AnimatedSprite3D" parent="." unique_id=169253263]
|
||||||
transform = Transform3D(1.2, 0, 0, 0, -5.2453668e-08, -1.2, 0, 1.2, -5.2453668e-08, 0, -0.506722, -4.4299043e-08)
|
transform = Transform3D(1.2, 0, 0, 0, -5.2453668e-08, -1.2, 0, 1.2, -5.2453668e-08, 0, -0.506722, -4.4299043e-08)
|
||||||
visible = false
|
visible = false
|
||||||
|
render_priority = 3
|
||||||
sprite_frames = ExtResource("10_y4r1p")
|
sprite_frames = ExtResource("10_y4r1p")
|
||||||
animation = &"floor_spawn_bot"
|
animation = &"floor_spawn_bot"
|
||||||
frame = 35
|
frame = 35
|
||||||
@@ -174,6 +187,7 @@ frame_progress = 1.0
|
|||||||
transform = Transform3D(0.5, 0, 0, 0, -2.1855694e-08, -0.5, 0, 0.5, -2.1855694e-08, 0, 1.5653763, 0)
|
transform = Transform3D(0.5, 0, 0, 0, -2.1855694e-08, -0.5, 0, 0.5, -2.1855694e-08, 0, 1.5653763, 0)
|
||||||
visible = false
|
visible = false
|
||||||
billboard = 1
|
billboard = 1
|
||||||
|
render_priority = 3
|
||||||
sprite_frames = ExtResource("10_y4r1p")
|
sprite_frames = ExtResource("10_y4r1p")
|
||||||
animation = &"stunned-receiver"
|
animation = &"stunned-receiver"
|
||||||
frame = 59
|
frame = 59
|
||||||
@@ -182,12 +196,14 @@ frame_progress = 1.0
|
|||||||
[node name="attack_mode_top" type="AnimatedSprite3D" parent="." unique_id=2002706555]
|
[node name="attack_mode_top" type="AnimatedSprite3D" parent="." unique_id=2002706555]
|
||||||
transform = Transform3D(0.5, 0, 0, 0, -2.1855694e-08, -0.5, 0, 0.5, -2.1855694e-08, 0, 1.5653763, 0)
|
transform = Transform3D(0.5, 0, 0, 0, -2.1855694e-08, -0.5, 0, 0.5, -2.1855694e-08, 0, 1.5653763, 0)
|
||||||
visible = false
|
visible = false
|
||||||
|
render_priority = 3
|
||||||
sprite_frames = ExtResource("10_y4r1p")
|
sprite_frames = ExtResource("10_y4r1p")
|
||||||
animation = &"attack-mode-receiver-top"
|
animation = &"attack-mode-receiver-top"
|
||||||
|
|
||||||
[node name="attack_mode_bot" type="AnimatedSprite3D" parent="." unique_id=1320274503]
|
[node name="attack_mode_bot" type="AnimatedSprite3D" parent="." unique_id=1320274503]
|
||||||
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, -1, 0, 1, -4.371139e-08, 0, -0.6701627, 0)
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, -1, 0, 1, -4.371139e-08, 0, -0.6701627, 0)
|
||||||
visible = false
|
visible = false
|
||||||
|
render_priority = 3
|
||||||
sprite_frames = ExtResource("10_y4r1p")
|
sprite_frames = ExtResource("10_y4r1p")
|
||||||
animation = &"attack-mode-receiver-bot"
|
animation = &"attack-mode-receiver-bot"
|
||||||
frame = 31
|
frame = 31
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.3731489, 0)
|
|||||||
pixel_size = 0.002
|
pixel_size = 0.002
|
||||||
billboard = 1
|
billboard = 1
|
||||||
no_depth_test = true
|
no_depth_test = true
|
||||||
|
render_priority = 1
|
||||||
texture = ExtResource("4_grab_icon")
|
texture = ExtResource("4_grab_icon")
|
||||||
|
|
||||||
[node name="KeyLabel" type="Label3D" parent="InteractionPrompt" unique_id=1816493043]
|
[node name="KeyLabel" type="Label3D" parent="InteractionPrompt" unique_id=1816493043]
|
||||||
@@ -41,6 +42,8 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.30466843, 0)
|
|||||||
pixel_size = 0.01
|
pixel_size = 0.01
|
||||||
billboard = 1
|
billboard = 1
|
||||||
no_depth_test = true
|
no_depth_test = true
|
||||||
|
render_priority = 2
|
||||||
|
outline_render_priority = 1
|
||||||
modulate = Color(0.1, 1, 0.2, 1)
|
modulate = Color(0.1, 1, 0.2, 1)
|
||||||
text = "[ G ]"
|
text = "[ G ]"
|
||||||
font_size = 48
|
font_size = 48
|
||||||
@@ -51,6 +54,8 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.79176676, 0)
|
|||||||
pixel_size = 0.01
|
pixel_size = 0.01
|
||||||
billboard = 1
|
billboard = 1
|
||||||
no_depth_test = true
|
no_depth_test = true
|
||||||
|
render_priority = 2
|
||||||
|
outline_render_priority = 1
|
||||||
text = "LIFT TEKTON"
|
text = "LIFT TEKTON"
|
||||||
font_size = 38
|
font_size = 38
|
||||||
outline_size = 10
|
outline_size = 10
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ anchor_right = 1.0
|
|||||||
anchor_bottom = 1.0
|
anchor_bottom = 1.0
|
||||||
grow_horizontal = 2
|
grow_horizontal = 2
|
||||||
grow_vertical = 2
|
grow_vertical = 2
|
||||||
mouse_filter = 2
|
mouse_filter = 1
|
||||||
color = Color(0, 0, 0, 1)
|
color = Color(0, 0, 0, 1)
|
||||||
|
|
||||||
[node name="HighlightBorder" type="Panel" parent="." unique_id=25061739]
|
[node name="HighlightBorder" type="Panel" parent="." unique_id=25061739]
|
||||||
@@ -157,3 +157,42 @@ offset_left = 1080.0
|
|||||||
offset_top = 96.0
|
offset_top = 96.0
|
||||||
offset_right = 1356.0
|
offset_right = 1356.0
|
||||||
offset_bottom = 405.0
|
offset_bottom = 405.0
|
||||||
|
|
||||||
|
[node name="ObjectivePanel" type="PanelContainer" parent="." unique_id=-1098906247]
|
||||||
|
visible = false
|
||||||
|
anchors_preset = 3
|
||||||
|
anchor_left = 1.0
|
||||||
|
anchor_top = 1.0
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
offset_left = -315.0
|
||||||
|
offset_top = -210.0
|
||||||
|
offset_right = -15.0
|
||||||
|
offset_bottom = -130.0
|
||||||
|
grow_horizontal = 0
|
||||||
|
grow_vertical = 0
|
||||||
|
mouse_filter = 2
|
||||||
|
theme_override_styles/panel = SubResource("StyleBoxFlat_panel")
|
||||||
|
|
||||||
|
[node name="MarginContainer" type="MarginContainer" parent="ObjectivePanel" unique_id=-197916117]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_constants/margin_left = 15
|
||||||
|
theme_override_constants/margin_top = 10
|
||||||
|
theme_override_constants/margin_right = 15
|
||||||
|
theme_override_constants/margin_bottom = 10
|
||||||
|
|
||||||
|
[node name="VBoxContainer" type="VBoxContainer" parent="ObjectivePanel/MarginContainer" unique_id=1029384756]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="Title" type="Label" parent="ObjectivePanel/MarginContainer/VBoxContainer" unique_id=1352415614]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_colors/font_color = Color(1, 0.85, 0.1, 1)
|
||||||
|
theme_override_font_sizes/font_size = 14
|
||||||
|
text = "CURRENT OBJECTIVE"
|
||||||
|
|
||||||
|
[node name="ObjectiveText" type="RichTextLabel" parent="ObjectivePanel/MarginContainer/VBoxContainer" unique_id=895826431]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_font_sizes/normal_font_size = 18
|
||||||
|
bbcode_enabled = true
|
||||||
|
text = "Objective text goes here"
|
||||||
|
fit_content = true
|
||||||
|
|||||||
@@ -573,16 +573,16 @@ theme_override_styles/pressed = SubResource("StyleBoxTexture_3r3oo")
|
|||||||
theme_override_styles/hover = SubResource("StyleBoxTexture_cn37d")
|
theme_override_styles/hover = SubResource("StyleBoxTexture_cn37d")
|
||||||
|
|
||||||
[node name="AchievementPanel" type="Panel" parent="MainMargin/MainHBox/BottomWrapper" unique_id=689276483]
|
[node name="AchievementPanel" type="Panel" parent="MainMargin/MainHBox/BottomWrapper" unique_id=689276483]
|
||||||
custom_minimum_size = Vector2(165.5, 208)
|
custom_minimum_size = Vector2(82.75, 104)
|
||||||
layout_mode = 1
|
layout_mode = 1
|
||||||
anchors_preset = -1
|
anchors_preset = -1
|
||||||
anchor_left = 0.35300002
|
anchor_left = 0.377
|
||||||
anchor_top = -1.9760001
|
anchor_top = -1.1520001
|
||||||
anchor_right = 0.45800003
|
anchor_right = 0.44700003
|
||||||
anchor_bottom = 0.42600003
|
anchor_bottom = 0.407
|
||||||
offset_left = -0.08200073
|
offset_left = 0.4619751
|
||||||
offset_top = 0.008010864
|
offset_top = -11.383995
|
||||||
offset_right = 19.047974
|
offset_right = 13.421753
|
||||||
offset_bottom = 8.641998
|
offset_bottom = -1.8549156
|
||||||
rotation = 0.10297442
|
rotation = 0.10297442
|
||||||
theme_override_styles/panel = SubResource("StyleBoxTexture_abdxb")
|
theme_override_styles/panel = SubResource("StyleBoxTexture_abdxb")
|
||||||
|
|||||||
@@ -328,5 +328,5 @@ grow_horizontal = 0
|
|||||||
grow_vertical = 0
|
grow_vertical = 0
|
||||||
theme_override_colors/font_color = Color(0.6, 0.6, 0.6, 0.6)
|
theme_override_colors/font_color = Color(0.6, 0.6, 0.6, 0.6)
|
||||||
theme_override_font_sizes/font_size = 11
|
theme_override_font_sizes/font_size = 11
|
||||||
text = "v2.1.0"
|
text = "v2.1.2"
|
||||||
horizontal_alignment = 2
|
horizontal_alignment = 2
|
||||||
|
|||||||
@@ -55,7 +55,9 @@ func _process(delta):
|
|||||||
base_pos = player.target_position
|
base_pos = player.target_position
|
||||||
var target_position = base_pos + move_vec
|
var target_position = base_pos + move_vec
|
||||||
movement_manager.simple_move_to(target_position)
|
movement_manager.simple_move_to(target_position)
|
||||||
|
else:
|
||||||
|
if movement_manager.is_moving:
|
||||||
|
movement_manager.movement_queue.clear()
|
||||||
|
|
||||||
|
|
||||||
func handle_unhandled_input(event):
|
func handle_unhandled_input(event):
|
||||||
|
|||||||
@@ -24,6 +24,10 @@ func _ready() -> void:
|
|||||||
break
|
break
|
||||||
await get_tree().process_frame
|
await get_tree().process_frame
|
||||||
elapsed += get_process_delta_time()
|
elapsed += get_process_delta_time()
|
||||||
|
|
||||||
|
# Pause match timer during tutorial
|
||||||
|
if main_scene and main_scene.get("goals_cycle_manager"):
|
||||||
|
main_scene.goals_cycle_manager.set_process(false)
|
||||||
|
|
||||||
if not local_player:
|
if not local_player:
|
||||||
print("Tutorial Error: Local player not found.")
|
print("Tutorial Error: Local player not found.")
|
||||||
@@ -78,15 +82,17 @@ func _run_tutorial() -> void:
|
|||||||
# Grid Highlight
|
# Grid Highlight
|
||||||
overlay.clear_highlight()
|
overlay.clear_highlight()
|
||||||
await overlay.display_text("Look at the board! You will see [color=gold]Normal Tiles[/color] and shiny [color=cyan]Holo Tiles[/color].", true)
|
await overlay.display_text("Look at the board! You will see [color=gold]Normal Tiles[/color] and shiny [color=cyan]Holo Tiles[/color].", true)
|
||||||
|
# ==============================================================================
|
||||||
# --- INTERACTIVE 1: NORMAL TILE ---
|
# --- INTERACTIVE 1: NORMAL TILE ---
|
||||||
var normal_pos = _find_closest_tile(local_player.current_position, [7, 8, 9, 10])
|
# ==============================================================================
|
||||||
|
var normal_pos = _find_closest_tile(local_player.current_position, [7, 8, 9, 10], 4)
|
||||||
if normal_pos != Vector2i(-1, -1):
|
if normal_pos != Vector2i(-1, -1):
|
||||||
_highlight_floor_cell(normal_pos, Color(1.0, 1.0, 0.0)) # Yellow box
|
_highlight_floor_cell(normal_pos, Color(1.0, 1.0, 0.0)) # Yellow box
|
||||||
overlay.display_text("I've highlighted a [color=gold]Normal Tile[/color] with a yellow box. Walk over to it and press [color=red]SPACE[/color] to Grab it!", false)
|
overlay.display_text("I've highlighted a [color=gold]Normal Tile[/color] with a yellow box. Walk over to it and press [color=red]SPACE[/color] to Grab it!", false)
|
||||||
else:
|
else:
|
||||||
overlay.display_text("Walk up to any Normal Tile and press [color=red]SPACE[/color] to Grab it!", false)
|
overlay.display_text("Walk up to any Normal Tile and press [color=red]SPACE[/color] to Grab it!", false)
|
||||||
|
|
||||||
|
overlay.set_objective("Walk to a [color=gold]Normal Tile[/color] and press [color=red]SPACE[/color] to grab it.")
|
||||||
overlay.hide_overlay()
|
overlay.hide_overlay()
|
||||||
get_tree().paused = false
|
get_tree().paused = false
|
||||||
|
|
||||||
@@ -100,13 +106,15 @@ func _run_tutorial() -> void:
|
|||||||
break
|
break
|
||||||
await get_tree().process_frame
|
await get_tree().process_frame
|
||||||
|
|
||||||
|
overlay.hide_objective()
|
||||||
_clear_floor_highlights()
|
_clear_floor_highlights()
|
||||||
get_tree().paused = true
|
get_tree().paused = true
|
||||||
overlay.show_overlay()
|
overlay.show_overlay()
|
||||||
|
|
||||||
await overlay.display_text("Outstanding! You secured a tile.", true)
|
await overlay.display_text("Outstanding! You secured a tile.", true)
|
||||||
|
# ==============================================================================
|
||||||
# --- SCORE AND GOALS SECTION ---
|
# --- SCORE AND GOALS SECTION ---
|
||||||
|
# ==============================================================================
|
||||||
overlay.highlight_zone("Leaderboard")
|
overlay.highlight_zone("Leaderboard")
|
||||||
await overlay.display_text("Your main objective is to climb the [color=gold]Leaderboard[/color] on the right by scoring points.", true)
|
await overlay.display_text("Your main objective is to climb the [color=gold]Leaderboard[/color] on the right by scoring points.", true)
|
||||||
|
|
||||||
@@ -114,54 +122,159 @@ func _run_tutorial() -> void:
|
|||||||
await overlay.display_text("You earn points by collecting tiles, but the real score comes from completing your [color=gold]Playerboard Goals[/color]!", true)
|
await overlay.display_text("You earn points by collecting tiles, but the real score comes from completing your [color=gold]Playerboard Goals[/color]!", true)
|
||||||
await overlay.display_text("Fill your entire board shape to complete a goal. This grants massive points, clears the board, and ranks you up!", true)
|
await overlay.display_text("Fill your entire board shape to complete a goal. This grants massive points, clears the board, and ranks you up!", true)
|
||||||
|
|
||||||
# --- TEKTONS SECTION ---
|
# ==============================================================================
|
||||||
overlay.clear_highlight()
|
# --- POWER UP SECTION ---
|
||||||
await overlay.display_text("Now, what about those little creatures running around the map? Those are [color=cyan]Tektons[/color]!", true)
|
# ==============================================================================
|
||||||
await overlay.display_text("Grabbing a dynamic Tekton gives you [color=gold]PASSIVE score points[/color] over time and spawns bonus tiles for you while you carry it.", true)
|
|
||||||
await overlay.display_text("Hold onto them as long as you can... but watch out, opponents will try to RAM you and steal them!", true)
|
|
||||||
await overlay.display_text("Also keep an eye on [color=gray]Static Tektons[/color] standing on podiums. They periodically throw new free tiles onto the board for you to collect!", true)
|
|
||||||
|
|
||||||
# --- INTERACTIVE 2: HOLO TILE ---
|
|
||||||
await overlay.display_text("Now, let's talk about [color=cyan]Holo Tiles[/color]. They grant you special Power-Ups!", true)
|
await overlay.display_text("Now, let's talk about [color=cyan]Holo Tiles[/color]. They grant you special Power-Ups!", true)
|
||||||
|
|
||||||
var holo_pos = _find_closest_tile(local_player.current_position, [11, 12, 13, 14])
|
overlay.clear_highlight()
|
||||||
if holo_pos != Vector2i(-1, -1):
|
await overlay.display_text("There are [color=cyan]4 types of Power-Ups[/color] from Holo Tiles. Let me walk you through each one, one by one.", true)
|
||||||
_highlight_floor_cell(holo_pos, Color(0.0, 1.0, 1.0)) # Cyan box
|
|
||||||
overlay.display_text("I've highlighted a [color=cyan]Holo Tile[/color] with a cyan box. Go ahead and grab it!", false)
|
|
||||||
else:
|
|
||||||
# Fallback: force spawn one if the RNG map generation didn't place any
|
|
||||||
holo_pos = local_player.current_position + Vector2i(0, 1)
|
|
||||||
var gridmap = local_player.get("enhanced_gridmap")
|
|
||||||
if gridmap:
|
|
||||||
gridmap.set_cell_item(Vector3i(holo_pos.x, 1, holo_pos.y), 11) # Spawn speed boost
|
|
||||||
_highlight_floor_cell(holo_pos, Color(0.0, 1.0, 1.0))
|
|
||||||
overlay.display_text("I just dropped a Holo Tile near you (cyan box). Go ahead and grab it!", false)
|
|
||||||
|
|
||||||
|
var powerup_ids = [11, 12, 13, 14]
|
||||||
|
var powerup_names = {
|
||||||
|
11: "[color=gold]Speed Boost[/color] (Make you run fast)",
|
||||||
|
12: "[color=aqua]Area Freeze[/color] (Slows nearby opponents)",
|
||||||
|
13: "[color=gray]Iron Wall[/color] (Blocks opponent path)",
|
||||||
|
14: "[color=white]Ghost Mode[/color] (Invisibility and ram immunity)"
|
||||||
|
}
|
||||||
|
var powerup_enums = {11: 0, 12: 1, 13: 2, 14: 3}
|
||||||
|
var gridmap = local_player.get("enhanced_gridmap")
|
||||||
|
|
||||||
|
for pid in powerup_ids:
|
||||||
|
overlay.clear_highlight()
|
||||||
|
overlay.show_powerup_card(pid)
|
||||||
|
await overlay.display_text("Next is %s. I will drop this Holo Tile near you." % powerup_names[pid], true)
|
||||||
|
overlay.hide_powerup_card()
|
||||||
|
|
||||||
|
var ppos = local_player.current_position + Vector2i(0, 1)
|
||||||
|
if gridmap:
|
||||||
|
gridmap.set_cell_item(Vector3i(ppos.x, 1, ppos.y), pid)
|
||||||
|
_highlight_floor_cell(ppos, Color(0.0, 1.0, 1.0))
|
||||||
|
|
||||||
|
overlay.display_text("Grab the tile, press [color=yellow]'F'[/color] to use it, and for some skills press it again or Click to confirm!", false)
|
||||||
|
|
||||||
|
overlay.set_objective("Grab the [color=cyan]Holo Tile[/color] and press [color=yellow]'F'[/color] to use %s." % powerup_names[pid])
|
||||||
|
overlay.hide_overlay()
|
||||||
|
get_tree().paused = false
|
||||||
|
|
||||||
|
# Wait for it to be grabbed
|
||||||
|
while gridmap and gridmap.get_cell_item(Vector3i(ppos.x, 1, ppos.y)) == pid:
|
||||||
|
await get_tree().process_frame
|
||||||
|
|
||||||
|
# Highlight the Power-Up item slot now that they picked it up
|
||||||
|
overlay.highlight_zone("PowerUpItem")
|
||||||
|
|
||||||
|
# Wait for it to be used
|
||||||
|
var effect_enum = powerup_enums[pid]
|
||||||
|
while local_player.get("special_tiles_manager") and local_player.special_tiles_manager.inventory.get(effect_enum, false) == true:
|
||||||
|
await get_tree().process_frame
|
||||||
|
|
||||||
|
overlay.clear_highlight()
|
||||||
|
|
||||||
|
overlay.hide_objective()
|
||||||
|
_clear_floor_highlights()
|
||||||
|
get_tree().paused = true
|
||||||
|
overlay.show_overlay()
|
||||||
|
await overlay.display_text("Excellent! You used %s." % powerup_names[pid], true)
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# --- TEKTONS SECTION ---
|
||||||
|
# ==============================================================================
|
||||||
|
overlay.clear_highlight()
|
||||||
|
# --- DYNAMIC TEKTON FOCUS ---
|
||||||
|
var dynamic_tektons = get_tree().get_nodes_in_group("Tektons")
|
||||||
|
var cam_mgr = main_scene.get("camera_context_manager") if main_scene else null
|
||||||
|
if dynamic_tektons.size() > 0 and cam_mgr:
|
||||||
|
# Find nearest dynamic tekton
|
||||||
|
var nearest = null
|
||||||
|
var nearest_dist = 999999
|
||||||
|
for tk in dynamic_tektons:
|
||||||
|
if tk.get("is_static_turret") == false:
|
||||||
|
var dist = local_player.global_position.distance_to(tk.global_position)
|
||||||
|
if dist < nearest_dist:
|
||||||
|
nearest_dist = dist
|
||||||
|
nearest = tk
|
||||||
|
|
||||||
|
if nearest:
|
||||||
|
cam_mgr.process_mode = Node.PROCESS_MODE_ALWAYS
|
||||||
|
cam_mgr.set_player(nearest)
|
||||||
|
await get_tree().create_timer(1.2, true).timeout
|
||||||
|
|
||||||
|
var cam = main_scene.get_node_or_null("Camera3D200")
|
||||||
|
if cam and cam is Camera3D:
|
||||||
|
var screen_pos = cam.unproject_position(nearest.global_position)
|
||||||
|
overlay.highlight_rect(Rect2(screen_pos.x - 75, screen_pos.y - 75, 150, 150))
|
||||||
|
|
||||||
|
await overlay.display_text("Now, what about those little creatures running around the map? Those are [color=cyan]Tektons[/color]!", true)
|
||||||
|
|
||||||
|
if cam_mgr:
|
||||||
|
cam_mgr.set_player(local_player)
|
||||||
|
cam_mgr.process_mode = Node.PROCESS_MODE_INHERIT
|
||||||
|
overlay.clear_highlight()
|
||||||
|
await get_tree().create_timer(0.8, true).timeout
|
||||||
|
# ----------------------------
|
||||||
|
|
||||||
|
await overlay.display_text("Grabbing a dynamic Tekton gives you [color=gold]PASSIVE score points[/color] over time and spawns bonus tiles for you while you carry it.", true)
|
||||||
|
await overlay.display_text("Hold onto them as long as you can... but watch out, opponents will try to RAM you and steal them!", true)
|
||||||
|
|
||||||
|
await overlay.display_text("Go and catch one of the Tektons running around!", false)
|
||||||
|
overlay.set_objective("Walk into a [color=cyan]Tekton[/color] or press [color=red]G[/color] near one to grab it.")
|
||||||
overlay.hide_overlay()
|
overlay.hide_overlay()
|
||||||
get_tree().paused = false
|
get_tree().paused = false
|
||||||
|
|
||||||
initial_items = local_player.playerboard.count(-1)
|
while not local_player.is_carrying_tekton:
|
||||||
while true:
|
|
||||||
if holo_pos != Vector2i(-1, -1) and local_player.get("enhanced_gridmap"):
|
|
||||||
if local_player.enhanced_gridmap.get_cell_item(Vector3i(holo_pos.x, 1, holo_pos.y)) == -1:
|
|
||||||
break
|
|
||||||
elif local_player.playerboard.count(-1) < initial_items:
|
|
||||||
break
|
|
||||||
await get_tree().process_frame
|
await get_tree().process_frame
|
||||||
|
|
||||||
_clear_floor_highlights()
|
overlay.hide_objective()
|
||||||
get_tree().paused = true
|
get_tree().paused = true
|
||||||
overlay.show_overlay()
|
overlay.show_overlay()
|
||||||
|
await overlay.display_text("Great job! Notice your score passively increasing.", true)
|
||||||
|
|
||||||
# --- POWER UP SECTION ---
|
await overlay.display_text("But you won't hold it forever! The Tekton runs away when your carry timer reaches 0, or you can manually throw it by pressing [color=red]G[/color].", false)
|
||||||
# Highlight Power Up Icon
|
overlay.set_objective("Wait for the [color=cyan]Tekton[/color] to escape, or press [color=red]G[/color] to throw it!")
|
||||||
overlay.highlight_zone("PowerUpItem")
|
overlay.hide_overlay()
|
||||||
await overlay.display_text("Nice! You grabbed a Holo Tile — that earned you a special [color=cyan]Power-Up[/color] item!", true)
|
get_tree().paused = false
|
||||||
await overlay.display_text("There are [color=cyan]4 types of Power-Ups[/color] from Holo Tiles. Let me walk you through each one.", true)
|
|
||||||
await overlay.show_powerup_showcase()
|
|
||||||
await overlay.display_text("To activate your stored Power-Up, press [color=yellow]'F'[/color]. If you don't like this key, you can remap it in [color=gold]Settings[/color].", true)
|
|
||||||
|
|
||||||
|
while local_player.is_carrying_tekton:
|
||||||
|
await get_tree().process_frame
|
||||||
|
|
||||||
|
overlay.hide_objective()
|
||||||
|
get_tree().paused = true
|
||||||
|
overlay.show_overlay()
|
||||||
|
await overlay.display_text("Oops, it got away! But don't worry, you can always catch another one.", true)
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# --- STATIC TEKTON FOCUS ---
|
||||||
|
# ==============================================================================
|
||||||
|
var static_stands = get_tree().get_nodes_in_group("StaticTektonStands")
|
||||||
|
cam_mgr = main_scene.get("camera_context_manager") if main_scene else null
|
||||||
|
|
||||||
|
if static_stands.size() > 0 and cam_mgr:
|
||||||
|
var target_stand = static_stands[0]
|
||||||
|
cam_mgr.process_mode = Node.PROCESS_MODE_ALWAYS # Allow camera to slide while paused
|
||||||
|
cam_mgr.set_player(target_stand)
|
||||||
|
|
||||||
|
# Give it time to pan over
|
||||||
|
await get_tree().create_timer(1.2, true).timeout
|
||||||
|
|
||||||
|
# Dim the screen around it
|
||||||
|
var cam = main_scene.get_node_or_null("Camera3D200")
|
||||||
|
if cam and cam is Camera3D:
|
||||||
|
var screen_pos = cam.unproject_position(target_stand.global_position)
|
||||||
|
overlay.highlight_rect(Rect2(screen_pos.x - 100, screen_pos.y - 120, 200, 200))
|
||||||
|
|
||||||
|
await overlay.display_text("Also keep an eye on [color=gray]Static Tektons[/color] standing on podiums. They periodically throw new free tiles onto the board for you to collect!", true)
|
||||||
|
|
||||||
|
if cam_mgr:
|
||||||
|
cam_mgr.set_player(local_player)
|
||||||
|
cam_mgr.process_mode = Node.PROCESS_MODE_INHERIT
|
||||||
|
overlay.clear_highlight()
|
||||||
|
|
||||||
|
# Let it pan back briefly
|
||||||
|
await get_tree().create_timer(0.8, true).timeout
|
||||||
|
# ==============================================================================
|
||||||
# --- BATTERY GAUGE & RAMMING SECTION ---
|
# --- BATTERY GAUGE & RAMMING SECTION ---
|
||||||
|
# ==============================================================================
|
||||||
# Switch to highlight Power Bar / Battery Gauge
|
# Switch to highlight Power Bar / Battery Gauge
|
||||||
overlay.highlight_zone("PowerBar")
|
overlay.highlight_zone("PowerBar")
|
||||||
await overlay.display_text("Next, look at your [color=cyan]Battery Gauge[/color] — it [color=yellow]fills up automatically over time[/color]. You don't need to do anything to charge it.", true)
|
await overlay.display_text("Next, look at your [color=cyan]Battery Gauge[/color] — it [color=yellow]fills up automatically over time[/color]. You don't need to do anything to charge it.", true)
|
||||||
@@ -187,15 +300,41 @@ func _run_tutorial() -> void:
|
|||||||
spawned_bot.add_to_group("Bots", true)
|
spawned_bot.add_to_group("Bots", true)
|
||||||
await get_tree().create_timer(0.2).timeout
|
await get_tree().create_timer(0.2).timeout
|
||||||
|
|
||||||
# Freeze it so its AI doesn't run away during the tutorial
|
|
||||||
var bc = spawned_bot.get_node_or_null("BotController")
|
var bc = spawned_bot.get_node_or_null("BotController")
|
||||||
if bc:
|
if bc:
|
||||||
bc.set_process(false)
|
bc.set_process(true)
|
||||||
bc.set_physics_process(false)
|
bc.set_physics_process(true)
|
||||||
spawned_bot.set("is_frozen", true)
|
|
||||||
|
|
||||||
if spawned_bot:
|
if spawned_bot:
|
||||||
await overlay.display_text("Let's try it. I'm placing a Bot right next to you, and I'll instantly fill your Battery Gauge to max.", true)
|
# Always unfreeze in case it was caught in the earlier Area Freeze blast
|
||||||
|
spawned_bot.set("is_frozen", false)
|
||||||
|
var target_bc = spawned_bot.get_node_or_null("BotController")
|
||||||
|
if target_bc:
|
||||||
|
target_bc.set_process(true)
|
||||||
|
target_bc.set_physics_process(true)
|
||||||
|
|
||||||
|
await overlay.display_text("Let's try it. There is a Bot roaming the map right now. I will fill your Battery Gauge to max.", true)
|
||||||
|
|
||||||
|
# --- CAMERA PAN TO BOT ---
|
||||||
|
cam_mgr = main_scene.get("camera_context_manager") if main_scene else null
|
||||||
|
if cam_mgr:
|
||||||
|
cam_mgr.process_mode = Node.PROCESS_MODE_ALWAYS
|
||||||
|
cam_mgr.set_player(spawned_bot)
|
||||||
|
await get_tree().create_timer(1.2, true).timeout
|
||||||
|
|
||||||
|
var cam = main_scene.get_node_or_null("Camera3D200")
|
||||||
|
if cam and cam is Camera3D:
|
||||||
|
var screen_pos = cam.unproject_position(spawned_bot.global_position)
|
||||||
|
overlay.highlight_rect(Rect2(screen_pos.x - 75, screen_pos.y - 100, 150, 150))
|
||||||
|
|
||||||
|
await overlay.display_text("Behold, your opponent! Their AI is active so you will have to hunt them down.", true)
|
||||||
|
|
||||||
|
if cam_mgr:
|
||||||
|
cam_mgr.set_player(local_player)
|
||||||
|
cam_mgr.process_mode = Node.PROCESS_MODE_INHERIT
|
||||||
|
overlay.clear_highlight()
|
||||||
|
await get_tree().create_timer(0.8, true).timeout
|
||||||
|
# ------------------------
|
||||||
|
|
||||||
# Instantly grant FULL BOOST
|
# Instantly grant FULL BOOST
|
||||||
if local_player.get("powerup_manager"):
|
if local_player.get("powerup_manager"):
|
||||||
@@ -204,41 +343,42 @@ func _run_tutorial() -> void:
|
|||||||
local_player.powerup_manager.acquire_smash_bonus()
|
local_player.powerup_manager.acquire_smash_bonus()
|
||||||
local_player.powerup_manager.acquire_smash_bonus()
|
local_player.powerup_manager.acquire_smash_bonus()
|
||||||
|
|
||||||
var n_pos = local_player.current_position + Vector2i(1, 0)
|
overlay.display_text("Press 'Q' to enter Attack Mode, then chase the Bot down to RAM it!", false)
|
||||||
if local_player.get("enhanced_gridmap"):
|
|
||||||
var neighbors = local_player.enhanced_gridmap.get_neighbors(local_player.current_position, 0)
|
|
||||||
for n in neighbors:
|
|
||||||
if n.get("is_walkable"):
|
|
||||||
n_pos = n.position
|
|
||||||
break
|
|
||||||
|
|
||||||
# Safely set bot position
|
|
||||||
spawned_bot.current_position = n_pos
|
|
||||||
if local_player.get("enhanced_gridmap") and local_player.enhanced_gridmap.has_method("grid_to_world"):
|
|
||||||
spawned_bot.global_position = local_player.enhanced_gridmap.grid_to_world(n_pos)
|
|
||||||
|
|
||||||
overlay.display_text("Press 'Q' to enter Attack Mode, then Walk into the Bot!", false)
|
|
||||||
|
|
||||||
|
overlay.set_objective("Press [color=yellow]'Q'[/color] to enter [color=red]ATTACK MODE[/color], then chase and RAM the bot!")
|
||||||
overlay.hide_overlay()
|
overlay.hide_overlay()
|
||||||
get_tree().paused = false
|
get_tree().paused = false
|
||||||
|
|
||||||
# Wait for the player to push the bot (bot's position changes)
|
# Wait for the player to push the bot
|
||||||
var bot_old_pos = spawned_bot.current_position
|
while true:
|
||||||
while spawned_bot.current_position == bot_old_pos:
|
if spawned_bot.get("is_knock_mode") == true:
|
||||||
|
break
|
||||||
|
|
||||||
|
# Fallback: if player's attack mode deactivated early despite having timer left, they likely successfully rammed
|
||||||
|
var t = local_player.get("attack_mode_timer")
|
||||||
|
if local_player.get("is_attack_mode") == false and t != null and t > 0.0 and t < 3.0:
|
||||||
|
break
|
||||||
|
|
||||||
await get_tree().process_frame
|
await get_tree().process_frame
|
||||||
|
|
||||||
|
overlay.hide_objective()
|
||||||
get_tree().paused = true
|
get_tree().paused = true
|
||||||
overlay.show_overlay()
|
overlay.show_overlay()
|
||||||
await overlay.display_text("Smashing! You pushed it away. Notice your Battery Gauge was consumed.", true)
|
await overlay.display_text("Smashing! You pushed it away. Notice your Battery Gauge was consumed.", true)
|
||||||
|
|
||||||
await overlay.display_text("Beware! Your opponents can RAM you to steal your tiles too. Get ready to defend yourself against the Bots!", true)
|
await overlay.display_text("Beware! Your opponents can RAM you to steal your tiles too. Get ready to defend yourself against the Bots!", true)
|
||||||
|
|
||||||
|
await overlay.display_text("Tutorial Complete! Returning to the Main Menu.", true)
|
||||||
|
|
||||||
overlay.hide_overlay()
|
overlay.hide_overlay()
|
||||||
get_tree().paused = false
|
get_tree().paused = false
|
||||||
_set_bots_enabled(true)
|
|
||||||
|
|
||||||
|
if main_scene and main_scene.get("goals_cycle_manager"):
|
||||||
|
main_scene.goals_cycle_manager.set_process(true)
|
||||||
|
|
||||||
LobbyManager.is_tutorial_mode = false
|
LobbyManager.is_tutorial_mode = false
|
||||||
queue_free()
|
LobbyManager.leave_room()
|
||||||
|
get_tree().change_scene_to_file("res://scenes/lobby.tscn")
|
||||||
|
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
# Helper Floor Highlighting and Tile Detection Logic
|
# Helper Floor Highlighting and Tile Detection Logic
|
||||||
@@ -246,7 +386,7 @@ func _run_tutorial() -> void:
|
|||||||
|
|
||||||
var _floor_highlights: Array[Node] = []
|
var _floor_highlights: Array[Node] = []
|
||||||
|
|
||||||
func _find_closest_tile(start_pos: Vector2i, types: Array) -> Vector2i:
|
func _find_closest_tile(start_pos: Vector2i, types: Array, min_dist: int = 0) -> Vector2i:
|
||||||
var gridmap = local_player.get("enhanced_gridmap")
|
var gridmap = local_player.get("enhanced_gridmap")
|
||||||
if not gridmap: return Vector2i(-1, -1)
|
if not gridmap: return Vector2i(-1, -1)
|
||||||
|
|
||||||
@@ -258,7 +398,7 @@ func _find_closest_tile(start_pos: Vector2i, types: Array) -> Vector2i:
|
|||||||
var item = gridmap.get_cell_item(Vector3i(x, 1, z))
|
var item = gridmap.get_cell_item(Vector3i(x, 1, z))
|
||||||
if item in types:
|
if item in types:
|
||||||
var dist = abs(start_pos.x - x) + abs(start_pos.y - z)
|
var dist = abs(start_pos.x - x) + abs(start_pos.y - z)
|
||||||
if dist < best_dist:
|
if dist >= min_dist and dist < best_dist:
|
||||||
best_dist = dist
|
best_dist = dist
|
||||||
best_pos = Vector2i(x, z)
|
best_pos = Vector2i(x, z)
|
||||||
return best_pos
|
return best_pos
|
||||||
|
|||||||
@@ -2,12 +2,15 @@ extends CanvasLayer
|
|||||||
class_name TutorialOverlay
|
class_name TutorialOverlay
|
||||||
|
|
||||||
# --- Scene node references ---
|
# --- Scene node references ---
|
||||||
@onready var dim_rect: ColorRect = $DimRect
|
@onready var dim_rect: ColorRect = $DimRect
|
||||||
@onready var highlight_border: Panel = $HighlightBorder
|
@onready var highlight_border: Panel = $HighlightBorder
|
||||||
@onready var dialogue_panel: PanelContainer = $DialoguePanel
|
@onready var dialogue_panel: PanelContainer = $DialoguePanel
|
||||||
@onready var text_label: RichTextLabel = $DialoguePanel/MarginContainer/HBoxContainer/VBoxContainer/DialogueText
|
@onready var text_label: RichTextLabel = $DialoguePanel/MarginContainer/HBoxContainer/VBoxContainer/DialogueText
|
||||||
@onready var next_indicator: Label = $DialoguePanel/MarginContainer/HBoxContainer/VBoxContainer/NextIndicator
|
@onready var next_indicator: Label = $DialoguePanel/MarginContainer/HBoxContainer/VBoxContainer/NextIndicator
|
||||||
@onready var highlight_zones: Node = $HighlightZones
|
@onready var highlight_zones: Node = $HighlightZones
|
||||||
|
|
||||||
|
@onready var objective_panel: PanelContainer = $ObjectivePanel
|
||||||
|
@onready var objective_text: RichTextLabel = $ObjectivePanel/MarginContainer/VBoxContainer/ObjectiveText
|
||||||
|
|
||||||
# --- State ---
|
# --- State ---
|
||||||
var is_waiting_for_input: bool = false
|
var is_waiting_for_input: bool = false
|
||||||
@@ -63,15 +66,15 @@ func highlight_rect(rect: Rect2) -> void:
|
|||||||
|
|
||||||
# Position the glowing border panel on top
|
# Position the glowing border panel on top
|
||||||
highlight_border.position = rect.position - Vector2(6, 6)
|
highlight_border.position = rect.position - Vector2(6, 6)
|
||||||
highlight_border.size = rect.size + Vector2(12, 12)
|
highlight_border.size = rect.size + Vector2(12, 12)
|
||||||
highlight_border.visible = true
|
highlight_border.visible = true
|
||||||
|
|
||||||
# Pulsing glow animation
|
# Pulsing glow animation
|
||||||
if _pulse_tween:
|
if _pulse_tween:
|
||||||
_pulse_tween.kill()
|
_pulse_tween.kill()
|
||||||
_pulse_tween = create_tween().set_loops()
|
_pulse_tween = create_tween().set_loops()
|
||||||
_pulse_tween.tween_property(highlight_border, "self_modulate:a", 0.25, 0.75)
|
_pulse_tween.tween_property(highlight_border, "self_modulate:a", 0.25, 0.75)
|
||||||
_pulse_tween.tween_property(highlight_border, "self_modulate:a", 1.0, 0.75)
|
_pulse_tween.tween_property(highlight_border, "self_modulate:a", 1.0, 0.75)
|
||||||
|
|
||||||
func clear_highlight() -> void:
|
func clear_highlight() -> void:
|
||||||
if _dim_material:
|
if _dim_material:
|
||||||
@@ -86,14 +89,23 @@ func clear_highlight() -> void:
|
|||||||
# Show / Hide whole overlay
|
# Show / Hide whole overlay
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
func hide_overlay() -> void:
|
func hide_overlay() -> void:
|
||||||
dim_rect.visible = false
|
dim_rect.visible = false
|
||||||
highlight_border.visible = false
|
highlight_border.visible = false
|
||||||
dialogue_panel.visible = false
|
dialogue_panel.visible = false
|
||||||
|
|
||||||
func show_overlay() -> void:
|
func show_overlay() -> void:
|
||||||
dim_rect.visible = true
|
dim_rect.visible = true
|
||||||
dialogue_panel.visible = true
|
dialogue_panel.visible = true
|
||||||
|
|
||||||
|
func set_objective(text: String) -> void:
|
||||||
|
if objective_panel and objective_text:
|
||||||
|
objective_text.text = text
|
||||||
|
objective_panel.visible = true
|
||||||
|
|
||||||
|
func hide_objective() -> void:
|
||||||
|
if objective_panel:
|
||||||
|
objective_panel.visible = false
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Dialogue
|
# Dialogue
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@@ -106,11 +118,11 @@ func display_text(bbcode_text: String, wait_for_click: bool = true) -> void:
|
|||||||
|
|
||||||
if wait_for_click:
|
if wait_for_click:
|
||||||
next_indicator.visible = true
|
next_indicator.visible = true
|
||||||
is_waiting_for_input = true
|
is_waiting_for_input = true
|
||||||
await next_pressed
|
await next_pressed
|
||||||
else:
|
else:
|
||||||
next_indicator.visible = false
|
next_indicator.visible = false
|
||||||
is_waiting_for_input = false
|
is_waiting_for_input = false
|
||||||
|
|
||||||
func _input(event: InputEvent) -> void:
|
func _input(event: InputEvent) -> void:
|
||||||
if not is_waiting_for_input:
|
if not is_waiting_for_input:
|
||||||
@@ -121,38 +133,46 @@ func _input(event: InputEvent) -> void:
|
|||||||
elif event is InputEventScreenTouch and event.pressed:
|
elif event is InputEventScreenTouch and event.pressed:
|
||||||
consumed = true
|
consumed = true
|
||||||
if consumed:
|
if consumed:
|
||||||
is_waiting_for_input = false
|
is_waiting_for_input = false
|
||||||
next_indicator.visible = false
|
next_indicator.visible = false
|
||||||
next_pressed.emit()
|
next_pressed.emit()
|
||||||
get_viewport().set_input_as_handled()
|
var vp = get_viewport()
|
||||||
|
if vp:
|
||||||
|
vp.set_input_as_handled()
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Power-Up Showcase — one card per powerup with icon + name + description
|
# Power-Up Showcase — one card per powerup with icon + name + description
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
func show_powerup_showcase() -> void:
|
var _current_showcase: Control
|
||||||
"""Display each powerup as an interactive card. Awaits click between each."""
|
|
||||||
var powerups = [
|
func show_powerup_card(pid: int) -> void:
|
||||||
{
|
var powerups = {
|
||||||
|
11: {
|
||||||
"icon": "res://assets/graphics/touch_control/speed.png",
|
"icon": "res://assets/graphics/touch_control/speed.png",
|
||||||
"name": "[color=gold]⚡ Speed Boost[/color]",
|
"name": "[color=gold]Speed Boost[/color]",
|
||||||
"desc": "Temporarily increases your movement speed for [color=yellow]5 seconds[/color]. Great for racing across the board to grab tiles before opponents."
|
"desc": "Temporarily increases your movement speed for [color=yellow]5 seconds[/color]. Great for racing across the board to grab tiles before opponents."
|
||||||
},
|
},
|
||||||
{
|
12: {
|
||||||
"icon": "res://assets/graphics/touch_control/freeze_area.png",
|
"icon": "res://assets/graphics/touch_control/freeze_area.png",
|
||||||
"name": "[color=aqua]❄ Area Freeze[/color]",
|
"name": "[color=aqua]Area Freeze[/color]",
|
||||||
"desc": "Freezes all opponents within a radius of [color=aqua]5 tiles[/color] around you, slowing them to a crawl for [color=yellow]3 seconds[/color]."
|
"desc": "Freezes all opponents within a radius of [color=aqua]5 tiles[/color] around you, slowing them to a crawl for [color=yellow]3 seconds[/color]."
|
||||||
},
|
},
|
||||||
{
|
13: {
|
||||||
"icon": "res://assets/graphics/touch_control/wall.png",
|
"icon": "res://assets/graphics/touch_control/wall.png",
|
||||||
"name": "[color=gray]🧱 Iron Wall[/color]",
|
"name": "[color=gray]Iron Wall[/color]",
|
||||||
"desc": "Projects a full row or column of wall tiles in front of you, blocking opponent movement and protecting your tiles."
|
"desc": "Projects a full row or column of wall tiles in front of you, blocking opponent movement and protecting your tiles."
|
||||||
},
|
},
|
||||||
{
|
14: {
|
||||||
"icon": "res://assets/graphics/touch_control/ghost.png",
|
"icon": "res://assets/graphics/touch_control/ghost.png",
|
||||||
"name": "[color=white]👻 Ghost Mode[/color]",
|
"name": "[color=white]Ghost Mode[/color]",
|
||||||
"desc": "Makes you [color=white]invisible[/color] for [color=yellow]6 seconds[/color]. You cannot be rammed while invisible — perfect for escaping danger or sneaking around."
|
"desc": "Makes you [color=white]invisible[/color] for [color=yellow]6 seconds[/color]. You cannot be rammed while invisible — perfect for escaping danger or sneaking around."
|
||||||
},
|
}
|
||||||
]
|
}
|
||||||
|
|
||||||
|
if not powerups.has(pid):
|
||||||
|
return
|
||||||
|
|
||||||
|
var pu = powerups[pid]
|
||||||
|
|
||||||
# Build a showcase panel sitting above the dialogue panel
|
# Build a showcase panel sitting above the dialogue panel
|
||||||
var showcase = PanelContainer.new()
|
var showcase = PanelContainer.new()
|
||||||
@@ -161,22 +181,22 @@ func show_powerup_showcase() -> void:
|
|||||||
|
|
||||||
var showcase_style = StyleBoxFlat.new()
|
var showcase_style = StyleBoxFlat.new()
|
||||||
showcase_style.bg_color = Color(0.05, 0.05, 0.12, 0.97)
|
showcase_style.bg_color = Color(0.05, 0.05, 0.12, 0.97)
|
||||||
showcase_style.border_width_left = 3
|
showcase_style.border_width_left = 3
|
||||||
showcase_style.border_width_top = 3
|
showcase_style.border_width_top = 3
|
||||||
showcase_style.border_width_right = 3
|
showcase_style.border_width_right = 3
|
||||||
showcase_style.border_width_bottom = 3
|
showcase_style.border_width_bottom = 3
|
||||||
showcase_style.border_color = Color(0.6, 0.4, 1.0, 1.0)
|
showcase_style.border_color = Color(0.6, 0.4, 1.0, 1.0)
|
||||||
showcase_style.corner_radius_top_left = 12
|
showcase_style.corner_radius_top_left = 12
|
||||||
showcase_style.corner_radius_top_right = 12
|
showcase_style.corner_radius_top_right = 12
|
||||||
showcase_style.corner_radius_bottom_left = 12
|
showcase_style.corner_radius_bottom_left = 12
|
||||||
showcase_style.corner_radius_bottom_right = 12
|
showcase_style.corner_radius_bottom_right = 12
|
||||||
showcase.add_theme_stylebox_override("panel", showcase_style)
|
showcase.add_theme_stylebox_override("panel", showcase_style)
|
||||||
add_child(showcase)
|
add_child(showcase)
|
||||||
|
|
||||||
var margin = MarginContainer.new()
|
var margin = MarginContainer.new()
|
||||||
margin.add_theme_constant_override("margin_left", 24)
|
margin.add_theme_constant_override("margin_left", 24)
|
||||||
margin.add_theme_constant_override("margin_top", 16)
|
margin.add_theme_constant_override("margin_top", 16)
|
||||||
margin.add_theme_constant_override("margin_right", 24)
|
margin.add_theme_constant_override("margin_right", 24)
|
||||||
margin.add_theme_constant_override("margin_bottom", 16)
|
margin.add_theme_constant_override("margin_bottom", 16)
|
||||||
showcase.add_child(margin)
|
showcase.add_child(margin)
|
||||||
|
|
||||||
@@ -187,9 +207,12 @@ func show_powerup_showcase() -> void:
|
|||||||
# Icon
|
# Icon
|
||||||
var icon_rect = TextureRect.new()
|
var icon_rect = TextureRect.new()
|
||||||
icon_rect.custom_minimum_size = Vector2(96, 96)
|
icon_rect.custom_minimum_size = Vector2(96, 96)
|
||||||
icon_rect.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
icon_rect.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||||
icon_rect.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
icon_rect.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
||||||
icon_rect.size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
icon_rect.size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
||||||
|
var tex = load(pu["icon"])
|
||||||
|
if tex:
|
||||||
|
icon_rect.texture = tex
|
||||||
hbox.add_child(icon_rect)
|
hbox.add_child(icon_rect)
|
||||||
|
|
||||||
# Text column
|
# Text column
|
||||||
@@ -203,6 +226,7 @@ func show_powerup_showcase() -> void:
|
|||||||
name_label.fit_content = true
|
name_label.fit_content = true
|
||||||
name_label.scroll_active = false
|
name_label.scroll_active = false
|
||||||
name_label.add_theme_font_size_override("normal_font_size", 24)
|
name_label.add_theme_font_size_override("normal_font_size", 24)
|
||||||
|
name_label.text = pu["name"]
|
||||||
vbox.add_child(name_label)
|
vbox.add_child(name_label)
|
||||||
|
|
||||||
var desc_label = RichTextLabel.new()
|
var desc_label = RichTextLabel.new()
|
||||||
@@ -211,36 +235,24 @@ func show_powerup_showcase() -> void:
|
|||||||
desc_label.scroll_active = false
|
desc_label.scroll_active = false
|
||||||
desc_label.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
desc_label.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||||
desc_label.add_theme_font_size_override("normal_font_size", 18)
|
desc_label.add_theme_font_size_override("normal_font_size", 18)
|
||||||
|
desc_label.text = pu["desc"]
|
||||||
vbox.add_child(desc_label)
|
vbox.add_child(desc_label)
|
||||||
|
|
||||||
# Counter label (e.g. "1 / 4")
|
|
||||||
var counter_label = Label.new()
|
|
||||||
counter_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT
|
|
||||||
counter_label.add_theme_font_size_override("font_size", 14)
|
|
||||||
counter_label.add_theme_color_override("font_color", Color(0.6, 0.6, 0.8))
|
|
||||||
vbox.add_child(counter_label)
|
|
||||||
|
|
||||||
# Position the showcase above the dialogue panel
|
# Position the showcase above the dialogue panel
|
||||||
|
# We rely on call deferred or await frame to ensure layout sizing is processed
|
||||||
await get_tree().process_frame
|
await get_tree().process_frame
|
||||||
|
if not is_inside_tree() or not is_instance_valid(showcase):
|
||||||
|
return
|
||||||
|
|
||||||
var vp = get_viewport().get_visible_rect().size
|
var vp = get_viewport().get_visible_rect().size
|
||||||
showcase.position = Vector2(
|
showcase.position = Vector2(
|
||||||
(vp.x - showcase.custom_minimum_size.x) / 2.0,
|
(vp.x - showcase.custom_minimum_size.x) / 2.0,
|
||||||
dialogue_panel.position.y - showcase.custom_minimum_size.y - 12
|
dialogue_panel.position.y - showcase.custom_minimum_size.y - 12
|
||||||
)
|
)
|
||||||
|
|
||||||
# Cycle through each powerup
|
_current_showcase = showcase
|
||||||
for i in powerups.size():
|
|
||||||
var pu = powerups[i]
|
|
||||||
var tex = load(pu["icon"])
|
|
||||||
if tex:
|
|
||||||
icon_rect.texture = tex
|
|
||||||
name_label.text = pu["name"]
|
|
||||||
desc_label.text = pu["desc"]
|
|
||||||
counter_label.text = "Power-Up %d / %d — Click to continue ▼" % [i + 1, powerups.size()]
|
|
||||||
|
|
||||||
# Reuse the existing input wait mechanism
|
func hide_powerup_card() -> void:
|
||||||
is_waiting_for_input = true
|
if is_instance_valid(_current_showcase):
|
||||||
await next_pressed
|
_current_showcase.queue_free()
|
||||||
|
_current_showcase = null
|
||||||
# Clean up showcase
|
|
||||||
showcase.queue_free()
|
|
||||||
|
|||||||
Reference in New Issue
Block a user