diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..8ad74f78 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Normalize EOL for all files that Git considers text files. +* text=auto eol=lf diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..47091836 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +# Godot 4+ specific ignores +.godot/ diff --git a/icon.svg b/icon.svg new file mode 100644 index 00000000..adc26df6 --- /dev/null +++ b/icon.svg @@ -0,0 +1 @@ + diff --git a/icon.svg.import b/icon.svg.import new file mode 100644 index 00000000..82d57d3f --- /dev/null +++ b/icon.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://jl4sirrpr1l1" +path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://icon.svg" +dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/bptc_ldr=0 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/project.godot b/project.godot new file mode 100644 index 00000000..872ae098 --- /dev/null +++ b/project.godot @@ -0,0 +1,61 @@ +; Engine configuration file. +; It's best edited using the editor UI and not directly, +; since the parameters that go here are not all obvious. +; +; Format: +; [section] ; section goes between [] +; param=value ; assign values to parameters + +config_version=5 + +_global_script_classes=[{ +"base": "Node", +"class": &"GameGlobalData", +"language": &"GDScript", +"path": "res://sources/utils/autoloads/game_globals.gd" +}, { +"base": "Resource", +"class": &"LogResource", +"language": &"GDScript", +"path": "res://sources/utils/minigame_resources/log.gd" +}, { +"base": "Node", +"class": &"Logger", +"language": &"GDScript", +"path": "res://sources/utils/autoloads/lesson_logger.gd" +}, { +"base": "Node", +"class": &"State", +"language": &"GDScript", +"path": "res://sources/utils/state_machine/state.gd" +}, { +"base": "Node", +"class": &"StateMachine", +"language": &"GDScript", +"path": "res://sources/utils/state_machine/state_machine.gd" +}] +_global_script_class_icons={ +"GameGlobalData": "", +"LogResource": "", +"Logger": "", +"State": "", +"StateMachine": "" +} + +[application] + +config/name="Kalulu" +config/features=PackedStringArray("4.0", "Forward Plus") +config/icon="res://icon.svg" + +[autoload] + +GameGlobals="*res://sources/utils/autoloads/game_globals.gd" +LessonLogger="*res://sources/utils/autoloads/lesson_logger.gd" + +[display] + +window/size/viewport_width=2560 +window/size/viewport_height=1800 +window/size/window_width_override=1280 +window/size/window_height_override=900 diff --git a/sources/utils/autoloads/game_globals.gd b/sources/utils/autoloads/game_globals.gd new file mode 100644 index 00000000..af4ac91f --- /dev/null +++ b/sources/utils/autoloads/game_globals.gd @@ -0,0 +1,9 @@ +extends Node +class_name GameGlobalData + +var language: = "French" +var teacher_id: = "" +var user_id: = "" + +var minigame_difficulty: = 0 +var lesson_difficulty: = 0 diff --git a/sources/utils/autoloads/lesson_logger.gd b/sources/utils/autoloads/lesson_logger.gd new file mode 100644 index 00000000..708c0010 --- /dev/null +++ b/sources/utils/autoloads/lesson_logger.gd @@ -0,0 +1,31 @@ +extends Node +class_name Logger + +const log_resource_class: = preload("res://sources/utils/minigame_resources/log.gd") + +var log_resources: = {} + + +func save_logs(logs: Dictionary, teacher_id: String, user_id: String, minigame_name: String, lesson: String, time: String) -> void: + var file_path: = "user://" + teacher_id + "/" + user_id + "/" + minigame_name + ".tres" + + if not ResourceLoader.exists(file_path): + var log_resource: LogResource = log_resource_class.instance() + ResourceSaver.save(log_resource, file_path, ResourceSaver.FLAG_COMPRESS) + + if not file_path in log_resources: + var log_resource: = ResourceLoader.load(file_path) + log_resources[file_path] = log_resource + + if not log_resources[file_path].has(lesson): + log_resources[file_path][lesson] = {} + + if not log_resources[file_path][lesson].has(time): + log_resources[file_path][lesson][time] = logs + else: + var i: = 0 + while log_resources[file_path][lesson].has(time + "_" + str(i)): + i += 1 + log_resources[file_path][lesson][time + "_" + str(i)] = logs + + ResourceSaver.save(log_resources[file_path], file_path, ResourceSaver.FLAG_COMPRESS) diff --git a/sources/utils/minigame_resources/log.gd b/sources/utils/minigame_resources/log.gd new file mode 100644 index 00000000..28c5c925 --- /dev/null +++ b/sources/utils/minigame_resources/log.gd @@ -0,0 +1,4 @@ +extends Resource +class_name LogResource + +@export var logs: = {} diff --git a/sources/utils/state_machine/state.gd b/sources/utils/state_machine/state.gd new file mode 100644 index 00000000..3c59d175 --- /dev/null +++ b/sources/utils/state_machine/state.gd @@ -0,0 +1,34 @@ +extends Node +class_name State + +@export var can_be_previous: = true + +var state_machine: StateMachine + + +func _init() -> void: + add_to_group("state") + + +func enter_state(_msg: Dictionary = {}) -> void: + pass + + +func exit_state() -> void: + pass + + +func state_process(_delta: float) -> void: + pass + + +func state_physics_process(_delta: float) -> void: + pass + + +func state_unhandled_input(_event: InputEvent) -> void: + pass + + +func go_to_state(state_path: String, msg: Dictionary = {}) -> void: + state_machine.go_to_state(state_path, msg) diff --git a/sources/utils/state_machine/state_machine.gd b/sources/utils/state_machine/state_machine.gd new file mode 100644 index 00000000..75f9e489 --- /dev/null +++ b/sources/utils/state_machine/state_machine.gd @@ -0,0 +1,87 @@ +extends Node +class_name StateMachine + +signal state_changed(state_path, msg) + +@export_node_path(Node) var initial_state_path: NodePath + +var state: State = null +var current_msg: = {} +var previous_state: State = null +var previous_msg: = {} +var _is_active: = false +var is_active: = false: + get: return _get_is_active() + set(value): _set_is_active(value) + + +func _ready() -> void: + self.is_active = false + + var children: = get_children() + for node in children: + children.append_array(node.get_children()) + if node is State: + node.state_machine = self + + +func start() -> void: + go_to_state(initial_state_path) + self.is_active = true + + +func _process(delta: float) -> void: + if state: + state.state_process(delta) + + +func _physics_process(delta: float) -> void: + if state: + state.state_physics_process(delta) + + +func _unhandled_input(event: InputEvent) -> void: + if state: + state.state_unhandled_input(event) + + +func go_to_state(state_path: String, msg:= {}): + var new_state: State = null + if state_path == "Previous": + if previous_state == null: + push_error("No previous state at this point") + return + new_state = previous_state + for key in previous_msg.keys(): + if not msg.has(key): + msg[key] = previous_msg[key] + else: + if not has_node(state_path): + push_error("State not found :" + state_path) + return + new_state = get_node(state_path) + + if state and state.can_be_previous: + previous_msg = current_msg + previous_state = state + + if state: + state.exit_state() + + self.state = new_state + state.enter_state(msg) + current_msg = msg + + emit_signal("state_changed", state_path, msg) + + +func _set_is_active(value: bool) -> void: + _is_active = value + + set_process(value) + set_physics_process(value) + set_process_unhandled_input(value) + + +func _get_is_active() -> bool: + return _is_active