Add components

This commit is contained in:
Ategon 2024-10-06 04:22:46 -04:00
parent cc427f861a
commit 37e056bb21
112 changed files with 4150 additions and 0 deletions

BIN
Fonts/Qubi.ttf Normal file

Binary file not shown.

40
Fonts/Qubi.ttf.import Normal file
View file

@ -0,0 +1,40 @@
[remap]
importer="font_data_dynamic"
type="FontFile"
uid="uid://byubry1acvlug"
path="res://.godot/imported/Qubi.ttf-ef2072390941155281c267608c0b0094.fontdata"
[deps]
source_file="res://Fonts/Qubi.ttf"
dest_files=["res://.godot/imported/Qubi.ttf-ef2072390941155281c267608c0b0094.fontdata"]
[params]
Rendering=null
antialiasing=1
generate_mipmaps=false
disable_embedded_bitmaps=true
multichannel_signed_distance_field=false
msdf_pixel_range=8
msdf_size=48
allow_system_fallback=true
force_autohinter=false
hinting=0
subpixel_positioning=1
oversampling=0.0
Fallbacks=null
fallbacks=[]
Compress=null
compress=true
preload=[{
"chars": [],
"glyphs": [],
"name": "New Configuration",
"size": Vector2i(16, 0),
"variation_embolden": 0.0
}]
language_support={}
script_support={}
opentype_features={}

BIN
Fonts/Qubio.ttf Normal file

Binary file not shown.

34
Fonts/Qubio.ttf.import Normal file
View file

@ -0,0 +1,34 @@
[remap]
importer="font_data_dynamic"
type="FontFile"
uid="uid://chmfli1xm8oe1"
path="res://.godot/imported/Qubio.ttf-32f8479b52e99fe78535ddaada4aa1d7.fontdata"
[deps]
source_file="res://Fonts/Qubio.ttf"
dest_files=["res://.godot/imported/Qubio.ttf-32f8479b52e99fe78535ddaada4aa1d7.fontdata"]
[params]
Rendering=null
antialiasing=1
generate_mipmaps=false
disable_embedded_bitmaps=true
multichannel_signed_distance_field=false
msdf_pixel_range=8
msdf_size=48
allow_system_fallback=true
force_autohinter=false
hinting=0
subpixel_positioning=1
oversampling=0.0
Fallbacks=null
fallbacks=[]
Compress=null
compress=true
preload=[]
language_support={}
script_support={}
opentype_features={}

7
Fonts/Theme.tres Normal file
View file

@ -0,0 +1,7 @@
[gd_resource type="Theme" load_steps=2 format=3 uid="uid://ck7603ob4gflc"]
[ext_resource type="FontFile" uid="uid://byubry1acvlug" path="res://Fonts/Qubi.ttf" id="1_y7uny"]
[resource]
default_font = ExtResource("1_y7uny")
default_font_size = 8

3
Main.tscn Normal file
View file

@ -0,0 +1,3 @@
[gd_scene format=3 uid="uid://bs6ojoud4mvb8"]
[node name="Main" type="Node2D"]

View file

@ -0,0 +1,7 @@
[plugin]
name="Laia Highlighter"
description="A highlighter to highting laia scripting files"
author="Ategon"
version="v1.0.0"
script="plugin.gd"

View file

@ -0,0 +1,81 @@
@tool
extends EditorPlugin
var dialogue_highlighter:DialogueHighlighter
func _enter_tree() -> void:
dialogue_highlighter = DialogueHighlighter.new()
var script_editor = EditorInterface.get_script_editor()
print(script_editor)
print(dialogue_highlighter)
script_editor.register_syntax_highlighter(dialogue_highlighter)
print(script_editor.get_current_script())
print(script_editor.get_open_scripts())
script_editor.goto_line(20)
func _exit_tree() -> void:
if is_instance_valid(dialogue_highlighter):
var script_editor = EditorInterface.get_script_editor()
script_editor.unregister_syntax_highlighter(dialogue_highlighter)
dialogue_highlighter = null
class DialogueHighlighter extends EditorSyntaxHighlighter:
func _get_name() -> String:
return "Laia"
func _get_supported_languages() -> PackedStringArray:
return ["TextFile"]
func _get_line_syntax_highlighting(line: int) -> Dictionary:
var color_map = {}
var text_editor = get_text_edit()
var str = text_editor.get_line(line)
# Comment
if str.strip_edges().begins_with("#"):
color_map[0] = { "color": Color.WEB_GRAY }
return color_map
# Key
var regex3 = RegEx.new()
regex3.compile("([a-zA-Z0-9_]+:).*")
var result3 = regex3.search(str)
if result3:
color_map[result3.get_start(1)] = { "color": Color.SEA_GREEN }
color_map[result3.get_end(1)] = { "color": Color.WHITE }
# Array
var regex = RegEx.new()
regex.compile("([a-zA-Z0-9_\\-])+\\[\\]")
var result = regex.search(str)
if result:
color_map[result.get_start()] = { "color": Color.CYAN }
color_map[result.get_end(1)] = { "color": Color.LIGHT_CYAN }
# Enum
var regex4 = RegEx.new()
regex4.compile("[a-zA-Z0-9_]+(\\.[a-zA-Z0-9_]+)")
var result4 = regex4.search(str)
if result4:
color_map[result4.get_start()] = { "color": Color.ORANGE }
color_map[result4.get_start(1)] = { "color": Color.ORANGE_RED }
color_map[result4.get_end()] = { "color": Color.WHITE }
# Color
var regex2 = RegEx.new()
regex2.compile("#[a-zA-Z0-9]+")
var result2 = regex2.search(str)
if result2:
color_map[result2.get_start()] = { "color": Color(result2.get_string()) }
return color_map

View file

@ -0,0 +1,164 @@
[gd_scene load_steps=11 format=3 uid="uid://c8nsgn4idu8ay"]
[ext_resource type="Script" path="res://components/Achievements/achievements.gd" id="1_fj2tg"]
[ext_resource type="Texture2D" uid="uid://dat440dg86mjl" path="res://components/Achievements/back.png" id="2_1q85v"]
[ext_resource type="Theme" uid="uid://ck7603ob4gflc" path="res://Fonts/Theme.tres" id="2_p5tbu"]
[ext_resource type="PackedScene" uid="uid://dykc1mgg5uopw" path="res://components/Cursor/MouseHandler.tscn" id="2_vij8n"]
[ext_resource type="Texture2D" uid="uid://bypm21lqwg7g0" path="res://components/Achievements/Village 6.png" id="4_1mson"]
[ext_resource type="Texture2D" uid="uid://ur6oiwg6ksns" path="res://components/Achievements/award.svg" id="4_7grt2"]
[ext_resource type="Texture2D" uid="uid://dcj0xniur7dk1" path="res://components/Achievements/thumbnail-mask.png" id="6_dwjjq"]
[ext_resource type="AudioStream" uid="uid://dxac8e02mctgp" path="res://components/Achievements/achievement.wav" id="8_74gug"]
[ext_resource type="AudioStream" uid="uid://4m4dwlrv78l" path="res://components/Achievements/achievement-back.ogg" id="9_c3xir"]
[sub_resource type="RectangleShape2D" id="RectangleShape2D_yajw4"]
size = Vector2(180, 32)
[node name="Achievements" type="Node"]
script = ExtResource("1_fj2tg")
[node name="CanvasLayer" type="CanvasLayer" parent="."]
[node name="Popup" type="Control" parent="CanvasLayer"]
layout_mode = 3
anchors_preset = 3
anchor_left = 1.0
anchor_top = 1.0
anchor_right = 1.0
anchor_bottom = 1.0
offset_left = -140.0
offset_top = -42.0
offset_right = 40.0
offset_bottom = -12.0
grow_horizontal = 0
grow_vertical = 0
[node name="MouseHandler" parent="CanvasLayer/Popup" instance=ExtResource("2_vij8n")]
position = Vector2(62, 15)
[node name="CollisionShape2D" type="CollisionShape2D" parent="CanvasLayer/Popup/MouseHandler"]
position = Vector2(29, 0)
shape = SubResource("RectangleShape2D_yajw4")
[node name="Shadow" type="TextureRect" parent="CanvasLayer/Popup"]
modulate = Color(0, 0, 0, 1)
show_behind_parent = true
layout_mode = 1
anchors_preset = 3
anchor_left = 1.0
anchor_top = 1.0
anchor_right = 1.0
anchor_bottom = 1.0
offset_left = -178.0
offset_top = -29.0
offset_right = 2.0
offset_bottom = 2.0
grow_horizontal = 0
grow_vertical = 0
size_flags_horizontal = 8
size_flags_vertical = 8
theme = ExtResource("2_p5tbu")
texture = ExtResource("2_1q85v")
expand_mode = 1
[node name="Popup" type="TextureRect" parent="CanvasLayer/Popup"]
clip_children = 2
layout_mode = 1
anchors_preset = 6
anchor_left = 1.0
anchor_top = 0.5
anchor_right = 1.0
anchor_bottom = 0.5
offset_left = -180.0
offset_top = -15.0
offset_bottom = 15.0
grow_horizontal = 0
grow_vertical = 2
size_flags_horizontal = 8
size_flags_vertical = 8
texture = ExtResource("2_1q85v")
expand_mode = 1
[node name="Title" type="RichTextLabel" parent="CanvasLayer/Popup/Popup"]
modulate = Color(0.752941, 0.478431, 0.129412, 1)
layout_mode = 1
anchors_preset = 4
anchor_top = 0.5
anchor_bottom = 0.5
offset_left = 46.0
offset_top = -11.0
offset_right = 217.0
offset_bottom = 7.0
grow_vertical = 2
theme_override_colors/font_shadow_color = Color(0, 0, 0, 1)
theme_override_font_sizes/normal_font_size = 7
text = "Achievement Text"
[node name="Body" type="RichTextLabel" parent="CanvasLayer/Popup/Popup"]
layout_mode = 1
anchors_preset = 4
anchor_top = 0.5
anchor_bottom = 0.5
offset_left = 37.0
offset_top = 2.0
offset_right = 223.0
offset_bottom = 18.0
grow_vertical = 2
theme_override_colors/default_color = Color(0.607843, 0.607843, 0.607843, 1)
theme_override_colors/font_shadow_color = Color(0, 0, 0, 1)
theme_override_font_sizes/normal_font_size = 7
text = "Achievement Body"
[node name="AwardShadow" type="TextureRect" parent="CanvasLayer/Popup/Popup"]
modulate = Color(0, 0, 0, 1)
layout_mode = 0
offset_left = 36.0
offset_top = 6.0
offset_right = 45.0
offset_bottom = 15.0
texture = ExtResource("4_7grt2")
expand_mode = 2
[node name="Award" type="TextureRect" parent="CanvasLayer/Popup/Popup"]
modulate = Color(0.752941, 0.478431, 0.129412, 1)
layout_mode = 0
offset_left = 34.5
offset_top = 4.5
offset_right = 43.5
offset_bottom = 13.5
texture = ExtResource("4_7grt2")
expand_mode = 2
[node name="ThumbnailMask" type="TextureRect" parent="CanvasLayer/Popup"]
clip_children = 1
layout_mode = 1
anchors_preset = 4
anchor_top = 0.5
anchor_bottom = 0.5
offset_left = 3.0
offset_top = -12.0
offset_right = 32.0
offset_bottom = 12.0
grow_vertical = 2
texture = ExtResource("6_dwjjq")
expand_mode = 1
[node name="Thumbnail" type="TextureRect" parent="CanvasLayer/Popup/ThumbnailMask"]
layout_mode = 0
offset_right = 29.0
offset_bottom = 24.0
texture = ExtResource("4_1mson")
expand_mode = 1
[node name="AudioStreamPlayer" type="AudioStreamPlayer" parent="."]
stream = ExtResource("8_74gug")
volume_db = -9.043
[node name="AudioStreamPlayer2" type="AudioStreamPlayer" parent="."]
stream = ExtResource("9_c3xir")
volume_db = -17.441
[connection signal="clicked" from="CanvasLayer/Popup/MouseHandler" to="." method="_on_mouse_handler_clicked"]
[connection signal="hovered" from="CanvasLayer/Popup/MouseHandler" to="." method="_on_mouse_handler_hovered"]
[connection signal="unhovered" from="CanvasLayer/Popup/MouseHandler" to="." method="_on_mouse_handler_unhovered"]
[editable path="CanvasLayer/Popup/MouseHandler"]

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 MiB

