Normal Castform icon.
[zzz-pokedex.git] / pokedex / struct / _pokemon_struct.py
1 # encoding: utf8
2 u"""Defines a construct `pokemon_struct`, containing the structure of a single
3 Pokémon saved within a game -- often seen as a .pkm file. This is the same
4 format sent back and forth over the GTS.
5 """
6
7 import datetime
8
9 from construct import *
10
11 # TODO:
12 # - strings should be validated, going both in and out
13 # - strings need to pad themselves when being re-encoded
14 # - strings sometimes need specific padding christ
15 # - date_met is not optional
16 # - some way to be more lenient with junk data, or at least
17 # - higher-level validation; see XXXes below
18 # - personality indirectly influences IVs due to PRNG use
19
20 # The entire gen 4 character table:
21 character_table = {
22 0x0002: u'ぁ',
23 0x0003: u'あ',
24 0x0004: u'ぃ',
25 0x0005: u'い',
26 0x0006: u'ぅ',
27 0x0007: u'う',
28 0x0008: u'ぇ',
29 0x0009: u'え',
30 0x000a: u'ぉ',
31 0x000b: u'お',
32 0x000c: u'か',
33 0x000d: u'が',
34 0x000e: u'き',
35 0x000f: u'ぎ',
36 0x0010: u'く',
37 0x0011: u'ぐ',
38 0x0012: u'け',
39 0x0013: u'げ',
40 0x0014: u'こ',
41 0x0015: u'ご',
42 0x0016: u'さ',
43 0x0017: u'ざ',
44 0x0018: u'し',
45 0x0019: u'じ',
46 0x001a: u'す',
47 0x001b: u'ず',
48 0x001c: u'せ',
49 0x001d: u'ぜ',
50 0x001e: u'そ',
51 0x001f: u'ぞ',
52 0x0020: u'た',
53 0x0021: u'だ',
54 0x0022: u'ち',
55 0x0023: u'ぢ',
56 0x0024: u'っ',
57 0x0025: u'つ',
58 0x0026: u'づ',
59 0x0027: u'て',
60 0x0028: u'で',
61 0x0029: u'と',
62 0x002a: u'ど',
63 0x002b: u'な',
64 0x002c: u'に',
65 0x002d: u'ぬ',
66 0x002e: u'ね',
67 0x002f: u'の',
68 0x0030: u'は',
69 0x0031: u'ば',
70 0x0032: u'ぱ',
71 0x0033: u'ひ',
72 0x0034: u'び',
73 0x0035: u'ぴ',
74 0x0036: u'ふ',
75 0x0037: u'ぶ',
76 0x0038: u'ぷ',
77 0x0039: u'へ',
78 0x003a: u'べ',
79 0x003b: u'ぺ',
80 0x003c: u'ほ',
81 0x003d: u'ぼ',
82 0x003e: u'ぽ',
83 0x003f: u'ま',
84 0x0040: u'み',
85 0x0041: u'む',
86 0x0042: u'め',
87 0x0043: u'も',
88 0x0044: u'ゃ',
89 0x0045: u'や',
90 0x0046: u'ゅ',
91 0x0047: u'ゆ',
92 0x0048: u'ょ',
93 0x0049: u'よ',
94 0x004a: u'ら',
95 0x004b: u'り',
96 0x004c: u'る',
97 0x004d: u'れ',
98 0x004e: u'ろ',
99 0x004f: u'わ',
100 0x0050: u'を',
101 0x0051: u'ん',
102 0x0052: u'ァ',
103 0x0053: u'ア',
104 0x0054: u'ィ',
105 0x0055: u'イ',
106 0x0056: u'ゥ',
107 0x0057: u'ウ',
108 0x0058: u'ェ',
109 0x0059: u'エ',
110 0x005a: u'ォ',
111 0x005b: u'オ',
112 0x005c: u'カ',
113 0x005d: u'ガ',
114 0x005e: u'キ',
115 0x005f: u'ギ',
116 0x0060: u'ク',
117 0x0061: u'グ',
118 0x0062: u'ケ',
119 0x0063: u'ゲ',
120 0x0064: u'コ',
121 0x0065: u'ゴ',
122 0x0066: u'サ',
123 0x0067: u'ザ',
124 0x0068: u'シ',
125 0x0069: u'ジ',
126 0x006a: u'ス',
127 0x006b: u'ズ',
128 0x006c: u'セ',
129 0x006d: u'ゼ',
130 0x006e: u'ソ',
131 0x006f: u'ゾ',
132 0x0070: u'タ',
133 0x0071: u'ダ',
134 0x0072: u'チ',
135 0x0073: u'ヂ',
136 0x0074: u'ッ',
137 0x0075: u'ツ',
138 0x0076: u'ヅ',
139 0x0077: u'テ',
140 0x0078: u'デ',
141 0x0079: u'ト',
142 0x007a: u'ド',
143 0x007b: u'ナ',
144 0x007c: u'ニ',
145 0x007d: u'ヌ',
146 0x007e: u'ネ',
147 0x007f: u'ノ',
148 0x0080: u'ハ',
149 0x0081: u'バ',
150 0x0082: u'パ',
151 0x0083: u'ヒ',
152 0x0084: u'ビ',
153 0x0085: u'ピ',
154 0x0086: u'フ',
155 0x0087: u'ブ',
156 0x0088: u'プ',
157 0x0089: u'ヘ',
158 0x008a: u'ベ',
159 0x008b: u'ペ',
160 0x008c: u'ホ',
161 0x008d: u'ボ',
162 0x008e: u'ポ',
163 0x008f: u'マ',
164 0x0090: u'ミ',
165 0x0091: u'ム',
166 0x0092: u'メ',
167 0x0093: u'モ',
168 0x0094: u'ャ',
169 0x0095: u'ヤ',
170 0x0096: u'ュ',
171 0x0097: u'ユ',
172 0x0098: u'ョ',
173 0x0099: u'ヨ',
174 0x009a: u'ラ',
175 0x009b: u'リ',
176 0x009c: u'ル',
177 0x009d: u'レ',
178 0x009e: u'ロ',
179 0x009f: u'ワ',
180 0x00a0: u'ヲ',
181 0x00a1: u'ン',
182 0x00a2: u'0',
183 0x00a3: u'1',
184 0x00a4: u'2',
185 0x00a5: u'3',
186 0x00a6: u'4',
187 0x00a7: u'5',
188 0x00a8: u'6',
189 0x00a9: u'7',
190 0x00aa: u'8',
191 0x00ab: u'9',
192 0x00ac: u'A',
193 0x00ad: u'B',
194 0x00ae: u'C',
195 0x00af: u'D',
196 0x00b0: u'E',
197 0x00b1: u'F',
198 0x00b2: u'G',
199 0x00b3: u'H',
200 0x00b4: u'I',
201 0x00b5: u'J',
202 0x00b6: u'K',
203 0x00b7: u'L',
204 0x00b8: u'M',
205 0x00b9: u'N',
206 0x00ba: u'O',
207 0x00bb: u'P',
208 0x00bc: u'Q',
209 0x00bd: u'R',
210 0x00be: u'S',
211 0x00bf: u'T',
212 0x00c0: u'U',
213 0x00c1: u'V',
214 0x00c2: u'W',
215 0x00c3: u'X',
216 0x00c4: u'Y',
217 0x00c5: u'Z',
218 0x00c6: u'a',
219 0x00c7: u'b',
220 0x00c8: u'c',
221 0x00c9: u'd',
222 0x00ca: u'e',
223 0x00cb: u'f',
224 0x00cc: u'g',
225 0x00cd: u'h',
226 0x00ce: u'i',
227 0x00cf: u'j',
228 0x00d0: u'k',
229 0x00d1: u'l',
230 0x00d2: u'm',
231 0x00d3: u'n',
232 0x00d4: u'o',
233 0x00d5: u'p',
234 0x00d6: u'q',
235 0x00d7: u'r',
236 0x00d8: u's',
237 0x00d9: u't',
238 0x00da: u'u',
239 0x00db: u'v',
240 0x00dc: u'w',
241 0x00dd: u'x',
242 0x00de: u'y',
243 0x00df: u'z',
244 0x00e0: u'à',
245 0x00e1: u'!',
246 0x00e2: u'?',
247 0x00e3: u'、',
248 0x00e4: u'。',
249 0x00e5: u'…',
250 0x00e6: u'・',
251 0x00e7: u'/',
252 0x00e8: u'「',
253 0x00e9: u'」',
254 0x00ea: u'『',
255 0x00eb: u'』',
256 0x00ec: u'(',
257 0x00ed: u')',
258 0x00ee: u'♂',
259 0x00ef: u'♀',
260 0x00f0: u'+',
261 0x00f1: u'ー',
262 0x00f2: u'×',
263 0x00f3: u'÷',
264 0x00f4: u'=',
265 0x00f5: u'~',
266 0x00f6: u':',
267 0x00f7: u';',
268 0x00f8: u'.',
269 0x00f9: u',',
270 0x00fa: u'♠',
271 0x00fb: u'♣',
272 0x00fc: u'♥',
273 0x00fd: u'♦',
274 0x00fe: u'★',
275 0x00ff: u'◎',
276 0x0100: u'○',
277 0x0101: u'□',
278 0x0102: u'△',
279 0x0103: u'◇',
280 0x0104: u'@',
281 0x0105: u'♪',
282 0x0106: u'%',
283 0x0107: u'☀',
284 0x0108: u'☁',
285 0x0109: u'☂',
286 0x010a: u'☃',
287 0x010f: u'⤴',
288 0x0110: u'⤵',
289 0x0112: u'円',
290 0x0116: u'✉',
291 0x011b: u'←',
292 0x011c: u'↑',
293 0x011d: u'↓',
294 0x011e: u'→',
295 0x0120: u'&',
296 0x0121: u'0',
297 0x0122: u'1',
298 0x0123: u'2',
299 0x0124: u'3',
300 0x0125: u'4',
301 0x0126: u'5',
302 0x0127: u'6',
303 0x0128: u'7',
304 0x0129: u'8',
305 0x012a: u'9',
306 0x012b: u'A',
307 0x012c: u'B',
308 0x012d: u'C',
309 0x012e: u'D',
310 0x012f: u'E',
311 0x0130: u'F',
312 0x0131: u'G',
313 0x0132: u'H',
314 0x0133: u'I',
315 0x0134: u'J',
316 0x0135: u'K',
317 0x0136: u'L',
318 0x0137: u'M',
319 0x0138: u'N',
320 0x0139: u'O',
321 0x013a: u'P',
322 0x013b: u'Q',
323 0x013c: u'R',
324 0x013d: u'S',
325 0x013e: u'T',
326 0x013f: u'U',
327 0x0140: u'V',
328 0x0141: u'W',
329 0x0142: u'X',
330 0x0143: u'Y',
331 0x0144: u'Z',
332 0x0145: u'a',
333 0x0146: u'b',
334 0x0147: u'c',
335 0x0148: u'd',
336 0x0149: u'e',
337 0x014a: u'f',
338 0x014b: u'g',
339 0x014c: u'h',
340 0x014d: u'i',
341 0x014e: u'j',
342 0x014f: u'k',
343 0x0150: u'l',
344 0x0151: u'm',
345 0x0152: u'n',
346 0x0153: u'o',
347 0x0154: u'p',
348 0x0155: u'q',
349 0x0156: u'r',
350 0x0157: u's',
351 0x0158: u't',
352 0x0159: u'u',
353 0x015a: u'v',
354 0x015b: u'w',
355 0x015c: u'x',
356 0x015d: u'y',
357 0x015e: u'z',
358 0x015f: u'À',
359 0x0160: u'Á',
360 0x0161: u'Â',
361 0x0163: u'Ä',
362 0x0166: u'Ç',
363 0x0167: u'È',
364 0x0168: u'É',
365 0x0169: u'Ê',
366 0x016a: u'Ë',
367 0x016b: u'Ì',
368 0x016c: u'Í',
369 0x016d: u'Î',
370 0x016e: u'Ï',
371 0x0170: u'Ñ',
372 0x0171: u'Ò',
373 0x0172: u'Ó',
374 0x0173: u'Ô',
375 0x0175: u'Ö',
376 0x0176: u'×',
377 0x0178: u'Ù',
378 0x0179: u'Ú',
379 0x017a: u'Û',
380 0x017b: u'Ü',
381 0x017e: u'ß',
382 0x017f: u'à',
383 0x0180: u'á',
384 0x0181: u'â',
385 0x0183: u'ä',
386 0x0186: u'ç',
387 0x0187: u'è',
388 0x0188: u'é',
389 0x0189: u'ê',
390 0x018a: u'ë',
391 0x018b: u'ì',
392 0x018c: u'í',
393 0x018d: u'î',
394 0x018e: u'ï',
395 0x0190: u'ñ',
396 0x0191: u'ò',
397 0x0192: u'ó',
398 0x0193: u'ô',
399 0x0195: u'ö',
400 0x0196: u'÷',
401 0x0198: u'ù',
402 0x0199: u'ú',
403 0x019a: u'û',
404 0x019b: u'ü',
405 0x019f: u'Œ',
406 0x01a0: u'œ',
407 0x01a3: u'ª',
408 0x01a4: u'º',
409 0x01a5: u'þ',
410 0x01a6: u'Þ',
411 0x01a7: u'ʳ',
412 0x01a8: u'¥',
413 0x01a9: u'¡',
414 0x01aa: u'¿',
415 0x01ab: u'!',
416 0x01ac: u'?',
417 0x01ad: u',',
418 0x01ae: u'.',
419 0x01af: u'…',
420 0x01b0: u'·',
421 0x01b1: u'/',
422 0x01b2: u'‘',
423 0x01b3: u'\'',
424 0x01b3: u'’',
425 0x01b4: u'“',
426 0x01b5: u'”',
427 0x01b6: u'„',
428 0x01b7: u'«',
429 0x01b8: u'»',
430 0x01b9: u'(',
431 0x01ba: u')',
432 0x01bb: u'♂',
433 0x01bc: u'♀',
434 0x01bd: u'+',
435 0x01be: u'-',
436 0x01bf: u'*',
437 0x01c0: u'#',
438 0x01c1: u'=',
439 0x01c2: u'&',
440 0x01c3: u'~',
441 0x01c4: u':',
442 0x01c5: u';',
443 0x01c6: u'♠',
444 0x01c7: u'♣',
445 0x01c8: u'♥',
446 0x01c9: u'♦',
447 0x01ca: u'★',
448 0x01cb: u'◎',
449 0x01cc: u'○',
450 0x01cd: u'□',
451 0x01ce: u'△',
452 0x01cf: u'◇',
453 0x01d0: u'@',
454 0x01d1: u'♪',
455 0x01d2: u'%',
456 0x01d3: u'☀',
457 0x01d4: u'☁',
458 0x01d5: u'☂',
459 0x01d6: u'☃',
460 0x01db: u'⤴',
461 0x01dc: u'⤵',
462 0x01de: u' ',
463 0xe000: u'\n',
464 0x25bc: u'\f',
465 0x25bd: u'\r',
466 }
467
468 # And the reverse dict, used with str.translate()
469 inverse_character_table = dict()
470 for in_, out in character_table.iteritems():
471 inverse_character_table[ord(out)] = in_
472
473
474 def LittleEndianBitStruct(*args):
475 """Construct's bit structs read a byte at a time in the order they appear,
476 reading each bit from most to least significant. Alas, this doesn't work
477 at all for a 32-bit bit field, because the bytes are 'backwards' in
478 little-endian files.
479
480 So this acts as a bit struct, but reverses the order of bytes before
481 reading/writing, so ALL the bits are read from most to least significant.
482 """
483 return Buffered(
484 BitStruct(*args),
485 encoder=lambda s: s[::-1],
486 decoder=lambda s: s[::-1],
487 resizer=lambda _: _,
488 )
489
490 class PokemonStringAdapter(Adapter):
491 u"""Adapter that encodes/decodes Pokémon-formatted text stored in a regular
492 String struct.
493 """
494 def _decode(self, obj, context):
495 decoded_text = obj.decode('utf16')
496
497 # Real string ends at the \uffff character
498 if u'\uffff' in decoded_text:
499 decoded_text = decoded_text[0:decoded_text.index(u'\uffff')]
500 # XXX save "trash bytes" somewhere..?
501
502 return decoded_text.translate(character_table)
503
504 def _encode(self, obj, context):
505 #padded_text = (obj + u'\xffff' + '\x00' * 12)
506 padded_text = obj
507 decoded_text = padded_text.translate(inverse_character_table)
508 return decoded_text.encode('utf16')
509
510 class DateAdapter(Adapter):
511 """Converts between a three-byte string and a Python date.
512
513 Only dates in 2000 or later will work!
514 """
515 def _decode(self, obj, context):
516 if obj == '\x00\x00\x00':
517 return None
518
519 y, m, d = (ord(byte) for byte in obj)
520 y += 2000
521 return datetime.date(y, m, d)
522
523 def _encode(self, obj, context):
524 if obj is None:
525 return '\x00\x00\x00'
526
527 y, m, d = obj.year - 2000, obj.month, obj.day
528 return ''.join(chr(n) for n in (y, m, d))
529
530 class PokemonFormAdapter(Adapter):
531 """Converts form ids to form names, and vice versa."""
532 pokemon_forms = {
533 # Unown
534 201: 'abcdefghijklmnopqrstuvwxyz!?',
535
536 # Deoxys
537 386: ['normal', 'attack', 'defense', 'speed'],
538
539 # Burmy and Wormadam
540 412: ['plant', 'sandy', 'trash'],
541 413: ['plant', 'sandy', 'trash'],
542
543 # Shellos and Gastrodon
544 422: ['west', 'east'],
545 423: ['west', 'east'],
546
547 # Rotom
548 479: ['normal', 'heat', 'wash', 'frost', 'fan', 'cut'],
549
550 # Giratina
551 487: ['altered', 'origin'],
552
553 # Shaymin
554 492: ['land', 'sky'],
555
556 # Arceus
557 493: [
558 'normal', 'fighting', 'flying', 'poison', 'ground', 'rock',
559 'bug', 'ghost', 'steel', 'fire', 'water', 'grass',
560 'thunder', 'psychic', 'ice', 'dragon', 'dark', '???',
561 ],
562 }
563
564 def _decode(self, obj, context):
565 try:
566 forms = self.pokemon_forms[ context['national_id'] ]
567 except KeyError:
568 return None
569
570 return forms[obj >> 3]
571
572 def _encode(self, obj, context):
573 try:
574 forms = self.pokemon_forms[ context['national_id'] ]
575 except KeyError:
576 return None
577
578 return forms.index(obj) << 3
579
580
581
582 # And here we go.
583 # Docs: http://projectpokemon.org/wiki/Pokemon_NDS_Structure
584 pokemon_struct = Struct('pokemon_struct',
585 # Header
586 ULInt32('personality'), # XXX aughgh http://bulbapedia.bulbagarden.net/wiki/Personality
587 Padding(2),
588 ULInt16('checksum'), # XXX should be checked or calculated
589
590 # Block A
591 ULInt16('national_id'),
592 ULInt16('held_item_id'),
593 ULInt16('original_trainer_id'),
594 ULInt16('original_trainer_secret_id'),
595 ULInt32('exp'),
596 ULInt8('happiness'),
597 ULInt8('ability_id'), # XXX needs to match personality + species
598 BitStruct('markings',
599 Padding(2),
600 Flag('diamond'),
601 Flag('star'),
602 Flag('heart'),
603 Flag('square'),
604 Flag('triangle'),
605 Flag('circle'),
606 ),
607 Enum(
608 ULInt8('original_country'),
609 jp=1,
610 us=2,
611 fr=3,
612 it=4,
613 de=5,
614 es=7,
615 kr=8,
616 ),
617
618 # XXX sum cannot surpass 510
619 ULInt8('effort_hp'),
620 ULInt8('effort_attack'),
621 ULInt8('effort_defense'),
622 ULInt8('effort_speed'),
623 ULInt8('effort_special_attack'),
624 ULInt8('effort_special_defense'),
625
626 ULInt8('contest_cool'),
627 ULInt8('contest_beauty'),
628 ULInt8('contest_cute'),
629 ULInt8('contest_smart'),
630 ULInt8('contest_tough'),
631 ULInt8('contest_sheen'),
632
633 LittleEndianBitStruct('sinnoh_ribbons',
634 Padding(4),
635 Flag('premier_ribbon'),
636 Flag('classic_ribbon'),
637 Flag('carnival_ribbon'),
638 Flag('festival_ribbon'),
639 Flag('blue_ribbon'),
640 Flag('green_ribbon'),
641 Flag('red_ribbon'),
642 Flag('legend_ribbon'),
643 Flag('history_ribbon'),
644 Flag('record_ribbon'),
645 Flag('footprint_ribbon'),
646 Flag('gorgeous_royal_ribbon'),
647 Flag('royal_ribbon'),
648 Flag('gorgeous_ribbon'),
649 Flag('smile_ribbon'),
650 Flag('snooze_ribbon'),
651 Flag('relax_ribbon'),
652 Flag('careless_ribbon'),
653 Flag('downcast_ribbon'),
654 Flag('shock_ribbon'),
655 Flag('alert_ribbon'),
656 Flag('world_ability_ribbon'),
657 Flag('pair_ability_ribbon'),
658 Flag('multi_ability_ribbon'),
659 Flag('double_ability_ribbon'),
660 Flag('great_ability_ribbon'),
661 Flag('ability_ribbon'),
662 Flag('sinnoh_champ_ribbon'),
663 ),
664
665 # Block B
666 ULInt16('move1_id'),
667 ULInt16('move2_id'),
668 ULInt16('move3_id'),
669 ULInt16('move4_id'),
670 ULInt8('move1_pp'),
671 ULInt8('move2_pp'),
672 ULInt8('move3_pp'),
673 ULInt8('move4_pp'),
674 ULInt8('move1_pp_ups'),
675 ULInt8('move2_pp_ups'),
676 ULInt8('move3_pp_ups'),
677 ULInt8('move4_pp_ups'),
678
679 LittleEndianBitStruct('ivs',
680 Flag('is_nicknamed'),
681 Flag('is_egg'),
682 BitField('iv_special_defense', 5),
683 BitField('iv_special_attack', 5),
684 BitField('iv_speed', 5),
685 BitField('iv_defense', 5),
686 BitField('iv_attack', 5),
687 BitField('iv_hp', 5),
688 ),
689 LittleEndianBitStruct('hoenn_ribbons',
690 Flag('world_ribbon'),
691 Flag('earth_ribbon'),
692 Flag('national_ribbon'),
693 Flag('country_ribbon'),
694 Flag('sky_ribbon'),
695 Flag('land_ribbon'),
696 Flag('marine_ribbon'),
697 Flag('effort_ribbon'),
698 Flag('artist_ribbon'),
699 Flag('victory_ribbon'),
700 Flag('winning_ribbon'),
701 Flag('champion_ribbon'),
702 Flag('tough_ribbon_master'),
703 Flag('tough_ribbon_hyper'),
704 Flag('tough_ribbon_super'),
705 Flag('tough_ribbon'),
706 Flag('smart_ribbon_master'),
707 Flag('smart_ribbon_hyper'),
708 Flag('smart_ribbon_super'),
709 Flag('smart_ribbon'),
710 Flag('cute_ribbon_master'),
711 Flag('cute_ribbon_hyper'),
712 Flag('cute_ribbon_super'),
713 Flag('cute_ribbon'),
714 Flag('beauty_ribbon_master'),
715 Flag('beauty_ribbon_hyper'),
716 Flag('beauty_ribbon_super'),
717 Flag('beauty_ribbon'),
718 Flag('cool_ribbon_master'),
719 Flag('cool_ribbon_hyper'),
720 Flag('cool_ribbon_super'),
721 Flag('cool_ribbon'),
722 ),
723 EmbeddedBitStruct(
724 PokemonFormAdapter(BitField('alternate_form', 5)),
725 Enum(BitField('gender', 2),
726 genderless = 2,
727 male = 0,
728 female = 1,
729 ),
730 Flag('fateful_encounter'),
731 ),
732 BitStruct('shining_leaves',
733 Padding(2),
734 Flag('crown'),
735 Flag('leaf5'),
736 Flag('leaf4'),
737 Flag('leaf3'),
738 Flag('leaf2'),
739 Flag('leaf1'),
740 ),
741 Padding(2),
742 ULInt16('pt_egg_location_id'),
743 ULInt16('pt_met_location_id'),
744
745 # Block C
746 PokemonStringAdapter(String('nickname', 22)),
747 Padding(1),
748 Enum(ULInt8('original_version'),
749 sapphire = 1,
750 ruby = 2,
751 emerald = 3,
752 firered = 4,
753 leafgreen = 5,
754 heartgold = 7,
755 soulsilver = 8,
756 diamond = 10,
757 pearl = 11,
758 platinum = 12,
759 orre = 15,
760 ),
761 LittleEndianBitStruct('sinnoh_contest_ribbons',
762 Padding(12),
763 Flag('tough_ribbon_master'),
764 Flag('tough_ribbon_ultra'),
765 Flag('tough_ribbon_great'),
766 Flag('tough_ribbon'),
767 Flag('smart_ribbon_master'),
768 Flag('smart_ribbon_ultra'),
769 Flag('smart_ribbon_great'),
770 Flag('smart_ribbon'),
771 Flag('cute_ribbon_master'),
772 Flag('cute_ribbon_ultra'),
773 Flag('cute_ribbon_great'),
774 Flag('cute_ribbon'),
775 Flag('beauty_ribbon_master'),
776 Flag('beauty_ribbon_ultra'),
777 Flag('beauty_ribbon_great'),
778 Flag('beauty_ribbon'),
779 Flag('cool_ribbon_master'),
780 Flag('cool_ribbon_ultra'),
781 Flag('cool_ribbon_great'),
782 Flag('cool_ribbon'),
783 ),
784 Padding(4),
785
786 # Block D
787 PokemonStringAdapter(String('original_trainer_name', 16)),
788 DateAdapter(String('date_egg_received', 3)),
789 DateAdapter(String('date_met', 3)),
790 ULInt16('dp_egg_location_id'),
791 ULInt16('dp_met_location_id'),
792 ULInt8('pokerus'),
793 ULInt8('dppt_pokeball'),
794 EmbeddedBitStruct(
795 Enum(Flag('original_trainer_gender'),
796 male = False,
797 female = True,
798 ),
799 BitField('met_at_level', 7),
800 ),
801 Enum(ULInt8('encounter_type'),
802 special = 0, # egg; pal park; event; honey tree; shaymin
803 grass = 2, # or darkrai
804 dialga_palkia = 4,
805 cave = 5, # or giratina or hall of origin
806 water = 7,
807 building = 9,
808 safari_zone = 10, # includes great marsh
809 gift = 12, # starter; fossil; ingame trade?
810 # distortion_world = ???,
811 hgss_gift = 24, # starter; fossil; bebe's eevee (pt only??)
812 ),
813 ULInt8('hgss_pokeball'),
814 Padding(1),
815 )