shithub: pokecrystal

Download patch

ref: 873b07dcf92379476a859cebabe4612a7207aae7
parent: 0a7278c1447f3d74f81d3987b94c5f2c366ed8fc
author: Bryan Bishop <[email protected]>
date: Sun Mar 11 21:09:25 EDT 2012

trainer headers

--- a/extras/crystal.py
+++ b/extras/crystal.py
@@ -375,6 +375,8 @@
         bank = calculate_bank(address)
     elif bank == "reverse" or bank == "reversed":
         bank = ord(rom[address+2])
+    elif type(bank) == int:
+        pass
     else:
         raise "bad bank given to calculate_pointer_from_bytes_at"
     byte1 = ord(rom[address])
@@ -410,7 +412,7 @@
     #info1 += "    long_info: " + long_info
     return info1
 
-def parse_text_engine_script_at(address):
+def parse_text_engine_script_at(address, map_group=None, map_id=None):
     """parses a text-engine script ("in-text scripts")
     http://hax.iimarck.us/files/scriptingcodes_eng.htm#InText
     """
@@ -2538,6 +2540,56 @@
             "script": script,
         })
     return signposts
+def parse_trainer_header_at(address, map_group=None, map_id=None):
+    """
+    [Bit no. (2byte)][Trainer group][Trainer]
+    [2byte pointer to Text when seen]
+    [2byte pointer to text when trainer beaten]
+    [2byte pointer to script when lost (0000=Blackout)]
+    [2byte pointer to script if won/talked to again]
+     
+    The bit number tell the game later on if the trainer has been
+    beaten already (bit = 1) or not (bit = 0). All Bit number of BitTable1.
+     
+    03 = Nothing
+    04 = Nothing
+    05 = Nothing
+    06 = Nothing
+    """
+    bank = calculate_bank(address)
+    bytes = rom_interval(address, 12, strings=False)
+    bit_number = bytes[0]
+    trainer_group = bytes[1]
+    trainer_id = bytes[2]
+    text_when_seen_ptr = calculate_pointer_from_bytes_at(address+3, bank=bank)
+    text_when_seen = parse_text_engine_script_at(text_when_seen_ptr, map_group=map_group, map_id=map_id)
+    text_when_trainer_beaten_ptr = calculate_pointer_from_bytes_at(address+5, bank=bank)
+    text_when_trainer_beaten = parse_text_engine_script_at(text_when_trainer_beaten_ptr, map_group=map_group, map_id=map_id)
+    if [ord(rom[address+7]), ord(rom[address+8])] == [0, 0]:
+        script_when_lost_ptr = 0
+        script_when_lost = None
+    else:
+        print "parsing script-when-lost"
+        script_when_lost_ptr = calculate_pointer_from_bytes_at(address+7, bank=bank)
+        script_when_lost = None #parse_script_engine_script_at(script_when_lost_ptr, map_group=map_group, map_id=map_id)
+    print "parsing script-talk-again" #or is this a text?
+    script_talk_again_ptr = calculate_pointer_from_bytes_at(address+9, bank=bank)
+    script_talk_again = None #parse_script_engine_script_at(script_talk_again_ptr, map_group=map_group, map_id=map_id)
+    
+    return {
+        "bit_number": bit_number,
+        "trainer_group": trainer_group,
+        "trainer_id": trainer_id,
+        "text_when_seen_ptr": text_when_seen_ptr,
+        "text_when_seen": text_when_seen,
+        "text_when_trainer_beaten_ptr": text_when_trainer_beaten_ptr,
+        "text_when_trainer_beaten": text_when_trainer_beaten,
+        "script_when_lost_ptr": script_when_lost_ptr,
+        "script_when_lost": script_when_lost,
+        "script_talk_again_ptr": script_talk_again_ptr,
+        "script_talk_again": script_talk_again,
+    }
+    
 def parse_people_event_bytes(some_bytes, address=None, map_group=None, map_id=None): #max of 14 people per map?
     """parse some number of people-events from the data
     see http://hax.iimarck.us/files/scriptingcodes_eng.htm#Scripthdr
@@ -2568,6 +2620,20 @@
         color_function_byte = int(bytes[7], 16) #Color|Function
         trainer_sight_range = int(bytes[8], 16)
         
+        lower_bits = color_function_byte & 0xF
+        #lower_bits_high = lower_bits >> 2
+        #lower_bits_low = lower_bits & 3
+        higher_bits = color_function_byte >> 4
+        #higher_bits_high = higher_bits >> 2
+        #higher_bits_low = higher_bits & 3
+
+        is_regular_script = lower_bits == 00
+        #pointer points to script
+        is_give_item = lower_bits == 01
+        #pointer points to [Item no.][Amount]
+        is_trainer = lower_bits == 02
+        #pointer points to trainer header
+
         #goldmap called these next two bytes "text_block" and "text_bank"?
         script_pointer_byte1 = int(bytes[9], 16)
         script_pointer_byte2 = int(bytes[10], 16)
@@ -2574,14 +2640,34 @@
         script_pointer = script_pointer_byte1 + (script_pointer_byte2 << 8)
         #calculate the full address by assuming it's in the current bank
         #but what if it's not in the same bank?
-        script_address = None
-        script = None
+        extra_portion = {}
         if bank:
-            print "parsing a person-script at x=" + str(x) + " y=" + str(y)
-            script_address = calculate_pointer(script_pointer, bank)
-            script = parse_script_engine_script_at(script_address, map_group=map_group, map_id=map_id)
-
-        #take the script pointer
+            ptr_address = calculate_pointer(script_pointer, bank)
+            if is_regular_script:
+                print "parsing a person-script at x=" + str(x-4) + " y=" + str(y-4)
+                script = parse_script_engine_script_at(ptr_address, map_group=map_group, map_id=map_id)
+                extra_portion = {
+                    "script_address": ptr_address,
+                    #"script": script,
+                    "event_type": "script",
+                }
+            if is_give_item:
+                print "... not parsing give item event... [item id][quantity]"
+                extra_portion = {
+                    "event_type": "give_item",
+                    "give_item_data_address": ptr_address,
+                    "item_id": ord(rom[ptr_address]),
+                    "item_qty": ord(rom[ptr_address+1]),
+                }
+            if is_trainer:
+                print "parsing a trainer (person-event) at x=" + str(x) + " y=" + str(y)
+                parsed_trainer = parse_trainer_header_at(ptr_address, map_group=map_group, map_id=map_id)
+                extra_portion = {
+                    "event_type": "trainer",
+                    "trainer_data_address": ptr_address,
+                    "trainer_data": parsed_trainer,
+                }
+                
 
         #XXX not sure what's going on here
         #bit no. of bit table 1 (hidden if set)
@@ -2589,7 +2675,11 @@
         when_byte = int(bytes[11], 16)
         hide = int(bytes[12], 16)
 
-        people_events.append({
+        bit_number_of_bit_table1_byte2 = int(bytes[11], 16)
+        bit_number_of_bit_table1_byte1 = int(bytes[12], 16)
+        bit_number_of_bit_table1 = bit_number_of_bit_table1_byte1 + (bit_number_of_bit_table1_byte2 << 8)
+
+        people_event = {
             "pict": pict,
             "y": y,                      #y from top + 4
             "x": x,                      #x from left + 4
@@ -2601,13 +2691,14 @@
             "trainer_sight_range": trainer_sight_range,  #trainer range of sight
             "script_pointer": {"1": script_pointer_byte1,
                                "2": script_pointer_byte2},
-            "script_address": script_address,
-            "script": script,            #parsed script.. hah!
+
             #"text_block": text_block,   #script pointer byte 1
             #"text_bank": text_bank,     #script pointer byte 2
             "when_byte": when_byte,      #bit no. of bit table 1 (hidden if set)
             "hide": hide,                #note: FFFF for none
-        })
+        }
+        people_event.update(extra_portion)
+        people_events.append(people_event)
     return people_events
 
 class MapEventElement():
@@ -2737,14 +2828,12 @@
     after_signposts = after_triggers + 1 + signpost_byte_count
     returnable.update({"signpost_count": signpost_count, "signposts": parse_signpost_bytes(signposts, bank=bank, map_group=map_group, map_id=map_id)})
   
-    print "skipping event data... (oops)"
-    #raise NotImplementedError, "holy mother of god"
-    #XXX parse trainer data too.. this changes the structure of people events...
     #people events
-    #people_event_count = ord(rom[after_signposts])
-    #people_event_byte_count = people_event_byte_size * people_event_count
-    #people_events = rom_interval(after_signposts+1, people_event_byte_count)
-    #returnable.update({"people_event_count": people_event_count, "people_events": parse_people_event_bytes(people_events, address=after_signposts+1, map_group=map_group, map_id=map_id)})
+    people_event_count = ord(rom[after_signposts])
+    people_event_byte_count = people_event_byte_size * people_event_count
+    people_events_bytes = rom_interval(after_signposts+1, people_event_byte_count)
+    people_events = parse_people_event_bytes(people_events_bytes, address=after_signposts+1, map_group=map_group, map_id=map_id)
+    returnable.update({"people_event_count": people_event_count, "people_events": people_events})
 
     return returnable
 
@@ -2800,6 +2889,7 @@
         after battle:
             01, 04
     """