View file

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bypm21lqwg7g0"
path="res://.godot/imported/Village 6.png-38dba7a44eb73e6643b934b25a9dbbf9.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://components/Achievements/Village 6.png"
dest_files=["res://.godot/imported/Village 6.png-38dba7a44eb73e6643b934b25a9dbbf9.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
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/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

Binary file not shown.

View file

@ -0,0 +1,19 @@
[remap]
importer="oggvorbisstr"
type="AudioStreamOggVorbis"
uid="uid://4m4dwlrv78l"
path="res://.godot/imported/achievement-back.ogg-e15f114c4307f4746154a747d47f126e.oggvorbisstr"
[deps]
source_file="res://components/Achievements/achievement-back.ogg"
dest_files=["res://.godot/imported/achievement-back.ogg-e15f114c4307f4746154a747d47f126e.oggvorbisstr"]
[params]
loop=false
loop_offset=0
bpm=0
beat_count=0
bar_beats=4

Binary file not shown.

View file

@ -0,0 +1,24 @@
[remap]
importer="wav"
type="AudioStreamWAV"
uid="uid://dxac8e02mctgp"
path="res://.godot/imported/achievement.wav-eb6c9e09c6c75764f5cf65335ad5f16a.sample"
[deps]
source_file="res://components/Achievements/achievement.wav"
dest_files=["res://.godot/imported/achievement.wav-eb6c9e09c6c75764f5cf65335ad5f16a.sample"]
[params]
force/8_bit=false
force/mono=false
force/max_rate=false
force/max_rate_hz=44100
edit/trim=false
edit/normalize=false
edit/loop_mode=0
edit/loop_begin=0
edit/loop_end=-1
compress/mode=0

View file

@ -0,0 +1,261 @@
extends Base
## Achievement handler to check and unlock achievements
##
## An achievement handler that will check the available achievements defined in
## both the game files and the mods. When called with triggers will check to see
## if that trigger value unlocks achievements.
signal achievement_unlocked(achievement: String)
const CACHE_TIME = 60000
const POPUP_POP_TIME = 1000
const POPUP_LINGER_TIME = 5000
const POPUP_HIDE_TIME = 1000
const POPUP_BREAK = 1000
const POPUP_HOVER_TIME = 250
@onready var popup = $"CanvasLayer/Popup"
@onready var popup_title = $"CanvasLayer/Popup/Popup/Title"
@onready var popup_body = $"CanvasLayer/Popup/Popup/Body"
@onready var audio = $"AudioStreamPlayer"
@onready var audio2 = $"AudioStreamPlayer2"
enum AchievementState {
ENTERING,
SHOWN,
HOVERED,
EXITING,
HIDDEN
}
var queue = []
var cached_percents = {}
var last_percent_pull: int
var showing_popup = false
var starting_popup_pos
var starting_popup_size
var popup_tween
var popup_timer = 0
var popup_time = 6
#var entering = false
#var exiting = false
#var hovered = false
var achievement_state = AchievementState.HIDDEN
var hovered = false
func _ready():
#_log_category = "ACH"
#_log_icon = "res://components/Logger/scroll-text.svg"
#_log_color = "#a166a1"
super()
_info("Achievements is active")
starting_popup_pos = popup.position
starting_popup_size = popup.size
popup.position.x = starting_popup_pos.x + starting_popup_size.x
popup.modulate = Color.TRANSPARENT
popup.scale = Vector2(0.5, 0.5)
if _triggerer:
_triggerer.listen("any", _on_trigger)
func _on_trigger(data: Dictionary) -> void:
_check_trigger(data.trigger, "Trigger")
func _process(delta):
popup_timer += delta
if popup_timer > popup_time and achievement_state == AchievementState.SHOWN:
_exit_popup()
if not queue.is_empty() and not showing_popup:
_show_popup(queue.pop_front())
if popup_tween and not popup_tween.is_running():
if hovered and achievement_state == AchievementState.SHOWN:
achievement_state = AchievementState.HOVERED
popup_tween = create_tween()
popup_tween.set_parallel()
popup_tween.set_trans(Tween.TRANS_QUAD)
popup_tween.tween_property(popup, "scale", Vector2(1.05, 1.05), float(POPUP_HOVER_TIME) / 1000)
popup_tween.tween_property(popup, "position:x", starting_popup_pos.x - 20, float(POPUP_HOVER_TIME) / 1000)
if not hovered and achievement_state == AchievementState.HOVERED:
achievement_state = AchievementState.SHOWN
popup_tween = create_tween()
popup_tween.set_parallel()
popup_tween.set_trans(Tween.TRANS_QUAD)
popup_tween.tween_property(popup, "scale", Vector2(1, 1), float(POPUP_HOVER_TIME) / 1000)
popup_tween.tween_property(popup, "position:x", starting_popup_pos.x, float(POPUP_HOVER_TIME) / 1000)
func _exit_popup():
achievement_state = AchievementState.EXITING
audio2.play()
if popup_tween: popup_tween.kill()
popup_tween = create_tween()
popup_tween.set_ease(Tween.EASE_IN)
popup_tween.set_trans(Tween.TRANS_BACK)
popup_tween.set_parallel()
popup_tween.tween_property(popup, "modulate", Color.TRANSPARENT, POPUP_POP_TIME / 1000)
popup_tween.tween_property(popup, "scale", Vector2(0.5, 0.5), POPUP_POP_TIME / 1000)
popup_tween.tween_property(popup, "position:x", starting_popup_pos.x + starting_popup_size.x, POPUP_HIDE_TIME / 1000)
popup_tween.tween_interval(POPUP_BREAK / 1000)
popup_tween.chain()
popup_tween.tween_callback(func(): showing_popup = false)
_info("Hiding achievement popup")
func _on_data_persisted(key: String, value, category: PersisterEnums.Scope):
_check_trigger(key, "Data", value)
## Get all of the achievement info
func get_achievements() -> Dictionary:
if not _data:
if (_logger): _logger.warn("Could not find data autoload when getting achievements")
return {}
if not _data.data.has("achievements"):
if (_logger): _logger.warn("Could not find achievement data")
return {}
var local_ach_data = _data.data.achievements.duplicate()
var percents = _get_achievement_percents()
for achievement in _data.data.achievements:
if percents.keys().has(achievement):
local_ach_data.percent = percents[achievement]
return _data.data.achievements
## Get achievement info given the achievement slug
func get_achievement(achievement: String) -> Dictionary:
if not _data:
if _logger: _logger.warn("Could not find data autoload when getting achievement %s" % [achievement])
return {}
if not _data.data.has("achievements"):
if _logger: _logger.warn("Could not find achievement data")
return {}
if not _data.data.achievements.has(achievement):
if _logger: _logger.warn("Could not find achievement %s" % [achievement])
return {}
var achievement_data = _data.data.achievements[achievement].duplicate()
# TODO: Add in achievement percent
return achievement_data
func _show_popup(achievement: String) -> void:
var achievement_data = get_achievement(achievement)
achievement_state = AchievementState.ENTERING
popup_timer = 0
if achievement_data.is_empty():
if _logger: _logger.error("Could not get achievement %s info when trying to show" % [achievement])
return
popup_title.text = achievement_data.name
popup_body.text = achievement_data.description
showing_popup = true
popup.position.x = starting_popup_pos.x + starting_popup_size.x
popup.modulate = Color.TRANSPARENT
popup.scale = Vector2(0.5, 0.5)
#popup.position.y = starting_popup_pos.y + starting_popup_size.y
if popup_tween:
popup_tween.kill()
audio.play()
popup_tween = create_tween()
popup_tween.set_parallel()
popup_tween.set_ease(Tween.EASE_OUT)
popup_tween.set_trans(Tween.TRANS_BACK)
popup_tween.tween_property(popup, "modulate", Color.WHITE, POPUP_POP_TIME / 1000)
popup_tween.tween_property(popup, "scale", Vector2(1, 1), POPUP_POP_TIME / 1000)
popup_tween.tween_property(popup, "position:x", starting_popup_pos.x, POPUP_POP_TIME / 1000)
popup_tween.chain()
popup_tween.tween_callback(func():
achievement_state = AchievementState.SHOWN
)
_info("Showing achievement %s popup" % [achievement])
func _get_achievement_percents() -> Dictionary:
if not last_percent_pull:
return _get_percents_from_db()
if last_percent_pull + CACHE_TIME <= Time.get_ticks_msec():
return cached_percents
return _get_percents_from_db()
func _get_percents_from_db() -> Dictionary:
last_percent_pull = Time.get_ticks_msec()
return {}
func _send_to_db(achievement: String) -> void:
pass
func _check_trigger(key: String, type: String, value = null):
if not _data:
if (_logger): _logger.warn("Could not find data autoload when checking trigger")
return
if not _data.data.has("achievements"):
return
for achievement in _data.data.achievements:
# If the persister does not have the achievement already
if not _persister.get_value(achievement):
var ach_data = _data.data.achievements[achievement]
var valid = false
match type:
"Data":
if ach_data.has("key") and ach_data.key == key:
valid = ach_data.value <= value
"Trigger":
if ach_data.has("trigger") and ach_data.trigger == key:
valid = true
if valid:
achievement_unlocked.emit(achievement)
_persister.persist_data(achievement, true, PersisterEnums.Scope.PERMANENT)
_info("Added achievement %s to queue" % [achievement])
queue.push_back(achievement)
_send_to_db(achievement)
func _on_mouse_handler_hovered():
hovered = true
func _on_mouse_handler_clicked():
if achievement_state != AchievementState.EXITING:
_exit_popup()
func _on_mouse_handler_unhovered():
hovered = false

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-award"><path d="m15.477 12.89 1.515 8.526a.5.5 0 0 1-.81.47l-3.58-2.687a1 1 0 0 0-1.197 0l-3.586 2.686a.5.5 0 0 1-.81-.469l1.514-8.526"/><circle cx="12" cy="8" r="6"/></svg>

After

Width:  |  Height:  |  Size: 368 B

View file

@ -0,0 +1,37 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://ur6oiwg6ksns"
path="res://.godot/imported/award.svg-6bd80af369d65193b7f216d026b9ff51.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://components/Achievements/award.svg"
dest_files=["res://.godot/imported/award.svg-6bd80af369d65193b7f216d026b9ff51.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
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/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
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

View file

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dat440dg86mjl"
path="res://.godot/imported/back.png-7865ce000d117e80cc752a23c0588205.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://components/Achievements/back.png"
dest_files=["res://.godot/imported/back.png-7865ce000d117e80cc752a23c0588205.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
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/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

View file

@ -0,0 +1,8 @@
name: Achievements
short: Achievement handler to check and unlock achievements
description: An achievement handler that will check the available achievements
defined in both the game files and the mods. When called with triggers will
check to see if that trigger value unlocks achievements.
accent: #a166a1
log_category: ACH
icon: res://components/Logger/scroll-text.svg

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 B

View file

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://brmlpo1rv8m47"
path="res://.godot/imported/particle.png-659e7c73fd80f7940a2d61abac8f1984.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://components/Achievements/particle.png"
dest_files=["res://.godot/imported/particle.png-659e7c73fd80f7940a2d61abac8f1984.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
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/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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dpmrungfff7jd"
path="res://.godot/imported/popup-background.png-1f543826c612308bac959317015a3a98.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://components/Achievements/popup-background.png"
dest_files=["res://.godot/imported/popup-background.png-1f543826c612308bac959317015a3a98.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
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/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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View file

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dcj0xniur7dk1"
path="res://.godot/imported/thumbnail-mask.png-9e7311d6f1141413915356d4bb61948c.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://components/Achievements/thumbnail-mask.png"
dest_files=["res://.godot/imported/thumbnail-mask.png-9e7311d6f1141413915356d4bb61948c.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
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/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

View file

@ -0,0 +1,6 @@
[gd_scene load_steps=2 format=3 uid="uid://cjcs6jhw45bj4"]
[ext_resource type="Script" path="res://components/Audio/audio.gd" id="1_c2epj"]
[node name="Audio" type="Node"]
script = ExtResource("1_c2epj")

99
components/Audio/audio.gd Normal file
View file

@ -0,0 +1,99 @@
@icon("res://components/Audio/music.svg")
extends Base
var music_data
var sfx_data
var current_playing_music
var tweens = {}
func _spawned():
if _triggerer:
_triggerer.listen("any", _on_trigger)
music_data = _data.data.music
sfx_data = _data.data.sfx
for music in music_data:
var music_value = music_data[music]
if not _data.data.audio.has(music):
_error("Could not find file for music %s" % [music])
continue
music_value.track = _data.data.audio[music]
var music_object = AudioStreamPlayer.new()
music_object.name = "Music - %s" % [music_value.name]
music_object.stream = music_value.track
add_child(music_object)
music_value.object = music_object
_info("Loaded music %s" % [music])
for sfx in sfx_data:
var sfx_value = sfx_data[sfx]
if not _data.data.audio.has(sfx):
_error("Could not find file for sfx %s" % [sfx])
continue
sfx_value.track = _data.data.audio[sfx]
var sfx_object = AudioStreamPlayer.new()
sfx_object.name = "SFX - %s" % [sfx_value.name]
sfx_object.stream = sfx_value.track
add_child(sfx_object)
sfx_value.object = sfx_object
_info("Loaded sfx %s" % [sfx])
func _on_trigger(data: Dictionary) -> void:
var trigger = data.trigger
if not trigger.begins_with("audio_"):
return
var audio_name = trigger.split("_", false, 1)[1]
for music in music_data:
var music_value = music_data[music]
if not music == audio_name:
continue
if not music_value.has("track"):
continue
if current_playing_music:
if tweens.has(current_playing_music):
tweens[current_playing_music].kill()
tweens[current_playing_music] = create_tween()
tweens[current_playing_music].tween_property(music_data[current_playing_music].object, "volume_db", -30, 1)
tweens[current_playing_music].tween_callback(func():
music_data[current_playing_music].object.stop()
)
if tweens.has(music):
tweens[music].kill()
if data.has("keep_position") and data.keep_position:
music_value.object.play(music_data[current_playing_music].object.get_playback_position())
else:
music_value.object.play()
tweens[music] = create_tween()
tweens[music].tween_property(music_data[music].object, "volume_db", 0, 1)
current_playing_music = music
return
for sfx in sfx_data:
if not sfx == audio_name:
continue
pass

View file

@ -0,0 +1,6 @@
name: Audio
short: ???
description: ???
accent: #32ad61
log_category: AUD
icon: res://components/Audio/music.svg

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-music"><path d="M9 18V5l12-2v13"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="16" r="3"/></svg>

After

Width:  |  Height:  |  Size: 296 B

View file

@ -0,0 +1,37 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bnrlsuxullf0v"
path="res://.godot/imported/music.svg-641a4ffd0c5780599b93a42e5f43eb33.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://components/Audio/music.svg"
dest_files=["res://.godot/imported/music.svg-641a4ffd0c5780599b93a42e5f43eb33.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
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/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
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false

90
components/Base/base.gd Normal file
View file

@ -0,0 +1,90 @@
class_name Base
extends Node
## A base addon
##
## A base addon for shared functionality between all other addons
var _logger
var _data
var _persister
var _triggerer
var _information = {
"log_category": "???",
"accent": "#000000",
"icon": "res://components/Cursor/mouse-pointer-2.svg"
}
var CORE_NODES = {
"Logger": {
"property": "_logger"
},
"Data": {
"property": "_data"
},
"Triggerer": {
"property": "_triggerer",
},
"Persister": {
"property": "_persister",
"connections": {"data_persisted": "_on_data_persisted"}
}
}
func _ready():
for node in CORE_NODES:
# Prevent circular references
if name == node:
break
# Connect up core nodes
var node_value = CORE_NODES[node]
if get_tree().root.has_node(node):
set(node_value.property, get_tree().root.get_node(node))
var property = get(node_value.property)
if node_value.has("connections"):
var connections = node_value.connections
for connection in connections:
var connection_callback = connections[connection]
property.get(connection).connect(get(connection_callback))
if _data and _data.components.has(name):
_information = _data.components[name].information
if _information.has("triggers"):
for trigger in _information.triggers:
_triggerer.listen(trigger, Callable(self, _information.triggers[trigger]))
if has_method("_prespawned"):
call("_prespawned")
_info("%s is active" % [name])
if has_method("_spawned"):
call("_spawned")
_info("%s is ready" % [name])
func _on_data_persisted(key: String, value, category: PersisterEnums.Scope):
pass
func _debug(message: String):
if _logger: _logger.debug(message, { "category": _information.log_category, "image": _information.icon, "color": _information.accent })
func _info(message: String):
if _logger: _logger.info(message, { "category": _information.log_category, "image": _information.icon, "color": _information.accent })
func _warn(message: String):
if _logger: _logger.warn(message, { "category": _information.log_category, "image": _information.icon, "color": _information.accent })
func _error(message: String):
if _logger: _logger.error(message, { "category": _information.log_category, "image": _information.icon, "color": _information.accent })

View file

@ -0,0 +1,21 @@
[gd_scene load_steps=4 format=3 uid="uid://qecwga1b4yqn"]
[ext_resource type="Script" path="res://components/Cursor/cursor.gd" id="1_nmkwm"]
[ext_resource type="Texture2D" uid="uid://yg134s8wlxmi" path="res://icon.svg" id="2_yaf0k"]
[sub_resource type="RectangleShape2D" id="RectangleShape2D_4cq27"]
[node name="Cursor" type="CanvasLayer"]
script = ExtResource("1_nmkwm")
[node name="MouseControl" type="Area2D" parent="."]
[node name="CollisionShape2D" type="CollisionShape2D" parent="MouseControl"]
shape = SubResource("RectangleShape2D_4cq27")
[node name="Sprite2D" type="Sprite2D" parent="MouseControl"]
scale = Vector2(0.15625, 0.15625)
texture = ExtResource("2_yaf0k")
[connection signal="area_entered" from="MouseControl" to="." method="_on_mouse_control_area_entered"]
[connection signal="area_exited" from="MouseControl" to="." method="_on_mouse_control_area_exited"]

View file

@ -0,0 +1,6 @@
[gd_scene load_steps=2 format=3 uid="uid://dykc1mgg5uopw"]
[ext_resource type="Script" path="res://components/Cursor/mouse_handler.gd" id="1_n30mb"]
[node name="MouseHandler" type="Area2D"]
script = ExtResource("1_n30mb")

View file

@ -0,0 +1,30 @@
@icon("res://components/Cursor/mouse-pointer-2.svg")
extends Base
@onready var mouse_control = $"MouseControl"
func _process(delta):
Input.set_mouse_mode(Input.MOUSE_MODE_HIDDEN)
mouse_control.position = mouse_control.get_global_mouse_position()
if Input.is_action_just_pressed("left_click"):
var overlapping_areas = mouse_control.get_overlapping_areas()
overlapping_areas.sort_custom(func(a, b):
return a.z_index > b.z_index
)
for area in overlapping_areas:
if area.has_method("_on_clicked"):
if not area._on_clicked():
break
func _on_mouse_control_area_entered(area):
if area.has_method("_on_hovered"):
area._on_hovered()
func _on_mouse_control_area_exited(area):
if area.has_method("_on_unhovered"):
area._on_unhovered()

View file

@ -0,0 +1,6 @@
name: Cursor
short: ???
description: ???
accent: #35b84b
log_category: CUR
icon: res://components/Cursor/mouse-pointer-2.svg

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-mouse-pointer-2"><path d="m4 4 7.07 17 2.51-7.39L21 11.07z"/></svg>

After

Width:  |  Height:  |  Size: 262 B

View file

@ -0,0 +1,37 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cdu6b7pclsrrg"
path="res://.godot/imported/mouse-pointer-2.svg-528a80312e1a4aed351ba060d183df97.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://components/Cursor/mouse-pointer-2.svg"
dest_files=["res://.godot/imported/mouse-pointer-2.svg-528a80312e1a4aed351ba060d183df97.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
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/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
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-mouse-pointer-click"><path d="m9 9 5 12 1.8-5.2L21 14Z"/><path d="M7.2 2.2 8 5.1"/><path d="m5.1 8-2.9-.8"/><path d="M14 4.1 12 6"/><path d="m6 12-1.9 2"/></svg>

After

Width:  |  Height:  |  Size: 356 B

View file

@ -0,0 +1,37 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://ddkp18the486t"
path="res://.godot/imported/mouse-pointer-click.svg-f0b06ba161b377fd039b4f40e477ff4d.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://components/Cursor/mouse-pointer-click.svg"
dest_files=["res://.godot/imported/mouse-pointer-click.svg-f0b06ba161b377fd039b4f40e477ff4d.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
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/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
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false

View file

@ -0,0 +1,39 @@
@icon("res://components/Cursor/mouse-pointer-click.svg")
extends Area2D
signal clicked
signal hovered
signal unhovered
@export var passthrough = false
var _logger
func _ready():
if get_tree().root.has_node("Logger"):
_logger = get_tree().root.get_node("Logger")
func _on_clicked():
clicked.emit()
#_logger.info("Clicked mouse handler for object →%s←" % [get_parent().name], {
#"color": "#919191",
#"image": "res://components/Cursor/mouse-pointer-click.svg",
#"category": "MOU"
#})
return passthrough
func _on_hovered():
hovered.emit()
#_logger.info("Hovered over mouse handler for object →%s←" % [get_parent().name], {
#"color": "#919191",
#"image": "res://components/Cursor/mouse-pointer-click.svg",
#"category": "MOU"
#})
func _on_unhovered():
unhovered.emit()
#_logger.info("Unhovered mouse handler for object →%s←" % [get_parent().name], {
#"color": "#919191",
#"image": "res://components/Cursor/mouse-pointer-click.svg",
#"category": "MOU"
#})

View file

@ -0,0 +1,6 @@
[gd_scene load_steps=2 format=3 uid="uid://b4o7cekdsf4pu"]
[ext_resource type="Script" path="res://components/Data/data.gd" id="1_xutp1"]
[node name="Data" type="Node"]
script = ExtResource("1_xutp1")

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-book-marked"><path d="M4 19.5v-15A2.5 2.5 0 0 1 6.5 2H20v20H6.5a2.5 2.5 0 0 1 0-5H20"/><polyline points="10 2 10 10 13 7 16 10 16 2"/></svg>

After

Width:  |  Height:  |  Size: 335 B

View file

@ -0,0 +1,37 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://05aeafxrb5ph"
path="res://.godot/imported/book-marked.svg-4d90597eaf7440ba51cd915ad6f20255.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://components/Data/book-marked.svg"
dest_files=["res://.godot/imported/book-marked.svg-4d90597eaf7440ba51cd915ad6f20255.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
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/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
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false

View file

@ -0,0 +1,18 @@
const LOG_CATEGORY = "DATAT"
const NAME = "Data"
func send_log(parent):
parent.tools[NAME].node.info("Test Debug!", LOG_CATEGORY)
func send_debug(parent):
parent.tools[NAME].node.debug("Test Log!", LOG_CATEGORY)
func send_warning(parent):
parent.tools[NAME].node.warn("Test Warning!", LOG_CATEGORY)
func send_error(parent):
parent.tools[NAME].node.error("Test Error!", LOG_CATEGORY)

241
components/Data/data.gd Normal file
View file

@ -0,0 +1,241 @@
@icon("res://components/Data/book-marked.svg")
class_name DataType
extends Base
## Data handler to read in data from files
##
## A data handler that will read in data from txt files and other sources for
## use in various parts of the game. Reads both from the parts folder in the
## main game directory and the mods folder in the user folder to allow users to
## easily mod the game.
var _FILE_FUNCTIONS = {
"*.txt": _read_txt,
"*.png": _read_resource,
"*.png.import": _read_png_import,
"*.ogg": _read_resource,
"*.mp3": _read_resource,
"*.wav": _read_resource,
"*.gd": _read_script_resource,
}
var _FILE_LOCATION_OVERRIDES = {
"*.gd": "scripts",
"*.png.import": "images",
"*.png": "images",
"*.ogg": "audio",
"*.wav": "audio"
}
var data = {}
var components = {}
var location_overrides = {}
func _prespawned():
_information = {
"accent": "#a27155",
"log_category": "DATA",
"icon": "res://components/Data/book-marked.svg"
}
func _spawned():
reload_data()
## Reload the data object by pulling from available sources
func reload_data() -> void:
data = {} # Remove all old mod data
# Open part folder from project (Ignore if none) and if exists set mod data to it
var res_dir = DirAccess.open("res://")
if res_dir.dir_exists("parts"):
data = _read_directory("res://parts")
data = _merge_objects(location_overrides, data)
if res_dir.dir_exists("components"):
location_overrides = {}
components = _read_directory("res://components")
components = _merge_objects(location_overrides, components)
func _merge_objects(object1, object2):
var newObject = {}
for key in object1:
newObject[key] = object1[key]
for key in object2:
if(newObject.has(key)):
if(typeof(newObject[key]) == TYPE_STRING):
newObject[key] = object1[key]
elif(typeof(newObject[key]) == TYPE_OBJECT):
if newObject[key] is Texture:
newObject[key] = object1[key]
else:
newObject[key] = _merge_objects(object1[key], object2[key])
elif(typeof(newObject[key]) == TYPE_DICTIONARY):
newObject[key] = _merge_objects(object1[key], object2[key])
elif(typeof(newObject[key]) == TYPE_ARRAY):
newObject[key] = object1[key] + object2[key]
else:
newObject[key] = object2[key]
return newObject
func _read_directory(path) -> Dictionary:
var dir = DirAccess.open(path)
var local_data = {}
if not dir:
_warn("Could not read directory [%s]" % [path])
return {}
dir.list_dir_begin()
var file_name = dir.get_next()
while file_name != "":
if dir.current_is_dir():
var micro_data = _read_directory("%s/%s" % [path, file_name])
if micro_data:
local_data[file_name] = micro_data
else:
var file_handling = _get_file_handling(file_name)
if (file_handling):
var location_override = _get_location_override(file_name)
if location_override:
var micro_data = file_handling.call("%s/%s" % [path, file_name])
if not location_overrides.has(location_override):
location_overrides[location_override] = {}
location_overrides[location_override][file_name.split(".")[0]] = micro_data
else:
var micro_data = file_handling.call("%s/%s" % [path, file_name])
if micro_data:
local_data[file_name.split(".")[0]] = micro_data
file_name = dir.get_next()
_info("Read directory ♢%s" % [path])
return local_data
func _get_file_handling(file):
var split_file = file.split(".", true, 1)
for file_function in _FILE_FUNCTIONS:
if(file_function == file):
return _FILE_FUNCTIONS[file_function]
var split_file_function = file_function.split(".", true, 1)
if(split_file_function[0] == "*" and split_file_function[1] == split_file[1]):
return _FILE_FUNCTIONS[file_function]
return null
func _read_script_resource(path):
return load(path)
func _read_resource(path):
var song = load(path)
return song
func _read_png_import(path):
var image = load(path.rsplit(".", true, 1)[0])
return image
func _get_location_override(file):
var split_file = file.split(".", true, 1)
for location_override in _FILE_LOCATION_OVERRIDES:
if location_override == file:
return _FILE_LOCATION_OVERRIDES[location_override]
var split_file_function = location_override.split(".", true, 1)
if(split_file_function[0] == "*" and split_file_function[1] == split_file[1]):
return _FILE_LOCATION_OVERRIDES[location_override]
func _read_txt(path) -> Dictionary:
# Open file for reading
var file = FileAccess.open(path, FileAccess.READ)
var content = file.get_as_text()
var local_data = {}
# Separate into lines
var split_content = content.split("\n", false)
# Indentation
var indentation = 0
var indentation_levels = []
# Iterate over everything
for content_piece in split_content:
# Fix Indentation to actual content level
var actual_indentation = _count_indentation(content_piece)
while(actual_indentation < indentation):
indentation -= 1
indentation_levels.pop_back()
# Navigate to current indentation data
var micro_data = local_data
var previous_data = null
var i = 0
while i < indentation:
previous_data = micro_data
micro_data = micro_data[indentation_levels[i]]
i += 1
# Reading
if(content_piece.ends_with("[]")):
# Array handling
var trimmed_content = content_piece.strip_edges().trim_suffix("[]")
indentation += 1
indentation_levels.append(trimmed_content)
micro_data[trimmed_content] = {}
else:
var split_args = content_piece.split(":", true, 1)
if split_args.size() == 2:
# Dict Handling
var key = split_args[0].strip_edges()
var value = split_args[1].strip_edges()
if value.is_valid_int():
value = value.to_int()
micro_data[key] = value
elif split_args.size() == 1:
# Value Handling
var value = split_args[0].strip_edges()
if typeof(micro_data) == TYPE_DICTIONARY:
# TODO: FIX BELOW
if indentation_levels.size() == 0:
continue
if previous_data[indentation_levels[indentation_levels.size()-1]].keys().size() == 0:
previous_data[indentation_levels[indentation_levels.size()-1]] = [split_args[0].strip_edges()]
else:
pass
else:
previous_data[indentation_levels[indentation_levels.size()-1]] += [split_args[0].strip_edges()]
return local_data
func _count_indentation(string: String):
var tabs = 0
for character in string:
if(character == "\t"):
tabs += 1
else:
return tabs
return tabs

View file

@ -0,0 +1,10 @@
name: Data
short: Data handler to read in data from files
description: |
A data handler that will read in data from txt files and other
sources for use in various parts of the game. Reads both from the
parts folder in the main game directory and the mods folder in the
user folder to allow users to easily mod the game.
accent: #a27155
log_category: DATA
icon: res://components/Data/book-marked.svg

View file

@ -0,0 +1,20 @@
debug[]
type: button
name: Send Debug
accent: #11a1a1
function: send_debug
log[]
type: button
name: Send Log
accent: #11a11a
function: send_log
warning[]
type: button
name: Send Warning
accent: #a1a111
function: send_warning
error[]
type: button
name: Send Error
accent: #f13333
function: send_error

View file

@ -0,0 +1,100 @@
[gd_scene load_steps=6 format=3 uid="uid://mhltvrm84abx"]
[ext_resource type="Script" path="res://components/Dialogue/dialogue.gd" id="1_0g08k"]
[ext_resource type="Script" path="res://components/Dialogue/area.gd" id="3_4w6ab"]
[ext_resource type="Texture2D" uid="uid://camtxohytwrqd" path="res://components/Dialogue/textbox.png" id="3_o1ce5"]
[ext_resource type="Texture2D" uid="uid://yg134s8wlxmi" path="res://icon.svg" id="5_s3ups"]
[sub_resource type="RectangleShape2D" id="RectangleShape2D_wsoph"]
size = Vector2(480, 80)
[node name="Dialogue" type="CanvasLayer"]
script = ExtResource("1_0g08k")
[node name="TextBox" type="Control" parent="."]
layout_mode = 3
anchors_preset = 0
offset_left = 80.0
offset_top = 280.0
offset_right = 560.0
offset_bottom = 360.0
pivot_offset = Vector2(240, 80)
[node name="MinimizeHandler" type="Area2D" parent="TextBox"]
visible = false
z_index = 10
script = ExtResource("3_4w6ab")
[node name="CollisionShape2D" type="CollisionShape2D" parent="TextBox/MinimizeHandler"]
position = Vector2(240, 40)
shape = SubResource("RectangleShape2D_wsoph")
[node name="Graphics" type="TextureRect" parent="TextBox"]
layout_mode = 1
anchors_preset = 7
anchor_left = 0.5
anchor_top = 1.0
anchor_right = 0.5
anchor_bottom = 1.0
offset_left = -240.0
offset_top = -80.0
offset_right = 240.0
grow_horizontal = 2
grow_vertical = 0
texture = ExtResource("3_o1ce5")
[node name="TextBoxAvatar" type="TextureRect" parent="TextBox/Graphics"]
layout_mode = 1
anchors_preset = 7
anchor_left = 0.5
anchor_top = 1.0
anchor_right = 0.5
anchor_bottom = 1.0
offset_left = -206.0
offset_top = -104.0
offset_right = -158.0
offset_bottom = -40.0
grow_horizontal = 2
grow_vertical = 0
texture = ExtResource("5_s3ups")
[node name="TextBoxText" type="RichTextLabel" parent="TextBox/Graphics"]
modulate = Color(0.705882, 0.690196, 0.552941, 1)
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -125.0
offset_top = -24.0
offset_right = 226.0
offset_bottom = 30.0
grow_horizontal = 2
grow_vertical = 2
theme_override_colors/font_shadow_color = Color(0, 0, 0, 1)
theme_override_constants/shadow_offset_y = 1
theme_override_constants/shadow_offset_x = 0
theme_override_font_sizes/normal_font_size = 16
text = "This is test text"
[node name="TextBoxName" type="RichTextLabel" parent="TextBox/Graphics"]
modulate = Color(0.705882, 0.690196, 0.552941, 1)
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -237.0
offset_top = 14.0
offset_right = -125.0
offset_bottom = 38.0
grow_horizontal = 2
grow_vertical = 2
theme_override_colors/font_shadow_color = Color(0, 0, 0, 1)
theme_override_constants/shadow_offset_y = 1
theme_override_constants/shadow_offset_x = 0
theme_override_font_sizes/normal_font_size = 16
bbcode_enabled = true
text = "[center]NAME"

View file

@ -0,0 +1,9 @@
extends Area2D
signal clicked
@export var passthrough = false
func _on_clicked():
clicked.emit()
return passthrough

View file

@ -0,0 +1,144 @@
extends Base
var used_lines = []
var mouse_over = false
@onready var text_box = $"TextBox"
@onready var text_box_text = $"TextBox/Graphics/TextBoxText"
@onready var text_box_name = $"TextBox/Graphics/TextBoxName"
@onready var text_box_image = $"TextBox/Graphics/TextBoxAvatar"
@onready var minimize_handler = $"TextBox/MinimizeHandler"
var pop_tween
var last_lines = {}
func _spawned():
text_box.modulate = Color.TRANSPARENT
text_box.scale = Vector2(0, 0)
text_box.position.y = 360
minimize_handler.clicked.connect(_on_clicked)
if _triggerer:
_triggerer.listen("any", _on_trigger)
func _on_trigger(data: Dictionary) -> void:
if has_trigger(data.trigger):
trigger_dialogue(data.trigger)
func _on_clicked():
if pop_tween:
pop_tween.kill()
pop_tween = create_tween()
pop_tween.set_ease(Tween.EASE_IN)
pop_tween.set_trans(Tween.TRANS_BACK)
pop_tween.set_parallel()
pop_tween.tween_property(text_box, "modulate", Color.TRANSPARENT, 0.5)
pop_tween.tween_property(text_box, "scale", Vector2(0, 0), 0.5)
pop_tween.tween_property(text_box, "position:y", 360, 0.5)
pop_tween.chain()
func get_priority_from_string(string: String):
match string:
"low": return 1
"medium": return 2
"high": return 3
func trigger_dialogue(trigger: String):
_info("Dialogue trigger %s triggered" % [trigger])
var dialogue = get_dialogue(trigger)
if not dialogue:
return
var lines = dialogue.values()
if pop_tween:
pop_tween.kill()
#var person = Data.data.people[lines[0].character]
text_box_text.text = lines[0].text
#text_box_image.texture = Data.data.images[lines[0].character]
#text_box_name.text = "[center]%s" % [person.short]
pop_tween = create_tween()
pop_tween.set_ease(Tween.EASE_OUT)
pop_tween.set_trans(Tween.TRANS_BACK)
pop_tween.set_parallel()
pop_tween.tween_property(text_box, "modulate", Color.WHITE, 0.5)
pop_tween.tween_property(text_box, "scale", Vector2(1, 1), 0.5)
pop_tween.tween_property(text_box, "position:y", 280, 0.5)
pop_tween.chain()
#get_parent().move_child(self, get_parent().get_child_count() - 1)
func has_trigger(trigger: String):
var dialogue_files = Data.data.dialogue.values()
for file in dialogue_files:
for key in file:
if file[key].has("trigger"):
if file[key].trigger == trigger:
return true
return false
func get_dialogue(trigger: String):
var dialogue_files = Data.data.dialogue.values()
var combined_object = {}
for file in dialogue_files:
for key in file:
combined_object[key] = file[key]
combined_object[key].key = key
var lines = combined_object.values()
var trigger_lines = lines.filter(func(x): return x.trigger == trigger)
trigger_lines.sort_custom(func(a, b):
var apriority = a.rules.priority if a.rules.has("priority") else "medium"
var bpriority = b.rules.priority if b.rules.has("priority") else "medium"
if get_priority_from_string(apriority) == get_priority_from_string(bpriority):
return randf() < 0.5
return get_priority_from_string(apriority) > get_priority_from_string(bpriority)
)
for line in trigger_lines:
var invalid = false
if last_lines.has(line.trigger) and last_lines[line.trigger] == line.key:
invalid = true
for rule in line.rules:
if rule == "priority":
continue
elif rule == "unique":
if used_lines.has(line.key):
invalid = true
break
else:
var value = Persister.get_value(rule)
if value != line.rules[rule]:
invalid = true
break
if invalid:
continue
last_lines[line.trigger] = line.key
used_lines.push_back(line.key)
return line.lines
return null

View file

@ -0,0 +1,6 @@
name: Dialogue
short: ???
description: ???
accent: #2ec778
log_category: DIA
icon: res://components/Dialogue/message-square-more.svg

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-message-square-more"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/><path d="M8 10h.01"/><path d="M12 10h.01"/><path d="M16 10h.01"/></svg>

After

Width:  |  Height:  |  Size: 360 B

View file

@ -0,0 +1,37 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bwghow6a1p84w"
path="res://.godot/imported/message-square-more.svg-c15333f4fba2c19064690b510c5f7565.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://components/Dialogue/message-square-more.svg"
dest_files=["res://.godot/imported/message-square-more.svg-c15333f4fba2c19064690b510c5f7565.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
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/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
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://camtxohytwrqd"
path="res://.godot/imported/textbox.png-a3656dca7d0232cc5645bc8f60474933.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://components/Dialogue/textbox.png"
dest_files=["res://.godot/imported/textbox.png-a3656dca7d0232cc5645bc8f60474933.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
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/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

View file

@ -0,0 +1,6 @@
[gd_scene load_steps=2 format=3 uid="uid://dvjtjq2j522co"]
[ext_resource type="Script" path="res://components/Leaderboard/leaderboard.gd" id="1_gvlwy"]
[node name="Leaderboard" type="Node"]
script = ExtResource("1_gvlwy")

View file

@ -0,0 +1,6 @@
name: Leaderboard
short: ???
description: ???
accent: #2e4fc7
log_category: LEA
icon: res://components/Leaderboard/trophy.svg

View file

@ -0,0 +1,2 @@
@icon("res://components/Leaderboard/trophy.svg")
extends Base

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-trophy"><path d="M6 9H4.5a2.5 2.5 0 0 1 0-5H6"/><path d="M18 9h1.5a2.5 2.5 0 0 0 0-5H18"/><path d="M4 22h16"/><path d="M10 14.66V17c0 .55-.47.98-.97 1.21C7.85 18.75 7 20.24 7 22"/><path d="M14 14.66V17c0 .55.47.98.97 1.21C16.15 18.75 17 20.24 17 22"/><path d="M18 2H6v7a6 6 0 0 0 12 0V2Z"/></svg>

After

Width:  |  Height:  |  Size: 491 B

View file

@ -0,0 +1,37 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://for54f1or3ir"
path="res://.godot/imported/trophy.svg-50b272fe3a1d033c20559dd811d9f235.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://components/Leaderboard/trophy.svg"
dest_files=["res://.godot/imported/trophy.svg-50b272fe3a1d033c20559dd811d9f235.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
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/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
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false

View file

@ -0,0 +1,6 @@
[gd_scene load_steps=2 format=3 uid="uid://7p8ecy62n2h8"]
[ext_resource type="Script" path="res://components/Logger/logger.gd" id="1_gse6q"]
[node name="Logger" type="Node"]
script = ExtResource("1_gse6q")

View file

@ -0,0 +1,2 @@
func send_log():
pass

View file

@ -0,0 +1,9 @@
name: Logger
short: A logger to log data to relevant locations
description: A logger that logs various forms of data at different log levels to
both built in locations in Godot as well as other components that listen to
the provided log created signal.
accent: #71a255
log_category: LOG
icon: res://components/Logger/scroll-text.svg
version: v1.0.0

View file

@ -0,0 +1,34 @@
const LOG_CATEGORY = "TOOLT"
const NAME = "Logger"
func send_log(parent):
parent.info("Test Log!", {
"image": "res://components/Toolbar/hammer.svg",
"color": "#818181",
"category": "TST"
})
func send_debug(parent):
parent.debug("Test Debug!", {
"image": "res://components/Toolbar/hammer.svg",
"color": "#818181",
"category": "TST"
})
func send_warning(parent):
parent.warn("Test Warn!", {
"image": "res://components/Toolbar/hammer.svg",
"color": "#818181",
"category": "TST"
})
func send_error(parent):
parent.error("Test Error!", {
"image": "res://components/Toolbar/hammer.svg",
"color": "#818181",
"category": "TST"
})

133
components/Logger/logger.gd Normal file
View file

@ -0,0 +1,133 @@
@icon("res://components/Logger/scroll-text.svg")
extends Node
## A logger to log data to relevant locations
##
## A logger that logs various forms of data at different log levels to both
## built in locations in Godot as well as other components that listen to the
## provided log created signal.
signal log_created(message: String, level: LogLevel)
enum LogLevel {
DEBUG,
INFO,
WARN,
ERROR
}
## The log level that should be outputted as a minimum.
@export var log_level: LogLevel
## Log a message at log level debug (meant for troubleshooting).
func debug(message: String, arguments: Dictionary = {}) -> void:
_log(message, LogLevel.DEBUG, arguments)
## Log a message at log level info (log to indicate something happened).
func info(message: String, arguments: Dictionary = {}) -> void:
_log(message, LogLevel.INFO, arguments)
## Log a warning at log level warning (something unexpected happened but it can
## continue).
func warn(message: String, arguments: Dictionary = {}) -> void:
_log(message, LogLevel.WARN, arguments)
## Log an error at log level error (an issue that prevents something from
## functioning).
func error(message: String, arguments: Dictionary = {}) -> void:
_log(message, LogLevel.ERROR, arguments)
func _log(message: String, level: LogLevel, arguments: Dictionary = {}) -> void:
var category = arguments.category if arguments.has("category") and arguments.category else "???"
var color = arguments.color if arguments.has("color") else "olive"
var image = arguments.image if arguments.has("image") and arguments.image else "res://components/Logger/scroll-text.svg"
var adjusted_message = _clean_message(message)
var constructed_message = "[color=%s][%s][/color] [img= width=12 height=12 valign=center]%s[/img] %s" % [color, category, image, adjusted_message]
print_rich(constructed_message)
log_created.emit(constructed_message, level)
func _clean_message(message: String) -> String:
var cleans = [
{
"type": "button",
"regex": "μ(.*)μ",
"color": Color.html("#a4bf37")
},
{
"type": "key",
"regex": "<(.*)>",
"color": Color.html("#42ad24")
},
{
"type": "tool",
"regex": "λ(.*)λ",
"color": Color.html("#bf9d37")
},
{
"type": "object",
"regex": "→(.*)←",
"color": Color.html("#854322")
},
{
"type": "path",
"regex": "♢(.*)♢",
"color": Color.html("#22852e")
},
{
"type": "function",
"regex": "(.*)",
"color": Color.html("#ad2452")
},
{
"type": "trigger",
"regex": "∧(.*)∧",
"color": Color.html("#ad2d24")
},
{
"type": "category",
"regex": "\\{(.*)\\}",
"color": Color.html("#ad9b24")
},
{
"type": "value",
"regex": "\\|(.*)\\|",
"color": Color.TEAL
}
]
var adjusted_message = message
for clean in cleans:
adjusted_message = _replace_regex_color(adjusted_message, clean.regex, clean.color)
return adjusted_message
func _replace_regex_color(message: String, regex_string: String, color: Color) -> String:
return _replace_regex(message, regex_string, "[color=" + color.to_html() + "]%s[/color]")
func _replace_regex(message: String, regex_string: String, new_content: String) -> String:
var adjusted_message = message
var stripped_message = message
var regex = RegEx.new()
regex.compile(regex_string)
var result = regex.search(adjusted_message)
while result:
var before_content = adjusted_message.substr(0, result.get_start())
var after_content = adjusted_message.substr(result.get_end(), adjusted_message.length())
var template_string = "%s" + new_content + "%s"
adjusted_message = template_string % [before_content, result.get_string(1), after_content]
result = regex.search(adjusted_message)
return adjusted_message

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-scroll-text"><path d="M15 12h-5"/><path d="M15 8h-5"/><path d="M19 17V5a2 2 0 0 0-2-2H4"/><path d="M8 21h12a2 2 0 0 0 2-2v-1a1 1 0 0 0-1-1H11a1 1 0 0 0-1 1v1a2 2 0 1 1-4 0V5a2 2 0 1 0-4 0v2a1 1 0 0 0 1 1h3"/></svg>

After

Width:  |  Height:  |  Size: 409 B

View file

@ -0,0 +1,37 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bt1irjjewldcq"
path="res://.godot/imported/scroll-text.svg-3edd1135d80784e9e14ee4871d671a9a.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://components/Logger/scroll-text.svg"
dest_files=["res://.godot/imported/scroll-text.svg-3edd1135d80784e9e14ee4871d671a9a.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
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/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
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false

View file

@ -0,0 +1,11 @@
log_level[]
name: Log Level
description: The level of info you want as a minimum to be logged to
relevant locations.
category: misc
default: LogLevel.WARN
values[]
LogLevel.DEBUG
LogLevel.INFO
LogLevel.WARN
LogLevel.ERROR

View file

@ -0,0 +1,24 @@
debug[]
type: button
name: Send Debug
accent: #11a1a1
function: send_debug
test[]
type: label
name: Testing Label
accent: #11a1cc
log[]
type: button
name: Send Log
accent: #11a11a
function: send_log
warning[]
type: button
name: Send Warning
accent: #a1a111
function: send_warning
error[]
type: button
name: Send Error
accent: #f13333
function: send_error

691
components/Menu/Menu.tscn Normal file
View file

@ -0,0 +1,691 @@
[gd_scene load_steps=14 format=3 uid="uid://dcu7jrwg24hg1"]
[ext_resource type="Script" path="res://components/Menu/menu.gd" id="1_f186y"]
[ext_resource type="Theme" uid="uid://ck7603ob4gflc" path="res://Fonts/Theme.tres" id="1_fowhs"]
[ext_resource type="Shader" path="res://components/Menu/god_rays.gdshader" id="1_n8upd"]
[ext_resource type="Script" path="res://components/Menu/populate_from_metadata.gd" id="3_727p5"]
[ext_resource type="PackedScene" uid="uid://cmyjaeahyipq4" path="res://components/Menu/MenuButton.tscn" id="5_goj86"]
[ext_resource type="Script" path="res://components/Menu/credits.gd" id="6_b724h"]
[sub_resource type="ShaderMaterial" id="ShaderMaterial_ygqow"]
shader = ExtResource("1_n8upd")
shader_parameter/angle = 0.525
shader_parameter/position = 0.27
shader_parameter/spread = 0.595
shader_parameter/cutoff = 0.0710001
shader_parameter/falloff = 0.845
shader_parameter/edge_fade = 0.34
shader_parameter/speed = 1.0
shader_parameter/ray1_density = 8.0
shader_parameter/ray2_density = 30.0
shader_parameter/ray2_intensity = 0.169
shader_parameter/color = Vector4(1, 0.9, 0.65, 0.1)
shader_parameter/hdr = false
shader_parameter/seed = 5.0
[sub_resource type="Animation" id="Animation_5jiy0"]
resource_name = "show_main"
length = 5.0
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("CanvasLayer/MainMenu/GameInfo/GameTitle:position")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 0.0333333, 0.0666667, 0.1, 0.133333, 0.166667, 0.2, 0.233333, 0.266667, 0.3, 0.333333, 0.366667, 0.4, 0.433333, 0.466667, 0.5),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
"update": 0,
"values": [Vector2(135, 168), Vector2(185.297, 168), Vector2(226.423, 168), Vector2(259.221, 168), Vector2(284.538, 168), Vector2(303.219, 168), Vector2(316.109, 168), Vector2(324.053, 168), Vector2(327.897, 168), Vector2(328.486, 168), Vector2(326.665, 168), Vector2(323.28, 168), Vector2(319.175, 168), Vector2(315.197, 168), Vector2(312.19, 168), Vector2(311, 168)]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("CanvasLayer/MainMenu/GameInfo/GameUnderline:position")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0, 0.0333333, 0.0666667, 0.1, 0.133333, 0.166667, 0.2, 0.233333, 0.266667, 0.3, 0.333333, 0.366667, 0.4, 0.433333, 0.466667, 0.5),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
"update": 0,
"values": [Vector2(650, 194), Vector2(582.556, 194), Vector2(527.41, 194), Vector2(483.431, 194), Vector2(449.483, 194), Vector2(424.434, 194), Vector2(407.15, 194), Vector2(396.497, 194), Vector2(391.343, 194), Vector2(390.553, 194), Vector2(392.995, 194), Vector2(397.534, 194), Vector2(403.038, 194), Vector2(408.372, 194), Vector2(412.404, 194), Vector2(414, 194)]
}
tracks/2/type = "value"
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/path = NodePath("CanvasLayer/MainMenu/GameInfo/Author:position")
tracks/2/interp = 1
tracks/2/loop_wrap = true
tracks/2/keys = {
"times": PackedFloat32Array(0, 0.0333333, 0.0666667, 0.1, 0.133333, 0.166667, 0.2, 0.233333, 0.266667, 0.3, 0.333333, 0.366667, 0.4, 0.433333, 0.466667, 0.5),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
"update": 0,
"values": [Vector2(648, 199), Vector2(561.123, 199), Vector2(490.088, 199), Vector2(433.436, 199), Vector2(389.707, 199), Vector2(357.44, 199), Vector2(335.176, 199), Vector2(321.454, 199), Vector2(314.814, 199), Vector2(313.797, 199), Vector2(316.942, 199), Vector2(322.79, 199), Vector2(329.879, 199), Vector2(336.751, 199), Vector2(341.944, 199), Vector2(344, 199)]
}
tracks/3/type = "value"
tracks/3/imported = false
tracks/3/enabled = true
tracks/3/path = NodePath("CanvasLayer/MainMenu/Rays:position")
tracks/3/interp = 1
tracks/3/loop_wrap = true
tracks/3/keys = {
"times": PackedFloat32Array(0, 0.0333333, 0.0666667, 0.1, 0.133333, 0.166667, 0.2, 0.233333, 0.266667, 0.3, 0.333333, 0.366667, 0.4, 0.433333, 0.466667, 0.5),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
"update": 0,
"values": [Vector2(0, 0), Vector2(32.0074, 0), Vector2(58.1781, 0), Vector2(79.0498, 0), Vector2(95.1607, 0), Vector2(107.048, 0), Vector2(115.251, 0), Vector2(120.307, 0), Vector2(122.753, 0), Vector2(123.127, 0), Vector2(121.969, 0), Vector2(119.814, 0), Vector2(117.202, 0), Vector2(114.671, 0), Vector2(112.757, 0), Vector2(112, 0)]
}
tracks/4/type = "value"
tracks/4/imported = false
tracks/4/enabled = true
tracks/4/path = NodePath("CanvasLayer/MainMenu/MenuButtons/PlayButton:position")
tracks/4/interp = 1
tracks/4/loop_wrap = true
tracks/4/keys = {
"times": PackedFloat32Array(0.9, 0.933333, 0.966667, 1, 1.03333, 1.06667, 1.1, 1.13333, 1.16667, 1.2),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
"update": 0,
"values": [Vector2(-110, 128), Vector2(-39.3658, 128), Vector2(9.80145, 128), Vector2(41.0148, 128), Vector2(57.7873, 128), Vector2(63.6323, 128), Vector2(62.0629, 128), Vector2(56.5923, 128), Vector2(50.7336, 128), Vector2(48, 128)]
}
tracks/5/type = "value"
tracks/5/imported = false
tracks/5/enabled = true
tracks/5/path = NodePath("CanvasLayer/MainMenu/MenuButtons/OptionsButton:position")
tracks/5/interp = 1
tracks/5/loop_wrap = true
tracks/5/keys = {
"times": PackedFloat32Array(1.15, 1.18333, 1.21667, 1.25, 1.28333, 1.31667, 1.35, 1.38333, 1.41667, 1.45),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
"update": 0,
"values": [Vector2(-110, 160), Vector2(-32.2129, 160), Vector2(21.9332, 160), Vector2(56.3074, 160), Vector2(74.7784, 160), Vector2(81.2154, 160), Vector2(79.487, 160), Vector2(73.4624, 160), Vector2(67.0104, 160), Vector2(64, 160)]
}
tracks/6/type = "value"
tracks/6/imported = false
tracks/6/enabled = true
tracks/6/path = NodePath("CanvasLayer/MainMenu/MenuButtons/CreditsButton:position")
tracks/6/interp = 1
tracks/6/loop_wrap = true
tracks/6/keys = {
"times": PackedFloat32Array(1.4, 1.43333, 1.46667, 1.5, 1.53333, 1.56667, 1.6, 1.63333, 1.66667, 1.7),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
"update": 0,
"values": [Vector2(-110, 192), Vector2(-25.0601, 192), Vector2(34.065, 192), Vector2(71.6, 192), Vector2(91.7696, 192), Vector2(98.7984, 192), Vector2(96.9111, 192), Vector2(90.3325, 192), Vector2(83.2872, 192), Vector2(80, 192)]
}
tracks/7/type = "value"
tracks/7/imported = false
tracks/7/enabled = true
tracks/7/path = NodePath("CanvasLayer/MainMenu/MenuButtons/QuitButton:position")
tracks/7/interp = 1
tracks/7/loop_wrap = true
tracks/7/keys = {
"times": PackedFloat32Array(1.65, 1.68333, 1.71667, 1.75, 1.78333, 1.81667, 1.85, 1.88333, 1.91667, 1.95),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
"update": 0,
"values": [Vector2(-110, 224), Vector2(-17.9072, 224), Vector2(46.1968, 224), Vector2(86.8927, 224), Vector2(108.761, 224), Vector2(116.381, 224), Vector2(114.335, 224), Vector2(107.203, 224), Vector2(99.5641, 224), Vector2(96, 224)]
}
[sub_resource type="Animation" id="Animation_u1e5j"]
length = 0.001
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("CanvasLayer/MainMenu/GameInfo/GameTitle:position")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector2(135, 168)]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("CanvasLayer/MainMenu/GameInfo/GameUnderline:position")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector2(650, 194)]
}
tracks/2/type = "value"
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/path = NodePath("CanvasLayer/MainMenu/GameInfo/Author:position")
tracks/2/interp = 1
tracks/2/loop_wrap = true
tracks/2/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector2(648, 199)]
}
tracks/3/type = "value"
tracks/3/imported = false
tracks/3/enabled = true
tracks/3/path = NodePath("CanvasLayer/MainMenu/Rays:position")
tracks/3/interp = 1
tracks/3/loop_wrap = true
tracks/3/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector2(0, 0)]
}
tracks/4/type = "value"
tracks/4/imported = false
tracks/4/enabled = true
tracks/4/path = NodePath("CanvasLayer/MainMenu/MenuButtons/PlayButton:position")
tracks/4/interp = 1
tracks/4/loop_wrap = true
tracks/4/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector2(-110, 128)]
}
tracks/5/type = "value"
tracks/5/imported = false
tracks/5/enabled = true
tracks/5/path = NodePath("CanvasLayer/MainMenu/MenuButtons/OptionsButton:position")
tracks/5/interp = 1
tracks/5/loop_wrap = true
tracks/5/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector2(-110, 160)]
}
tracks/6/type = "value"
tracks/6/imported = false
tracks/6/enabled = true
tracks/6/path = NodePath("CanvasLayer/MainMenu/MenuButtons/CreditsButton:position")
tracks/6/interp = 1
tracks/6/loop_wrap = true
tracks/6/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector2(-110, 192)]
}
tracks/7/type = "value"
tracks/7/imported = false
tracks/7/enabled = true
tracks/7/path = NodePath("CanvasLayer/MainMenu/MenuButtons/QuitButton:position")
tracks/7/interp = 1
tracks/7/loop_wrap = true
tracks/7/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector2(-110, 224)]
}
[sub_resource type="Animation" id="Animation_ob40t"]
resource_name = "hide_main"
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("CanvasLayer/MainMenu/MenuButtons/PlayButton:position")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 0.0333333, 0.0666667, 0.1, 0.133333, 0.166667, 0.2, 0.233333, 0.266667, 0.3, 0.333333, 0.366667, 0.4, 0.433333, 0.466667, 0.5),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
"update": 0,
"values": [Vector2(48, 128), Vector2(27.6356, 128), Vector2(8.67555, 128), Vector2(-8.88, 128), Vector2(-25.0311, 128), Vector2(-39.7778, 128), Vector2(-53.12, 128), Vector2(-65.0578, 128), Vector2(-75.5911, 128), Vector2(-84.72, 128), Vector2(-92.4444, 128), Vector2(-98.7645, 128), Vector2(-103.68, 128), Vector2(-107.191, 128), Vector2(-109.298, 128), Vector2(-110, 128)]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("CanvasLayer/MainMenu/MenuButtons/OptionsButton:position")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0, 0.0333333, 0.0666667, 0.1, 0.133333, 0.166667, 0.2, 0.233333, 0.266667, 0.3, 0.333333, 0.366667, 0.4, 0.433333, 0.466667, 0.5),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
"update": 0,
"values": [Vector2(64, 160), Vector2(41.5733, 160), Vector2(20.6933, 160), Vector2(1.36, 160), Vector2(-16.4267, 160), Vector2(-32.6667, 160), Vector2(-47.36, 160), Vector2(-60.5067, 160), Vector2(-72.1067, 160), Vector2(-82.16, 160), Vector2(-90.6667, 160), Vector2(-97.6267, 160), Vector2(-103.04, 160), Vector2(-106.907, 160), Vector2(-109.227, 160), Vector2(-110, 160)]
}
tracks/2/type = "value"
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/path = NodePath("CanvasLayer/MainMenu/MenuButtons/CreditsButton:position")
tracks/2/interp = 1
tracks/2/loop_wrap = true
tracks/2/keys = {
"times": PackedFloat32Array(0, 0.0333333, 0.0666667, 0.1, 0.133333, 0.166667, 0.2, 0.233333, 0.266667, 0.3, 0.333333, 0.366667, 0.4, 0.433333, 0.466667, 0.5),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
"update": 0,
"values": [Vector2(80, 192), Vector2(55.5111, 192), Vector2(32.7111, 192), Vector2(11.6, 192), Vector2(-7.82223, 192), Vector2(-25.5556, 192), Vector2(-41.6, 192), Vector2(-55.9556, 192), Vector2(-68.6222, 192), Vector2(-79.6, 192), Vector2(-88.8889, 192), Vector2(-96.4889, 192), Vector2(-102.4, 192), Vector2(-106.622, 192), Vector2(-109.156, 192), Vector2(-110, 192)]
}
tracks/3/type = "value"
tracks/3/imported = false
tracks/3/enabled = true
tracks/3/path = NodePath("CanvasLayer/MainMenu/MenuButtons/QuitButton:position")
tracks/3/interp = 1
tracks/3/loop_wrap = true
tracks/3/keys = {
"times": PackedFloat32Array(0, 0.0333333, 0.0666667, 0.1, 0.133333, 0.166667, 0.2, 0.233333, 0.266667, 0.3, 0.333333, 0.366667, 0.4, 0.433333, 0.466667, 0.5),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
"update": 0,
"values": [Vector2(96, 224), Vector2(69.4489, 224), Vector2(44.7289, 224), Vector2(21.84, 224), Vector2(0.782219, 224), Vector2(-18.4445, 224), Vector2(-35.84, 224), Vector2(-51.4044, 224), Vector2(-65.1378, 224), Vector2(-77.04, 224), Vector2(-87.1111, 224), Vector2(-95.3511, 224), Vector2(-101.76, 224), Vector2(-106.338, 224), Vector2(-109.084, 224), Vector2(-110, 224)]
}
tracks/4/type = "value"
tracks/4/imported = false
tracks/4/enabled = true
tracks/4/path = NodePath("CanvasLayer/MainMenu/GameInfo/GameTitle:position")
tracks/4/interp = 1
tracks/4/loop_wrap = true
tracks/4/keys = {
"times": PackedFloat32Array(0, 0.0333333, 0.0666667, 0.1, 0.133333, 0.166667, 0.2, 0.233333, 0.266667, 0.3, 0.333333, 0.366667, 0.4, 0.433333, 0.466667, 0.5),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
"update": 0,
"values": [Vector2(311, 168), Vector2(288.316, 168), Vector2(267.196, 168), Vector2(247.64, 168), Vector2(229.649, 168), Vector2(213.222, 168), Vector2(198.36, 168), Vector2(185.062, 168), Vector2(173.329, 168), Vector2(163.16, 168), Vector2(154.556, 168), Vector2(147.516, 168), Vector2(142.04, 168), Vector2(138.129, 168), Vector2(135.782, 168), Vector2(135, 168)]
}
tracks/5/type = "value"
tracks/5/imported = false
tracks/5/enabled = true
tracks/5/path = NodePath("CanvasLayer/MainMenu/GameInfo/GameUnderline:position")
tracks/5/interp = 1
tracks/5/loop_wrap = true
tracks/5/keys = {
"times": PackedFloat32Array(0, 0.0333333, 0.0666667, 0.1, 0.133333, 0.166667, 0.2, 0.233333, 0.266667, 0.3, 0.333333),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
"update": 0,
"values": [Vector2(414, 194), Vector2(458.84, 194), Vector2(498.96, 194), Vector2(534.36, 194), Vector2(565.04, 194), Vector2(591, 194), Vector2(612.24, 194), Vector2(628.76, 194), Vector2(640.56, 194), Vector2(647.64, 194), Vector2(650, 194)]
}
tracks/6/type = "value"
tracks/6/imported = false
tracks/6/enabled = true
tracks/6/path = NodePath("CanvasLayer/MainMenu/GameInfo/Author:position")
tracks/6/interp = 1
tracks/6/loop_wrap = true
tracks/6/keys = {
"times": PackedFloat32Array(0, 0.0333333, 0.0666667, 0.1, 0.133333, 0.166667, 0.2, 0.233333, 0.266667, 0.3, 0.333333, 0.366667, 0.4, 0.433333, 0.466667, 0.5),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
"update": 0,
"values": [Vector2(344, 199), Vector2(383.182, 199), Vector2(419.662, 199), Vector2(453.44, 199), Vector2(484.516, 199), Vector2(512.889, 199), Vector2(538.56, 199), Vector2(561.529, 199), Vector2(581.796, 199), Vector2(599.36, 199), Vector2(614.222, 199), Vector2(626.382, 199), Vector2(635.84, 199), Vector2(642.596, 199), Vector2(646.649, 199), Vector2(648, 199)]
}
tracks/7/type = "value"
tracks/7/imported = false
tracks/7/enabled = true
tracks/7/path = NodePath("CanvasLayer/MainMenu/Rays:position")
tracks/7/interp = 1
tracks/7/loop_wrap = true
tracks/7/keys = {
"times": PackedFloat32Array(0, 0.0333333, 0.0666667, 0.1, 0.133333, 0.166667, 0.2, 0.233333, 0.266667, 0.3, 0.333333, 0.366667, 0.4, 0.433333, 0.466667, 0.5),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
"update": 0,
"values": [Vector2(112, 0), Vector2(97.5644, 0), Vector2(84.1244, 0), Vector2(71.68, 0), Vector2(60.2311, 0), Vector2(49.7778, 0), Vector2(40.32, 0), Vector2(31.8578, 0), Vector2(24.3911, 0), Vector2(17.92, 0), Vector2(12.4445, 0), Vector2(7.96444, 0), Vector2(4.48, 0), Vector2(1.99111, 0), Vector2(0.49778, 0), Vector2(0, 0)]
}
[sub_resource type="Animation" id="Animation_2xxnd"]
resource_name = "show_credits"
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("CanvasLayer/MainMenu/MenuButtons/PlayButton:position")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 0.0333333, 0.0666667, 0.1, 0.133333, 0.166667, 0.2, 0.233333, 0.266667, 0.3, 0.333333, 0.366667, 0.4, 0.433333, 0.466667, 0.5),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
"update": 0,
"values": [Vector2(48, 128), Vector2(27.6356, 128), Vector2(8.67555, 128), Vector2(-8.88, 128), Vector2(-25.0311, 128), Vector2(-39.7778, 128), Vector2(-53.12, 128), Vector2(-65.0578, 128), Vector2(-75.5911, 128), Vector2(-84.72, 128), Vector2(-92.4444, 128), Vector2(-98.7645, 128), Vector2(-103.68, 128), Vector2(-107.191, 128), Vector2(-109.298, 128), Vector2(-110, 128)]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("CanvasLayer/MainMenu/MenuButtons/OptionsButton:position")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0, 0.0333333, 0.0666667, 0.1, 0.133333, 0.166667, 0.2, 0.233333, 0.266667, 0.3, 0.333333, 0.366667, 0.4, 0.433333, 0.466667, 0.5),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
"update": 0,
"values": [Vector2(64, 160), Vector2(41.5733, 160), Vector2(20.6933, 160), Vector2(1.36, 160), Vector2(-16.4267, 160), Vector2(-32.6667, 160), Vector2(-47.36, 160), Vector2(-60.5067, 160), Vector2(-72.1067, 160), Vector2(-82.16, 160), Vector2(-90.6667, 160), Vector2(-97.6267, 160), Vector2(-103.04, 160), Vector2(-106.907, 160), Vector2(-109.227, 160), Vector2(-110, 160)]
}
tracks/2/type = "value"
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/path = NodePath("CanvasLayer/MainMenu/MenuButtons/CreditsButton:position")
tracks/2/interp = 1
tracks/2/loop_wrap = true
tracks/2/keys = {
"times": PackedFloat32Array(0, 0.0333333, 0.0666667, 0.1, 0.133333, 0.166667, 0.2, 0.233333, 0.266667, 0.3, 0.333333, 0.366667, 0.4, 0.433333, 0.466667, 0.5),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
"update": 0,
"values": [Vector2(80, 192), Vector2(55.5111, 192), Vector2(32.7111, 192), Vector2(11.6, 192), Vector2(-7.82223, 192), Vector2(-25.5556, 192), Vector2(-41.6, 192), Vector2(-55.9556, 192), Vector2(-68.6222, 192), Vector2(-79.6, 192), Vector2(-88.8889, 192), Vector2(-96.4889, 192), Vector2(-102.4, 192), Vector2(-106.622, 192), Vector2(-109.156, 192), Vector2(-110, 192)]
}
tracks/3/type = "value"
tracks/3/imported = false
tracks/3/enabled = true
tracks/3/path = NodePath("CanvasLayer/MainMenu/MenuButtons/QuitButton:position")
tracks/3/interp = 1
tracks/3/loop_wrap = true
tracks/3/keys = {
"times": PackedFloat32Array(0, 0.0333333, 0.0666667, 0.1, 0.133333, 0.166667, 0.2, 0.233333, 0.266667, 0.3, 0.333333, 0.366667, 0.4, 0.433333, 0.466667, 0.5),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
"update": 0,
"values": [Vector2(96, 224), Vector2(69.4489, 224), Vector2(44.7289, 224), Vector2(21.84, 224), Vector2(0.782219, 224), Vector2(-18.4445, 224), Vector2(-35.84, 224), Vector2(-51.4044, 224), Vector2(-65.1378, 224), Vector2(-77.04, 224), Vector2(-87.1111, 224), Vector2(-95.3511, 224), Vector2(-101.76, 224), Vector2(-106.338, 224), Vector2(-109.084, 224), Vector2(-110, 224)]
}
tracks/4/type = "value"
tracks/4/imported = false
tracks/4/enabled = true
tracks/4/path = NodePath("CanvasLayer/MainMenu/GameInfo/GameTitle:position")
tracks/4/interp = 1
tracks/4/loop_wrap = true
tracks/4/keys = {
"times": PackedFloat32Array(0, 0.0333333, 0.0666667, 0.1, 0.133333, 0.166667, 0.2, 0.233333, 0.266667, 0.3, 0.333333, 0.366667, 0.4, 0.433333, 0.466667, 0.5),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
"update": 0,
"values": [Vector2(311, 168), Vector2(354.049, 168), Vector2(394.129, 168), Vector2(431.24, 168), Vector2(465.382, 168), Vector2(496.556, 168), Vector2(524.76, 168), Vector2(549.996, 168), Vector2(572.262, 168), Vector2(591.56, 168), Vector2(607.889, 168), Vector2(621.249, 168), Vector2(631.64, 168), Vector2(639.062, 168), Vector2(643.516, 168), Vector2(645, 168)]
}
tracks/5/type = "value"
tracks/5/imported = false
tracks/5/enabled = true
tracks/5/path = NodePath("CanvasLayer/MainMenu/GameInfo/GameUnderline:position")
tracks/5/interp = 1
tracks/5/loop_wrap = true
tracks/5/keys = {
"times": PackedFloat32Array(0, 0.0333333, 0.0666667, 0.1, 0.133333, 0.166667, 0.2, 0.233333, 0.266667, 0.3, 0.333333),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
"update": 0,
"values": [Vector2(414, 194), Vector2(458.84, 194), Vector2(498.96, 194), Vector2(534.36, 194), Vector2(565.04, 194), Vector2(591, 194), Vector2(612.24, 194), Vector2(628.76, 194), Vector2(640.56, 194), Vector2(647.64, 194), Vector2(650, 194)]
}
tracks/6/type = "value"
tracks/6/imported = false
tracks/6/enabled = true
tracks/6/path = NodePath("CanvasLayer/MainMenu/GameInfo/Author:position")
tracks/6/interp = 1
tracks/6/loop_wrap = true
tracks/6/keys = {
"times": PackedFloat32Array(0, 0.0333333, 0.0666667, 0.1, 0.133333, 0.166667, 0.2, 0.233333, 0.266667, 0.3, 0.333333, 0.366667, 0.4, 0.433333, 0.466667, 0.5),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
"update": 0,
"values": [Vector2(344, 199), Vector2(383.182, 199), Vector2(419.662, 199), Vector2(453.44, 199), Vector2(484.516, 199), Vector2(512.889, 199), Vector2(538.56, 199), Vector2(561.529, 199), Vector2(581.796, 199), Vector2(599.36, 199), Vector2(614.222, 199), Vector2(626.382, 199), Vector2(635.84, 199), Vector2(642.596, 199), Vector2(646.649, 199), Vector2(648, 199)]
}
tracks/7/type = "value"
tracks/7/imported = false
tracks/7/enabled = true
tracks/7/path = NodePath("CanvasLayer/MainMenu/Rays:position")
tracks/7/interp = 1
tracks/7/loop_wrap = true
tracks/7/keys = {
"times": PackedFloat32Array(0, 0.0333333, 0.0666667, 0.1, 0.133333, 0.166667, 0.2, 0.233333, 0.266667, 0.3, 0.333333, 0.366667, 0.4, 0.433333, 0.466667, 0.5),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
"update": 0,
"values": [Vector2(112, 0), Vector2(97.5644, 0), Vector2(84.1244, 0), Vector2(71.68, 0), Vector2(60.2311, 0), Vector2(49.7778, 0), Vector2(40.32, 0), Vector2(31.8578, 0), Vector2(24.3911, 0), Vector2(17.92, 0), Vector2(12.4445, 0), Vector2(7.96444, 0), Vector2(4.48, 0), Vector2(1.99111, 0), Vector2(0.49778, 0), Vector2(0, 0)]
}
[sub_resource type="Animation" id="Animation_awvye"]
resource_name = "hide_credits"
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("CanvasLayer/MainMenu/MenuButtons/PlayButton:position")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 0.0333333, 0.0666667, 0.1, 0.133333, 0.166667, 0.2, 0.233333, 0.266667, 0.3, 0.333333, 0.366667, 0.4, 0.433333, 0.466667, 0.5),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
"update": 0,
"values": [Vector2(-110, 128), Vector2(-89.6356, 128), Vector2(-70.6756, 128), Vector2(-53.12, 128), Vector2(-36.9689, 128), Vector2(-22.2222, 128), Vector2(-8.87999, 128), Vector2(3.05778, 128), Vector2(13.5911, 128), Vector2(22.72, 128), Vector2(30.4444, 128), Vector2(36.7645, 128), Vector2(41.68, 128), Vector2(45.1911, 128), Vector2(47.2978, 128), Vector2(48, 128)]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("CanvasLayer/MainMenu/MenuButtons/OptionsButton:position")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0, 0.0333333, 0.0666667, 0.1, 0.133333, 0.166667, 0.2, 0.233333, 0.266667, 0.3, 0.333333, 0.366667, 0.4, 0.433333, 0.466667, 0.5),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
"update": 0,
"values": [Vector2(-110, 160), Vector2(-87.5733, 160), Vector2(-66.6933, 160), Vector2(-47.36, 160), Vector2(-29.5733, 160), Vector2(-13.3333, 160), Vector2(1.36001, 160), Vector2(14.5067, 160), Vector2(26.1067, 160), Vector2(36.16, 160), Vector2(44.6667, 160), Vector2(51.6267, 160), Vector2(57.04, 160), Vector2(60.9067, 160), Vector2(63.2267, 160), Vector2(64, 160)]
}
tracks/2/type = "value"
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/path = NodePath("CanvasLayer/MainMenu/MenuButtons/CreditsButton:position")
tracks/2/interp = 1
tracks/2/loop_wrap = true
tracks/2/keys = {
"times": PackedFloat32Array(0, 0.0333333, 0.0666667, 0.1, 0.133333, 0.166667, 0.2, 0.233333, 0.266667, 0.3, 0.333333, 0.366667, 0.4, 0.433333, 0.466667, 0.5),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
"update": 0,
"values": [Vector2(-110, 192), Vector2(-85.5111, 192), Vector2(-62.7111, 192), Vector2(-41.6, 192), Vector2(-22.1778, 192), Vector2(-4.44444, 192), Vector2(11.6, 192), Vector2(25.9556, 192), Vector2(38.6222, 192), Vector2(49.6, 192), Vector2(58.8889, 192), Vector2(66.4889, 192), Vector2(72.4, 192), Vector2(76.6222, 192), Vector2(79.1555, 192), Vector2(80, 192)]
}
tracks/3/type = "value"
tracks/3/imported = false
tracks/3/enabled = true
tracks/3/path = NodePath("CanvasLayer/MainMenu/MenuButtons/QuitButton:position")
tracks/3/interp = 1
tracks/3/loop_wrap = true
tracks/3/keys = {
"times": PackedFloat32Array(0, 0.0333333, 0.0666667, 0.1, 0.133333, 0.166667, 0.2, 0.233333, 0.266667, 0.3, 0.333333, 0.366667, 0.4, 0.433333, 0.466667, 0.5),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
"update": 0,
"values": [Vector2(-110, 224), Vector2(-83.4489, 224), Vector2(-58.7289, 224), Vector2(-35.84, 224), Vector2(-14.7822, 224), Vector2(4.44445, 224), Vector2(21.84, 224), Vector2(37.4044, 224), Vector2(51.1378, 224), Vector2(63.04, 224), Vector2(73.1111, 224), Vector2(81.3511, 224), Vector2(87.76, 224), Vector2(92.3378, 224), Vector2(95.0844, 224), Vector2(96, 224)]
}
tracks/4/type = "value"
tracks/4/imported = false
tracks/4/enabled = true
tracks/4/path = NodePath("CanvasLayer/MainMenu/GameInfo/GameTitle:position")
tracks/4/interp = 1
tracks/4/loop_wrap = true
tracks/4/keys = {
"times": PackedFloat32Array(0, 0.0333333, 0.0666667, 0.1, 0.133333, 0.166667, 0.2, 0.233333, 0.266667, 0.3, 0.333333, 0.366667, 0.4, 0.433333, 0.466667, 0.5),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
"update": 0,
"values": [Vector2(645, 168), Vector2(601.951, 168), Vector2(561.871, 168), Vector2(524.76, 168), Vector2(490.618, 168), Vector2(459.444, 168), Vector2(431.24, 168), Vector2(406.004, 168), Vector2(383.738, 168), Vector2(364.44, 168), Vector2(348.111, 168), Vector2(334.751, 168), Vector2(324.36, 168), Vector2(316.938, 168), Vector2(312.484, 168), Vector2(311, 168)]
}
tracks/5/type = "value"
tracks/5/imported = false
tracks/5/enabled = true
tracks/5/path = NodePath("CanvasLayer/MainMenu/GameInfo/GameUnderline:position")
tracks/5/interp = 1
tracks/5/loop_wrap = true
tracks/5/keys = {
"times": PackedFloat32Array(0.0666667, 0.1, 0.133333, 0.166667, 0.2, 0.233333, 0.266667, 0.3, 0.333333, 0.366667, 0.4, 0.433333, 0.466667, 0.5),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
"update": 0,
"values": [Vector2(650, 194), Vector2(615.089, 194), Vector2(582.97, 194), Vector2(553.645, 194), Vector2(527.112, 194), Vector2(503.373, 194), Vector2(482.426, 194), Vector2(464.272, 194), Vector2(448.911, 194), Vector2(436.343, 194), Vector2(426.568, 194), Vector2(419.586, 194), Vector2(415.396, 194), Vector2(414, 194)]
}
tracks/6/type = "value"
tracks/6/imported = false
tracks/6/enabled = true
tracks/6/path = NodePath("CanvasLayer/MainMenu/GameInfo/Author:position")
tracks/6/interp = 1
tracks/6/loop_wrap = true
tracks/6/keys = {
"times": PackedFloat32Array(0, 0.0333333, 0.0666667, 0.1, 0.133333, 0.166667, 0.2, 0.233333, 0.266667, 0.3, 0.333333, 0.366667, 0.4, 0.433333, 0.466667, 0.5),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
"update": 0,
"values": [Vector2(648, 199), Vector2(608.818, 199), Vector2(572.338, 199), Vector2(538.56, 199), Vector2(507.484, 199), Vector2(479.111, 199), Vector2(453.44, 199), Vector2(430.471, 199), Vector2(410.204, 199), Vector2(392.64, 199), Vector2(377.778, 199), Vector2(365.618, 199), Vector2(356.16, 199), Vector2(349.404, 199), Vector2(345.351, 199), Vector2(344, 199)]
}
tracks/7/type = "value"
tracks/7/imported = false
tracks/7/enabled = true
tracks/7/path = NodePath("CanvasLayer/MainMenu/Rays:position")
tracks/7/interp = 1
tracks/7/loop_wrap = true
tracks/7/keys = {
"times": PackedFloat32Array(0, 0.0333333, 0.0666667, 0.1, 0.133333, 0.166667, 0.2, 0.233333, 0.266667, 0.3, 0.333333, 0.366667, 0.4, 0.433333, 0.466667, 0.5),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
"update": 0,
"values": [Vector2(0, 0), Vector2(14.4356, 0), Vector2(27.8756, 0), Vector2(40.32, 0), Vector2(51.7689, 0), Vector2(62.2222, 0), Vector2(71.68, 0), Vector2(80.1422, 0), Vector2(87.6089, 0), Vector2(94.08, 0), Vector2(99.5555, 0), Vector2(104.036, 0), Vector2(107.52, 0), Vector2(110.009, 0), Vector2(111.502, 0), Vector2(112, 0)]
}
[sub_resource type="AnimationLibrary" id="AnimationLibrary_twm3r"]
_data = {
"RESET": SubResource("Animation_u1e5j"),
"hide_credits": SubResource("Animation_awvye"),
"hide_main": SubResource("Animation_ob40t"),
"show_credits": SubResource("Animation_2xxnd"),
"show_main": SubResource("Animation_5jiy0")
}
[node name="Menu" type="Node"]
script = ExtResource("1_f186y")
[node name="CanvasLayer" type="CanvasLayer" parent="."]
[node name="MainMenu" type="Control" parent="CanvasLayer"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme = ExtResource("1_fowhs")
[node name="Rays" type="ColorRect" parent="CanvasLayer/MainMenu"]
z_index = 100
material = SubResource("ShaderMaterial_ygqow")
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="AnimationPlayer" type="AnimationPlayer" parent="CanvasLayer/MainMenu"]
root_node = NodePath("../../..")
libraries = {
"": SubResource("AnimationLibrary_twm3r")
}
[node name="GameInfo" type="Control" parent="CanvasLayer/MainMenu"]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="GameTitle" type="RichTextLabel" parent="CanvasLayer/MainMenu/GameInfo"]
z_index = 200
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -185.0
offset_top = -12.0
offset_right = 183.0
offset_bottom = 28.0
grow_horizontal = 2
grow_vertical = 2
theme_override_font_sizes/normal_font_size = 24
bbcode_enabled = true
text = "[center]Game Title"
script = ExtResource("3_727p5")
key = "name"
[node name="GameUnderline" type="ColorRect" parent="CanvasLayer/MainMenu/GameInfo"]
z_index = 200
layout_mode = 1
anchors_preset = 6
anchor_left = 1.0
anchor_top = 0.5
anchor_right = 1.0
anchor_bottom = 0.5
offset_left = 10.0
offset_top = 14.0
offset_right = 330.525
offset_bottom = 16.0
grow_horizontal = 0
grow_vertical = 2
[node name="Author" type="RichTextLabel" parent="CanvasLayer/MainMenu/GameInfo"]
z_index = 200
layout_mode = 1
anchors_preset = 6
anchor_left = 1.0
anchor_top = 0.5
anchor_right = 1.0
anchor_bottom = 0.5
offset_left = 8.0
offset_top = 19.0
offset_right = 296.0
offset_bottom = 59.0
grow_horizontal = 0
grow_vertical = 2
bbcode_enabled = true
text = "[right]by Team Auboreal"
script = ExtResource("3_727p5")
key = "author"
alignment = "right"
[node name="MenuButtons" type="Control" parent="CanvasLayer/MainMenu"]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="PlayButton" parent="CanvasLayer/MainMenu/MenuButtons" instance=ExtResource("5_goj86")]
layout_mode = 0
anchors_preset = 0
anchor_top = 0.0
anchor_bottom = 0.0
offset_left = -110.0
offset_top = 128.0
offset_right = -19.13
offset_bottom = 152.515
grow_vertical = 1
[node name="OptionsButton" parent="CanvasLayer/MainMenu/MenuButtons" instance=ExtResource("5_goj86")]
layout_mode = 0
anchors_preset = 0
anchor_top = 0.0
anchor_bottom = 0.0
offset_left = -110.0
offset_top = 160.0
offset_right = -19.13
offset_bottom = 184.515
grow_vertical = 1
text = "Options"
[node name="CreditsButton" parent="CanvasLayer/MainMenu/MenuButtons" instance=ExtResource("5_goj86")]
layout_mode = 0
anchors_preset = 0
anchor_top = 0.0
anchor_bottom = 0.0
offset_left = -110.0
offset_top = 192.0
offset_right = -19.13
offset_bottom = 216.515
grow_vertical = 1
text = "Credits"
[node name="QuitButton" parent="CanvasLayer/MainMenu/MenuButtons" instance=ExtResource("5_goj86")]
layout_mode = 0
anchors_preset = 0
anchor_top = 0.0
anchor_bottom = 0.0
offset_left = -110.0
offset_top = 224.0
offset_right = -19.13
offset_bottom = 248.515
grow_vertical = 1
text = "Quit"
[node name="Credits" type="Control" parent="CanvasLayer/MainMenu"]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
script = ExtResource("6_b724h")
[connection signal="clicked" from="CanvasLayer/MainMenu/MenuButtons/PlayButton" to="." method="_on_play_button_clicked"]
[connection signal="clicked" from="CanvasLayer/MainMenu/MenuButtons/OptionsButton" to="." method="_on_options_button_clicked"]
[connection signal="clicked" from="CanvasLayer/MainMenu/MenuButtons/CreditsButton" to="." method="_on_credits_button_clicked"]
[connection signal="clicked" from="CanvasLayer/MainMenu/MenuButtons/QuitButton" to="." method="_on_quit_button_clicked"]

