From 787d4d089ca8b7ed31f6b3a2ac0d48e5392a47bc Mon Sep 17 00:00:00 2001 From: Adrien Ufferte Date: Fri, 5 Sep 2025 15:55:48 +0200 Subject: [PATCH] Nomenclatures corrections --- .github/scripts/check_gd_nomenclature.py | 357 +++++++++++++++--- .../environment_switcher.gd | 6 + .../godot-form-validator/example/example.gd | 1 + .../rules/alphanumeric_rule.gd | 2 +- .../rules/boolean_rule.gd | 2 +- .../rules/does_not_match_rule.gd | 2 +- .../godot-form-validator/rules/equals_rule.gd | 2 +- .../rules/not_blank_rule.gd | 2 +- .../godot-form-validator/rules/rule_result.gd | 2 +- .../rules/validator_rule.gd | 2 +- folder_unzipper.gd | 2 +- folder_zipper.gd | 2 +- prof_tool_save.gd | 2 +- resources/device_settings.gd | 7 +- resources/gardens/garden.gd | 32 +- resources/gardens/garden_layout.gd | 97 ++--- resources/gardens/gardens_layout.gd | 3 +- resources/user/student_data.gd | 4 +- resources/user/student_progression.gd | 4 +- resources/user/teacher_settings.gd | 21 +- resources/user/user_confusion_matrix.gd | 9 +- resources/user/user_difficulty.gd | 5 +- resources/user/user_minigame_history.gd | 15 +- resources/user/user_remediation.gd | 28 +- resources/user/user_speeches.gd | 6 +- script_templates/Node/default.gd | 14 + sources/gardens/flower_particle.gd | 4 +- sources/gardens/gardens.gd | 38 +- sources/gardens/gardens_edit_tool.gd | 1 - sources/gardens/minigame_layout.gd | 7 +- sources/kalulu.gd | 3 +- sources/language_tool/fish_word_list.gd | 4 +- .../language_tool/fish_word_list_element.gd | 9 +- sources/language_tool/globals.gd | 3 +- .../gp_image_and_sound_descriptions.gd | 6 +- sources/language_tool/gp_list.gd | 4 +- sources/language_tool/gp_list_button.gd | 2 +- sources/language_tool/gp_list_element.gd | 25 +- sources/language_tool/gp_select_popup.gd | 6 +- .../language_tool/gp_video_descriptions.gd | 4 +- .../image_and_sound_gp_description.gd | 14 +- sources/language_tool/in_game_sounds.gd | 1 - sources/language_tool/kalulu_speech.gd | 2 +- sources/language_tool/kalulu_speech_title.gd | 3 +- sources/language_tool/kalulu_speeches.gd | 1 - sources/language_tool/lesson_container.gd | 6 +- .../lesson_exercises_container.gd | 6 +- sources/language_tool/lesson_gp_label.gd | 2 +- sources/language_tool/lessons_list.gd | 7 +- sources/language_tool/list_title.gd | 5 +- sources/language_tool/plus_button.gd | 2 +- sources/language_tool/prof_tool_menu.gd | 22 +- sources/language_tool/segment_build.gd | 14 +- sources/language_tool/segment_container.gd | 29 +- sources/language_tool/segment_point_button.gd | 2 +- sources/language_tool/sentence_list.gd | 1 + .../language_tool/sentence_list_element.gd | 4 +- sources/language_tool/syllable_list.gd | 2 +- sources/language_tool/tracing_builder.gd | 10 +- sources/language_tool/video_gp_description.gd | 8 +- sources/language_tool/word_list.gd | 19 +- sources/language_tool/word_list_element.gd | 35 +- sources/lesson_screen/lesson_button.gd | 6 +- sources/look_and_learn/letter_segment.gd | 3 +- sources/look_and_learn/look_and_learn.gd | 29 +- sources/look_and_learn/tracing_effects.gd | 2 +- sources/look_and_learn/tracing_manager.gd | 10 +- sources/look_and_learn/tracing_path.gd | 20 +- sources/menus/adult_check/adult_check.gd | 3 +- sources/menus/brain/brain.gd | 6 +- sources/menus/components/code_keyboard.gd | 5 +- .../menus/components/password_visualizer.gd | 4 +- .../device_selection/device_selection.gd | 3 + .../language_selection/package_downloader.gd | 16 +- sources/menus/login/login.gd | 8 +- sources/menus/main/device_button.gd | 11 +- sources/menus/main/kalulu.gd | 15 +- sources/menus/main/language_field.gd | 1 + sources/menus/main/login.gd | 3 +- sources/menus/main/main_menu.gd | 2 - sources/menus/register/progress_bar.gd | 3 +- sources/menus/register/register.gd | 7 +- .../menus/register/steps/account_type_step.gd | 1 + sources/menus/register/steps/base_step.gd | 13 +- .../menus/register/steps/credentials_step.gd | 1 + sources/menus/register/steps/device_recap.gd | 3 +- sources/menus/register/steps/recap_step.gd | 3 +- .../steps/teacher/students_count_step.gd | 4 +- .../register/steps/validation/confirm_rule.gd | 3 +- .../steps/validation/item_list_validator.gd | 2 +- sources/menus/settings/device_tab.gd | 6 +- sources/menus/settings/lesson_unlock.gd | 6 +- sources/menus/settings/lesson_unlocks.gd | 16 +- .../menus/settings/sound_settings_button.gd | 1 + sources/menus/settings/student_panel.gd | 9 +- sources/menus/settings/teacher_settings.gd | 11 +- sources/minigames/ants/ant.gd | 2 +- sources/minigames/ants/ants_minigame.gd | 9 +- sources/minigames/ants/blank.gd | 3 +- sources/minigames/ants/word.gd | 13 +- sources/minigames/base/base_minigame.gd | 46 +-- .../base/hear_and_find/syllables_minigame.gd | 8 +- sources/minigames/base/kalulu.gd | 3 +- .../base/minigame_audio_stream_player.gd | 5 +- sources/minigames/base/minigame_ui.gd | 34 +- .../minigames/base/words/words_minigame.gd | 9 +- sources/minigames/caterpillar/berry.gd | 18 +- sources/minigames/caterpillar/branch.gd | 13 +- sources/minigames/caterpillar/caterpillar.gd | 8 +- .../caterpillar_audio_stream_player.gd | 3 +- .../minigames/caterpillar/caterpillar_body.gd | 10 +- .../minigames/caterpillar/caterpillar_head.gd | 3 +- .../caterpillar/caterpillar_minigame.gd | 36 +- sources/minigames/caterpillar/leaf.gd | 3 +- sources/minigames/caterpillar/spit_fx.gd | 3 +- sources/minigames/crabs/crab/crab.gd | 21 +- sources/minigames/crabs/crabs_minigame.gd | 24 +- sources/minigames/crabs/hole/hole.gd | 18 +- .../crabs/hole/hole_audio_stream_player_2d.gd | 2 +- sources/minigames/fish/fish_minigame.gd | 25 +- sources/minigames/frog/frog.gd | 12 +- sources/minigames/frog/frog_minigame.gd | 27 +- sources/minigames/frog/lilypad.gd | 16 +- sources/minigames/frog/lilypad_track.gd | 11 +- sources/minigames/frog/river.gd | 4 +- sources/minigames/jellyfish/jellyfish.gd | 23 +- .../minigames/jellyfish/jellyfish_minigame.gd | 27 +- .../minigames/monkeys/broken_coconut_fx.gd | 4 +- sources/minigames/monkeys/coconut.gd | 12 +- sources/minigames/monkeys/king_monkey.gd | 2 +- sources/minigames/monkeys/monkey.gd | 23 +- sources/minigames/monkeys/monkeys_minigame.gd | 48 ++- sources/minigames/parakeets/parakeet.gd | 25 +- .../minigames/parakeets/parakeets_minigame.gd | 26 +- sources/minigames/penguin/penguin.gd | 7 +- sources/minigames/penguin/penguin_label.gd | 10 +- sources/minigames/penguin/penguin_minigame.gd | 8 +- sources/minigames/penguin/snowball.gd | 9 +- sources/minigames/turtles/island.gd | 9 +- sources/minigames/turtles/turtle.gd | 24 +- sources/minigames/turtles/turtles_minigame.gd | 38 +- sources/minigames/turtles/water.gd | 3 +- sources/ui/loading_popup.gd | 10 +- sources/ui/popup.gd | 10 +- sources/ui/tr_item_list.gd | 1 + sources/utils/auto_size_label.gd | 3 + sources/utils/autoloads/database.gd | 5 +- sources/utils/autoloads/lesson_logger.gd | 4 - sources/utils/autoloads/logger.gd | 20 +- sources/utils/autoloads/music_manager.gd | 18 +- sources/utils/autoloads/opening_curtain.gd | 3 +- sources/utils/autoloads/server_manager.gd | 17 +- sources/utils/autoloads/user_data_manager.gd | 77 +++- .../autoloads/user_database_synchronizer.gd | 16 +- sources/utils/autoloads/utils.gd | 6 + sources/utils/binder/control_binder.gd | 3 +- sources/utils/binder/form_binder.gd | 3 +- sources/utils/coroutine.gd | 8 +- sources/utils/dynamic_font_size_label.gd | 13 +- sources/utils/fx/fireworks.gd | 7 +- sources/utils/fx/highlight.gd | 5 +- sources/utils/fx/right.gd | 6 +- sources/utils/fx/rocket.gd | 29 +- sources/utils/fx/sand.gd | 5 +- sources/utils/fx/water_ring.gd | 3 +- sources/utils/fx/wrong.gd | 6 +- sources/utils/keyboard_spacer.gd | 3 +- sources/utils/math/bezier.gd | 2 +- sources/utils/minigame_resources/log.gd | 2 +- sources/utils/percent_margin_container.gd | 2 +- sources/utils/sprite_control.gd | 2 +- sources/utils/swipe_detector.gd | 7 +- 172 files changed, 1215 insertions(+), 944 deletions(-) diff --git a/.github/scripts/check_gd_nomenclature.py b/.github/scripts/check_gd_nomenclature.py index af6c1e10..1f7f7c53 100644 --- a/.github/scripts/check_gd_nomenclature.py +++ b/.github/scripts/check_gd_nomenclature.py @@ -57,10 +57,7 @@ def split_params(param_string: str): return params EXCLUDED_DIRS = {"addons", ".git", ".github"} - -PASCAL_CASE = re.compile(r"^[A-Z][A-Za-z0-9]*$") -SNAKE_CASE = re.compile(r"^_?[a-z][a-z0-9_]*$") -UPPER_SNAKE_CASE = re.compile(r"^_?[A-Z][A-Z0-9_]*$") +EXCLUDED_FILES = {os.path.normpath("script_templates/Node/default.gd")} issues = [] MESSAGES = { @@ -69,63 +66,317 @@ MESSAGES = { 'variable': 'is a variable name and should be in snake_case', 'constant': 'is a constant name and should be in UPPER_SNAKE_CASE', 'signal': 'is a signal name and should be in snake_case', + 'annotation_order': 'annotations must be on the first line and include only \@tool, \@icon or \@static_unload', + 'class_position': 'class_name must appear after annotations (if any)', + 'extends_position': 'extends must appear after annotation and class_name', + 'extends_missing': 'extends is required and must follow annotation and class_name', + 'func_blank': 'functions must be preceded by exactly two empty lines (or only one if preceded by a #region comment)', + 'signal_position': 'signals must come right after extends', + 'signal_format': 'signals must end with ()', + 'signal_blank': 'signals must not be separated by empty lines', + 'enum_position': 'enums must come after signals and be grouped together', + 'enum_format': "enum declaration should be 'enum Name {'", + 'enum_member_blank': 'enum members must not be separated by empty lines', + 'enum_member_indent': 'enum members must be indented with a single tab', + 'enum_no_close': 'enum declaration is missing a closing }', + 'enum_blank': 'enums must be preceded by one empty line and must not be separated by empty lines', + 'const_position': 'constants must come after enums and be grouped together', + 'const_blank': 'constants must be preceded by one empty line and must not be separated by empty lines', + 'static_position': 'static variables must come after constants and be grouped together', + 'static_blank': 'static variables must be preceded by one empty line and must not be separated by empty lines', + 'export_position': 'export variables must come after static variables and be grouped together', + 'export_blank': 'export variables must be preceded by one empty line and must not be separated by empty lines', + 'var_position': 'variables must come after export variables and be grouped together', + 'var_blank': 'variables must be preceded by one empty line and must not be separated by empty lines', + 'onready_position': '@onready variables must come after other variables and be grouped together', + 'onready_blank': '@onready variables must be preceded by one empty line and must not be separated by empty lines', } +# Naming conventions +PASCAL_CASE = re.compile(r"^[A-Z][A-Za-z0-9]*$") +SNAKE_CASE = re.compile(r"^_?[a-z][a-z0-9_]*$") +UPPER_SNAKE_CASE = re.compile(r"^_?[A-Z][A-Z0-9_]*$") +REGION_RE = re.compile(r"#\s*(region|endregion)\b", re.IGNORECASE) + +def check_naming(path: str, lines: list[str]): + for idx, line in enumerate(lines, 1): + stripped = line.strip() + if stripped.startswith('#') or stripped.startswith('@warning_ignore(') or not stripped: + continue + match_class = re.match(r"class_name\s+([A-Za-z0-9_]+)", stripped) + if match_class: + name = match_class.group(1) + if not PASCAL_CASE.match(name): + issues.append((path, idx, 'class', name)) + match_func = re.match(r"(?:static\s+)?func\s+([A-Za-z0-9_]+)\s*(\([^)]*\))?", stripped) + if match_func: + name = match_func.group(1) + if not SNAKE_CASE.match(name): + issues.append((path, idx, 'function', name)) + params = match_func.group(2) + if params: + params = params.strip('()') + for param in split_params(params): + param_name = param.split(':')[0].split('=')[0].strip() + if param_name and not SNAKE_CASE.match(param_name): + issues.append((path, idx, 'variable', param_name)) + match_export = re.match(r"(?:@export\s+)?var\s+([A-Za-z0-9_]+)", stripped) + if match_export: + name = match_export.group(1) + if not SNAKE_CASE.match(name): + issues.append((path, idx, 'variable', name)) + match_const = re.match(r"const\s+([A-Za-z0-9_]+)", stripped) + if match_const: + name = match_const.group(1) + if not UPPER_SNAKE_CASE.match(name): + issues.append((path, idx, 'constant', name)) + match_signal = re.match(r"signal\s+([A-Za-z0-9_]+)", stripped) + if match_signal: + name = match_signal.group(1) + if not SNAKE_CASE.match(name): + issues.append((path, idx, 'signal', name)) + match_for = re.match(r"for\s+([A-Za-z0-9_]+)(?:\s*:\s*[^\s]+)?\s+in\b", stripped) + if match_for: + name = match_for.group(1) + if not SNAKE_CASE.match(name): + issues.append((path, idx, 'variable', name)) + +# Content order +ANNOTATION_LINE_RE = re.compile( + r"^(?:@(tool|icon|static_unload)(?:\([^\n]*\))?)(?:,\s*@(tool|icon|static_unload)(?:\([^\n]*\))?)*$" +) +ALLOWED_ANNOTATION_RE = re.compile(r"@(tool|icon|static_unload)\b") + +def check_content_order(path: str, lines: list[str]): + content = [ + (line.rstrip('\n'), idx) + for idx, line in enumerate(lines, 1) + if not line.startswith(' ') # Line is not indented + and not line.lstrip().startswith('#') + and not line.lstrip().startswith('@warning_ignore(') + ] + idx = 0 + n = len(content) + + # 1) annotations + if idx < n and ANNOTATION_LINE_RE.fullmatch(content[idx][0].strip()): + idx += 1 + else: + for j in range(idx, n): + if ALLOWED_ANNOTATION_RE.search(content[j][0]): + issues.append((path, content[j][1], 'annotation_order', content[j][0].strip())) + break + + # 2) class_name (optional) + for j in range(idx, n): + if content[j][0].strip().startswith('class_name'): + if j != idx: + issues.append((path, content[j][1], 'class_position', 'class_name')) + else: + idx += 1 + break + + # 3) extends (required) + extends_pos = None + for j in range(idx, n): + if content[j][0].strip().startswith('extends'): + extends_pos = j + break + if extends_pos is None: + issues.append((path, 0, 'extends_missing', 'extends')) + return + if extends_pos != idx: + issues.append((path, content[extends_pos][1], 'extends_position', 'extends')) + idx = extends_pos + 1 + + order = ['signal', 'enum', 'const', 'static var', '@export', 'var', '@onready var'] + order_index = {name: i for i, name in enumerate(order)} + seen: set[str] = set() + current_order = -1 + prev_token: str | None = content[extends_pos][0].strip() + j = idx + while j < n: + line, line_no = content[j] + stripped = line.strip() + if stripped == '': + prev_token = '' + j += 1 + continue + if re.match(r'(?:static\s+)?func\b', stripped): + break + token = None + if stripped.startswith('signal'): + token = 'signal' + if not re.fullmatch(r"signal\s+\w+\([^)]*\)", stripped): + issues.append((path, line_no, 'signal_format', stripped)) + if 'signal' in seen and prev_token == '': + issues.append((path, content[j - 1][1], 'signal_blank', 'signal')) + seen.add('signal') + elif stripped.startswith('enum'): + token = 'enum' + if not re.fullmatch(r"enum\s+\w+\s*{", stripped): + issues.append((path, line_no, 'enum_format', stripped)) + if 'enum' not in seen: + if prev_token != '': + issues.append((path, line_no, 'enum_blank', 'enum')) + else: + if prev_token != '}' and prev_token != ']': + issues.append((path, line_no, 'enum_blank', 'enum')) + k = j + 1 + while k < n and content[k][0].strip() != '}': + member, m_line_no = content[k] + if member.strip() == '': + issues.append((path, m_line_no, 'enum_member_blank', 'enum')) + if not member.startswith('\t') or member.startswith('\t\t'): + issues.append((path, m_line_no, 'enum_member_indent', member.strip())) + k += 1 + if k >= n: + issues.append((path, line_no, 'enum_no_close', 'enum')) + return + j = k + prev_token = '}' + seen.add('enum') + curr_order = order_index['enum'] + if curr_order < current_order: + issues.append((path, line_no, 'enum_position', 'enum')) + else: + current_order = max(current_order, curr_order) + j += 1 + continue + elif stripped.startswith('const '): + token = 'const' + if 'const' not in seen: + if prev_token != '': + issues.append((path, line_no, 'const_blank', 'const')) + else: + if prev_token != 'const' and prev_token != '}' and prev_token != ']': + issues.append((path, line_no, 'const_blank', 'const')) + seen.add('const') + elif stripped.startswith('static var '): + token = 'static var' + if 'static var' not in seen: + if prev_token != '': + issues.append((path, line_no, 'static_blank', 'static var')) + else: + if prev_token != 'static var' and prev_token != '}' and prev_token != ']': + issues.append((path, line_no, 'static_blank', 'static var')) + seen.add('static var') + elif stripped.startswith('@export'): + token = '@export' + if '@export' not in seen: + if prev_token != '': + issues.append((path, line_no, 'export_blank', '@export')) + else: + if prev_token != '@export' and prev_token != '}' and prev_token != ']': + issues.append((path, line_no, 'export_blank', '@export')) + seen.add('@export') + elif stripped.startswith('var '): + token = 'var' + if 'var' not in seen: + if prev_token != '': + issues.append((path, line_no, 'var_blank', 'var')) + else: + if prev_token != 'var' and prev_token != '}' and prev_token != ']': + issues.append((path, line_no, 'var_blank', 'var')) + seen.add('var') + elif stripped.startswith('@onready var '): + token = '@onready var' + if '@onready var' not in seen: + if prev_token != '': + issues.append((path, line_no, 'onready_blank', '@onready var')) + else: + if prev_token != '@onready var' and prev_token != '}' and prev_token != ']': + issues.append((path, line_no, 'onready_blank', '@onready var')) + seen.add('@onready var') + else: + prev_token = stripped + j += 1 + continue + curr_order = order_index[token] + key_map = { + 'signal': 'signal_position', + 'enum': 'enum_position', + 'const': 'const_position', + 'static var': 'static_position', + '@export': 'export_position', + 'var': 'var_position', + '@onready var': 'onready_position', + } + if curr_order < current_order: + issues.append((path, line_no, key_map[token], token)) + else: + current_order = max(current_order, curr_order) + + prev_token = token + j += 1 + + +# Spacing for functions +def check_func_spacing(path: str): + with open(path, 'r', encoding='utf-8') as file: + lines = file.readlines() + for idx, line in enumerate(lines): + stripped_line = line.lstrip() + if re.match(r'(?:static\s+)?func\b', stripped_line): + if re.match(r'(?:static\s+)?func\s*\(', stripped_line): + continue + start_idx = idx + # Skip annotations and regular comments above the function + while start_idx > 0: + prev_line = lines[start_idx - 1].lstrip() + if prev_line.startswith('@warning_ignore('): + start_idx -= 1 + elif prev_line.startswith('#') and not REGION_RE.match(prev_line): + start_idx -= 1 + else: + break + test_index = start_idx - 1 + blank_count = 0 + while test_index >= 0: + stripped = lines[test_index].lstrip() + if stripped == '': + blank_count += 1 + test_index -= 1 + continue + if stripped.startswith('@warning_ignore('): + test_index -= 1 + continue + if stripped.startswith('#') and not REGION_RE.match(stripped): + test_index -= 1 + continue + break + region_above = test_index >= 0 and REGION_RE.match(lines[test_index].lstrip()) + if region_above: + if blank_count > 1: + issues.append((path, idx + 1, 'func_blank', 'func')) + continue + elif blank_count != 2: + if not (blank_count == 1 and test_index >= 0 and lines[test_index].lstrip().startswith('#region')): + issues.append((path, idx + 1, 'func_blank', 'func')) + + +# Main function for root, dirs, files in os.walk('.', topdown=True): rel_root = os.path.relpath(root, '.') if any(rel_root == excluded or rel_root.startswith(f"{excluded}{os.sep}") for excluded in EXCLUDED_DIRS): dirs[:] = [] continue for fname in files: - if fname.endswith('.gd'): - path = os.path.join(root, fname) - try: - with open(path, 'r', encoding='utf-8') as file: - lines = file.readlines() - except Exception as e: - issues.append((path, 0, 'error', f'Could not read file: {e}')) - continue - for idx, line in enumerate(lines, 1): - stripped = line.strip() - if stripped.startswith('#') or not stripped: - continue - match_class = re.match(r"class_name\s+([A-Za-z0-9_]+)", stripped) - if match_class: - name = match_class.group(1) - if not PASCAL_CASE.match(name): - issues.append((path, idx, 'class', name)) - match_func = re.match(r"func\s+([A-Za-z0-9_]+)\s*(\([^)]*\))?", stripped) - if match_func: - name = match_func.group(1) - if not SNAKE_CASE.match(name): - issues.append((path, idx, 'function', name)) - params = match_func.group(2) - if params: - params = params.strip('()') - for param in split_params(params): - param_name = param.split(':')[0].split('=')[0].strip() - if param_name and not SNAKE_CASE.match(param_name): - issues.append((path, idx, 'variable', param_name)) - match_export = re.match(r"(?:@export\s+)?var\s+([A-Za-z0-9_]+)", stripped) - if match_export: - name = match_export.group(1) - if not SNAKE_CASE.match(name): - issues.append((path, idx, 'variable', name)) - match_const = re.match(r"const\s+([A-Za-z0-9_]+)", stripped) - if match_const: - name = match_const.group(1) - if not UPPER_SNAKE_CASE.match(name): - issues.append((path, idx, 'constant', name)) - match_signal = re.match(r"signal\s+([A-Za-z0-9_]+)", stripped) - if match_signal: - name = match_signal.group(1) - if not SNAKE_CASE.match(name): - issues.append((path, idx, 'signal', name)) - match_for = re.match(r"for\s+([A-Za-z0-9_]+)(?:\s*:\s*[^\s]+)?\s+in\b", stripped) - if match_for: - name = match_for.group(1) - if not SNAKE_CASE.match(name): - issues.append((path, idx, 'variable', name)) + if not fname.endswith('.gd'): + continue + path = os.path.join(root, fname) + rel_path = os.path.normpath(os.path.relpath(path, '.')) + if rel_path in EXCLUDED_FILES: + continue + try: + with open(path, 'r', encoding='utf-8') as file: + lines = file.readlines() + except Exception as e: + issues.append((path, 0, 'error', f'Could not read file: {e}')) + continue + check_naming(path, lines) + check_content_order(path, lines) + check_func_spacing(path) if issues: print("### \u274c GDScript Naming Convention Check Failed\n") diff --git a/addons/EnvironmentSwitcher/environment_switcher.gd b/addons/EnvironmentSwitcher/environment_switcher.gd index e8bcccf0..40a12cad 100644 --- a/addons/EnvironmentSwitcher/environment_switcher.gd +++ b/addons/EnvironmentSwitcher/environment_switcher.gd @@ -8,6 +8,7 @@ const CONFIG_PATH: String = "user://environment.cfg" var env_selector: OptionButton var current_environment: EnvType = EnvType.DEV + func _enter_tree() -> void: # Create OptionButton env_selector = OptionButton.new() @@ -25,27 +26,32 @@ func _enter_tree() -> void: # Reflect the current environment in UI env_selector.select(current_environment) + func _exit_tree() -> void: # Clean up the UI and save state remove_control_from_container(EditorPlugin.CONTAINER_TOOLBAR, env_selector) env_selector.queue_free() + func _on_env_selected(index: int) -> void: current_environment = index save_environment() print("Environment switched to:", _environment_to_string(current_environment)) + func _environment_to_string(env: EnvType) -> String: match env: EnvType.DEV: return "DEV" EnvType.PROD: return "PROD" _: return "Unknown" + func save_environment() -> void: var config = ConfigFile.new() config.set_value("environment", "current", str(current_environment)) config.save(CONFIG_PATH) + func load_environment() -> void: var config = ConfigFile.new() if config.load(CONFIG_PATH) == OK: diff --git a/addons/godot-form-validator/example/example.gd b/addons/godot-form-validator/example/example.gd index 04a1a373..2e274f33 100644 --- a/addons/godot-form-validator/example/example.gd +++ b/addons/godot-form-validator/example/example.gd @@ -2,6 +2,7 @@ extends PanelContainer @onready var form_validator_control: FormValidator = $MarginContainer/FormValidator + func _on_form_validator_control_control_validated(control, passed, messages) -> void: var error_label = _get_error_label(control) var valid_label = _get_valid_label(control) diff --git a/addons/godot-form-validator/rules/alphanumeric_rule.gd b/addons/godot-form-validator/rules/alphanumeric_rule.gd index 50a5a482..160dae1e 100644 --- a/addons/godot-form-validator/rules/alphanumeric_rule.gd +++ b/addons/godot-form-validator/rules/alphanumeric_rule.gd @@ -1,6 +1,6 @@ @tool -extends ValidatorRule class_name AlphanumericRule +extends ValidatorRule func _init() -> void: diff --git a/addons/godot-form-validator/rules/boolean_rule.gd b/addons/godot-form-validator/rules/boolean_rule.gd index b80a11a2..20489121 100644 --- a/addons/godot-form-validator/rules/boolean_rule.gd +++ b/addons/godot-form-validator/rules/boolean_rule.gd @@ -1,6 +1,6 @@ @tool -extends ValidatorRule class_name BooleanRule +extends ValidatorRule @export var target_value: bool diff --git a/addons/godot-form-validator/rules/does_not_match_rule.gd b/addons/godot-form-validator/rules/does_not_match_rule.gd index b8e91756..22ddbe1d 100644 --- a/addons/godot-form-validator/rules/does_not_match_rule.gd +++ b/addons/godot-form-validator/rules/does_not_match_rule.gd @@ -1,6 +1,6 @@ @tool -extends ValidatorRule class_name DoesNotMatchRule +extends ValidatorRule @export var pattern: String diff --git a/addons/godot-form-validator/rules/equals_rule.gd b/addons/godot-form-validator/rules/equals_rule.gd index 2a08436d..6908f41c 100644 --- a/addons/godot-form-validator/rules/equals_rule.gd +++ b/addons/godot-form-validator/rules/equals_rule.gd @@ -1,6 +1,6 @@ @tool -extends ValidatorRule class_name EqualsRule +extends ValidatorRule @export var target_value: String diff --git a/addons/godot-form-validator/rules/not_blank_rule.gd b/addons/godot-form-validator/rules/not_blank_rule.gd index 5b47874e..60db3151 100644 --- a/addons/godot-form-validator/rules/not_blank_rule.gd +++ b/addons/godot-form-validator/rules/not_blank_rule.gd @@ -1,6 +1,6 @@ @tool -extends ValidatorRule class_name NotBlankRule +extends ValidatorRule func _init() -> void: diff --git a/addons/godot-form-validator/rules/rule_result.gd b/addons/godot-form-validator/rules/rule_result.gd index 3b4800cd..da29303b 100644 --- a/addons/godot-form-validator/rules/rule_result.gd +++ b/addons/godot-form-validator/rules/rule_result.gd @@ -1,5 +1,5 @@ -extends RefCounted class_name RuleResult +extends RefCounted var passed: bool = false var message: String = "" diff --git a/addons/godot-form-validator/rules/validator_rule.gd b/addons/godot-form-validator/rules/validator_rule.gd index fe97db07..e143ee7b 100644 --- a/addons/godot-form-validator/rules/validator_rule.gd +++ b/addons/godot-form-validator/rules/validator_rule.gd @@ -1,6 +1,6 @@ @tool -extends Resource class_name ValidatorRule +extends Resource @export var fail_message: String = "" diff --git a/folder_unzipper.gd b/folder_unzipper.gd index 6585bd04..ac8f6130 100644 --- a/folder_unzipper.gd +++ b/folder_unzipper.gd @@ -1,5 +1,5 @@ -extends ZIPReader class_name FolderUnzipper +extends ZIPReader signal file_count(count: int) signal file_copied(count: int, name: String) diff --git a/folder_zipper.gd b/folder_zipper.gd index cd035834..bcde1caa 100644 --- a/folder_zipper.gd +++ b/folder_zipper.gd @@ -1,5 +1,5 @@ -extends ZIPPacker class_name FolderZipper +extends ZIPPacker func write_folder_recursive(abs_path: String, rel_path: String) -> Error: diff --git a/prof_tool_save.gd b/prof_tool_save.gd index 67502aff..a22ee9ff 100644 --- a/prof_tool_save.gd +++ b/prof_tool_save.gd @@ -1,4 +1,4 @@ -extends Resource class_name ProfToolSave +extends Resource @export var selected_language: String = "" diff --git a/resources/device_settings.gd b/resources/device_settings.gd index 9e3cf3f4..7dd8a1e8 100644 --- a/resources/device_settings.gd +++ b/resources/device_settings.gd @@ -1,7 +1,6 @@ @tool -extends Resource class_name DeviceSettings - +extends Resource const SUPPORTED_LOCALES: Array[String] = [ # French France @@ -26,25 +25,21 @@ const SUPPORTED_LOCALES: Array[String] = [ @export var device_id: int @export var language_versions: Dictionary = {} # locale: datetime @export var game_version: String = "0.0.1" - @export var master_volume: float = 0.0: set(volume): master_volume = volume var ind: int = AudioServer.get_bus_index("Master") AudioServer.set_bus_volume_db(ind, volume) - @export var music_volume: float = 0.0: set(volume): music_volume = volume var ind: int = AudioServer.get_bus_index("Music") AudioServer.set_bus_volume_db(ind, volume) - @export var voice_volume: float = 0.0: set(volume): voice_volume = volume var ind: int = AudioServer.get_bus_index("Voice") AudioServer.set_bus_volume_db(ind, volume) - @export var effects_volume: float = 0.0: set(volume): effects_volume = volume diff --git a/resources/gardens/garden.gd b/resources/gardens/garden.gd index 50f71791..466e5da9 100644 --- a/resources/gardens/garden.gd +++ b/resources/gardens/garden.gd @@ -1,15 +1,28 @@ @tool -extends Control class_name Garden +extends Control + +enum FlowerSizes{ + NOT_STARTED, + SMALL, + MEDIUM, + LARGE +} const FLOWER_PATH_MODEL: String = "res://assets/gardens/flowers/plant_%02d_%02d_%s.png" const BACKGROUND_PATH_MODEL: String = "res://assets/gardens/gardens/garden_%02d_open.png" @export var garden_layout: GardenLayout: set = set_garden_layout - @export var garden_colors: Array[Color] = [] +var flowers: Array[GardenLayout.Flower] = [] +var flowers_sizes: Array[FlowerSizes] = [] +var color: Color +var current_progression: float = 0.0 +var max_progression: float = 0.0 +var garden_index: int = -1 + @onready var buttons: Control = $Buttons @onready var flower_controls: Array[TextureRect] = [ %Flower1, @@ -26,21 +39,6 @@ const BACKGROUND_PATH_MODEL: String = "res://assets/gardens/gardens/garden_%02d_ %Button4, ] -enum FlowerSizes{ - NOT_STARTED, - SMALL, - MEDIUM, - LARGE -} - -var flowers: Array[GardenLayout.Flower] = [] -var flowers_sizes: Array[FlowerSizes] = [] -var color: Color - -var current_progression: float = 0.0 -var max_progression: float = 0.0 - -var garden_index: int = -1 func get_button_size() -> Vector2: return lesson_button_controls[0].get_size() diff --git a/resources/gardens/garden_layout.gd b/resources/gardens/garden_layout.gd index 8b8f769b..7e0484cf 100644 --- a/resources/gardens/garden_layout.gd +++ b/resources/gardens/garden_layout.gd @@ -1,46 +1,6 @@ @tool -extends Resource class_name GardenLayout - - -class Flower: - var color: int = 0 - var type: int = 0 - var position: Vector2 = Vector2i.ZERO - - func _init(p_color: int = 0, p_type: int = 0, p_position: Vector2i = Vector2i.ZERO) -> void: - color = p_color - type = p_type - position = p_position - - static func from_dict(d: Dictionary) -> Flower: - return Flower.new(d.color as int, d.type as int, d.position as Vector2i) - - func to_dict() -> Dictionary: - return { - color = color, - type = type, - position = position, - } - - -class GardenLayoutLessonButton: - var position: Vector2i = Vector2i.ZERO - var path_out_position: Vector2i = Vector2i.ZERO - - func _init(p_position: Vector2i = Vector2i.ZERO, p_path_out_position: Vector2i = Vector2i.ZERO) -> void: - position = p_position - path_out_position = p_path_out_position - - static func from_dict(d: Dictionary) -> GardenLayoutLessonButton: - return GardenLayoutLessonButton.new(d.position as Vector2i, d.path_out_position as Vector2i) - - func to_dict() -> Dictionary: - return { - position = position, - path_out_position = path_out_position - } - +extends Resource enum FirstOrLast { First, @@ -48,18 +8,18 @@ enum FirstOrLast { Last } - @export var color: int = 0 -var flowers: Array[Flower] = []: - set = set_flowers @export var flowers_export: Array[Dictionary] = []: set = set_flowers_export -var lesson_buttons: Array[GardenLayoutLessonButton] = []: - set = set_lesson_buttons @export var lesson_buttons_export: Array[Dictionary] = []: set = set_lesson_buttons_export @export var is_first_or_last: FirstOrLast = FirstOrLast.Neither +var flowers: Array[Flower] = []: + set = set_flowers +var lesson_buttons: Array[GardenLayoutLessonButton] = []: + set = set_lesson_buttons + func set_flowers_export(p_flowers_export: Array[Dictionary]) -> void: flowers_export = p_flowers_export @@ -87,3 +47,48 @@ func set_lesson_buttons(p_lesson_buttons: Array[GardenLayoutLessonButton]) -> vo lesson_buttons_export.clear() for lesson_button: GardenLayoutLessonButton in lesson_buttons: lesson_buttons_export.append(lesson_button.to_dict()) + + +class Flower: + var color: int = 0 + var type: int = 0 + var position: Vector2 = Vector2i.ZERO + + + func _init(p_color: int = 0, p_type: int = 0, p_position: Vector2i = Vector2i.ZERO) -> void: + color = p_color + type = p_type + position = p_position + + + static func from_dict(d: Dictionary) -> Flower: + return Flower.new(d.color as int, d.type as int, d.position as Vector2i) + + + func to_dict() -> Dictionary: + return { + color = color, + type = type, + position = position, + } + + +class GardenLayoutLessonButton: + var position: Vector2i = Vector2i.ZERO + var path_out_position: Vector2i = Vector2i.ZERO + + + func _init(p_position: Vector2i = Vector2i.ZERO, p_path_out_position: Vector2i = Vector2i.ZERO) -> void: + position = p_position + path_out_position = p_path_out_position + + + static func from_dict(d: Dictionary) -> GardenLayoutLessonButton: + return GardenLayoutLessonButton.new(d.position as Vector2i, d.path_out_position as Vector2i) + + + func to_dict() -> Dictionary: + return { + position = position, + path_out_position = path_out_position + } diff --git a/resources/gardens/gardens_layout.gd b/resources/gardens/gardens_layout.gd index 6105d3f7..181317c3 100644 --- a/resources/gardens/gardens_layout.gd +++ b/resources/gardens/gardens_layout.gd @@ -1,6 +1,5 @@ @tool -extends Resource class_name GardensLayout - +extends Resource @export var gardens: Array[GardenLayout] = [] diff --git a/resources/user/student_data.gd b/resources/user/student_data.gd index 3cd06635..e059c974 100644 --- a/resources/user/student_data.gd +++ b/resources/user/student_data.gd @@ -1,6 +1,5 @@ -extends Resource class_name StudentData - +extends Resource enum Level { Beginner, @@ -14,6 +13,7 @@ enum Level { @export var age: int = 0 @export var last_modified: String = "" + func to_dict() -> Dictionary: return { "code": code, diff --git a/resources/user/student_progression.gd b/resources/user/student_progression.gd index 11457f2c..5b0c9b78 100644 --- a/resources/user/student_progression.gd +++ b/resources/user/student_progression.gd @@ -1,5 +1,5 @@ -extends Resource class_name StudentProgression +extends Resource signal unlocks_changed() @@ -17,6 +17,7 @@ enum Status{ func _init() -> void: init_unlocks() + # Make sure the unlocks are correct func init_unlocks() -> void: if not unlocks: @@ -73,6 +74,7 @@ func look_and_learn_completed(lesson_number: int) -> bool: unlocks_changed.emit() return true + # Return true if the progression is saved or false if the game was already completed func game_completed(lesson_number: int, game_number: int) -> bool: # If the game is already completed, do nothing diff --git a/resources/user/teacher_settings.gd b/resources/user/teacher_settings.gd index 7702ca86..b2eab2ee 100644 --- a/resources/user/teacher_settings.gd +++ b/resources/user/teacher_settings.gd @@ -1,28 +1,28 @@ -extends Resource class_name TeacherSettings - -const AVAILABLE_CODES: Array[int] = [123, 124, 125, 126, 132, 134, 135, 136, 142, 143, 145, 146, 152, 153, 154, 213, 214, 215, 216, 231, 234, 235, 236, 241, 243, 245, 246, 251, 253, 254, 321, 324, 325, 326, 312, 314, 315, 316, 342, 341, 345, 346, 352, 351, 354, 423, 421, 425, 426, 432, 431, 435, 436, 412, 413, 415, 416, 452, 453, 451, 523, 524, 521, 526, 532, 534, 531, 536, 542, 543, 541, 546, 512, 513, 514, 623, 624, 625, 621, 632, 634, 635, 631, 642, 643, 645, 641, 652, 653, 654] - +extends Resource enum AccountType { Teacher, Parent } - enum EducationMethod { AppOnly, Complete } +const AVAILABLE_CODES: Array[int] = [123, 124, 125, 126, 132, 134, 135, 136, 142, 143, 145, 146, 152, 153, 154, 213, 214, 215, 216, 231, 234, 235, 236, 241, 243, 245, 246, 251, 253, 254, 321, 324, 325, 326, 312, 314, 315, 316, 342, 341, 345, 346, 352, 351, 354, 423, 421, 425, 426, 432, 431, 435, 436, 412, 413, 415, 416, 452, 453, 451, 523, 524, 521, 526, 532, 534, 531, 536, 542, 543, 541, 546, 512, 513, 514, 623, 624, 625, 621, 632, 634, 635, 631, 642, 643, 645, 641, 652, 653, 654] + @export var account_type: AccountType @export var education_method: EducationMethod -var devices_count: int @export var students: Dictionary[int, Array] = {} # int (device): Array[StudentData] @export var email: String -var password: String @export var token: String @export var last_modified: String = "" +var devices_count: int +var password: String + + func update_from_dict(dict: Dictionary) -> void: if dict.has("account_type"): account_type = dict.account_type @@ -104,6 +104,7 @@ func get_new_code() -> int: var code: int = codes.pick_random() return code + func to_dict() -> Dictionary: var dict: Dictionary = { "account_type": account_type, @@ -122,6 +123,7 @@ func to_dict() -> Dictionary: return dict + func get_number_of_students() -> int: if not students: return 0 @@ -130,12 +132,14 @@ func get_number_of_students() -> int: result += data.size() return result + func get_all_students_data() -> Array[StudentData]: var result: Array[StudentData] = [] for data: Array[StudentData] in students.values(): result.append_array(data) return result + func delete_student(student_code: int) -> void: for device: int in students.keys(): for index: int in range(students[device].size()): @@ -146,12 +150,14 @@ func delete_student(student_code: int) -> void: return Logger.warn("TeacherSettings: Trying to delete student, but code %d not found" % student_code) + func get_student_with_code(student_code: int) -> StudentData: for student_data: StudentData in get_all_students_data(): if student_data.code == student_code: return student_data return null + func get_student_device(student_code: int) -> int: for device: int in students.keys(): for index: int in range(students[device].size()): @@ -159,6 +165,7 @@ func get_student_device(student_code: int) -> int: return device return -1 + func set_data_student_with_code(student_code: int, new_device_id: int, new_name: String, new_age: int, new_last_modified: String) -> void: update_student_device(student_code, new_device_id) for student_data: StudentData in students[new_device_id]: diff --git a/resources/user/user_confusion_matrix.gd b/resources/user/user_confusion_matrix.gd index a8f7e067..d2764ce3 100644 --- a/resources/user/user_confusion_matrix.gd +++ b/resources/user/user_confusion_matrix.gd @@ -39,11 +39,9 @@ func append_and_trim(target: Dictionary[int, PackedInt32Array], expected_id: int # Key is the ID of the expected answer # Value is a PackedInt32Array whose entries are the IDs of the answers -@export -var gp_scores: Dictionary[int, PackedInt32Array] = {} +@export var gp_scores: Dictionary[int, PackedInt32Array] = {} +@export var gp_last_modified: String = "" -@export -var gp_last_modified: String = "" # Gets (a copy of) the data of a GP func get_gp_scores(id: int) -> PackedInt32Array: @@ -52,6 +50,7 @@ func get_gp_scores(id: int) -> PackedInt32Array: return PackedInt32Array(gp_scores[id]) return PackedInt32Array() + # Updates the confusion matrix from a minigame scores func update_gp_scores(minigame_scores: Dictionary[int, PackedInt32Array]) -> void: if not minigame_scores or minigame_scores.is_empty(): @@ -63,6 +62,7 @@ func update_gp_scores(minigame_scores: Dictionary[int, PackedInt32Array]) -> voi set_gp_last_modified(Time.get_datetime_string_from_system(true)) score_changed.emit() + func set_gp_scores(new_scores: Dictionary[int, PackedInt32Array]) -> void: var cleaned: Dictionary[int, PackedInt32Array] = {} for expected_id: int in new_scores.keys(): @@ -71,6 +71,7 @@ func set_gp_scores(new_scores: Dictionary[int, PackedInt32Array]) -> void: gp_scores = cleaned set_gp_last_modified(Time.get_datetime_string_from_system(true)) + func set_gp_last_modified(new_date: String) -> void: gp_last_modified = new_date diff --git a/resources/user/user_difficulty.gd b/resources/user/user_difficulty.gd index b8dec247..78e1553a 100644 --- a/resources/user/user_difficulty.gd +++ b/resources/user/user_difficulty.gd @@ -1,13 +1,12 @@ -extends Resource class_name UserDifficulty +extends Resource signal difficulty_changed() # Stores the user history for all the minigames # Key -> minigame_name: String # Value -> UserMinigameHistory -@export -var minigames_histories: Dictionary = {} +@export var minigames_histories: Dictionary = {} # Gets the difficulty of the user for the given minigame diff --git a/resources/user/user_minigame_history.gd b/resources/user/user_minigame_history.gd index 7e86e955..16e45be6 100644 --- a/resources/user/user_minigame_history.gd +++ b/resources/user/user_minigame_history.gd @@ -1,19 +1,16 @@ -extends Resource class_name UserMinigameHistory +extends Resource const MIN_DIFFICULTY: int = 0 const MAX_DIFFICULTY: int = 4 const CONSECUTIVE_WINS_TO_PROMOTE: int = 2 const CONSECUTIVE_LOSSES_TO_DEMOTE: int = 2 -@export -var difficulty: int = 0 -@export -var consecutives_losses: int = 0 -@export -var consecutives_wins: int = 0 -@export -var history: Array[bool] = [] +@export var difficulty: int = 0 +@export var consecutives_losses: int = 0 +@export var consecutives_wins: int = 0 +@export var history: Array[bool] = [] + func add_game(is_won: bool) -> void: history.append(is_won) diff --git a/resources/user/user_remediation.gd b/resources/user/user_remediation.gd index 493670c5..8a6836f1 100644 --- a/resources/user/user_remediation.gd +++ b/resources/user/user_remediation.gd @@ -1,6 +1,5 @@ class_name UserRemediation extends Resource - ## A remediation score indicates how much extra practice an item needs. ## It is a cumulative value that becomes more negative when the student struggles ## and rises back toward 0 as they succeed. Items at or below a defined @@ -19,11 +18,9 @@ const REMEDIATION_SCORE: int = -2 # Key is the ID of the GP # Value is the score of the GP -@export -var gps_scores: Dictionary[int, int] = {} +@export var gps_scores: Dictionary[int, int] = {} +@export var gp_last_modified: String = "" -@export -var gp_last_modified: String = "" # Gets the score of a GP if it is below or equals to the remediation score func get_gp_score(id: int) -> int: @@ -31,6 +28,7 @@ func get_gp_score(id: int) -> int: return gps_scores[id] if gps_scores[id] <= REMEDIATION_SCORE else 0 return 0 + # Updates the gp scores from a minigame scores func update_gp_scores(minigame_scores: Dictionary) -> void: if not minigame_scores: @@ -47,9 +45,11 @@ func update_gp_scores(minigame_scores: Dictionary) -> void: set_gp_last_modified(Time.get_datetime_string_from_system(true)) score_changed.emit() + func set_gp_scores(new_scores: Dictionary[int, int]) -> void: gps_scores = new_scores + func set_gp_last_modified(new_date: String) -> void: gp_last_modified = new_date @@ -59,11 +59,9 @@ func set_gp_last_modified(new_date: String) -> void: # Key is the ID of the syllable # Value is the score of the syllable -@export -var syllables_scores: Dictionary[int, int] = {} +@export var syllables_scores: Dictionary[int, int] = {} +@export var syllables_last_modified: String = "" -@export -var syllables_last_modified: String = "" # Gets the score of a syllable if it is below or equals to the remediation score func get_syllable_score(id: int) -> int: @@ -71,6 +69,7 @@ func get_syllable_score(id: int) -> int: return syllables_scores[id] if syllables_scores[id] <= REMEDIATION_SCORE else 0 return 0 + # Updates the syllables scores from a minigame scores func update_syllables_scores(minigame_scores: Dictionary) -> void: if not minigame_scores: @@ -87,9 +86,11 @@ func update_syllables_scores(minigame_scores: Dictionary) -> void: set_syllables_last_modified(Time.get_datetime_string_from_system(true)) score_changed.emit() + func set_syllables_scores(new_scores: Dictionary[int, int]) -> void: syllables_scores = new_scores + func set_syllables_last_modified(new_date: String) -> void: syllables_last_modified = new_date @@ -99,11 +100,9 @@ func set_syllables_last_modified(new_date: String) -> void: # Key is the ID of the word # Value is the score of the word -@export -var words_scores: Dictionary[int, int] = {} +@export var words_scores: Dictionary[int, int] = {} +@export var words_last_modified: String = "" -@export -var words_last_modified: String = "" # Gets the score of a word if it is below or equals to the remediation score func get_word_score(id: int) -> int: @@ -111,6 +110,7 @@ func get_word_score(id: int) -> int: return words_scores[id] if words_scores[id] <= REMEDIATION_SCORE else 0 return 0 + # Updates the words scores from a minigame scores func update_words_scores(minigame_scores: Dictionary) -> void: if not minigame_scores: @@ -127,9 +127,11 @@ func update_words_scores(minigame_scores: Dictionary) -> void: set_words_last_modified(Time.get_datetime_string_from_system(true)) score_changed.emit() + func set_words_scores(new_scores: Dictionary[int, int]) -> void: words_scores = new_scores + func set_words_last_modified(new_date: String) -> void: words_last_modified = new_date diff --git a/resources/user/user_speeches.gd b/resources/user/user_speeches.gd index 3aab16f4..5942c91d 100644 --- a/resources/user/user_speeches.gd +++ b/resources/user/user_speeches.gd @@ -1,15 +1,17 @@ -extends Resource class_name UserSpeeches +extends Resource -signal speeches_changed +signal speeches_changed() # Contains the list of speeches already played @export var speeches_played: Array[String] = [] + func add_speech(speech: String) -> void: if not speeches_played.has(speech): speeches_played.append(speech) speeches_changed.emit() + func is_speech_played(speech: String) -> bool: return speeches_played.has(speech) diff --git a/script_templates/Node/default.gd b/script_templates/Node/default.gd index c6232da6..449353cb 100644 --- a/script_templates/Node/default.gd +++ b/script_templates/Node/default.gd @@ -22,13 +22,20 @@ extends _BASE_ ## and any further detail. #05. signals + #06. enums + #07. constants + #08. static variables + #09. @export variables + #10. remaning regular variables + #11. @onready variables + #12. static_init # Called automatically when the class is loaded, after the static variables have been initialized static func _static_init(): @@ -38,6 +45,8 @@ static func _static_init(): #13. remaining static methods + + #14-1. overridden built-in virtual methods: # Called upon creating the object in memory. func _init(): @@ -66,6 +75,11 @@ func _physics_process(float) -> void: #14-2. remaining virtual methods + #15. overridden custom methods + + #16. remaining methods + + #17. subclasses diff --git a/sources/gardens/flower_particle.gd b/sources/gardens/flower_particle.gd index 0b291dd4..d60808c4 100644 --- a/sources/gardens/flower_particle.gd +++ b/sources/gardens/flower_particle.gd @@ -1,5 +1,5 @@ -extends Control class_name FlowerVFX +extends Control @export var sounds: Array[AudioStream] = [] @@ -8,9 +8,9 @@ class_name FlowerVFX $Particles2, $Particles3 ] - @onready var audio_stream_player: AudioStreamPlayer2D = $AudioStreamPlayer2D + func play() -> void: audio_stream_player.stream = sounds.pick_random() audio_stream_player.play() diff --git a/sources/gardens/gardens.gd b/sources/gardens/gardens.gd index 82545800..93d31e34 100644 --- a/sources/gardens/gardens.gd +++ b/sources/gardens/gardens.gd @@ -1,30 +1,39 @@ -extends Control class_name Gardens +extends Control signal minigame_layout_opened() -# Namespace const KALULU := preload("res://sources/minigames/base/kalulu.gd") - const GARDEN_SCENE: PackedScene = preload("res://resources/gardens/garden.tscn") const LOOK_AND_LEARN_SCENE: PackedScene = preload("res://sources/look_and_learn/look_and_learn.tscn") const FLOWER_FVX: PackedScene = preload("res://sources/gardens/flower_particle.tscn") - const GARDEN_SIZE: int = 2400 +static var transition_data: Dictionary = {} + @export_category("Layout") @export var gardens_layout: GardensLayout: set = set_gardens_layout @export var starting_garden: int = -1 - @export_category("Colors") @export var unlocked_color: Color = Color("1c2662") #blue @export var locked_color: Color = Color("1d2229") #black - @export_group("Minigames") @export var minigames_scenes: Array[PackedScene] = [] @export var minigames_icons: Array[Texture] = [] +var lessons: Dictionary = {} +var points: Array[Array] = [] +var is_scrolling: bool = false +var scroll_beginning_garden: int = 0 +var scroll_tween: Tween +var is_locked: bool = false +var in_minigame_selection: bool = false +var current_lesson_number: int = -1 +var current_garden: Garden +var current_button_global_position: Vector2 = Vector2.ZERO +var current_button: LessonButton + @onready var garden_parent: HBoxContainer = %GardenParent @onready var locked_line: Line2D = $ScrollContainer/LockedLine @onready var unlocked_line: Line2D = $ScrollContainer/UnlockedLine @@ -48,26 +57,10 @@ const GARDEN_SIZE: int = 2400 @onready var lock: Control = %Lock @onready var kalulu: KALULU = %Kalulu @onready var kalulu_button: CanvasItem = %KaluluButton - @onready var intro_speech: AudioStreamMP3 = Database.load_external_sound(Database.get_kalulu_speech_path("gardens_screen", "intro")) @onready var help_few_plants_speech: AudioStreamMP3 = Database.load_external_sound(Database.get_kalulu_speech_path("gardens_screen", "help_few_plants")) @onready var help_many_plants_speech: AudioStreamMP3 = Database.load_external_sound(Database.get_kalulu_speech_path("gardens_screen", "help_many_plants")) -var lessons: Dictionary = {} -var points: Array[Array] = [] -var is_scrolling: bool = false -var scroll_beginning_garden: int = 0 -var scroll_tween: Tween -var is_locked: bool = false - -var in_minigame_selection: bool = false -var current_lesson_number: int = -1 -var current_garden: Garden -var current_button_global_position: Vector2 = Vector2.ZERO -var current_button: LessonButton - -static var transition_data: Dictionary = {} - func _ready() -> void: @@ -382,7 +375,6 @@ func _ready() -> void: await kalulu.play_kalulu_speech(intro_speech) kalulu_button.show() UserDataManager.mark_speech_as_played("gardens") - static func compute_lessons_distribution(total_lessons: int, garden_layouts: Array[GardenLayout]) -> Array[int]: diff --git a/sources/gardens/gardens_edit_tool.gd b/sources/gardens/gardens_edit_tool.gd index c68048cc..8d22c690 100644 --- a/sources/gardens/gardens_edit_tool.gd +++ b/sources/gardens/gardens_edit_tool.gd @@ -5,7 +5,6 @@ const GARDEN_TEXTURES_NB: int = 20 const FLOWER_TYPES_NB: int = 5 const GARDENS_LAYOUT_RESOURCE_PATH: String = "res://resources/gardens/gardens_layout.tres" - var dragging_element: Variant var drag_data: Dictionary = {} diff --git a/sources/gardens/minigame_layout.gd b/sources/gardens/minigame_layout.gd index d00ef204..b5ee2bcb 100644 --- a/sources/gardens/minigame_layout.gd +++ b/sources/gardens/minigame_layout.gd @@ -1,20 +1,23 @@ -extends TextureRect class_name MinigameLayout +extends TextureRect signal pressed() +var is_disabled: bool = false + @onready var icon: TextureRect = $TextureRect @onready var area: Area2D = $Area2D @onready var right_fx: RightFX = $TextureRect/RightFX -var is_disabled: bool = false func _ready() -> void: area.connect("input_event", _on_click) + func _on_click(_viewport: Node, event: InputEvent, _shape_idx: int) -> void: if event.is_action_pressed("left_click") and not is_disabled: pressed.emit() + func right() -> void: right_fx.play() diff --git a/sources/kalulu.gd b/sources/kalulu.gd index 0410f493..2ddd65a3 100644 --- a/sources/kalulu.gd +++ b/sources/kalulu.gd @@ -1,12 +1,11 @@ extends AnimatedSprite2D + func _on_animation_finished() -> void: - if animation in ["Hide", "Show"]: return var rand: float = randf() - match animation: "Idle1", "Idle2": if rand < 0.5: diff --git a/sources/language_tool/fish_word_list.gd b/sources/language_tool/fish_word_list.gd index 83916744..3898c2c2 100644 --- a/sources/language_tool/fish_word_list.gd +++ b/sources/language_tool/fish_word_list.gd @@ -2,10 +2,10 @@ extends Control const ELEMENT_SCENE: PackedScene = preload("res://sources/language_tool/fish_word_list_element.tscn") -@onready var elements_container: VBoxContainer = %ElementsContainer - var word_list: Array = [] +@onready var elements_container: VBoxContainer = %ElementsContainer + func _ready() -> void: var query: String = "SELECT name FROM sqlite_master WHERE type='table' AND name='Pseudowords'" diff --git a/sources/language_tool/fish_word_list_element.gd b/sources/language_tool/fish_word_list_element.gd index eeb7e786..963b2def 100644 --- a/sources/language_tool/fish_word_list_element.gd +++ b/sources/language_tool/fish_word_list_element.gd @@ -1,6 +1,5 @@ -extends MarginContainer class_name FishWordListElement - +extends MarginContainer @export var word_id: int = 1: set = set_word_id @@ -10,13 +9,13 @@ class_name FishWordListElement set = set_lesson_nb @export var pseudoword_id: int = -1 +var is_in_line_edit_changed: bool = false +var word: String = "" + @onready var option_button: OptionButton = %OptionButton @onready var line_edit: LineEdit = %LineEdit @onready var lesson_label: Label = %LessonLabel -var is_in_line_edit_changed: bool = false -var word: String = "" - func set_word_id(p_word_id: int) -> void: word_id = p_word_id diff --git a/sources/language_tool/globals.gd b/sources/language_tool/globals.gd index 08c88302..21990600 100644 --- a/sources/language_tool/globals.gd +++ b/sources/language_tool/globals.gd @@ -1,8 +1,7 @@ extends Node +## Global data for prof_tool only -# For prof_tool only var main_menu_selected_tab: int = 0 - var device_colors: Array[Color] = [ Color("9670e0"), Color("ffe823"), diff --git a/sources/language_tool/gp_image_and_sound_descriptions.gd b/sources/language_tool/gp_image_and_sound_descriptions.gd index a0d837fc..b91ebc3c 100644 --- a/sources/language_tool/gp_image_and_sound_descriptions.gd +++ b/sources/language_tool/gp_image_and_sound_descriptions.gd @@ -1,10 +1,10 @@ -extends Control class_name GPImageAndSoundDescriptions - -@onready var description_container: VBoxContainer = %DescriptionsContainer +extends Control const DESCRIPTION_LINE_SCENE: PackedScene = preload("res://sources/language_tool/image_and_sound_gp_description.tscn") +@onready var description_container: VBoxContainer = %DescriptionsContainer + func _ready() -> void: DirAccess.make_dir_recursive_absolute(Database.BASE_PATH + Database.language + Database.LOOK_AND_LEARN_IMAGES) diff --git a/sources/language_tool/gp_list.gd b/sources/language_tool/gp_list.gd index 88b2185e..5924410c 100644 --- a/sources/language_tool/gp_list.gd +++ b/sources/language_tool/gp_list.gd @@ -1,12 +1,11 @@ extends Control +var undo_redo: UndoRedo = UndoRedo.new() var element_scene: PackedScene = preload("res://sources/language_tool/gp_list_element.tscn") @onready var elements_container: VBoxContainer = %ElementsContainer @onready var error_label: Label = %ErrorLabel -var undo_redo: UndoRedo = UndoRedo.new() - func _ready() -> void: var query: String = "Select * FROM GPs ORDER BY GPs.Grapheme" @@ -79,7 +78,6 @@ func _on_back_button_pressed() -> void: get_tree().change_scene_to_file("res://sources/language_tool/prof_tool_menu.tscn") - func _on_grapheme_gui_input(event: InputEvent) -> void: if event.is_action_pressed("left_click"): _reorder_by("grapheme") diff --git a/sources/language_tool/gp_list_button.gd b/sources/language_tool/gp_list_button.gd index 7268a68a..576e4bf6 100644 --- a/sources/language_tool/gp_list_button.gd +++ b/sources/language_tool/gp_list_button.gd @@ -1,5 +1,5 @@ -extends OptionButton class_name GPListButton +extends OptionButton signal gp_selected(id: int) signal new_selected() diff --git a/sources/language_tool/gp_list_element.gd b/sources/language_tool/gp_list_element.gd index 36a29fd6..e8890ca5 100644 --- a/sources/language_tool/gp_list_element.gd +++ b/sources/language_tool/gp_list_element.gd @@ -1,5 +1,5 @@ -extends MarginContainer class_name GPListElement +extends MarginContainer signal delete_pressed() signal validated() @@ -10,18 +10,6 @@ enum Type { Consonant, } -@onready var exception_checkbox: CheckBox = %ExceptionCheckBox -@onready var exception_edit_checkbox: CheckBox = %ExceptionEditCheckBox -@onready var grapheme_label: Label = $%Grapheme -@onready var phoneme_label: Label = $%Phoneme -@onready var type_label: Label = $%Type -@onready var grapheme_edit: LineEdit = $%GraphemeEdit -@onready var phoneme_edit: LineEdit = $%PhonemeEdit -@onready var type_edit: OptionButton = $%TypeEdit -@onready var tab_container: TabContainer = $%TabContainer - - - var grapheme: String = "": set = set_grapheme var phoneme: String = "": @@ -37,6 +25,16 @@ var undo_redo: UndoRedo: undo_redo = UndoRedo.new() return undo_redo +@onready var exception_checkbox: CheckBox = %ExceptionCheckBox +@onready var exception_edit_checkbox: CheckBox = %ExceptionEditCheckBox +@onready var grapheme_label: Label = $%Grapheme +@onready var phoneme_label: Label = $%Phoneme +@onready var type_label: Label = $%Type +@onready var grapheme_edit: LineEdit = $%GraphemeEdit +@onready var phoneme_edit: LineEdit = $%PhonemeEdit +@onready var type_edit: OptionButton = $%TypeEdit +@onready var tab_container: TabContainer = $%TabContainer + func set_grapheme(p_grapheme: String) -> void: grapheme = p_grapheme @@ -61,6 +59,7 @@ func set_type(p_type: Type) -> void: if type_edit: type_edit.selected = type + func set_exception(p_exception: bool) -> void: exception = p_exception if exception_checkbox: diff --git a/sources/language_tool/gp_select_popup.gd b/sources/language_tool/gp_select_popup.gd index 5218b133..268f03c6 100644 --- a/sources/language_tool/gp_select_popup.gd +++ b/sources/language_tool/gp_select_popup.gd @@ -4,14 +4,12 @@ signal gp_selected(grapheme_ind: int, gp_id: int, text: String) signal focus_changed(has_focus: bool) signal new_gp_asked() -@onready var container: VBoxContainer = $VBoxContainer -@onready var button: Button = $Button - - var grapheme_ind: int = -1 var ind_selected: int = -1: set = set_ind_selected +@onready var container: VBoxContainer = $VBoxContainer +@onready var button: Button = $Button func _ready() -> void: diff --git a/sources/language_tool/gp_video_descriptions.gd b/sources/language_tool/gp_video_descriptions.gd index 05f766ed..7c7fc759 100644 --- a/sources/language_tool/gp_video_descriptions.gd +++ b/sources/language_tool/gp_video_descriptions.gd @@ -1,9 +1,9 @@ extends Control -@onready var description_container: VBoxContainer = %DescriptionsContainer - const DESCRIPTION_LINE_SCENE: PackedScene = preload("res://sources/language_tool/video_gp_description.tscn") +@onready var description_container: VBoxContainer = %DescriptionsContainer + func _ready() -> void: var _description_line: VideoGPDescription = DESCRIPTION_LINE_SCENE.instantiate() diff --git a/sources/language_tool/image_and_sound_gp_description.gd b/sources/language_tool/image_and_sound_gp_description.gd index 8214807a..1656639f 100644 --- a/sources/language_tool/image_and_sound_gp_description.gd +++ b/sources/language_tool/image_and_sound_gp_description.gd @@ -1,7 +1,11 @@ -extends HBoxContainer class_name ImageAndSoundGPDescription +extends HBoxContainer -signal delete +signal deleted() + +var gp: Dictionary = {} +var get_image_path: Callable = Database.get_gp_look_and_learn_image_path +var get_sound_path: Callable = Database.get_gp_look_and_learn_sound_path @onready var gp_menu_button: MenuButton = %GPMenuButton @onready var image_preview: TextureRect = %ImagePreview @@ -13,10 +17,6 @@ signal delete @onready var image_clear_button: MarginContainer = %ImageClearButton @onready var sound_clear_button: MarginContainer = %SoundClearButton -var gp: Dictionary = {} -var get_image_path: Callable = Database.get_gp_look_and_learn_image_path -var get_sound_path: Callable = Database.get_gp_look_and_learn_sound_path - func _image_file_selected(file_path: String) -> void: file_dialog.files_selected.connect(_image_file_selected.bind(file_dialog)) @@ -114,7 +114,7 @@ func _on_sound_upload_button_pressed() -> void: func _on_button_pressed() -> void: - delete.emit() + deleted.emit() func _on_sound_preview_pressed() -> void: diff --git a/sources/language_tool/in_game_sounds.gd b/sources/language_tool/in_game_sounds.gd index 277b5762..4bf23baf 100644 --- a/sources/language_tool/in_game_sounds.gd +++ b/sources/language_tool/in_game_sounds.gd @@ -1,6 +1,5 @@ extends GPImageAndSoundDescriptions - func _ready() -> void: DirAccess.make_dir_recursive_absolute(Database.BASE_PATH + Database.language + Database.LANGUAGE_SOUNDS) diff --git a/sources/language_tool/kalulu_speech.gd b/sources/language_tool/kalulu_speech.gd index e7862cc8..ba19a11d 100644 --- a/sources/language_tool/kalulu_speech.gd +++ b/sources/language_tool/kalulu_speech.gd @@ -1,5 +1,5 @@ -extends PanelContainer class_name KaluluSpeech +extends PanelContainer @export var speech_category: String @export var speech_name: String: diff --git a/sources/language_tool/kalulu_speech_title.gd b/sources/language_tool/kalulu_speech_title.gd index 974a938b..11709f81 100644 --- a/sources/language_tool/kalulu_speech_title.gd +++ b/sources/language_tool/kalulu_speech_title.gd @@ -1,6 +1,5 @@ -extends PanelContainer class_name KaluluTitle - +extends PanelContainer @export var title: String = "": set = _set_title diff --git a/sources/language_tool/kalulu_speeches.gd b/sources/language_tool/kalulu_speeches.gd index 3cee60ff..0af491db 100644 --- a/sources/language_tool/kalulu_speeches.gd +++ b/sources/language_tool/kalulu_speeches.gd @@ -1,6 +1,5 @@ extends Control - const TITLE_SCENE: PackedScene = preload("res://sources/language_tool/kalulu_speech_title.tscn") const SPEECH_SCENE: PackedScene = preload("res://sources/language_tool/kalulu_speech.tscn") diff --git a/sources/language_tool/lesson_container.gd b/sources/language_tool/lesson_container.gd index c9ce93cb..1d2a3edf 100644 --- a/sources/language_tool/lesson_container.gd +++ b/sources/language_tool/lesson_container.gd @@ -1,14 +1,12 @@ -extends MarginContainer class_name LessonContainer - -var gp_label_scene: PackedScene = preload("res://sources/language_tool/lesson_gp_label.tscn") +extends MarginContainer signal lesson_dropped(before: bool, number: int, dropped_number: int) +var gp_label_scene: PackedScene = preload("res://sources/language_tool/lesson_gp_label.tscn") var number: int = 0: set = set_number - @onready var gp_container: HBoxContainer = $%GPContainer @onready var number_label: Label = $%NumberLabel diff --git a/sources/language_tool/lesson_exercises_container.gd b/sources/language_tool/lesson_exercises_container.gd index c2dbc9ae..7b322996 100644 --- a/sources/language_tool/lesson_exercises_container.gd +++ b/sources/language_tool/lesson_exercises_container.gd @@ -1,9 +1,11 @@ -extends PanelContainer class_name LessonExerciseContainer +extends PanelContainer @export var lesson_number: int = -1: set = _set_lesson_number +var sentences_by_lesson: Dictionary = {} + @onready var lesson_id_label: Label = %LessonIDLabel @onready var lesson_gps: HBoxContainer = %LessonGPs @onready var exercise_buttons: Array[OptionButton] = [%ExerciseButton1, %ExerciseButton2, %ExerciseButton3] @@ -13,8 +15,6 @@ class_name LessonExerciseContainer @onready var number_of_words: Label = %NumberOfWords @onready var number_of_sentences: Label = %NumberOfSentences -var sentences_by_lesson: Dictionary = {} - func _ready() -> void: Database.db.query("Select * FROM ExerciseTypes") diff --git a/sources/language_tool/lesson_gp_label.gd b/sources/language_tool/lesson_gp_label.gd index 6c6d1e61..a94a46e7 100644 --- a/sources/language_tool/lesson_gp_label.gd +++ b/sources/language_tool/lesson_gp_label.gd @@ -1,5 +1,5 @@ -extends Label class_name LessonGPLabel +extends Label signal gp_dropped(before: bool, data: Dictionary) diff --git a/sources/language_tool/lessons_list.gd b/sources/language_tool/lessons_list.gd index 52beccee..a4975388 100644 --- a/sources/language_tool/lessons_list.gd +++ b/sources/language_tool/lessons_list.gd @@ -1,13 +1,12 @@ extends Control -@onready var lessons_container: VBoxContainer = $%LessonsContainer -@onready var unused_gp_container: GridContainer = $%UnusedGPContainer - var lesson_container_scene: PackedScene = preload("res://sources/language_tool/lesson_container.tscn") var gp_label_scene: PackedScene = preload("res://sources/language_tool/lesson_gp_label.tscn") - var lessons: Dictionary[int, LessonContainer] = {} +@onready var lessons_container: VBoxContainer = $%LessonsContainer +@onready var unused_gp_container: GridContainer = $%UnusedGPContainer + func _ready() -> void: Database.db.query("Select Grapheme, Phoneme, LessonNb, GPID FROM Lessons diff --git a/sources/language_tool/list_title.gd b/sources/language_tool/list_title.gd index 8046d29f..275da387 100644 --- a/sources/language_tool/list_title.gd +++ b/sources/language_tool/list_title.gd @@ -1,5 +1,5 @@ -extends MarginContainer class_name ListTitle +extends MarginContainer signal add_pressed() signal save_pressed() @@ -7,10 +7,11 @@ signal back_pressed() signal new_search(new_text: String) signal import_path_selected(path: String, match_to_file: bool) +var my_button: Button + @onready var title_label: Label = %TitleLabel @onready var file_dialog: FileDialog = $FileDialog -var my_button: Button func _ready() -> void: my_button = file_dialog.add_button("Match list to file (delete elements not in file)", true, "act") diff --git a/sources/language_tool/plus_button.gd b/sources/language_tool/plus_button.gd index a56254a0..6aac3d15 100644 --- a/sources/language_tool/plus_button.gd +++ b/sources/language_tool/plus_button.gd @@ -1,5 +1,5 @@ -extends MarginContainer class_name PlusButton +extends MarginContainer signal pressed() diff --git a/sources/language_tool/prof_tool_menu.gd b/sources/language_tool/prof_tool_menu.gd index fd08efad..2dc95008 100644 --- a/sources/language_tool/prof_tool_menu.gd +++ b/sources/language_tool/prof_tool_menu.gd @@ -1,7 +1,14 @@ extends Control +enum FileCheckResult { + OK, + ERROR_NOT_FOUND, + ERROR_CASE_MISMATCH +} + const BASE_PATH: String = "user://language_resources/" const SAVE_FILE_PATH: String = "user://prof_tool_save.tres" + var save_file: ProfToolSave @onready var language_select_button: OptionButton = %LanguageSelectButton @@ -140,6 +147,7 @@ var integrity_checking: bool = false var integrity_log_path: String = "user://database-integrity-log.txt" var total_integrity_warnings: int = 0 + func _check_db_integrity() -> void: if integrity_checking: return @@ -258,6 +266,7 @@ func _check_db_integrity() -> void: var file_path: String = ProjectSettings.globalize_path(integrity_log_path) Logger.trace("ProfToolMenu: Logs saved at " + file_path) OS.shell_open(file_path) + #endregion func log_message(message: String) -> bool: @@ -281,11 +290,6 @@ func log_message(message: String) -> bool: integrity_checking = false return false -enum FileCheckResult { - OK, - ERROR_NOT_FOUND, - ERROR_CASE_MISMATCH -} func file_exists_case_sensitive(path: String) -> Dictionary: var result: Dictionary = { @@ -325,6 +329,7 @@ func file_exists_case_sensitive(path: String) -> Dictionary: return result + func _get_available_languages() -> Array[String]: var available_languages: Array[String] = [] var dir: DirAccess = DirAccess.open(BASE_PATH) @@ -523,8 +528,8 @@ func _on_open_folder_button_pressed() -> void: func _on_tab_container_tab_changed(tab: int) -> void: Globals.main_menu_selected_tab = tab - #region Book Generation + func create_book() -> void: var lang_path: String = BASE_PATH.path_join(Database.language) var file_names: Dictionary[String, String] = { @@ -635,6 +640,7 @@ func create_book() -> void: error_label.text = "📘 Export data of the booklet finished to path: " + output_path Logger.trace("ProfToolMenu: " + error_label.text) + # Fonction qui ajoute une ligne au dictionnaire func add_row(dict: Dictionary[String, PackedStringArray], row_data: Dictionary[String, String], categorie: String, all_headers: Array) -> void: # Nombre de lignes déjà enregistrées (doit être égal pour chaque colonne) @@ -688,6 +694,7 @@ func parse_csv_line(line: String) -> PackedStringArray: result.append(current) return result + # Transforme une ligne pour l'écriture CSV, avec échappement func escape_csv_line(fields: PackedStringArray) -> String: var output: String = "" @@ -700,10 +707,12 @@ func escape_csv_line(fields: PackedStringArray) -> String: output += "," return output + # Normalise les noms de colonnes (ex: writing page -> Writing page) func normalize_header(header_name: String) -> String: return header_name.strip_edges()[0].to_upper() + header_name.strip_edges().substr(1, -1).to_lower() + # Lit une "ligne logique" complète d’un CSV (même si elle est sur plusieurs lignes à cause des guillemets) func read_csv_record(file: FileAccess) -> String: var record: String = "" @@ -727,5 +736,4 @@ func read_csv_record(file: FileAccess) -> String: return record - #endregion diff --git a/sources/language_tool/segment_build.gd b/sources/language_tool/segment_build.gd index 11d92d7a..be48bff9 100644 --- a/sources/language_tool/segment_build.gd +++ b/sources/language_tool/segment_build.gd @@ -1,14 +1,14 @@ -extends HBoxContainer class_name SegmentBuild +extends HBoxContainer -signal modify() -signal delete() +signal modified() +signal deleted() + +var points: Array[Vector2] = [] @onready var number_of_points_labels: Label = %NumberOfPointsLabel @onready var color_rect: ColorRect = %ColorRect -var points: Array[Vector2] = [] - func add_point(point: Vector2) -> void: points.append(point) @@ -35,9 +35,9 @@ func set_color(color: Color) -> void: func _on_modify_button_pressed() -> void: - modify.emit() + modified.emit() func _on_delete_button_pressed() -> void: - delete.emit() + deleted.emit() queue_free() diff --git a/sources/language_tool/segment_container.gd b/sources/language_tool/segment_container.gd index ff4106cb..9b33a42a 100644 --- a/sources/language_tool/segment_container.gd +++ b/sources/language_tool/segment_container.gd @@ -1,25 +1,24 @@ -extends HBoxContainer class_name SegmentContainer +extends HBoxContainer signal changed() +const SEGMENT_BUILD_SCENE: PackedScene = preload("res://sources/language_tool/segment_build.tscn") +const POINT_BUTTON_SCENE: PackedScene = preload("res://sources/language_tool/segment_point_button.tscn") + @export var points_per_lines: int = 25 @export var points_per_gradient: int = 7 +var gradient: Gradient +var current_segment: SegmentBuild +var current_button: SegmentPointButton +var buttons: Array[SegmentPointButton] = [] + @onready var grapheme_label: Label = %GraphemeLabel @onready var buttons_parent: Control = %ButtonsParent @onready var segments_container: VBoxContainer = %SegmentsContainer @onready var lines: Node2D = %Lines -const SEGMENT_BUILD_SCENE: PackedScene = preload("res://sources/language_tool/segment_build.tscn") -const POINT_BUTTON_SCENE: PackedScene = preload("res://sources/language_tool/segment_point_button.tscn") - -var gradient: Gradient - -var current_segment: SegmentBuild -var current_button: SegmentPointButton -var buttons: Array[SegmentPointButton] = [] - func reset() -> void: var to_free: Array[Node] = lines.get_children() @@ -126,8 +125,8 @@ func _on_add_segment_button_pressed() -> void: segments_container.add_child(new_segment) # Connect signals for modifying and deleting the segment - new_segment.modify.connect(_on_segment_modify.bind(new_segment)) - new_segment.delete.connect(_on_segment_delete.bind(new_segment)) + new_segment.modified.connect(_on_segment_modified.bind(new_segment)) + new_segment.deleted.connect(_on_segment_deleted.bind(new_segment)) # Store the new segment as the currently selected one current_segment = new_segment @@ -156,15 +155,13 @@ func _on_add_segment_button_pressed() -> void: changed.emit() -func _on_segment_modify(segment: SegmentBuild) -> void: +func _on_segment_modified(segment: SegmentBuild) -> void: current_segment = segment - match_segment_with_buttons() - changed.emit() -func _on_segment_delete(segment: SegmentBuild) -> void: +func _on_segment_deleted(segment: SegmentBuild) -> void: if segment == current_segment: var possible_segments: Array[Node] = segments_container.get_children() if not possible_segments.is_empty(): diff --git a/sources/language_tool/segment_point_button.gd b/sources/language_tool/segment_point_button.gd index e220abef..7ad450fa 100644 --- a/sources/language_tool/segment_point_button.gd +++ b/sources/language_tool/segment_point_button.gd @@ -1,5 +1,5 @@ -extends Control class_name SegmentPointButton +extends Control signal point_down() signal point_up() diff --git a/sources/language_tool/sentence_list.gd b/sources/language_tool/sentence_list.gd index b46bfcf5..123cb9a3 100644 --- a/sources/language_tool/sentence_list.gd +++ b/sources/language_tool/sentence_list.gd @@ -1,6 +1,7 @@ extends WordList var not_found_list: String = "" + @onready var export_not_found_button: Button = %ExportNotFoundButton @onready var file_dialog_export: FileDialog = $FileDialogExport diff --git a/sources/language_tool/sentence_list_element.gd b/sources/language_tool/sentence_list_element.gd index 02114aaa..da7c1c13 100644 --- a/sources/language_tool/sentence_list_element.gd +++ b/sources/language_tool/sentence_list_element.gd @@ -1,5 +1,5 @@ -extends WordListElement class_name SentenceListElement +extends WordListElement signal not_found(text: String) @@ -13,8 +13,6 @@ func _ready() -> void: graphemes_label.hide() - - func update_lesson() -> void: var highest_min_lesson: int = -1 diff --git a/sources/language_tool/syllable_list.gd b/sources/language_tool/syllable_list.gd index e93d2346..e976a55e 100644 --- a/sources/language_tool/syllable_list.gd +++ b/sources/language_tool/syllable_list.gd @@ -1,4 +1,4 @@ -extends "res://sources/language_tool/word_list.gd" +extends WordList func _on_list_title_import_path_selected(path: String, match_to_file: bool) -> void: diff --git a/sources/language_tool/tracing_builder.gd b/sources/language_tool/tracing_builder.gd index d9cd03b1..e6b35a05 100644 --- a/sources/language_tool/tracing_builder.gd +++ b/sources/language_tool/tracing_builder.gd @@ -1,18 +1,18 @@ extends Control +const EXTENSION: String = ".csv" + @export var gradient: Gradient +var letters: Array[String] = [] +var current_letter: int = -1 + @onready var lower_container: SegmentContainer = %Lower @onready var upper_container: SegmentContainer = %Upper @onready var letter_picker: OptionButton = %LetterPicker @onready var save_ok: TextureRect = %SaveOk @onready var copy_from: MenuButton = %CopyFrom -const EXTENSION: String = ".csv" - -var letters: Array[String] = [] -var current_letter: int = -1 - func _ready() -> void: copy_from.get_popup().id_pressed.connect(_on_copy_from_id_pressed) diff --git a/sources/language_tool/video_gp_description.gd b/sources/language_tool/video_gp_description.gd index 8891e1b5..29d86d34 100644 --- a/sources/language_tool/video_gp_description.gd +++ b/sources/language_tool/video_gp_description.gd @@ -1,16 +1,16 @@ -extends HBoxContainer class_name VideoGPDescription +extends HBoxContainer @warning_ignore("unused_signal") -signal delete +signal deleted() + +var gp: Dictionary = {} @onready var gp_menu_button: MenuButton = %GPMenuButton @onready var video_player: VideoStreamPlayer = %VideoStreamPlayer @onready var video_upload_button: PlusButton = %VideoUploadButton @onready var file_dialog: FileDialog = $FileDialog -var gp: Dictionary = {} - func _video_file_selected(file_path: String) -> void: file_dialog.files_selected.connect(_video_file_selected.bind(file_dialog)) diff --git a/sources/language_tool/word_list.gd b/sources/language_tool/word_list.gd index 35657079..3c5313ed 100644 --- a/sources/language_tool/word_list.gd +++ b/sources/language_tool/word_list.gd @@ -1,8 +1,16 @@ -extends Control class_name WordList +extends Control @export var element_scene: PackedScene = preload("res://sources/language_tool/word_list_element.tscn") +var undo_redo: UndoRedo = UndoRedo.new() +var in_new_gp_mode: bool = false: + set = set_in_new_gp_mode +var _element: WordListElement +var sub_elements_list: Dictionary = {} +var new_gp_asked_element: WordListElement +var new_gp_asked_ind: int + @onready var elements_container: VBoxContainer = %ElementsContainer @onready var new_gp_layer: CanvasLayer = $NewGPLayer @onready var new_gp: Variant = %NewGP @@ -12,14 +20,6 @@ class_name WordList @onready var graphemes_title: Label = %Graphemes @onready var error_label: Label = %ErrorLabel -var undo_redo: UndoRedo = UndoRedo.new() -var in_new_gp_mode: bool = false: - set = set_in_new_gp_mode -var _element: WordListElement -var sub_elements_list: Dictionary = {} -var new_gp_asked_element: WordListElement -var new_gp_asked_ind: int - func create_sub_elements_list() -> void: sub_elements_list.clear() @@ -190,7 +190,6 @@ func _on_save_button_pressed() -> void: undo_redo.clear_history() - func _on_back_button_pressed() -> void: get_tree().change_scene_to_file("res://sources/language_tool/prof_tool_menu.tscn") diff --git a/sources/language_tool/word_list_element.gd b/sources/language_tool/word_list_element.gd index 331d68d6..a9adb0da 100644 --- a/sources/language_tool/word_list_element.gd +++ b/sources/language_tool/word_list_element.gd @@ -1,5 +1,5 @@ -extends MarginContainer class_name WordListElement +extends MarginContainer signal delete_pressed() signal new_gp_asked(i: int) @@ -17,21 +17,6 @@ const PLUS_BUTTON_SCENE: PackedScene = preload("res://sources/language_tool/plus @export var relational_table: String = "GPsInWords" @export var sub_table_id: String = "GPID" -@onready var word_label: Label = %Word -@onready var graphemes_label: Label = %Graphemes -@onready var word_edit: LineEdit = %WordEdit -@onready var tab_container: TabContainer = $TabContainer -@onready var lesson_label: Label = %Lesson -@onready var exception_checkbox: CheckBox = %ExceptionCheckBox -@onready var exception_edit_checkbox: CheckBox = %ExceptionEditCheckBox -@onready var reading_checkbox: CheckBox = %ReadingCheckBox -@onready var writing_checkbox: CheckBox = %WritingCheckBox -@onready var reading_edit_checkbox: CheckBox = %ReadingEditCheckBox -@onready var writing_edit_checkbox: CheckBox = %WritingEditCheckBox -@onready var graphemes_edit_container: HBoxContainer = %GraphemesEditContainer -@onready var add_gp_button: MarginContainer = %AddGPButton -@onready var remove_gp_button: MarginContainer = %RemoveGPButton2 - var word: String = "": set = set_word var lesson: int = 0: @@ -53,6 +38,21 @@ var writing: int = 0: set = set_writing var sub_elements_list: Dictionary = {} +@onready var word_label: Label = %Word +@onready var graphemes_label: Label = %Graphemes +@onready var word_edit: LineEdit = %WordEdit +@onready var tab_container: TabContainer = $TabContainer +@onready var lesson_label: Label = %Lesson +@onready var exception_checkbox: CheckBox = %ExceptionCheckBox +@onready var exception_edit_checkbox: CheckBox = %ExceptionEditCheckBox +@onready var reading_checkbox: CheckBox = %ReadingCheckBox +@onready var writing_checkbox: CheckBox = %WritingCheckBox +@onready var reading_edit_checkbox: CheckBox = %ReadingEditCheckBox +@onready var writing_edit_checkbox: CheckBox = %WritingEditCheckBox +@onready var graphemes_edit_container: HBoxContainer = %GraphemesEditContainer +@onready var add_gp_button: MarginContainer = %AddGPButton +@onready var remove_gp_button: MarginContainer = %RemoveGPButton2 + func set_exception(p_exception: bool) -> void: exception = p_exception @@ -61,6 +61,7 @@ func set_exception(p_exception: bool) -> void: if exception_edit_checkbox: exception_edit_checkbox.button_pressed = bool(exception) + func set_reading(p_reading: bool) -> void: reading = p_reading if reading_checkbox: @@ -68,6 +69,7 @@ func set_reading(p_reading: bool) -> void: if reading_edit_checkbox: reading_edit_checkbox.button_pressed = bool(reading) + func set_writing(p_writing: bool) -> void: writing = p_writing if writing_checkbox: @@ -367,7 +369,6 @@ func _on_add_gp_button_pressed(element: Node) -> void: add_gp_list_button(gp_id, ind_gp_id + 1) - func _on_empty_add_gp_button_pressed() -> void: var gp_id: int = sub_elements_list.keys()[0] unvalidated_gp_ids.append(gp_id) diff --git a/sources/lesson_screen/lesson_button.gd b/sources/lesson_screen/lesson_button.gd index 18dd47cb..129cfc8b 100644 --- a/sources/lesson_screen/lesson_button.gd +++ b/sources/lesson_screen/lesson_button.gd @@ -1,5 +1,5 @@ -extends TextureButton class_name LessonButton +extends TextureButton @export_color_no_alpha var base_color: Color: set = _set_base_color @@ -15,11 +15,12 @@ class_name LessonButton @onready var placeholder: TextureRect = %Placeholder @onready var right_fx: RightFX = %RightFX + func _ready() -> void: _set_base_color(base_color) _set_completed_color(completed_color) _set_text(text) - + func show_placeholder(is_shown: bool) -> void: placeholder.visible = is_shown @@ -30,6 +31,7 @@ func right() -> void: right_fx.play() await right_fx.finished + func _set_base_color(color: Color) -> void: base_color = color if center and not completed: diff --git a/sources/look_and_learn/letter_segment.gd b/sources/look_and_learn/letter_segment.gd index 61d3784c..dede76d1 100644 --- a/sources/look_and_learn/letter_segment.gd +++ b/sources/look_and_learn/letter_segment.gd @@ -1,5 +1,5 @@ -extends Node2D class_name LetterSegment +extends Node2D signal finished() @@ -25,6 +25,7 @@ func start() -> void: func stop() -> void: finished.emit() + func demo() -> void: tracing_path.demo() diff --git a/sources/look_and_learn/look_and_learn.gd b/sources/look_and_learn/look_and_learn.gd index e52a7780..80fce461 100644 --- a/sources/look_and_learn/look_and_learn.gd +++ b/sources/look_and_learn/look_and_learn.gd @@ -1,9 +1,20 @@ -extends Control class_name LookAndLearn +extends Control + +static var transition_data: Dictionary = {} @export var lesson_nb: int = 1 @export var current_button_pressed: int = 0 +var gp_list: Array[Dictionary] = [] +var current_video: int = 0 +var videos: Array[VideoStream] = [] +var current_image_and_sound: int = 0 +var images: Array[Texture] = [] +var sounds: Array[AudioStream] = [] +var gardens_data: Dictionary = {} +var current_tracing: int = 0 + @onready var animation_player: AnimationPlayer = $AnimationPlayer @onready var audio_player: AudioStreamPlayer = $AudioStreamPlayer @onready var video_player: VideoStreamPlayer = %VideoStreamPlayer @@ -13,21 +24,6 @@ class_name LookAndLearn @onready var grapheme_particles: GPUParticles2D = $GraphemeParticles -var gp_list: Array[Dictionary] = [] -var current_video: int = 0 -var videos: Array[VideoStream] = [] - -var current_image_and_sound: int = 0 -var images: Array[Texture] = [] -var sounds: Array[AudioStream] = [] - -static var transition_data: Dictionary = {} -var gardens_data: Dictionary = {} - - -var current_tracing: int = 0 - - func _ready() -> void: MusicManager.stop() @@ -157,7 +153,6 @@ func _on_tracing_manager_finished() -> void: _back_to_gardens() - func _back_to_gardens() -> void: await OpeningCurtain.close() diff --git a/sources/look_and_learn/tracing_effects.gd b/sources/look_and_learn/tracing_effects.gd index 1c6ffa76..900bb0e5 100644 --- a/sources/look_and_learn/tracing_effects.gd +++ b/sources/look_and_learn/tracing_effects.gd @@ -1,5 +1,5 @@ -extends Node2D class_name TracingEffects +extends Node2D @onready var particles_effect: GPUParticles2D = $TracingParticles @onready var sound_effect: AudioStreamPlayer = $TracingAudioStreamPlayer diff --git a/sources/look_and_learn/tracing_manager.gd b/sources/look_and_learn/tracing_manager.gd index 66347e19..32731810 100644 --- a/sources/look_and_learn/tracing_manager.gd +++ b/sources/look_and_learn/tracing_manager.gd @@ -1,16 +1,16 @@ -extends Control class_name TracingManager +extends Control signal finished() const LETTER_SEGMENT_CLASS: PackedScene = preload("res://sources/look_and_learn/letter_segment.tscn") +const EXTENSION: String = ".csv" @export var label_settings: LabelSettings @onready var lower_labels: HBoxContainer = %LowerLabels @onready var upper_labels: HBoxContainer = %UpperLabels -const EXTENSION: String = ".csv" func _process(_delta: float) -> void: place_segments(upper_labels.get_children()) @@ -34,8 +34,6 @@ func reset() -> void: await get_tree().process_frame -# --- Setup --- - func setup(grapheme: String) -> void: await reset() for letter: String in grapheme: @@ -118,10 +116,6 @@ func _real_path(path: String) -> String: return Database.BASE_PATH.path_join(Database.language).path_join(Database.TRACING_DATA_FOLDER).path_join(path) + EXTENSION - -# --- Start --- - - func start() -> void: if upper_labels.get_child_count(false) > 0: lower_labels.visible = false diff --git a/sources/look_and_learn/tracing_path.gd b/sources/look_and_learn/tracing_path.gd index a7f0b23c..f9688ffd 100644 --- a/sources/look_and_learn/tracing_path.gd +++ b/sources/look_and_learn/tracing_path.gd @@ -1,30 +1,28 @@ -extends Path2D class_name TracingPath +extends Path2D -signal finished -signal demo_finished +signal finished() +signal demo_finished() @export var points_per_curve: int = 25 @export var hand_min_travel_time: float = 0.5 @export var hand_max_travel_time: float = 2.0 @export var distance: float = 100.0 - @export var color_gradient: Gradient +var curve_points: PackedVector2Array +var is_playing: bool = false +var is_in_demo: bool = false +var touch_positions: Array[Vector2] = [] +var should_play_effects: bool = false + @onready var line: Line2D = $Line2D @onready var guide: PathFollow2D = $GuidePathFollow @onready var hand: PathFollow2D = $HandPathFollow2D @onready var guide_sprite: Sprite2D = $GuidePathFollow/Guide @onready var hand_sprite: Sprite2D = $HandPathFollow2D/Hand - -var curve_points: PackedVector2Array @onready var remaining_curve: Curve2D = Curve2D.new() -var is_playing: bool = false -var is_in_demo: bool = false -var touch_positions: Array[Vector2] = [] -var should_play_effects: bool = false - func _ready() -> void: guide_sprite.visible = false diff --git a/sources/menus/adult_check/adult_check.gd b/sources/menus/adult_check/adult_check.gd index e8879bee..9c36450a 100644 --- a/sources/menus/adult_check/adult_check.gd +++ b/sources/menus/adult_check/adult_check.gd @@ -11,10 +11,11 @@ const SYMBOLS_NAMES: Dictionary[String, String] = { "6": "TRIANGLE", } +var password: String = "" + @onready var code_keyboard: CodeKeyboard = %CodeKeyboard @onready var password_label: Label = %PasswordLabel -var password: String = "" func _ready() -> void: _reset_password() diff --git a/sources/menus/brain/brain.gd b/sources/menus/brain/brain.gd index 965660c6..a0e62f9c 100644 --- a/sources/menus/brain/brain.gd +++ b/sources/menus/brain/brain.gd @@ -10,7 +10,6 @@ const KALULU := preload("res://sources/minigames/base/kalulu.gd") @onready var kalulu: KALULU = $Kalulu @onready var kalulu_button: TextureButton = %KaluluButton @onready var audio_stream_player: AudioStreamPlayer = $AudioStreamPlayer - @onready var garden_buttons: Array[TextureButton] = [ %GardenButton1, %GardenButton2, @@ -33,7 +32,6 @@ const KALULU := preload("res://sources/minigames/base/kalulu.gd") %GardenButton19, %GardenButton20, ] - @onready var particles: Array[GPUParticles2D] = [ %Particles1, %Particles2, @@ -56,18 +54,18 @@ const KALULU := preload("res://sources/minigames/base/kalulu.gd") %Particles19, %Particles20, ] - @onready var tutorial_speeches: Array[AudioStream]= [ Database.load_external_sound(Database.get_kalulu_speech_path("brain_screen", "intro_1")), Database.load_external_sound(Database.get_kalulu_speech_path("brain_screen", "intro_2")), Database.load_external_sound(Database.get_kalulu_speech_path("brain_screen", "intro_3")) ] - @onready var help_speech: AudioStream = Database.load_external_sound(Database.get_kalulu_speech_path("brain_screen", "help")) + static func _compute_lessons_distribution(total_lessons: int, garden_layouts: Array[GardenLayout]) -> Array[int]: return Gardens.compute_lessons_distribution(total_lessons, garden_layouts) + func _ready() -> void: UserDataManager.start_synchronization_timer() diff --git a/sources/menus/components/code_keyboard.gd b/sources/menus/components/code_keyboard.gd index ad79b7e2..710ac50e 100644 --- a/sources/menus/components/code_keyboard.gd +++ b/sources/menus/components/code_keyboard.gd @@ -1,14 +1,15 @@ -extends Control class_name CodeKeyboard +extends Control signal button_pressed(key: String, password: Array[String]) signal password_entered(password: String) +var password: Array[String] = [] + @onready var password_visualizer: PasswordVisualizer = %PasswordVisualizer @onready var buttons: GridContainer = %Buttons @onready var sound_player: AudioStreamPlayer = $ButtonSoundPlayer -var password: Array[String] = [] func _ready() -> void: for button: TextureButton in buttons.get_children(false): diff --git a/sources/menus/components/password_visualizer.gd b/sources/menus/components/password_visualizer.gd index 620ab0b4..5892d691 100644 --- a/sources/menus/components/password_visualizer.gd +++ b/sources/menus/components/password_visualizer.gd @@ -1,6 +1,6 @@ @tool -extends HBoxContainer class_name PasswordVisualizer +extends HBoxContainer const ICONS_TEXTURES: Dictionary[String, CompressedTexture2D] = { "1": preload("res://assets/menus/login/symbol_01.png"), @@ -24,12 +24,14 @@ const ICONS_TEXTURES: Dictionary[String, CompressedTexture2D] = { @onready var icons: Array[TextureRect] = [] + func _ready() -> void: _draw_password() for icon: TextureRect in icons: icon.custom_minimum_size.x = key_size icon.custom_minimum_size.y = key_size + func _draw_password() -> void: if not icons: diff --git a/sources/menus/device_selection/device_selection.gd b/sources/menus/device_selection/device_selection.gd index 129a06bc..3275256c 100644 --- a/sources/menus/device_selection/device_selection.gd +++ b/sources/menus/device_selection/device_selection.gd @@ -5,9 +5,11 @@ const LOGIN_SCENE_PATH: String = "res://sources/menus/login/login.tscn" @onready var container: GridContainer = %GridContainer + func _ready() -> void: _refresh() + func _refresh() -> void: if not UserDataManager.teacher_settings: return @@ -23,6 +25,7 @@ func _refresh() -> void: button.pressed.connect(_device_button_pressed.bind(device)) OpeningCurtain.open() + func _device_button_pressed(device: int) -> void: Logger.trace("DeviceSelection: User selected device %d" % device) if UserDataManager.set_device_id(device): diff --git a/sources/menus/language_selection/package_downloader.gd b/sources/menus/language_selection/package_downloader.gd index 8d857d8e..c7b73791 100644 --- a/sources/menus/language_selection/package_downloader.gd +++ b/sources/menus/language_selection/package_downloader.gd @@ -1,11 +1,10 @@ -extends Control class_name PackageDownloader +extends Control const MAIN_MENU_SCENE_PATH: String = "res://sources/menus/main/main_menu.tscn" const DEVICE_SELECTION_SCENE_PATH: String = "res://sources/menus/device_selection/device_selection.tscn" const LOGIN_SCENE_PATH: String = "res://sources/menus/login/login.tscn" const USER_LANGUAGE_RESOURCES_PATH: String = "user://language_resources" - const ERROR_MESSAGES: Array[String] = [ "DISCONNECTED_ERROR", "NO_INTERNET_ACCESS", @@ -13,6 +12,12 @@ const ERROR_MESSAGES: Array[String] = [ "INVALID_LANGUAGE_DIRECTORY", ] +var device_language: String +var current_language_path: String +var mutex: Mutex +var thread: Thread +var server_language_version: Dictionary = {} +var current_language_version: Dictionary = {} @onready var http_request: HTTPRequest = $HTTPRequest @onready var checking_label: Label = %CheckingLabel @@ -25,13 +30,6 @@ const ERROR_MESSAGES: Array[String] = [ @onready var error_label: Label = %ErrorLabel @onready var error_popup: ConfirmPopup = $ErrorPopup -var device_language: String -var current_language_path: String -var mutex: Mutex -var thread: Thread - -var server_language_version: Dictionary = {} -var current_language_version: Dictionary = {} func _ready() -> void: await get_tree().process_frame diff --git a/sources/menus/login/login.gd b/sources/menus/login/login.gd index 0668314f..072f355a 100644 --- a/sources/menus/login/login.gd +++ b/sources/menus/login/login.gd @@ -5,9 +5,12 @@ const BACK_SCENE_PATH: String = "res://sources/menus/main/main_menu.tscn" const NEXT_SCENE_PATH: String = "res://sources/menus/brain/brain.tscn" const TEACHER_SCENE_PATH: String = "res://sources/menus/settings/teacher_settings.tscn" const PACKAGE_LOADER_SCENE_PATH: String = "res://sources/menus/language_selection/package_downloader.tscn" - const KALULU := preload("res://sources/minigames/base/kalulu.gd") +var help_speech: AudioStream +var wrong_password_speech: AudioStream +var right_password_speech: AudioStream + @onready var kalulu: KALULU = $Kalulu @onready var music_player: AudioStreamPlayer = $MusicStreamPlayer @onready var device_number_label: Label = $DeviceNumber @@ -16,9 +19,6 @@ const KALULU := preload("res://sources/minigames/base/kalulu.gd") @onready var teacher_help_label: Label = %TeacherHelpLabel @onready var kalulu_button: CanvasItem = %KaluluButton -var help_speech: AudioStream -var wrong_password_speech: AudioStream -var right_password_speech: AudioStream func _ready() -> void: UserDataManager.stop_synchronization_timer() diff --git a/sources/menus/main/device_button.gd b/sources/menus/main/device_button.gd index fc3b0034..fe45a878 100644 --- a/sources/menus/main/device_button.gd +++ b/sources/menus/main/device_button.gd @@ -1,23 +1,22 @@ @tool -extends TextureButton class_name DeviceButton - -@onready var background: TextureRect = $Background -@onready var label: Label = $Label - +extends TextureButton @export_range(1, 99) var number: int: set(value): number = value if label: label.text = str(value) - @export var background_color: Color: set(value): background_color = value if background: background.self_modulate = background_color +@onready var background: TextureRect = $Background +@onready var label: Label = $Label + + func _ready() -> void: label.text = str(number) background.self_modulate = background_color diff --git a/sources/menus/main/kalulu.gd b/sources/menus/main/kalulu.gd index 4e018803..6f3dc7f4 100644 --- a/sources/menus/main/kalulu.gd +++ b/sources/menus/main/kalulu.gd @@ -1,11 +1,7 @@ extends Control -@onready var speech_player: AudioStreamPlayer = $SpeechPlayer -@onready var sprite: AnimatedSprite2D = $Sprite - var tuto_speech: AudioStreamMP3 -var feedback_speech: AudioStreamMP3 - +var feedback_speech: AudioStreamMP3 var is_speaking: bool = false: set(value): is_speaking = value @@ -16,6 +12,9 @@ var is_speaking: bool = false: sprite.play("Tc_Idle1") var elapsed_time: float = 0.0 +@onready var speech_player: AudioStreamPlayer = $SpeechPlayer +@onready var sprite: AnimatedSprite2D = $Sprite + func _ready() -> void: tuto_speech = Database.load_external_sound(Database.get_kalulu_speech_path("title_screen", "tuto_welcome_oneshot")) @@ -26,27 +25,23 @@ func _ready() -> void: func _process(delta: float) -> void: if not visible: return - if not sprite.is_playing(): sprite.play("Tc_Idle1") - if not is_speaking: elapsed_time += delta if elapsed_time > 20: start_speech() + func _play_speech(speech: AudioStream) -> void: if not speech: Logger.warn("Kalulu: Speech not found") is_speaking = false return - is_speaking = true - speech_player.stream = speech speech_player.play() await speech_player.finished - is_speaking = false diff --git a/sources/menus/main/language_field.gd b/sources/menus/main/language_field.gd index 9c473fe3..cec461c1 100644 --- a/sources/menus/main/language_field.gd +++ b/sources/menus/main/language_field.gd @@ -2,6 +2,7 @@ extends OptionButton var items: Array[String] = [] + func _ready() -> void: # Adds the supported locales to the field var idx: int = 0 diff --git a/sources/menus/main/login.gd b/sources/menus/main/login.gd index 478146ee..3c5ae379 100644 --- a/sources/menus/main/login.gd +++ b/sources/menus/main/login.gd @@ -1,12 +1,11 @@ extends Control -signal logged_in +signal logged_in() @onready var validator: FormValidator = %LoginFormValidator @onready var email_field: LineEdit = %EmailField @onready var password_field: LineEdit = %PasswordField @onready var login_message: Label = %LoginError - @onready var device_id_container: VBoxContainer = %DeviceIDContainer @onready var device_id_field: SpinBox = %DeviceIDField diff --git a/sources/menus/main/main_menu.gd b/sources/menus/main/main_menu.gd index 4dbc0be1..86b9157f 100644 --- a/sources/menus/main/main_menu.gd +++ b/sources/menus/main/main_menu.gd @@ -1,14 +1,12 @@ extends Control const KALULU := preload("res://sources/menus/main/kalulu.gd") - const ADULT_CHECK_SCENE_PATH: String = "res://sources/menus/adult_check/adult_check.tscn" const PACKAGE_LOADER_SCENE_PATH: String = "res://sources/menus/language_selection/package_downloader.tscn" @onready var version_label: Label = $Informations/BuildVersionValue @onready var teacher_label: Label = $Informations/TeacherValue @onready var device_id_label: Label = $Informations/DeviceIDValue - @onready var kalulu: KALULU = $Kalulu @onready var play_button: Button = %PlayButton @onready var interface_left: MarginContainer = %InterfaceLeft diff --git a/sources/menus/register/progress_bar.gd b/sources/menus/register/progress_bar.gd index 9cdc637c..779f5914 100644 --- a/sources/menus/register/progress_bar.gd +++ b/sources/menus/register/progress_bar.gd @@ -1,5 +1,6 @@ -extends ProgressBar class_name RegisterProgressBar +extends ProgressBar + func set_value_with_tween(new_value: float) -> void: create_tween().tween_property(self, "value", new_value, 0.15).set_trans(Tween.TRANS_LINEAR) diff --git a/sources/menus/register/register.gd b/sources/menus/register/register.gd index 50417aa7..18fc74e1 100644 --- a/sources/menus/register/register.gd +++ b/sources/menus/register/register.gd @@ -3,6 +3,8 @@ extends Control const MAIN_MENU_PATH: String = "res://sources/menus/main/main_menu.tscn" const NEXT_SCENE_PATH: String = "res://sources/menus/language_selection/package_downloader.tscn" +var current_steps: Array[Step] = [] + @onready var teacher_steps: Array[PackedScene] = [ preload("res://sources/menus/register/steps/teacher/method_step.tscn"), preload("res://sources/menus/register/steps/teacher/devices_count_step.tscn") @@ -18,15 +20,13 @@ const NEXT_SCENE_PATH: String = "res://sources/menus/language_selection/package_ @onready var account_type_step: PackedScene = preload("res://sources/menus/register/steps/account_type_step.tscn") @onready var students_step: PackedScene = preload("res://sources/menus/register/steps/teacher/students_count_step.tscn") @onready var player_step: PackedScene = preload("res://sources/menus/register/steps/parent/player_step.tscn") - -var current_steps: Array[Step] = [] - @onready var register_data: TeacherSettings = TeacherSettings.new() @onready var progress_bar: RegisterProgressBar = %ProgressBar @onready var steps: Control = %Steps @onready var popup: TextureRect = %Popup @onready var popup_info_label: Label = %PopupInfo + func _ready() -> void: current_steps = [account_type_step.instantiate()] _go_to_step(int(progress_bar.value)) @@ -129,5 +129,6 @@ func _remove_future_steps() -> void: # Resize the array to remove unwanted steps current_steps.resize(int(progress_bar.value + 1)) + func _on_popup_button_pressed() -> void: popup.hide() diff --git a/sources/menus/register/steps/account_type_step.gd b/sources/menus/register/steps/account_type_step.gd index 95c64da3..99628ccd 100644 --- a/sources/menus/register/steps/account_type_step.gd +++ b/sources/menus/register/steps/account_type_step.gd @@ -3,6 +3,7 @@ extends Step @onready var type: ItemList = %TypeSelect + func _ready() -> void: type.clear() type.add_item(tr("TEACHER")) diff --git a/sources/menus/register/steps/base_step.gd b/sources/menus/register/steps/base_step.gd index c508258e..73d93a85 100644 --- a/sources/menus/register/steps/base_step.gd +++ b/sources/menus/register/steps/base_step.gd @@ -1,20 +1,21 @@ @tool -extends Control class_name Step +extends Control signal back(step: Step) signal next(step: Step) +@export var step_name: String +@export_multiline var question: String +@export_multiline var infos: String +@export var data: Resource + @onready var question_label: Label = %QuestionLabel @onready var info_label: Label = %InfoLabel @onready var form_validator: FormValidator = %FormValidator @onready var form_binder: FormBinder = %FormBinder @onready var form_container: Control = %FormContainer -@export var step_name: String -@export_multiline var question: String -@export_multiline var infos: String -@export var data: Resource func on_enter() -> void: form_binder.read(data) @@ -25,6 +26,7 @@ func on_enter() -> void: else: info_label.visible = false + func _on_back() -> bool: return true @@ -32,6 +34,7 @@ func _on_back() -> bool: func _on_next() -> bool: return true + # Display error messages func _on_form_validator_control_validated(control: Control, passed: bool, messages: PackedStringArray) -> void: var label: Label = find_child(control.name as String + "Error", true, false) as Label diff --git a/sources/menus/register/steps/credentials_step.gd b/sources/menus/register/steps/credentials_step.gd index 3d766858..8e3ddb1a 100644 --- a/sources/menus/register/steps/credentials_step.gd +++ b/sources/menus/register/steps/credentials_step.gd @@ -3,6 +3,7 @@ extends Step @onready var api_email_field_error: Label = %APIEmailFieldError + func _on_validate_button_pressed() -> void: api_email_field_error.visible = false diff --git a/sources/menus/register/steps/device_recap.gd b/sources/menus/register/steps/device_recap.gd index d6c16066..9cc36239 100644 --- a/sources/menus/register/steps/device_recap.gd +++ b/sources/menus/register/steps/device_recap.gd @@ -1,5 +1,5 @@ -extends Control class_name DeviceRecap +extends Control const STUDENT_PANEL_SCENE: PackedScene = preload("res://sources/menus/settings/student_panel.tscn") @@ -9,6 +9,7 @@ const STUDENT_PANEL_SCENE: PackedScene = preload("res://sources/menus/settings/s @onready var title_label: Label = %Title @onready var students_container: GridContainer = %StudentsContainer + func _ready() -> void: if title: diff --git a/sources/menus/register/steps/recap_step.gd b/sources/menus/register/steps/recap_step.gd index e5eb4bcb..551a8ab4 100644 --- a/sources/menus/register/steps/recap_step.gd +++ b/sources/menus/register/steps/recap_step.gd @@ -1,6 +1,6 @@ @tool -extends Step class_name RecapStep +extends Step const DEVICE_RECAP_SCENE: PackedScene = preload("res://sources/menus/register/steps/device_recap.tscn") @@ -11,6 +11,7 @@ const DEVICE_RECAP_SCENE: PackedScene = preload("res://sources/menus/register/st @onready var devices_count: Label = %DevicesCount @onready var students_count: Label = %StudentsCount + func on_enter() -> void: super.on_enter() diff --git a/sources/menus/register/steps/teacher/students_count_step.gd b/sources/menus/register/steps/teacher/students_count_step.gd index 93698044..35c7c9eb 100644 --- a/sources/menus/register/steps/teacher/students_count_step.gd +++ b/sources/menus/register/steps/teacher/students_count_step.gd @@ -1,10 +1,12 @@ @tool -extends Step class_name StudentsCountStep +extends Step @export var device_id: int + @onready var students_count_field: SpinBox = %StudentsCountField + func _on_back() -> bool: var register_data: TeacherSettings = data as TeacherSettings if register_data: diff --git a/sources/menus/register/steps/validation/confirm_rule.gd b/sources/menus/register/steps/validation/confirm_rule.gd index 5601289b..3bb552fe 100644 --- a/sources/menus/register/steps/validation/confirm_rule.gd +++ b/sources/menus/register/steps/validation/confirm_rule.gd @@ -1,9 +1,10 @@ @tool -extends ValidatorRule class_name ConfirmRule +extends ValidatorRule @export_node_path("Control") var confirm_control_path: NodePath + func _init() -> void: fail_message = "Value must be the same in both fields." diff --git a/sources/menus/register/steps/validation/item_list_validator.gd b/sources/menus/register/steps/validation/item_list_validator.gd index f4396b5f..a24961ec 100644 --- a/sources/menus/register/steps/validation/item_list_validator.gd +++ b/sources/menus/register/steps/validation/item_list_validator.gd @@ -1,6 +1,6 @@ @tool -extends Validator class_name ItemListValidator +extends Validator func get_value(control: Control) -> Variant: diff --git a/sources/menus/settings/device_tab.gd b/sources/menus/settings/device_tab.gd index 6d4e1b35..9ac37508 100644 --- a/sources/menus/settings/device_tab.gd +++ b/sources/menus/settings/device_tab.gd @@ -1,15 +1,15 @@ -extends TabBar class_name DeviceTab +extends TabBar signal student_pressed(code: int) const STUDENT_PANEL_SCENE: PackedScene = preload("res://sources/menus/settings/student_panel.tscn") -@onready var students_container: GridContainer = %StudentsContainer - @export var device_id: int @export var students: Array[StudentData] = [] +@onready var students_container: GridContainer = %StudentsContainer + func _ready() -> void: refresh() diff --git a/sources/menus/settings/lesson_unlock.gd b/sources/menus/settings/lesson_unlock.gd index 709ba506..f6e7f501 100644 --- a/sources/menus/settings/lesson_unlock.gd +++ b/sources/menus/settings/lesson_unlock.gd @@ -1,14 +1,12 @@ -extends MarginContainer class_name LessonUnlock +extends MarginContainer -signal unlocks_changed +signal unlocks_changed() @export var lesson_number: int: set = _set_lesson_number - @export var lesson_gps: String: set = _set_lesson_gps - @export var unlocks: Dictionary = {} @onready var lesson_label: Label = %LessonLabel diff --git a/sources/menus/settings/lesson_unlocks.gd b/sources/menus/settings/lesson_unlocks.gd index 6b83b231..dc9e746a 100644 --- a/sources/menus/settings/lesson_unlocks.gd +++ b/sources/menus/settings/lesson_unlocks.gd @@ -1,24 +1,24 @@ -extends Control class_name LessonUnlocks +extends Control signal student_deleted(code: int) const DEVICE_BUTTON_SCENE: PackedScene = preload("res://sources/menus/main/device_button.tscn") const LESSON_UNLOCK_SCENE: PackedScene = preload("res://sources/menus/settings/lesson_unlock.tscn") -@onready var lesson_container: VBoxContainer = %LessonContainer -@onready var name_line_edit: LineEdit = %NameLineEdit -@onready var device_selection_container: PanelContainer = %DeviceSelectionContainer -@onready var container: GridContainer = %GridContainer - -var teacher_settings: SettingsTeacherSettings = null - @export var device: int: set = _on_device_changed @export var student: int: set = _on_student_changed var progression: StudentProgression +var teacher_settings: SettingsTeacherSettings = null + +@onready var lesson_container: VBoxContainer = %LessonContainer +@onready var name_line_edit: LineEdit = %NameLineEdit +@onready var device_selection_container: PanelContainer = %DeviceSelectionContainer +@onready var container: GridContainer = %GridContainer + func _ready() -> void: name_line_edit.connect("text_submitted", _on_name_changed) diff --git a/sources/menus/settings/sound_settings_button.gd b/sources/menus/settings/sound_settings_button.gd index bb1fdd9e..dec9df3a 100644 --- a/sources/menus/settings/sound_settings_button.gd +++ b/sources/menus/settings/sound_settings_button.gd @@ -7,6 +7,7 @@ extends TextureButton @onready var voice_volume_slider: HSlider = %VoiceVolumeSlider @onready var effects_volume_slider: HSlider = %EffectsVolumeSlider + func _ready() -> void: set_master_volume_slider(UserDataManager.get_master_volume()) set_music_volume_slider(UserDataManager.get_music_volume()) diff --git a/sources/menus/settings/student_panel.gd b/sources/menus/settings/student_panel.gd index 60d8d4f4..1d89be29 100644 --- a/sources/menus/settings/student_panel.gd +++ b/sources/menus/settings/student_panel.gd @@ -1,13 +1,14 @@ -extends Control class_name StudentPanel +extends Control -signal pressed +signal pressed() + +@export var student_count: int +@export var student_data: StudentData @onready var name_label: Label = %NameLabel @onready var password_visualizer: PasswordVisualizer = %PasswordVisualizer -@export var student_count: int -@export var student_data: StudentData func _ready() -> void: if not student_data: diff --git a/sources/menus/settings/teacher_settings.gd b/sources/menus/settings/teacher_settings.gd index 3672a2ca..86122fae 100644 --- a/sources/menus/settings/teacher_settings.gd +++ b/sources/menus/settings/teacher_settings.gd @@ -1,31 +1,26 @@ -extends Control class_name SettingsTeacherSettings +extends Control const MAIN_MENU_PATH: String = "res://sources/menus/main/main_menu.tscn" const LOGIN_MENU_PATH: String = "res://sources/menus/login/login.tscn" const DEVICE_SELECTION_SCENE_PATH: String = "res://sources/menus/device_selection/device_selection.tscn" - const DEVICE_TAB_SCENE: PackedScene = preload("res://sources/menus/settings/device_tab.tscn") +var last_device_id: int = -1 + @onready var devices_tab_container: TabContainer = %DevicesTabContainer @onready var lesson_unlocks: LessonUnlocks = $LessonUnlocks @onready var delete_popup: ConfirmPopup = %DeletePopup @onready var loading_popup: LoadingPopup = %LoadingPopup - - @onready var account_type_option_button: OptionButton = %AccountTypeOptionButton @onready var education_method_option_button: OptionButton = %EducationMethodOptionButton - @onready var add_device_button: Button = %AddDeviceButton @onready var add_student_button: Button = %AddStudentButton @onready var label_internet_mandatory: Label = %LabelInternetMandatory - @onready var add_device_popup: CanvasLayer = %AddDevicePopup @onready var add_student_popup: CanvasLayer = %AddStudentPopup @onready var delete_student_popup: CanvasLayer = %DeleteStudentPopup -var last_device_id: int = -1 - func _ready() -> void: refresh_devices_tabs() diff --git a/sources/minigames/ants/ant.gd b/sources/minigames/ants/ant.gd index 97d1acec..c9a85372 100644 --- a/sources/minigames/ants/ant.gd +++ b/sources/minigames/ants/ant.gd @@ -1,5 +1,5 @@ -extends Area2D class_name Ant +extends Area2D @onready var animation_player: AnimationPlayer = $AnimationPlayer @onready var anchor: Node2D = $Anchor diff --git a/sources/minigames/ants/ants_minigame.gd b/sources/minigames/ants/ants_minigame.gd index f67c664d..28657479 100644 --- a/sources/minigames/ants/ants_minigame.gd +++ b/sources/minigames/ants/ants_minigame.gd @@ -4,9 +4,12 @@ extends Minigame const BLANK_SCENE: PackedScene = preload("res://sources/minigames/ants/blank.tscn") const ANT_SCENE: PackedScene = preload("res://sources/minigames/ants/ant.tscn") const WORD_SCENE: PackedScene = preload("res://sources/minigames/ants/word.tscn") - const LABEL_SETTINGS: LabelSettings = preload("res://resources/themes/minigames_label_settings.tres") +var current_sentence: Dictionary = {} +var answer_input_done: Array[bool] = [] +var answers: Dictionary[String, String] # Expected, current + @onready var sentence_container: HFlowContainer = %Sentence @onready var ants_spawn: Node2D = %AntsSpawn @onready var ants_start: Node2D = %AntsStart @@ -15,10 +18,6 @@ const LABEL_SETTINGS: LabelSettings = preload("res://resources/themes/minigames_ @onready var ants: Node2D = %Ants @onready var words: Node2D = %Words -var current_sentence: Dictionary = {} -var answer_input_done: Array[bool] = [] -var answers: Dictionary[String, String] # Expected, current - func _find_stimuli_and_distractions() -> void: var sentences_list: Array = Database.get_sentences_for_lesson(lesson_nb, difficulty + 2, 50) diff --git a/sources/minigames/ants/blank.gd b/sources/minigames/ants/blank.gd index 7c201c11..75ce6d10 100644 --- a/sources/minigames/ants/blank.gd +++ b/sources/minigames/ants/blank.gd @@ -1,6 +1,5 @@ -extends TextureRect - class_name Blank +extends TextureRect const IMAGES: Array[String] = [ "res://assets/minigames/ants/graphics/hole_02.png", diff --git a/sources/minigames/ants/word.gd b/sources/minigames/ants/word.gd index 3b31af9e..704d8403 100644 --- a/sources/minigames/ants/word.gd +++ b/sources/minigames/ants/word.gd @@ -1,20 +1,19 @@ -extends TextureButton - class_name Word +extends TextureButton signal answer(stimulus: String, expected_stimulus: String) signal no_answer() -@onready var area: Area2D = $Area2D -@onready var label: Label = %Label -@onready var right_fx: RightFX = $RightFX -@onready var wrong_fx: WrongFX = $WrongFX - var stimulus: String: set = _set_stimulus var follow_mouse: bool = false var current_anchor: CanvasItem +@onready var area: Area2D = $Area2D +@onready var label: Label = %Label +@onready var right_fx: RightFX = $RightFX +@onready var wrong_fx: WrongFX = $WrongFX + func right() -> void: right_fx.play() diff --git a/sources/minigames/base/base_minigame.gd b/sources/minigames/base/base_minigame.gd index 40ee7136..e5b29597 100644 --- a/sources/minigames/base/base_minigame.gd +++ b/sources/minigames/base/base_minigame.gd @@ -1,5 +1,5 @@ -extends Control class_name Minigame +extends Control enum Type { jellyfish, @@ -14,63 +14,43 @@ enum Type { fish } +const WIN_SOUND_FX: AudioStreamMP3 = preload("res://assets/sfx/sfx_game_over_win.mp3") +const LOSE_SOUND_FX: AudioStreamMP3 = preload("res://assets/sfx/sfx_game_over_lose.mp3") + +static var transition_data: Dictionary = {} @export var minigame_name: Type - @export var lesson_nb: int = 1 @export_range(0, 4) var difficulty: int = 0 @export_range(0, 1) var current_lesson_stimuli_ratio: float = 0.7 @export var minigame_number: int = 1 - @export_category("Difficulty") @export var max_number_of_lives: int = 0: set(value): max_number_of_lives = value - @export var max_progression: int = 0: set(value): max_progression = value if minigame_ui: minigame_ui.set_max_progression(value) - @export_category("Hints") @export var errors_before_help_speech: int = 2 @export var errors_before_highlight: int = 3 -@onready var minigame_ui: MinigameUI = $MinigameUI -@onready var audio_player: MinigameAudioStreamPlayer = $AudioStreamPlayer -@onready var fireworks: Fireworks = $Fireworks - -# Game root shall contain all the game tree. -# This node is pausable unlike the others, so the pause button can stop the game but not other essential processes. -@onready var game_root: Control = $GameRoot - -# Expected number of stimuli from current lesson -@onready var current_lesson_stimuli_number: int = floori(max_progression * current_lesson_stimuli_ratio) - -# Sounds -const WIN_SOUND_FX: AudioStreamMP3 = preload("res://assets/sfx/sfx_game_over_win.mp3") -const LOSE_SOUND_FX: AudioStreamMP3 = preload("res://assets/sfx/sfx_game_over_lose.mp3") - # Lesson var minigame_difficulty: int var lesson_difficulty: int - # Logs var logs: Dictionary = {} - # Scores for the remediation engine var remediation_gp_scores: Dictionary = {} var remediation_syllables_scores: Dictionary = {} var remediation_words_scores: Dictionary = {} - # Scores for the confusion matrix engine var confusion_matrix_gp_scores: Dictionary[int, PackedInt32Array] = {} - # Stimuli var stimuli: Array = [] var distractions: Array = [] - # Lives var current_lives: int = 0: set(value): @@ -84,7 +64,6 @@ var current_lives: int = 0: _play_kalulu_help_speech() elif consecutive_errors == errors_before_highlight: is_highlighting = true - # Progression var current_progression: int = 0: set = set_current_progression var current_number_of_hints: int = 0 @@ -96,16 +75,22 @@ var is_highlighting: bool = false: _highlight() else: _stop_highlight() - # Speeches var intro_kalulu_speech: AudioStreamMP3 var help_kalulu_speech: AudioStreamMP3 var win_kalulu_speech: AudioStreamMP3 var lose_kalulu_speech: AudioStreamMP3 - # data to go back to the right place in gardens var gardens_data: Dictionary = {} -static var transition_data: Dictionary = {} + +@onready var minigame_ui: MinigameUI = $MinigameUI +@onready var audio_player: MinigameAudioStreamPlayer = $AudioStreamPlayer +@onready var fireworks: Fireworks = $Fireworks +# Game root shall contain all the game tree. +# This node is pausable unlike the others, so the pause button can stop the game but not other essential processes. +@onready var game_root: Control = $GameRoot +# Expected number of stimuli from current lesson +@onready var current_lesson_stimuli_number: int = floori(max_progression * current_lesson_stimuli_ratio) #region Initialisation @@ -277,6 +262,7 @@ func _lose() -> void: _reset() + func _submit_student_level_time() -> void: var elapsed_time: int = int(Time.get_ticks_msec() / 1000.0 - _start_time - _elapsed_paused) ServerManager.submit_student_level_time(lesson_nb, elapsed_time) @@ -339,6 +325,7 @@ func _update_remediation_gp_score(id: int, score: int) -> void: new_remediation_gp_score += score remediation_gp_scores[id] = new_remediation_gp_score + # Updates the remediation score of a syllable defined by his ID func _update_remediation_syllable_score(id: int, score: int) -> void: var new_remediation_syllable_score: int = 0 @@ -347,6 +334,7 @@ func _update_remediation_syllable_score(id: int, score: int) -> void: new_remediation_syllable_score += score remediation_syllables_scores[id] = new_remediation_syllable_score + # Updates the remediation score of a word defined by his ID func _update_remediation_word_score(id: int, score: int) -> void: var new_remediation_word_score: int = 0 diff --git a/sources/minigames/base/hear_and_find/syllables_minigame.gd b/sources/minigames/base/hear_and_find/syllables_minigame.gd index 782a6343..b57af5cc 100644 --- a/sources/minigames/base/hear_and_find/syllables_minigame.gd +++ b/sources/minigames/base/hear_and_find/syllables_minigame.gd @@ -1,6 +1,6 @@ @tool -extends Minigame class_name SyllablesMinigame +extends Minigame signal stimulus_heard(is_heard: bool) signal stimulus_found() @@ -10,14 +10,14 @@ signal stimulus_found() # Time before the current stimulus is repeated @export var stimulus_repeat_time: float = 15 -@onready var stimulus_timer: Timer = $StimulusTimer - # Define if the current stimulus have been heard by the player. The stimuli can't be pressed if this is false var is_stimulus_heard: bool = false: set(value): is_stimulus_heard = value stimulus_heard.emit(value) +@onready var stimulus_timer: Timer = $StimulusTimer + func _start() -> void: super() @@ -178,7 +178,6 @@ func _await_for_future_or_stimulus_found(future: Signal) -> bool: # ------------ Connections ------------ - func _on_stimulus_pressed(stimulus: Dictionary, _node: Node) -> bool: if not is_stimulus_heard: return false @@ -222,7 +221,6 @@ func _on_stimulus_timer_timeout() -> void: func _on_stimulus_found() -> void: pass - #region UI Callbacks func _on_current_progression_changed() -> void: diff --git a/sources/minigames/base/kalulu.gd b/sources/minigames/base/kalulu.gd index 8c3ec38a..6d95f9f9 100644 --- a/sources/minigames/base/kalulu.gd +++ b/sources/minigames/base/kalulu.gd @@ -1,6 +1,6 @@ extends Control -signal speech_ended +signal speech_ended() const SHOW_SOUND: AudioStreamMP3 = preload("res://assets/kalulu/audio/ui_button_on.mp3") const HIDE_SOUND: AudioStreamMP3 = preload("res://assets/kalulu/audio/ui_button_off.mp3") @@ -46,6 +46,7 @@ func play_kalulu_speech(speech: AudioStream, show_animation: bool = true, hide_a AudioServer.set_bus_volume_db(ind, music_volume) speech_ended.emit() + func _on_pass_button_pressed() -> void: if audio_player.playing: audio_player.stop() diff --git a/sources/minigames/base/minigame_audio_stream_player.gd b/sources/minigames/base/minigame_audio_stream_player.gd index 3fe47a1f..025c17d5 100644 --- a/sources/minigames/base/minigame_audio_stream_player.gd +++ b/sources/minigames/base/minigame_audio_stream_player.gd @@ -1,5 +1,6 @@ -extends AudioStreamPlayer class_name MinigameAudioStreamPlayer +extends AudioStreamPlayer + func play_gp(gp: Dictionary) -> void: Logger.trace("Minigame Audio Stream Player: Playing GP " + str(gp)) @@ -13,6 +14,7 @@ func play_gp(gp: Dictionary) -> void: await play_audio_stream(phoneme_audiostream) + func play_syllable(syllable: Dictionary) -> void: Logger.trace("Minigame Audio Stream Player: Playing Syllable " + str(syllable)) if not syllable or syllable.is_empty(): @@ -37,6 +39,7 @@ func play_word(word: String) -> void: await play_audio_stream(word_audiostream) + func play_audio_stream(audio: AudioStreamMP3) -> void: stream = audio play() diff --git a/sources/minigames/base/minigame_ui.gd b/sources/minigames/base/minigame_ui.gd index 9516cdba..8a9ce9b5 100644 --- a/sources/minigames/base/minigame_ui.gd +++ b/sources/minigames/base/minigame_ui.gd @@ -1,16 +1,13 @@ @tool -extends CanvasLayer class_name MinigameUI +extends CanvasLayer -signal garden_button_pressed -signal stimulus_button_pressed - -signal restart_button_pressed - -signal kalulu_button_pressed -signal kalulu_speech_ended - -signal pause_ended +signal garden_button_pressed() +signal stimulus_button_pressed() +signal restart_button_pressed() +signal kalulu_button_pressed() +signal kalulu_speech_ended() +signal pause_ended() const KALULU := preload("res://sources/minigames/base/kalulu.gd") @@ -22,33 +19,22 @@ const KALULU := preload("res://sources/minigames/base/kalulu.gd") if stimulus_button: _handle_stimulus_button() -# Using unique names to avoid changing the path if the interface architecture changes -# Left panel -@onready var garden_button: TextureButton = %GardenButton +var is_paused: bool = false +@onready var garden_button: TextureButton = %GardenButton @onready var stimulus_margin: MarginContainer = %StimulusMargin @onready var stimulus_button: TextureButton = %StimulusButton - @onready var stimulus_texture: TextureRect = %StimulusTexture - @onready var pause_margin: MarginContainer = %PauseMargin @onready var pause_button: TextureButton = %PauseButton - @onready var kalulu_button: TextureButton = %KaluluButton - -# Center menu @onready var center_menu: MarginContainer = %CenterMenu - -# Kalulu @onready var kalulu: KALULU = %Kalulu - @onready var progression_container: VBoxContainer = %ProgressionContainer @onready var progression_gauge: NinePatchRect = %ProgressionGauge @onready var model_progression_rect: TextureRect = %ProgressionIconsRect - @onready var animation_player: AnimationPlayer = $AnimationPlayer -var is_paused: bool = false func _ready() -> void: model_progression_rect.texture = empty_progression_icon @@ -127,8 +113,6 @@ func _on_pause_button_pressed() -> void: is_paused = true show_center_menu(true) get_tree().paused = true - - #pause_button_pressed.emit() func _on_kalulu_button_pressed() -> void: diff --git a/sources/minigames/base/words/words_minigame.gd b/sources/minigames/base/words/words_minigame.gd index a6aefc98..57d47904 100644 --- a/sources/minigames/base/words/words_minigame.gd +++ b/sources/minigames/base/words/words_minigame.gd @@ -1,5 +1,5 @@ -extends Minigame class_name WordsMinigame +extends Minigame # Define the maximum number of GP inside each word @export var max_number_of_gps: int = 6 @@ -10,11 +10,10 @@ class_name WordsMinigame var current_word_progression: int = 0: set = _set_current_word_progression var max_word_progression: int = 0 - var current_gp_distractors_queue: Array[Dictionary] = [] - var current_word_has_errors: bool = false + # Find the stimuli and distractions of the minigame. func _find_stimuli_and_distractions() -> void: # Get the currently known words list @@ -199,17 +198,13 @@ func _log_new_response_and_score(gp: Dictionary) -> void: current_word_has_errors = true _update_remediation_gp_score(self._get_gp().ID as int, -1) - # ------------- UI Callbacks ------------- # - func _play_stimulus() -> void: await audio_player.play_word(_get_current_stimulus().Word as String) - # -------------- CONNECTIONS -------------- # - func _on_current_word_progression_changed() -> void: _reset_distractors_queue() diff --git a/sources/minigames/caterpillar/berry.gd b/sources/minigames/caterpillar/berry.gd index 573ef7fd..ed1307f9 100644 --- a/sources/minigames/caterpillar/berry.gd +++ b/sources/minigames/caterpillar/berry.gd @@ -1,14 +1,8 @@ -extends Area2D class_name Berry +extends Area2D signal pressed(gp: Dictionary) -@onready var collision_shape: CollisionShape2D = $CollisionShape2D -@onready var label: Label = %Label -@onready var path_follow: PathFollow2D = $Path2D/PathFollow2D -@onready var highlight_fx: HighlightFX = $HighlightFX -@onready var wrong_fx: WrongFX = $WrongFX - var gp: Dictionary = {}: set(value): gp = value @@ -16,14 +10,18 @@ var gp: Dictionary = {}: label.text = gp.Grapheme else: label.text = "" - -var is_distractor: bool = false - var is_eaten: bool = false: set(value): is_eaten = value if is_eaten: collision_shape.set_deferred("disabled", true) +var is_distractor: bool = false + +@onready var collision_shape: CollisionShape2D = $CollisionShape2D +@onready var label: Label = %Label +@onready var path_follow: PathFollow2D = $Path2D/PathFollow2D +@onready var highlight_fx: HighlightFX = $HighlightFX +@onready var wrong_fx: WrongFX = $WrongFX func highlight() -> void: diff --git a/sources/minigames/caterpillar/branch.gd b/sources/minigames/caterpillar/branch.gd index 159da5c9..7c6d1187 100644 --- a/sources/minigames/caterpillar/branch.gd +++ b/sources/minigames/caterpillar/branch.gd @@ -1,6 +1,6 @@ @tool -extends Node2D class_name Branch +extends Node2D signal branch_pressed() signal berry_pressed(gp: Dictionary) @@ -8,15 +8,15 @@ signal berry_pressed(gp: Dictionary) const LEAF_SCENE: PackedScene = preload("res://sources/minigames/caterpillar/leaf.tscn") const BERRY_SCENE: PackedScene = preload("res://sources/minigames/caterpillar/berry.tscn") +var velocity: float = 0.0 +var is_highlighting: bool = false: + set = _set_highlighting +var is_running: bool = true + @onready var leaves: Node2D = $Leaves @onready var berries: Node2D = $Berries @onready var leaf_timer: Timer = $LeafTimer -var velocity: float = 0.0 -var is_highlighting: bool = false: - set = _set_highlighting - -var is_running: bool = true func _set_highlighting(value: bool) -> void: is_highlighting = value @@ -65,7 +65,6 @@ func clear_berries() -> void: for berry: Berry in berries.get_children(): berry.fall() - # ---------- CONNECTIONS ---------- # func _on_button_pressed() -> void: diff --git a/sources/minigames/caterpillar/caterpillar.gd b/sources/minigames/caterpillar/caterpillar.gd index 11ee14a4..a77ca5c2 100644 --- a/sources/minigames/caterpillar/caterpillar.gd +++ b/sources/minigames/caterpillar/caterpillar.gd @@ -1,21 +1,21 @@ @tool -extends Node2D class_name Caterpillar +extends Node2D signal berry_eaten(berry: Berry) const BODY_PART_SCENE: PackedScene = preload("res://sources/minigames/caterpillar/caterpillar_body.tscn") - const BODY_PART_WIDTH: int = 128 const BODY_PART_MOVE_TIME: float = 0.25 const BODY_PART_WAIT_TIME: float = 0.04 +var is_moving: bool = false +var is_eating: bool = false + @onready var head: CaterpillarHead = $Head @onready var body_parts: Node2D = $BodyParts @onready var tail: Node2D = $Tail -var is_moving: bool = false -var is_eating: bool = false func idle() -> void: for body_part: CaterpillarBody in body_parts.get_children(): diff --git a/sources/minigames/caterpillar/caterpillar_audio_stream_player.gd b/sources/minigames/caterpillar/caterpillar_audio_stream_player.gd index feb7034f..84cf183a 100644 --- a/sources/minigames/caterpillar/caterpillar_audio_stream_player.gd +++ b/sources/minigames/caterpillar/caterpillar_audio_stream_player.gd @@ -1,5 +1,5 @@ -extends AudioStreamPlayer class_name CaterpillarAudioStreamPlayer +extends AudioStreamPlayer const EAT_SFX: Array[AudioStream] = [ preload("res://assets/minigames/caterpillar/audios/caterpillar_eat_random_01.mp3"), @@ -8,6 +8,7 @@ const EAT_SFX: Array[AudioStream] = [ preload("res://assets/minigames/caterpillar/audios/caterpillar_eat_random_04.mp3"), ] + func eat() -> void: stream = EAT_SFX.pick_random() play() diff --git a/sources/minigames/caterpillar/caterpillar_body.gd b/sources/minigames/caterpillar/caterpillar_body.gd index 5743aa20..e077853d 100644 --- a/sources/minigames/caterpillar/caterpillar_body.gd +++ b/sources/minigames/caterpillar/caterpillar_body.gd @@ -1,10 +1,6 @@ @tool -extends Node2D class_name CaterpillarBody - -@onready var animated_sprite: AnimatedSprite2D = $AnimatedSprite2D -@onready var label: Label = $Label -@onready var right_FX: RightFX = $RightFX +extends Node2D var gp: Dictionary = {}: set(value): @@ -14,6 +10,10 @@ var gp: Dictionary = {}: else: label.text = "" +@onready var animated_sprite: AnimatedSprite2D = $AnimatedSprite2D +@onready var label: Label = $Label +@onready var right_FX: RightFX = $RightFX + func _ready() -> void: walk() diff --git a/sources/minigames/caterpillar/caterpillar_head.gd b/sources/minigames/caterpillar/caterpillar_head.gd index b76f2da2..bcaebeca 100644 --- a/sources/minigames/caterpillar/caterpillar_head.gd +++ b/sources/minigames/caterpillar/caterpillar_head.gd @@ -1,11 +1,12 @@ @tool -extends Node2D class_name CaterpillarHead +extends Node2D @onready var animated_sprite: AnimatedSprite2D = $AnimatedSprite2D @onready var audio_stream_player: CaterpillarAudioStreamPlayer = $CaterpillarAudioStreamPlayer @onready var spit_vfx: SpitVFX = $SpitFX + func _ready() -> void: idle() diff --git a/sources/minigames/caterpillar/caterpillar_minigame.gd b/sources/minigames/caterpillar/caterpillar_minigame.gd index e14c3ee0..283ed2a1 100644 --- a/sources/minigames/caterpillar/caterpillar_minigame.gd +++ b/sources/minigames/caterpillar/caterpillar_minigame.gd @@ -3,20 +3,6 @@ extends WordsMinigame const BRANCH_SCENE: PackedScene = preload("res://sources/minigames/caterpillar/branch.tscn") - -class DifficultySettings: - var branches: int = 2 - var stimuli_ratio: float = 0.75 - var velocity: float = 400. - var spawn_rate: float = 3. - - func _init(p_branches: int, p_stimuli_ratio: float, p_velocity: float, p_spawn_rate: float) -> void: - branches = p_branches - stimuli_ratio = p_stimuli_ratio - velocity = p_velocity - spawn_rate = p_spawn_rate - - var difficulty_settings: Array[DifficultySettings] = [ DifficultySettings.new(2, 0.75, 400., 3.), DifficultySettings.new(2, 0.66, 450., 2.5), @@ -24,16 +10,14 @@ var difficulty_settings: Array[DifficultySettings] = [ DifficultySettings.new(3, 0.25, 550., 1.), DifficultySettings.new(4, 0.25, 600., 1.) ] - +var branches: Array[Branch] = [] +var branches_spawn_indexes: Array[int] = [] @onready var branches_zone: Control = $GameRoot/BranchesZone @onready var caterpillar: Caterpillar = $GameRoot/Caterpillar @onready var berry_timer: Timer = $GameRoot/BerryTimer -var branches: Array[Branch] = [] -var branches_spawn_indexes: Array[int] = [] - func _setup_minigame() -> void: super._setup_minigame() @@ -82,16 +66,19 @@ func _stop_highlight() -> void: for branch: Branch in branches: branch.is_highlighting = false + func _run() -> void: caterpillar.walk() for branch: Branch in branches: branch.is_running = true + func _stop() -> void: caterpillar.idle() for branch: Branch in branches: branch.is_running = false + func _get_difficulty_settings() -> DifficultySettings: return difficulty_settings[difficulty] @@ -176,3 +163,16 @@ func _on_current_progression_changed() -> void: berry_timer.start() #endregion + +class DifficultySettings: + var branches: int = 2 + var stimuli_ratio: float = 0.75 + var velocity: float = 400. + var spawn_rate: float = 3. + + + func _init(p_branches: int, p_stimuli_ratio: float, p_velocity: float, p_spawn_rate: float) -> void: + branches = p_branches + stimuli_ratio = p_stimuli_ratio + velocity = p_velocity + spawn_rate = p_spawn_rate diff --git a/sources/minigames/caterpillar/leaf.gd b/sources/minigames/caterpillar/leaf.gd index f9eee100..cb8f522a 100644 --- a/sources/minigames/caterpillar/leaf.gd +++ b/sources/minigames/caterpillar/leaf.gd @@ -1,5 +1,6 @@ -extends Node2D class_name Leaf +extends Node2D + func _on_visible_on_screen_notifier_2d_screen_exited() -> void: queue_free() diff --git a/sources/minigames/caterpillar/spit_fx.gd b/sources/minigames/caterpillar/spit_fx.gd index 7cec093a..b7e8b5cc 100644 --- a/sources/minigames/caterpillar/spit_fx.gd +++ b/sources/minigames/caterpillar/spit_fx.gd @@ -1,8 +1,9 @@ -extends Control class_name SpitVFX +extends Control @onready var particles: GPUParticles2D = $Particles + func play() -> void: particles.amount = randi_range(5, 8) particles.restart() diff --git a/sources/minigames/crabs/crab/crab.gd b/sources/minigames/crabs/crab/crab.gd index 8e9403de..fb5acd38 100644 --- a/sources/minigames/crabs/crab/crab.gd +++ b/sources/minigames/crabs/crab/crab.gd @@ -1,18 +1,9 @@ @tool -extends Control class_name Crab +extends Control signal crab_hit(stimulus: Dictionary) -@onready var body: Control = $Body -@onready var animated_sprite: AnimatedSprite2D = %AnimatedSprite2D -@onready var label: Label = $Body/Label -@onready var button: Button = $Button -@onready var highlight_fx: HighlightFX = %HighlightFX -@onready var right_fx: RightFX = %RightFX -@onready var wrong_fx: WrongFX = %WrongFX -@onready var audio_stream_player: AudioStreamPlayer = $AudioStreamPlayer - var sounds: Array[AudioStreamMP3] = [ preload("res://assets/minigames/crabs/audio/sfx/crab_random_1.mp3"), preload("res://assets/minigames/crabs/audio/sfx/crab_random_2.mp3"), @@ -28,10 +19,18 @@ var sounds: Array[AudioStreamMP3] = [ preload("res://assets/minigames/crabs/audio/sfx/crab_random_12.mp3"), preload("res://assets/minigames/crabs/audio/sfx/crab_random_13.mp3"), ] - var stimulus: Dictionary: set = _set_stimulus +@onready var body: Control = $Body +@onready var animated_sprite: AnimatedSprite2D = %AnimatedSprite2D +@onready var label: Label = $Body/Label +@onready var button: Button = $Button +@onready var highlight_fx: HighlightFX = %HighlightFX +@onready var right_fx: RightFX = %RightFX +@onready var wrong_fx: WrongFX = %WrongFX +@onready var audio_stream_player: AudioStreamPlayer = $AudioStreamPlayer + func _ready() -> void: set_button_active(false) diff --git a/sources/minigames/crabs/crabs_minigame.gd b/sources/minigames/crabs/crabs_minigame.gd index 3303e30d..7656e49b 100644 --- a/sources/minigames/crabs/crabs_minigame.gd +++ b/sources/minigames/crabs/crabs_minigame.gd @@ -3,14 +3,6 @@ extends SyllablesMinigame const HOLE_SCENE: PackedScene = preload("res://sources/minigames/crabs/hole/hole.tscn") -class DifficultySettings: - var stimuli_ratio: float = 0.75 - var rows: Array[int] = [2, 1] - - func _init(p_stimuli_ratio: float, p_rows: Array[int]) -> void: - stimuli_ratio = p_stimuli_ratio - rows = p_rows - var difficulty_settings: Array[DifficultySettings] = [ DifficultySettings.new(0.75, [2, 1]), DifficultySettings.new(0.66, [3, 2]), @@ -18,16 +10,13 @@ var difficulty_settings: Array[DifficultySettings] = [ DifficultySettings.new(0.25, [4, 3, 2]), DifficultySettings.new(0.25, [4, 3, 4]) ] - -@onready var crab_zone: Control = $GameRoot/CrabZone - var holes: Array[Hole] = [] var stimulus_spawned: bool = false +@onready var crab_zone: Control = $GameRoot/CrabZone # ------------ Initialisation ------------ - # Find and set the parameters of the minigame, like the number of lives or the victory conditions. func _setup_minigame() -> void: super._setup_minigame() @@ -119,7 +108,6 @@ func _on_current_progression_changed() -> void: # Restarts the spawning of crabs _spawn_crabs() - # ------------ Crabs ------------ # Spawn a set amount of crabs in random holes @@ -172,3 +160,13 @@ func _on_stimulus_found() -> void: # Despawn all the crabs for hole: Hole in holes: hole.stop.emit() + + +class DifficultySettings: + var stimuli_ratio: float = 0.75 + var rows: Array[int] = [2, 1] + + + func _init(p_stimuli_ratio: float, p_rows: Array[int]) -> void: + stimuli_ratio = p_stimuli_ratio + rows = p_rows diff --git a/sources/minigames/crabs/hole/hole.gd b/sources/minigames/crabs/hole/hole.gd index 7b63e091..4f1ab3c2 100644 --- a/sources/minigames/crabs/hole/hole.gd +++ b/sources/minigames/crabs/hole/hole.gd @@ -1,5 +1,5 @@ -extends Node2D class_name Hole +extends Node2D signal stimulus_hit(stimulus: Dictionary) signal crab_despawned(is_stimulus: bool) @@ -8,13 +8,6 @@ signal crab_out(hole: Hole) const CRAB_SCENE: PackedScene = preload("res://sources/minigames/crabs/crab/crab.tscn") -@onready var hole_back: Sprite2D = $HoleBack -@onready var hole_front: Sprite2D = $HoleFront -@onready var mask: Sprite2D = %Mask -@onready var sand_vfx: SandVFX = $SandVFX -@onready var timer: Timer = $Timer -@onready var crab_audio_stream_player: HoleAudioStreamPlayer = $CrabAudioStreamPlayer2D - var crab: Crab var crab_x: float var stimulus_heard: bool = false: @@ -27,6 +20,13 @@ var crab_visible: bool = false: _set_crab_button_active(stimulus_heard and crab_visible) var is_stimulus: bool = false +@onready var hole_back: Sprite2D = $HoleBack +@onready var hole_front: Sprite2D = $HoleFront +@onready var mask: Sprite2D = %Mask +@onready var sand_vfx: SandVFX = $SandVFX +@onready var timer: Timer = $Timer +@onready var crab_audio_stream_player: HoleAudioStreamPlayer = $CrabAudioStreamPlayer2D + func _process(_delta: float) -> void: if not crab: @@ -154,10 +154,8 @@ func _set_crab_button_active(is_active: bool) -> void: if crab: crab.set_button_active(is_active) - # ------------ Connections ------------ - func _on_crab_hit(stimulus: Dictionary) -> void: crab.reparent(self) diff --git a/sources/minigames/crabs/hole/hole_audio_stream_player_2d.gd b/sources/minigames/crabs/hole/hole_audio_stream_player_2d.gd index 5acbdf10..f1b083f9 100644 --- a/sources/minigames/crabs/hole/hole_audio_stream_player_2d.gd +++ b/sources/minigames/crabs/hole/hole_audio_stream_player_2d.gd @@ -1,5 +1,5 @@ -extends AudioStreamPlayer2D class_name HoleAudioStreamPlayer +extends AudioStreamPlayer2D const CRAB_SOUND_LIST: Array[AudioStreamMP3] = [ preload("res://assets/minigames/crabs/audio/sfx/crab_random_1.mp3"), diff --git a/sources/minigames/fish/fish_minigame.gd b/sources/minigames/fish/fish_minigame.gd index 6f7d7bdc..8e0275c6 100644 --- a/sources/minigames/fish/fish_minigame.gd +++ b/sources/minigames/fish/fish_minigame.gd @@ -5,6 +5,18 @@ signal beacon_fish_dropped(is_answered_real: bool) const FISH_TEXTURE_RECT_SCENE: PackedScene = preload("res://sources/minigames/fish/fish_texture_rect.tscn") +@export var game_duration: int = 4 * 60 +@export var minimum_correct_ratio: float = 0.8 +@export var winning_color: Color = Color.WHITE +@export var max_words_count: int = 15 + +var tween: Tween +var words_to_present: Array[String] = [] +var words_to_present_next: Array[String] = [] +var progress_gauge_max_margin: float = 0.95 +var total_number_of_words: int = 30 +var tutorial_count: int = 0 + @onready var fish_start_zone: Control = %FishStartZone @onready var beacon1: SpriteControl = %Beacon1 @onready var beacon2: SpriteControl = %Beacon2 @@ -20,19 +32,6 @@ const FISH_TEXTURE_RECT_SCENE: PackedScene = preload("res://sources/minigames/fi @onready var progress_gauge_internal: NinePatchRect = %ProgressionGaugeInternal -@export var game_duration: int = 4 * 60 -@export var minimum_correct_ratio: float = 0.8 -@export var winning_color: Color = Color.WHITE -@export var max_words_count: int = 15 - -var tween: Tween -var words_to_present: Array[String] = [] -var words_to_present_next: Array[String] = [] -var progress_gauge_max_margin: float = 0.95 -var total_number_of_words: int = 30 -var tutorial_count: int = 0 - - func _fish_get_drag_data(_at_position: Vector2) -> Variant: var fish_texture_rect: Control = FISH_TEXTURE_RECT_SCENE.instantiate() fish_texture_rect.size = Vector2(200, 200) diff --git a/sources/minigames/frog/frog.gd b/sources/minigames/frog/frog.gd index 8a9162d7..568c3a54 100644 --- a/sources/minigames/frog/frog.gd +++ b/sources/minigames/frog/frog.gd @@ -1,14 +1,9 @@ -extends Control - class_name Frog +extends Control signal drowned() signal jumped() -@onready var animation_player: AnimationPlayer = $AnimationPlayer -@onready var audio_player: AudioStreamPlayer2D = $AudioStreamPlayer2D -@onready var sprite: Sprite2D = $Sprite - const JUMP_SOUNDS: Array[AudioStreamMP3] = [ preload("res://assets/minigames/frog/audio/frog_jump_random_01.mp3"), preload("res://assets/minigames/frog/audio/frog_jump_random_02.mp3"), @@ -16,7 +11,6 @@ const JUMP_SOUNDS: Array[AudioStreamMP3] = [ preload("res://assets/minigames/frog/audio/frog_jump_random_04.mp3"), preload("res://assets/minigames/frog/audio/frog_jump_random_05.mp3"), ] - const FROG_SOUNDS: Array[AudioStreamMP3] = [ preload("res://assets/minigames/frog/audio/frog_random_01.mp3"), preload("res://assets/minigames/frog/audio/frog_random_02.mp3"), @@ -25,6 +19,10 @@ const FROG_SOUNDS: Array[AudioStreamMP3] = [ preload("res://assets/minigames/frog/audio/frog_random_05.mp3"), ] +@onready var animation_player: AnimationPlayer = $AnimationPlayer +@onready var audio_player: AudioStreamPlayer2D = $AudioStreamPlayer2D +@onready var sprite: Sprite2D = $Sprite + func jump_to(destination: Vector2) -> void: animation_player.play("jump") diff --git a/sources/minigames/frog/frog_minigame.gd b/sources/minigames/frog/frog_minigame.gd index dc9aa78a..5f55a064 100644 --- a/sources/minigames/frog/frog_minigame.gd +++ b/sources/minigames/frog/frog_minigame.gd @@ -1,20 +1,9 @@ @tool -extends WordsMinigame class_name FrogMinigame +extends WordsMinigame const LILYPAD_TRACK_SCENE: PackedScene = preload("res://sources/minigames/frog/lilypad_track.tscn") -class DifficultySettings: - var stimuli_ratio: float = 0.75 - var pads_speed_disabled: float = 100.0 - var pads_speed: float = 200.0 - - func _init(p_stimuli_ratio: float, p_pads_speed_disabled: float, p_pads_speed: float) -> void: - stimuli_ratio = p_stimuli_ratio - pads_speed_disabled = p_pads_speed_disabled - pads_speed = p_pads_speed - - var difficulty_settings: Array[DifficultySettings] = [ DifficultySettings.new(0.75, 100., 200.), DifficultySettings.new(0.66, 150., 250.), @@ -23,13 +12,10 @@ var difficulty_settings: Array[DifficultySettings] = [ DifficultySettings.new(0.25, 300., 400.) ] - @onready var start: Control = %Start @onready var end: Control = %End - @onready var frog_spawn_point: Control = %FrogSpawnPoint @onready var frog_despawn_point: Control = %FrogDespawnPoint - @onready var river: River = $GameRoot/Background/River @onready var lilypad_tracks_container: HBoxContainer = %LilypadTracksContainer @onready var frog: Frog = %Frog @@ -174,3 +160,14 @@ func _on_current_progression_changed() -> void: super() #endregion + +class DifficultySettings: + var stimuli_ratio: float = 0.75 + var pads_speed_disabled: float = 100.0 + var pads_speed: float = 200.0 + + + func _init(p_stimuli_ratio: float, p_pads_speed_disabled: float, p_pads_speed: float) -> void: + stimuli_ratio = p_stimuli_ratio + pads_speed_disabled = p_pads_speed_disabled + pads_speed = p_pads_speed diff --git a/sources/minigames/frog/lilypad.gd b/sources/minigames/frog/lilypad.gd index 5da5d0e3..4624391d 100644 --- a/sources/minigames/frog/lilypad.gd +++ b/sources/minigames/frog/lilypad.gd @@ -1,16 +1,9 @@ -extends Control class_name Lilypad +extends Control signal pressed() signal disappeared() -@onready var animation_player: AnimationPlayer = $AnimationPlayer -@onready var button: TextureButton = $TextureButton -@onready var label: Label = %Label -@onready var highlight_fx: HighlightFX = %HighlightFX -@onready var right_fx: RightFX = %RightFX -@onready var wrong_fx: WrongFX = %WrongFX - var stimulus: Dictionary = {}: set = _set_stimulus var disabled: bool = false: @@ -18,6 +11,13 @@ var disabled: bool = false: var is_distractor: bool = true var top_to_bottom: bool = false +@onready var animation_player: AnimationPlayer = $AnimationPlayer +@onready var button: TextureButton = $TextureButton +@onready var label: Label = %Label +@onready var highlight_fx: HighlightFX = %HighlightFX +@onready var right_fx: RightFX = %RightFX +@onready var wrong_fx: WrongFX = %WrongFX + func disappear() -> void: button.disabled = true diff --git a/sources/minigames/frog/lilypad_track.gd b/sources/minigames/frog/lilypad_track.gd index 3b596a7f..ff3e2bd7 100644 --- a/sources/minigames/frog/lilypad_track.gd +++ b/sources/minigames/frog/lilypad_track.gd @@ -1,13 +1,10 @@ -extends Control class_name LilypadTrack +extends Control signal lilypad_in_center(lilypad: Lilypad) const LILYPAD_SCENE: PackedScene = preload("res://sources/minigames/frog/lilypad.tscn") -@onready var audio_player: AudioStreamPlayer2D = $AudioStreamPlayer2D -@onready var spawn_timer: Timer = $SpawnTimer - var top_to_bottom: bool = false var is_stopped: bool = false var is_cleared: bool = false @@ -15,8 +12,6 @@ var is_enabled: bool = false: set = _set_enabled var is_highlighting: bool = false: set = _set_highlighting - - var difficulty_settings: FrogMinigame.DifficultySettings var gp: Dictionary = {}: set(value): @@ -26,10 +21,12 @@ var gp: Dictionary = {}: var distractors: Array[Dictionary] = [] var distractors_queue: Array[Dictionary] = [] var distractors_queue_size: int = 5 - var lilypads: Array[Lilypad] = [] var lilypad_size: Vector2 +@onready var audio_player: AudioStreamPlayer2D = $AudioStreamPlayer2D +@onready var spawn_timer: Timer = $SpawnTimer + func _process(delta: float) -> void: if is_stopped: diff --git a/sources/minigames/frog/river.gd b/sources/minigames/frog/river.gd index f59fdf9a..8f11f31e 100644 --- a/sources/minigames/frog/river.gd +++ b/sources/minigames/frog/river.gd @@ -1,10 +1,10 @@ @tool +class_name River extends TextureRect -class_name River - const WATER_RING_SCENE: PackedScene = preload("res://sources/utils/fx/water_ring.tscn") + func spawn_water_ring(pos: Vector2) -> void: var fx: WaterRingFX = WATER_RING_SCENE.instantiate() fx.global_position = pos diff --git a/sources/minigames/jellyfish/jellyfish.gd b/sources/minigames/jellyfish/jellyfish.gd index 87c544b0..2058a5a0 100644 --- a/sources/minigames/jellyfish/jellyfish.gd +++ b/sources/minigames/jellyfish/jellyfish.gd @@ -1,6 +1,6 @@ @tool -extends Control class_name Jellyfish +extends Control signal pressed(stimulus: Dictionary) @@ -17,12 +17,10 @@ const ANIMATIONS_ARMS: Array[SpriteFrames] = [ preload("res://sources/minigames/jellyfish/blue_jellyfish_animations_arms.tres"), preload("res://sources/minigames/jellyfish/pink_jellyfish_animations_arms.tres"), ] - const SCALES: Array[Vector2] = [ Vector2(1.,1.), Vector2(1.25, 1.25) ] - const SCALE_FACTOR: float = 0.2 @export var color: int = Colors.Red: @@ -41,6 +39,15 @@ const SCALE_FACTOR: float = 0.2 # Handles sprite size sprite_control.resized.emit() +var stimulus: Dictionary = {}: + set(value): + stimulus = value + if label: + if value.has("Grapheme"): + label.text = value.Grapheme + else: + label.text = "" + @onready var sprite_control: SpriteControl = $SpriteControl @onready var animated_sprite_body: AnimatedSprite2D = %AnimatedSprite2D_Body @onready var animated_sprite_arms: AnimatedSprite2D = %AnimatedSprite2D_Arms @@ -52,16 +59,6 @@ const SCALE_FACTOR: float = 0.2 @onready var text_box_outline_sprite_2d: Sprite2D = %TextBox_Outline_Sprite2D -var stimulus: Dictionary = {}: - set(value): - stimulus = value - if label: - if value.has("Grapheme"): - label.text = value.Grapheme - else: - label.text = "" - - func _ready() -> void: stimulus = stimulus diff --git a/sources/minigames/jellyfish/jellyfish_minigame.gd b/sources/minigames/jellyfish/jellyfish_minigame.gd index 6d544bea..24f0478c 100644 --- a/sources/minigames/jellyfish/jellyfish_minigame.gd +++ b/sources/minigames/jellyfish/jellyfish_minigame.gd @@ -3,16 +3,6 @@ extends SyllablesMinigame const JELLYFISH_SCENE: PackedScene = preload("res://sources/minigames/jellyfish/jellyfish.tscn") -class DifficultySettings: - var spawn_time: float = 4.0 - var stimuli_ratio: float = 0.75 - var velocity: int = 150 - - func _init(p_spawn_time: float, p_stimuli_ratio: float, p_velocity: int) -> void: - spawn_time = p_spawn_time - stimuli_ratio = p_stimuli_ratio - velocity = p_velocity - var difficulty_settings: Array[DifficultySettings] = [ DifficultySettings.new(4, 0.75, 150), DifficultySettings.new(3, 0.66, 175), @@ -20,12 +10,11 @@ var difficulty_settings: Array[DifficultySettings] = [ DifficultySettings.new(1, 0.25, 250), DifficultySettings.new(1, 0.25, 300) ] - +var blocking_jellyfish: Array[Jellyfish] = [] @onready var spawning_space: Control = %SpawningSpace @onready var spawn_timer: Timer = $GameRoot/SpawnTimer -var blocking_jellyfish: Array[Jellyfish] = [] func _start() -> void: super() @@ -127,10 +116,8 @@ func _on_current_progression_changed() -> void: # Restarts the spawning of jellyfishes spawn_timer.start() - # ------------ Connections ------------ - func _on_spawn_timer_timeout() -> void: _spawn() spawn_timer.wait_time = _get_difficulty_settings().spawn_time @@ -184,3 +171,15 @@ func _on_stimulus_found() -> void: jellyfish.delete() blocking_jellyfish.clear() + + +class DifficultySettings: + var spawn_time: float = 4.0 + var stimuli_ratio: float = 0.75 + var velocity: int = 150 + + + func _init(p_spawn_time: float, p_stimuli_ratio: float, p_velocity: int) -> void: + spawn_time = p_spawn_time + stimuli_ratio = p_stimuli_ratio + velocity = p_velocity diff --git a/sources/minigames/monkeys/broken_coconut_fx.gd b/sources/minigames/monkeys/broken_coconut_fx.gd index 6b27d397..cb0ea68b 100644 --- a/sources/minigames/monkeys/broken_coconut_fx.gd +++ b/sources/minigames/monkeys/broken_coconut_fx.gd @@ -1,14 +1,14 @@ -extends Control class_name BrokenCoconutFX +extends Control signal finished() - @onready var top_particles: GPUParticles2D = $TopParticles @onready var shards_particles: GPUParticles2D = $ShardsParticles @onready var bottom_particles: GPUParticles2D = $BottomParticles @onready var lines_particles: GPUParticles2D = $LinesParticles + func play() -> void: shards_particles.amount = randi_range(4, 10) lines_particles.amount = randi_range(1, 3) diff --git a/sources/minigames/monkeys/coconut.gd b/sources/minigames/monkeys/coconut.gd index 11228367..dd86b2e6 100644 --- a/sources/minigames/monkeys/coconut.gd +++ b/sources/minigames/monkeys/coconut.gd @@ -1,10 +1,5 @@ -extends Node2D class_name Coconut - -@onready var highlight_fx: HighlightFX = $HighlightFX -@onready var sprite: Sprite2D = $Sprite2D -@onready var label: Label = $Label -@onready var broken_coconut_fx: BrokenCoconutFX = $BrokenCoconutFX +extends Node2D var text: String: set(value): @@ -12,6 +7,11 @@ var text: String: if label: label.text = text +@onready var highlight_fx: HighlightFX = $HighlightFX +@onready var sprite: Sprite2D = $Sprite2D +@onready var label: Label = $Label +@onready var broken_coconut_fx: BrokenCoconutFX = $BrokenCoconutFX + func highlight() -> void: highlight_fx.play() diff --git a/sources/minigames/monkeys/king_monkey.gd b/sources/minigames/monkeys/king_monkey.gd index f85e0486..3407789a 100644 --- a/sources/minigames/monkeys/king_monkey.gd +++ b/sources/minigames/monkeys/king_monkey.gd @@ -1,5 +1,5 @@ -extends Node2D class_name KingMonkey +extends Node2D @onready var animation_player: AnimationPlayer = $AnimationPlayer @onready var coconut: Coconut = $Marker2D/Coconut diff --git a/sources/minigames/monkeys/monkey.gd b/sources/minigames/monkeys/monkey.gd index 74717e54..3084c74e 100644 --- a/sources/minigames/monkeys/monkey.gd +++ b/sources/minigames/monkeys/monkey.gd @@ -1,20 +1,10 @@ @tool -extends Node2D class_name Monkey +extends Node2D signal pressed() signal dragged_into_self() - -@onready var stars: AnimatedSprite2D = $Stars -@onready var coconut: Coconut = $Marker2D/Coconut -@onready var coconut_pivot: Marker2D = $Marker2D -@onready var animation_player: AnimationPlayer = $AnimationPlayer -@onready var drag_preview_label: Label = $Button/DragPreview/Label -@onready var drag_preview: TextureRect = $Button/DragPreview -@onready var button: Button = $Button -@onready var hit_position: Marker2D = $HitPosition - var locked: bool = true: set(value): locked = value or stunned @@ -23,8 +13,6 @@ var stunned: bool = false: stunned = value stars.visible = stunned locked = true - - var stimulus: Dictionary = {}: set(value): stimulus = value @@ -36,6 +24,15 @@ var stimulus: Dictionary = {}: drag_preview_label.text = "" coconut_pivot.hide() +@onready var stars: AnimatedSprite2D = $Stars +@onready var coconut: Coconut = $Marker2D/Coconut +@onready var coconut_pivot: Marker2D = $Marker2D +@onready var animation_player: AnimationPlayer = $AnimationPlayer +@onready var drag_preview_label: Label = $Button/DragPreview/Label +@onready var drag_preview: TextureRect = $Button/DragPreview +@onready var button: Button = $Button +@onready var hit_position: Marker2D = $HitPosition + func _ready() -> void: (button as Control).set_drag_forwarding(_get_drag_data, _can_drop_data, _drop_data) diff --git a/sources/minigames/monkeys/monkeys_minigame.gd b/sources/minigames/monkeys/monkeys_minigame.gd index 7f80f469..635da579 100644 --- a/sources/minigames/monkeys/monkeys_minigame.gd +++ b/sources/minigames/monkeys/monkeys_minigame.gd @@ -1,27 +1,22 @@ @tool extends WordsMinigame -const MONKEY_SCENE: PackedScene = preload("res://sources/minigames/monkeys/monkey.tscn") - -const AUDIO_STREAMS: Array[AudioStreamMP3] = [ - preload("res://assets/minigames/monkeys/audio/monkey_sendcoco.mp3"), - preload("res://assets/minigames/monkeys/audio/monkey_sendcoco_right.mp3"), - preload("res://assets/minigames/monkeys/audio/monkey_sendcoco_wrong.mp3"), -] - enum Audio { SendToKing, SendToPlank, SendToMonkey, } +const MONKEY_SCENE: PackedScene = preload("res://sources/minigames/monkeys/monkey.tscn") +const AUDIO_STREAMS: Array[AudioStreamMP3] = [ + preload("res://assets/minigames/monkeys/audio/monkey_sendcoco.mp3"), + preload("res://assets/minigames/monkeys/audio/monkey_sendcoco_right.mp3"), + preload("res://assets/minigames/monkeys/audio/monkey_sendcoco_wrong.mp3"), +] -class DifficultySettings: - var distractors_count: int = 1 - - func _init(p_distractors_count: int) -> void: - distractors_count = p_distractors_count - +@export var throw_to_king_duration: float = 1.2 +@export var throw_to_monkey_duration: float = 0.4 +@export var throw_to_plank_duration: float = 0.8 var difficulty_settings: Array[DifficultySettings] = [ DifficultySettings.new(1), @@ -30,11 +25,12 @@ var difficulty_settings: Array[DifficultySettings] = [ DifficultySettings.new(3), DifficultySettings.new(3) ] - - -@export var throw_to_king_duration: float = 1.2 -@export var throw_to_monkey_duration: float = 0.4 -@export var throw_to_plank_duration: float = 0.8 +var monkeys: Array[Monkey] = [] +var is_locked: bool = true: + set(value): + is_locked = value + for monkey: Monkey in monkeys: + monkey.locked = value @onready var monkeys_node: Control = $GameRoot/Monkeys @onready var possible_positions_parent: TextureRect = $GameRoot/PalmTreeMonkeys @@ -43,13 +39,6 @@ var difficulty_settings: Array[DifficultySettings] = [ @onready var parabola_summit: Control = $GameRoot/ParabolaSummit @onready var text_plank: TextureRect = $GameRoot/TextPlank -var monkeys: Array[Monkey] = [] -var is_locked: bool = true: - set(value): - is_locked = value - for monkey: Monkey in monkeys: - monkey.locked = value - # Find and set the parameters of the minigame, like the number of lives or the victory conditions. func _setup_minigame() -> void: @@ -250,3 +239,10 @@ func _on_current_progression_changed() -> void: is_locked = false #endregion + +class DifficultySettings: + var distractors_count: int = 1 + + + func _init(p_distractors_count: int) -> void: + distractors_count = p_distractors_count diff --git a/sources/minigames/parakeets/parakeet.gd b/sources/minigames/parakeets/parakeet.gd index 936b142d..be58c079 100644 --- a/sources/minigames/parakeets/parakeet.gd +++ b/sources/minigames/parakeets/parakeet.gd @@ -1,8 +1,8 @@ @tool -extends Node2D class_name Parakeet +extends Node2D -const INSTANCE_SCENE: String = "res://sources/minigames/parakeets/parakeet.tscn" +signal pressed() enum Colors { Red, @@ -10,14 +10,13 @@ enum Colors { Yellow, } +const INSTANCE_SCENE: String = "res://sources/minigames/parakeets/parakeet.tscn" const ANIMATIONS: Array[SpriteFrames] = [ preload("res://sources/minigames/parakeets/red_parakeet_animations.tres"), preload("res://sources/minigames/parakeets/green_parakeet_animations.tres"), preload("res://sources/minigames/parakeets/yellow_parakeet_animation.tres") ] -signal pressed() - @export var sad_duration: float = 2.0 @export var color: Colors = Colors.Red: set(value): @@ -30,17 +29,21 @@ signal pressed() if label: label.text = label.text.to_upper() if uppercase else label.text.to_lower() -@onready var animated_sprite: AnimatedSprite2D = $AnimatedSprite2D -@onready var label: Label = $Label -@onready var right_FX: RightFX = $RightFX -@onready var wrong_FX: WrongFX = $WrongFX - var stimulus: Dictionary = {}: set(value): stimulus = value var grapheme: String = value.Grapheme as String label.text = grapheme.to_upper() if uppercase else grapheme +@onready var animated_sprite: AnimatedSprite2D = $AnimatedSprite2D +@onready var label: Label = $Label +@onready var right_FX: RightFX = $RightFX +@onready var wrong_FX: WrongFX = $WrongFX + + +static func instantiate() -> Parakeet: + return (load(INSTANCE_SCENE) as PackedScene).instantiate() + func _ready() -> void: color = color @@ -51,10 +54,6 @@ func _on_button_pressed() -> void: pressed.emit() -static func instantiate() -> Parakeet: - return (load(INSTANCE_SCENE) as PackedScene).instantiate() - - func turn_to_back() -> void: animated_sprite.play("turn_to_back") label.hide() diff --git a/sources/minigames/parakeets/parakeets_minigame.gd b/sources/minigames/parakeets/parakeets_minigame.gd index 88470733..4aff3eb1 100644 --- a/sources/minigames/parakeets/parakeets_minigame.gd +++ b/sources/minigames/parakeets/parakeets_minigame.gd @@ -7,7 +7,6 @@ enum State { Selected1, Selected2, } - enum Audio { Fly, Happy, @@ -21,9 +20,21 @@ const AUDIO_STREAMS: Array[AudioStreamMP3] = [ preload("res://assets/minigames/parakeets/audio/parakeet_turn_over.mp3"), preload("res://assets/minigames/parakeets/audio/parakeet_win.mp3"), ] +const DIFFICULTY_SETTINGS: Dictionary[int, Dictionary] = { + 0: {"pairs_count": 2}, + 1: {"pairs_count": 3}, + 2: {"pairs_count": 4}, + 3: {"pairs_count": 5}, + 4: {"pairs_count": 6}, +} @export var fly_duration: float = 3.0 +var possible_branch_positions: Array[Vector2] = [] +var parakeets: Array[Parakeet] = [] +var selected: Array[Parakeet] = [] +var state: State = State.Locked + @onready var branches: Control = $GameRoot/TreeTrunk/Branches @onready var possible_start_positions_parent: Control = $GameRoot/FlyFrom @onready var parakeets_node: Control = $GameRoot/Parakeets @@ -40,19 +51,6 @@ const AUDIO_STREAMS: Array[AudioStreamMP3] = [ fly_away_position_2.global_position ] -var possible_branch_positions: Array[Vector2] = [] -var parakeets: Array[Parakeet] = [] -var selected: Array[Parakeet] = [] -var state: State = State.Locked - -const DIFFICULTY_SETTINGS: Dictionary[int, Dictionary] = { - 0: {"pairs_count": 2}, - 1: {"pairs_count": 3}, - 2: {"pairs_count": 4}, - 3: {"pairs_count": 5}, - 4: {"pairs_count": 6}, -} - # Find and set the parameters of the minigame, like the number of lives or the victory conditions. func _setup_minigame() -> void: diff --git a/sources/minigames/penguin/penguin.gd b/sources/minigames/penguin/penguin.gd index 4a329abe..fee2bc72 100644 --- a/sources/minigames/penguin/penguin.gd +++ b/sources/minigames/penguin/penguin.gd @@ -1,15 +1,14 @@ -extends Node2D class_name Penguin - +extends Node2D const SNOWBALL_SCENE: PackedScene = preload("res://sources/minigames/penguin/snowball.tscn") +var throw_position: Vector2 + @onready var snowball_position: Marker2D = $Sprite2D/Snowball @onready var animation_player: AnimationPlayer = $AnimationPlayer @onready var audiostream_player: AudioStreamPlayer = $AudioStreamPlayer -var throw_position: Vector2 - func _create_snowball() -> void: var snowball: Snowball = SNOWBALL_SCENE.instantiate() diff --git a/sources/minigames/penguin/penguin_label.gd b/sources/minigames/penguin/penguin_label.gd index 8358a050..2e687e6b 100644 --- a/sources/minigames/penguin/penguin_label.gd +++ b/sources/minigames/penguin/penguin_label.gd @@ -1,16 +1,17 @@ -extends Label class_name PenguinLabel +extends Label signal pressed(pos: Vector2) +var gp: Dictionary = {} +var capitalized: bool = false +var is_pressed: bool = false + @onready var highlight_fx: HighlightFX = %HighlightFX @onready var right_fx: RightFX = %RightFX @onready var wrong_fx: WrongFX = %WrongFX @onready var button: Button = $Button -var gp: Dictionary = {} -var capitalized: bool = false -var is_pressed: bool = false func _ready() -> void: if gp: @@ -36,6 +37,7 @@ func wrong() -> void: set("theme_override_colors/font_color",Color.RED) await wrong_fx.finished + func highlight(value: bool = true) -> void: if value: highlight_fx.play() diff --git a/sources/minigames/penguin/penguin_minigame.gd b/sources/minigames/penguin/penguin_minigame.gd index 9b721fe5..63a79a74 100644 --- a/sources/minigames/penguin/penguin_minigame.gd +++ b/sources/minigames/penguin/penguin_minigame.gd @@ -1,17 +1,15 @@ @tool extends Minigame -# Namespace const LABEL_SCENE: PackedScene = preload("res://sources/minigames/penguin/penguin_label.tscn") +var current_word_progression: int = 0: set = _set_current_word_progression +var max_word_progression: int = 0 +var labels: Array[PenguinLabel] = [] @onready var penguin: Penguin = $GameRoot/Penguin @onready var labels_container: HFlowContainer = $GameRoot/Control/LabelsContainer -var current_word_progression: int = 0: set = _set_current_word_progression -var max_word_progression: int = 0 - -var labels: Array[PenguinLabel] = [] # Find words with silent GPs func _find_stimuli_and_distractions() -> void: diff --git a/sources/minigames/penguin/snowball.gd b/sources/minigames/penguin/snowball.gd index 63b59e36..69aac407 100644 --- a/sources/minigames/penguin/snowball.gd +++ b/sources/minigames/penguin/snowball.gd @@ -1,23 +1,20 @@ -extends Path2D class_name Snowball +extends Path2D + +var target_position: Vector2 @onready var path_follow: PathFollow2D = $PathFollow2D @onready var sprite: Sprite2D = $PathFollow2D/Sprite2D @onready var particles: GPUParticles2D = $PathFollow2D/Particles -var target_position: Vector2 func _ready() -> void: curve.set_point_position(1, target_position) - var tween: Tween = create_tween() tween.tween_property(path_follow, "progress_ratio", 1, .5) await tween.finished - sprite.visible = false - # Particles particles.restart() await particles.finished - queue_free() diff --git a/sources/minigames/turtles/island.gd b/sources/minigames/turtles/island.gd index c385a758..71fa7032 100644 --- a/sources/minigames/turtles/island.gd +++ b/sources/minigames/turtles/island.gd @@ -1,19 +1,18 @@ -extends Area2D class_name Island - -@onready var label: Label = $Label -@onready var collision: CollisionPolygon2D = $CollisionPolygon2D +extends Area2D var stimulus: Dictionary = {}: set(value): stimulus = value progress = 0 - var progress: int = 0: set(value): progress = value _update_label() +@onready var label: Label = $Label +@onready var collision: CollisionPolygon2D = $CollisionPolygon2D + func set_enabled(is_enabled: bool) -> void: collision.set_deferred("disabled", !is_enabled) diff --git a/sources/minigames/turtles/turtle.gd b/sources/minigames/turtles/turtle.gd index d64b8a98..3af59dca 100644 --- a/sources/minigames/turtles/turtle.gd +++ b/sources/minigames/turtles/turtle.gd @@ -1,20 +1,9 @@ -extends Node2D class_name Turtle +extends Node2D signal pressed(gp: Dictionary) signal animation_changed(position: Vector2) -@onready var body: Node2D = $Body -@onready var sprite: AnimatedSprite2D = $Body/AnimatedSprite2D -@onready var label: Label = $Label -@onready var head_area_collision_shape: CollisionShape2D = $Body/HeadArea/CollisionShape2D -@onready var body_area_collision_shape: CollisionShape2D = $Body/BodyArea/CollisionShape2D -@onready var highlight_fx: HighlightFX = $HighlightFX -@onready var right_fx: RightFX = $RightFX -@onready var wrong_fx: WrongFX = $WrongFX -@onready var delete_timer: Timer = $DeleteTimer -@onready var audio_stream_player: AudioStreamPlayer2D = $AudioStreamPlayer2D - var gp: Dictionary = {}: set(value): gp = value @@ -29,6 +18,17 @@ var is_moving: bool = true var is_changing_direction: bool = false var is_visible_on_screen: bool = false +@onready var body: Node2D = $Body +@onready var sprite: AnimatedSprite2D = $Body/AnimatedSprite2D +@onready var label: Label = $Label +@onready var head_area_collision_shape: CollisionShape2D = $Body/HeadArea/CollisionShape2D +@onready var body_area_collision_shape: CollisionShape2D = $Body/BodyArea/CollisionShape2D +@onready var highlight_fx: HighlightFX = $HighlightFX +@onready var right_fx: RightFX = $RightFX +@onready var wrong_fx: WrongFX = $WrongFX +@onready var delete_timer: Timer = $DeleteTimer +@onready var audio_stream_player: AudioStreamPlayer2D = $AudioStreamPlayer2D + func _process(delta: float) -> void: if is_moving: diff --git a/sources/minigames/turtles/turtles_minigame.gd b/sources/minigames/turtles/turtles_minigame.gd index 6d154efc..c27ece76 100644 --- a/sources/minigames/turtles/turtles_minigame.gd +++ b/sources/minigames/turtles/turtles_minigame.gd @@ -8,18 +8,6 @@ const MAX_TURTLE_COUNT: int = 5 # Defines the minimum distance between turtles when spawning them const MIN_DISTANCE: int = 500 - -class DifficultySettings: - var stimuli_ratio: float = 0.75 - var velocity: float = 250. - var spawn_rate: float = 4. - - func _init(p_stimuli_ratio: float, p_velocity: float, p_spawn_rate: float) -> void: - stimuli_ratio = p_stimuli_ratio - velocity = p_velocity - spawn_rate = p_spawn_rate - - var difficulty_settings: Array[DifficultySettings] = [ DifficultySettings.new(.75, 200., 4.), DifficultySettings.new(.66, 250., 3.5), @@ -27,14 +15,6 @@ var difficulty_settings: Array[DifficultySettings] = [ DifficultySettings.new(.25, 333., 2.5), DifficultySettings.new(.25, 366., 2.) ] - - -@onready var water: Water = $GameRoot/Water -@onready var island: Island = $GameRoot/Island -@onready var turtles: Control = %Turtles -@onready var spawn_location: PathFollow2D = $GameRoot/SpawnPath/SpawnLocation -@onready var spawn_timer: Timer = $GameRoot/SpawnTimer - var settings: DifficultySettings var turtle_count: int = 0: set(value): @@ -43,6 +23,13 @@ var turtle_count: int = 0: turtle_count = value var stimulus_spawned: bool = false +@onready var water: Water = $GameRoot/Water +@onready var island: Island = $GameRoot/Island +@onready var turtles: Control = %Turtles +@onready var spawn_location: PathFollow2D = $GameRoot/SpawnPath/SpawnLocation +@onready var spawn_timer: Timer = $GameRoot/SpawnTimer + + # Find and set the parameters of the minigame, like the number of lives or the victory conditions. func _setup_minigame() -> void: super._setup_minigame() @@ -216,3 +203,14 @@ func _on_current_progression_changed() -> void: spawn_timer.start() #endregion + +class DifficultySettings: + var stimuli_ratio: float = 0.75 + var velocity: float = 250. + var spawn_rate: float = 4. + + + func _init(p_stimuli_ratio: float, p_velocity: float, p_spawn_rate: float) -> void: + stimuli_ratio = p_stimuli_ratio + velocity = p_velocity + spawn_rate = p_spawn_rate diff --git a/sources/minigames/turtles/water.gd b/sources/minigames/turtles/water.gd index e6fe7f95..84e45383 100644 --- a/sources/minigames/turtles/water.gd +++ b/sources/minigames/turtles/water.gd @@ -1,10 +1,11 @@ -extends TextureRect class_name Water +extends TextureRect const WATER_RING_SCENE: PackedScene = preload("res://sources/utils/fx/water_ring.tscn") @export var ring_color: Color + func spawn_water_ring(pos: Vector2) -> void: var fx: WaterRingFX = WATER_RING_SCENE.instantiate() fx.position = pos diff --git a/sources/ui/loading_popup.gd b/sources/ui/loading_popup.gd index af278f4b..12fb6128 100644 --- a/sources/ui/loading_popup.gd +++ b/sources/ui/loading_popup.gd @@ -1,20 +1,18 @@ @tool -extends CanvasLayer class_name LoadingPopup +extends CanvasLayer -signal cancel -signal ok +signal cancel() +signal ok() @export_multiline var content_text: String = "": set = _set_content_text +@export var cancel_text_override: String = "" @onready var content_label: Label = %ContentLabel @onready var progress_bar: ProgressBar = %ProgressBar - @onready var cancel_button: Button = %CancelButton @onready var ok_button: Button = %OKButton -@export var cancel_text_override: String = "" - func set_text(text: String) -> void: content_label.text = text diff --git a/sources/ui/popup.gd b/sources/ui/popup.gd index 53b847ed..50ecb319 100644 --- a/sources/ui/popup.gd +++ b/sources/ui/popup.gd @@ -1,18 +1,18 @@ @tool -extends CanvasLayer class_name ConfirmPopup +extends CanvasLayer -signal accepted -signal refused +signal accepted() +signal refused() @export_multiline var content_text: String = "": set = _set_content_text +@export var confirm_text_override: String = "" +@export var cancel_text_override: String = "" @onready var content_label: Label = %ContentLabel @onready var confirm_button: Button = %ConfirmButton @onready var cancel_button: Button = %CancelButton -@export var confirm_text_override: String = "" -@export var cancel_text_override: String = "" func _ready() -> void: _set_content_text(content_text) diff --git a/sources/ui/tr_item_list.gd b/sources/ui/tr_item_list.gd index 26a8ce10..33cce8bb 100644 --- a/sources/ui/tr_item_list.gd +++ b/sources/ui/tr_item_list.gd @@ -1,5 +1,6 @@ extends ItemList + func _ready() -> void: for index: int in range(self.item_count): self.set_item_text(index, tr(self.get_item_text(index))) diff --git a/sources/utils/auto_size_label.gd b/sources/utils/auto_size_label.gd index e8053f0e..b0426258 100644 --- a/sources/utils/auto_size_label.gd +++ b/sources/utils/auto_size_label.gd @@ -2,9 +2,12 @@ extends Container @export_multiline var ref_size_text: String = "" + var ref_size: Vector2 + @onready var label: Label = $Label + func _notification(what: int) -> void: if what == NOTIFICATION_SORT_CHILDREN: _rescale() diff --git a/sources/utils/autoloads/database.gd b/sources/utils/autoloads/database.gd index 3852d9c4..20aae49f 100644 --- a/sources/utils/autoloads/database.gd +++ b/sources/utils/autoloads/database.gd @@ -26,7 +26,6 @@ var language: String: language = value db_path = BASE_PATH + language + "/language.db" words_path = BASE_PATH + language + "/words/" - var db_path: String = BASE_PATH + language + "/language.db": set(value): db_path = value @@ -34,12 +33,11 @@ var db_path: String = BASE_PATH + language + "/language.db": db.path = db_path db.foreign_keys = true connect_to_db() - var words_path: String = BASE_PATH + language + "/words/" var additional_word_list: Dictionary = {} +var is_open: bool = false @onready var db: SQLite = SQLite.new() -var is_open: bool = false func _exit_tree() -> void: @@ -616,6 +614,7 @@ func _phoneme_to_string(phoneme: String) -> String: else: return "cap." + phoneme.to_lower() + # Returns an array containing an int followed by an array of int func _import_word_from_csv(ortho: String, gpmatch: String, is_word: bool = true) -> Array[Variant]: var gp_list: PackedStringArray = gpmatch.trim_prefix("(").trim_suffix(")").split(".") diff --git a/sources/utils/autoloads/lesson_logger.gd b/sources/utils/autoloads/lesson_logger.gd index fa34b273..88393b0d 100644 --- a/sources/utils/autoloads/lesson_logger.gd +++ b/sources/utils/autoloads/lesson_logger.gd @@ -6,18 +6,14 @@ var log_resources: Dictionary = {} func save_logs(logs: Dictionary, folder_path: String, minigame_name: String, lesson_nb: int, time: String) -> void: var file_path: String = folder_path + minigame_name + ".tres" - var log_resource: LogResource if not ResourceLoader.exists(file_path): log_resource = LogResource.new() ResourceSaver.save(log_resource, file_path, ResourceSaver.FLAG_COMPRESS) - if not file_path in log_resources: log_resource = ResourceLoader.load(file_path) log_resources[file_path] = log_resource else: log_resource = log_resources[file_path] - log_resource.add_log(lesson_nb, logs, time) - ResourceSaver.save(log_resource, file_path, ResourceSaver.FLAG_COMPRESS) diff --git a/sources/utils/autoloads/logger.gd b/sources/utils/autoloads/logger.gd index 63dbf157..ffa45f9b 100644 --- a/sources/utils/autoloads/logger.gd +++ b/sources/utils/autoloads/logger.gd @@ -6,15 +6,17 @@ enum LogLevel { INFO, WARNING, ERROR, + # TODO : PANIC NONE } +const LOG_PATH: String = "user://Logs/" + var current_level: LogLevel = LogLevel.INFO var log_file_path: String var log_file: FileAccess var initialized: bool = false -const LOG_PATH: String = "user://Logs/" func _ready() -> void: delete_old_logs() @@ -29,6 +31,7 @@ func _ready() -> void: _log_internal(LogLevel.INFO, "--- Logging started at " + Time.get_datetime_string_from_system() + " ---") _log_internal(LogLevel.INFO, "--- Logging set at level " + str(current_level) + " ---") + func delete_old_logs(days_threshold: float = 10) -> void: var dir: DirAccess = DirAccess.open(LOG_PATH) var err: Error = DirAccess.get_open_error() @@ -66,6 +69,7 @@ func delete_old_logs(days_threshold: float = 10) -> void: file_name = dir.get_next() dir.list_dir_end() + func _init_log_file() -> void: # Ensure Logs directory exists var logs_dir: DirAccess = DirAccess.open(LOG_PATH) @@ -88,6 +92,7 @@ func _init_log_file() -> void: push_error("Logger: Could not open log file at " + log_file_path) return + # Internal log function (renamed to avoid conflict) func _log_internal(level: LogLevel, message: String) -> void: if initialized && level < current_level: # If not initialized, no logs are filtered @@ -116,17 +121,28 @@ func _log_internal(level: LogLevel, message: String) -> void: _log_to_file(log_message) + func _log_to_file(message: String) -> void: if log_file: log_file.store_line(message) log_file.flush() -# Sugar functions + # trace can be used everywhere, in order to have a full log of all that is hapenning func trace(msg: String) -> void: _log_internal(LogLevel.TRACE, msg) + + # debug should only be used in a dev environment to track a specific bug. func debug(msg: String) -> void: _log_internal(LogLevel.DEBUG, msg) + + # info can carry important information(s) that should always be logged but that are not problematic func info(msg: String) -> void: _log_internal(LogLevel.INFO, msg) + + +# warning should be used when a behaviour is not normal, but this is not blocking or it could be ignored func warn(msg: String) -> void: _log_internal(LogLevel.WARNING, msg) + + +# error should be used everytime the program does something that is problematic and could potentially harm the user experience func error(msg: String) -> void: _log_internal(LogLevel.ERROR, msg) diff --git a/sources/utils/autoloads/music_manager.gd b/sources/utils/autoloads/music_manager.gd index 98797426..d1572016 100644 --- a/sources/utils/autoloads/music_manager.gd +++ b/sources/utils/autoloads/music_manager.gd @@ -1,27 +1,31 @@ extends Node -@onready var music_player: AudioStreamPlayer = $MusicPlayer - -const TRACKS: Array = [ - preload("res://assets/music/title.mp3"), - preload("res://assets/music/garden.mp3") -] - enum Track { Title, Garden } +const TRACKS: Array = [ + preload("res://assets/music/title.mp3"), + preload("res://assets/music/garden.mp3") +] + +@onready var music_player: AudioStreamPlayer = $MusicPlayer + + func _ready() -> void: play(Track.Title) + func _on_music_player_finished() -> void: music_player.stream_paused = false music_player.play() + func play(track: Track) -> void: music_player.stream = TRACKS[track] music_player.play() + func stop() -> void: music_player.stop() diff --git a/sources/utils/autoloads/opening_curtain.gd b/sources/utils/autoloads/opening_curtain.gd index b1b23b32..43866fdd 100644 --- a/sources/utils/autoloads/opening_curtain.gd +++ b/sources/utils/autoloads/opening_curtain.gd @@ -3,9 +3,10 @@ extends CanvasLayer signal animation_finished(animation_name: StringName) +var is_closed: bool = false + @onready var animation_player: AnimationPlayer = $AnimationPlayer -var is_closed: bool = false func open() -> void: if is_closed: diff --git a/sources/utils/autoloads/server_manager.gd b/sources/utils/autoloads/server_manager.gd index f7c951fa..db267901 100644 --- a/sources/utils/autoloads/server_manager.gd +++ b/sources/utils/autoloads/server_manager.gd @@ -1,15 +1,21 @@ -extends CanvasLayer class_name ServerManagerClass +extends CanvasLayer signal request_completed(success: bool, code: int, body: Dictionary) signal internet_check_completed(has_acces: bool) +const INTERNET_CHECK_URL: String = "https://google.com" + +# Response from the last request +var success: bool +var code: int +var json: Dictionary = {} +var environment_url: String = "" + @onready var internet_check: HTTPRequest = $InternetCheck @onready var http_request: HTTPRequest = $HTTPRequest @onready var loading_rect: TextureRect = $TextureRect -const INTERNET_CHECK_URL: String = "https://google.com" -var environment_url: String = "" func _ready() -> void: var config: ConfigFile = ConfigFile.new() @@ -158,11 +164,6 @@ func _create_request_headers(content_type_json: bool = false) -> PackedStringArr return headers -# Response from the last request -var success: bool -var code: int -var json: Dictionary = {} - func _response() -> Dictionary: var res: Dictionary = { "success": success, diff --git a/sources/utils/autoloads/user_data_manager.gd b/sources/utils/autoloads/user_data_manager.gd index ffb8ed2c..81eda5f9 100644 --- a/sources/utils/autoloads/user_data_manager.gd +++ b/sources/utils/autoloads/user_data_manager.gd @@ -1,6 +1,5 @@ -extends Node class_name UserDataManagerClass - +extends Node var student: String = "": set(student_name): @@ -18,7 +17,6 @@ var student: String = "": _student_remediation = null _student_confusion_matrix = null _student_speeches = null - var _device_settings: DeviceSettings var teacher_settings: TeacherSettings var student_progression: StudentProgression @@ -26,7 +24,6 @@ var _student_remediation: UserRemediation var _student_confusion_matrix: UserConfusionMatrix var _student_difficulty: UserDifficulty var _student_speeches: UserSpeeches - var user_database_synchronizer: UserDatabaseSynchronizer var synchronization_timer: int = 0 var synchronization_timer_running: bool = false @@ -35,6 +32,7 @@ var now: int var last_time: int = 0 var real_delta: int + func _ready() -> void: if get_device_settings().teacher: _load_teacher_settings() @@ -43,6 +41,7 @@ func _ready() -> void: user_database_synchronizer = UserDatabaseSynchronizer.new() + func purge_user_folders_if_needed() -> void: var current_version: String = ProjectSettings.get_setting("application/config/version") var previous_version: String = _device_settings.game_version @@ -69,6 +68,7 @@ func purge_user_folders_if_needed() -> void: _device_settings.game_version = current_version ResourceSaver.save(_device_settings, "user://device_settings.tres") + func _process(_delta: float) -> void: if Engine.is_editor_hint(): return # Do nothing in editor mode @@ -114,6 +114,7 @@ func register(register_settings: TeacherSettings) -> bool: return true + # Allow the user to log-in from the server func login(infos: Dictionary) -> bool: if not _device_settings: @@ -163,6 +164,7 @@ func login(infos: Dictionary) -> bool: return true + func safe_load_and_fix_resource(path: String, old_texts: Array[String], new_texts: Array[String]) -> Resource: if not FileAccess.file_exists(path): Logger.error("UserDataManager: File not found: " + path) @@ -192,6 +194,7 @@ func safe_load_and_fix_resource(path: String, old_texts: Array[String], new_text Logger.trace("UserDataManager: Loading success: " + path) return resource + func set_device_id(device: int) -> bool: if not _device_settings: Logger.warn("UserDataManager: set_device_id called with no device settings loaded") @@ -205,6 +208,7 @@ func set_device_id(device: int) -> bool: _save_device_settings() return true + func logout() -> void: # Handles device settings @@ -219,10 +223,12 @@ func logout() -> void: if student: student = "" + func delete_teacher_data() -> void: if DirAccess.dir_exists_absolute(get_teacher_folder()): Utils.clean_dir(get_teacher_folder()) + func student_exists(code: String) -> bool: if not _device_settings: Logger.trace("UserDataManager: student_exists called with invalid _device_settings") @@ -237,6 +243,7 @@ func student_exists(code: String) -> bool: return true return false + func login_student(code: String) -> bool: if not _device_settings: Logger.warn("UserDataManager: login_student failed because of invalid _device_settings") @@ -256,6 +263,7 @@ func login_student(code: String) -> bool: Logger.warn("UserDataManager: login_student failed, code not found: " + code) return false + func logout_student() -> bool: if not _device_settings: Logger.warn("UserDataManager: logout_student failed because of invalid _device_settings") @@ -274,11 +282,13 @@ func logout_student() -> bool: func get_device_settings_path() -> String: return "user://device_settings.tres" + func get_device_settings() -> DeviceSettings: if not _device_settings: _load_device_settings() return _device_settings + func _load_device_settings() -> void: if FileAccess.file_exists(get_device_settings_path()): _device_settings = load(get_device_settings_path()) @@ -289,81 +299,90 @@ func _load_device_settings() -> void: _device_settings.init_os_language() _save_device_settings() + func _save_device_settings() -> void: Logger.trace("UserDataManager: Saving device settings in " + ProjectSettings.globalize_path(get_device_settings_path())) ResourceSaver.save(_device_settings, get_device_settings_path()) + func set_language(language: String) -> void: if _device_settings: _device_settings.language = language _save_device_settings() + func set_language_version(language: String, version: Dictionary) -> void: if _device_settings: _device_settings.language_versions[language] = version _save_device_settings() + func set_master_volume(value: float) -> void: if _device_settings: var volume: float = denormalize_volume(value) _device_settings.master_volume = volume _save_device_settings() + func set_music_volume(value: float) -> void: if _device_settings: var volume: float = denormalize_volume(value) _device_settings.music_volume = volume _save_device_settings() + func set_voice_volume(value: float) -> void: if _device_settings: var volume: float = denormalize_volume(value) _device_settings.voice_volume = volume _save_device_settings() + func set_effects_volume(value: float) -> void: if _device_settings: var volume: float = denormalize_volume(value) _device_settings.effects_volume = volume _save_device_settings() + func get_master_volume() -> float: var value: float = 0.0 if _device_settings: var volume: float = _device_settings.master_volume value = normalize_slider(volume) - return value + func get_music_volume() -> float: var value: float = 0.0 if _device_settings: var volume: float = _device_settings.music_volume value = normalize_slider(volume) - return value + func get_voice_volume() -> float: var value: float = 0.0 if _device_settings: var volume: float = _device_settings.voice_volume value = normalize_slider(volume) - return value + func get_effects_volume() -> float: var value: float = 0.0 if _device_settings: var volume: float = _device_settings.effects_volume value = normalize_slider(volume) - return value + # Convert the volume from [-80, 6]db to [0, 100] and back func normalize_slider(volume: float) -> float: var value: float = pow((volume + 80.0) / 86, 5.0) * 100.0 return value + func denormalize_volume(value: float) -> float: var volume: float = pow(float(value) / 100.0, 0.2) * 86 - 80 return volume @@ -375,12 +394,15 @@ func denormalize_volume(value: float) -> float: func get_teacher_folder() -> String: return "user://".path_join(_device_settings.teacher) + func _get_teacher_settings_path(teacher: String) -> String: return "user://".path_join(teacher).path_join("teacher_settings.tres") + func get_teacher_settings_path() -> String: return _get_teacher_settings_path(_device_settings.teacher) + func _load_teacher_settings() -> void: if FileAccess.file_exists(get_teacher_settings_path()): teacher_settings = safe_load_and_fix_resource(get_teacher_settings_path(), @@ -391,10 +413,12 @@ func _load_teacher_settings() -> void: _device_settings.device_id = 0 _save_device_settings() + func save_teacher_settings() -> void: Logger.trace("UserDataManager: Saving teacher settings in " + ProjectSettings.globalize_path(get_teacher_settings_path())) ResourceSaver.save(teacher_settings, get_teacher_settings_path()) + func _delete_inexistants_students_saves() -> void: if not teacher_settings: return @@ -426,6 +450,7 @@ func _delete_inexistants_students_saves() -> void: if not exists: Utils.delete_directory_recursive(path.path_join(device).path_join(language).path_join(p_student)) + func update_configuration(configuration: Dictionary) -> bool: if not teacher_settings: return false @@ -448,6 +473,7 @@ func update_configuration(configuration: Dictionary) -> bool: return true + func get_number_of_students() -> int: if not teacher_settings: return 0 @@ -463,6 +489,7 @@ func get_student_folder(student_code: int = 0) -> String: else: return _device_settings.get_folder_path().path_join(str(student_code)) + func delete_student(student_code: int) -> void: teacher_settings.delete_student(student_code) @@ -480,6 +507,7 @@ func get_student_progression_path(device: int = 0, student_code: int = 0) -> Str var remediation_path: String = student_path.path_join("progression.tres") return remediation_path + func _load_student_progression() -> void: if FileAccess.file_exists(get_student_progression_path()): student_progression = safe_load_and_fix_resource( get_student_progression_path(), @@ -494,13 +522,16 @@ func _load_student_progression() -> void: student_progression.init_unlocks() student_progression.unlocks_changed.connect(_on_user_progression_unlocks_changed) + func _save_student_progression() -> void: Logger.trace("UserDataManager: Saving student progression in " + ProjectSettings.globalize_path(get_student_progression_path())) ResourceSaver.save(student_progression, get_student_progression_path()) + func _on_user_progression_unlocks_changed() -> void: _save_student_progression() + func get_student_progression_for_code(device: int, code: int) -> StudentProgression: if device == 0: var device_path: String = find_device_dir_for_student(code) @@ -530,12 +561,14 @@ func get_student_progression_for_code(device: int, code: int) -> StudentProgress return progression + func save_student_progression_for_code(device: int, code: int, progression: StudentProgression) -> void: var progression_path: String = "user://".path_join(_device_settings.teacher).path_join(str(device)).path_join(_device_settings.language).path_join(str(code)).path_join("progression.tres") var error: Error = ResourceSaver.save(progression, progression_path) if error != OK: Logger.error("UserDataManager: save_student_progression_for_code(device = %s, code = %s): error %s" % [str(device), str(code), error_string(error)]) + func set_student_progression_data(student_code: int, version: String, new_data: Dictionary, updated_at: String) -> void: var current_data: StudentProgression = get_student_progression_for_code(0, student_code) if current_data == null: @@ -561,6 +594,7 @@ func _get_student_remediation_path(device: int = 0, student_code: int = 0) -> St var remediation_path: String = student_path.path_join("remediation.tres") return remediation_path + func _load_student_remediation() -> void: if FileAccess.file_exists(_get_student_remediation_path()): _student_remediation = load(_get_student_remediation_path()) @@ -572,6 +606,7 @@ func _load_student_remediation() -> void: _student_remediation.score_changed.connect(_save_student_remediation) + func get_student_remediation_data(student_code: int) -> UserRemediation: var remediation_data_path: String = _get_student_remediation_path(0, student_code) if FileAccess.file_exists(remediation_data_path): @@ -581,6 +616,7 @@ func get_student_remediation_data(student_code: int) -> UserRemediation: Logger.trace("UserDataManager: Remediation data of student code %d not found" % student_code) return null + func set_student_remediation_gp_data(student_code: int, new_scores: Dictionary[int, int], updated_at: String) -> void: var remediation_data_path: String = _get_student_remediation_path(0, student_code) var student_remediation: UserRemediation @@ -592,6 +628,7 @@ func set_student_remediation_gp_data(student_code: int, new_scores: Dictionary[i student_remediation.set_gp_last_modified(updated_at) ResourceSaver.save(student_remediation, remediation_data_path) + func set_student_remediation_syllables_data(student_code: int, new_scores: Dictionary[int, int], updated_at: String) -> void: var remediation_data_path: String = _get_student_remediation_path(0, student_code) var student_remediation: UserRemediation @@ -603,6 +640,7 @@ func set_student_remediation_syllables_data(student_code: int, new_scores: Dicti student_remediation.set_syllables_last_modified(updated_at) ResourceSaver.save(student_remediation, remediation_data_path) + func set_student_remediation_words_data(student_code: int, new_scores: Dictionary[int, int], updated_at: String) -> void: var remediation_data_path: String = _get_student_remediation_path(0, student_code) var student_remediation: UserRemediation @@ -614,15 +652,18 @@ func set_student_remediation_words_data(student_code: int, new_scores: Dictionar student_remediation.set_words_last_modified(updated_at) ResourceSaver.save(student_remediation, remediation_data_path) + func _save_student_remediation() -> void: Logger.trace("UserDataManager: Saving student remediation in " + ProjectSettings.globalize_path(_get_student_remediation_path())) ResourceSaver.save(_student_remediation, _get_student_remediation_path()) + func get_gp_remediation_score(gp_id: int) -> int: if not _student_remediation: return 0 return _student_remediation.get_gp_score(gp_id) + func update_remediation_gp_scores(remediation_gp_scores: Dictionary) -> void: if not _student_remediation: Logger.warn("UserDataManager: No student remediation data for " + str(student)) @@ -630,6 +671,7 @@ func update_remediation_gp_scores(remediation_gp_scores: Dictionary) -> void: if remediation_gp_scores: _student_remediation.update_gp_scores(remediation_gp_scores) + func update_remediation_syllables_scores(remediation_syllables_scores: Dictionary) -> void: if not _student_remediation: Logger.warn("UserDataManager: No student remediation data for " + str(student)) @@ -637,6 +679,7 @@ func update_remediation_syllables_scores(remediation_syllables_scores: Dictionar if remediation_syllables_scores: _student_remediation.update_syllables_scores(remediation_syllables_scores) + func update_remediation_words_scores(remediation_words_scores: Dictionary) -> void: if not _student_remediation: Logger.warn("UserDataManager: No student remediation data for " + str(student)) @@ -658,6 +701,7 @@ func _get_student_confusion_matrix_path(device: int = 0, student_code: int = 0) var confusion_matrix_path: String = student_path.path_join("confusion_matrix.tres") return confusion_matrix_path + func _load_student_confusion_matrix() -> void: if FileAccess.file_exists(_get_student_confusion_matrix_path()): _student_confusion_matrix = load(_get_student_confusion_matrix_path()) @@ -669,6 +713,7 @@ func _load_student_confusion_matrix() -> void: _student_confusion_matrix.score_changed.connect(_save_student_confusion_matrix) + func get_student_confusion_matrix_data(student_code: int) -> UserConfusionMatrix: var confusion_matrix_data_path: String = _get_student_confusion_matrix_path(0, student_code) if FileAccess.file_exists(confusion_matrix_data_path): @@ -678,6 +723,7 @@ func get_student_confusion_matrix_data(student_code: int) -> UserConfusionMatrix Logger.trace("UserDataManager: Confusion matrix data of student code %d not found" % student_code) return null + func set_student_confusion_matrix_gp_data(student_code: int, new_scores: Dictionary[int, PackedInt32Array], updated_at: String) -> void: var confusion_matrix_data_path: String = _get_student_confusion_matrix_path(0, student_code) var student_confusion_matrix: UserConfusionMatrix @@ -689,15 +735,18 @@ func set_student_confusion_matrix_gp_data(student_code: int, new_scores: Diction student_confusion_matrix.set_gp_last_modified(updated_at) ResourceSaver.save(student_confusion_matrix, confusion_matrix_data_path) + func _save_student_confusion_matrix() -> void: Logger.trace("UserDataManager: Saving student confusion_matrix in " + ProjectSettings.globalize_path(_get_student_confusion_matrix_path())) ResourceSaver.save(_student_confusion_matrix, _get_student_confusion_matrix_path()) + func get_gp_confusion_matrix_score(gp_id: int) -> PackedInt32Array: if not _student_confusion_matrix: return [] return _student_confusion_matrix.get_gp_scores(gp_id) + func update_confusion_matrix_gp_scores(confusion_matrix_gp_scores: Dictionary) -> void: if not _student_confusion_matrix: Logger.warn("UserDataManager: No student confusion matrix data for " + str(student)) @@ -712,6 +761,7 @@ func update_confusion_matrix_gp_scores(confusion_matrix_gp_scores: Dictionary) - func _get_student_difficulty_path() -> String: return get_student_folder().path_join("difficulty.tres") + func _load_student_difficulty() -> void: if FileAccess.file_exists(_get_student_difficulty_path()): _student_difficulty = load(_get_student_difficulty_path()) @@ -723,16 +773,19 @@ func _load_student_difficulty() -> void: _student_difficulty.difficulty_changed.connect(_save_student_difficulty) + func _save_student_difficulty() -> void: Logger.trace("UserDataManager: Saving student difficulty in " + ProjectSettings.globalize_path(_get_student_difficulty_path())) ResourceSaver.save(_student_difficulty, _get_student_difficulty_path()) + func get_difficulty_for_minigame(minigame_name: String) -> int: if not _student_difficulty: Logger.warn("UserDataManager: No student difficulty data for " + str(student)) return 0 return _student_difficulty.get_difficulty(minigame_name) + func update_difficulty_for_minigame(minigame_name: String, minigame_won: bool) -> void: if not _student_difficulty: Logger.warn("UserDataManager: No student difficulty data for " + str(student)) @@ -746,6 +799,7 @@ func update_difficulty_for_minigame(minigame_name: String, minigame_won: bool) - func _get_student_speeches_path() -> String: return get_student_folder().path_join("speeches.tres") + func _load_student_speeches() -> void: if FileAccess.file_exists(_get_student_speeches_path()): _student_speeches = load(_get_student_speeches_path()) @@ -756,10 +810,12 @@ func _load_student_speeches() -> void: _save_student_speeches() _student_speeches.speeches_changed.connect(_save_student_speeches) + func _save_student_speeches() -> void: Logger.trace("UserDataManager: Saving student speeches in " + ProjectSettings.globalize_path(_get_student_speeches_path())) ResourceSaver.save(_student_speeches, _get_student_speeches_path()) + func mark_speech_as_played(speech: String) -> void: if not _student_speeches: if not Engine.is_editor_hint(): @@ -767,6 +823,7 @@ func mark_speech_as_played(speech: String) -> void: return _student_speeches.add_speech(speech) + func is_speech_played(speech: String) -> bool: if not _student_speeches: if not Engine.is_editor_hint(): @@ -798,18 +855,21 @@ func move_user_device_folder(old_device: String, new_device: String, student_cod return save_teacher_settings() + func find_student_dir(student_code: int) -> String: return _scan_teacher_devices(func(_device_dir: String, lang_dir: String, sub_file: String) -> String: if sub_file == str(student_code): return lang_dir.path_join(sub_file) return "") + func find_device_dir_for_student(student_code: int) -> String: return _scan_teacher_devices(func(device_dir: String, _lang_dir: String, sub_file: String) -> String: if sub_file == str(student_code): return device_dir return "") + func _scan_teacher_devices(match_callback: Callable) -> String: var teacher_path: String = "user://".path_join(_device_settings.teacher) var dir: DirAccess = DirAccess.open(teacher_path) @@ -845,6 +905,7 @@ func _scan_teacher_devices(match_callback: Callable) -> String: dir.list_dir_end() return "" + func save_all() -> void: _save_device_settings() save_teacher_settings() diff --git a/sources/utils/autoloads/user_database_synchronizer.gd b/sources/utils/autoloads/user_database_synchronizer.gd index 86d05226..3820de69 100644 --- a/sources/utils/autoloads/user_database_synchronizer.gd +++ b/sources/utils/autoloads/user_database_synchronizer.gd @@ -1,13 +1,5 @@ -extends Node class_name UserDatabaseSynchronizer - - -var synchronizing: bool = false - -var account_type_option_button: OptionButton -var education_method_option_button: OptionButton - -var loading_popup: LoadingPopup +extends Node enum UpdateNeeded { Nothing, @@ -17,6 +9,11 @@ enum UpdateNeeded { DeleteServer } +var synchronizing: bool = false +var account_type_option_button: OptionButton +var education_method_option_button: OptionButton +var loading_popup: LoadingPopup + func start_sync() -> void: synchronizing = true @@ -519,6 +516,7 @@ func validate_student_data(data: Dictionary) -> bool: Logger.trace("UserDatabaseSynchronizer: Student data is incomplete. Missing keys: %s" % str(missing)) return false + func set_loading_bar_progression(value_percent: float, wait_time: float = 0.2) -> void: if loading_popup != null: loading_popup.set_progress(value_percent) diff --git a/sources/utils/autoloads/utils.gd b/sources/utils/autoloads/utils.gd index a17eeb69..0a3e7fce 100644 --- a/sources/utils/autoloads/utils.gd +++ b/sources/utils/autoloads/utils.gd @@ -1,5 +1,6 @@ extends Node + func reorder_children_by_property(container: Node, property_name: String) -> void: var children: Array[Node] = container.get_children() children.sort_custom(Utils.sort_by_property.bind(property_name)) @@ -8,13 +9,16 @@ func reorder_children_by_property(container: Node, property_name: String) -> voi for element: Node in children: container.add_child(element) + func sort_by_property(node_a: Node, node_b: Node, property_name: String) -> bool: return node_a.get(property_name) < node_b.get(property_name) + func disconnect_all(signals: Signal) -> void: for connection: Dictionary in signals.get_connections(): (connection["signal"] as Signal).disconnect(connection["callable"] as Callable) + func clean_dir(path: String) -> Error: var dir: DirAccess = DirAccess.open(path) var error: Error = DirAccess.get_open_error() @@ -31,6 +35,7 @@ func clean_dir(path: String) -> Error: dir.remove(subfolder) return OK + func delete_directory_recursive(path: String) -> void: var err: Error = clean_dir(path) if err != OK: @@ -42,6 +47,7 @@ func delete_directory_recursive(path: String) -> void: else: Logger.info("Utils: Folder deleted: %s" % path) + ## Returns -1 if version_a is lower than version_b, 0 if they are equals, and 1 if version_a is greater than version_b func compare_versions(version_a: String, version_b: String) -> int: var va: PackedStringArray = version_a.split(".") diff --git a/sources/utils/binder/control_binder.gd b/sources/utils/binder/control_binder.gd index b1c28547..cc8d5597 100644 --- a/sources/utils/binder/control_binder.gd +++ b/sources/utils/binder/control_binder.gd @@ -1,11 +1,12 @@ @tool -extends Control class_name ControlBinder +extends Control @export var property_name: String var control: Control + func _ready() -> void: control = get_parent() diff --git a/sources/utils/binder/form_binder.gd b/sources/utils/binder/form_binder.gd index bab28029..69129161 100644 --- a/sources/utils/binder/form_binder.gd +++ b/sources/utils/binder/form_binder.gd @@ -1,11 +1,12 @@ @tool -extends Control class_name FormBinder +extends Control @export var data: Resource var _control_binder_map: Dictionary[Control, ControlBinder] = {} + func _ready() -> void: _find_binders(self) diff --git a/sources/utils/coroutine.gd b/sources/utils/coroutine.gd index 00e4481d..f64fe086 100644 --- a/sources/utils/coroutine.gd +++ b/sources/utils/coroutine.gd @@ -1,15 +1,13 @@ -extends RefCounted class_name Coroutine +extends RefCounted # For resume functionality signal resume_signal() +signal _join() + var _is_started: bool = false var is_completed: bool = false - -# For join functionality -signal _join() var _ended_count: int = -1 - var return_value: Array = [] diff --git a/sources/utils/dynamic_font_size_label.gd b/sources/utils/dynamic_font_size_label.gd index 3b21683b..e24b3089 100644 --- a/sources/utils/dynamic_font_size_label.gd +++ b/sources/utils/dynamic_font_size_label.gd @@ -1,5 +1,5 @@ -extends Label class_name DynamicFontSizeLabel +extends Label @export var autosize_on: bool = true @export var font_size_override: int = -1 @@ -10,47 +10,46 @@ class_name DynamicFontSizeLabel var _current_font_size: int var _default_font_size: int + func _ready() -> void: resized.connect(_on_resized) _initialize_default_font_size() _update_font_size() + func _initialize_default_font_size() -> void: _default_font_size = get_theme_font_size("font_size") + func _on_resized() -> void: _update_font_size() + func _update_font_size() -> void: if not autosize_on: return - if font_size_override >= 0: _current_font_size = font_size_override else: _current_font_size = _calculate_best_font_size() - add_theme_font_size_override("font_size", _current_font_size) + # Recherche binaire de la taille de police optimale func _calculate_best_font_size() -> int: var available_width: float = size.x * font_size_width_percent var available_height: float = size.y - var font: Font = get_theme_font("font") var low: int = font_size_min var high: int = font_size_max var best_size: int = low - while low <= high: var mid: int = int((low + high) / 2.0) var text_size: Vector2 = font.get_string_size(text, HORIZONTAL_ALIGNMENT_LEFT, -1, mid) - # Si le texte rentre, on essaie de l'augmenter if text_size.x <= available_width and text_size.y <= available_height: best_size = mid low = mid + 1 # On essaie une taille plus grande else: high = mid - 1 # On essaie une taille plus petite - return best_size diff --git a/sources/utils/fx/fireworks.gd b/sources/utils/fx/fireworks.gd index 7a5bad51..903e5659 100644 --- a/sources/utils/fx/fireworks.gd +++ b/sources/utils/fx/fireworks.gd @@ -1,5 +1,5 @@ -extends Node class_name Fireworks +extends Node signal finished() @@ -7,15 +7,14 @@ const ROCKET_SCENE: PackedScene = preload("res://sources/utils/fx/rocket.tscn") @export var number_of_rockets: int = 25 +var count: int = 0 + @onready var fire_delay_timer: Timer = $FireDelayTimer @onready var starts: Array[Node] = $Starts.get_children() @onready var ends: Array[Node] = $Ends.get_children() @onready var rockets: Node2D = $Rockets -var count: int = 0 - - func start() -> void: count = 0 _on_fire_delay_timer_timeout() diff --git a/sources/utils/fx/highlight.gd b/sources/utils/fx/highlight.gd index 79799b0a..b821e450 100644 --- a/sources/utils/fx/highlight.gd +++ b/sources/utils/fx/highlight.gd @@ -1,10 +1,11 @@ @tool -extends Control class_name HighlightFX +extends Control + +var is_playing: bool = false @onready var animation_player: AnimationPlayer = $AnimationPlayer -var is_playing: bool = false func play() -> void: is_playing = true diff --git a/sources/utils/fx/right.gd b/sources/utils/fx/right.gd index 07aae4a4..a05b443e 100644 --- a/sources/utils/fx/right.gd +++ b/sources/utils/fx/right.gd @@ -1,14 +1,14 @@ @tool -extends Control class_name RightFX +extends Control signal finished() +var is_playing: bool = false + @onready var animation_player: AnimationPlayer = $AnimationPlayer @onready var audio_player: AudioStreamPlayer2D = $AudioStreamPlayer2D -var is_playing: bool = false - func play() -> void: is_playing = true diff --git a/sources/utils/fx/rocket.gd b/sources/utils/fx/rocket.gd index 9f9e7433..f5add515 100644 --- a/sources/utils/fx/rocket.gd +++ b/sources/utils/fx/rocket.gd @@ -1,19 +1,5 @@ -extends Path2D class_name Rocket - -@export var spread_angle: float = PI/8.0 -@export var segments: int = 5 - -@onready var path_follow: PathFollow2D = $PathFollow2D - -@onready var traveling_timer: Timer = $TravelingTimer -@onready var explosion_timer: Timer = $ExplosionTimer - -@onready var rocket: Sprite2D = $PathFollow2D/Rocket -@onready var explosion_particles: Node2D = $PathFollow2D/ExplosionParticles - -@onready var firework_audio_player: AudioStreamPlayer2D = $FireworkAudioPlayer -@onready var blast_audio_player: AudioStreamPlayer2D = $BlastAudioPlayer +extends Path2D const FIREWORK_SOUNDS: Array[AudioStreamMP3] = [ preload("res://assets/sfx/fireworks_1.mp3"), @@ -22,7 +8,6 @@ const FIREWORK_SOUNDS: Array[AudioStreamMP3] = [ preload("res://assets/sfx/fireworks_4.mp3"), preload("res://assets/sfx/fireworks_5.mp3"), ] - const BLAST_SOUNDS: Array[AudioStreamMP3] = [ preload("res://assets/sfx/blast_1.mp3"), preload("res://assets/sfx/blast_2.mp3"), @@ -30,7 +15,6 @@ const BLAST_SOUNDS: Array[AudioStreamMP3] = [ preload("res://assets/sfx/blast_4.mp3"), preload("res://assets/sfx/blast_5.mp3"), ] - const COLORS: Array[Color] = [ Color(0.427, 0.796, 1), Color(0.976, 0.322, 0.392), @@ -41,8 +25,19 @@ const COLORS: Array[Color] = [ Color(0.216, 0.757, 0.341), ] +@export var spread_angle: float = PI/8.0 +@export var segments: int = 5 + var ind_color: int = 0 +@onready var path_follow: PathFollow2D = $PathFollow2D +@onready var traveling_timer: Timer = $TravelingTimer +@onready var explosion_timer: Timer = $ExplosionTimer +@onready var rocket: Sprite2D = $PathFollow2D/Rocket +@onready var explosion_particles: Node2D = $PathFollow2D/ExplosionParticles +@onready var firework_audio_player: AudioStreamPlayer2D = $FireworkAudioPlayer +@onready var blast_audio_player: AudioStreamPlayer2D = $BlastAudioPlayer + func _ready() -> void: ind_color = randi() % int(rocket.texture.get_size().x / rocket.region_rect.size.x) diff --git a/sources/utils/fx/sand.gd b/sources/utils/fx/sand.gd index 37644e96..afa07faa 100644 --- a/sources/utils/fx/sand.gd +++ b/sources/utils/fx/sand.gd @@ -1,6 +1,6 @@ @tool -extends Control class_name SandVFX +extends Control const TEXTURES: Array[CompressedTexture2D] = [ preload("res://assets/vfx/sand_01.png"), @@ -12,10 +12,11 @@ const TEXTURES: Array[CompressedTexture2D] = [ preload("res://assets/vfx/sand_07.png") ] +var is_playing: bool = false + @onready var particles: GPUParticles2D = $Particles @onready var timer: Timer = $Timer -var is_playing: bool = false func _ready() -> void: timer.wait_time = particles.lifetime diff --git a/sources/utils/fx/water_ring.gd b/sources/utils/fx/water_ring.gd index b4816d0e..85ef903f 100644 --- a/sources/utils/fx/water_ring.gd +++ b/sources/utils/fx/water_ring.gd @@ -1,11 +1,12 @@ -extends Control class_name WaterRingFX +extends Control @export_range(1, 10) var min_particle: int = 1 @export_range(1, 10) var max_particle: int = 4 @onready var particles: GPUParticles2D = $GPUParticles2D + func play() -> void: particles.amount = randi_range(min_particle, max_particle) particles.restart() diff --git a/sources/utils/fx/wrong.gd b/sources/utils/fx/wrong.gd index 84c01c29..bb7d91c8 100644 --- a/sources/utils/fx/wrong.gd +++ b/sources/utils/fx/wrong.gd @@ -1,13 +1,13 @@ -extends Control class_name WrongFX +extends Control signal finished() +var is_playing: bool = false + @onready var animation_player: AnimationPlayer = $AnimationPlayer @onready var audio_player: AudioStreamPlayer2D = $AudioStreamPlayer2D -var is_playing: bool = false - func play() -> void: is_playing = true diff --git a/sources/utils/keyboard_spacer.gd b/sources/utils/keyboard_spacer.gd index 34028da2..cecc2c25 100644 --- a/sources/utils/keyboard_spacer.gd +++ b/sources/utils/keyboard_spacer.gd @@ -1,9 +1,10 @@ -extends MarginContainer class_name KeyboardSpacer +extends MarginContainer var screen_scale: float var last_margin: int = -1 + func _ready() -> void: screen_scale = DisplayServer.screen_get_scale() set_process(OS.has_feature("mobile")) diff --git a/sources/utils/math/bezier.gd b/sources/utils/math/bezier.gd index 19032931..507c8035 100644 --- a/sources/utils/math/bezier.gd +++ b/sources/utils/math/bezier.gd @@ -1,5 +1,5 @@ -extends Node class_name Bezier +extends Node static func bezier_square_error(current_points: Array, ref_points: Array) -> float: diff --git a/sources/utils/minigame_resources/log.gd b/sources/utils/minigame_resources/log.gd index 7b8e4ef6..228c5718 100644 --- a/sources/utils/minigame_resources/log.gd +++ b/sources/utils/minigame_resources/log.gd @@ -1,5 +1,5 @@ -extends Resource class_name LogResource +extends Resource @export var logs: Dictionary = {} # int: Dictionary {String: Dictionary} diff --git a/sources/utils/percent_margin_container.gd b/sources/utils/percent_margin_container.gd index 2c3a5fcd..403673f5 100644 --- a/sources/utils/percent_margin_container.gd +++ b/sources/utils/percent_margin_container.gd @@ -1,6 +1,6 @@ @tool -extends Container class_name PercentMarginContainer +extends Container @export var margin_left_ratio: float = 0.0: set = set_margin_left_ratio diff --git a/sources/utils/sprite_control.gd b/sources/utils/sprite_control.gd index c1fbc232..f9cbe492 100644 --- a/sources/utils/sprite_control.gd +++ b/sources/utils/sprite_control.gd @@ -1,6 +1,6 @@ @tool -extends Control class_name SpriteControl +extends Control @export var sprites: Array[CanvasItem] = []: set = set_sprites diff --git a/sources/utils/swipe_detector.gd b/sources/utils/swipe_detector.gd index ab9a31c3..bda3f843 100644 --- a/sources/utils/swipe_detector.gd +++ b/sources/utils/swipe_detector.gd @@ -1,13 +1,14 @@ -extends Button class_name SwipeDetector +extends Button signal swipe(start_position: Vector2, end_position: Vector2) -@onready var drag_preview: TextureRect = $DragPreview - var current_preview: TextureRect var start_position: Vector2 +@onready var drag_preview: TextureRect = $DragPreview + + func _ready() -> void: set_drag_forwarding( # _get_drag_data