mirror of
https://github.com/veekun/pokedex.git
synced 2024-08-20 18:16:34 +00:00
Figure out, fix, and dump a bunch of "mystery" data from moves and Pokémon
This commit is contained in:
parent
cf7526a39a
commit
956ba7a426
2 changed files with 199 additions and 72 deletions
|
@ -19,8 +19,8 @@ from construct import (
|
||||||
Const, Flag, Int16sl, Int16ul, Int8sl, Int8ul, Int32ul, Padding,
|
Const, Flag, Int16sl, Int16ul, Int8sl, Int8ul, Int32ul, Padding,
|
||||||
# Structures and meta stuff
|
# Structures and meta stuff
|
||||||
Array, BitsInteger, BitsSwapped, Bitwise, Embedded, Enum, Filter,
|
Array, BitsInteger, BitsSwapped, Bitwise, Embedded, Enum, Filter,
|
||||||
FocusedSeq, GreedyRange, Pointer, PrefixedArray, Range, Struct, Terminated,
|
FlagsEnum, FocusedSeq, GreedyRange, Pointer, PrefixedArray, Range, Struct,
|
||||||
this,
|
Terminated, this,
|
||||||
# temp
|
# temp
|
||||||
Peek, Bytes,
|
Peek, Bytes,
|
||||||
)
|
)
|
||||||
|
@ -90,17 +90,32 @@ EGG_GROUPS = {
|
||||||
15: 'eg.no-eggs',
|
15: 'eg.no-eggs',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# TODO the order of these in the veekun db doesn't match the order in the games
|
||||||
|
COLORS = {
|
||||||
|
4: 'pc.black',
|
||||||
|
1: 'pc.blue',
|
||||||
|
5: 'pc.brown',
|
||||||
|
7: 'pc.gray',
|
||||||
|
3: 'pc.green',
|
||||||
|
9: 'pc.pink',
|
||||||
|
6: 'pc.purple',
|
||||||
|
0: 'pc.red',
|
||||||
|
8: 'pc.white',
|
||||||
|
2: 'pc.yellow',
|
||||||
|
}
|
||||||
|
|
||||||
DAMAGE_CLASSES = {
|
DAMAGE_CLASSES = {
|
||||||
0: 'dc.status',
|
0: 'dc.status',
|
||||||
1: 'dc.physical',
|
1: 'dc.physical',
|
||||||
2: 'dc.special',
|
2: 'dc.special',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# TODO the order of these in the veekun db doesn't match the order in the games
|
||||||
MOVE_RANGES = {
|
MOVE_RANGES = {
|
||||||
13: 'mr.specific-move',
|
13: 'mr.specific-move',
|
||||||
3: 'mr.selected-pokemon-me-first',
|
3: 'mr.selected-pokemon-me-first',
|
||||||
2: 'mr.ally',
|
2: 'mr.ally',
|
||||||
6: 'mr.users-field',
|
12: 'mr.users-field',
|
||||||
1: 'mr.user-or-ally',
|
1: 'mr.user-or-ally',
|
||||||
11: 'mr.opponents-field',
|
11: 'mr.opponents-field',
|
||||||
7: 'mr.user',
|
7: 'mr.user',
|
||||||
|
@ -109,10 +124,96 @@ MOVE_RANGES = {
|
||||||
0: 'mr.selected-pokemon',
|
0: 'mr.selected-pokemon',
|
||||||
5: 'mr.all-opponents',
|
5: 'mr.all-opponents',
|
||||||
10: 'mr.entire-field',
|
10: 'mr.entire-field',
|
||||||
12: 'mr.user-and-allies',
|
6: 'mr.user-and-allies',
|
||||||
8: 'mr.all-pokemon',
|
8: 'mr.all-pokemon',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AILMENTS = {
|
||||||
|
-1: 'ma.unknown',
|
||||||
|
0: 'ma.none',
|
||||||
|
1: 'ma.paralysis',
|
||||||
|
2: 'ma.sleep',
|
||||||
|
3: 'ma.freeze',
|
||||||
|
4: 'ma.burn',
|
||||||
|
5: 'ma.poison',
|
||||||
|
6: 'ma.confusion',
|
||||||
|
7: 'ma.infatuation',
|
||||||
|
8: 'ma.trap',
|
||||||
|
9: 'ma.nightmare',
|
||||||
|
12: 'ma.torment',
|
||||||
|
13: 'ma.disable',
|
||||||
|
14: 'ma.yawn',
|
||||||
|
15: 'ma.heal-block',
|
||||||
|
17: 'ma.no-type-immunity',
|
||||||
|
18: 'ma.leech-seed',
|
||||||
|
19: 'ma.embargo',
|
||||||
|
20: 'ma.perish-song',
|
||||||
|
21: 'ma.ingrain',
|
||||||
|
24: 'ma.silence',
|
||||||
|
}
|
||||||
|
|
||||||
|
MOVE_CATEGORIES = {
|
||||||
|
0: 'mc.damage',
|
||||||
|
1: 'mc.ailment',
|
||||||
|
2: 'mc.net-good-stats',
|
||||||
|
3: 'mc.heal',
|
||||||
|
4: 'mc.damage+ailment',
|
||||||
|
5: 'mc.swagger',
|
||||||
|
6: 'mc.damage+lower',
|
||||||
|
7: 'mc.damage+raise',
|
||||||
|
8: 'mc.damage+heal',
|
||||||
|
9: 'mc.ohko',
|
||||||
|
10: 'mc.whole-field-effect',
|
||||||
|
11: 'mc.field-effect',
|
||||||
|
12: 'mc.force-switch',
|
||||||
|
13: 'mc.unique',
|
||||||
|
}
|
||||||
|
|
||||||
|
MOVE_FLAGS = {
|
||||||
|
1: 'mf.contact',
|
||||||
|
2: 'mf.charge',
|
||||||
|
3: 'mf.recharge',
|
||||||
|
4: 'mf.protect',
|
||||||
|
5: 'mf.reflectable',
|
||||||
|
6: 'mf.snatch',
|
||||||
|
7: 'mf.mirror',
|
||||||
|
8: 'mf.punch',
|
||||||
|
9: 'mf.sound',
|
||||||
|
10: 'mf.gravity',
|
||||||
|
11: 'mf.defrost',
|
||||||
|
12: 'mf.distance',
|
||||||
|
13: 'mf.heal',
|
||||||
|
14: 'mf.authentic',
|
||||||
|
# FIXME this was powder before? whenever "before" was? also this name, is bad.
|
||||||
|
15: 'mf.non-sky-battle',
|
||||||
|
|
||||||
|
# NOTE: 16 indicates a distinct animation when the move is used on an ally,
|
||||||
|
# I think; doesn't seem like something we care about
|
||||||
|
#16: 'mf.unknown16',
|
||||||
|
|
||||||
|
# FIXME this is new
|
||||||
|
17: 'mf.dance',
|
||||||
|
|
||||||
|
# FIXME these are either gone, or in a different order? the last four seem
|
||||||
|
# to be inventions by surskitty, not sure where they came from
|
||||||
|
#16: 'mf.bite',
|
||||||
|
#17: 'mf.pulse',
|
||||||
|
#18: 'mf.ballistics',
|
||||||
|
#19: 'mf.mental',
|
||||||
|
#20: 'mf.non-sky-battle',
|
||||||
|
}
|
||||||
|
|
||||||
|
# FIXME hokey; "all" in particular is not great
|
||||||
|
MOVE_STATS = {
|
||||||
|
1: 'st.attack',
|
||||||
|
2: 'st.defense',
|
||||||
|
3: 'st.special-attack',
|
||||||
|
4: 'st.special-defense',
|
||||||
|
5: 'st.speed',
|
||||||
|
6: 'st.accuracy',
|
||||||
|
7: 'st.evasion',
|
||||||
|
8: 'st.all',
|
||||||
|
}
|
||||||
|
|
||||||
# ja-Hrkt: hiragana/katakana
|
# ja-Hrkt: hiragana/katakana
|
||||||
# zh-Hans: simplified
|
# zh-Hans: simplified
|
||||||
|
@ -406,21 +507,26 @@ pokemon_struct = Struct(
|
||||||
'form_species_start' / Int16ul,
|
'form_species_start' / Int16ul,
|
||||||
'form_sprite_start' / Int16ul,
|
'form_sprite_start' / Int16ul,
|
||||||
'form_count' / Int8ul,
|
'form_count' / Int8ul,
|
||||||
'color' / Int8ul,
|
'color' / VeekunEnum(Int8ul, COLORS),
|
||||||
'base_exp' / Int16ul,
|
'base_exp' / Int16ul,
|
||||||
'height' / Int16ul,
|
'height' / Int16ul,
|
||||||
'weight' / Int16ul,
|
'weight' / Int16ul,
|
||||||
'machines' / BitsSwapped(Bitwise(Array(14 * 8, Flag))),
|
'machines' / BitsSwapped(Bitwise(Array(16 * 8, Flag))),
|
||||||
Padding(2),
|
|
||||||
'tutors' / Int32ul,
|
'tutors' / Int32ul,
|
||||||
'mystery1' / Int16ul,
|
'mystery1' / Int16ul,
|
||||||
'mystery2' / Int16ul,
|
'mystery2' / Int16ul,
|
||||||
'bp_tutors1' / Int32ul, # unused in sumo
|
# TODO these are unused in sumo
|
||||||
'bp_tutors2' / Int32ul, # unused in sumo
|
'bp_tutors1' / Const(b'\x00\x00\x00\x00'),
|
||||||
'bp_tutors3' / Int32ul, # unused in sumo
|
'bp_tutors2' / Const(b'\x00\x00\x00\x00'),
|
||||||
'bp_tutors4' / Int32ul, # sumo: big numbers for pikachu, eevee, snorlax, mew, starter evos, couple others?? maybe special z-move item?
|
'bp_tutors3' / Const(b'\x00\x00\x00\x00'),
|
||||||
# TODO sumo is four bytes longer, not sure why, find out if those bytes are anything and a better way to express them
|
# FIXME this is bp_tutors4 in oras
|
||||||
GreedyRange(Const(b'\x00')),
|
'z_crystal' / Int16ul,
|
||||||
|
'z_base_move' / Int16ul,
|
||||||
|
# FIXME oras ends here
|
||||||
|
'z_move' / Int16ul,
|
||||||
|
# Not sure where this is used but it seems to be 1 for Alolan Pokémon only
|
||||||
|
# (but not their totem versions)
|
||||||
|
'is_alolan' / Int16ul,
|
||||||
)
|
)
|
||||||
|
|
||||||
pokemon_mega_evolutions_struct = Filter(this.number != 0, Range(
|
pokemon_mega_evolutions_struct = Filter(this.number != 0, Range(
|
||||||
|
@ -462,39 +568,36 @@ level_up_moves_struct = GreedyRange(
|
||||||
|
|
||||||
move_struct = Struct(
|
move_struct = Struct(
|
||||||
'type' / VeekunEnum(Int8ul, TYPES),
|
'type' / VeekunEnum(Int8ul, TYPES),
|
||||||
'category' / Int8ul,
|
'category' / VeekunEnum(Int8ul, MOVE_CATEGORIES),
|
||||||
'damage_class' / VeekunEnum(Int8ul, DAMAGE_CLASSES),
|
'damage_class' / VeekunEnum(Int8ul, DAMAGE_CLASSES),
|
||||||
'power' / Int8ul,
|
'power' / Int8ul,
|
||||||
'accuracy' / Int8ul,
|
'accuracy' / Int8ul,
|
||||||
'pp' / Int8ul,
|
'pp' / Int8ul,
|
||||||
'priority' / Int8sl,
|
'priority' / Int8sl,
|
||||||
'min_max_hits' / Int8ul,
|
'min_max_hits' / Int8ul,
|
||||||
'caused_effect' / Int16sl,
|
'ailment' / VeekunEnum(Int16sl, AILMENTS),
|
||||||
'effect_chance' / Int8ul,
|
'ailment_chance' / Int8ul,
|
||||||
'status' / Int8ul,
|
'status' / Int8ul,
|
||||||
'min_turns' / Int8ul,
|
'min_turns' / Int8ul,
|
||||||
'max_turns' / Int8ul,
|
'max_turns' / Int8ul,
|
||||||
'crit_rate' / Int8ul,
|
'crit_rate' / Int8ul,
|
||||||
'flinch_chance' / Int8ul,
|
'flinch_chance' / Int8ul,
|
||||||
'effect' / Int16ul,
|
'effect' / Int16ul,
|
||||||
'recoil' / Int8sl,
|
'drain' / Int8sl,
|
||||||
'healing' / Int8ul,
|
'healing' / Int8sl,
|
||||||
'range' / VeekunEnum(Int8ul, MOVE_RANGES),
|
'range' / VeekunEnum(Int8ul, MOVE_RANGES),
|
||||||
'stat_change' / Bitwise(Array(6, BitsInteger(4))),
|
'stat_change' / Array(3, Int8ul),
|
||||||
'stat_amount' / Bitwise(Array(6, BitsInteger(4))),
|
'stat_amount' / Array(3, Int8sl),
|
||||||
'stat_chance' / Bitwise(Array(6, BitsInteger(4))),
|
'stat_chance' / Array(3, Int8ul),
|
||||||
# FIXME sumo only; padding in oras i think
|
# FIXME sumo only; padding in oras i think
|
||||||
'z_move_id' / Int16ul, # ok
|
'z_move_id' / Int16ul,
|
||||||
'flags' / Int16ul,
|
'z_move_power' / Int8ul,
|
||||||
'padding2' / Int8ul, # ok
|
'z_move_effect' / Int8ul,
|
||||||
'extra' / Int8ul,
|
# FIXME this cuts off somewhere in ORAS, unsure where... but the flags are last, so, ??
|
||||||
# FIXME unsure whether this exists in ORAS; should use a length limiter in the parent
|
'mystery3' / Int8ul, # 0-4
|
||||||
'extra2' / Int8ul,
|
'mystery4' / Int8ul, # 0, 25, 50, or 100
|
||||||
'extra3' / Int8ul,
|
|
||||||
# a single flag, 1 = dance move
|
'flags' / FlagsEnum(Int32ul, **{v: 1 << (k - 1) for (k, v) in MOVE_FLAGS.items()}),
|
||||||
'extra4' / Int8ul,
|
|
||||||
# all zeroes
|
|
||||||
Padding(1, strict=True),
|
|
||||||
)
|
)
|
||||||
move_container_struct = FocusedSeq('records',
|
move_container_struct = FocusedSeq('records',
|
||||||
Const(b'WD'), # waza... descriptions?
|
Const(b'WD'), # waza... descriptions?
|
||||||
|
@ -885,7 +988,11 @@ ORAS_NORMAL_MOVE_TUTORS = (
|
||||||
# TODO ripe for being put in the pokedex codebase itself
|
# TODO ripe for being put in the pokedex codebase itself
|
||||||
def make_identifier(english_name):
|
def make_identifier(english_name):
|
||||||
# TODO do nidoran too
|
# TODO do nidoran too
|
||||||
return re.sub('[. ]+', '-', english_name.lower())
|
return re.sub(
|
||||||
|
'[^a-zA-Z0-9-]+',
|
||||||
|
'-',
|
||||||
|
english_name.lower().replace('’', ''),
|
||||||
|
)
|
||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def read_garc(path):
|
def read_garc(path):
|
||||||
|
@ -969,9 +1076,15 @@ def extract_data(root, out):
|
||||||
identifiers['item'] = list(map(make_identifier, texts['en']['item-names']))
|
identifiers['item'] = list(map(make_identifier, texts['en']['item-names']))
|
||||||
identifiers['ability'] = list(map(make_identifier, texts['en']['ability-names']))
|
identifiers['ability'] = list(map(make_identifier, texts['en']['ability-names']))
|
||||||
|
|
||||||
# De-duplicate some items with identical names
|
# De-duplicate some moves and items with identical names
|
||||||
# TODO eventually these should be a separate manual list that these scripts
|
# TODO eventually these should be a separate manual list that these scripts
|
||||||
# can update when necessary for new games
|
# can update when necessary for new games
|
||||||
|
# Generic Z-moves come in both physical and special, with the same names
|
||||||
|
for i in range(622, 658):
|
||||||
|
if i % 2 == 0:
|
||||||
|
identifiers['move'][i] += '--physical'
|
||||||
|
else:
|
||||||
|
identifiers['move'][i] += '--special'
|
||||||
# TODO or maybe we should name /both/ items in each pair... but for old
|
# TODO or maybe we should name /both/ items in each pair... but for old
|
||||||
# items that requires matching up with older versions in some sensible way,
|
# items that requires matching up with older versions in some sensible way,
|
||||||
# right? maybe?
|
# right? maybe?
|
||||||
|
@ -1470,6 +1583,9 @@ def extract_data(root, out):
|
||||||
# FIXME this skips over form names for non-concrete forms, ugh
|
# FIXME this skips over form names for non-concrete forms, ugh
|
||||||
pokémon.form_name = collect_text(texts, 'form-names', species_forms[base_species_id]['flavor_ids'][form_name_id])
|
pokémon.form_name = collect_text(texts, 'form-names', species_forms[base_species_id]['flavor_ids'][form_name_id])
|
||||||
|
|
||||||
|
# TODO stage? i'm iffy on that since it's a computed thing and what if
|
||||||
|
# it's incorrect? same problem as trusting the move meta stuff i
|
||||||
|
# suppose
|
||||||
pokémon.base_stats = {
|
pokémon.base_stats = {
|
||||||
'hp': record.stat_hp,
|
'hp': record.stat_hp,
|
||||||
'attack': record.stat_atk,
|
'attack': record.stat_atk,
|
||||||
|
@ -1491,7 +1607,6 @@ def extract_data(root, out):
|
||||||
else:
|
else:
|
||||||
pokémon.types = [record.type1, record.type2]
|
pokémon.types = [record.type1, record.type2]
|
||||||
pokémon.capture_rate = record.capture_rate
|
pokémon.capture_rate = record.capture_rate
|
||||||
# TODO stage?
|
|
||||||
# Held items are a bit goofy; if the same item is in all three slots, it always appears!
|
# Held items are a bit goofy; if the same item is in all three slots, it always appears!
|
||||||
pokémon.held_items = {}
|
pokémon.held_items = {}
|
||||||
if 0 != record.held_item1 == record.held_item2 == record.held_item3:
|
if 0 != record.held_item1 == record.held_item2 == record.held_item3:
|
||||||
|
@ -1520,9 +1635,8 @@ def extract_data(root, out):
|
||||||
for ability in (record.ability1, record.ability2, record.ability_hidden)
|
for ability in (record.ability1, record.ability2, record.ability_hidden)
|
||||||
]
|
]
|
||||||
# FIXME safari escape??
|
# FIXME safari escape??
|
||||||
# FIXME form stuff
|
|
||||||
# FIXME color
|
|
||||||
pokémon.base_experience = record.base_exp
|
pokémon.base_experience = record.base_exp
|
||||||
|
pokémon.color = record.color
|
||||||
# FIXME what units are these!
|
# FIXME what units are these!
|
||||||
pokémon.height = record.height
|
pokémon.height = record.height
|
||||||
pokémon.weight = record.weight
|
pokémon.weight = record.weight
|
||||||
|
@ -1532,13 +1646,12 @@ def extract_data(root, out):
|
||||||
|
|
||||||
# TODO transform to an OD somehow probably
|
# TODO transform to an OD somehow probably
|
||||||
pokemon_data.append(record)
|
pokemon_data.append(record)
|
||||||
print("{:4d} {:25s} {} {:5d} {:5d} {:20s} {:4d} {:4d} {:2d} | {} - {p.effort_padding:2d} - {p.effort:04x} {p.effort_hp:1d} {p.effort_attack:1d} {p.effort_defense:1d} {p.effort_speed:1d} {p.effort_special_attack:1d} {p.effort_special_defense:1d}".format(
|
print("{:4d} {:25s} {} {:5d} {:5d} {:4d} {:4d} {:2d} / {p.z_crystal:3d} {p.z_base_move:3d} {p.z_move:3d} | {:10s} - {p.effort_padding:2d} - {p.effort:04x} {p.effort_hp:1d} {p.effort_attack:1d} {p.effort_defense:1d} {p.effort_speed:1d} {p.effort_special_attack:1d} {p.effort_special_defense:1d}".format(
|
||||||
i,
|
i,
|
||||||
identifiers['pokémon'][i],
|
identifiers['pokémon'][i],
|
||||||
('0'*16 + bin(record.mystery1)[2:])[-16:],
|
('0'*16 + bin(record.mystery1)[2:])[-16:],
|
||||||
record.mystery2,
|
record.mystery2,
|
||||||
record.stage,
|
record.stage,
|
||||||
texts['en']['form-names'][i],
|
|
||||||
record.form_species_start,
|
record.form_species_start,
|
||||||
record.form_sprite_start,
|
record.form_sprite_start,
|
||||||
record.form_count,
|
record.form_count,
|
||||||
|
@ -1556,8 +1669,12 @@ def extract_data(root, out):
|
||||||
# TODO assert only one file wherever i do this
|
# TODO assert only one file wherever i do this
|
||||||
records = move_container_struct.parse_stream(garc[0][0])
|
records = move_container_struct.parse_stream(garc[0][0])
|
||||||
for i, record in enumerate(records):
|
for i, record in enumerate(records):
|
||||||
|
if i == 0:
|
||||||
|
# Skip the dummy zeroth move, which has no useful properties
|
||||||
|
continue
|
||||||
|
|
||||||
# TODO with the release of oras all moves have contest types and effects again! where are they??
|
# TODO with the release of oras all moves have contest types and effects again! where are they??
|
||||||
print(f"{i:3d} {texts['en']['move-names'][i]:30s} | {record.type:10s} {record.category:3d} / {record.priority:2d} {record.range:20s} {record.damage_class:12s} / {record.effect:3d} {record.caused_effect:3d} {record.effect_chance:3d} -- {record.min_max_hits:3d}, {record.status:3d} {record.min_turns:3d} {record.max_turns:3d} {record.crit_rate:3d} {record.flinch_chance:3d} {record.recoil:4d} {record.healing:3d} ~ {identifiers['move'][record.z_move_id]:30s} {record.flags:04x} {record.padding2:3d} {record.extra:3d} {record.extra2:08b} {record.extra2 >> 3:3d}+{record.extra2 & 7:<3d} {record.extra3:3d} {record.extra4:3d}")
|
print(f"{i:3d} {texts['en']['move-names'][i]:30s} | {record.type:10s} / {record.effect:3d} {record.ailment_chance:3d} -- {record.status:3d} ~ {record.z_move_id:3d} {record.z_move_power:3d} {record.z_move_effect:4d} ~ {record.mystery3:3d} {record.mystery4:3d} ~ {' '.join(k for (k, v) in record.flags.items() if v)} | {[x for x in zip(record.stat_change, record.stat_amount, record.stat_chance) if x[0]]}")
|
||||||
|
|
||||||
ident = identifiers['move'][i]
|
ident = identifiers['move'][i]
|
||||||
move = all_moves[ident] = schema.Move()
|
move = all_moves[ident] = schema.Move()
|
||||||
|
@ -1577,7 +1694,10 @@ def extract_data(root, out):
|
||||||
move.range = record.range
|
move.range = record.range
|
||||||
|
|
||||||
move.effect = record.effect
|
move.effect = record.effect
|
||||||
move.effect_chance = record.effect_chance
|
# NOTE that this is now a weird computed thing, which raises the
|
||||||
|
# question of exactly how much of the meta stuff is used by code vs
|
||||||
|
# how much isn't; are there decompiles of this?
|
||||||
|
move.effect_chance = record.ailment_chance or record.flinch_chance or record.stat_chance[0] or record.stat_chance[1] or record.stat_chance[2] or None
|
||||||
# FIXME need to identify whether THIS move is a z-move?
|
# FIXME need to identify whether THIS move is a z-move?
|
||||||
if record.z_move_id:
|
if record.z_move_id:
|
||||||
move.z_move = identifiers['move'][record.z_move_id]
|
move.z_move = identifiers['move'][record.z_move_id]
|
||||||
|
@ -1588,41 +1708,41 @@ def extract_data(root, out):
|
||||||
|
|
||||||
move.min_hits = record.min_max_hits & 0x0f
|
move.min_hits = record.min_max_hits & 0x0f
|
||||||
move.max_hits = record.min_max_hits >> 4
|
move.max_hits = record.min_max_hits >> 4
|
||||||
# -1: tri attack? telekinesis, smack down, thousand arrows
|
|
||||||
# 1: paralysis
|
|
||||||
# 2: sleep
|
|
||||||
# 3: frozen
|
|
||||||
# 4: burn
|
|
||||||
# 5: poison
|
|
||||||
# 6: confusion
|
|
||||||
# 7: infatuation
|
|
||||||
# 8: trapped? multi-turn move?
|
|
||||||
# 9: nightmare
|
|
||||||
# 12: tormented
|
|
||||||
# 13: disabled
|
|
||||||
# 14: drowsy (yawn)
|
|
||||||
# 15: heal blocked
|
|
||||||
# 17: foresight + odor sleuth + miracle eye (identified?)
|
|
||||||
# 18: seeded
|
|
||||||
# 19: embargoed
|
|
||||||
# 20: perish song
|
|
||||||
# 21: ingrain?
|
|
||||||
# 24: throat chop?? (silenced?)
|
|
||||||
move.category = record.category
|
move.category = record.category
|
||||||
move.ailment = record.caused_effect
|
move.ailment = record.ailment
|
||||||
|
move.ailment_chance = record.ailment_chance
|
||||||
# FIXME what is record.status???
|
# FIXME what is record.status???
|
||||||
# FIXME where is this
|
# FIXME this is nonsense, it should be per-stat?? also it's often
|
||||||
#ailment_chance = _Value(int)
|
# zero. also one of the stats is "all". this may take a little
|
||||||
# FIXME this is nonsense, it should be per-stat??
|
# caressing
|
||||||
#move.stat_chance = _Value(int)
|
#move.stat_chance = _Value(int)
|
||||||
move.min_turns = record.min_turns
|
move.min_turns = record.min_turns
|
||||||
move.max_turns = record.max_turns
|
move.max_turns = record.max_turns
|
||||||
# FIXME split drain out from healing
|
move.drain = record.drain
|
||||||
#drain = _Value(int)
|
|
||||||
move.healing = record.healing
|
move.healing = record.healing
|
||||||
move.crit_rate = record.crit_rate
|
move.crit_rate = record.crit_rate
|
||||||
move.flinch_chance = record.flinch_chance
|
move.flinch_chance = record.flinch_chance
|
||||||
|
|
||||||
|
move.flags = set(k for (k, v) in record.flags.items() if v)
|
||||||
|
|
||||||
|
print()
|
||||||
|
moves_by_status = defaultdict(list)
|
||||||
|
for i, record in enumerate(records):
|
||||||
|
if record.status:
|
||||||
|
moves_by_status[record.status].append(i)
|
||||||
|
for status in sorted(moves_by_status):
|
||||||
|
print(f"moves with status == {status}:")
|
||||||
|
print(*(identifiers['move'][i] for i in moves_by_status[status]))
|
||||||
|
|
||||||
|
print()
|
||||||
|
moves_by_mystery4 = defaultdict(list)
|
||||||
|
for i, record in enumerate(records):
|
||||||
|
if record.mystery4:
|
||||||
|
moves_by_mystery4[record.mystery4].append(i)
|
||||||
|
for mystery4 in sorted(moves_by_mystery4):
|
||||||
|
print(f"moves with mystery4 == {mystery4}:")
|
||||||
|
print(*(identifiers['move'][i] for i in moves_by_mystery4[mystery4]))
|
||||||
|
|
||||||
with (out / 'moves.yaml').open('w') as f:
|
with (out / 'moves.yaml').open('w') as f:
|
||||||
f.write(Camel([schema.POKEDEX_TYPES]).dump(all_moves))
|
f.write(Camel([schema.POKEDEX_TYPES]).dump(all_moves))
|
||||||
|
|
||||||
|
|
|
@ -270,20 +270,27 @@ class Move(VersionedLocus):
|
||||||
|
|
||||||
# FIXME this should be an enum really too
|
# FIXME this should be an enum really too
|
||||||
effect = _Value(MoveEffect)
|
effect = _Value(MoveEffect)
|
||||||
|
# FIXME this is a bogus derived value now
|
||||||
effect_chance = _Value(int)
|
effect_chance = _Value(int)
|
||||||
|
|
||||||
# NOTE: In the old schema, this stuff is in a separate table, since it's
|
# NOTE: In the old schema, this stuff is in a separate table, since it's
|
||||||
# not quite 100% reliable; in particular the lack of a value doesn't mean
|
# not quite 100% reliable; in particular the lack of a value doesn't mean
|
||||||
# that the effect cannot happen via code. Also, consider Tri Attack, whose
|
# that the effect cannot happen via code. Also, consider Tri Attack, whose
|
||||||
# inflicted ailments aren't listed here at all. :(
|
# inflicted ailments aren't listed here at all. :( Not sure what we
|
||||||
# TODO i wonder if these should be left out of the yaml if blank
|
# should do with it, since it's interesting for nerds but confusing for
|
||||||
max_hits = _Value(int)
|
# everyone else.
|
||||||
|
# FIXME this should probably be, like, _Set(MoveFlag)
|
||||||
|
# FIXME also it doesn't dump using ? syntax like the yaml registry says
|
||||||
|
flags = _Value(set)
|
||||||
# FIXME these should be enums
|
# FIXME these should be enums
|
||||||
category = _Value(int)
|
category = _Value(int)
|
||||||
ailment = _Value(int)
|
ailment = _Value(int)
|
||||||
|
# FIXME this is bogus, it's per stat change
|
||||||
|
# FIXME also, include stat changes?
|
||||||
|
#stat_chance = _Value(int)
|
||||||
|
# TODO i wonder if all these should be left out of the yaml if blank
|
||||||
min_hits = _Value(int)
|
min_hits = _Value(int)
|
||||||
stat_chance = _Value(int)
|
max_hits = _Value(int)
|
||||||
min_turns = _Value(int)
|
min_turns = _Value(int)
|
||||||
max_turns = _Value(int)
|
max_turns = _Value(int)
|
||||||
drain = _Value(int)
|
drain = _Value(int)
|
||||||
|
|
Loading…
Reference in a new issue