View file

@ -0,0 +1,45 @@
[gd_scene load_steps=5 format=3 uid="uid://cmyjaeahyipq4"]
[ext_resource type="Script" path="res://components/Menu/menu_button.gd" id="1_kxfx8"]
[ext_resource type="PackedScene" uid="uid://dykc1mgg5uopw" path="res://components/Cursor/MouseHandler.tscn" id="2_g6apf"]
[ext_resource type="Script" path="res://components/Menu/background_highlight.gd" id="3_cxaw3"]
[sub_resource type="RectangleShape2D" id="RectangleShape2D_oahx4"]
size = Vector2(147, 22)
[node name="MenuButton" type="RichTextLabel"]
clip_contents = false
anchors_preset = 4
anchor_top = 0.5
anchor_bottom = 0.5
offset_left = 48.0
offset_top = -52.0
offset_right = 138.87
offset_bottom = -27.485
grow_vertical = 2
theme_override_font_sizes/normal_font_size = 16
bbcode_enabled = true
text = "Play"
script = ExtResource("1_kxfx8")
[node name="MouseHandler" parent="." instance=ExtResource("2_g6apf")]
[node name="CollisionShape2D" type="CollisionShape2D" parent="MouseHandler"]
position = Vector2(36.5, 7)
shape = SubResource("RectangleShape2D_oahx4")
[node name="BackgroundHighlight" type="ColorRect" parent="."]
show_behind_parent = true
layout_mode = 0
offset_left = -420.0
offset_top = -8.0
offset_right = -142.0
offset_bottom = 22.0
color = Color(0, 0, 0, 1)
script = ExtResource("3_cxaw3")
[connection signal="clicked" from="MouseHandler" to="." method="_on_play_mouse_handler_clicked"]
[connection signal="hovered" from="MouseHandler" to="." method="_on_mouse_handler_hovered"]
[connection signal="hovered" from="MouseHandler" to="BackgroundHighlight" method="_on_mouse_handler_hovered"]
[connection signal="unhovered" from="MouseHandler" to="." method="_on_mouse_handler_unhovered"]
[connection signal="unhovered" from="MouseHandler" to="BackgroundHighlight" method="_on_mouse_handler_unhovered"]