+    print "starting to parse the map's script header.."
     #[[Number1 of pointers] Number1 * [2byte pointer to script][00][00]]
     ptr_line_size = 4 #[2byte pointer to script][00][00]
     trigger_ptr_cnt = ord(rom[address])
@@ -2806,6 +2896,7 @@
     trigger_pointers = grouper(rom_interval(address+1, trigger_ptr_cnt * ptr_line_size, strings=False), count=ptr_line_size)
     triggers = {}
     for index, trigger_pointer in enumerate(trigger_pointers):
+        print "parsing a trigger header..."
         byte1 = trigger_pointer[0]
         byte2 = trigger_pointer[1]
         ptr   = byte1 + (byte2 << 8)
@@ -2827,6 +2918,7 @@
     callback_pointers = {}
     callbacks = {}
     for index, callback_line in enumerate(callback_ptrs):
+        print "parsing a callback header..."
         hook_byte = callback_line[0] #1, 2, 3, 4, 5
         callback_byte1 = callback_line[1]
         callback_byte2 = callback_line[2]
@@ -2851,18 +2943,40 @@
         "callback_scripts": callbacks,
     }
 
+def parse_map_header_by_id(*args, **kwargs):
+    """convenience function to parse a specific map"""
+    map_group, map_id = None, None
+    if "map_group" in kwargs.keys():
+        map_group = kwargs["map_group"]
+    if "map_id" in kwargs.keys():
+        map_id = kwargs["map_id"]
+    if (map_group == None and map_id != None) or \
+       (map_group != None and map_id == None):
+        raise Exception, "map_group and map_id must both be provided"
+    elif map_group == None and map_id == None and len(args) == 0:
+        raise Exception, "must be given an argument"
+    elif len(args) == 1 and type(args[0]) == str:
+        map_group = int(args[0].split(".")[0])
+        map_id = int(args[0].split(".")[1])
+    else:
+        raise Exception, "dunno what to do with input"
+    offset = map_names[map_group]["offset"]
+    map_header_offset = offset + ((map_id - 1) * map_header_byte_size)
+    return parse_map_header_at(map_header_offset, map_group=map_group, map_id=map_id)
+
 def parse_all_map_headers():
     """calls parse_map_header_at for each map in each map group"""
     global map_names
     if not map_names[1].has_key("offset"):
-        raise "dunno what to do - map_names should have groups with pre-calculated offsets by now"
+        raise Exception, "dunno what to do - map_names should have groups with pre-calculated offsets by now"
     for group_id, group_data in map_names.items():
         offset = group_data["offset"]
         #we only care about the maps
-        del group_data["offset"]
+        #del group_data["offset"]
         for map_id, map_data in group_data.items():
-            map_header_offset = offset + ((map_id - 1) * map_header_byte_size)
+            if map_id == "offset": continue #skip the "offset" address for this map group
             print "map_group is: " + str(group_id) + "  map_id is: " + str(map_id)
+            map_header_offset = offset + ((map_id - 1) * map_header_byte_size)
             parsed_map = parse_map_header_at(map_header_offset, map_group=group_id, map_id=map_id)
             map_names[group_id][map_id].update(parsed_map)
             map_names[group_id][map_id]["header_offset"] = map_header_offset