Dump most of the interesting bits about moves

This commit is contained in:
Eevee (Lexy Munroe) 2017-06-25 12:40:52 -07:00
parent 215366968b
commit 3d296ff7b4
2 changed files with 160 additions and 57 deletions

View file

@ -70,6 +70,30 @@ TYPES = {
17: 't.fairy', 17: 't.fairy',
} }
DAMAGE_CLASSES = {
0: 'dc.status',
1: 'dc.physical',
2: 'dc.special',
}
MOVE_RANGES = {
13: 'mr.specific-move',
3: 'mr.selected-pokemon-me-first',
2: 'mr.ally',
6: 'mr.users-field',
1: 'mr.user-or-ally',
11: 'mr.opponents-field',
7: 'mr.user',
9: 'mr.random-opponent',
4: 'mr.all-other-pokemon',
0: 'mr.selected-pokemon',
5: 'mr.all-opponents',
10: 'mr.entire-field',
12: 'mr.user-and-allies',
8: 'mr.all-pokemon',
}
# ja-Hrkt: hiragana/katakana # ja-Hrkt: hiragana/katakana
# zh-Hans: simplified # zh-Hans: simplified
# zh-Hant: traditional # zh-Hant: traditional
@ -319,6 +343,9 @@ FORM_NAMES = {
} }
def VeekunEnum(subcon, enumdict):
return Enum(subcon, **{v: k for (k, v) in enumdict.items()})
pokemon_struct = Struct( pokemon_struct = Struct(
'stat_hp' / Int8ul, 'stat_hp' / Int8ul,
'stat_atk' / Int8ul, 'stat_atk' / Int8ul,
@ -337,7 +364,7 @@ pokemon_struct = Struct(
'gender_rate' / Int8ul, 'gender_rate' / Int8ul,
'steps_to_hatch' / Int8ul, 'steps_to_hatch' / Int8ul,
'base_happiness' / Int8ul, 'base_happiness' / Int8ul,
'growth_rate' / Enum(Int8ul, **{v: k for (k, v) in GROWTH_RATES.items()}), 'growth_rate' / VeekunEnum(Int8ul, GROWTH_RATES),
'egg_group1' / Int8ul, 'egg_group1' / Int8ul,
'egg_group2' / Int8ul, 'egg_group2' / Int8ul,
'ability1' / Int8ul, 'ability1' / Int8ul,
@ -402,9 +429,9 @@ level_up_moves_struct = GreedyRange(
) )
move_struct = Struct( move_struct = Struct(
'type' / Enum(Int8ul, **{v:k for (k, v) in TYPES.items()}), 'type' / VeekunEnum(Int8ul, TYPES),
'category' / Int8ul, 'category' / Int8ul,
'damage_class' / Int8ul, 'damage_class' / VeekunEnum(Int8ul, DAMAGE_CLASSES),
'power' / Int8ul, 'power' / Int8ul,
'accuracy' / Int8ul, 'accuracy' / Int8ul,
'pp' / Int8ul, 'pp' / Int8ul,
@ -420,17 +447,22 @@ move_struct = Struct(
'effect' / Int16ul, 'effect' / Int16ul,
'recoil' / Int8sl, 'recoil' / Int8sl,
'healing' / Int8ul, 'healing' / Int8ul,
'range' / Int8ul, # ok 'range' / VeekunEnum(Int8ul, MOVE_RANGES),
'stat_change' / Bitwise(Array(6, BitsInteger(4))), 'stat_change' / Bitwise(Array(6, BitsInteger(4))),
'stat_amount' / Bitwise(Array(6, BitsInteger(4))), 'stat_amount' / Bitwise(Array(6, BitsInteger(4))),
'stat_chance' / Bitwise(Array(6, BitsInteger(4))), 'stat_chance' / Bitwise(Array(6, BitsInteger(4))),
'padding0' / Int8ul, # ok # FIXME sumo only; padding in oras i think
'padding1' / Int8ul, # ok 'z_move_id' / Int16ul, # ok
'flags' / Int16ul, 'flags' / Int16ul,
'padding2' / Int8ul, # ok 'padding2' / Int8ul, # ok
'extra' / Int8ul, 'extra' / Int8ul,
# FIXME unsure whether this exists in ORAS; should use a length limiter in the parent # FIXME unsure whether this exists in ORAS; should use a length limiter in the parent
'extra2' / Int32ul, 'extra2' / Int8ul,
'extra3' / Int8ul,
# a single flag, 1 = dance move
'extra4' / Int8ul,
# all zeroes
Padding(1),
) )
move_container_struct = FocusedSeq('records', move_container_struct = FocusedSeq('records',
Const(b'WD'), # waza... descriptions? Const(b'WD'), # waza... descriptions?
@ -1469,23 +1501,84 @@ def extract_data(root, out):
# ------------------------------------------------------------------------- # -------------------------------------------------------------------------
# Move stats # Move stats
all_moves = OrderedDict()
#with read_garc(root / 'rom/a/1/8/9') as garc: # ORAS #with read_garc(root / 'rom/a/1/8/9') as garc: # ORAS
with read_garc(root / 'rom/a/0/1/1') as garc: # SUMO with read_garc(root / 'rom/a/0/1/1') as garc: # SUMO
# Only one subfile # Only one subfile
# TODO assert this wherever i do it # TODO assert only one file wherever i do this
data = garc[0][0].read() records = move_container_struct.parse_stream(garc[0][0])
print(Struct('magic' / Bytes(2), 'count' / Int16ul, 'pointers' / Array(16, Int32ul)).parse(data))
print(move_struct.sizeof())
records = move_container_struct.parse(data)
for i, record in enumerate(records): for i, record in enumerate(records):
#print(texts['en']['move-names'][i])
#print(record)
# 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("{:3d} {:30s} | {m.type:10s} {m.category:3d} / {m.power:3d} {m.pp:2d} {m.accuracy:3d} / {m.priority:2d} {m.range:2d} {m.damage_class:1d} / {m.effect:3d} {m.caused_effect:3d} {m.effect_chance:3d} -- {m.status:3d} {m.min_turns:3d} {m.max_turns:3d} {m.crit_rate:3d} {m.flinch_chance:3d} {m.recoil:4d} {m.healing:3d} / {m.stat_change!r} {m.stat_amount!r} {m.stat_chance!r} ~ {m.padding0:3d} {m.padding1:3d} {m.flags:04x} {m.padding2:3d} {m.extra:3d} {m.extra2:10d}".format( 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}")
i,
texts['en']['move-names'][i], ident = identifiers['move'][i]
m=record, move = all_moves[ident] = schema.Move()
)) move.game_index = i
move.name = collect_text(texts, 'move-names', i)
move.type = record.type
# TODO does this need munging somehow?
move.power = record.power
move.pp = record.pp
# TODO does this need munging somehow?
move.accuracy = record.accuracy
move.priority = record.priority
move.damage_class = record.damage_class
move.range = record.range
move.effect = record.effect
move.effect_chance = record.effect_chance
# FIXME need to identify whether THIS move is a z-move?
if record.z_move_id:
move.z_move = identifiers['move'][record.z_move_id]
else:
# TODO what does it mean if the z-move is missing?? (how do z
# moves work for status moves anyway?)
pass
move.min_hits = record.min_max_hits & 0x0f
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.ailment = record.caused_effect
# FIXME what is record.status???
# FIXME where is this
#ailment_chance = _Value(int)
# FIXME this is nonsense, it should be per-stat??
#move.stat_chance = _Value(int)
move.min_turns = record.min_turns
move.max_turns = record.max_turns
# FIXME split drain out from healing
#drain = _Value(int)
move.healing = record.healing
move.crit_rate = record.crit_rate
move.flinch_chance = record.flinch_chance
with (out / 'moves.yaml').open('w') as f:
f.write(Camel([schema.POKEDEX_TYPES]).dump(all_moves))
return
# Egg moves # Egg moves
with read_garc(root / 'rom/a/0/1/2') as garc: # SUMO with read_garc(root / 'rom/a/0/1/2') as garc: # SUMO
@ -1742,7 +1835,6 @@ def extract_data(root, out):
machineset.append(moveident) machineset.append(moveident)
with (out / 'pokemon.yaml').open('w') as f: with (out / 'pokemon.yaml').open('w') as f:
#dump_to_yaml(all_pokémon, f)
f.write(Camel([schema.POKEDEX_TYPES]).dump(all_pokémon)) f.write(Camel([schema.POKEDEX_TYPES]).dump(all_pokémon))

View file

@ -249,13 +249,45 @@ Pokemon = Pokémon
MoveEffect = _ForwardDeclaration() MoveEffect = _ForwardDeclaration()
class Move(VersionedLocus): class Move(VersionedLocus):
game_index = _Value(int)
name = _Localized(str) name = _Localized(str)
type = _Value(Type) type = _Value(Type)
power = _Value(int) power = _Value(int)
pp = _Value(int) pp = _Value(int)
accuracy = _Value(int) accuracy = _Value(int)
priority = _Value(int)
# FIXME should be enums
damage_class = _Value(str)
range = _Value(str)
# FIXME oh goodness this is a self-referential one
z_move = _Value(str)
# FIXME this should be an enum really too
effect = _Value(MoveEffect) effect = _Value(MoveEffect)
effect_chance = _Value(int)
# 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
# that the effect cannot happen via code. Also, consider Tri Attack, whose
# inflicted ailments aren't listed here at all. :(
# TODO i wonder if these should be left out of the yaml if blank
max_hits = _Value(int)
# FIXME these should be enums
category = _Value(int)
ailment = _Value(int)
min_hits = _Value(int)
stat_chance = _Value(int)
min_turns = _Value(int)
max_turns = _Value(int)
drain = _Value(int)
healing = _Value(int)
crit_rate = _Value(int)
ailment_chance = _Value(int)
flinch_chance = _Value(int)
@ -342,9 +374,8 @@ def _dump_locus(locus):
return data return data
@POKEDEX_TYPES.loader('pokemon', version=None) def _make_locus_loader(cls):
def _load_locus(data, version): def load_locus(data, version):
cls = Pokémon
# TODO wrap with a writer thing? # TODO wrap with a writer thing?
obj = cls() obj = cls()
for key, value in data.items(): for key, value in data.items():
@ -353,38 +384,18 @@ def _load_locus(data, version):
setattr(obj, key, value) setattr(obj, key, value)
return obj return obj
return load_locus
POKEDEX_TYPES.loader('pokemon', version=None)(_make_locus_loader(Pokémon))
POKEDEX_TYPES.dumper(Move, 'move', version=None, inherit=True)(_dump_locus)
POKEDEX_TYPES.loader('move', version=None)(_make_locus_loader(Move))
POKEDEX_TYPES.dumper(Ability, 'ability', version=None, inherit=True)(_dump_locus) POKEDEX_TYPES.dumper(Ability, 'ability', version=None, inherit=True)(_dump_locus)
POKEDEX_TYPES.loader('ability', version=None)(_make_locus_loader(Ability))
@POKEDEX_TYPES.loader('ability', version=None)
def _load_locus(data, version):
cls = Ability
# TODO wrap with a writer thing?
obj = cls()
for key, value in data.items():
key = key.replace('-', '_')
assert hasattr(cls, key)
setattr(obj, key, value)
return obj
POKEDEX_TYPES.dumper(Item, 'item', version=None, inherit=True)(_dump_locus) POKEDEX_TYPES.dumper(Item, 'item', version=None, inherit=True)(_dump_locus)
POKEDEX_TYPES.loader('item', version=None)(_make_locus_loader(Item))
@POKEDEX_TYPES.loader('item', version=None)
def _load_locus(data, version):
cls = Item
# TODO wrap with a writer thing?
obj = cls()
for key, value in data.items():
key = key.replace('-', '_')
assert hasattr(cls, key)
setattr(obj, key, value)
return obj
def load_repository(): def load_repository():