View file

@ -0,0 +1,35 @@
extends ColorRect
var tween
func _on_mouse_handler_hovered() -> void:
if tween:
tween.kill()
tween = create_tween()
tween.set_ease(Tween.EASE_OUT)
tween.set_trans(Tween.TRANS_BACK)
tween.tween_property(self, "position:x", -136, 0.5)
tween.set_ease(Tween.EASE_IN_OUT)
tween.set_trans(Tween.TRANS_QUAD)
tween.tween_property(self, "position:x", -128, 0.25)
tween.set_ease(Tween.EASE_IN_OUT)
tween.tween_property(self, "position:x", -132, 0.25)
tween.tween_callback(func():
tween = create_tween()
tween.set_loops()
tween.set_ease(Tween.EASE_IN_OUT)
tween.set_trans(Tween.TRANS_QUAD)
tween.tween_property(self, "position:x", -136, 1)
tween.tween_property(self, "position:x", -132, 1)
)
func _on_mouse_handler_unhovered() -> void:
if tween:
tween.kill()
tween = create_tween()
tween.set_ease(Tween.EASE_OUT)
tween.set_trans(Tween.TRANS_BACK)
tween.tween_property(self, "position:x", -420, 0.5)

View file

@ -0,0 +1,69 @@
extends Control
var _data
const TEXT_PADDING = 30
var items = []
var tween
func _ready() -> void:
if get_tree().root.has_node("Data"):
_data = get_tree().root.get_node("Data")
if _data.data.has("metadata") and _data.data.metadata.has("credits"):
var credits = _data.data.metadata.credits
var sections = credits.keys()
var y = 50
for section in sections:
var section_text = RichTextLabel.new()
section_text.position = Vector2(-120, y)
section_text.size = Vector2(40, TEXT_PADDING)
section_text.bbcode_enabled = true
section_text.text = "[center]%s" % [section]
add_child(section_text)
items.push_back(section_text)
y += TEXT_PADDING
var people = credits[section].keys()
for person in people:
var person_text = RichTextLabel.new()
person_text.position = Vector2(-120, y)
person_text.size = Vector2(40, TEXT_PADDING)
person_text.bbcode_enabled = true
person_text.text = "[center]%s" % [person]
add_child(person_text)
items.push_back(person_text)
y += TEXT_PADDING
var links = credits[section][person].keys()
for link in links:
var url = credits[section][person][link]
y += TEXT_PADDING
func show_credits():
if tween:
tween.kill()
tween = create_tween()
tween.set_ease(Tween.EASE_OUT)
tween.set_trans(Tween.TRANS_BACK)
for item in items:
tween.tween_property(item, "position:x", 320, 0.25)
func hide_credits():
if tween:
tween.kill()
tween = create_tween()
tween.set_parallel()
tween.set_ease(Tween.EASE_OUT)
tween.set_trans(Tween.TRANS_QUAD)
for item in items:
tween.tween_property(item, "position:x", -120, 0.25)

