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 descriptions : Dictionary = {}
|
||||
@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 height : 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_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())
|
||||
|
||||
|
||||
var label := Label.new()
|
||||
label.text = "Pokémon (ids, noms, plages) :"
|
||||
add_child(label)
|
||||
|
|
@ -62,6 +65,24 @@ func _on_import_moves() -> void:
|
|||
editor_filesystem.scan()
|
||||
_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:
|
||||
if _busy: return
|
||||
var tokens := _parse_input(_input.text)
|
||||
|
|
|
|||
|
|
@ -10,18 +10,24 @@ var _fs : EditorFileSystem
|
|||
var _overwrite : bool
|
||||
var _languages : PackedStringArray
|
||||
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:
|
||||
_client = client
|
||||
_fs = fs
|
||||
_overwrite = overwrite
|
||||
_languages = PokeApiSettings.languages()
|
||||
_evolution = PokeApiEvolutionImporter.new(_client, _overwrite)
|
||||
|
||||
func run(tokens : Array) -> void:
|
||||
DirAccess.make_dir_recursive_absolute(PokeApiSettings.pokemon_dir())
|
||||
DirAccess.make_dir_recursive_absolute(PokeApiSettings.sprites_dir())
|
||||
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.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()
|
||||
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"]:
|
||||
d.types.append(t["type"]["name"])
|
||||
for a in j["abilities"]:
|
||||
d.abilities.append(a["ability"]["name"])
|
||||
d.abilities = _build_abilities(j["abilities"])
|
||||
for s in j["stats"]:
|
||||
d.base_stats[s["stat"]["name"]] = s["base_stat"]
|
||||
|
||||
|
|
@ -60,6 +66,8 @@ func _fetch_pokemon(token : Variant) -> void:
|
|||
if species != null:
|
||||
d.names = PokeApiText.names(species["names"], _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 art : Dictionary = sprites.get("other", {}).get("official-artwork", {})
|
||||
|
|
@ -123,3 +131,14 @@ func _build_learnset(raw_moves : Array) -> Array[LearnedMove]:
|
|||
result.append(lm)
|
||||
result.sort_custom(func(a : LearnedMove, b : LearnedMove) -> bool: return a.level < b.level)
|
||||
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 pokemon_dir() -> String: return data_dir() + "/pokemon/"
|
||||
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"
|
||||
static func pokemon_stem(id : int, api_name : String) -> String:
|
||||
|
|
|
|||
Loading…
Reference in a new issue