diff --git a/.vscode/settings.json b/.vscode/settings.json index 9191426..57efe6a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,3 @@ { - "godotTools.editorPath.godot4": "c:\\Users\\Malywan\\Desktop\\Godot\\Godot_v4.2.1-stable_mono_win64.exe" + "godotTools.editorPath.godot4": "c:\\Users\\Malywan\\Desktop\\Godot4.2\\Godot_v4.2.1-stable_mono_win64.exe" } \ No newline at end of file diff --git a/Core/Assets/Translation/main.csv b/Core/Assets/Translation/main.csv index dbb6bda..45482a3 100644 --- a/Core/Assets/Translation/main.csv +++ b/Core/Assets/Translation/main.csv @@ -82,3 +82,29 @@ HINT_IS_INVINCIBLE,wip,wip IS_LOOTABLE,Is lootable,Peut-être fouiller HINT_IS_LOOTABLE,wip,wip NEW_SKILL,New skill,Nouvelle compétence +ALL,All,Tous +ACTIVE,Active,Actif +PASSIVE,Passive,Passif +REACTIVE,Reactive,Réactif +SPECIAL,Special,Spécial +SKILL_TYPE,Skill type,Type de compétence +SKILL_TARGET,Skill target,Cible de la compétence +SKILL_COOLDOWN,Skill cooldown,Temps de recharge +SKILL_EFFECTS,Skill effects,Effets de compétence +SKILL_CONDITIONS,Skill conditions,Conditions +ADD,Add,Ajouter +CREATE,Create,Nouveau +SKILL,Skill,Compétence +SKILL_NAME,Skill name,Nom de la compétence +SKILL_DESCRIPTION,Skill description,Description de la compétence +OPEN_ADVANCED_EDITOR,Open the advanced text editor,Ouvrir l’éditeur de texte avancé +CHAR_NAME,Name,Prénom +CHAR_SURNAME,Surname,Nom +ALLY,Ally,Allié +ALLIES,Allies,Alliés +ENEMY,Enemy,Ennemi +ENEMIES,Enemies,Ennemis +SELF,Self,Soi +MS,ms,ms +SEC,sec,sec +MIN,min,min diff --git a/Core/Class/engine/history/history_skill.gd b/Core/Class/engine/history/history_skill.gd new file mode 100644 index 0000000..55bb294 --- /dev/null +++ b/Core/Class/engine/history/history_skill.gd @@ -0,0 +1,29 @@ +extends HistoryBase +class_name HistorySkill + +var skill_idx: String = "" +var edited_data: Dictionary = {} + +func _init(_action: EnumRegister.HistoryAction, _skill_idx: String, _edited_data: Dictionary = {}): + location = EnumRegister.HistoryLocation.DB_SKILL + action = _action + skill_idx = _skill_idx + edited_data = _edited_data + +func undo_change() -> void: + print("Undo changement to skill") + var skill: BaseSkill = SkillRegister.get_skill(skill_idx) + + for key in edited_data: + skill.set(key, edited_data[key]) + + SkillRegister.set_skill(skill_idx, skill) + +func redo_change() -> void: + print("Redo changement to skill") + var skill: BaseSkill = SkillRegister.get_skill(skill_idx) + + for key in edited_data: + skill.set(key, edited_data[key]) + + SkillRegister.set_skill(skill_idx, skill) \ No newline at end of file diff --git a/Core/Class/entities/Character.gd b/Core/Class/entities/Character.gd index 6a9e7fc..d8976d6 100644 --- a/Core/Class/entities/Character.gd +++ b/Core/Class/entities/Character.gd @@ -74,8 +74,8 @@ func is_enemy(_character: Character) -> bool: return true return false -func add_skill(_skill_name: String, _skill_lvl) -> void: - var skill = BaseSkill.new() - skill.name = _skill_name - skill.level = _skill_lvl +func add_skill(_skill_name: String) -> void: + var skill = SkillRegister.get_skill(_skill_name) + if skill == null: + return skills.append(skill) \ No newline at end of file diff --git a/Core/Class/skill.gd b/Core/Class/skill.gd index 064e957..a0f80a7 100644 --- a/Core/Class/skill.gd +++ b/Core/Class/skill.gd @@ -3,10 +3,11 @@ class_name BaseSkill const SkillTypes = EnumRegister.SkillTypes const SkillTarget = EnumRegister.SkillTarget +const SkillCooldownType = EnumRegister.SkillCooldownType +var id: String = "" # Skill's id var name: String = "" # Skill's name var description: String = "" # Skill's description -var level: int = 1 # Skill's level (For now, it's not used - It's different from the character's level!) var skill_type: SkillTypes = SkillTypes.ACTIVE # Skill's type var skill_target: SkillTarget = SkillTarget.SELF # Skill's target (self, ally, enemy, all) @@ -15,6 +16,7 @@ var skill_cost: Dictionary = {} # Skill's cost (ex: { "hp": 10, "mp": 5}) var skill_conditions: Array[BaseSkillCondition] = [] # Skill's conditions var skill_caster: Character = null # Skill's caster var skill_cooldown: int = 0 # Skill's cooldown +var skill_cooldown_type: SkillCooldownType = SkillCooldownType.MS # Skill's cooldown type # Function to use the skill # It should return true if the skill was used successfully, and false if it wasn't diff --git a/Core/Enums/gui/history/history_location.gd b/Core/Enums/gui/history/history_location.gd index b171761..1edd72c 100644 --- a/Core/Enums/gui/history/history_location.gd +++ b/Core/Enums/gui/history/history_location.gd @@ -3,5 +3,6 @@ enum HistoryLocation { NONE, DB_CHARACTERSLIST, DB_CHARACTER, - + DB_SKILLSLIST, + DB_SKILL, } \ No newline at end of file diff --git a/Core/Enums/skills/skill_cooldown_type.gd b/Core/Enums/skills/skill_cooldown_type.gd new file mode 100644 index 0000000..da049a3 --- /dev/null +++ b/Core/Enums/skills/skill_cooldown_type.gd @@ -0,0 +1,6 @@ + +enum SkillCooldownType { + MS, + SEC, + MIN, +} \ No newline at end of file diff --git a/Core/Registers/effect_register.gd b/Core/Registers/effect_register.gd new file mode 100644 index 0000000..3875bbf --- /dev/null +++ b/Core/Registers/effect_register.gd @@ -0,0 +1,89 @@ +extends Base +class_name EffectRegister +# This class is used to register all the effects in the game + +func _init(): + need_register = false # Set it to false to avoid registering this class in the class register + + set_custom_name("EffectRegister") + +static var data: Dictionary = {} + +static func set_effects(effects: Dictionary) -> void: + # Set the effects data + data = effects + +static func set_effect(effect_id: String, effect: BaseEffect) -> void: + # Set a effect data + data[effect_id] = effect + +static func get_effect(effect_id: String) -> BaseEffect: + # Get a effect data + return data[effect_id] + +static func get_all_effects() -> Dictionary: + # Get all effects data + return data + +static func get_all_effects_names() -> Array: + # Get all effects names + var names = [] + for effect in data.values(): + names.append(effect.name) + return names + +static func get_all_effects_ids() -> Array: + # Get all effects ids + return data.keys() + +static func get_all_effects_name_by_ids() -> Array: + # Get all effects names by ids + var names = [] + for effect_id in data.keys(): + names.append({"name": data[effect_id].name, "value": effect_id}) + return names + +static func remove_effect(effect_id: String) -> bool: + # Remove a effect data + return data.erase(effect_id) + +static func add_effect(effect: BaseEffect) -> String: + # Add a effect data + + # Check if the effect has an id, if not, generate one + if effect.id == "": + effect.id = IdGenerator.new().generate_id() + + var effect_id = effect.id + data[effect_id] = effect + return effect_id + +static func new_effect() -> BaseEffect: + # Create a new effect + + var id = IdGenerator.new().generate_id() + + var effect = BaseEffect.new() + + effect.id = id + effect.name = "New Effect" + effect.set_custom_name("Effect") + + add_effect(effect) + + return effect + +static func get_effect_by_name(name: String) -> BaseEffect: + # Get a effect by name + for effect in data.values(): + if effect.name == name: + return effect + return null + +static func effects_to_string() -> String: + # Convert the skills data to a string + return var_to_str(data) + +static func has_effect(effect_id: String) -> bool: + # Check if the effect exists + return data.has(effect_id) \ No newline at end of file diff --git a/Core/Registers/enum_register.gd b/Core/Registers/enum_register.gd index a0c71d2..c29f8a8 100644 --- a/Core/Registers/enum_register.gd +++ b/Core/Registers/enum_register.gd @@ -36,6 +36,7 @@ const EffectTarget = preload("res://Core/Enums/effects/effect_target.gd").Effect ## Skills const SkillTypes = preload("res://Core/Enums/skills/skill_types.gd").SkillTypes const SkillTarget = preload("res://Core/Enums/skills/skill_target.gd").SkillTarget +const SkillCooldownType = preload("res://Core/Enums/skills/skill_cooldown_type.gd").SkillCooldownType ## Objects const ObjectType = preload("res://Core/Enums/objects/object_type.gd").ObjectType ## Items diff --git a/Core/Registers/skill_register.gd b/Core/Registers/skill_register.gd new file mode 100644 index 0000000..5773781 --- /dev/null +++ b/Core/Registers/skill_register.gd @@ -0,0 +1,82 @@ +extends Base +class_name SkillRegister +# This class is used to register all the skills in the game + +func _init(): + need_register = false # Set it to false to avoid registering this class in the class register + + set_custom_name("SkillRegister") + +static var data: Dictionary = {} + +static func set_skills(skills: Dictionary) -> void: + # Set the skills data + data = skills + +static func set_skill(skill_id: String, skill: BaseSkill) -> void: + # Set a skill data + data[skill_id] = skill + +static func get_skill(skill_id: String) -> BaseSkill: + # Get a skill data + return data[skill_id] + +static func get_all_skills() -> Dictionary: + # Get all skills data + return data + +static func get_all_skills_names() -> Array: + # Get all skills names + var names = [] + for skill in data.values(): + names.append(skill.name) + return names + +static func get_all_skills_ids() -> Array: + # Get all skills ids + return data.keys() + +static func get_all_skills_name_by_ids() -> Array: + # Get all skills names by ids + var names = [] + for skill_id in data.keys(): + names.append({"name": data[skill_id].name, "value": skill_id}) + return names + +static func remove_skill(skill_id: String) -> bool: + # Remove a skill data + return data.erase(skill_id) + +static func add_skill(skill: BaseSkill) -> String: + # Add a skill data + + # Check if the skill has an id, if not, generate one + if skill.id == "": + skill.id = IdGenerator.new().generate_id() + + var skill_id = skill.id + data[skill_id] = skill + return skill_id + +static func new_skill() -> BaseSkill: + # Create a new skill + + var id: String = IdGenerator.new().generate_id() + + var skill = BaseSkill.new() + + skill.id = id + skill.name = "Skill" + skill.set_custom_name(id) + + add_skill(skill) + + return skill + +static func skills_to_string() -> String: + # Convert the skills data to a string + return var_to_str(data) + +static func has_skill(skill_id: String) -> bool: + # Check if a skill exists + return data.has(skill_id) \ No newline at end of file diff --git a/Core/Scenes/Tests/list_template_test.gd b/Core/Scenes/Tests/list_template_test.gd new file mode 100644 index 0000000..1c6a575 --- /dev/null +++ b/Core/Scenes/Tests/list_template_test.gd @@ -0,0 +1,18 @@ +extends CustomListTemplateBase + +var idx: String +var label: Label + + +func load(): # This function will be called first when the list is created. + label = get_node("Panel/MarginContainer/HBoxContainer/Label") + pass + +func set_data(_data: Dictionary): # This function will be called at third when the list is created. + + print(_data) + + label.text = _data["val"] + +func set_idx(_idx: String): # This function will be called at second when the list is created. The IDX is the unique id of the item. + idx = _idx \ No newline at end of file diff --git a/Core/Scenes/Utils/custom_list_v2.gd b/Core/Scenes/Utils/custom_list_v2.gd new file mode 100644 index 0000000..e846850 --- /dev/null +++ b/Core/Scenes/Utils/custom_list_v2.gd @@ -0,0 +1,27 @@ +extends VBoxContainer +class_name CustomListV2Base + +@onready var create_button: Button = get_node("MarginContainer2/menu/create") +@onready var add_button: Button = get_node("MarginContainer2/menu/add") +@onready var title_label: Label = get_node("TitleContainer/Title") +@onready var title_container: HBoxContainer = get_node("TitleContainer") + + +@export var show_create_button: bool = true +@export var show_add_button: bool = true +@export var show_title: bool = true + +@export var title: String = "Title" + +func _ready(): + + if !show_create_button: + create_button.hide() + + if !show_add_button: + add_button.hide() + + if !show_title: + title_container.hide() + + title_label.text = tr(title) \ No newline at end of file diff --git a/Core/Scenes/Utils/custom_list_v2.tscn b/Core/Scenes/Utils/custom_list_v2.tscn new file mode 100644 index 0000000..1eebc4a --- /dev/null +++ b/Core/Scenes/Utils/custom_list_v2.tscn @@ -0,0 +1,141 @@ +[gd_scene load_steps=5 format=3 uid="uid://cbboequg3adx8"] + +[ext_resource type="Script" path="res://Core/Scenes/Utils/custom_list_v2.gd" id="1_53hc0"] +[ext_resource type="Script" path="res://Core/Scenes/Utils/custom_template_list.gd" id="1_kj0b2"] +[ext_resource type="Script" path="res://Core/Scenes/Tests/list_template_test.gd" id="2_pn0k4"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_1oldo"] +bg_color = Color(0.6, 0.6, 0.6, 0.0823529) +border_width_bottom = 1 +border_color = Color(0.466181, 0.466181, 0.466181, 0.141176) +corner_radius_top_left = 4 +corner_radius_top_right = 4 +corner_radius_bottom_right = 4 +corner_radius_bottom_left = 4 + +[node name="customListV2" type="VBoxContainer"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 +script = ExtResource("1_53hc0") + +[node name="TitleContainer" type="HBoxContainer" parent="."] +layout_mode = 2 + +[node name="HSeparator" type="HSeparator" parent="TitleContainer"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="Title" type="Label" parent="TitleContainer"] +layout_mode = 2 +text = "Title" +horizontal_alignment = 1 +vertical_alignment = 1 + +[node name="HSeparator2" type="HSeparator" parent="TitleContainer"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="MarginContainer2" type="MarginContainer" parent="."] +layout_mode = 2 + +[node name="menu" type="HBoxContainer" parent="MarginContainer2"] +layout_mode = 2 + +[node name="search" type="LineEdit" parent="MarginContainer2/menu"] +layout_mode = 2 +size_flags_horizontal = 3 +placeholder_text = "SEARCH" + +[node name="add" type="Button" parent="MarginContainer2/menu"] +layout_mode = 2 +text = "ADD" + +[node name="create" type="Button" parent="MarginContainer2/menu"] +layout_mode = 2 +text = "CREATE" + +[node name="MarginContainer" type="MarginContainer" parent="."] +layout_mode = 2 +size_flags_vertical = 3 +theme_override_constants/margin_left = 0 +theme_override_constants/margin_right = 0 +theme_override_constants/margin_bottom = 0 + +[node name="Panel" type="Panel" parent="MarginContainer"] +layout_mode = 2 + +[node name="MarginContainer" type="MarginContainer" parent="MarginContainer/Panel"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_constants/margin_left = 8 +theme_override_constants/margin_top = 6 +theme_override_constants/margin_right = 8 +theme_override_constants/margin_bottom = 6 + +[node name="ScrollContainer" type="ScrollContainer" parent="MarginContainer/Panel/MarginContainer"] +layout_mode = 2 + +[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer/Panel/MarginContainer/ScrollContainer" node_paths=PackedStringArray("template")] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 +script = ExtResource("1_kj0b2") +template = NodePath("list_template") +rows = Array[Dictionary]([]) + +[node name="list_template" type="HBoxContainer" parent="MarginContainer/Panel/MarginContainer/ScrollContainer/VBoxContainer"] +custom_minimum_size = Vector2(0, 30) +layout_mode = 2 +script = ExtResource("2_pn0k4") + +[node name="Panel" type="Panel" parent="MarginContainer/Panel/MarginContainer/ScrollContainer/VBoxContainer/list_template"] +clip_contents = true +layout_mode = 2 +size_flags_horizontal = 3 +theme_override_styles/panel = SubResource("StyleBoxFlat_1oldo") + +[node name="MarginContainer" type="MarginContainer" parent="MarginContainer/Panel/MarginContainer/ScrollContainer/VBoxContainer/list_template/Panel"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_constants/margin_left = 5 +theme_override_constants/margin_right = 5 + +[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/Panel/MarginContainer/ScrollContainer/VBoxContainer/list_template/Panel/MarginContainer"] +layout_mode = 2 + +[node name="Label" type="Label" parent="MarginContainer/Panel/MarginContainer/ScrollContainer/VBoxContainer/list_template/Panel/MarginContainer/HBoxContainer"] +layout_mode = 2 +text = "Test" + +[node name="ADD_NEW_OBJECT_WINDOW" type="ConfirmationDialog" parent="."] +title = "Please choose..." +initial_position = 1 +size = Vector2i(550, 300) +min_size = Vector2i(550, 300) + +[node name="VBoxContainer" type="VBoxContainer" parent="ADD_NEW_OBJECT_WINDOW"] +offset_left = 8.0 +offset_top = 8.0 +offset_right = 542.0 +offset_bottom = 251.0 + +[node name="LineEdit" type="LineEdit" parent="ADD_NEW_OBJECT_WINDOW/VBoxContainer"] +layout_mode = 2 +placeholder_text = "SEARCH" + +[node name="VBoxContainer" type="VBoxContainer" parent="ADD_NEW_OBJECT_WINDOW/VBoxContainer"] +layout_mode = 2 diff --git a/Core/Scenes/Utils/custom_template_list.gd b/Core/Scenes/Utils/custom_template_list.gd new file mode 100644 index 0000000..171b484 --- /dev/null +++ b/Core/Scenes/Utils/custom_template_list.gd @@ -0,0 +1,317 @@ +extends VBoxContainer +## This class is used to create a list with a custom template provided by the user.[br] +## +## [color=yellow]!!! Please read before doing anything !!![br]This class is very sensitive to errors, make sure to follow the instructions carefully. If you don't and catch an error, the list will simply be removed from the scene tree.[/color][br] +## [br] +## [b]How to use:[/b][br] +## - Create a new scene[br] +## - Add a new VBoxContainer node[br] +## - Add this script to the node[br] +## - Set the template to the template you want to use (the template needs to have a script that extends the custom_list_template_base.gd)[br] +## - Set the rows to the rows you want to use - You can let it empty if you don't want to use the row system[br] +## - Save the scene[br] +## - Add the scene to the scene tree[br] +## - Done![br] +## [br] +## [b]How to create a new template:[/b][br] +## - Create a new scene[br] +## - Add a new Control node[br] +## - Add a new script to the node[br] +## - In the script, extend the custom_list_template_base.gd[br] +## - Implement all the functions found in the custom_list_template_base.gd[br] +## - Save the scene[br] +## - Done![br] +## [br] +## [b]How to create a new row:[/b][br] +## - Add a new row to the rows array[br] +## - The row needs to have the following data:[br] +## . - name: The name of the row - [String][br] +## . - metadata: The metadata of the row - [Dictionary][br] +## . - type: The type of the row - [enum List.ItemType][br] +## . - (optional) centered: If the row is centered - [bool][br] +## . - (optional) percentage_size: The percentage size of the row (from 0 to 1) - [float][br] +## - If you don't want to use the row system, you can simply let this empty.[br] +## - Done![br] +## [br] + + +## This template node.[br] +## The template need to have a script that extends the custom_list_template_base.gd[br] +## The script need to have ALL the functions found in the custom_list_template_base.gd implemented! +@export var template: Node = null + +## The list rows [br] +## Each row needs the following data:[br] +## - name: The name of the row - [String][br] +## - metadata: The metadata of the row - [Dictionary][br] +## - type: The type of the row - [enum List.ItemType][br] +## - (optional) centered: If the row is centered - [bool][br] +## - (optional) percentage_size: The percentage size of the row (from 0 to 1) - [float][br] +## [br] +## If you don't want to use the row system, you can simply let this empty. +@export var rows: Array[Dictionary] = [{}] + +## [b][color=red]Internal variable, do not touch.[/color][/b][br][br] +## The list node.[br] +## This is the node that will contain all the rows. +var list: VBoxContainer +## [b][color=red]Internal variable, do not touch.[/color][/b][br][br] +## The scroll node.[br] +## This is the node that will contain the list. +var scroll: ScrollContainer +## [b][color=red]Internal variable, do not touch.[/color][/b][br][br] +## The data of the list.[br] +## This is the data that will be shown in the list. +var data: Dictionary = {} +## [b][color=red]Internal variable, do not touch.[/color][/b][br][br] +## This will determine if the list is working (all check are done and valid, if not, set to true).[br] +var not_working: bool = false + + +# Called when the node enters the scene tree for the first time. +func _ready(): + + # Check if the template is valid. + if !_check_template(): + push_error("The template is invalid.") + not_working = true + + # Check if the rows are valid. + if !_check_rows(): + push_error("The rows are invalid.") + not_working = true + + # hide the template + template.hide() + + # Create the list. + _create_list() + + # Create the row. (If any) + _create_row() + +func _check_template(): + # Check if the template is a valid node. + if template == null: + push_error("The template is missing.") + return false + + # Check if the template is a valid node. + if !template.is_class("Control"): + push_error("The template is not a valid Control.") + return false + + if template.get_script() == null: + push_error("The template doesn't have a script.") + return false + + var script: Script = template.get_script() + + if script.get_base_script() == null: + push_error("The template script doesn't have a base script.") + return false + + var base_script: Script = script.get_base_script() + + if base_script.get_path() != "res://Core/gui/CustomListTemplate/custom_list_template_base.gd": + push_error("The template script doesn't have the correct base script.") + return false + + + # Check if the template has a _init function without arguments. (If no _init function is found, we don't care) + for i in script.get_method_list(): + if i.name != "_init": # We only want to check the _init function here. + continue + + # We don't want any arguments in the _init function. This is not allowed due to the fact that we will duplicate the template. + if i.args.size() > 0: + push_error("The template script has the _init function with arguments. This is not allowed.") + return false + + return true + +func _check_rows(): + for i in rows: + if !i.has("name"): + push_error("The row ",i," doesn't have a name.") + return false + + # Check if the name is a string. + if !typeof(i["name"]) == TYPE_STRING: + push_error("The row ",i," name is not a string.") + return false + + if !i.has("metadata"): + push_error("The row ",i," doesn't have metadata.") + return false + + # Check if the metadata is a dictionary. + if !typeof(i["metadata"]) == TYPE_DICTIONARY: + push_error("The row ",i," metadata is not a dictionary.") + return false + + if !i.has("type"): + push_error("The row ",i," doesn't have a type.") + return false + + # Check if the type is an integer. + if !typeof(i["type"]) == TYPE_INT: + push_error("The row ",i," type is not an integer.") + return false + + # Check if the type is valid. + if i["type"] < 0 or i["type"] > List.ItemType.MAX: + push_error("The row ",i," type is invalid.") + return false + + if i.has('centered'): + if !typeof(i["centered"]) == TYPE_BOOL: + push_error("The row ",i," centered is not a boolean.") + return false + else: + i["centered"] = false + + if i.has('percentage_size'): + if !typeof(i["percentage_size"]) == TYPE_FLOAT: + push_error("The row ",i," percentage_size is not a float.") + return false + else: + i["percentage_size"] = 1.0 + + return true +## This function is used to create the list.[br] +## This will create the list and scroll and add them to the node. [br] +## This will also set the anchors of the scroll. And set the size flags of the list.[br] +## [br] +## [b][color=red]Internal function, do not touch.[/color][/b] +func _create_list(): + + if not_working: + return + + # Create the list. + list = VBoxContainer.new() + scroll = ScrollContainer.new() + + # Add the list to the scroll. + scroll.add_child(list) + + # Add the scroll to the node. + add_child(scroll) + + # Set the anchors. + scroll.set_anchors_preset(Control.PRESET_FULL_RECT) + scroll.size_flags_vertical = Control.SIZE_EXPAND_FILL + scroll.size_flags_horizontal = Control.SIZE_EXPAND_FILL + list.size_flags_vertical = Control.SIZE_EXPAND_FILL + list.size_flags_horizontal = Control.SIZE_EXPAND_FILL + +func _create_row(): + + if not_working: + return + + + # Check if their is any rows. + if rows.size() == 0: + # No rows found. + # This means the user doesn't want to use the row system. + # We will simply return. + return + + # Create the row. + var _row: HBoxContainer = HBoxContainer.new() + + # Add the row to the list. + list.add_child(_row) + + # Set the anchors. + _row.size_flags_horizontal = Control.SIZE_EXPAND_FILL + + # Add labels to the row. + for i in rows: + var _label: Label = Label.new() + _label.text = i["name"] + if i["centered"]: + _label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER + + _label.size_flags_horizontal = Control.SIZE_EXPAND_FILL + _label.size_flags_stretch_ratio = i["percentage_size"] + _row.add_child(_label) + +func remove_item(idx: String): + + if not_working: + return + + # Check if the item exists. + if !data.has(idx): + push_error("The item ",idx," doesn't exist.") + return + + # Get the item. + var _item: __TemplateItem = data[idx] + + # Get the index of the item. + var id_list = _item.id_list + + # Remove the item from the list. + list.remove_child(id_list) + + # Remove the item from the data. + data.erase(idx) + + # Update the id_list of the items. + for i in data: + if data[i].id_list > id_list: + data[i].id_list -= 1 + +func add_item(_data: Dictionary): + + if not_working: + return + + + var id = IdGenerator.new().generate_id() + + # Create the item. + var _item: __TemplateItem = __TemplateItem.new() + # Set the id of the item. This will not change. + _item.id = id + # Set the data of the item. + _item.data = _data + + # Create a new row with the template + var _template: Control = template.duplicate() + + # Load the template. + _template.load() + + # Set the unique id of the item in the template. + _template.set_idx(id) + + # Set the data of the item in the template. + _template.set_data(_data) + + # Add the row to the list. + list.add_child(_template) + + # Set the id of the list. + _item.template_node = _template + + # Show the template + _template.show() + + # Add the item to the list + data[id] = _item + +# Class of the row +class Row: + var name: String + var metadata: Dictionary + var type: List.ItemType + +class __TemplateItem: + var id: String ## The id of the item (This will not change once set) + var template_node: Control ## The control of the list - This is used to identify where in the list the item is + var data: Dictionary = {} ## The data of the item \ No newline at end of file diff --git a/Core/Scenes/database/database.gd b/Core/Scenes/database/database.gd index 4456e8f..ea839fa 100644 --- a/Core/Scenes/database/database.gd +++ b/Core/Scenes/database/database.gd @@ -1,5 +1,10 @@ extends Control +const button_group_path = "res://Core/Scenes/database/ButtonGroup/LeftMenu.tres" + +func _init(): + + await _test_load_skill_from_db() # Called when the node enters the scene tree for the first time. func _ready(): @@ -10,10 +15,28 @@ func _ready(): # %Button4.connect("pressed", _on_generate_id) %ApplyDB.pressed.connect(_on_apply_changes) %CancelDB.pressed.connect(_on_load_file) + + + var button_group: ButtonGroup = %MenuEntities.button_group + button_group.pressed.connect(_on_menu_button_pressed) pass # Replace with function body. +func _test_load_skill_from_db(): + var storage = JsonStorage.new() + + var data = storage.get_all_data("Skills", "Skills") + + print(data) + + if data == null: + return + + for key in data: + var skill: BaseSkill = data[key] + SkillRegister.add_skill(skill) + func _on_load_file(): var storage = JsonStorage.new() @@ -53,6 +76,7 @@ func _on_apply_changes(): _save_box_entities() + _save_box_skills() pass @@ -62,4 +86,21 @@ func _save_box_entities(): var storage = JsonStorage.new() var return_data = storage.store_all_data(characters, "Entities", "Characters") - print("Data saved: ", return_data) + print("char_data saved: ", return_data) + +func _save_box_skills(): + var skills = SkillRegister.skills_to_string() + + var storage = JsonStorage.new() + + var return_data = storage.store_all_data(skills, "Skills", "Skills") + print("skill_data saved: ", return_data) + +func _on_menu_button_pressed(button: Button): + match(button.text): + "CHARACTERS": + %BoxEntities.show() + %BoxSkills.hide() + "SKILLS": + %BoxEntities.hide() + %BoxSkills.show() \ No newline at end of file diff --git a/Core/Scenes/database/database.tscn b/Core/Scenes/database/database.tscn index 6efd362..494095a 100644 --- a/Core/Scenes/database/database.tscn +++ b/Core/Scenes/database/database.tscn @@ -1,10 +1,11 @@ -[gd_scene load_steps=6 format=3 uid="uid://y13b3lbbj0m5"] +[gd_scene load_steps=7 format=3 uid="uid://y13b3lbbj0m5"] [ext_resource type="Theme" uid="uid://dxvkgbhgl3ilx" path="res://Core/Scenes/database/theme.tres" id="1_2ixfr"] [ext_resource type="Script" path="res://Core/Scenes/database/database.gd" id="1_w0qjs"] [ext_resource type="ButtonGroup" uid="uid://yfyf2jwsp5fg" path="res://Core/Scenes/database/ButtonGroup/LeftMenu.tres" id="2_p64cy"] [ext_resource type="StyleBox" uid="uid://dwaq4cefo31uo" path="res://Core/Scenes/database/ButtonGroup/buttonStyle-Focus.tres" id="3_lgoj1"] -[ext_resource type="PackedScene" uid="uid://lk3g8g6myah2" path="res://Core/Scenes/database/box_entities.tscn" id="5_7wih8"] +[ext_resource type="PackedScene" uid="uid://lk3g8g6myah2" path="res://Core/Scenes/database/entities/box_entities.tscn" id="5_7wih8"] +[ext_resource type="PackedScene" uid="uid://cvtt8ib4u0y2i" path="res://Core/Scenes/database/skills/box_skills.tscn" id="6_50rxi"] [node name="Database" type="Control"] layout_mode = 3 @@ -54,10 +55,18 @@ unique_name_in_owner = true layout_mode = 2 theme_override_styles/focus = ExtResource("3_lgoj1") toggle_mode = true -button_pressed = true button_group = ExtResource("2_p64cy") text = "CHARACTERS" +[node name="MenuSkills" type="Button" parent="VBoxContainer/HBoxContainer/page_menu/scroll/MenuContent"] +unique_name_in_owner = true +layout_mode = 2 +theme_override_styles/focus = ExtResource("3_lgoj1") +toggle_mode = true +button_pressed = true +button_group = ExtResource("2_p64cy") +text = "SKILLS" + [node name="MenuItem" type="Button" parent="VBoxContainer/HBoxContainer/page_menu/scroll/MenuContent"] unique_name_in_owner = true layout_mode = 2 @@ -98,9 +107,14 @@ theme_override_constants/margin_bottom = 4 [node name="BoxEntities" parent="VBoxContainer/HBoxContainer/page_content" instance=ExtResource("5_7wih8")] unique_name_in_owner = true +visible = false layout_mode = 2 theme_override_constants/separation = 0 +[node name="BoxSkills" parent="VBoxContainer/HBoxContainer/page_content" instance=ExtResource("6_50rxi")] +unique_name_in_owner = true +layout_mode = 2 + [node name="HSeparator" type="HSeparator" parent="VBoxContainer"] custom_minimum_size = Vector2(0, 1) layout_mode = 2 diff --git a/Core/Scenes/database/box_entities.tscn b/Core/Scenes/database/entities/box_entities.tscn similarity index 95% rename from Core/Scenes/database/box_entities.tscn rename to Core/Scenes/database/entities/box_entities.tscn index d516c87..624b3a0 100644 --- a/Core/Scenes/database/box_entities.tscn +++ b/Core/Scenes/database/entities/box_entities.tscn @@ -2,7 +2,7 @@ [ext_resource type="PackedScene" uid="uid://grljyoauhhtn" path="res://Core/Scenes/database/custom_list.tscn" id="1_1gsb4"] [ext_resource type="Script" path="res://Core/gui/BoxDB/box_entities.gd" id="1_u07jm"] -[ext_resource type="PackedScene" uid="uid://bqk3n33rqfdbm" path="res://Core/Scenes/database/info_entities.tscn" id="2_fdx10"] +[ext_resource type="PackedScene" uid="uid://bqk3n33rqfdbm" path="res://Core/Scenes/database/entities/info_entities.tscn" id="2_fdx10"] [node name="BoxEntities" type="HBoxContainer"] script = ExtResource("1_u07jm") diff --git a/Core/Scenes/database/info_entities.tscn b/Core/Scenes/database/entities/info_entities.tscn similarity index 100% rename from Core/Scenes/database/info_entities.tscn rename to Core/Scenes/database/entities/info_entities.tscn diff --git a/Core/Scenes/database/skills/box_skills.tscn b/Core/Scenes/database/skills/box_skills.tscn new file mode 100644 index 0000000..39967a8 --- /dev/null +++ b/Core/Scenes/database/skills/box_skills.tscn @@ -0,0 +1,62 @@ +[gd_scene load_steps=3 format=3 uid="uid://cvtt8ib4u0y2i"] + +[ext_resource type="PackedScene" uid="uid://c7tox0cp02ni7" path="res://Core/Scenes/database/skills/skill_list.tscn" id="1_a43cr"] +[ext_resource type="PackedScene" uid="uid://buoab2o2hrttm" path="res://Core/Scenes/database/skills/info_skills.tscn" id="2_5onr0"] + +[node name="BoxSkills" type="HBoxContainer"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="HSplitContainer" type="HSplitContainer" parent="."] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="left" type="VBoxContainer" parent="HSplitContainer"] +custom_minimum_size = Vector2(300, 0) +layout_mode = 2 + +[node name="searchForSkills" type="LineEdit" parent="HSplitContainer/left"] +unique_name_in_owner = true +layout_mode = 2 +placeholder_text = "SEARCH" + +[node name="skillList" parent="HSplitContainer/left" instance=ExtResource("1_a43cr")] +unique_name_in_owner = true +layout_mode = 2 + +[node name="addSkill" type="Button" parent="HSplitContainer/left"] +layout_mode = 2 +text = "ADD_NEW_SKILL" + +[node name="right" type="VBoxContainer" parent="HSplitContainer"] +custom_minimum_size = Vector2(600, 0) +layout_mode = 2 + +[node name="Panel" type="Panel" parent="HSplitContainer/right"] +layout_mode = 2 +size_flags_vertical = 3 + +[node name="MarginContainer" type="MarginContainer" parent="HSplitContainer/right/Panel"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_constants/margin_left = 4 +theme_override_constants/margin_top = 4 +theme_override_constants/margin_right = 4 +theme_override_constants/margin_bottom = 4 + +[node name="ScrollContainer" type="ScrollContainer" parent="HSplitContainer/right/Panel/MarginContainer"] +layout_mode = 2 + +[node name="infoSkills" parent="HSplitContainer/right/Panel/MarginContainer/ScrollContainer" instance=ExtResource("2_5onr0")] +layout_mode = 2 + +[connection signal="item_clicked" from="HSplitContainer/left/skillList" to="HSplitContainer/right/Panel/MarginContainer/ScrollContainer/infoSkills" method="_on_skill_list_item_clicked"] +[connection signal="pressed" from="HSplitContainer/left/addSkill" to="HSplitContainer/left/skillList" method="_on_add_skill_pressed"] +[connection signal="skill_renamed" from="HSplitContainer/right/Panel/MarginContainer/ScrollContainer/infoSkills" to="HSplitContainer/left/skillList" method="_on_info_skills_skill_renamed"] diff --git a/Core/Scenes/database/skills/info_skills.tscn b/Core/Scenes/database/skills/info_skills.tscn new file mode 100644 index 0000000..4fe1e7b --- /dev/null +++ b/Core/Scenes/database/skills/info_skills.tscn @@ -0,0 +1,130 @@ +[gd_scene load_steps=9 format=3 uid="uid://buoab2o2hrttm"] + +[ext_resource type="PackedScene" uid="uid://n5xa418dln6i" path="res://Core/Scenes/database/info_item_text.tscn" id="1_d5pqn"] +[ext_resource type="Script" path="res://Core/gui/InfoDB/skills/info_skills.gd" id="1_tisth"] +[ext_resource type="Script" path="res://Core/gui/InfoDB/child/info_item_lineedit.gd" id="2_vx3kh"] +[ext_resource type="Script" path="res://Core/gui/InfoDB/child/info_item_textedit.gd" id="3_h5602"] +[ext_resource type="Script" path="res://Core/gui/InfoDB/child/info_item_options.gd" id="4_pjtjx"] +[ext_resource type="Script" path="res://Core/gui/InfoDB/child/info_item_spinbox.gd" id="5_vwtvh"] +[ext_resource type="PackedScene" uid="uid://cbboequg3adx8" path="res://Core/Scenes/Utils/custom_list_v2.tscn" id="5_wlsgd"] +[ext_resource type="Script" path="res://Core/gui/List/Skill/effect_list.gd" id="6_gr7v8"] + +[node name="infoSkills" type="VBoxContainer"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 +script = ExtResource("1_tisth") + +[node name="TabContainer" type="TabContainer" parent="."] +layout_mode = 2 +size_flags_vertical = 3 + +[node name="DETAILS" type="MarginContainer" parent="TabContainer"] +layout_mode = 2 +theme_override_constants/margin_left = 4 +theme_override_constants/margin_top = 4 +theme_override_constants/margin_right = 4 +theme_override_constants/margin_bottom = 4 + +[node name="VBoxContainer" type="VBoxContainer" parent="TabContainer/DETAILS"] +layout_mode = 2 + +[node name="infoID" parent="TabContainer/DETAILS/VBoxContainer" instance=ExtResource("1_d5pqn")] +unique_name_in_owner = true +layout_mode = 2 +label_name = "ID" +content = "NaN" + +[node name="HBoxContainer" type="HBoxContainer" parent="TabContainer/DETAILS/VBoxContainer"] +layout_mode = 2 + +[node name="infoName" type="HBoxContainer" parent="TabContainer/DETAILS/VBoxContainer/HBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +script = ExtResource("2_vx3kh") +label_name = "SKILL_NAME" +content = "NaN" + +[node name="infoDesc" type="VBoxContainer" parent="TabContainer/DETAILS/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 +script = ExtResource("3_h5602") +label_name = "SKILL_DESCRIPTION" + +[node name="SKILL" type="MarginContainer" parent="TabContainer"] +visible = false +layout_mode = 2 +theme_override_constants/margin_left = 4 +theme_override_constants/margin_top = 4 +theme_override_constants/margin_right = 4 +theme_override_constants/margin_bottom = 4 + +[node name="VBoxContainer" type="VBoxContainer" parent="TabContainer/SKILL"] +layout_mode = 2 + +[node name="HBoxContainer" type="HBoxContainer" parent="TabContainer/SKILL/VBoxContainer"] +layout_mode = 2 + +[node name="infoType" type="HBoxContainer" parent="TabContainer/SKILL/VBoxContainer/HBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +script = ExtResource("4_pjtjx") +label_name = "SKILL_TYPE" + +[node name="infoTarget" type="HBoxContainer" parent="TabContainer/SKILL/VBoxContainer/HBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +script = ExtResource("4_pjtjx") +label_name = "SKILL_TARGET" + +[node name="HBoxContainer3" type="HBoxContainer" parent="TabContainer/SKILL/VBoxContainer"] +layout_mode = 2 + +[node name="infoCooldown" type="HBoxContainer" parent="TabContainer/SKILL/VBoxContainer/HBoxContainer3"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +script = ExtResource("5_vwtvh") +label_name = "SKILL_COOLDOWN" +suffix = "MS" + +[node name="cooldown_time_type" type="OptionButton" parent="TabContainer/SKILL/VBoxContainer/HBoxContainer3"] +unique_name_in_owner = true +layout_mode = 2 +selected = 0 + +[node name="HBoxContainer2" type="HBoxContainer" parent="TabContainer/SKILL/VBoxContainer"] +layout_mode = 2 + +[node name="infoEffects" parent="TabContainer/SKILL/VBoxContainer/HBoxContainer2" instance=ExtResource("5_wlsgd")] +unique_name_in_owner = true +custom_minimum_size = Vector2(0, 300) +layout_mode = 2 +script = ExtResource("6_gr7v8") +title = "SKILL_EFFECTS" + +[node name="MarginContainer" type="MarginContainer" parent="TabContainer/SKILL/VBoxContainer/HBoxContainer2"] +layout_mode = 2 + +[node name="infoConditions" parent="TabContainer/SKILL/VBoxContainer/HBoxContainer2" instance=ExtResource("5_wlsgd")] +unique_name_in_owner = true +custom_minimum_size = Vector2(0, 300) +layout_mode = 2 +script = ExtResource("6_gr7v8") +title = "SKILL_CONDITIONS" + +[connection signal="content_changed" from="TabContainer/DETAILS/VBoxContainer/HBoxContainer/infoName" to="." method="_on_info_name_content_changed"] +[connection signal="content_changed" from="TabContainer/DETAILS/VBoxContainer/infoDesc" to="." method="_on_info_desc_content_changed"] +[connection signal="content_changed" from="TabContainer/SKILL/VBoxContainer/HBoxContainer/infoType" to="." method="_on_info_type_content_changed"] +[connection signal="content_changed" from="TabContainer/SKILL/VBoxContainer/HBoxContainer/infoTarget" to="." method="_on_info_target_content_changed"] +[connection signal="content_changed" from="TabContainer/SKILL/VBoxContainer/HBoxContainer3/infoCooldown" to="." method="_on_info_cooldown_content_changed"] +[connection signal="item_selected" from="TabContainer/SKILL/VBoxContainer/HBoxContainer3/cooldown_time_type" to="." method="_on_cooldown_time_type_item_selected"] diff --git a/Core/Scenes/database/skills/skill_list.tscn b/Core/Scenes/database/skills/skill_list.tscn new file mode 100644 index 0000000..f897c1e --- /dev/null +++ b/Core/Scenes/database/skills/skill_list.tscn @@ -0,0 +1,61 @@ +[gd_scene load_steps=4 format=3 uid="uid://c7tox0cp02ni7"] + +[ext_resource type="Script" path="res://Core/gui/database/Skill/skill_list.gd" id="1_6kfvn"] +[ext_resource type="Script" path="res://Core/gui/CustomList/customList.gd" id="2_i6jh5"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_qa2ts"] +bg_color = Color(0.6, 0.6, 0.6, 0) + +[node name="skillList" type="TabContainer" node_paths=PackedStringArray("all_list", "active_list", "passive_list", "reactive_list", "special_list")] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +size_flags_vertical = 3 +theme_override_styles/panel = SubResource("StyleBoxFlat_qa2ts") +script = ExtResource("1_6kfvn") +all_list = NodePath("ALL") +active_list = NodePath("ACTIVE") +passive_list = NodePath("PASSIVE") +reactive_list = NodePath("REACTIVE") +special_list = NodePath("SPECIAL") + +[node name="ALL" type="Panel" parent="."] +layout_mode = 2 +script = ExtResource("2_i6jh5") +db_index_name = "" +db_context = "" +db_char_list_key = "" + +[node name="ACTIVE" type="Panel" parent="."] +visible = false +layout_mode = 2 +script = ExtResource("2_i6jh5") +db_index_name = "" +db_context = "" +db_char_list_key = "" + +[node name="PASSIVE" type="Panel" parent="."] +visible = false +layout_mode = 2 +script = ExtResource("2_i6jh5") +db_index_name = "" +db_context = "" +db_char_list_key = "" + +[node name="REACTIVE" type="Panel" parent="."] +visible = false +layout_mode = 2 +script = ExtResource("2_i6jh5") +db_index_name = "" +db_context = "" +db_char_list_key = "" + +[node name="SPECIAL" type="Panel" parent="."] +visible = false +layout_mode = 2 +script = ExtResource("2_i6jh5") +db_index_name = "" +db_context = "" +db_char_list_key = "" diff --git a/Core/gui/Class/ListData.gd b/Core/gui/Class/ListData.gd index 30a8e62..725dbcd 100644 --- a/Core/gui/Class/ListData.gd +++ b/Core/gui/Class/ListData.gd @@ -5,7 +5,9 @@ enum ItemType { TEXT, IMAGE, BUTTON, - CHECKBOX + CHECKBOX, + OPTION_BUTTON, + MAX } var rows: Array = [] @@ -39,8 +41,8 @@ func add_item(item_content: Array, item_name: String = "", _item_metadata: Dicti var listItem = ListItem.new(item_name, rows_type) - listItem.set_content(item_content) listItem.add_metadatas(_item_metadata) + listItem.set_content(item_content) items.append(listItem) diff --git a/Core/gui/Class/ListItemData.gd b/Core/gui/Class/ListItemData.gd index 338f014..2936a3c 100644 --- a/Core/gui/Class/ListItemData.gd +++ b/Core/gui/Class/ListItemData.gd @@ -4,7 +4,8 @@ enum ItemType { TEXT, IMAGE, BUTTON, - CHECKBOX + CHECKBOX, + OPTION_BUTTON } var name: String = "" @@ -73,6 +74,14 @@ func set_content(_content: Array): else: push_error("Invalid content type") return + ItemType.OPTION_BUTTON: + if typeof(object) == TYPE_STRING: + content.append(object.to_int()) + elif typeof(object) == TYPE_INT: + content.append(object) + else: + push_error("Invalid content type") + return func get_content() -> Array: return content diff --git a/Core/gui/CustomList/child/list_item_text.gd b/Core/gui/CustomList/child/list_item_text.gd new file mode 100644 index 0000000..12742cf --- /dev/null +++ b/Core/gui/CustomList/child/list_item_text.gd @@ -0,0 +1,3 @@ + +class_name CustomListItemText + diff --git a/Core/gui/CustomList/customList.gd b/Core/gui/CustomList/customList.gd index 8db6b54..dc0f038 100644 --- a/Core/gui/CustomList/customList.gd +++ b/Core/gui/CustomList/customList.gd @@ -10,10 +10,12 @@ var list_node: Dictionary = {} const itemList_NodePath: String = "res://Core/Scenes/database/custom_list_item.tscn" signal item_clicked(node: Node, name: String, metadata: Dictionary) +signal option_chosen(option: String, option_button: OptionButton) -var db_index_name: String = "char_idx" # The name of the index in the database -var db_context: String = "box_entities" # The context of the database -var db_char_list_key: String = "characters_list" # The key to access the list of characters in the database + +@export var db_index_name: String = "char_idx" # The name of the index in the database +@export var db_context: String = "box_entities" # The context of the database +@export var db_char_list_key: String = "characters_list" # The key to access the list of characters in the database var origin: String = "CustomList" # The origin of the data @@ -32,14 +34,53 @@ func _init(): func _ready(): - rows = %row_cat - list = %list_content - var data: Dictionary = list_object.get_list_property() + if get_child_count() == 0: + print("The list node is missing.") + print("Creating a new list node.") + + _create_body() + return + + rows = %row_cat + list = %list_content + if data.size() == 0: return + +func _create_body(): + var margin = MarginContainer.new() + var vbox = VBoxContainer.new() + var row_box = HBoxContainer.new() + var scroll = ScrollContainer.new() + var list_box = VBoxContainer.new() + + margin.add_child(vbox) + vbox.add_child(row_box) + vbox.add_child(scroll) + scroll.add_child(list_box) + + margin.add_theme_constant_override("margin_left", 4) + margin.add_theme_constant_override("margin_top", 4) + margin.add_theme_constant_override("margin_right", 4) + margin.add_theme_constant_override("margin_bottom", 4) + + + add_child(margin) + + margin.set_anchors_preset(Control.PRESET_FULL_RECT) + + scroll.size_flags_vertical = Control.SIZE_EXPAND_FILL + + list_box.size_flags_vertical = Control.SIZE_EXPAND_FILL + list_box.size_flags_horizontal = Control.SIZE_EXPAND_FILL + + list = list_box + rows = row_box + + # Add a row to the list func add_row(row_text: String, row_type: List.ItemType, min_size: Vector2 = Vector2(0,0)): list_object.add_row(row_text, row_type) @@ -61,7 +102,7 @@ func add_row(row_text: String, row_type: List.ItemType, min_size: Vector2 = Vect # It returns the index of the item in the list and the engine index # The index of the item SHOULD NOT be trusted, as it can change if an item is removed / added # If you need to do something with the item, use the "engine index" instead, this index can't change and is unique to the item -func add_item(Content: Array, _metadata: Dictionary = {}): +func add_item(Content: Array, _metadata: Dictionary = {}) -> Dictionary: var idx = list_object.add_item(Content, "", _metadata) var item_object = list_object.get_list_property()['items'][idx] @@ -90,8 +131,8 @@ func add_item(Content: Array, _metadata: Dictionary = {}): list.add_child(node) node.set_item_name(item_name) - node.set_item_content(item_content, list_object.get_list_property()['rows_type']) node.set_item_metadata(item_metadata) + node.set_item_content(item_content, list_object.get_list_property()['rows_type']) if DataRegister.has_key(db_context, db_char_list_key): var datas_list = DataRegister.get_data(db_context, db_char_list_key) @@ -116,10 +157,12 @@ func add_item(Content: Array, _metadata: Dictionary = {}): node.base_theme = bg_theme node.clicked_on_item.connect(_click_on_item) + node.option_chosen.connect(_on_option_chosen) list_node[item_metadata['engine_index']] = node + - return {"index": idx, "engine_index": item_metadata['engine_index']} + return {"index": idx, "engine_index": item_metadata['engine_index'], "node": node} # Remove an item from the list @@ -142,6 +185,12 @@ func clear_items(): for i in list.get_children(): i.queue_free() + +func clear_rows(): + list_object.clear_rows() + for i in rows.get_children(): + i.queue_free() + #################### # SIGNALS @@ -183,4 +232,7 @@ func _on_data_registered(_context: String, _key: String, _value: Variant, _origi add_item(datas_list[key], {db_index_name: key}) func _click_on_item(node: Node, _name: String, _metadata: Dictionary): - item_clicked.emit(node, _name, _metadata) \ No newline at end of file + item_clicked.emit(node, _name, _metadata) + +func _on_option_chosen(option: String, option_button: OptionButton): + option_chosen.emit(option, option_button) \ No newline at end of file diff --git a/Core/gui/CustomList/customListItem.gd b/Core/gui/CustomList/customListItem.gd index 67f9f9b..0f42360 100644 --- a/Core/gui/CustomList/customListItem.gd +++ b/Core/gui/CustomList/customListItem.gd @@ -8,6 +8,7 @@ var base_theme: StyleBoxFlat var node_item: HBoxContainer signal clicked_on_item(node: Node, name: String, metadata: Dictionary) +signal option_chosen(option: String, option_button: OptionButton) func _ready(): print("Hi") @@ -51,10 +52,33 @@ func set_item_content(_content: Array, _type: Array): checkbox.size_flags_horizontal = Control.SIZE_EXPAND_FILL checkbox.size_flags_vertical = Control.SIZE_SHRINK_CENTER node_item.add_child(checkbox) + List.ItemType.OPTION_BUTTON: + var option_button = OptionButton.new() + option_button.size_flags_horizontal = Control.SIZE_EXPAND_FILL + option_button.size_flags_vertical = Control.SIZE_SHRINK_CENTER + + # Get options metadata + var options = metadata["options"] + for option in options: + + if typeof(option) == TYPE_STRING: + option_button.add_item(option) + else: + option_button.add_item(option["name"]) + # Set the metadata of the option + option_button.set_item_metadata(option_button.item_count - 1, {"value": option['value']}) + option_button.selected = content[i] + + option_button.item_selected.connect(_on_option_chosen.bind(option_button)) + + node_item.add_child(option_button) func set_item_metadata(_metadata: Dictionary): metadata = _metadata func _click_on_panel(): - clicked_on_item.emit(self, item_name, metadata) \ No newline at end of file + clicked_on_item.emit(self, item_name, metadata) + +func _on_option_chosen(option: int, option_button: OptionButton): + option_chosen.emit(str(option), option_button) \ No newline at end of file diff --git a/Core/gui/CustomList/customListItemBase.gd b/Core/gui/CustomList/customListItemBase.gd new file mode 100644 index 0000000..8662800 --- /dev/null +++ b/Core/gui/CustomList/customListItemBase.gd @@ -0,0 +1,39 @@ +extends VBoxContainer +class_name CustomListItemBase + +var metadata: Dictionary = {} +var content = [] +var types = [] +var item_name: String = "" +var base_theme: StyleBoxFlat +var node_item: HBoxContainer +var clickeable_panel: Panel + +signal clicked_on_item(node: Node, name: String, metadata: Dictionary) + +func _init(): + clickeable_panel = Panel.new() + clickeable_panel.custom_minimum_size = Vector2(0, 30) + clickeable_panel.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND + + add_child(clickeable_panel) + clickeable_panel.gui_input.connect(_click_on_panel) + + var margin: MarginContainer = MarginContainer.new() + margin.anchors_preset = MarginContainer.PRESET_FULL_RECT + margin.add_theme_constant_override("margin_left", 5) + margin.add_theme_constant_override("margin_right", 5) + + clickeable_panel.add_child(margin) + + node_item = HBoxContainer.new() + + margin.add_child(node_item) + +# test signal clickeable panel +func _click_on_panel(event): + if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.pressed: + print("Clicked on panel") + +func add_object(_object_type: Node): + pass \ No newline at end of file diff --git a/Core/gui/CustomListTemplate/custom_list_row.gd b/Core/gui/CustomListTemplate/custom_list_row.gd new file mode 100644 index 0000000..009c53d --- /dev/null +++ b/Core/gui/CustomListTemplate/custom_list_row.gd @@ -0,0 +1,10 @@ +extends RefCounted +class_name CustomListTemplateRow + +@export var row_name: String = "Row": + set(new): + row_name = tr(new) + +@export var row_type: List.ItemType = List.ItemType.TEXT + +@export var row_metadata: Dictionary = {} \ No newline at end of file diff --git a/Core/gui/CustomListTemplate/custom_list_template_base.gd b/Core/gui/CustomListTemplate/custom_list_template_base.gd new file mode 100644 index 0000000..c61e701 --- /dev/null +++ b/Core/gui/CustomListTemplate/custom_list_template_base.gd @@ -0,0 +1,28 @@ +extends Control +class_name CustomListTemplateBase +# This class is used to create a custom template for a list. +# All function NEED to be implemented in the child class. +# If any function is not implemented the list will not work at all! +# The _init function is not allowed to have any arguments. + +signal pressed(node: Control) + +# This function is called when the list is created. +func load(): + pass + +# This function will be called at third when the list is created. +func set_data(_data: Dictionary): + pass + +# This function will be called at second when the list is created. The IDX is the unique id of the item. +func set_idx(_idx: String): + pass + +# This function will be called when the item is pressed. +# +# !!! You don't need to implement this function in the child class. +func _gui_input(event): + if event is InputEventMouseButton: + if event.button_index == MOUSE_BUTTON_LEFT and event.pressed: + pressed.emit(self) \ No newline at end of file diff --git a/Core/gui/InfoDB/child/info_item_options.gd b/Core/gui/InfoDB/child/info_item_options.gd index a6683af..e86dbb1 100644 --- a/Core/gui/InfoDB/child/info_item_options.gd +++ b/Core/gui/InfoDB/child/info_item_options.gd @@ -71,6 +71,20 @@ func set_label(_label: String): func set_content(_content: int): content = _content +## Set the options inside the infoitem[br] +## [br] +## The given dictionnary need to have the following structure:[br] +## {uid: {"name": "OptionName", "uid": 2301}, ...}[br] +## uid being the "value" of, for example, an enum [br] +## So if we have 'SELF = 0', we get: +## [codeblock] +## { +## 0: { +## "name": "SELF", +## "uid": 0 +## } +## } +## [/codeblock] func set_options(_options: Dictionary): if _options.size() == 0: @@ -80,4 +94,4 @@ func set_options(_options: Dictionary): func _on_content_changed(value: int) -> void: content = value - emit_signal("content_changed", content) \ No newline at end of file + emit_signal("content_changed", str(content)) \ No newline at end of file diff --git a/Core/gui/InfoDB/child/info_item_spinbox.gd b/Core/gui/InfoDB/child/info_item_spinbox.gd index 1abfb56..19674fe 100644 --- a/Core/gui/InfoDB/child/info_item_spinbox.gd +++ b/Core/gui/InfoDB/child/info_item_spinbox.gd @@ -14,6 +14,11 @@ var content: int = 0: content = new reload_content() +@export +var suffix: String = "": + set(new): + content_node.suffix = tr(new) + signal content_changed(content: int) var label_node: Label @@ -29,6 +34,8 @@ func _init(): content_node = SpinBox.new() content_node.value = content content_node.size_flags_horizontal = Control.SIZE_EXPAND_FILL + # allow greater values + content_node.allow_greater = true content_node.connect("value_changed", _on_content_changed) diff --git a/Core/gui/InfoDB/child/info_item_textedit.gd b/Core/gui/InfoDB/child/info_item_textedit.gd index 65b4b85..56146ce 100644 --- a/Core/gui/InfoDB/child/info_item_textedit.gd +++ b/Core/gui/InfoDB/child/info_item_textedit.gd @@ -54,6 +54,7 @@ func _init(): content_node.bbcode_enabled = true content_node.text = content content_node.size_flags_horizontal = Control.SIZE_EXPAND_FILL + content_node.size_flags_vertical = Control.SIZE_EXPAND_FILL # We prepare the advanced edit window window = ConfirmationDialog.new() diff --git a/Core/gui/InfoDB/info_entities.gd b/Core/gui/InfoDB/info_entities.gd index bf93107..f0bb91d 100644 --- a/Core/gui/InfoDB/info_entities.gd +++ b/Core/gui/InfoDB/info_entities.gd @@ -184,7 +184,7 @@ func add_options(): var gender_options = {} for enum_name in CharacterGender: var enum_key = CharacterGender[enum_name] # Get the key (value) of the enum (e.g. 0, 1,2,3,..,n) - gender_options[enum_key] = {"name": enum_name, "uid": enum_key} + gender_options[enum_key] = {"name": tr(enum_name), "uid": enum_key} node_gender.set_options(gender_options) @@ -201,8 +201,7 @@ func set_list_prop(): skill_list.origin = "BoxEntities" - skill_list.add_row("SKILL_NAME", List.ItemType.TEXT) - skill_list.add_row("SKILL_LVL", List.ItemType.TEXT) + skill_list.add_row("SKILL_NAME", List.ItemType.OPTION_BUTTON) # Set the entities to show func set_entities(_character: Character): @@ -305,7 +304,7 @@ func init_skills(): var skills = character.skills for skill in skills: - skill_list.add_item([skill.name, str(skill.level)], {"char_idx": character.id}) + skill_list.add_item([skill.id], {"char_idx": character.id, "options": SkillRegister.get_all_skills_name_by_ids()}) # Init the inventory tab func init_inventory(): @@ -681,13 +680,16 @@ func _on_node_add_skill_pressed() -> void: if character.skills.size() >= character.max_skills: return + # Check if the database has any skill + if SkillRegister.get_all_skills_ids().size() == 0: + return + _add_to_history({"skills": character.skills}) # Add a new skill to the character - character.add_skill(tr("NEW_SKILL"), 1) - - %skillList.add_item([tr("NEW_SKILL"), "1"], {"char_idx": character.id}) + character.add_skill(SkillRegister.get_all_skills_ids()[0]) + %skillList.add_item([SkillRegister.get_all_skills_ids()[0]], {"char_idx": character.id, "options": SkillRegister.get_all_skills_name_by_ids()}) ############################################ diff --git a/Core/gui/InfoDB/skills/info_skills.gd b/Core/gui/InfoDB/skills/info_skills.gd new file mode 100644 index 0000000..4f70068 --- /dev/null +++ b/Core/gui/InfoDB/skills/info_skills.gd @@ -0,0 +1,186 @@ +extends VBoxContainer + +const SkillTypes = EnumRegister.SkillTypes +const SkillTargets = EnumRegister.SkillTarget + +var infoID: InfoItemText +var infoName: InfoItemLineEdit +var infoDesc: InfoItemTextedit +var infoType: InfoItemOptions +var infoTarget: InfoItemOptions +var infoCooldown: InfoItemSpinBox +var infoCooldownType: OptionButton +var infoEffects: CustomListV2Base +var infoConditions: CustomListV2Base + +var skill_loaded: BaseSkill = null + +var clicked_on: Node = null + +signal skill_renamed() + +# Get all the nodes from the scene +func _ready(): + infoID = %infoID + infoName = %infoName + infoDesc = %infoDesc + infoType = %infoType + infoTarget = %infoTarget + infoCooldown = %infoCooldown + infoCooldownType = %cooldown_time_type + infoEffects = %infoEffects + infoConditions = %infoConditions + + init_nodes() + +# Initialize the nodes +func init_nodes(): + + init_options() + +# Set the options for the infoItemOptions nodes (infoType & InfoTarget) +func init_options(): + + var target_option = {} + for enum_name in SkillTargets: + var enum_key: int = SkillTargets[enum_name] + target_option[enum_key] = {"name": tr(enum_name), "uid": enum_key} + + infoTarget.set_options(target_option) + + var type_option = {} + for enum_name in SkillTypes: + var enum_key: int = SkillTypes[enum_name] + type_option[enum_key] = {"name": tr(enum_name), "uid": enum_key} + + infoType.set_options(type_option) + + # Set the cooldown time type + for enum_name in EnumRegister.SkillCooldownType: + infoCooldownType.add_item(tr(enum_name), EnumRegister.SkillCooldownType[enum_name]) + +# Load a skill +func _on_load_skill(skill: BaseSkill): + + if skill == null: + return + + skill_loaded = skill + + infoID.set_content(skill.id) + infoName.set_content(skill.name) + infoDesc.set_content(skill.description) + infoType.set_content(skill.skill_type) + infoTarget.set_content(skill.skill_target) + infoCooldown.set_content(skill.skill_cooldown) + infoCooldownType.select(skill.skill_cooldown_type) + + _on_cooldown_time_type_item_selected(skill.skill_cooldown_type) + + # infoEffects.load_items(skill.effects) ## TODO: Implement the "load_items" inside the CustomListV2Base then in the custom script + # infoConditions.load_items(skill.conditions) ## TODO: Implement the "load_items" inside the CustomListV2Base then in the custom script + + +func _on_skill_list_item_clicked(_node:Node, _name:String, _metadata:Dictionary): + + print("skill_idx: ", _metadata['skill_idx']) + print("skill: ", SkillRegister.get_skill(_metadata['skill_idx'])) + + + # Check if the ignore exist + if _metadata.has('ignore'): + return + + if !_metadata.has('skill_idx'): + push_error("No skill index found in the metadata") + return + + var skill_idx: String = _metadata['skill_idx'] + + # Check if the skill exists + if !SkillRegister.has_skill(skill_idx): + push_error("Skill not found") + return + + var skill:BaseSkill = SkillRegister.get_skill(skill_idx) + _on_load_skill(skill) + skill_loaded = skill + print("Skill loaded: ", skill.name) + + +func _on_cooldown_time_type_item_selected(index:int): + + match(index): + 0: + infoCooldown.suffix = "MS" + 1: + infoCooldown.suffix = "SEC" + 2: + infoCooldown.suffix = "MIN" + _: + push_error("Invalid index selected") + infoCooldown.suffix = "MS" + + if skill_loaded == null: + return + + _add_to_history({"skill_cooldown_type": skill_loaded.skill_cooldown_type}) + skill_loaded.skill_cooldown_type = Utils.cast_to_enum(index, EnumRegister.SkillCooldownType) + + pass # Replace with function body. + +# When the target type is changed (ex: Self, Enemy, etc) +func _on_info_target_content_changed(content:String): + + if skill_loaded == null: + return + + _add_to_history({"skill_target": skill_loaded.skill_target}) + + skill_loaded.skill_target = Utils.cast_to_enum(content.to_int(), EnumRegister.SkillTarget) + +# when the skill type is changed (ex: Active, Passive, etc) +func _on_info_type_content_changed(content:String): + + if skill_loaded == null: + return + + _add_to_history({"skill_type": skill_loaded.skill_type}) + + skill_loaded.skill_type = Utils.cast_to_enum(content.to_int(), EnumRegister.SkillTypes) + +# When the cooldown is changed +func _on_info_cooldown_content_changed(content:int): + + if skill_loaded == null: + return + + _add_to_history({"skill_cooldown": skill_loaded.skill_cooldown}) + + skill_loaded.skill_cooldown = content + +# when the skill description is changed +func _on_info_desc_content_changed(content:String): + + if skill_loaded == null: + return + + _add_to_history({"description": skill_loaded.description}) + + skill_loaded.description = content + +# when the skill name is changed +func _on_info_name_content_changed(content:String): + + if skill_loaded == null: + return + + _add_to_history({"name": skill_loaded.name}) + + skill_loaded.name = content + skill_renamed.emit() + + +func _add_to_history(history_data: Dictionary) -> void: + var history = HistorySkill.new(EnumRegister.HistoryAction.CHANGE, skill_loaded.id, history_data) + HistoryRegister.add_to_history(history) \ No newline at end of file diff --git a/Core/gui/List/Skill/effect_list.gd b/Core/gui/List/Skill/effect_list.gd new file mode 100644 index 0000000..b7e0815 --- /dev/null +++ b/Core/gui/List/Skill/effect_list.gd @@ -0,0 +1,7 @@ +extends CustomListV2Base + +var effect_list: Array[BaseEffect] = [] + +func _ready(): + super() + \ No newline at end of file diff --git a/Core/gui/database/Skill/skill_list.gd b/Core/gui/database/Skill/skill_list.gd new file mode 100644 index 0000000..8516371 --- /dev/null +++ b/Core/gui/database/Skill/skill_list.gd @@ -0,0 +1,305 @@ +extends TabContainer + +var skill_list: Array[BaseSkill] = [] + +@export var all_list: CustomList +@export var active_list: CustomList +@export var passive_list: CustomList +@export var reactive_list: CustomList +@export var special_list: CustomList + +var clicked_on: Node = null +var clicked_skill_idx: String = "" + +## Emit it when the list needs to be fully reloaded. (Rows and items will be cleaned) +signal need_fullreload() +## Emit it when the list needs to be reloaded. (Items will be cleaned, not the rows) +signal need_reload() +## Connect to this signal to get the item clicked. +signal item_clicked(node: Node, name: String, metadata: Dictionary) + +# Called when the node enters the scene tree for the first time. +func _ready(): + + # Check if one of the nodes is missing. + if all_list == null or active_list == null or passive_list == null: + print("One of the nodes is missing.") + # Disable the node. + self.queue_free() + return + + # Set DB data & body. + _init_list() + + # Link us to the need_fullreload signal. + need_fullreload.connect(_fullreload_list) + # Link us to the need_reload signal. + need_reload.connect(_reload_list) + + # Link us to the item_clicked signal of all lists. + all_list.item_clicked.connect(_click_on_item) + active_list.item_clicked.connect(_click_on_item) + passive_list.item_clicked.connect(_click_on_item) + reactive_list.item_clicked.connect(_click_on_item) + special_list.item_clicked.connect(_click_on_item) + + _set_rows() + + # Emit the need_reload signal one time to load the skills. + need_reload.emit() + +# Clean all lists of all items and rows. +func _fullclean_all(): + _fullclean_all_list() + _fullclean_active_list() + _fullclean_passive_list() + _fullclean_reactive_list() + _fullclean_special_list() + +func _fullclean_all_list(): + _clean_all_list() + all_list.clear_rows() + +func _fullclean_active_list(): + _clean_active_list() + active_list.clear_rows() + +func _fullclean_passive_list(): + _clean_passive_list() + passive_list.clear_rows() + +func _fullclean_reactive_list(): + _clean_reactive_list() + reactive_list.clear_rows() + +func _fullclean_special_list(): + _clean_special_list() + special_list.clear_rows() + +func _clean_all(): + _clean_all_list() + _clean_active_list() + _clean_passive_list() + _clean_reactive_list() + _clean_special_list() + +func _clean_all_list(): + all_list.clear_items() + +func _clean_active_list(): + active_list.clear_items() + +func _clean_passive_list(): + passive_list.clear_items() + +func _clean_reactive_list(): + reactive_list.clear_items() + +func _clean_special_list(): + special_list.clear_items() + +func _init_list(): + _init_list_all() + _init_list_active() + _init_list_passive() + _init_list_reactive() + _init_list_special() + +func _init_list_all(): + all_list.set_db_data("skill_idx", "box_skills", "skills_list") + all_list.origin = "list_skills" + +func _init_list_active(): + active_list.set_db_data("skill_idx", "box_skills", "skills_list") + active_list.origin = "list_skills" + +func _init_list_passive(): + passive_list.set_db_data("skill_idx", "box_skills", "skills_list") + passive_list.origin = "list_skills" + +func _init_list_reactive(): + reactive_list.set_db_data("skill_idx", "box_skills", "skills_list") + reactive_list.origin = "list_skills" + +func _init_list_special(): + special_list.set_db_data("skill_idx", "box_skills", "skills_list") + special_list.origin = "list_skills" + +func _set_rows(): + _set_all_list_rows() + _set_active_list_rows() + _set_passive_list_rows() + _set_reactive_list_rows() + _set_special_list_rows() + +func _set_all_list_rows(): + all_list.add_row("SKILL_NAME", List.ItemType.TEXT) + +func _set_active_list_rows(): + active_list.add_row("SKILL_NAME", List.ItemType.TEXT) + +func _set_passive_list_rows(): + passive_list.add_row("SKILL_NAME", List.ItemType.TEXT) + +func _set_reactive_list_rows(): + reactive_list.add_row("SKILL_NAME", List.ItemType.TEXT) + +func _set_special_list_rows(): + special_list.add_row("SKILL_NAME", List.ItemType.TEXT) + +func _add_skill_to_list(list: CustomList, skill: BaseSkill): + var data = list.add_item([skill.name], { "skill_idx": skill.id, "clicked_on": (clicked_skill_idx)}) + + # set if the skill is clicked. + if clicked_skill_idx == skill.id: + clicked_on = data["node"] + # Edit the theme of the last clicked node to set it back to the default + var base_theme: StyleBoxFlat = clicked_on.base_theme.duplicate() + + base_theme.border_width_bottom = 2 + base_theme.border_width_top = 2 + base_theme.border_width_left = 2 + base_theme.border_width_right = 2 + base_theme.border_color = Color(0.4, 0.4, 0.4, 1.0) + clicked_on.get_node("Panel").add_theme_stylebox_override("panel", base_theme) + +# Fully reload all lists. +func _fullreload_list(): + + # Clean all lists. + _fullclean_all() + # Set all rows. + _set_rows() + + # Get skills from register. + _get_skills_from_register() + + # Get all skills. + var sorted_skills = _sort_skills_all() + # Get active skills. + var active_skills = _sort_skills_by_type(EnumRegister.SkillTypes.ACTIVE) + # Get passive skills. + var passive_skills = _sort_skills_by_type(EnumRegister.SkillTypes.PASSIVE) + # Get reactive skills. + var reactive_skills = _sort_skills_by_type(EnumRegister.SkillTypes.REACTIVE) + # Get special skills. + var special_skills = _sort_skills_by_type(EnumRegister.SkillTypes.SPECIAL) + + # Add all skills to the all list. + for skill in sorted_skills: + _add_skill_to_list(all_list, skill) + + # Add active skills to the active list. + for skill in active_skills: + _add_skill_to_list(active_list, skill) + + # Add passive skills to the passive list. + for skill in passive_skills: + _add_skill_to_list(passive_list, skill) + + # Add reactive skills to the reactive list. + for skill in reactive_skills: + _add_skill_to_list(reactive_list, skill) + + # Add special skills to the special list. + for skill in special_skills: + _add_skill_to_list(special_list, skill) + + pass + +func _reload_list(): + + # Clean items + _clean_all() + + # Get skills from register. + _get_skills_from_register() + + # Get all skills. + var sorted_skills = _sort_skills_all() + # Get active skills. + var active_skills = _sort_skills_by_type(EnumRegister.SkillTypes.ACTIVE) + # Get passive skills. + var passive_skills = _sort_skills_by_type(EnumRegister.SkillTypes.PASSIVE) + # Get reactive skills. + var reactive_skills = _sort_skills_by_type(EnumRegister.SkillTypes.REACTIVE) + # Get special skills. + var special_skills = _sort_skills_by_type(EnumRegister.SkillTypes.SPECIAL) + + # Add all skills to the all list. + for skill in sorted_skills: + _add_skill_to_list(all_list, skill) + + # Add active skills to the active list. + for skill in active_skills: + _add_skill_to_list(active_list, skill) + + # Add passive skills to the passive list. + for skill in passive_skills: + _add_skill_to_list(passive_list, skill) + + # Add reactive skills to the reactive list. + for skill in reactive_skills: + _add_skill_to_list(reactive_list, skill) + + # Add special skills to the special list. + for skill in special_skills: + _add_skill_to_list(special_list, skill) + + + + +func _get_skills_from_register(): + var skills = SkillRegister.get_all_skills() + + # Reset the skill list. + skill_list = [] + + for skill in skills.values(): + skill_list.append(skill) + +func _sort_skills_all() -> Array[BaseSkill]: + return skill_list + +func _sort_skills_by_type(type: EnumRegister.SkillTypes) -> Array[BaseSkill]: + var sorted_skills: Array[BaseSkill] = [] + for skill in skill_list: + if skill.skill_type == type: + sorted_skills.append(skill) + return sorted_skills + +func _click_on_item(_node: Node, _name: String, _metadata: Dictionary): + item_clicked.emit(_node, _name, _metadata) + + clicked_skill_idx = _metadata['skill_idx'] + + if clicked_on != null and clicked_on != _node: + # Edit the theme of the last clicked node to set it back to the default + var old_theme: StyleBoxFlat = clicked_on.base_theme + clicked_on.get_node("Panel").add_theme_stylebox_override("panel", old_theme) + + clicked_on = _node + + # Edit the theme of the last clicked node to set it back to the default + var base_theme: StyleBoxFlat = clicked_on.base_theme.duplicate() + + base_theme.border_width_bottom = 2 + base_theme.border_width_top = 2 + base_theme.border_width_left = 2 + base_theme.border_width_right = 2 + base_theme.border_color = Color(0.4, 0.4, 0.4, 1.0) + + clicked_on.get_node("Panel").add_theme_stylebox_override("panel", base_theme) + +func _on_add_skill_pressed(): + + SkillRegister.new_skill() + + # Emit the reload signal. + need_reload.emit() + + + +func _on_info_skills_skill_renamed(): + # Emit the reload signal. + need_reload.emit() diff --git a/test/custom_list_test.gd b/test/custom_list_test.gd new file mode 100644 index 0000000..239c433 --- /dev/null +++ b/test/custom_list_test.gd @@ -0,0 +1,22 @@ +extends Control + + +# Called when the node enters the scene tree for the first time. +func _ready(): + + %CustomList.add_row("Test", List.ItemType.TEXT) + + # Test option_button + var options = ["Option 1", "Option 2", "Option 3"] + %CustomList.add_row("Test", List.ItemType.OPTION_BUTTON) + + %CustomList.add_item(["Test", 0], { "options": options, "char_idx": 0 }) + + %CustomList.option_chosen.connect(_on_option_chosen) + + pass # Replace with function body. + + +func _on_option_chosen(option: String, option_button: OptionButton): + print("Option chosen: ", option) + print("Option button: ", option_button) \ No newline at end of file diff --git a/test/custom_list_test.tscn b/test/custom_list_test.tscn new file mode 100644 index 0000000..782d86c --- /dev/null +++ b/test/custom_list_test.tscn @@ -0,0 +1,28 @@ +[gd_scene load_steps=4 format=3 uid="uid://deeb53weg3vr3"] + +[ext_resource type="Script" path="res://test/custom_list_test.gd" id="1_g0f0d"] +[ext_resource type="PackedScene" uid="uid://grljyoauhhtn" path="res://Core/Scenes/database/custom_list.tscn" id="2_0n72a"] +[ext_resource type="Script" path="res://Core/gui/CustomList/customListItemBase.gd" id="3_eh48w"] + +[node name="Control" type="Control"] +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_g0f0d") + +[node name="CustomList" parent="." instance=ExtResource("2_0n72a")] +unique_name_in_owner = true +layout_mode = 1 + +[node name="CustomListItemBase" type="VBoxContainer" parent="."] +visible = false +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("3_eh48w")