Use helper function for saving

This commit is contained in:
Petr Viktorin 2012-10-14 01:00:56 +02:00
parent 14ea7a0adf
commit a2a63938a6
2 changed files with 83 additions and 99 deletions

View file

@ -12,6 +12,7 @@ import struct
import base64 import base64
import datetime import datetime
import contextlib import contextlib
from operator import attrgetter
import sqlalchemy.orm.exc import sqlalchemy.orm.exc
@ -219,19 +220,48 @@ class SaveFilePokemon(object):
""" """
st = self.structure st = self.structure
def save_trash(result, name, string): NO_VALUE = object()
def save(target_dict, key, value=NO_VALUE, transform=None,
condition=lambda x: x):
"""Set a dict key to a value, if a condition is true
If value is not given, it is looked up on self.
The value can be transformed by a function before setting.
"""
if value is NO_VALUE:
attrname = key.replace(' ', '_')
value = getattr(self, attrname)
if condition(value):
if transform:
value = transform(value)
target_dict[key] = value
def save_string(target_dict, string_key, trash_key, string):
"""Save a string, including trash bytes"""
target_dict[string_key] = unicode(string)
trash = getattr(string, 'original', None) trash = getattr(string, 'original', None)
if trash: if trash:
expected = (string + u'\uffff').encode('utf-16LE') expected = (string + u'\uffff').encode('utf-16LE')
if trash.rstrip('\0') != expected: if trash.rstrip('\0') != expected:
result[name] = base64.b64encode(trash) target_dict[trash_key] = base64.b64encode(trash)
def save_object(target_dict, key, value=NO_VALUE, **extra):
"""Objects are represented as dicts with "name" and a bunch of IDs
The name is for humans. The ID is the number from the struct.
"""
save(target_dict, key, value=value, transform=lambda value:
dict(name=value.name, **extra))
result = dict( result = dict(
species=dict(id=self.species.id, name=self.species.name), species=dict(id=self.species.id, name=self.species.name),
) )
ability = self.ability if self.form != self.species.default_form:
if ability: result['form'] = dict(id=st.form_id, name=self.form.form_name)
result['ability'] = dict(id=st.ability_id, name=ability.name)
save_object(result, 'ability', id=st.ability_id)
save_object(result, 'held item', id=st.held_item_id)
save_object(result, 'pokeball', id=st.dppt_pokeball or st.hgss_pokeball)
trainer = dict( trainer = dict(
id=self.original_trainer_id, id=self.original_trainer_id,
@ -239,86 +269,52 @@ class SaveFilePokemon(object):
name=unicode(self.original_trainer_name), name=unicode(self.original_trainer_name),
gender=self.original_trainer_gender gender=self.original_trainer_gender
) )
save_trash(trainer, 'name trash', self.original_trainer_name) save_string(trainer, 'name', 'name trash', self.original_trainer_name)
if (trainer['id'] or trainer['secret'] or if (trainer['id'] or trainer['secret'] or
trainer['name'].strip('\0') or trainer['gender'] != 'male'): trainer['name'].strip('\0') or trainer['gender'] != 'male'):
result['oiginal trainer'] = trainer result['oiginal trainer'] = trainer
if self.form != self.species.default_form: save(result, 'exp')
result['form'] = dict(id=st.form_id, name=self.form.form_name) save(result, 'happiness')
if self.held_item: save(result, 'markings', transform=sorted)
result['held item'] = dict(id=st.held_item_id, name=self.held_item.name) save(result, 'original country')
if self.exp: save(result, 'original version')
result['exp'] = self.exp save(result, 'encounter type', condition=lambda et:
if self.happiness: (et and et != 'special'))
result['happiness'] = self.happiness save_string(result, 'nickname', 'nickname trash', self.nickname)
if self.markings: save(result, 'egg received', self.date_egg_received,
result['markings'] = sorted(self.markings) transform=lambda x: x.isoformat())
if self.original_country and self.original_country != '_unset': save(result, 'date met',
result['original country'] = self.original_country transform=lambda x: x.isoformat())
if self.original_version and self.original_version != '_unset': save(result, 'pokerus data', self.pokerus)
result['original version'] = self.original_version save(result, 'met at level')
if self.encounter_type and self.encounter_type != 'special': save(result, 'nicknamed', self.is_nicknamed)
result['encounter type'] = self.encounter_type save(result, 'is egg')
if self.nickname: save(result, 'fateful encounter')
result['nickname'] = unicode(self.nickname) save(result, 'personality')
save_trash(result, 'nickname trash', self.nickname) save(result, 'gender', condition=lambda g: g != 'genderless')
if self.egg_location: save(result, 'has hidden ability', self.hidden_ability)
result['egg location'] = dict( save(result, 'ribbons',
id=st.pt_egg_location_id or st.dp_egg_location_id, sorted(r.replace('_', ' ') for r in self.ribbons))
name=self.egg_location.name)
elif st.pt_egg_location_id or st.dp_egg_location_id:
result['egg location'] = dict(
id=st.pt_egg_location_id or st.dp_egg_location_id)
if st.dp_egg_location_id:
result['egg location slot'] = 'dp'
if self.met_location:
result['met location'] = dict(
id=st.pt_met_location_id or st.dp_met_location_id,
name=self.met_location.name)
elif st.pt_met_location_id or st.dp_met_location_id:
result['egg location'] = dict(
id=st.pt_met_location_id or st.dp_met_location_id)
if st.dp_met_location_id:
result['met location slot'] = 'dp'
if self.date_egg_received:
result['egg received'] = self.date_egg_received.isoformat()
if self.date_met:
result['date met'] = self.date_met.isoformat()
if self.pokerus:
result['pokerus data'] = self.pokerus
if self.pokeball:
result['pokeball'] = dict(
id=st.dppt_pokeball or st.hgss_pokeball,
name=self.pokeball.name)
if self.met_at_level:
result['met at level'] = self.met_at_level
if self.is_nicknamed: for loc_type in 'egg', 'met':
result['nicknamed'] = True loc_dict = dict()
if self.is_egg: save(loc_dict, 'id_pt', st['pt_{0}_location_id'.format(loc_type)])
result['is egg'] = True save(loc_dict, 'id_dp', st['dp_{0}_location_id'.format(loc_type)])
if self.fateful_encounter: save(loc_dict, 'name',
result['fateful encounter'] = True getattr(self, '{0}_location'.format(loc_type)),
if self.personality: transform=attrgetter('name'))
result['personality'] = self.personality save(result, '{0} location'.format(loc_type), loc_dict)
if self.gender != 'genderless':
result['gender'] = self.gender
if st.hidden_ability:
result['has hidden ability'] = st.hidden_ability
moves = result['moves'] = [] moves = result['moves'] = []
for i, move_object in enumerate(self.moves, 1): for i, move_object in enumerate(self.moves, 1):
move = {} move = {}
if move_object: save(move, 'id', move_object, transform=attrgetter('id'))
move['id'] = move_object.id save(move, 'name', move_object, transform=attrgetter('name'))
move['name'] = move_object.name save(move, 'pp ups', st['move%s_pp_ups' % i])
move['pp'] = st['move%s_pp' % i] pp = st['move%s_pp' % i]
pp_up = st['move%s_pp_ups' % i] if move or pp:
if pp_up: move['pp'] = pp
move['pp ups'] = pp_up
if move:
moves.append(move) moves.append(move)
effort = {} effort = {}
@ -332,16 +328,10 @@ class SaveFilePokemon(object):
effort[dct_stat_identifier] = st['effort_' + st_stat_identifier] effort[dct_stat_identifier] = st['effort_' + st_stat_identifier]
for contest_stat in 'cool', 'beauty', 'cute', 'smart', 'tough', 'sheen': for contest_stat in 'cool', 'beauty', 'cute', 'smart', 'tough', 'sheen':
contest_stats[contest_stat] = st['contest_' + contest_stat] contest_stats[contest_stat] = st['contest_' + contest_stat]
if any(effort.values()): save(result, 'effort', effort, condition=any)
result['effort'] = effort save(result, 'genes', genes, condition=any)
if any(genes.values()): save(result, 'contest stats', contest_stats, condition=any)
result['genes'] = genes
if any(contest_stats.values()):
result['contest stats'] = contest_stats
ribbons = sorted(r.replace('_', ' ') for r in self.ribbons)
if ribbons:
result['ribbons'] = ribbons
return result return result
def update(self, dct, **kwargs): def update(self, dct, **kwargs):
@ -434,18 +424,14 @@ class SaveFilePokemon(object):
is_nicknamed='nicknamed', is_nicknamed='nicknamed',
) )
for loc_type in 'egg', 'met': for loc_type in 'egg', 'met':
key = '{0} location'.format(loc_type) loc_dict = dct.get('{0} location'.format(loc_type))
if key in dct: if loc_dict:
dp_attr = 'dp_{0}_location_id'.format(loc_type) dp_attr = 'dp_{0}_location_id'.format(loc_type)
pt_attr = 'pt_{0}_location_id'.format(loc_type) pt_attr = 'pt_{0}_location_id'.format(loc_type)
if dct.get('{0} location slot'.format(loc_type)) == 'dp': if 'id_dp' in loc_dict:
attr = dp_attr st[dp_attr] = loc_dict['id_dp']
other_attr = pt_attr if 'id_pt' in loc_dict:
else: st[pt_attr] = loc_dict['id_pt']
attr = pt_attr
other_attr = dp_attr
st[attr] = dct[key]['id']
st[other_attr] = 0
delattr(self, '{0}_location'.format(loc_type)) delattr(self, '{0}_location'.format(loc_type))
if 'date met' in dct: if 'date met' in dct:
self.date_met = datetime.datetime.strptime( self.date_met = datetime.datetime.strptime(
@ -798,7 +784,6 @@ class SaveFilePokemon(object):
for ribbonset_name in ( for ribbonset_name in (
'sinnoh_ribbons', 'hoenn_ribbons', 'sinnoh_contest_ribbons'): 'sinnoh_ribbons', 'hoenn_ribbons', 'sinnoh_contest_ribbons'):
ribbonset = self.structure[ribbonset_name] ribbonset = self.structure[ribbonset_name]
print ribbonset
for ribbon_name in ribbonset: for ribbon_name in ribbonset:
ribbonset[ribbon_name] = (ribbon_name in ribbons) ribbonset[ribbon_name] = (ribbon_name in ribbons)
ribbons.discard(ribbon_name) ribbons.discard(ribbon_name)
@ -948,7 +933,8 @@ class SaveFilePokemonGen5(SaveFilePokemon):
if 'nature' in dct: if 'nature' in dct:
self.structure.nature_id = dct['nature']['id'] self.structure.nature_id = dct['nature']['id']
if 'has hidden ability' not in dct: if 'has hidden ability' not in dct:
self.hidden_ability = (self.pokemon.dream_ability == self.ability) self.hidden_ability = (self.ability == self.pokemon.dream_ability
and self.ability not in self.pokemon.abilities)
@cached_property @cached_property
def nature(self): def nature(self):

View file

@ -721,7 +721,6 @@ def make_pokemon_struct(generation):
Flag('circle'), Flag('circle'),
), ),
LeakyEnum(ULInt8('original_country'), LeakyEnum(ULInt8('original_country'),
_unset = 0,
jp=1, jp=1,
us=2, us=2,
fr=3, fr=3,
@ -855,7 +854,6 @@ def make_pokemon_struct(generation):
PokemonStringAdapter(String('nickname', 22), 22), PokemonStringAdapter(String('nickname', 22), 22),
Padding(1), Padding(1),
LeakyEnum(ULInt8('original_version'), LeakyEnum(ULInt8('original_version'),
_unset = 0,
sapphire = 1, sapphire = 1,
ruby = 2, ruby = 2,
emerald = 3, emerald = 3,