View file

@ -0,0 +1,109 @@
/*
Shader from Godot Shaders - the free shader library.
godotshaders.com/shader/god-rays
Feel free to use, improve and change this shader according to your needs
and consider sharing the modified result on godotshaders.com.
*/
shader_type canvas_item;
uniform float angle = -0.3;
uniform float position = -0.2;
uniform float spread : hint_range(0.0, 1.0) = 0.5;
uniform float cutoff : hint_range(-1.0, 1.0) = 0.1;
uniform float falloff : hint_range(0.0, 1.0) = 0.2;
uniform float edge_fade : hint_range(0.0, 1.0) = 0.15;
uniform float speed = 1.0;
uniform float ray1_density = 8.0;
uniform float ray2_density = 30.0;
uniform float ray2_intensity : hint_range(0.0, 1.0) = 0.3;
uniform vec4 color = vec4(1.0, 0.9, 0.65, 0.8);
uniform bool hdr = false;
uniform float seed = 5.0;
uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, filter_linear_mipmap;
// Random and noise functions from Book of Shader's chapter on Noise.
float random(vec2 _uv) {
return fract(sin(dot(_uv.xy,
vec2(12.9898, 78.233))) *
43758.5453123);
}
float noise (in vec2 uv) {
vec2 i = floor(uv);
vec2 f = fract(uv);
// Four corners in 2D of a tile
float a = random(i);
float b = random(i + vec2(1.0, 0.0));
float c = random(i + vec2(0.0, 1.0));
float d = random(i + vec2(1.0, 1.0));
// Smooth Interpolation
// Cubic Hermine Curve. Same as SmoothStep()
vec2 u = f * f * (3.0-2.0 * f);
// Mix 4 coorners percentages
return mix(a, b, u.x) +
(c - a)* u.y * (1.0 - u.x) +
(d - b) * u.x * u.y;
}
mat2 rotate(float _angle){
return mat2(vec2(cos(_angle), -sin(_angle)),
vec2(sin(_angle), cos(_angle)));
}
vec4 screen(vec4 base, vec4 blend){
return 1.0 - (1.0 - base) * (1.0 - blend);
}
void fragment()
{
// Rotate, skew and move the UVs
vec2 transformed_uv = ( rotate(angle) * (UV - position) ) / ( (UV.y + spread) - (UV.y * spread) );
// Animate the ray according the the new transformed UVs
vec2 ray1 = vec2(transformed_uv.x * ray1_density + sin(TIME * 0.1 * speed) * (ray1_density * 0.2) + seed, 1.0);
vec2 ray2 = vec2(transformed_uv.x * ray2_density + sin(TIME * 0.2 * speed) * (ray1_density * 0.2) + seed, 1.0);
// Cut off the ray's edges
float cut = step(cutoff, transformed_uv.x) * step(cutoff, 1.0 - transformed_uv.x);
ray1 *= cut;
ray2 *= cut;
// Apply the noise pattern (i.e. create the rays)
float rays;
if (hdr){
// This is not really HDR, but check this to not clamp the two merged rays making
// their values go over 1.0. Can make for some nice effect
rays = noise(ray1) + (noise(ray2) * ray2_intensity);
}
else{
rays = clamp(noise(ray1) + (noise(ray2) * ray2_intensity), 0., 1.);
}
// Fade out edges
rays *= smoothstep(0.0, falloff, (1.0 - UV.y)); // Bottom
rays *= smoothstep(0.0 + cutoff, edge_fade + cutoff, transformed_uv.x); // Left
rays *= smoothstep(0.0 + cutoff, edge_fade + cutoff, 1.0 - transformed_uv.x); // Right
// Color to the rays
vec3 shine = vec3(rays) * color.rgb;
// Try different blending modes for a nicer effect. "Screen" is included in the code,
// but take a look at https://godotshaders.com/snippet/blending-modes/ for more.
// With "Screen" blend mode:
shine = screen(texture(SCREEN_TEXTURE, SCREEN_UV), vec4(color)).rgb;
COLOR = vec4(shine, rays * color.a);
}

