Add types, abilities and evolutions
This commit is contained in:
parent
aee47dab71
commit
bb75ce1b6c
15
data/ability_data.gd
Normal file
15
data/ability_data.gd
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
# data/ability_data.gd
|
||||||
|
@tool
|
||||||
|
class_name AbilityData
|
||||||
|
extends Resource
|
||||||
|
|
||||||
|
@export var id : int
|
||||||
|
@export var api_name : String
|
||||||
|
@export var names : Dictionary = {}
|
||||||
|
@export var descriptions : Dictionary = {}
|
||||||
|
|
||||||
|
func get_display_name() -> String:
|
||||||
|
return L10n.pick(names, api_name.capitalize())
|
||||||
|
|
||||||
|
func get_description() -> String:
|
||||||
|
return L10n.pick(descriptions)
|
||||||
1
data/ability_data.gd.uid
Normal file
1
data/ability_data.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://bhjudhgrl7ohg
|
||||||
14
data/evolution_edge.gd
Normal file
14
data/evolution_edge.gd
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
# data/evolution_edge.gd
|
||||||
|
@tool
|
||||||
|
class_name EvolutionEdge
|
||||||
|
extends Resource
|
||||||
|
|
||||||
|
@export var trigger : String # "level-up", "trade", "use-item", "shed"...
|
||||||
|
@export var min_level : int = 0 # 0 = pas de condition de niveau
|
||||||
|
@export var item : String # objet à utiliser, "" si aucun
|
||||||
|
@export var held_item : String # objet à tenir, "" si aucun
|
||||||
|
@export var known_move : String # capacité requise, "" si aucune
|
||||||
|
@export var min_happiness : int = 0
|
||||||
|
@export var time_of_day : String # "day", "night", "" si indifférent
|
||||||
|
@export var trade_species : String # échange contre cette espèce précise, "" sinon
|
||||||
|
@export var target : EvolutionNode
|
||||||
1
data/evolution_edge.gd.uid
Normal file
1
data/evolution_edge.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://bcfihr0vig1sm
|
||||||
7
data/evolution_node.gd
Normal file
7
data/evolution_node.gd
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
# data/evolution_node.gd
|
||||||
|
@tool
|
||||||
|
class_name EvolutionNode
|
||||||
|
extends Resource
|
||||||
|
|
||||||
|
@export var species_name : String
|
||||||
|
@export var evolves_to : Array[EvolutionEdge] = []
|
||||||
1
data/evolution_node.gd.uid
Normal file
1
data/evolution_node.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://b364h4i46hwo1
|
||||||
7
data/pokemon_ability.gd
Normal file
7
data/pokemon_ability.gd
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
# data/pokemon_ability.gd
|
||||||
|
@tool
|
||||||
|
class_name PokemonAbility
|
||||||
|
extends Resource
|
||||||
|
|
||||||
|
@export var ability : AbilityData
|
||||||
|
@export var is_hidden : bool = false
|
||||||
1
data/pokemon_ability.gd.uid
Normal file
1
data/pokemon_ability.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://cpejtpjkcrvfy
|
||||||
|
|
@ -8,7 +8,8 @@ extends Resource
|
||||||
@export var names : Dictionary = {}
|
@export var names : Dictionary = {}
|
||||||
@export var descriptions : Dictionary = {}
|
@export var descriptions : Dictionary = {}
|
||||||
@export var types : PackedStringArray
|
@export var types : PackedStringArray
|
||||||
@export var abilities : PackedStringArray
|
@export var abilities : Array[PokemonAbility] = [] # remplace l'ancien PackedStringArray
|
||||||
|
@export var evolution_chain : EvolutionNode
|
||||||
@export var base_stats : Dictionary = {}
|
@export var base_stats : Dictionary = {}
|
||||||
@export var height : float
|
@export var height : float
|
||||||
@export var weight : float
|
@export var weight : float
|
||||||
|
|
|
||||||
25
data/type_data.gd
Normal file
25
data/type_data.gd
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
# data/type_data.gd
|
||||||
|
@tool
|
||||||
|
class_name TypeData
|
||||||
|
extends Resource
|
||||||
|
|
||||||
|
@export var id : int
|
||||||
|
@export var api_name : String
|
||||||
|
@export var names : Dictionary = {}
|
||||||
|
|
||||||
|
@export var double_damage_to : PackedStringArray
|
||||||
|
@export var double_damage_from : PackedStringArray
|
||||||
|
@export var half_damage_to : PackedStringArray
|
||||||
|
@export var half_damage_from : PackedStringArray
|
||||||
|
@export var no_damage_to : PackedStringArray
|
||||||
|
@export var no_damage_from : PackedStringArray
|
||||||
|
|
||||||
|
func get_display_name() -> String:
|
||||||
|
return L10n.pick(names, api_name.capitalize())
|
||||||
|
|
||||||
|
## Multiplicateur de dégâts quand ce type attaque `defending_type_name`.
|
||||||
|
func get_multiplier_against(defending_type_name : String) -> float:
|
||||||
|
if defending_type_name in no_damage_to: return 0.0
|
||||||
|
if defending_type_name in double_damage_to: return 2.0
|
||||||
|
if defending_type_name in half_damage_to: return 0.5
|
||||||
|
return 1.0
|
||||||
1
data/type_data.gd.uid
Normal file
1
data/type_data.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://cvvmd5x42xk8n
|
||||||
44
editor/ability_importer.gd
Normal file
44
editor/ability_importer.gd
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
# editor/ability_importer.gd
|
||||||
|
@tool
|
||||||
|
class_name PokeApiAbilityImporter
|
||||||
|
extends RefCounted
|
||||||
|
|
||||||
|
signal message(text : String)
|
||||||
|
|
||||||
|
var _client : PokeApiClient
|
||||||
|
var _overwrite : bool
|
||||||
|
var _languages : PackedStringArray
|
||||||
|
var _dir : String
|
||||||
|
|
||||||
|
func _init(client : PokeApiClient, overwrite : bool) -> void:
|
||||||
|
_client = client
|
||||||
|
_overwrite = overwrite
|
||||||
|
_languages = PokeApiSettings.languages()
|
||||||
|
_dir = PokeApiSettings.abilities_dir()
|
||||||
|
|
||||||
|
func run() -> void:
|
||||||
|
DirAccess.make_dir_recursive_absolute(_dir)
|
||||||
|
var list = await _client.get_json(PokeApiClient.API + "ability?limit=1000")
|
||||||
|
if list == null:
|
||||||
|
message.emit("[color=red]Impossible de récupérer la liste des talents.[/color]")
|
||||||
|
return
|
||||||
|
|
||||||
|
message.emit("%d talents à traiter..." % list["results"].size())
|
||||||
|
await _client.run_parallel(list["results"], _import_ability)
|
||||||
|
message.emit("Talents terminés.")
|
||||||
|
|
||||||
|
func _import_ability(entry : Dictionary) -> void:
|
||||||
|
var path : String = _dir + entry["name"] + ".tres"
|
||||||
|
if !_overwrite and FileAccess.file_exists(path): return
|
||||||
|
|
||||||
|
var j = await _client.get_json(entry["url"])
|
||||||
|
if j == null:
|
||||||
|
message.emit("[color=red]Échec : %s[/color]" % entry["name"])
|
||||||
|
return
|
||||||
|
|
||||||
|
var a := AbilityData.new()
|
||||||
|
a.id = j["id"]
|
||||||
|
a.api_name = j["name"]
|
||||||
|
a.names = PokeApiText.names(j["names"], _languages)
|
||||||
|
a.descriptions = PokeApiText.flavors(j["flavor_text_entries"], _languages)
|
||||||
|
ResourceSaver.save(a, path)
|
||||||
1
editor/ability_importer.gd.uid
Normal file
1
editor/ability_importer.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://dr3x526ada416
|
||||||
52
editor/evolution_importer.gd
Normal file
52
editor/evolution_importer.gd
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
# editor/evolution_importer.gd
|
||||||
|
@tool
|
||||||
|
class_name PokeApiEvolutionImporter
|
||||||
|
extends RefCounted
|
||||||
|
|
||||||
|
var _client : PokeApiClient
|
||||||
|
var _overwrite : bool
|
||||||
|
var _cache : Dictionary = {} # id de chaîne -> EvolutionNode, pour ce run
|
||||||
|
|
||||||
|
func _init(client : PokeApiClient, overwrite : bool) -> void:
|
||||||
|
_client = client
|
||||||
|
_overwrite = overwrite
|
||||||
|
DirAccess.make_dir_recursive_absolute(PokeApiSettings.evolution_dir())
|
||||||
|
|
||||||
|
## Retourne la racine de la chaîne (déjà sauvegardée sur disque au retour).
|
||||||
|
func get_or_build(chain_url : String) -> EvolutionNode:
|
||||||
|
var chain_id := int(String(chain_url).trim_suffix("/").get_file())
|
||||||
|
if _cache.has(chain_id): return _cache[chain_id]
|
||||||
|
|
||||||
|
var path := PokeApiSettings.evolution_dir() + str(chain_id) + ".tres"
|
||||||
|
if !_overwrite and ResourceLoader.exists(path):
|
||||||
|
var existing := load(path) as EvolutionNode
|
||||||
|
_cache[chain_id] = existing
|
||||||
|
return existing
|
||||||
|
|
||||||
|
var j = await _client.get_json(chain_url)
|
||||||
|
if j == null: return null
|
||||||
|
|
||||||
|
var root := _build_node(j["chain"])
|
||||||
|
ResourceSaver.save(root, path)
|
||||||
|
_cache[chain_id] = root
|
||||||
|
return root
|
||||||
|
|
||||||
|
func _build_node(link : Dictionary) -> EvolutionNode:
|
||||||
|
var node := EvolutionNode.new()
|
||||||
|
node.species_name = link["species"]["name"]
|
||||||
|
for evo in link["evolves_to"]:
|
||||||
|
var edge := EvolutionEdge.new()
|
||||||
|
var details : Array = evo["evolution_details"]
|
||||||
|
if !details.is_empty():
|
||||||
|
var det : Dictionary = details[0] # première méthode si plusieurs sont possibles
|
||||||
|
edge.trigger = det["trigger"]["name"] if det["trigger"] != null else ""
|
||||||
|
edge.min_level = int(det["min_level"]) if det["min_level"] != null else 0
|
||||||
|
edge.item = det["item"]["name"] if det["item"] != null else ""
|
||||||
|
edge.held_item = det["held_item"]["name"] if det["held_item"] != null else ""
|
||||||
|
edge.known_move = det["known_move"]["name"] if det["known_move"] != null else ""
|
||||||
|
edge.min_happiness = int(det["min_happiness"]) if det["min_happiness"] != null else 0
|
||||||
|
edge.time_of_day = String(det["time_of_day"]) if det["time_of_day"] != null else ""
|
||||||
|
edge.trade_species = det["trade_species"]["name"] if det["trade_species"] != null else ""
|
||||||
|
edge.target = _build_node(evo)
|
||||||
|
node.evolves_to.append(edge)
|
||||||
|
return node
|
||||||
1
editor/evolution_importer.gd.uid
Normal file
1
editor/evolution_importer.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://dtlgaci7tl522
|
||||||
|
|
@ -20,8 +20,11 @@ func _ready() -> void:
|
||||||
add_child(_client)
|
add_child(_client)
|
||||||
|
|
||||||
_add_button("Importer toutes les capacités", _on_import_moves)
|
_add_button("Importer toutes les capacités", _on_import_moves)
|
||||||
|
_add_button("Importer les types", _on_import_types)
|
||||||
|
_add_button("Importer les talents", _on_import_abilities)
|
||||||
add_child(HSeparator.new())
|
add_child(HSeparator.new())
|
||||||
|
|
||||||
|
|
||||||
var label := Label.new()
|
var label := Label.new()
|
||||||
label.text = "Pokémon (ids, noms, plages) :"
|
label.text = "Pokémon (ids, noms, plages) :"
|
||||||
add_child(label)
|
add_child(label)
|
||||||
|
|
@ -62,6 +65,24 @@ func _on_import_moves() -> void:
|
||||||
editor_filesystem.scan()
|
editor_filesystem.scan()
|
||||||
_set_busy(false)
|
_set_busy(false)
|
||||||
|
|
||||||
|
func _on_import_types() -> void:
|
||||||
|
if _busy: return
|
||||||
|
_set_busy(true)
|
||||||
|
var importer := PokeApiTypeImporter.new(_client, _overwrite.button_pressed)
|
||||||
|
importer.message.connect(_print)
|
||||||
|
await importer.run()
|
||||||
|
editor_filesystem.scan()
|
||||||
|
_set_busy(false)
|
||||||
|
|
||||||
|
func _on_import_abilities() -> void:
|
||||||
|
if _busy: return
|
||||||
|
_set_busy(true)
|
||||||
|
var importer := PokeApiAbilityImporter.new(_client, _overwrite.button_pressed)
|
||||||
|
importer.message.connect(_print)
|
||||||
|
await importer.run()
|
||||||
|
editor_filesystem.scan()
|
||||||
|
_set_busy(false)
|
||||||
|
|
||||||
func _on_import_pokemon() -> void:
|
func _on_import_pokemon() -> void:
|
||||||
if _busy: return
|
if _busy: return
|
||||||
var tokens := _parse_input(_input.text)
|
var tokens := _parse_input(_input.text)
|
||||||
|
|
|
||||||
|
|
@ -10,18 +10,24 @@ var _fs : EditorFileSystem
|
||||||
var _overwrite : bool
|
var _overwrite : bool
|
||||||
var _languages : PackedStringArray
|
var _languages : PackedStringArray
|
||||||
var _pending : Array = [] # pokémon récupérés, en attente de sauvegarde
|
var _pending : Array = [] # pokémon récupérés, en attente de sauvegarde
|
||||||
|
var _evolution : PokeApiEvolutionImporter
|
||||||
|
|
||||||
func _init(client : PokeApiClient, fs : EditorFileSystem, overwrite : bool) -> void:
|
func _init(client : PokeApiClient, fs : EditorFileSystem, overwrite : bool) -> void:
|
||||||
_client = client
|
_client = client
|
||||||
_fs = fs
|
_fs = fs
|
||||||
_overwrite = overwrite
|
_overwrite = overwrite
|
||||||
_languages = PokeApiSettings.languages()
|
_languages = PokeApiSettings.languages()
|
||||||
|
_evolution = PokeApiEvolutionImporter.new(_client, _overwrite)
|
||||||
|
|
||||||
func run(tokens : Array) -> void:
|
func run(tokens : Array) -> void:
|
||||||
DirAccess.make_dir_recursive_absolute(PokeApiSettings.pokemon_dir())
|
DirAccess.make_dir_recursive_absolute(PokeApiSettings.pokemon_dir())
|
||||||
DirAccess.make_dir_recursive_absolute(PokeApiSettings.sprites_dir())
|
DirAccess.make_dir_recursive_absolute(PokeApiSettings.sprites_dir())
|
||||||
if !DirAccess.dir_exists_absolute(PokeApiSettings.moves_dir()):
|
if !DirAccess.dir_exists_absolute(PokeApiSettings.moves_dir()):
|
||||||
message.emit("[color=orange]Aucune capacité importée : les learnsets seront vides.[/color]")
|
message.emit("[color=orange]Aucune capacité importée : les learnsets seront vides.[/color]")
|
||||||
|
if !DirAccess.dir_exists_absolute(PokeApiSettings.moves_dir()):
|
||||||
|
message.emit("[color=orange]Aucune capacité importée : les learnsets seront vides.[/color]")
|
||||||
|
if !DirAccess.dir_exists_absolute(PokeApiSettings.abilities_dir()):
|
||||||
|
message.emit("[color=orange]Aucun talent importé : les talents des pokémon seront vides.[/color]")
|
||||||
|
|
||||||
_pending.clear()
|
_pending.clear()
|
||||||
await _client.run_parallel(tokens, _fetch_pokemon) # phase 1 : téléchargement
|
await _client.run_parallel(tokens, _fetch_pokemon) # phase 1 : téléchargement
|
||||||
|
|
@ -52,7 +58,7 @@ func _fetch_pokemon(token : Variant) -> void:
|
||||||
for t in j["types"]:
|
for t in j["types"]:
|
||||||
d.types.append(t["type"]["name"])
|
d.types.append(t["type"]["name"])
|
||||||
for a in j["abilities"]:
|
for a in j["abilities"]:
|
||||||
d.abilities.append(a["ability"]["name"])
|
d.abilities = _build_abilities(j["abilities"])
|
||||||
for s in j["stats"]:
|
for s in j["stats"]:
|
||||||
d.base_stats[s["stat"]["name"]] = s["base_stat"]
|
d.base_stats[s["stat"]["name"]] = s["base_stat"]
|
||||||
|
|
||||||
|
|
@ -60,6 +66,8 @@ func _fetch_pokemon(token : Variant) -> void:
|
||||||
if species != null:
|
if species != null:
|
||||||
d.names = PokeApiText.names(species["names"], _languages)
|
d.names = PokeApiText.names(species["names"], _languages)
|
||||||
d.descriptions = PokeApiText.flavors(species["flavor_text_entries"], _languages)
|
d.descriptions = PokeApiText.flavors(species["flavor_text_entries"], _languages)
|
||||||
|
if species.get("evolution_chain") != null:
|
||||||
|
d.evolution_chain = await _evolution.get_or_build(species["evolution_chain"]["url"])
|
||||||
|
|
||||||
var sprites : Dictionary = j["sprites"]
|
var sprites : Dictionary = j["sprites"]
|
||||||
var art : Dictionary = sprites.get("other", {}).get("official-artwork", {})
|
var art : Dictionary = sprites.get("other", {}).get("official-artwork", {})
|
||||||
|
|
@ -123,3 +131,14 @@ func _build_learnset(raw_moves : Array) -> Array[LearnedMove]:
|
||||||
result.append(lm)
|
result.append(lm)
|
||||||
result.sort_custom(func(a : LearnedMove, b : LearnedMove) -> bool: return a.level < b.level)
|
result.sort_custom(func(a : LearnedMove, b : LearnedMove) -> bool: return a.level < b.level)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
func _build_abilities(raw_abilities : Array) -> Array[PokemonAbility]:
|
||||||
|
var result : Array[PokemonAbility] = []
|
||||||
|
for a in raw_abilities:
|
||||||
|
var path : String = PokeApiSettings.abilities_dir() + String(a["ability"]["name"]) + ".tres"
|
||||||
|
if !FileAccess.file_exists(path): continue
|
||||||
|
var pa := PokemonAbility.new()
|
||||||
|
pa.ability = load(path) as AbilityData
|
||||||
|
pa.is_hidden = a["is_hidden"]
|
||||||
|
result.append(pa)
|
||||||
|
return result
|
||||||
|
|
|
||||||
61
editor/type_importer.gd
Normal file
61
editor/type_importer.gd
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
# editor/type_importer.gd
|
||||||
|
@tool
|
||||||
|
class_name PokeApiTypeImporter
|
||||||
|
extends RefCounted
|
||||||
|
|
||||||
|
signal message(text : String)
|
||||||
|
|
||||||
|
var _client : PokeApiClient
|
||||||
|
var _overwrite : bool
|
||||||
|
var _languages : PackedStringArray
|
||||||
|
var _dir : String
|
||||||
|
|
||||||
|
func _init(client : PokeApiClient, overwrite : bool) -> void:
|
||||||
|
_client = client
|
||||||
|
_overwrite = overwrite
|
||||||
|
_languages = PokeApiSettings.languages()
|
||||||
|
_dir = PokeApiSettings.types_dir()
|
||||||
|
|
||||||
|
func run() -> void:
|
||||||
|
DirAccess.make_dir_recursive_absolute(_dir)
|
||||||
|
var list = await _client.get_json(PokeApiClient.API + "type?limit=100")
|
||||||
|
if list == null:
|
||||||
|
message.emit("[color=red]Impossible de récupérer la liste des types.[/color]")
|
||||||
|
return
|
||||||
|
|
||||||
|
var entries : Array = []
|
||||||
|
for r in list["results"]:
|
||||||
|
var id : int = int(String(r["url"]).trim_suffix("/").get_file())
|
||||||
|
if id < 10000: entries.append(r) # ignore "unknown"/"shadow" (10001, 10002)
|
||||||
|
|
||||||
|
message.emit("%d types à traiter..." % entries.size())
|
||||||
|
await _client.run_parallel(entries, _import_type)
|
||||||
|
message.emit("Types terminés.")
|
||||||
|
|
||||||
|
func _import_type(entry : Dictionary) -> void:
|
||||||
|
var path : String = _dir + entry["name"] + ".tres"
|
||||||
|
if !_overwrite and FileAccess.file_exists(path): return
|
||||||
|
|
||||||
|
var j = await _client.get_json(entry["url"])
|
||||||
|
if j == null:
|
||||||
|
message.emit("[color=red]Échec : %s[/color]" % entry["name"])
|
||||||
|
return
|
||||||
|
|
||||||
|
var t := TypeData.new()
|
||||||
|
t.id = j["id"]
|
||||||
|
t.api_name = j["name"]
|
||||||
|
t.names = PokeApiText.names(j["names"], _languages)
|
||||||
|
|
||||||
|
var rel : Dictionary = j["damage_relations"]
|
||||||
|
t.double_damage_to = _names_of(rel["double_damage_to"])
|
||||||
|
t.double_damage_from = _names_of(rel["double_damage_from"])
|
||||||
|
t.half_damage_to = _names_of(rel["half_damage_to"])
|
||||||
|
t.half_damage_from = _names_of(rel["half_damage_from"])
|
||||||
|
t.no_damage_to = _names_of(rel["no_damage_to"])
|
||||||
|
t.no_damage_from = _names_of(rel["no_damage_from"])
|
||||||
|
ResourceSaver.save(t, path)
|
||||||
|
|
||||||
|
func _names_of(entries : Array) -> PackedStringArray:
|
||||||
|
var out := PackedStringArray()
|
||||||
|
for e in entries: out.append(e["name"])
|
||||||
|
return out
|
||||||
1
editor/type_importer.gd.uid
Normal file
1
editor/type_importer.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://ceb3knywwobbt
|
||||||
|
|
@ -45,6 +45,9 @@ static func max_concurrent() -> int:
|
||||||
static func moves_dir() -> String: return data_dir() + "/moves/"
|
static func moves_dir() -> String: return data_dir() + "/moves/"
|
||||||
static func pokemon_dir() -> String: return data_dir() + "/pokemon/"
|
static func pokemon_dir() -> String: return data_dir() + "/pokemon/"
|
||||||
static func sprites_dir() -> String: return data_dir() + "/sprites/"
|
static func sprites_dir() -> String: return data_dir() + "/sprites/"
|
||||||
|
static func types_dir() -> String: return data_dir() + "/types/"
|
||||||
|
static func abilities_dir() -> String: return data_dir() + "/abilities/"
|
||||||
|
static func evolution_dir() -> String: return data_dir() + "/evolution/"
|
||||||
|
|
||||||
# nommage des fichiers pokémon : "0025_pikachu"
|
# nommage des fichiers pokémon : "0025_pikachu"
|
||||||
static func pokemon_stem(id : int, api_name : String) -> String:
|
static func pokemon_stem(id : int, api_name : String) -> String:
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue