mirror of
https://gitlab.com/cable-mc/cobblemon.git
synced 2026-10-29 21:38:53 -04:00
Temporarily exchanges items that aren't in Cobblemon referenced on some species with items that are, avoiding the crash that would occur when Bisharp's evolution was parsed. Adds a new utility script to mass-manage TM/Tutor moves from the movepool. Reintroduces the "tutor" subset of TMs for addons that utilize the source already. More aggressive culling on unplanned base-mod TM moves from level/egg pools, this prevents breakage with addons using the "lazy" way of only pulling the source in species data. Doing this will eventually break custom TMs in the TMM, so it is recommended that addons/plugins migrate to global lists of TMs for interfacing moves instead of just pulling "tm:" for each species. Also re-preps the aspect format for Keldeo's species feature to match others.
196 lines
13 KiB
Python
196 lines
13 KiB
Python
import os
|
|
import json
|
|
|
|
# This is the entire list of "External Moves" as it is designated in official game data.
|
|
# Functionally, it is our entire list of potential base-mod TMs when the TMM is complete.
|
|
# Fans often split these into "TM moves" and "Tutor moves" depending on the game.
|
|
potential_tm_list = [
|
|
"focuspunch", "dragonclaw", "waterpulse", "calmmind", "roar", "toxic", "hail", "bulkup", "bulletseed",
|
|
"sunnyday", "taunt", "icebeam", "blizzard", "hyperbeam", "lightscreen", "protect", "raindance", "gigadrain",
|
|
"safeguard", "solarbeam", "irontail", "thunderbolt", "thunder", "earthquake", "dig", "psychic", "shadowball",
|
|
"brickbreak", "doubleteam", "reflect", "shockwave", "flamethrower", "sludgebomb", "sandstorm", "fireblast", "rocktomb",
|
|
"aerialace", "torment", "facade", "secretpower", "rest", "attract", "thief", "steelwing", "skillswap",
|
|
"snatch", "overheat", "roost", "focusblast", "energyball", "falseswipe", "brine", "fling", "chargebeam",
|
|
"endure", "dragonpulse", "drainpunch", "willowisp", "silverwind", "embargo", "explosion", "shadowclaw", "payback",
|
|
"recycle", "gigaimpact", "rockpolish", "flash", "stoneedge", "avalanche", "thunderwave", "gyroball", "swordsdance",
|
|
"stealthrock", "psychup", "captivate", "darkpulse", "rockslide", "xscissor", "sleeptalk", "naturalgift", "poisonjab",
|
|
"dreameater", "grassknot", "swagger", "pluck", "uturn", "substitute", "flashcannon", "trickroom", "dive",
|
|
"mudslap", "furycutter", "icywind", "rollout", "thunderpunch", "firepunch", "superpower", "icepunch", "ironhead",
|
|
"aquatail", "ominouswind", "gastroacid", "snore", "spite", "aircutter", "helpinghand", "endeavor", "outrage",
|
|
"ancientpower", "synthesis", "signalbeam", "zenheadbutt", "vacuumwave", "earthpower", "gunkshot", "twister", "seedbomb",
|
|
"irondefense", "magnetrise", "lastresort", "bounce", "trick", "heatwave", "knockoff", "suckerpunch", "swift",
|
|
"uproar", "superfang", "painsplit", "stringshot", "tailwind", "gravity", "worryseed", "magiccoat", "roleplay",
|
|
"healbell", "lowkick", "skyattack", "block", "bugbite", "headbutt", "cut", "fly", "surf",
|
|
"strength", "whirlpool", "defog", "rocksmash", "waterfall", "rockclimb", "honeclaws", "psyshock", "venoshock",
|
|
"telekinesis", "smackdown", "sludgewave", "flamecharge", "lowsweep", "round", "echoedvoice", "allyswitch", "scald",
|
|
"skydrop", "incinerate", "quash", "acrobatics", "retaliate", "voltswitch", "strugglebug", "bulldoze", "frostbreath",
|
|
"dragontail", "workup", "afteryou", "magicroom", "wonderroom", "bind", "foulplay", "electroweb", "hypervoice",
|
|
"covet", "dualchop", "drillrun", "wildcharge", "snarl", "grasspledge", "firepledge", "waterpledge", "frenzyplant",
|
|
"blastburn", "hydrocannon", "dracometeor", "infestation", "naturepower", "poweruppunch", "dazzlinggleam", "confide", "leechlife",
|
|
"brutalswing", "smartstrike", "auroraveil", "liquidation", "stompingtantrum", "throatchop", "laserfocus", "megapunch", "megakick",
|
|
"payday", "pinmissile", "magicalleaf", "solarblade", "firespin", "screech", "selfdestruct", "scaryface", "charm",
|
|
"beatup", "revenge", "imprison", "weatherball", "faketears", "sandtomb", "iciclespear", "mudshot", "rockblast",
|
|
"assurance", "powerswap", "guardswap", "speedswap", "thunderfang", "icefang", "firefang", "psychocut", "crosspoison",
|
|
"hex", "razorshell", "tailslap", "phantomforce", "drainingkiss", "grassyterrain", "mistyterrain", "electricterrain", "psychicterrain",
|
|
"mysticalfire", "eerieimpulse", "airslash", "breakingswipe", "bodyslam", "hydropump", "agility", "focusenergy", "metronome",
|
|
"amnesia", "triattack", "reversal", "spikes", "megahorn", "batonpass", "encore", "crunch", "futuresight",
|
|
"blazekick", "cosmicpower", "muddywater", "leafblade", "dragondance", "closecombat", "toxicspikes", "flareblitz", "aurasphere",
|
|
"bugbuzz", "powergem", "bravebird", "nastyplot", "leafstorm", "powerwhip", "heavyslam", "electroball", "storedpower",
|
|
"heatcrash", "hurricane", "playrough", "venomdrench", "darkestlariat", "highhorsepower", "pollenpuff", "psychicfangs", "bodypress",
|
|
"steelbeam", "terrainpulse", "burningjealousy", "flipturn", "risingvoltage", "grassyglide", "tripleaxel", "coaching", "corrosivegas",
|
|
"scorchingsands", "dualwingbeat", "expandingforce", "skittersmack", "meteorbeam", "poltergeist", "scaleshot", "lashout", "steelroller",
|
|
"mistyexplosion", "iceball", "powershift", "babydolleyes", "takedown", "acidspray", "psybeam", "confuseray", "disarmingvoice",
|
|
"trailblaze", "pounce", "chillingwater", "poisontail", "metalclaw", "nightshade", "snowscape", "icespinner", "terablast",
|
|
"charge", "haze", "lunge", "doubleedge", "petalblizzard", "temperflare", "supercellslam", "featherdance", "metalsound",
|
|
"curse", "hardpress", "dragoncheer", "alluringvoice", "psychicnoise", "upperhand"
|
|
]
|
|
|
|
# 99% of this is a subset of TMs since Tutors no longer exist in the official games.
|
|
# Since addons use the source anyways, we will provide some minor redundancy to maintain support. :)
|
|
# The assumption here is if we decide to have special tutor moves, this list won't just repeat TMs.
|
|
# This list will probably be useless then, because deviating from official sets would require manual edits to the species files.
|
|
tutor_list = [
|
|
"aerialace", "afteryou", "aircutter", "allyswitch", "ancientpower", "aquatail", "babydolleyes",
|
|
"bind", "blastburn", "block", "bounce", "bugbite", "bulkup", "bulldoze",
|
|
"burningjealousy", "calmmind", "chargebeam", "coaching", "corrosivegas", "covet", "darkpulse",
|
|
"dazzlinggleam", "defog", "dive", "dracometeor", "dragonascent", "dragonpulse", "drainpunch",
|
|
"drillrun", "dualchop", "dualwingbeat", "earthpower", "electroweb", "endeavor", "energyball",
|
|
"expandingforce", "falseswipe", "firefang", "firepledge", "firepunch", "flamethrower", "flashcannon",
|
|
"flipturn", "focusenergy", "focuspunch", "foulplay", "frenzyplant", "furycutter", "gastroacid",
|
|
"gigadrain", "gigaimpact", "grasspledge", "grassyglide", "gravity", "gunkshot", "healbell",
|
|
"heatwave", "helpinghand", "highhorsepower", "hydrocannon", "hyperbeam", "hypervoice", "iceball",
|
|
"icebeam", "icefang", "icepunch", "icywind", "irondefense", "ironhead", "irontail",
|
|
"knockoff", "laserfocus", "lashout", "lastresort", "leechlife", "liquidation", "lowkick",
|
|
"magiccoat", "magicroom", "magicalleaf", "magnetrise", "megahorn", "meteorbeam", "mistyexplosion",
|
|
"mudslap", "mysticalfire", "ominouswind", "outrage", "painsplit", "playrough", "poisonjab",
|
|
"poltergeist", "powershift", "psychic", "psychocut", "recycle", "relicsong", "rest",
|
|
"risingvoltage", "rockslide", "rocksmash", "roleplay", "rollout", "roost", "scaleshot",
|
|
"scorchingsands", "secretsword", "seedbomb", "shadowball", "shadowclaw", "shockwave", "signalbeam",
|
|
"skillswap", "skittersmack", "skyattack", "sleeptalk", "sludgebomb", "snarl", "snatch",
|
|
"snore", "spikes", "spite", "stealthrock", "steelbeam", "steelroller", "stompingtantrum",
|
|
"stoneedge", "stringshot", "suckerpunch", "superfang", "superpower", "swift", "synthesis",
|
|
"tailwind", "telekinesis", "terrainpulse", "throatchop", "thunderfang", "thunderpunch", "thunderbolt",
|
|
"triaattack", "trick", "tripleaxel", "twister", "uproar", "vacuumwave", "volttackle",
|
|
"waterpledge", "waterpulse", "wildcharge", "wonderroom", "worryseed", "xscissor", "zenheadbutt"
|
|
]
|
|
|
|
# These Pokemon are always allowed to learn every External Move in the games.
|
|
# By "these" we mean Mew. Mew is the only one, but even it isn't always in every game.
|
|
# Unless the list of TMs ONLY represents games where Mew is present, this is necessary.
|
|
always_tm_species = [
|
|
"mew"
|
|
]
|
|
|
|
# These Pokemon are never allowed to learn any moves outside of their available set.
|
|
# Addons can do as they please, but "official" behavior says never-ever.
|
|
never_tm_species = [
|
|
"magikarp", "ditto", "unown", "wobbuffet", "smeargle", "wynaut", "pyukumuku", "cosmog", "cosmoem"
|
|
]
|
|
|
|
# These Pokemon would be part of the "never_tm" list if not for Tera Blast.
|
|
# We don't know if there will be other universal gimmick moves like Tera Blast, better safe than sorry.
|
|
# We still won't teach these anything aside from Tera Blast.
|
|
sometimes_tm_species = [
|
|
"caterpie", "metapod", "weedle", "kakuna", "wurmple", "silcoon", "cascoon", "beldum", "kricketot",
|
|
"burmy", "combee", "tynamo", "scatterbug", "spewpa", "blipbug", "applin", "snom"
|
|
]
|
|
|
|
# List of desired moves that are learned by everything, where Pokemon haven't appeared in a game its featured in.
|
|
# We should ideally never add to this list, best to make no assumptions on who learns what unless game data suggests.
|
|
# Protect and Substitute are examples of this, but not necessary since they have consistently appeared every game.
|
|
universal_tms = [
|
|
]
|
|
|
|
# Only do this because it is such a pivotal component of Terastal.
|
|
# It's also not quite just a "universal tm" because even more Pokemon than those learn it.
|
|
super_universal_tms = [
|
|
"terablast"
|
|
]
|
|
|
|
# List of moves that when available have been learnable by everyone, but haven't been TMs for some time.
|
|
# If desired, place these in universal_tms to replicate the behavior from the games these moves were TMs in.
|
|
# Otherwise, restrict them to only those who learn organically to avoid overcentralization.
|
|
# (You don't really want everything to learn Double Team and Swagger, right? RIGHT?!)
|
|
ambiguously_present_tms = [
|
|
"captivate", "attract", "naturalgift", "secretpower", "confide", "swagger",
|
|
"doubleteam", "round", "snore"
|
|
]
|
|
|
|
# Though they aren't in recent TM availability, Captivate and Attract are reasonably learnable by all who have a gender.
|
|
# If you want to include them as TMs, include them here.
|
|
# Note: Nincada/Ninjask lost these due to an additional rule with genderless evos.
|
|
gender_only_tms = [
|
|
]
|
|
|
|
# These are moves that have been designated as "signature moves" for particular Pokemon.
|
|
# While they could be functional TMs, only being learnable by one line is a deterrent.
|
|
# Note: Hidden Power, Return, and Frustration are formerly universal.
|
|
# Keep them here if you want "latest" mechanics, remove them if you long for the past. (Beware HP Ice Regieleki!)
|
|
signature_move_tms = [
|
|
"volttackle", "hiddenpower", "return", "frustration", "secretsword", "relicsong", "dragonascent"
|
|
]
|
|
|
|
# List of directories to process
|
|
base_directories = [
|
|
'species/generation1', 'species/generation2', 'species/generation3', 'species/generation4',
|
|
'species/generation5', 'species/generation6', 'species/generation7', 'species/generation7b',
|
|
'species/generation8', 'species/generation8a', 'species/generation9'
|
|
]
|
|
output_directory = 'species'
|
|
|
|
def process_species_file(base_species_data, base_species_path, output_file_path):
|
|
os.makedirs(os.path.dirname(output_file_path), exist_ok=True)
|
|
|
|
def process_moves(moves):
|
|
for move in tutor_list:
|
|
tutor_move = f"tutor:{move}"
|
|
if any(move in m for m in moves) and tutor_move not in moves:
|
|
moves.append(tutor_move)
|
|
|
|
# Curates TM source for "tighter" representation of what is actually an externally available move.
|
|
# Note: This will break custom/datapackable TMs in the future and necessitates manual edits to get them to work.
|
|
moves = [move for move in moves if not (move.startswith('tm:') and move.split(':')[1] not in potential_tm_list and any(
|
|
move.split(':')[1] in m for m in moves if m.split(':')[0].isdigit() or m.startswith('egg:')
|
|
))]
|
|
|
|
# Give em the ol' sort-a-roo.
|
|
egg_moves = sorted([move for move in moves if move.startswith('egg:')])
|
|
tm_moves = sorted([move for move in moves if move.startswith('tm:')])
|
|
tutor_moves = sorted([move for move in moves if move.startswith('tutor:')])
|
|
other_moves = [move for move in moves if not (move.startswith('tm:') or move.startswith('tutor:') or move.startswith('egg:'))]
|
|
|
|
moves = other_moves + egg_moves + tm_moves + tutor_moves
|
|
|
|
return moves
|
|
|
|
# Mew? Mew. (Ensures Mew's functionality isn't compromised by the games' differing species/move availability.)
|
|
if base_species_data['name'].lower() in always_tm_species:
|
|
for move in potential_tm_list:
|
|
tm_move = f"tm:{move}"
|
|
if tm_move not in base_species_data['moves']:
|
|
base_species_data['moves'].append(tm_move)
|
|
|
|
# Process base species moves
|
|
base_species_data['moves'] = process_moves(base_species_data.get('moves', []))
|
|
|
|
# Process moves for each form
|
|
for form in base_species_data.get('forms', []):
|
|
form['moves'] = process_moves(form.get('moves', []))
|
|
|
|
# Write the modified data to the output file
|
|
with open(output_file_path, 'w') as output_file:
|
|
json.dump(base_species_data, output_file, indent=2)
|
|
|
|
# Process each species file in the base directories and its subdirectories
|
|
for base_directory in base_directories:
|
|
for root, _, files in os.walk(base_directory):
|
|
for filename in files:
|
|
if filename.endswith('.json'):
|
|
base_species_path = os.path.join(root, filename)
|
|
with open(base_species_path, 'r') as file:
|
|
base_species_data = json.load(file)
|
|
|
|
relative_path = os.path.relpath(base_species_path, base_directory)
|
|
output_file_path = os.path.join(output_directory, base_directory.split('/')[-1], relative_path)
|
|
process_species_file(base_species_data, base_species_path, output_file_path)
|