41
components/Menu/menu.gd Normal file
View file

@ -0,0 +1,41 @@
extends Base
@onready var animation_player: AnimationPlayer = $CanvasLayer/MainMenu/AnimationPlayer
@onready var credits: Control = $CanvasLayer/MainMenu/Credits
var menu_state = "start"
func _process(delta: float) -> void:
if menu_state == "start" and Input.is_action_just_pressed("left_click"):
menu_state = "main"
animation_player.play("show_main")
if Input.is_action_just_pressed("escape"):
match menu_state:
"main":
menu_state = "start"
animation_player.play("hide_main")
"credits":
menu_state = "main"
animation_player.play("hide_credits")
credits.hide_credits()
func _on_play_button_clicked() -> void:
if _data:
get_tree().change_scene_to_packed(load(_data.data.metadata.start_scene))
else:
_error("No start scene defined")
func _on_options_button_clicked() -> void:
pass # Replace with function body.
func _on_credits_button_clicked() -> void:
menu_state = "credits"
animation_player.play("show_credits")
credits.show_credits()
func _on_quit_button_clicked() -> void:
get_tree().quit()

View file

@ -0,0 +1,24 @@
extends RichTextLabel
signal clicked
var color_tween
func _on_play_mouse_handler_clicked() -> void:
clicked.emit()
func _on_mouse_handler_hovered() -> void:
if color_tween:
color_tween.kill()
color_tween = create_tween()
color_tween.tween_property(self, "self_modulate", Color.GOLD, 0.25)
func _on_mouse_handler_unhovered() -> void:
if color_tween:
color_tween.kill()
color_tween = create_tween()
color_tween.tween_property(self, "self_modulate", Color.WHITE, 0.25)

