From 8f0e053963b1a34c1c9b1c02ff36f890bc44f2dd Mon Sep 17 00:00:00 2001 From: TheThomaas Date: Sun, 4 Oct 2026 14:05:43 +0200 Subject: [PATCH] Handle Pokemon PC Boxes --- scripts/game_data.gd | 11 ++- scripts/pokemon/pokemon_team.gd | 10 ++ scripts/storage/pokemon_box.gd | 30 ++++++ scripts/storage/pokemon_storage.gd | 146 +++++++++++++++++++++++++++++ 4 files changed, 196 insertions(+), 1 deletion(-) create mode 100644 scripts/storage/pokemon_box.gd create mode 100644 scripts/storage/pokemon_storage.gd diff --git a/scripts/game_data.gd b/scripts/game_data.gd index 5d3755e..ce6d19d 100644 --- a/scripts/game_data.gd +++ b/scripts/game_data.gd @@ -3,11 +3,18 @@ extends Node var story_progress : int = 0 # 0 = début, 1 = après 1er badge, 2 = après 2e badge, etc. var player_team : PokemonTeam = PokemonTeam.new() +var player_storage : PokemonStorage = PokemonStorage.new() + +func give_pokemon(pokemon : PokemonInstance) -> PokemonStorage.ReceiveResult: + #point d'entree unique pour obtenir un pokemon (starter, cadeau, capture...) : + #equipe si elle a de la place, sinon PC. A l'appelant d'informer le joueur selon le resultat. + return player_storage.receive_pokemon(player_team, pokemon) func save() -> void: var config := ConfigFile.new() config.set_value("progress", "story_progress", story_progress) config.set_value("team", "data", player_team.to_dict()) + config.set_value("storage", "data", player_storage.to_dict()) config.save("user://save.cfg") func load_data() -> void: @@ -15,4 +22,6 @@ func load_data() -> void: if config.load("user://save.cfg") == OK: story_progress = config.get_value("progress", "story_progress", 0) var team_data : Variant = config.get_value("team", "data", {}) - player_team = PokemonTeam.from_dict(team_data) if team_data is Dictionary else PokemonTeam.new() \ No newline at end of file + player_team = PokemonTeam.from_dict(team_data) if team_data is Dictionary else PokemonTeam.new() + var storage_data : Variant = config.get_value("storage", "data", {}) + player_storage = PokemonStorage.from_dict(storage_data) if storage_data is Dictionary else PokemonStorage.new() \ No newline at end of file diff --git a/scripts/pokemon/pokemon_team.gd b/scripts/pokemon/pokemon_team.gd index 89a14e2..22d42a8 100644 --- a/scripts/pokemon/pokemon_team.gd +++ b/scripts/pokemon/pokemon_team.gd @@ -49,6 +49,16 @@ func swap(index_a : int, index_b : int) -> bool: team_changed.emit() return true +func replace_at(index : int, pokemon : PokemonInstance) -> PokemonInstance: + #remplace le pokemon a cet index et renvoie l'ancien (utilise pour les echanges avec le PC) + if pokemon == null or !_is_valid_index(index) or members.has(pokemon): return null + var old : PokemonInstance = members[index] + members[index] = pokemon + pokemon_removed.emit(old, index) + pokemon_added.emit(pokemon, index) + team_changed.emit() + return old + #---------- combat ---------- func get_first_able_index() -> int: diff --git a/scripts/storage/pokemon_box.gd b/scripts/storage/pokemon_box.gd new file mode 100644 index 0000000..edb832c --- /dev/null +++ b/scripts/storage/pokemon_box.gd @@ -0,0 +1,30 @@ +class_name PokemonBox +extends Resource + +#une boite du PC : un nombre fixe d'emplacements, chacun vide (null) ou occupe + +var box_name : String = "" #vide = nom par defaut, a gerer par l'UI ("Boite 1"...) +var slots : Array[PokemonInstance] = [] + +func _init(p_size : int = 30) -> void: + slots.resize(p_size) + +func size() -> int: + return slots.size() + +func get_pokemon(slot : int) -> PokemonInstance: + return slots[slot] if slot >= 0 and slot < slots.size() else null + +func first_free_slot() -> int: + for i in slots.size(): + if slots[i] == null: return i + return -1 + +func is_full() -> bool: + return first_free_slot() == -1 + +func count() -> int: + var n : int = 0 + for p in slots: + if p != null: n += 1 + return n \ No newline at end of file diff --git a/scripts/storage/pokemon_storage.gd b/scripts/storage/pokemon_storage.gd new file mode 100644 index 0000000..9c4de2a --- /dev/null +++ b/scripts/storage/pokemon_storage.gd @@ -0,0 +1,146 @@ +class_name PokemonStorage +extends Resource + +signal storage_changed + +enum ReceiveResult { TEAM, BOX, FULL } + +const NO_SLOT : Vector2i = Vector2i(-1, -1) #(boite, emplacement) + +var boxes : Array[PokemonBox] = [] + +func _init(p_box_count : int = 8, p_box_size : int = 30) -> void: + for i in p_box_count: + boxes.append(PokemonBox.new(p_box_size)) + +#---------- infos ---------- + +func box_count() -> int: + return boxes.size() + +func get_box(box_index : int) -> PokemonBox: + return boxes[box_index] if box_index >= 0 and box_index < boxes.size() else null + +func get_pokemon(box_index : int, slot : int) -> PokemonInstance: + var box : PokemonBox = get_box(box_index) + return box.get_pokemon(slot) if box else null + +func get_total_count() -> int: + var n : int = 0 + for box in boxes: n += box.count() + return n + +func is_full() -> bool: + return find_free_slot() == NO_SLOT + +func find_free_slot() -> Vector2i: + for b in boxes.size(): + var s : int = boxes[b].first_free_slot() + if s != -1: return Vector2i(b, s) + return NO_SLOT + +#---------- reception d'un nouveau pokemon ---------- + +func receive_pokemon(team : PokemonTeam, pokemon : PokemonInstance) -> ReceiveResult: + #equipe d'abord ; si elle est pleine, premiere place libre du PC + if pokemon == null: return ReceiveResult.FULL + if team.add_pokemon(pokemon): return ReceiveResult.TEAM + var dest : Vector2i = find_free_slot() + if dest == NO_SLOT: return ReceiveResult.FULL + boxes[dest.x].slots[dest.y] = pokemon + storage_changed.emit() + return ReceiveResult.BOX + +#---------- equipe <-> PC ---------- + +func deposit(team : PokemonTeam, team_index : int, box_index : int = -1, slot : int = -1) -> bool: + #equipe -> PC (box_index = -1 : premiere place libre) + if team.get_pokemon(team_index) == null: return false + if !_team_stays_valid(team, team_index, null): return false + + var dest : Vector2i = find_free_slot() if box_index < 0 else Vector2i(box_index, slot) + if dest == NO_SLOT or get_box(dest.x) == null: return false + if dest.y < 0 or dest.y >= boxes[dest.x].size() or boxes[dest.x].slots[dest.y] != null: return false + + var pokemon : PokemonInstance = team.remove_at(team_index) + boxes[dest.x].slots[dest.y] = pokemon + storage_changed.emit() + return true + +func withdraw(team : PokemonTeam, box_index : int, slot : int) -> bool: + #PC -> equipe (a la fin) ; impossible si l'equipe est pleine + var pokemon : PokemonInstance = get_pokemon(box_index, slot) + if pokemon == null or team.is_full(): return false + if !team.add_pokemon(pokemon): return false + boxes[box_index].slots[slot] = null + storage_changed.emit() + return true + +func swap_with_team(team : PokemonTeam, team_index : int, box_index : int, slot : int) -> bool: + #echange un pokemon de l'equipe avec celui d'un emplacement occupe du PC + var from_team : PokemonInstance = team.get_pokemon(team_index) + var from_box : PokemonInstance = get_pokemon(box_index, slot) + if from_team == null or from_box == null: return false + if !_team_stays_valid(team, team_index, from_box): return false + if team.replace_at(team_index, from_box) == null: return false + boxes[box_index].slots[slot] = from_team + storage_changed.emit() + return true + +#---------- deplacements dans le PC ---------- + +func move_slot(box_a : int, slot_a : int, box_b : int, slot_b : int) -> bool: + #deplace (ou echange) le contenu d'un emplacement vers un autre, destination vide ou non + var source : PokemonInstance = get_pokemon(box_a, slot_a) + if source == null: return false + var dest_box : PokemonBox = get_box(box_b) + if dest_box == null or slot_b < 0 or slot_b >= dest_box.size(): return false + if box_a == box_b and slot_a == slot_b: return false + boxes[box_a].slots[slot_a] = dest_box.slots[slot_b] + dest_box.slots[slot_b] = source + storage_changed.emit() + return true + +func release(box_index : int, slot : int) -> PokemonInstance: + #retire definitivement un pokemon du PC (relacher) ; renvoie le pokemon retire + var pokemon : PokemonInstance = get_pokemon(box_index, slot) + if pokemon == null: return null + boxes[box_index].slots[slot] = null + storage_changed.emit() + return pokemon + +#---------- regle d'equipe ---------- + +func _team_stays_valid(team : PokemonTeam, removed_index : int, replacement : PokemonInstance) -> bool: + #l'equipe ne doit jamais etre vide, ni perdre son dernier pokemon apte + #(sauf si elle n'en avait deja aucun : tous K.O.) + var size_after : int = team.size() - (1 if replacement == null else 0) + if size_after < 1: return false + if !team.has_able_pokemon(): return true + for i in team.size(): + if i != removed_index and !team.members[i].is_fainted(): return true + return replacement != null and !replacement.is_fainted() + +#---------- sauvegarde ---------- + +func to_dict() -> Dictionary: + var boxes_data : Array = [] + for box in boxes: + var slots_data : Array = [] + for p in box.slots: + slots_data.append(p.to_dict() if p != null else null) + boxes_data.append({"name": box.box_name, "slots": slots_data}) + return {"boxes": boxes_data} + +static func from_dict(data : Dictionary) -> PokemonStorage: + var storage := PokemonStorage.new(0) + for box_data in data.get("boxes", []): + var slots_data : Array = box_data.get("slots", []) + var box := PokemonBox.new(slots_data.size()) + box.box_name = box_data.get("name", "") + for i in slots_data.size(): + if slots_data[i] is Dictionary: + box.slots[i] = PokemonInstance.from_dict(slots_data[i]) + storage.boxes.append(box) + if storage.boxes.is_empty(): return PokemonStorage.new() + return storage \ No newline at end of file