Nomenclatures corrections

This commit is contained in:
Adrien Ufferte
2025-09-05 15:55:48 +02:00
parent ced0fba792
commit 787d4d089c
172 changed files with 1215 additions and 944 deletions
+304 -53
View File
@@ -57,10 +57,7 @@ def split_params(param_string: str):
return params return params
EXCLUDED_DIRS = {"addons", ".git", ".github"} EXCLUDED_DIRS = {"addons", ".git", ".github"}
EXCLUDED_FILES = {os.path.normpath("script_templates/Node/default.gd")}
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_]*$")
issues = [] issues = []
MESSAGES = { MESSAGES = {
@@ -69,63 +66,317 @@ MESSAGES = {
'variable': 'is a variable name and should be in snake_case', 'variable': 'is a variable name and should be in snake_case',
'constant': 'is a constant name and should be in UPPER_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', '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): for root, dirs, files in os.walk('.', topdown=True):
rel_root = os.path.relpath(root, '.') rel_root = os.path.relpath(root, '.')
if any(rel_root == excluded or rel_root.startswith(f"{excluded}{os.sep}") for excluded in EXCLUDED_DIRS): if any(rel_root == excluded or rel_root.startswith(f"{excluded}{os.sep}") for excluded in EXCLUDED_DIRS):
dirs[:] = [] dirs[:] = []
continue continue
for fname in files: for fname in files:
if fname.endswith('.gd'): if not fname.endswith('.gd'):
path = os.path.join(root, fname) continue
try: path = os.path.join(root, fname)
with open(path, 'r', encoding='utf-8') as file: rel_path = os.path.normpath(os.path.relpath(path, '.'))
lines = file.readlines() if rel_path in EXCLUDED_FILES:
except Exception as e: continue
issues.append((path, 0, 'error', f'Could not read file: {e}')) try:
continue with open(path, 'r', encoding='utf-8') as file:
for idx, line in enumerate(lines, 1): lines = file.readlines()
stripped = line.strip() except Exception as e:
if stripped.startswith('#') or not stripped: issues.append((path, 0, 'error', f'Could not read file: {e}'))
continue continue
match_class = re.match(r"class_name\s+([A-Za-z0-9_]+)", stripped) check_naming(path, lines)
if match_class: check_content_order(path, lines)
name = match_class.group(1) check_func_spacing(path)
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 issues: if issues:
print("### \u274c GDScript Naming Convention Check Failed\n") print("### \u274c GDScript Naming Convention Check Failed\n")
@@ -8,6 +8,7 @@ const CONFIG_PATH: String = "user://environment.cfg"
var env_selector: OptionButton var env_selector: OptionButton
var current_environment: EnvType = EnvType.DEV var current_environment: EnvType = EnvType.DEV
func _enter_tree() -> void: func _enter_tree() -> void:
# Create OptionButton # Create OptionButton
env_selector = OptionButton.new() env_selector = OptionButton.new()
@@ -25,27 +26,32 @@ func _enter_tree() -> void:
# Reflect the current environment in UI # Reflect the current environment in UI
env_selector.select(current_environment) env_selector.select(current_environment)
func _exit_tree() -> void: func _exit_tree() -> void:
# Clean up the UI and save state # Clean up the UI and save state
remove_control_from_container(EditorPlugin.CONTAINER_TOOLBAR, env_selector) remove_control_from_container(EditorPlugin.CONTAINER_TOOLBAR, env_selector)
env_selector.queue_free() env_selector.queue_free()
func _on_env_selected(index: int) -> void: func _on_env_selected(index: int) -> void:
current_environment = index current_environment = index
save_environment() save_environment()
print("Environment switched to:", _environment_to_string(current_environment)) print("Environment switched to:", _environment_to_string(current_environment))
func _environment_to_string(env: EnvType) -> String: func _environment_to_string(env: EnvType) -> String:
match env: match env:
EnvType.DEV: return "DEV" EnvType.DEV: return "DEV"
EnvType.PROD: return "PROD" EnvType.PROD: return "PROD"
_: return "Unknown" _: return "Unknown"
func save_environment() -> void: func save_environment() -> void:
var config = ConfigFile.new() var config = ConfigFile.new()
config.set_value("environment", "current", str(current_environment)) config.set_value("environment", "current", str(current_environment))
config.save(CONFIG_PATH) config.save(CONFIG_PATH)
func load_environment() -> void: func load_environment() -> void:
var config = ConfigFile.new() var config = ConfigFile.new()
if config.load(CONFIG_PATH) == OK: if config.load(CONFIG_PATH) == OK:
@@ -2,6 +2,7 @@ extends PanelContainer
@onready var form_validator_control: FormValidator = $MarginContainer/FormValidator @onready var form_validator_control: FormValidator = $MarginContainer/FormValidator
func _on_form_validator_control_control_validated(control, passed, messages) -> void: func _on_form_validator_control_control_validated(control, passed, messages) -> void:
var error_label = _get_error_label(control) var error_label = _get_error_label(control)
var valid_label = _get_valid_label(control) var valid_label = _get_valid_label(control)
@@ -1,6 +1,6 @@
@tool @tool
extends ValidatorRule
class_name AlphanumericRule class_name AlphanumericRule
extends ValidatorRule
func _init() -> void: func _init() -> void:
@@ -1,6 +1,6 @@
@tool @tool
extends ValidatorRule
class_name BooleanRule class_name BooleanRule
extends ValidatorRule
@export var target_value: bool @export var target_value: bool
@@ -1,6 +1,6 @@
@tool @tool
extends ValidatorRule
class_name DoesNotMatchRule class_name DoesNotMatchRule
extends ValidatorRule
@export var pattern: String @export var pattern: String
@@ -1,6 +1,6 @@
@tool @tool
extends ValidatorRule
class_name EqualsRule class_name EqualsRule
extends ValidatorRule
@export var target_value: String @export var target_value: String
@@ -1,6 +1,6 @@
@tool @tool
extends ValidatorRule
class_name NotBlankRule class_name NotBlankRule
extends ValidatorRule
func _init() -> void: func _init() -> void:
@@ -1,5 +1,5 @@
extends RefCounted
class_name RuleResult class_name RuleResult
extends RefCounted
var passed: bool = false var passed: bool = false
var message: String = "" var message: String = ""
@@ -1,6 +1,6 @@
@tool @tool
extends Resource
class_name ValidatorRule class_name ValidatorRule
extends Resource
@export var fail_message: String = "" @export var fail_message: String = ""
+1 -1
View File
@@ -1,5 +1,5 @@
extends ZIPReader
class_name FolderUnzipper class_name FolderUnzipper
extends ZIPReader
signal file_count(count: int) signal file_count(count: int)
signal file_copied(count: int, name: String) signal file_copied(count: int, name: String)
+1 -1
View File
@@ -1,5 +1,5 @@
extends ZIPPacker
class_name FolderZipper class_name FolderZipper
extends ZIPPacker
func write_folder_recursive(abs_path: String, rel_path: String) -> Error: func write_folder_recursive(abs_path: String, rel_path: String) -> Error:
+1 -1
View File
@@ -1,4 +1,4 @@
extends Resource
class_name ProfToolSave class_name ProfToolSave
extends Resource
@export var selected_language: String = "" @export var selected_language: String = ""
+1 -6
View File
@@ -1,7 +1,6 @@
@tool @tool
extends Resource
class_name DeviceSettings class_name DeviceSettings
extends Resource
const SUPPORTED_LOCALES: Array[String] = [ const SUPPORTED_LOCALES: Array[String] = [
# French France # French France
@@ -26,25 +25,21 @@ const SUPPORTED_LOCALES: Array[String] = [
@export var device_id: int @export var device_id: int
@export var language_versions: Dictionary = {} # locale: datetime @export var language_versions: Dictionary = {} # locale: datetime
@export var game_version: String = "0.0.1" @export var game_version: String = "0.0.1"
@export var master_volume: float = 0.0: @export var master_volume: float = 0.0:
set(volume): set(volume):
master_volume = volume master_volume = volume
var ind: int = AudioServer.get_bus_index("Master") var ind: int = AudioServer.get_bus_index("Master")
AudioServer.set_bus_volume_db(ind, volume) AudioServer.set_bus_volume_db(ind, volume)
@export var music_volume: float = 0.0: @export var music_volume: float = 0.0:
set(volume): set(volume):
music_volume = volume music_volume = volume
var ind: int = AudioServer.get_bus_index("Music") var ind: int = AudioServer.get_bus_index("Music")
AudioServer.set_bus_volume_db(ind, volume) AudioServer.set_bus_volume_db(ind, volume)
@export var voice_volume: float = 0.0: @export var voice_volume: float = 0.0:
set(volume): set(volume):
voice_volume = volume voice_volume = volume
var ind: int = AudioServer.get_bus_index("Voice") var ind: int = AudioServer.get_bus_index("Voice")
AudioServer.set_bus_volume_db(ind, volume) AudioServer.set_bus_volume_db(ind, volume)
@export var effects_volume: float = 0.0: @export var effects_volume: float = 0.0:
set(volume): set(volume):
effects_volume = volume effects_volume = volume
+15 -17
View File
@@ -1,15 +1,28 @@
@tool @tool
extends Control
class_name Garden 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 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" const BACKGROUND_PATH_MODEL: String = "res://assets/gardens/gardens/garden_%02d_open.png"
@export var garden_layout: GardenLayout: @export var garden_layout: GardenLayout:
set = set_garden_layout set = set_garden_layout
@export var garden_colors: Array[Color] = [] @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 buttons: Control = $Buttons
@onready var flower_controls: Array[TextureRect] = [ @onready var flower_controls: Array[TextureRect] = [
%Flower1, %Flower1,
@@ -26,21 +39,6 @@ const BACKGROUND_PATH_MODEL: String = "res://assets/gardens/gardens/garden_%02d_
%Button4, %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: func get_button_size() -> Vector2:
return lesson_button_controls[0].get_size() return lesson_button_controls[0].get_size()
+51 -46
View File
@@ -1,46 +1,6 @@
@tool @tool
extends Resource
class_name GardenLayout class_name GardenLayout
extends Resource
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
}
enum FirstOrLast { enum FirstOrLast {
First, First,
@@ -48,18 +8,18 @@ enum FirstOrLast {
Last Last
} }
@export var color: int = 0 @export var color: int = 0
var flowers: Array[Flower] = []:
set = set_flowers
@export var flowers_export: Array[Dictionary] = []: @export var flowers_export: Array[Dictionary] = []:
set = set_flowers_export set = set_flowers_export
var lesson_buttons: Array[GardenLayoutLessonButton] = []:
set = set_lesson_buttons
@export var lesson_buttons_export: Array[Dictionary] = []: @export var lesson_buttons_export: Array[Dictionary] = []:
set = set_lesson_buttons_export set = set_lesson_buttons_export
@export var is_first_or_last: FirstOrLast = FirstOrLast.Neither @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: func set_flowers_export(p_flowers_export: Array[Dictionary]) -> void:
flowers_export = p_flowers_export flowers_export = p_flowers_export
@@ -87,3 +47,48 @@ func set_lesson_buttons(p_lesson_buttons: Array[GardenLayoutLessonButton]) -> vo
lesson_buttons_export.clear() lesson_buttons_export.clear()
for lesson_button: GardenLayoutLessonButton in lesson_buttons: for lesson_button: GardenLayoutLessonButton in lesson_buttons:
lesson_buttons_export.append(lesson_button.to_dict()) 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
}
+1 -2
View File
@@ -1,6 +1,5 @@
@tool @tool
extends Resource
class_name GardensLayout class_name GardensLayout
extends Resource
@export var gardens: Array[GardenLayout] = [] @export var gardens: Array[GardenLayout] = []
+2 -2
View File
@@ -1,6 +1,5 @@
extends Resource
class_name StudentData class_name StudentData
extends Resource
enum Level { enum Level {
Beginner, Beginner,
@@ -14,6 +13,7 @@ enum Level {
@export var age: int = 0 @export var age: int = 0
@export var last_modified: String = "" @export var last_modified: String = ""
func to_dict() -> Dictionary: func to_dict() -> Dictionary:
return { return {
"code": code, "code": code,
+3 -1
View File
@@ -1,5 +1,5 @@
extends Resource
class_name StudentProgression class_name StudentProgression
extends Resource
signal unlocks_changed() signal unlocks_changed()
@@ -17,6 +17,7 @@ enum Status{
func _init() -> void: func _init() -> void:
init_unlocks() init_unlocks()
# Make sure the unlocks are correct # Make sure the unlocks are correct
func init_unlocks() -> void: func init_unlocks() -> void:
if not unlocks: if not unlocks:
@@ -73,6 +74,7 @@ func look_and_learn_completed(lesson_number: int) -> bool:
unlocks_changed.emit() unlocks_changed.emit()
return true return true
# Return true if the progression is saved or false if the game was already completed # 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: func game_completed(lesson_number: int, game_number: int) -> bool:
# If the game is already completed, do nothing # If the game is already completed, do nothing
+14 -7
View File
@@ -1,28 +1,28 @@
extends Resource
class_name TeacherSettings class_name TeacherSettings
extends Resource
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]
enum AccountType { enum AccountType {
Teacher, Teacher,
Parent Parent
} }
enum EducationMethod { enum EducationMethod {
AppOnly, AppOnly,
Complete 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 account_type: AccountType
@export var education_method: EducationMethod @export var education_method: EducationMethod
var devices_count: int
@export var students: Dictionary[int, Array] = {} # int (device): Array[StudentData] @export var students: Dictionary[int, Array] = {} # int (device): Array[StudentData]
@export var email: String @export var email: String
var password: String
@export var token: String @export var token: String
@export var last_modified: String = "" @export var last_modified: String = ""
var devices_count: int
var password: String
func update_from_dict(dict: Dictionary) -> void: func update_from_dict(dict: Dictionary) -> void:
if dict.has("account_type"): if dict.has("account_type"):
account_type = dict.account_type account_type = dict.account_type
@@ -104,6 +104,7 @@ func get_new_code() -> int:
var code: int = codes.pick_random() var code: int = codes.pick_random()
return code return code
func to_dict() -> Dictionary: func to_dict() -> Dictionary:
var dict: Dictionary = { var dict: Dictionary = {
"account_type": account_type, "account_type": account_type,
@@ -122,6 +123,7 @@ func to_dict() -> Dictionary:
return dict return dict
func get_number_of_students() -> int: func get_number_of_students() -> int:
if not students: if not students:
return 0 return 0
@@ -130,12 +132,14 @@ func get_number_of_students() -> int:
result += data.size() result += data.size()
return result return result
func get_all_students_data() -> Array[StudentData]: func get_all_students_data() -> Array[StudentData]:
var result: Array[StudentData] = [] var result: Array[StudentData] = []
for data: Array[StudentData] in students.values(): for data: Array[StudentData] in students.values():
result.append_array(data) result.append_array(data)
return result return result
func delete_student(student_code: int) -> void: func delete_student(student_code: int) -> void:
for device: int in students.keys(): for device: int in students.keys():
for index: int in range(students[device].size()): for index: int in range(students[device].size()):
@@ -146,12 +150,14 @@ func delete_student(student_code: int) -> void:
return return
Logger.warn("TeacherSettings: Trying to delete student, but code %d not found" % student_code) Logger.warn("TeacherSettings: Trying to delete student, but code %d not found" % student_code)
func get_student_with_code(student_code: int) -> StudentData: func get_student_with_code(student_code: int) -> StudentData:
for student_data: StudentData in get_all_students_data(): for student_data: StudentData in get_all_students_data():
if student_data.code == student_code: if student_data.code == student_code:
return student_data return student_data
return null return null
func get_student_device(student_code: int) -> int: func get_student_device(student_code: int) -> int:
for device: int in students.keys(): for device: int in students.keys():
for index: int in range(students[device].size()): for index: int in range(students[device].size()):
@@ -159,6 +165,7 @@ func get_student_device(student_code: int) -> int:
return device return device
return -1 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: 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) update_student_device(student_code, new_device_id)
for student_data: StudentData in students[new_device_id]: for student_data: StudentData in students[new_device_id]:
+5 -4
View File
@@ -39,11 +39,9 @@ func append_and_trim(target: Dictionary[int, PackedInt32Array], expected_id: int
# Key is the ID of the expected answer # Key is the ID of the expected answer
# Value is a PackedInt32Array whose entries are the IDs of the answers # Value is a PackedInt32Array whose entries are the IDs of the answers
@export @export var gp_scores: Dictionary[int, PackedInt32Array] = {}
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 # Gets (a copy of) the data of a GP
func get_gp_scores(id: int) -> PackedInt32Array: 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(gp_scores[id])
return PackedInt32Array() return PackedInt32Array()
# Updates the confusion matrix from a minigame scores # Updates the confusion matrix from a minigame scores
func update_gp_scores(minigame_scores: Dictionary[int, PackedInt32Array]) -> void: func update_gp_scores(minigame_scores: Dictionary[int, PackedInt32Array]) -> void:
if not minigame_scores or minigame_scores.is_empty(): 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)) set_gp_last_modified(Time.get_datetime_string_from_system(true))
score_changed.emit() score_changed.emit()
func set_gp_scores(new_scores: Dictionary[int, PackedInt32Array]) -> void: func set_gp_scores(new_scores: Dictionary[int, PackedInt32Array]) -> void:
var cleaned: Dictionary[int, PackedInt32Array] = {} var cleaned: Dictionary[int, PackedInt32Array] = {}
for expected_id: int in new_scores.keys(): 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 gp_scores = cleaned
set_gp_last_modified(Time.get_datetime_string_from_system(true)) set_gp_last_modified(Time.get_datetime_string_from_system(true))
func set_gp_last_modified(new_date: String) -> void: func set_gp_last_modified(new_date: String) -> void:
gp_last_modified = new_date gp_last_modified = new_date
+2 -3
View File
@@ -1,13 +1,12 @@
extends Resource
class_name UserDifficulty class_name UserDifficulty
extends Resource
signal difficulty_changed() signal difficulty_changed()
# Stores the user history for all the minigames # Stores the user history for all the minigames
# Key -> minigame_name: String # Key -> minigame_name: String
# Value -> UserMinigameHistory # Value -> UserMinigameHistory
@export @export var minigames_histories: Dictionary = {}
var minigames_histories: Dictionary = {}
# Gets the difficulty of the user for the given minigame # Gets the difficulty of the user for the given minigame
+6 -9
View File
@@ -1,19 +1,16 @@
extends Resource
class_name UserMinigameHistory class_name UserMinigameHistory
extends Resource
const MIN_DIFFICULTY: int = 0 const MIN_DIFFICULTY: int = 0
const MAX_DIFFICULTY: int = 4 const MAX_DIFFICULTY: int = 4
const CONSECUTIVE_WINS_TO_PROMOTE: int = 2 const CONSECUTIVE_WINS_TO_PROMOTE: int = 2
const CONSECUTIVE_LOSSES_TO_DEMOTE: int = 2 const CONSECUTIVE_LOSSES_TO_DEMOTE: int = 2
@export @export var difficulty: int = 0
var difficulty: int = 0 @export var consecutives_losses: int = 0
@export @export var consecutives_wins: int = 0
var consecutives_losses: int = 0 @export var history: Array[bool] = []
@export
var consecutives_wins: int = 0
@export
var history: Array[bool] = []
func add_game(is_won: bool) -> void: func add_game(is_won: bool) -> void:
history.append(is_won) history.append(is_won)
+15 -13
View File
@@ -1,6 +1,5 @@
class_name UserRemediation class_name UserRemediation
extends Resource extends Resource
## A remediation score indicates how much extra practice an item needs. ## A remediation score indicates how much extra practice an item needs.
## It is a cumulative value that becomes more negative when the student struggles ## 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 ## 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 # Key is the ID of the GP
# Value is the score of the GP # Value is the score of the GP
@export @export var gps_scores: Dictionary[int, int] = {}
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 # Gets the score of a GP if it is below or equals to the remediation score
func get_gp_score(id: int) -> int: 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 gps_scores[id] if gps_scores[id] <= REMEDIATION_SCORE else 0
return 0 return 0
# Updates the gp scores from a minigame scores # Updates the gp scores from a minigame scores
func update_gp_scores(minigame_scores: Dictionary) -> void: func update_gp_scores(minigame_scores: Dictionary) -> void:
if not minigame_scores: 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)) set_gp_last_modified(Time.get_datetime_string_from_system(true))
score_changed.emit() score_changed.emit()
func set_gp_scores(new_scores: Dictionary[int, int]) -> void: func set_gp_scores(new_scores: Dictionary[int, int]) -> void:
gps_scores = new_scores gps_scores = new_scores
func set_gp_last_modified(new_date: String) -> void: func set_gp_last_modified(new_date: String) -> void:
gp_last_modified = new_date 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 # Key is the ID of the syllable
# Value is the score of the syllable # Value is the score of the syllable
@export @export var syllables_scores: Dictionary[int, int] = {}
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 # Gets the score of a syllable if it is below or equals to the remediation score
func get_syllable_score(id: int) -> int: 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 syllables_scores[id] if syllables_scores[id] <= REMEDIATION_SCORE else 0
return 0 return 0
# Updates the syllables scores from a minigame scores # Updates the syllables scores from a minigame scores
func update_syllables_scores(minigame_scores: Dictionary) -> void: func update_syllables_scores(minigame_scores: Dictionary) -> void:
if not minigame_scores: 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)) set_syllables_last_modified(Time.get_datetime_string_from_system(true))
score_changed.emit() score_changed.emit()
func set_syllables_scores(new_scores: Dictionary[int, int]) -> void: func set_syllables_scores(new_scores: Dictionary[int, int]) -> void:
syllables_scores = new_scores syllables_scores = new_scores
func set_syllables_last_modified(new_date: String) -> void: func set_syllables_last_modified(new_date: String) -> void:
syllables_last_modified = new_date 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 # Key is the ID of the word
# Value is the score of the word # Value is the score of the word
@export @export var words_scores: Dictionary[int, int] = {}
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 # Gets the score of a word if it is below or equals to the remediation score
func get_word_score(id: int) -> int: 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 words_scores[id] if words_scores[id] <= REMEDIATION_SCORE else 0
return 0 return 0
# Updates the words scores from a minigame scores # Updates the words scores from a minigame scores
func update_words_scores(minigame_scores: Dictionary) -> void: func update_words_scores(minigame_scores: Dictionary) -> void:
if not minigame_scores: 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)) set_words_last_modified(Time.get_datetime_string_from_system(true))
score_changed.emit() score_changed.emit()
func set_words_scores(new_scores: Dictionary[int, int]) -> void: func set_words_scores(new_scores: Dictionary[int, int]) -> void:
words_scores = new_scores words_scores = new_scores
func set_words_last_modified(new_date: String) -> void: func set_words_last_modified(new_date: String) -> void:
words_last_modified = new_date words_last_modified = new_date
+4 -2
View File
@@ -1,15 +1,17 @@
extends Resource
class_name UserSpeeches class_name UserSpeeches
extends Resource
signal speeches_changed signal speeches_changed()
# Contains the list of speeches already played # Contains the list of speeches already played
@export var speeches_played: Array[String] = [] @export var speeches_played: Array[String] = []
func add_speech(speech: String) -> void: func add_speech(speech: String) -> void:
if not speeches_played.has(speech): if not speeches_played.has(speech):
speeches_played.append(speech) speeches_played.append(speech)
speeches_changed.emit() speeches_changed.emit()
func is_speech_played(speech: String) -> bool: func is_speech_played(speech: String) -> bool:
return speeches_played.has(speech) return speeches_played.has(speech)
+14
View File
@@ -22,13 +22,20 @@ extends _BASE_
## and any further detail. ## and any further detail.
#05. signals #05. signals
#06. enums #06. enums
#07. constants #07. constants
#08. static variables #08. static variables
#09. @export variables #09. @export variables
#10. remaning regular variables #10. remaning regular variables
#11. @onready variables #11. @onready variables
#12. static_init #12. static_init
# Called automatically when the class is loaded, after the static variables have been initialized # Called automatically when the class is loaded, after the static variables have been initialized
static func _static_init(): static func _static_init():
@@ -38,6 +45,8 @@ static func _static_init():
#13. remaining static methods #13. remaining static methods
#14-1. overridden built-in virtual methods: #14-1. overridden built-in virtual methods:
# Called upon creating the object in memory. # Called upon creating the object in memory.
func _init(): func _init():
@@ -66,6 +75,11 @@ func _physics_process(float) -> void:
#14-2. remaining virtual methods #14-2. remaining virtual methods
#15. overridden custom methods #15. overridden custom methods
#16. remaining methods #16. remaining methods
#17. subclasses #17. subclasses
+2 -2
View File
@@ -1,5 +1,5 @@
extends Control
class_name FlowerVFX class_name FlowerVFX
extends Control
@export var sounds: Array[AudioStream] = [] @export var sounds: Array[AudioStream] = []
@@ -8,9 +8,9 @@ class_name FlowerVFX
$Particles2, $Particles2,
$Particles3 $Particles3
] ]
@onready var audio_stream_player: AudioStreamPlayer2D = $AudioStreamPlayer2D @onready var audio_stream_player: AudioStreamPlayer2D = $AudioStreamPlayer2D
func play() -> void: func play() -> void:
audio_stream_player.stream = sounds.pick_random() audio_stream_player.stream = sounds.pick_random()
audio_stream_player.play() audio_stream_player.play()
+15 -23
View File
@@ -1,30 +1,39 @@
extends Control
class_name Gardens class_name Gardens
extends Control
signal minigame_layout_opened() signal minigame_layout_opened()
# Namespace
const KALULU := preload("res://sources/minigames/base/kalulu.gd") const KALULU := preload("res://sources/minigames/base/kalulu.gd")
const GARDEN_SCENE: PackedScene = preload("res://resources/gardens/garden.tscn") 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 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 FLOWER_FVX: PackedScene = preload("res://sources/gardens/flower_particle.tscn")
const GARDEN_SIZE: int = 2400 const GARDEN_SIZE: int = 2400
static var transition_data: Dictionary = {}
@export_category("Layout") @export_category("Layout")
@export var gardens_layout: GardensLayout: @export var gardens_layout: GardensLayout:
set = set_gardens_layout set = set_gardens_layout
@export var starting_garden: int = -1 @export var starting_garden: int = -1
@export_category("Colors") @export_category("Colors")
@export var unlocked_color: Color = Color("1c2662") #blue @export var unlocked_color: Color = Color("1c2662") #blue
@export var locked_color: Color = Color("1d2229") #black @export var locked_color: Color = Color("1d2229") #black
@export_group("Minigames") @export_group("Minigames")
@export var minigames_scenes: Array[PackedScene] = [] @export var minigames_scenes: Array[PackedScene] = []
@export var minigames_icons: Array[Texture] = [] @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 garden_parent: HBoxContainer = %GardenParent
@onready var locked_line: Line2D = $ScrollContainer/LockedLine @onready var locked_line: Line2D = $ScrollContainer/LockedLine
@onready var unlocked_line: Line2D = $ScrollContainer/UnlockedLine @onready var unlocked_line: Line2D = $ScrollContainer/UnlockedLine
@@ -48,26 +57,10 @@ const GARDEN_SIZE: int = 2400
@onready var lock: Control = %Lock @onready var lock: Control = %Lock
@onready var kalulu: KALULU = %Kalulu @onready var kalulu: KALULU = %Kalulu
@onready var kalulu_button: CanvasItem = %KaluluButton @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 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_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")) @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: func _ready() -> void:
@@ -382,7 +375,6 @@ func _ready() -> void:
await kalulu.play_kalulu_speech(intro_speech) await kalulu.play_kalulu_speech(intro_speech)
kalulu_button.show() kalulu_button.show()
UserDataManager.mark_speech_as_played("gardens") UserDataManager.mark_speech_as_played("gardens")
static func compute_lessons_distribution(total_lessons: int, garden_layouts: Array[GardenLayout]) -> Array[int]: static func compute_lessons_distribution(total_lessons: int, garden_layouts: Array[GardenLayout]) -> Array[int]:
-1
View File
@@ -5,7 +5,6 @@ const GARDEN_TEXTURES_NB: int = 20
const FLOWER_TYPES_NB: int = 5 const FLOWER_TYPES_NB: int = 5
const GARDENS_LAYOUT_RESOURCE_PATH: String = "res://resources/gardens/gardens_layout.tres" const GARDENS_LAYOUT_RESOURCE_PATH: String = "res://resources/gardens/gardens_layout.tres"
var dragging_element: Variant var dragging_element: Variant
var drag_data: Dictionary = {} var drag_data: Dictionary = {}
+5 -2
View File
@@ -1,20 +1,23 @@
extends TextureRect
class_name MinigameLayout class_name MinigameLayout
extends TextureRect
signal pressed() signal pressed()
var is_disabled: bool = false
@onready var icon: TextureRect = $TextureRect @onready var icon: TextureRect = $TextureRect
@onready var area: Area2D = $Area2D @onready var area: Area2D = $Area2D
@onready var right_fx: RightFX = $TextureRect/RightFX @onready var right_fx: RightFX = $TextureRect/RightFX
var is_disabled: bool = false
func _ready() -> void: func _ready() -> void:
area.connect("input_event", _on_click) area.connect("input_event", _on_click)
func _on_click(_viewport: Node, event: InputEvent, _shape_idx: int) -> void: func _on_click(_viewport: Node, event: InputEvent, _shape_idx: int) -> void:
if event.is_action_pressed("left_click") and not is_disabled: if event.is_action_pressed("left_click") and not is_disabled:
pressed.emit() pressed.emit()
func right() -> void: func right() -> void:
right_fx.play() right_fx.play()
+1 -2
View File
@@ -1,12 +1,11 @@
extends AnimatedSprite2D extends AnimatedSprite2D
func _on_animation_finished() -> void: func _on_animation_finished() -> void:
if animation in ["Hide", "Show"]: if animation in ["Hide", "Show"]:
return return
var rand: float = randf() var rand: float = randf()
match animation: match animation:
"Idle1", "Idle2": "Idle1", "Idle2":
if rand < 0.5: if rand < 0.5:
+2 -2
View File
@@ -2,10 +2,10 @@ extends Control
const ELEMENT_SCENE: PackedScene = preload("res://sources/language_tool/fish_word_list_element.tscn") const ELEMENT_SCENE: PackedScene = preload("res://sources/language_tool/fish_word_list_element.tscn")
@onready var elements_container: VBoxContainer = %ElementsContainer
var word_list: Array = [] var word_list: Array = []
@onready var elements_container: VBoxContainer = %ElementsContainer
func _ready() -> void: func _ready() -> void:
var query: String = "SELECT name FROM sqlite_master WHERE type='table' AND name='Pseudowords'" var query: String = "SELECT name FROM sqlite_master WHERE type='table' AND name='Pseudowords'"
@@ -1,6 +1,5 @@
extends MarginContainer
class_name FishWordListElement class_name FishWordListElement
extends MarginContainer
@export var word_id: int = 1: @export var word_id: int = 1:
set = set_word_id set = set_word_id
@@ -10,13 +9,13 @@ class_name FishWordListElement
set = set_lesson_nb set = set_lesson_nb
@export var pseudoword_id: int = -1 @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 option_button: OptionButton = %OptionButton
@onready var line_edit: LineEdit = %LineEdit @onready var line_edit: LineEdit = %LineEdit
@onready var lesson_label: Label = %LessonLabel @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: func set_word_id(p_word_id: int) -> void:
word_id = p_word_id word_id = p_word_id
+1 -2
View File
@@ -1,8 +1,7 @@
extends Node extends Node
## Global data for prof_tool only
# For prof_tool only
var main_menu_selected_tab: int = 0 var main_menu_selected_tab: int = 0
var device_colors: Array[Color] = [ var device_colors: Array[Color] = [
Color("9670e0"), Color("9670e0"),
Color("ffe823"), Color("ffe823"),
@@ -1,10 +1,10 @@
extends Control
class_name GPImageAndSoundDescriptions class_name GPImageAndSoundDescriptions
extends Control
@onready var description_container: VBoxContainer = %DescriptionsContainer
const DESCRIPTION_LINE_SCENE: PackedScene = preload("res://sources/language_tool/image_and_sound_gp_description.tscn") 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: func _ready() -> void:
DirAccess.make_dir_recursive_absolute(Database.BASE_PATH + Database.language + Database.LOOK_AND_LEARN_IMAGES) DirAccess.make_dir_recursive_absolute(Database.BASE_PATH + Database.language + Database.LOOK_AND_LEARN_IMAGES)
+1 -3
View File
@@ -1,12 +1,11 @@
extends Control extends Control
var undo_redo: UndoRedo = UndoRedo.new()
var element_scene: PackedScene = preload("res://sources/language_tool/gp_list_element.tscn") var element_scene: PackedScene = preload("res://sources/language_tool/gp_list_element.tscn")
@onready var elements_container: VBoxContainer = %ElementsContainer @onready var elements_container: VBoxContainer = %ElementsContainer
@onready var error_label: Label = %ErrorLabel @onready var error_label: Label = %ErrorLabel
var undo_redo: UndoRedo = UndoRedo.new()
func _ready() -> void: func _ready() -> void:
var query: String = "Select * FROM GPs ORDER BY GPs.Grapheme" 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") get_tree().change_scene_to_file("res://sources/language_tool/prof_tool_menu.tscn")
func _on_grapheme_gui_input(event: InputEvent) -> void: func _on_grapheme_gui_input(event: InputEvent) -> void:
if event.is_action_pressed("left_click"): if event.is_action_pressed("left_click"):
_reorder_by("grapheme") _reorder_by("grapheme")
+1 -1
View File
@@ -1,5 +1,5 @@
extends OptionButton
class_name GPListButton class_name GPListButton
extends OptionButton
signal gp_selected(id: int) signal gp_selected(id: int)
signal new_selected() signal new_selected()
+12 -13
View File
@@ -1,5 +1,5 @@
extends MarginContainer
class_name GPListElement class_name GPListElement
extends MarginContainer
signal delete_pressed() signal delete_pressed()
signal validated() signal validated()
@@ -10,18 +10,6 @@ enum Type {
Consonant, 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 = "": var grapheme: String = "":
set = set_grapheme set = set_grapheme
var phoneme: String = "": var phoneme: String = "":
@@ -37,6 +25,16 @@ var undo_redo: UndoRedo:
undo_redo = UndoRedo.new() undo_redo = UndoRedo.new()
return undo_redo 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: func set_grapheme(p_grapheme: String) -> void:
grapheme = p_grapheme grapheme = p_grapheme
@@ -61,6 +59,7 @@ func set_type(p_type: Type) -> void:
if type_edit: if type_edit:
type_edit.selected = type type_edit.selected = type
func set_exception(p_exception: bool) -> void: func set_exception(p_exception: bool) -> void:
exception = p_exception exception = p_exception
if exception_checkbox: if exception_checkbox:
+2 -4
View File
@@ -4,14 +4,12 @@ signal gp_selected(grapheme_ind: int, gp_id: int, text: String)
signal focus_changed(has_focus: bool) signal focus_changed(has_focus: bool)
signal new_gp_asked() signal new_gp_asked()
@onready var container: VBoxContainer = $VBoxContainer
@onready var button: Button = $Button
var grapheme_ind: int = -1 var grapheme_ind: int = -1
var ind_selected: int = -1: var ind_selected: int = -1:
set = set_ind_selected set = set_ind_selected
@onready var container: VBoxContainer = $VBoxContainer
@onready var button: Button = $Button
func _ready() -> void: func _ready() -> void:
@@ -1,9 +1,9 @@
extends Control extends Control
@onready var description_container: VBoxContainer = %DescriptionsContainer
const DESCRIPTION_LINE_SCENE: PackedScene = preload("res://sources/language_tool/video_gp_description.tscn") const DESCRIPTION_LINE_SCENE: PackedScene = preload("res://sources/language_tool/video_gp_description.tscn")
@onready var description_container: VBoxContainer = %DescriptionsContainer
func _ready() -> void: func _ready() -> void:
var _description_line: VideoGPDescription = DESCRIPTION_LINE_SCENE.instantiate() var _description_line: VideoGPDescription = DESCRIPTION_LINE_SCENE.instantiate()
@@ -1,7 +1,11 @@
extends HBoxContainer
class_name ImageAndSoundGPDescription 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 gp_menu_button: MenuButton = %GPMenuButton
@onready var image_preview: TextureRect = %ImagePreview @onready var image_preview: TextureRect = %ImagePreview
@@ -13,10 +17,6 @@ signal delete
@onready var image_clear_button: MarginContainer = %ImageClearButton @onready var image_clear_button: MarginContainer = %ImageClearButton
@onready var sound_clear_button: MarginContainer = %SoundClearButton @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: func _image_file_selected(file_path: String) -> void:
file_dialog.files_selected.connect(_image_file_selected.bind(file_dialog)) 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: func _on_button_pressed() -> void:
delete.emit() deleted.emit()
func _on_sound_preview_pressed() -> void: func _on_sound_preview_pressed() -> void:
-1
View File
@@ -1,6 +1,5 @@
extends GPImageAndSoundDescriptions extends GPImageAndSoundDescriptions
func _ready() -> void: func _ready() -> void:
DirAccess.make_dir_recursive_absolute(Database.BASE_PATH + Database.language + Database.LANGUAGE_SOUNDS) DirAccess.make_dir_recursive_absolute(Database.BASE_PATH + Database.language + Database.LANGUAGE_SOUNDS)
+1 -1
View File
@@ -1,5 +1,5 @@
extends PanelContainer
class_name KaluluSpeech class_name KaluluSpeech
extends PanelContainer
@export var speech_category: String @export var speech_category: String
@export var speech_name: String: @export var speech_name: String:
+1 -2
View File
@@ -1,6 +1,5 @@
extends PanelContainer
class_name KaluluTitle class_name KaluluTitle
extends PanelContainer
@export var title: String = "": @export var title: String = "":
set = _set_title set = _set_title
-1
View File
@@ -1,6 +1,5 @@
extends Control extends Control
const TITLE_SCENE: PackedScene = preload("res://sources/language_tool/kalulu_speech_title.tscn") 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") const SPEECH_SCENE: PackedScene = preload("res://sources/language_tool/kalulu_speech.tscn")
+2 -4
View File
@@ -1,14 +1,12 @@
extends MarginContainer
class_name LessonContainer class_name LessonContainer
extends MarginContainer
var gp_label_scene: PackedScene = preload("res://sources/language_tool/lesson_gp_label.tscn")
signal lesson_dropped(before: bool, number: int, dropped_number: int) 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: var number: int = 0:
set = set_number set = set_number
@onready var gp_container: HBoxContainer = $%GPContainer @onready var gp_container: HBoxContainer = $%GPContainer
@onready var number_label: Label = $%NumberLabel @onready var number_label: Label = $%NumberLabel
@@ -1,9 +1,11 @@
extends PanelContainer
class_name LessonExerciseContainer class_name LessonExerciseContainer
extends PanelContainer
@export var lesson_number: int = -1: @export var lesson_number: int = -1:
set = _set_lesson_number set = _set_lesson_number
var sentences_by_lesson: Dictionary = {}
@onready var lesson_id_label: Label = %LessonIDLabel @onready var lesson_id_label: Label = %LessonIDLabel
@onready var lesson_gps: HBoxContainer = %LessonGPs @onready var lesson_gps: HBoxContainer = %LessonGPs
@onready var exercise_buttons: Array[OptionButton] = [%ExerciseButton1, %ExerciseButton2, %ExerciseButton3] @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_words: Label = %NumberOfWords
@onready var number_of_sentences: Label = %NumberOfSentences @onready var number_of_sentences: Label = %NumberOfSentences
var sentences_by_lesson: Dictionary = {}
func _ready() -> void: func _ready() -> void:
Database.db.query("Select * FROM ExerciseTypes") Database.db.query("Select * FROM ExerciseTypes")
+1 -1
View File
@@ -1,5 +1,5 @@
extends Label
class_name LessonGPLabel class_name LessonGPLabel
extends Label
signal gp_dropped(before: bool, data: Dictionary) signal gp_dropped(before: bool, data: Dictionary)
+3 -4
View File
@@ -1,13 +1,12 @@
extends Control 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 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 gp_label_scene: PackedScene = preload("res://sources/language_tool/lesson_gp_label.tscn")
var lessons: Dictionary[int, LessonContainer] = {} var lessons: Dictionary[int, LessonContainer] = {}
@onready var lessons_container: VBoxContainer = $%LessonsContainer
@onready var unused_gp_container: GridContainer = $%UnusedGPContainer
func _ready() -> void: func _ready() -> void:
Database.db.query("Select Grapheme, Phoneme, LessonNb, GPID FROM Lessons Database.db.query("Select Grapheme, Phoneme, LessonNb, GPID FROM Lessons
+3 -2
View File
@@ -1,5 +1,5 @@
extends MarginContainer
class_name ListTitle class_name ListTitle
extends MarginContainer
signal add_pressed() signal add_pressed()
signal save_pressed() signal save_pressed()
@@ -7,10 +7,11 @@ signal back_pressed()
signal new_search(new_text: String) signal new_search(new_text: String)
signal import_path_selected(path: String, match_to_file: bool) signal import_path_selected(path: String, match_to_file: bool)
var my_button: Button
@onready var title_label: Label = %TitleLabel @onready var title_label: Label = %TitleLabel
@onready var file_dialog: FileDialog = $FileDialog @onready var file_dialog: FileDialog = $FileDialog
var my_button: Button
func _ready() -> void: func _ready() -> void:
my_button = file_dialog.add_button("Match list to file (delete elements not in file)", true, "act") my_button = file_dialog.add_button("Match list to file (delete elements not in file)", true, "act")
+1 -1
View File
@@ -1,5 +1,5 @@
extends MarginContainer
class_name PlusButton class_name PlusButton
extends MarginContainer
signal pressed() signal pressed()
+15 -7
View File
@@ -1,7 +1,14 @@
extends Control extends Control
enum FileCheckResult {
OK,
ERROR_NOT_FOUND,
ERROR_CASE_MISMATCH
}
const BASE_PATH: String = "user://language_resources/" const BASE_PATH: String = "user://language_resources/"
const SAVE_FILE_PATH: String = "user://prof_tool_save.tres" const SAVE_FILE_PATH: String = "user://prof_tool_save.tres"
var save_file: ProfToolSave var save_file: ProfToolSave
@onready var language_select_button: OptionButton = %LanguageSelectButton @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 integrity_log_path: String = "user://database-integrity-log.txt"
var total_integrity_warnings: int = 0 var total_integrity_warnings: int = 0
func _check_db_integrity() -> void: func _check_db_integrity() -> void:
if integrity_checking: if integrity_checking:
return return
@@ -258,6 +266,7 @@ func _check_db_integrity() -> void:
var file_path: String = ProjectSettings.globalize_path(integrity_log_path) var file_path: String = ProjectSettings.globalize_path(integrity_log_path)
Logger.trace("ProfToolMenu: Logs saved at " + file_path) Logger.trace("ProfToolMenu: Logs saved at " + file_path)
OS.shell_open(file_path) OS.shell_open(file_path)
#endregion #endregion
func log_message(message: String) -> bool: func log_message(message: String) -> bool:
@@ -281,11 +290,6 @@ func log_message(message: String) -> bool:
integrity_checking = false integrity_checking = false
return false return false
enum FileCheckResult {
OK,
ERROR_NOT_FOUND,
ERROR_CASE_MISMATCH
}
func file_exists_case_sensitive(path: String) -> Dictionary: func file_exists_case_sensitive(path: String) -> Dictionary:
var result: Dictionary = { var result: Dictionary = {
@@ -325,6 +329,7 @@ func file_exists_case_sensitive(path: String) -> Dictionary:
return result return result
func _get_available_languages() -> Array[String]: func _get_available_languages() -> Array[String]:
var available_languages: Array[String] = [] var available_languages: Array[String] = []
var dir: DirAccess = DirAccess.open(BASE_PATH) 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: func _on_tab_container_tab_changed(tab: int) -> void:
Globals.main_menu_selected_tab = tab Globals.main_menu_selected_tab = tab
#region Book Generation #region Book Generation
func create_book() -> void: func create_book() -> void:
var lang_path: String = BASE_PATH.path_join(Database.language) var lang_path: String = BASE_PATH.path_join(Database.language)
var file_names: Dictionary[String, String] = { 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 error_label.text = "📘 Export data of the booklet finished to path: " + output_path
Logger.trace("ProfToolMenu: " + error_label.text) Logger.trace("ProfToolMenu: " + error_label.text)
# Fonction qui ajoute une ligne au dictionnaire # 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: 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) # 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) result.append(current)
return result return result
# Transforme une ligne pour l'écriture CSV, avec échappement # Transforme une ligne pour l'écriture CSV, avec échappement
func escape_csv_line(fields: PackedStringArray) -> String: func escape_csv_line(fields: PackedStringArray) -> String:
var output: String = "" var output: String = ""
@@ -700,10 +707,12 @@ func escape_csv_line(fields: PackedStringArray) -> String:
output += "," output += ","
return output return output
# Normalise les noms de colonnes (ex: writing page -> Writing page) # Normalise les noms de colonnes (ex: writing page -> Writing page)
func normalize_header(header_name: String) -> String: func normalize_header(header_name: String) -> String:
return header_name.strip_edges()[0].to_upper() + header_name.strip_edges().substr(1, -1).to_lower() return header_name.strip_edges()[0].to_upper() + header_name.strip_edges().substr(1, -1).to_lower()
# Lit une "ligne logique" complète dun CSV (même si elle est sur plusieurs lignes à cause des guillemets) # Lit une "ligne logique" complète dun CSV (même si elle est sur plusieurs lignes à cause des guillemets)
func read_csv_record(file: FileAccess) -> String: func read_csv_record(file: FileAccess) -> String:
var record: String = "" var record: String = ""
@@ -727,5 +736,4 @@ func read_csv_record(file: FileAccess) -> String:
return record return record
#endregion #endregion
+7 -7
View File
@@ -1,14 +1,14 @@
extends HBoxContainer
class_name SegmentBuild class_name SegmentBuild
extends HBoxContainer
signal modify() signal modified()
signal delete() signal deleted()
var points: Array[Vector2] = []
@onready var number_of_points_labels: Label = %NumberOfPointsLabel @onready var number_of_points_labels: Label = %NumberOfPointsLabel
@onready var color_rect: ColorRect = %ColorRect @onready var color_rect: ColorRect = %ColorRect
var points: Array[Vector2] = []
func add_point(point: Vector2) -> void: func add_point(point: Vector2) -> void:
points.append(point) points.append(point)
@@ -35,9 +35,9 @@ func set_color(color: Color) -> void:
func _on_modify_button_pressed() -> void: func _on_modify_button_pressed() -> void:
modify.emit() modified.emit()
func _on_delete_button_pressed() -> void: func _on_delete_button_pressed() -> void:
delete.emit() deleted.emit()
queue_free() queue_free()
+13 -16
View File
@@ -1,25 +1,24 @@
extends HBoxContainer
class_name SegmentContainer class_name SegmentContainer
extends HBoxContainer
signal changed() 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_lines: int = 25
@export var points_per_gradient: int = 7 @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 grapheme_label: Label = %GraphemeLabel
@onready var buttons_parent: Control = %ButtonsParent @onready var buttons_parent: Control = %ButtonsParent
@onready var segments_container: VBoxContainer = %SegmentsContainer @onready var segments_container: VBoxContainer = %SegmentsContainer
@onready var lines: Node2D = %Lines @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: func reset() -> void:
var to_free: Array[Node] = lines.get_children() 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) segments_container.add_child(new_segment)
# Connect signals for modifying and deleting the segment # Connect signals for modifying and deleting the segment
new_segment.modify.connect(_on_segment_modify.bind(new_segment)) new_segment.modified.connect(_on_segment_modified.bind(new_segment))
new_segment.delete.connect(_on_segment_delete.bind(new_segment)) new_segment.deleted.connect(_on_segment_deleted.bind(new_segment))
# Store the new segment as the currently selected one # Store the new segment as the currently selected one
current_segment = new_segment current_segment = new_segment
@@ -156,15 +155,13 @@ func _on_add_segment_button_pressed() -> void:
changed.emit() changed.emit()
func _on_segment_modify(segment: SegmentBuild) -> void: func _on_segment_modified(segment: SegmentBuild) -> void:
current_segment = segment current_segment = segment
match_segment_with_buttons() match_segment_with_buttons()
changed.emit() changed.emit()
func _on_segment_delete(segment: SegmentBuild) -> void: func _on_segment_deleted(segment: SegmentBuild) -> void:
if segment == current_segment: if segment == current_segment:
var possible_segments: Array[Node] = segments_container.get_children() var possible_segments: Array[Node] = segments_container.get_children()
if not possible_segments.is_empty(): if not possible_segments.is_empty():
@@ -1,5 +1,5 @@
extends Control
class_name SegmentPointButton class_name SegmentPointButton
extends Control
signal point_down() signal point_down()
signal point_up() signal point_up()
+1
View File
@@ -1,6 +1,7 @@
extends WordList extends WordList
var not_found_list: String = "" var not_found_list: String = ""
@onready var export_not_found_button: Button = %ExportNotFoundButton @onready var export_not_found_button: Button = %ExportNotFoundButton
@onready var file_dialog_export: FileDialog = $FileDialogExport @onready var file_dialog_export: FileDialog = $FileDialogExport
@@ -1,5 +1,5 @@
extends WordListElement
class_name SentenceListElement class_name SentenceListElement
extends WordListElement
signal not_found(text: String) signal not_found(text: String)
@@ -13,8 +13,6 @@ func _ready() -> void:
graphemes_label.hide() graphemes_label.hide()
func update_lesson() -> void: func update_lesson() -> void:
var highest_min_lesson: int = -1 var highest_min_lesson: int = -1
+1 -1
View File
@@ -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: func _on_list_title_import_path_selected(path: String, match_to_file: bool) -> void:
+5 -5
View File
@@ -1,18 +1,18 @@
extends Control extends Control
const EXTENSION: String = ".csv"
@export var gradient: Gradient @export var gradient: Gradient
var letters: Array[String] = []
var current_letter: int = -1
@onready var lower_container: SegmentContainer = %Lower @onready var lower_container: SegmentContainer = %Lower
@onready var upper_container: SegmentContainer = %Upper @onready var upper_container: SegmentContainer = %Upper
@onready var letter_picker: OptionButton = %LetterPicker @onready var letter_picker: OptionButton = %LetterPicker
@onready var save_ok: TextureRect = %SaveOk @onready var save_ok: TextureRect = %SaveOk
@onready var copy_from: MenuButton = %CopyFrom @onready var copy_from: MenuButton = %CopyFrom
const EXTENSION: String = ".csv"
var letters: Array[String] = []
var current_letter: int = -1
func _ready() -> void: func _ready() -> void:
copy_from.get_popup().id_pressed.connect(_on_copy_from_id_pressed) copy_from.get_popup().id_pressed.connect(_on_copy_from_id_pressed)
@@ -1,16 +1,16 @@
extends HBoxContainer
class_name VideoGPDescription class_name VideoGPDescription
extends HBoxContainer
@warning_ignore("unused_signal") @warning_ignore("unused_signal")
signal delete signal deleted()
var gp: Dictionary = {}
@onready var gp_menu_button: MenuButton = %GPMenuButton @onready var gp_menu_button: MenuButton = %GPMenuButton
@onready var video_player: VideoStreamPlayer = %VideoStreamPlayer @onready var video_player: VideoStreamPlayer = %VideoStreamPlayer
@onready var video_upload_button: PlusButton = %VideoUploadButton @onready var video_upload_button: PlusButton = %VideoUploadButton
@onready var file_dialog: FileDialog = $FileDialog @onready var file_dialog: FileDialog = $FileDialog
var gp: Dictionary = {}
func _video_file_selected(file_path: String) -> void: func _video_file_selected(file_path: String) -> void:
file_dialog.files_selected.connect(_video_file_selected.bind(file_dialog)) file_dialog.files_selected.connect(_video_file_selected.bind(file_dialog))
+9 -10
View File
@@ -1,8 +1,16 @@
extends Control
class_name WordList class_name WordList
extends Control
@export var element_scene: PackedScene = preload("res://sources/language_tool/word_list_element.tscn") @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 elements_container: VBoxContainer = %ElementsContainer
@onready var new_gp_layer: CanvasLayer = $NewGPLayer @onready var new_gp_layer: CanvasLayer = $NewGPLayer
@onready var new_gp: Variant = %NewGP @onready var new_gp: Variant = %NewGP
@@ -12,14 +20,6 @@ class_name WordList
@onready var graphemes_title: Label = %Graphemes @onready var graphemes_title: Label = %Graphemes
@onready var error_label: Label = %ErrorLabel @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: func create_sub_elements_list() -> void:
sub_elements_list.clear() sub_elements_list.clear()
@@ -190,7 +190,6 @@ func _on_save_button_pressed() -> void:
undo_redo.clear_history() undo_redo.clear_history()
func _on_back_button_pressed() -> void: func _on_back_button_pressed() -> void:
get_tree().change_scene_to_file("res://sources/language_tool/prof_tool_menu.tscn") get_tree().change_scene_to_file("res://sources/language_tool/prof_tool_menu.tscn")
+18 -17
View File
@@ -1,5 +1,5 @@
extends MarginContainer
class_name WordListElement class_name WordListElement
extends MarginContainer
signal delete_pressed() signal delete_pressed()
signal new_gp_asked(i: int) 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 relational_table: String = "GPsInWords"
@export var sub_table_id: String = "GPID" @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 = "": var word: String = "":
set = set_word set = set_word
var lesson: int = 0: var lesson: int = 0:
@@ -53,6 +38,21 @@ var writing: int = 0:
set = set_writing set = set_writing
var sub_elements_list: Dictionary = {} 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: func set_exception(p_exception: bool) -> void:
exception = p_exception exception = p_exception
@@ -61,6 +61,7 @@ func set_exception(p_exception: bool) -> void:
if exception_edit_checkbox: if exception_edit_checkbox:
exception_edit_checkbox.button_pressed = bool(exception) exception_edit_checkbox.button_pressed = bool(exception)
func set_reading(p_reading: bool) -> void: func set_reading(p_reading: bool) -> void:
reading = p_reading reading = p_reading
if reading_checkbox: if reading_checkbox:
@@ -68,6 +69,7 @@ func set_reading(p_reading: bool) -> void:
if reading_edit_checkbox: if reading_edit_checkbox:
reading_edit_checkbox.button_pressed = bool(reading) reading_edit_checkbox.button_pressed = bool(reading)
func set_writing(p_writing: bool) -> void: func set_writing(p_writing: bool) -> void:
writing = p_writing writing = p_writing
if writing_checkbox: 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) add_gp_list_button(gp_id, ind_gp_id + 1)
func _on_empty_add_gp_button_pressed() -> void: func _on_empty_add_gp_button_pressed() -> void:
var gp_id: int = sub_elements_list.keys()[0] var gp_id: int = sub_elements_list.keys()[0]
unvalidated_gp_ids.append(gp_id) unvalidated_gp_ids.append(gp_id)
+4 -2
View File
@@ -1,5 +1,5 @@
extends TextureButton
class_name LessonButton class_name LessonButton
extends TextureButton
@export_color_no_alpha var base_color: Color: @export_color_no_alpha var base_color: Color:
set = _set_base_color set = _set_base_color
@@ -15,11 +15,12 @@ class_name LessonButton
@onready var placeholder: TextureRect = %Placeholder @onready var placeholder: TextureRect = %Placeholder
@onready var right_fx: RightFX = %RightFX @onready var right_fx: RightFX = %RightFX
func _ready() -> void: func _ready() -> void:
_set_base_color(base_color) _set_base_color(base_color)
_set_completed_color(completed_color) _set_completed_color(completed_color)
_set_text(text) _set_text(text)
func show_placeholder(is_shown: bool) -> void: func show_placeholder(is_shown: bool) -> void:
placeholder.visible = is_shown placeholder.visible = is_shown
@@ -30,6 +31,7 @@ func right() -> void:
right_fx.play() right_fx.play()
await right_fx.finished await right_fx.finished
func _set_base_color(color: Color) -> void: func _set_base_color(color: Color) -> void:
base_color = color base_color = color
if center and not completed: if center and not completed:
+2 -1
View File
@@ -1,5 +1,5 @@
extends Node2D
class_name LetterSegment class_name LetterSegment
extends Node2D
signal finished() signal finished()
@@ -25,6 +25,7 @@ func start() -> void:
func stop() -> void: func stop() -> void:
finished.emit() finished.emit()
func demo() -> void: func demo() -> void:
tracing_path.demo() tracing_path.demo()
+12 -17
View File
@@ -1,9 +1,20 @@
extends Control
class_name LookAndLearn class_name LookAndLearn
extends Control
static var transition_data: Dictionary = {}
@export var lesson_nb: int = 1 @export var lesson_nb: int = 1
@export var current_button_pressed: int = 0 @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 animation_player: AnimationPlayer = $AnimationPlayer
@onready var audio_player: AudioStreamPlayer = $AudioStreamPlayer @onready var audio_player: AudioStreamPlayer = $AudioStreamPlayer
@onready var video_player: VideoStreamPlayer = %VideoStreamPlayer @onready var video_player: VideoStreamPlayer = %VideoStreamPlayer
@@ -13,21 +24,6 @@ class_name LookAndLearn
@onready var grapheme_particles: GPUParticles2D = $GraphemeParticles @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: func _ready() -> void:
MusicManager.stop() MusicManager.stop()
@@ -157,7 +153,6 @@ func _on_tracing_manager_finished() -> void:
_back_to_gardens() _back_to_gardens()
func _back_to_gardens() -> void: func _back_to_gardens() -> void:
await OpeningCurtain.close() await OpeningCurtain.close()
+1 -1
View File
@@ -1,5 +1,5 @@
extends Node2D
class_name TracingEffects class_name TracingEffects
extends Node2D
@onready var particles_effect: GPUParticles2D = $TracingParticles @onready var particles_effect: GPUParticles2D = $TracingParticles
@onready var sound_effect: AudioStreamPlayer = $TracingAudioStreamPlayer @onready var sound_effect: AudioStreamPlayer = $TracingAudioStreamPlayer
+2 -8
View File
@@ -1,16 +1,16 @@
extends Control
class_name TracingManager class_name TracingManager
extends Control
signal finished() signal finished()
const LETTER_SEGMENT_CLASS: PackedScene = preload("res://sources/look_and_learn/letter_segment.tscn") const LETTER_SEGMENT_CLASS: PackedScene = preload("res://sources/look_and_learn/letter_segment.tscn")
const EXTENSION: String = ".csv"
@export var label_settings: LabelSettings @export var label_settings: LabelSettings
@onready var lower_labels: HBoxContainer = %LowerLabels @onready var lower_labels: HBoxContainer = %LowerLabels
@onready var upper_labels: HBoxContainer = %UpperLabels @onready var upper_labels: HBoxContainer = %UpperLabels
const EXTENSION: String = ".csv"
func _process(_delta: float) -> void: func _process(_delta: float) -> void:
place_segments(upper_labels.get_children()) place_segments(upper_labels.get_children())
@@ -34,8 +34,6 @@ func reset() -> void:
await get_tree().process_frame await get_tree().process_frame
# --- Setup ---
func setup(grapheme: String) -> void: func setup(grapheme: String) -> void:
await reset() await reset()
for letter: String in grapheme: 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 return Database.BASE_PATH.path_join(Database.language).path_join(Database.TRACING_DATA_FOLDER).path_join(path) + EXTENSION
# --- Start ---
func start() -> void: func start() -> void:
if upper_labels.get_child_count(false) > 0: if upper_labels.get_child_count(false) > 0:
lower_labels.visible = false lower_labels.visible = false
+9 -11
View File
@@ -1,30 +1,28 @@
extends Path2D
class_name TracingPath class_name TracingPath
extends Path2D
signal finished signal finished()
signal demo_finished signal demo_finished()
@export var points_per_curve: int = 25 @export var points_per_curve: int = 25
@export var hand_min_travel_time: float = 0.5 @export var hand_min_travel_time: float = 0.5
@export var hand_max_travel_time: float = 2.0 @export var hand_max_travel_time: float = 2.0
@export var distance: float = 100.0 @export var distance: float = 100.0
@export var color_gradient: Gradient @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 line: Line2D = $Line2D
@onready var guide: PathFollow2D = $GuidePathFollow @onready var guide: PathFollow2D = $GuidePathFollow
@onready var hand: PathFollow2D = $HandPathFollow2D @onready var hand: PathFollow2D = $HandPathFollow2D
@onready var guide_sprite: Sprite2D = $GuidePathFollow/Guide @onready var guide_sprite: Sprite2D = $GuidePathFollow/Guide
@onready var hand_sprite: Sprite2D = $HandPathFollow2D/Hand @onready var hand_sprite: Sprite2D = $HandPathFollow2D/Hand
var curve_points: PackedVector2Array
@onready var remaining_curve: Curve2D = Curve2D.new() @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: func _ready() -> void:
guide_sprite.visible = false guide_sprite.visible = false
+2 -1
View File
@@ -11,10 +11,11 @@ const SYMBOLS_NAMES: Dictionary[String, String] = {
"6": "TRIANGLE", "6": "TRIANGLE",
} }
var password: String = ""
@onready var code_keyboard: CodeKeyboard = %CodeKeyboard @onready var code_keyboard: CodeKeyboard = %CodeKeyboard
@onready var password_label: Label = %PasswordLabel @onready var password_label: Label = %PasswordLabel
var password: String = ""
func _ready() -> void: func _ready() -> void:
_reset_password() _reset_password()
+2 -4
View File
@@ -10,7 +10,6 @@ const KALULU := preload("res://sources/minigames/base/kalulu.gd")
@onready var kalulu: KALULU = $Kalulu @onready var kalulu: KALULU = $Kalulu
@onready var kalulu_button: TextureButton = %KaluluButton @onready var kalulu_button: TextureButton = %KaluluButton
@onready var audio_stream_player: AudioStreamPlayer = $AudioStreamPlayer @onready var audio_stream_player: AudioStreamPlayer = $AudioStreamPlayer
@onready var garden_buttons: Array[TextureButton] = [ @onready var garden_buttons: Array[TextureButton] = [
%GardenButton1, %GardenButton1,
%GardenButton2, %GardenButton2,
@@ -33,7 +32,6 @@ const KALULU := preload("res://sources/minigames/base/kalulu.gd")
%GardenButton19, %GardenButton19,
%GardenButton20, %GardenButton20,
] ]
@onready var particles: Array[GPUParticles2D] = [ @onready var particles: Array[GPUParticles2D] = [
%Particles1, %Particles1,
%Particles2, %Particles2,
@@ -56,18 +54,18 @@ const KALULU := preload("res://sources/minigames/base/kalulu.gd")
%Particles19, %Particles19,
%Particles20, %Particles20,
] ]
@onready var tutorial_speeches: Array[AudioStream]= [ @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_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_2")),
Database.load_external_sound(Database.get_kalulu_speech_path("brain_screen", "intro_3")) 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")) @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]: static func _compute_lessons_distribution(total_lessons: int, garden_layouts: Array[GardenLayout]) -> Array[int]:
return Gardens.compute_lessons_distribution(total_lessons, garden_layouts) return Gardens.compute_lessons_distribution(total_lessons, garden_layouts)
func _ready() -> void: func _ready() -> void:
UserDataManager.start_synchronization_timer() UserDataManager.start_synchronization_timer()
+3 -2
View File
@@ -1,14 +1,15 @@
extends Control
class_name CodeKeyboard class_name CodeKeyboard
extends Control
signal button_pressed(key: String, password: Array[String]) signal button_pressed(key: String, password: Array[String])
signal password_entered(password: String) signal password_entered(password: String)
var password: Array[String] = []
@onready var password_visualizer: PasswordVisualizer = %PasswordVisualizer @onready var password_visualizer: PasswordVisualizer = %PasswordVisualizer
@onready var buttons: GridContainer = %Buttons @onready var buttons: GridContainer = %Buttons
@onready var sound_player: AudioStreamPlayer = $ButtonSoundPlayer @onready var sound_player: AudioStreamPlayer = $ButtonSoundPlayer
var password: Array[String] = []
func _ready() -> void: func _ready() -> void:
for button: TextureButton in buttons.get_children(false): for button: TextureButton in buttons.get_children(false):
@@ -1,6 +1,6 @@
@tool @tool
extends HBoxContainer
class_name PasswordVisualizer class_name PasswordVisualizer
extends HBoxContainer
const ICONS_TEXTURES: Dictionary[String, CompressedTexture2D] = { const ICONS_TEXTURES: Dictionary[String, CompressedTexture2D] = {
"1": preload("res://assets/menus/login/symbol_01.png"), "1": preload("res://assets/menus/login/symbol_01.png"),
@@ -24,12 +24,14 @@ const ICONS_TEXTURES: Dictionary[String, CompressedTexture2D] = {
@onready var icons: Array[TextureRect] = [] @onready var icons: Array[TextureRect] = []
func _ready() -> void: func _ready() -> void:
_draw_password() _draw_password()
for icon: TextureRect in icons: for icon: TextureRect in icons:
icon.custom_minimum_size.x = key_size icon.custom_minimum_size.x = key_size
icon.custom_minimum_size.y = key_size icon.custom_minimum_size.y = key_size
func _draw_password() -> void: func _draw_password() -> void:
if not icons: if not icons:
@@ -5,9 +5,11 @@ const LOGIN_SCENE_PATH: String = "res://sources/menus/login/login.tscn"
@onready var container: GridContainer = %GridContainer @onready var container: GridContainer = %GridContainer
func _ready() -> void: func _ready() -> void:
_refresh() _refresh()
func _refresh() -> void: func _refresh() -> void:
if not UserDataManager.teacher_settings: if not UserDataManager.teacher_settings:
return return
@@ -23,6 +25,7 @@ func _refresh() -> void:
button.pressed.connect(_device_button_pressed.bind(device)) button.pressed.connect(_device_button_pressed.bind(device))
OpeningCurtain.open() OpeningCurtain.open()
func _device_button_pressed(device: int) -> void: func _device_button_pressed(device: int) -> void:
Logger.trace("DeviceSelection: User selected device %d" % device) Logger.trace("DeviceSelection: User selected device %d" % device)
if UserDataManager.set_device_id(device): if UserDataManager.set_device_id(device):
@@ -1,11 +1,10 @@
extends Control
class_name PackageDownloader class_name PackageDownloader
extends Control
const MAIN_MENU_SCENE_PATH: String = "res://sources/menus/main/main_menu.tscn" 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 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 LOGIN_SCENE_PATH: String = "res://sources/menus/login/login.tscn"
const USER_LANGUAGE_RESOURCES_PATH: String = "user://language_resources" const USER_LANGUAGE_RESOURCES_PATH: String = "user://language_resources"
const ERROR_MESSAGES: Array[String] = [ const ERROR_MESSAGES: Array[String] = [
"DISCONNECTED_ERROR", "DISCONNECTED_ERROR",
"NO_INTERNET_ACCESS", "NO_INTERNET_ACCESS",
@@ -13,6 +12,12 @@ const ERROR_MESSAGES: Array[String] = [
"INVALID_LANGUAGE_DIRECTORY", "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 http_request: HTTPRequest = $HTTPRequest
@onready var checking_label: Label = %CheckingLabel @onready var checking_label: Label = %CheckingLabel
@@ -25,13 +30,6 @@ const ERROR_MESSAGES: Array[String] = [
@onready var error_label: Label = %ErrorLabel @onready var error_label: Label = %ErrorLabel
@onready var error_popup: ConfirmPopup = $ErrorPopup @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: func _ready() -> void:
await get_tree().process_frame await get_tree().process_frame
+4 -4
View File
@@ -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 NEXT_SCENE_PATH: String = "res://sources/menus/brain/brain.tscn"
const TEACHER_SCENE_PATH: String = "res://sources/menus/settings/teacher_settings.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 PACKAGE_LOADER_SCENE_PATH: String = "res://sources/menus/language_selection/package_downloader.tscn"
const KALULU := preload("res://sources/minigames/base/kalulu.gd") 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 kalulu: KALULU = $Kalulu
@onready var music_player: AudioStreamPlayer = $MusicStreamPlayer @onready var music_player: AudioStreamPlayer = $MusicStreamPlayer
@onready var device_number_label: Label = $DeviceNumber @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 teacher_help_label: Label = %TeacherHelpLabel
@onready var kalulu_button: CanvasItem = %KaluluButton @onready var kalulu_button: CanvasItem = %KaluluButton
var help_speech: AudioStream
var wrong_password_speech: AudioStream
var right_password_speech: AudioStream
func _ready() -> void: func _ready() -> void:
UserDataManager.stop_synchronization_timer() UserDataManager.stop_synchronization_timer()
+5 -6
View File
@@ -1,23 +1,22 @@
@tool @tool
extends TextureButton
class_name DeviceButton class_name DeviceButton
extends TextureButton
@onready var background: TextureRect = $Background
@onready var label: Label = $Label
@export_range(1, 99) var number: int: @export_range(1, 99) var number: int:
set(value): set(value):
number = value number = value
if label: if label:
label.text = str(value) label.text = str(value)
@export var background_color: Color: @export var background_color: Color:
set(value): set(value):
background_color = value background_color = value
if background: if background:
background.self_modulate = background_color background.self_modulate = background_color
@onready var background: TextureRect = $Background
@onready var label: Label = $Label
func _ready() -> void: func _ready() -> void:
label.text = str(number) label.text = str(number)
background.self_modulate = background_color background.self_modulate = background_color
+5 -10
View File
@@ -1,11 +1,7 @@
extends Control extends Control
@onready var speech_player: AudioStreamPlayer = $SpeechPlayer
@onready var sprite: AnimatedSprite2D = $Sprite
var tuto_speech: AudioStreamMP3 var tuto_speech: AudioStreamMP3
var feedback_speech: AudioStreamMP3 var feedback_speech: AudioStreamMP3
var is_speaking: bool = false: var is_speaking: bool = false:
set(value): set(value):
is_speaking = value is_speaking = value
@@ -16,6 +12,9 @@ var is_speaking: bool = false:
sprite.play("Tc_Idle1") sprite.play("Tc_Idle1")
var elapsed_time: float = 0.0 var elapsed_time: float = 0.0
@onready var speech_player: AudioStreamPlayer = $SpeechPlayer
@onready var sprite: AnimatedSprite2D = $Sprite
func _ready() -> void: func _ready() -> void:
tuto_speech = Database.load_external_sound(Database.get_kalulu_speech_path("title_screen", "tuto_welcome_oneshot")) 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: func _process(delta: float) -> void:
if not visible: if not visible:
return return
if not sprite.is_playing(): if not sprite.is_playing():
sprite.play("Tc_Idle1") sprite.play("Tc_Idle1")
if not is_speaking: if not is_speaking:
elapsed_time += delta elapsed_time += delta
if elapsed_time > 20: if elapsed_time > 20:
start_speech() start_speech()
func _play_speech(speech: AudioStream) -> void: func _play_speech(speech: AudioStream) -> void:
if not speech: if not speech:
Logger.warn("Kalulu: Speech not found") Logger.warn("Kalulu: Speech not found")
is_speaking = false is_speaking = false
return return
is_speaking = true is_speaking = true
speech_player.stream = speech speech_player.stream = speech
speech_player.play() speech_player.play()
await speech_player.finished await speech_player.finished
is_speaking = false is_speaking = false
+1
View File
@@ -2,6 +2,7 @@ extends OptionButton
var items: Array[String] = [] var items: Array[String] = []
func _ready() -> void: func _ready() -> void:
# Adds the supported locales to the field # Adds the supported locales to the field
var idx: int = 0 var idx: int = 0
+1 -2
View File
@@ -1,12 +1,11 @@
extends Control extends Control
signal logged_in signal logged_in()
@onready var validator: FormValidator = %LoginFormValidator @onready var validator: FormValidator = %LoginFormValidator
@onready var email_field: LineEdit = %EmailField @onready var email_field: LineEdit = %EmailField
@onready var password_field: LineEdit = %PasswordField @onready var password_field: LineEdit = %PasswordField
@onready var login_message: Label = %LoginError @onready var login_message: Label = %LoginError
@onready var device_id_container: VBoxContainer = %DeviceIDContainer @onready var device_id_container: VBoxContainer = %DeviceIDContainer
@onready var device_id_field: SpinBox = %DeviceIDField @onready var device_id_field: SpinBox = %DeviceIDField
-2
View File
@@ -1,14 +1,12 @@
extends Control extends Control
const KALULU := preload("res://sources/menus/main/kalulu.gd") const KALULU := preload("res://sources/menus/main/kalulu.gd")
const ADULT_CHECK_SCENE_PATH: String = "res://sources/menus/adult_check/adult_check.tscn" 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" const PACKAGE_LOADER_SCENE_PATH: String = "res://sources/menus/language_selection/package_downloader.tscn"
@onready var version_label: Label = $Informations/BuildVersionValue @onready var version_label: Label = $Informations/BuildVersionValue
@onready var teacher_label: Label = $Informations/TeacherValue @onready var teacher_label: Label = $Informations/TeacherValue
@onready var device_id_label: Label = $Informations/DeviceIDValue @onready var device_id_label: Label = $Informations/DeviceIDValue
@onready var kalulu: KALULU = $Kalulu @onready var kalulu: KALULU = $Kalulu
@onready var play_button: Button = %PlayButton @onready var play_button: Button = %PlayButton
@onready var interface_left: MarginContainer = %InterfaceLeft @onready var interface_left: MarginContainer = %InterfaceLeft
+2 -1
View File
@@ -1,5 +1,6 @@
extends ProgressBar
class_name RegisterProgressBar class_name RegisterProgressBar
extends ProgressBar
func set_value_with_tween(new_value: float) -> void: func set_value_with_tween(new_value: float) -> void:
create_tween().tween_property(self, "value", new_value, 0.15).set_trans(Tween.TRANS_LINEAR) create_tween().tween_property(self, "value", new_value, 0.15).set_trans(Tween.TRANS_LINEAR)
+4 -3
View File
@@ -3,6 +3,8 @@ extends Control
const MAIN_MENU_PATH: String = "res://sources/menus/main/main_menu.tscn" 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" const NEXT_SCENE_PATH: String = "res://sources/menus/language_selection/package_downloader.tscn"
var current_steps: Array[Step] = []
@onready var teacher_steps: Array[PackedScene] = [ @onready var teacher_steps: Array[PackedScene] = [
preload("res://sources/menus/register/steps/teacher/method_step.tscn"), preload("res://sources/menus/register/steps/teacher/method_step.tscn"),
preload("res://sources/menus/register/steps/teacher/devices_count_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 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 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") @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 register_data: TeacherSettings = TeacherSettings.new()
@onready var progress_bar: RegisterProgressBar = %ProgressBar @onready var progress_bar: RegisterProgressBar = %ProgressBar
@onready var steps: Control = %Steps @onready var steps: Control = %Steps
@onready var popup: TextureRect = %Popup @onready var popup: TextureRect = %Popup
@onready var popup_info_label: Label = %PopupInfo @onready var popup_info_label: Label = %PopupInfo
func _ready() -> void: func _ready() -> void:
current_steps = [account_type_step.instantiate()] current_steps = [account_type_step.instantiate()]
_go_to_step(int(progress_bar.value)) _go_to_step(int(progress_bar.value))
@@ -129,5 +129,6 @@ func _remove_future_steps() -> void:
# Resize the array to remove unwanted steps # Resize the array to remove unwanted steps
current_steps.resize(int(progress_bar.value + 1)) current_steps.resize(int(progress_bar.value + 1))
func _on_popup_button_pressed() -> void: func _on_popup_button_pressed() -> void:
popup.hide() popup.hide()
@@ -3,6 +3,7 @@ extends Step
@onready var type: ItemList = %TypeSelect @onready var type: ItemList = %TypeSelect
func _ready() -> void: func _ready() -> void:
type.clear() type.clear()
type.add_item(tr("TEACHER")) type.add_item(tr("TEACHER"))
+8 -5
View File
@@ -1,20 +1,21 @@
@tool @tool
extends Control
class_name Step class_name Step
extends Control
signal back(step: Step) signal back(step: Step)
signal next(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 question_label: Label = %QuestionLabel
@onready var info_label: Label = %InfoLabel @onready var info_label: Label = %InfoLabel
@onready var form_validator: FormValidator = %FormValidator @onready var form_validator: FormValidator = %FormValidator
@onready var form_binder: FormBinder = %FormBinder @onready var form_binder: FormBinder = %FormBinder
@onready var form_container: Control = %FormContainer @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: func on_enter() -> void:
form_binder.read(data) form_binder.read(data)
@@ -25,6 +26,7 @@ func on_enter() -> void:
else: else:
info_label.visible = false info_label.visible = false
func _on_back() -> bool: func _on_back() -> bool:
return true return true
@@ -32,6 +34,7 @@ func _on_back() -> bool:
func _on_next() -> bool: func _on_next() -> bool:
return true return true
# Display error messages # Display error messages
func _on_form_validator_control_validated(control: Control, passed: bool, messages: PackedStringArray) -> void: 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 var label: Label = find_child(control.name as String + "Error", true, false) as Label
@@ -3,6 +3,7 @@ extends Step
@onready var api_email_field_error: Label = %APIEmailFieldError @onready var api_email_field_error: Label = %APIEmailFieldError
func _on_validate_button_pressed() -> void: func _on_validate_button_pressed() -> void:
api_email_field_error.visible = false api_email_field_error.visible = false
+2 -1
View File
@@ -1,5 +1,5 @@
extends Control
class_name DeviceRecap class_name DeviceRecap
extends Control
const STUDENT_PANEL_SCENE: PackedScene = preload("res://sources/menus/settings/student_panel.tscn") 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 title_label: Label = %Title
@onready var students_container: GridContainer = %StudentsContainer @onready var students_container: GridContainer = %StudentsContainer
func _ready() -> void: func _ready() -> void:
if title: if title:
+2 -1
View File
@@ -1,6 +1,6 @@
@tool @tool
extends Step
class_name RecapStep class_name RecapStep
extends Step
const DEVICE_RECAP_SCENE: PackedScene = preload("res://sources/menus/register/steps/device_recap.tscn") 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 devices_count: Label = %DevicesCount
@onready var students_count: Label = %StudentsCount @onready var students_count: Label = %StudentsCount
func on_enter() -> void: func on_enter() -> void:
super.on_enter() super.on_enter()
@@ -1,10 +1,12 @@
@tool @tool
extends Step
class_name StudentsCountStep class_name StudentsCountStep
extends Step
@export var device_id: int @export var device_id: int
@onready var students_count_field: SpinBox = %StudentsCountField @onready var students_count_field: SpinBox = %StudentsCountField
func _on_back() -> bool: func _on_back() -> bool:
var register_data: TeacherSettings = data as TeacherSettings var register_data: TeacherSettings = data as TeacherSettings
if register_data: if register_data:
@@ -1,9 +1,10 @@
@tool @tool
extends ValidatorRule
class_name ConfirmRule class_name ConfirmRule
extends ValidatorRule
@export_node_path("Control") var confirm_control_path: NodePath @export_node_path("Control") var confirm_control_path: NodePath
func _init() -> void: func _init() -> void:
fail_message = "Value must be the same in both fields." fail_message = "Value must be the same in both fields."
@@ -1,6 +1,6 @@
@tool @tool
extends Validator
class_name ItemListValidator class_name ItemListValidator
extends Validator
func get_value(control: Control) -> Variant: func get_value(control: Control) -> Variant:
+3 -3
View File
@@ -1,15 +1,15 @@
extends TabBar
class_name DeviceTab class_name DeviceTab
extends TabBar
signal student_pressed(code: int) signal student_pressed(code: int)
const STUDENT_PANEL_SCENE: PackedScene = preload("res://sources/menus/settings/student_panel.tscn") 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 device_id: int
@export var students: Array[StudentData] = [] @export var students: Array[StudentData] = []
@onready var students_container: GridContainer = %StudentsContainer
func _ready() -> void: func _ready() -> void:
refresh() refresh()
+2 -4
View File
@@ -1,14 +1,12 @@
extends MarginContainer
class_name LessonUnlock class_name LessonUnlock
extends MarginContainer
signal unlocks_changed signal unlocks_changed()
@export var lesson_number: int: @export var lesson_number: int:
set = _set_lesson_number set = _set_lesson_number
@export var lesson_gps: String: @export var lesson_gps: String:
set = _set_lesson_gps set = _set_lesson_gps
@export var unlocks: Dictionary = {} @export var unlocks: Dictionary = {}
@onready var lesson_label: Label = %LessonLabel @onready var lesson_label: Label = %LessonLabel
+8 -8
View File
@@ -1,24 +1,24 @@
extends Control
class_name LessonUnlocks class_name LessonUnlocks
extends Control
signal student_deleted(code: int) signal student_deleted(code: int)
const DEVICE_BUTTON_SCENE: PackedScene = preload("res://sources/menus/main/device_button.tscn") 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") 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: @export var device: int:
set = _on_device_changed set = _on_device_changed
@export var student: int: @export var student: int:
set = _on_student_changed set = _on_student_changed
var progression: StudentProgression 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: func _ready() -> void:
name_line_edit.connect("text_submitted", _on_name_changed) name_line_edit.connect("text_submitted", _on_name_changed)
@@ -7,6 +7,7 @@ extends TextureButton
@onready var voice_volume_slider: HSlider = %VoiceVolumeSlider @onready var voice_volume_slider: HSlider = %VoiceVolumeSlider
@onready var effects_volume_slider: HSlider = %EffectsVolumeSlider @onready var effects_volume_slider: HSlider = %EffectsVolumeSlider
func _ready() -> void: func _ready() -> void:
set_master_volume_slider(UserDataManager.get_master_volume()) set_master_volume_slider(UserDataManager.get_master_volume())
set_music_volume_slider(UserDataManager.get_music_volume()) set_music_volume_slider(UserDataManager.get_music_volume())
+5 -4
View File
@@ -1,13 +1,14 @@
extends Control
class_name StudentPanel 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 name_label: Label = %NameLabel
@onready var password_visualizer: PasswordVisualizer = %PasswordVisualizer @onready var password_visualizer: PasswordVisualizer = %PasswordVisualizer
@export var student_count: int
@export var student_data: StudentData
func _ready() -> void: func _ready() -> void:
if not student_data: if not student_data:
+3 -8
View File
@@ -1,31 +1,26 @@
extends Control
class_name SettingsTeacherSettings class_name SettingsTeacherSettings
extends Control
const MAIN_MENU_PATH: String = "res://sources/menus/main/main_menu.tscn" const MAIN_MENU_PATH: String = "res://sources/menus/main/main_menu.tscn"
const LOGIN_MENU_PATH: String = "res://sources/menus/login/login.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_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") 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 devices_tab_container: TabContainer = %DevicesTabContainer
@onready var lesson_unlocks: LessonUnlocks = $LessonUnlocks @onready var lesson_unlocks: LessonUnlocks = $LessonUnlocks
@onready var delete_popup: ConfirmPopup = %DeletePopup @onready var delete_popup: ConfirmPopup = %DeletePopup
@onready var loading_popup: LoadingPopup = %LoadingPopup @onready var loading_popup: LoadingPopup = %LoadingPopup
@onready var account_type_option_button: OptionButton = %AccountTypeOptionButton @onready var account_type_option_button: OptionButton = %AccountTypeOptionButton
@onready var education_method_option_button: OptionButton = %EducationMethodOptionButton @onready var education_method_option_button: OptionButton = %EducationMethodOptionButton
@onready var add_device_button: Button = %AddDeviceButton @onready var add_device_button: Button = %AddDeviceButton
@onready var add_student_button: Button = %AddStudentButton @onready var add_student_button: Button = %AddStudentButton
@onready var label_internet_mandatory: Label = %LabelInternetMandatory @onready var label_internet_mandatory: Label = %LabelInternetMandatory
@onready var add_device_popup: CanvasLayer = %AddDevicePopup @onready var add_device_popup: CanvasLayer = %AddDevicePopup
@onready var add_student_popup: CanvasLayer = %AddStudentPopup @onready var add_student_popup: CanvasLayer = %AddStudentPopup
@onready var delete_student_popup: CanvasLayer = %DeleteStudentPopup @onready var delete_student_popup: CanvasLayer = %DeleteStudentPopup
var last_device_id: int = -1
func _ready() -> void: func _ready() -> void:
refresh_devices_tabs() refresh_devices_tabs()
+1 -1
View File
@@ -1,5 +1,5 @@
extends Area2D
class_name Ant class_name Ant
extends Area2D
@onready var animation_player: AnimationPlayer = $AnimationPlayer @onready var animation_player: AnimationPlayer = $AnimationPlayer
@onready var anchor: Node2D = $Anchor @onready var anchor: Node2D = $Anchor
+4 -5
View File
@@ -4,9 +4,12 @@ extends Minigame
const BLANK_SCENE: PackedScene = preload("res://sources/minigames/ants/blank.tscn") const BLANK_SCENE: PackedScene = preload("res://sources/minigames/ants/blank.tscn")
const ANT_SCENE: PackedScene = preload("res://sources/minigames/ants/ant.tscn") const ANT_SCENE: PackedScene = preload("res://sources/minigames/ants/ant.tscn")
const WORD_SCENE: PackedScene = preload("res://sources/minigames/ants/word.tscn") const WORD_SCENE: PackedScene = preload("res://sources/minigames/ants/word.tscn")
const LABEL_SETTINGS: LabelSettings = preload("res://resources/themes/minigames_label_settings.tres") 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 sentence_container: HFlowContainer = %Sentence
@onready var ants_spawn: Node2D = %AntsSpawn @onready var ants_spawn: Node2D = %AntsSpawn
@onready var ants_start: Node2D = %AntsStart @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 ants: Node2D = %Ants
@onready var words: Node2D = %Words @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: func _find_stimuli_and_distractions() -> void:
var sentences_list: Array = Database.get_sentences_for_lesson(lesson_nb, difficulty + 2, 50) var sentences_list: Array = Database.get_sentences_for_lesson(lesson_nb, difficulty + 2, 50)
+1 -2
View File
@@ -1,6 +1,5 @@
extends TextureRect
class_name Blank class_name Blank
extends TextureRect
const IMAGES: Array[String] = [ const IMAGES: Array[String] = [
"res://assets/minigames/ants/graphics/hole_02.png", "res://assets/minigames/ants/graphics/hole_02.png",
+6 -7
View File
@@ -1,20 +1,19 @@
extends TextureButton
class_name Word class_name Word
extends TextureButton
signal answer(stimulus: String, expected_stimulus: String) signal answer(stimulus: String, expected_stimulus: String)
signal no_answer() 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: var stimulus: String:
set = _set_stimulus set = _set_stimulus
var follow_mouse: bool = false var follow_mouse: bool = false
var current_anchor: CanvasItem 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: func right() -> void:
right_fx.play() right_fx.play()

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