View file

@ -0,0 +1,13 @@
extends RichTextLabel
@export var key := ""
@export var alignment := "center"
var _data
func _ready() -> void:
if get_tree().root.has_node("Data"):
_data = get_tree().root.get_node("Data")
if _data.data.has("metadata"):
text = "[%s]%s" % [alignment, _data.data.metadata[key]]

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-square-menu"><rect width="18" height="18" x="3" y="3" rx="2"/><path d="M7 8h10"/><path d="M7 12h10"/><path d="M7 16h10"/></svg>

After

Width:  |  Height:  |  Size: 329 B

View file

@ -0,0 +1,37 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cp8tbups5d6p7"
path="res://.godot/imported/square-menu.svg-7299523024a845ac9eafa86412b4d5c3.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://components/Menu/square-menu.svg"
dest_files=["res://.godot/imported/square-menu.svg-7299523024a845ac9eafa86412b4d5c3.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
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/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
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false

View file

@ -0,0 +1,12 @@
[gd_scene load_steps=2 format=3 uid="uid://pht0rn54n3t8"]
[ext_resource type="Script" path="res://components/Persister/persister.gd" id="1_taxaa"]
[node name="Persister" type="Node"]
script = ExtResource("1_taxaa")
[node name="Timer" type="Timer" parent="."]
wait_time = 20.0
autostart = true
[connection signal="timeout" from="Timer" to="." method="_on_timer_timeout"]

View file

@ -0,0 +1,11 @@
class_name PersisterEnums
enum Scope {
PERMANENT, # Stays forever
SAVE, # Persists through a save
GAME, # Persists through runs
RUN, # Persists through an entire run of the game
ROUND, # Persists through a round (if applicable, e.g. between ifa round is 2 mins between shops)
ROOM, # Persists within a game room (if applicable)
UNKNOWN
}

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-hard-drive"><line x1="22" x2="2" y1="12" y2="12"/><path d="M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z"/><line x1="6" x2="6.01" y1="16" y2="16"/><line x1="10" x2="10.01" y1="16" y2="16"/></svg>

After

Width:  |  Height:  |  Size: 451 B

View file

@ -0,0 +1,37 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bru35jf108ajj"
path="res://.godot/imported/hard-drive.svg-f9677d2ad3a8226891a78779d376d996.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://components/Persister/hard-drive.svg"
dest_files=["res://.godot/imported/hard-drive.svg-f9677d2ad3a8226891a78779d376d996.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
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/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
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false

View file

@ -0,0 +1,10 @@
name: Persister
short: Data persister to persist data through locations
description: A data persister that is used to persist data through the game,
run, round, or room. A function is called to set data with a key in one
of the categories and then other functions can be called to clear
the data for a key or all data in a category.
accent: #a1a166
log_category: PER
icon: res://components/Persister/hard-drive.svg
version: v1.0.0

View file

@ -0,0 +1,5 @@
func save_one(parent):
parent.change_save(1)
func save_two(parent):
parent.change_save(2)

View file

@ -0,0 +1,334 @@
@icon("res://components/Persister/hard-drive.svg")
extends Base
## Data persister to persist data through locations
##
## A data persister that is used to persist data through the game, run, round,
## or room. A function is called to set data with a key in one of the categories
## and then other functions can be called to clear the data for a key or all
## data in a category.
signal data_persisted(key: String, value, category: PersisterEnums.Scope)
var _persisted = {}
func _spawned():
if _triggerer:
_info("Connecting to data scope triggers")
_triggerer.listen("game", _on_game_triggered)
_triggerer.listen("run", _on_run_triggered)
_triggerer.listen("round", _on_round_triggered)
_triggerer.listen("room", _on_room_triggered)
_load()
## Store data in a category
func persist_data(key: String, value, category := PersisterEnums.Scope.RUN) -> void:
# Only allow ints, bools or strings to be persisted and as Strings
if value is int:
value = str(value)
if value is bool:
value = str(value)
if not value is String:
_warn("Attempted to persist data for key <%s> with an invalid data type |%s|" % [key, type_string(typeof(value))])
return
# Create category if does not exist
if not _persisted.has(category):
_info("Created new persister category {%s}" % [_get_category_name(category)])
_persisted[category] = {}
# If key is already set to value exit early
if _persisted[category].has(key) and _persisted[category][key] == value:
return
_info("Set key <%s> in category {%s} to value |%s|" % [key, _get_category_name(category), value])
_persisted[category][key] = value
_emit_change(key, value, category)
## Get the value associated with a key in the highest priority or specified category
func get_value(key: String, category: PersisterEnums.Scope = PersisterEnums.Scope.UNKNOWN):
if category == PersisterEnums.Scope.UNKNOWN:
category = _get_key_category(key)
if category == PersisterEnums.Scope.UNKNOWN:
return null
if _persisted[category][key].is_valid_int():
return int(_persisted[category][key])
if _persisted[category][key] == "true" || _persisted[category][key] == "false":
return _persisted[category][key] == "true"
return _persisted[category][key]
## Delete data associated with a key from a certain category
func clear_data(key: String, category := PersisterEnums.Scope.RUN) -> void:
if not _persisted.has(category):
_info("Attempted to clear key <%s> in category {%s} but the category did not exist" % [key, _get_category_name(category)])
return
if not _persisted[category].has(key):
_info("Attempted to clear key <%s> in category {%s} but it did not exist" % [key, _get_category_name(category)])
return
_info("Cleared key <%s> in category {%s}" % [key, _get_category_name(category)])
_persisted[category].erase(key)
_emit_removal(key, category)
## Delete a category including all data within it
func clear_category(category := PersisterEnums.Scope.RUN) -> void:
if not _persisted.has(category):
_error("Attempted to clear category {%s} but it did not exist" % [_get_category_name(category)])
return
var keys = _persisted[category].keys()
_info("Cleared category {%s}" % [_get_category_name(category)])
_persisted.erase(category)
for key in keys:
_emit_removal(key, category)
## Add a number to a number value with the given key from a certain category
func change_value(key: String, value: int, category := PersisterEnums.Scope.RUN) -> void:
if not _persisted.has(category):
_persisted[category] = {}
if not _persisted[category].has(key):
persist_data(key, value, category)
return
if is_nan(int(_persisted[category][key])):
_error("Attempted to add number |%d| to key <%s> in category {%s} that is not a number (value: |%s|)" % [value, key, category, _persisted[category][key]])
return
var old_value = int(_persisted[category][key])
_info("Added number |%d| to key <%s> in category {%s} (old: |%d|) (new: |%d|)" % [value, key, _get_category_name(category), old_value, old_value + value])
persist_data(key, value + old_value, category)
func change_save(index: int):
_save()
persist_data("save", index)
_load()
func save():
_save()
func _emit_change(key: String, value: String, category: PersisterEnums.Scope) -> void:
var key_category = _get_key_category(key)
# Only emit change if the category set has the highest priority
if key_category == category:
if is_nan(int(value)):
data_persisted.emit(key, value, category)
else:
data_persisted.emit(key, int(value), category)
func _emit_removal(key: String, category: PersisterEnums.Scope) -> void:
var key_category = _get_key_category(key)
if key_category == PersisterEnums.Scope.UNKNOWN:
return
var category_priority = _get_category_priority(category)
var key_category_priority = _get_category_priority(key_category)
if category_priority > key_category_priority:
var value = _persister[key_category][key]
if is_nan(int(value)):
data_persisted.emit(key, value, key_category)
else:
data_persisted.emit(key, int(value), key_category)
func _get_category_name(category: PersisterEnums.Scope) -> String:
match category:
PersisterEnums.Scope.PERMANENT:
return "permanent"
PersisterEnums.Scope.SAVE:
return "save"
PersisterEnums.Scope.GAME:
return "game"
PersisterEnums.Scope.RUN:
return "run"
PersisterEnums.Scope.ROUND:
return "round"
PersisterEnums.Scope.ROOM:
return "room"
_:
return "unknown"
func _get_category_priority(category: PersisterEnums.Scope) -> int:
match category:
PersisterEnums.Scope.PERMANENT:
return 1
PersisterEnums.Scope.SAVE:
return 2
PersisterEnums.Scope.GAME:
return 3
PersisterEnums.Scope.RUN:
return 4
PersisterEnums.Scope.ROUND:
return 5
PersisterEnums.Scope.ROOM:
return 6
_:
return 0
func _get_key_category(key: String) -> PersisterEnums.Scope:
var category_order = []
for category in PersisterEnums.Scope:
var category_value = PersisterEnums.Scope[category]
category_order.push_back(
{
"priority": _get_category_priority(category_value),
"category": category_value
}
)
category_order.sort_custom(func(a, b):
return a.priority > b.priority
)
for value in category_order:
var category = value.category
if _persisted.has(category):
if _persisted[category].has(key):
return category
return PersisterEnums.Scope.UNKNOWN
func _get_all_category_data(category: PersisterEnums.Scope) -> Dictionary:
if not _persisted.has(category):
return {}
return _persisted[category]
func _on_game_triggered(data: Dictionary) -> void:
clear_category(PersisterEnums.Scope.GAME)
func _on_run_triggered(data: Dictionary) -> void:
clear_category(PersisterEnums.Scope.RUN)
func _on_round_triggered(data: Dictionary) -> void:
clear_category(PersisterEnums.Scope.ROUND)
func _on_room_triggered(data: Dictionary) -> void:
clear_category(PersisterEnums.Scope.ROOM)
func _save():
_info("Saving")
_save_permanent_data()
_save_save_data()
func _load():
_info("Loading")
_load_permanent_data()
if not get_value("save"):
_info("Creating starting save")
persist_data("save", 1, PersisterEnums.Scope.PERMANENT)
clear_category(PersisterEnums.Scope.SAVE)
_load_save_data()
func _save_permanent_data():
var save_file = FileAccess.open("user://data.json", FileAccess.WRITE)
var data = _get_all_category_data(PersisterEnums.Scope.PERMANENT)
var data_string = JSON.stringify(data)
_info("Saving permanent save data")
save_file.store_line(data_string)
func _save_save_data():
if not FileAccess.file_exists("user://saves"):
DirAccess.make_dir_absolute("user://saves")
var save = get_value("save")
var save_file = FileAccess.open("user://saves/save-%d.json" % [save], FileAccess.WRITE)
var data = _get_all_category_data(PersisterEnums.Scope.SAVE)
var data_string = JSON.stringify(data)
_info("Saving save save data")
save_file.store_line(data_string)
func _load_permanent_data():
var save_file = FileAccess.open("user://data.json", FileAccess.READ)
if not save_file:
return
_info("Loading permanent save data")
var json_string = ""
while save_file.get_position() < save_file.get_length():
json_string += save_file.get_line()
var json = JSON.new()
var result = json.parse(json_string)
var data = json.get_data()
for key in data:
Persister.persist_data(key, data[key], PersisterEnums.Scope.PERMANENT)
func _load_save_data():
var save = get_value("save")
var save_file = FileAccess.open("user://saves/save-%s.json" % [save], FileAccess.READ)
if not save_file:
return
_info("Loading save save data")
var json_string = ""
while save_file.get_position() < save_file.get_length():
json_string += save_file.get_line()
var json = JSON.new()
var result = json.parse(json_string)
var data = json.get_data()
Persister.clear_category(PersisterEnums.Scope.SAVE)
for key in data:
Persister.persist_data(key, data[key], PersisterEnums.Scope.SAVE)
func _on_timer_timeout():
_save()

View file

@ -0,0 +1,10 @@
save[]
type: button
name: Swap Save 1
accent: #11a1a1
function: save_one
save2[]
type: button
name: Swap Save 2
accent: #11a1a1
function: save_two

View file

@ -0,0 +1,6 @@
[gd_scene load_steps=2 format=3 uid="uid://d3uc4ryq5tqby"]
[ext_resource type="Script" path="res://components/Settings/settings.gd" id="1_wmbcp"]
[node name="Settings" type="Node"]
script = ExtResource("1_wmbcp")

View file

View file

@ -0,0 +1,16 @@
@icon("res://components/Audio/music.svg")
extends Base
func _ready():
#_log_category = "AUD"
#_log_icon = "res://components/Audio/music.svg"
#_log_color = "#32ad61"
super()
_info("Audio is active")
if _triggerer:
_triggerer.listen("any", _on_trigger)
func _on_trigger(data: Dictionary) -> void:
pass

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-settings"><path d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z"/><circle cx="12" cy="12" r="3"/></svg>

After

Width:  |  Height:  |  Size: 826 B

View file

@ -0,0 +1,37 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://c1toq8e1yg4he"
path="res://.godot/imported/settings.svg-0c63f5959ea52eb948e9c6dfb59e2f91.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://components/Settings/settings.svg"
dest_files=["res://.godot/imported/settings.svg-0c63f5959ea52eb948e9c6dfb59e2f91.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
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/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
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false

View file

@ -0,0 +1,6 @@
[gd_scene load_steps=2 format=3 uid="uid://cgivlj3yp8nsy"]
[ext_resource type="Script" path="res://components/Triggerer/trigger_receiver.gd" id="1_rb2wc"]
[node name="TriggerReceiver" type="Node"]
script = ExtResource("1_rb2wc")

View file

@ -0,0 +1,6 @@
[gd_scene load_steps=2 format=3 uid="uid://rjec7f6cseh"]
[ext_resource type="Script" path="res://components/Triggerer/triggerer.gd" id="1_e3bhf"]
[node name="Triggerer" type="Node"]
script = ExtResource("1_e3bhf")

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-antenna"><path d="M2 12 7 2"/><path d="m7 12 5-10"/><path d="m12 12 5-10"/><path d="m17 12 5-10"/><path d="M4.5 7h15"/><path d="M12 16v6"/></svg>

After

Width:  |  Height:  |  Size: 340 B

View file

@ -0,0 +1,37 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://hnqq5c8erlns"
path="res://.godot/imported/antenna.svg-9e84cc3637193460d89c85029a059bef.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://components/Triggerer/antenna.svg"
dest_files=["res://.godot/imported/antenna.svg-9e84cc3637193460d89c85029a059bef.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
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/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
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false

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