shithub: pokecrystal

Download patch

ref: 82731321cb7c6063fbca87ca9ab7ed0a0a364ba9
parent: fb7c3a3ea5c758e1f4ddd2d1d859115cbb419248
author: Bryan Bishop <[email protected]>
date: Sat May 19 12:39:36 EDT 2012

parse multiple party mons per trainer

--- a/extras/crystal.py
+++ b/extras/crystal.py
@@ -3440,6 +3440,7 @@
 trainer_group_pointer_table_address    = 0x39999
 trainer_group_pointer_table_address_gs = 0x3993E
 
+trainer_group_table = None
 class TrainerGroupTable:
     """ A list of pointers.
     """
@@ -3468,7 +3469,7 @@
         return dependencies
 
     def parse(self):
-        size = 0 
+        size = 0
         for (key, kvalue) in trainer_group_names.items():
             # calculate the location of this trainer group header from its pointer
             pointer_bytes_location = kvalue["pointer_address"]
@@ -3536,6 +3537,11 @@
         size = 0
         current_address = self.address
 
+        if self.group_id not in trainer_group_maximums.keys():
+            self.size = 0
+            self.last_address = current_address
+            return
+
         # create an IndividualTrainerHeader for each id in range(min id, max id + 1)
         min_id = min(trainer_group_maximums[self.group_id])
         max_id = max(trainer_group_maximums[self.group_id])
@@ -3542,7 +3548,9 @@
 
         for trainer_id in range(min_id, max_id+1):
             trainer_header = TrainerHeader(address=current_address, trainer_group_id=self.group_id, trainer_id=trainer_id, parent=self)
-            current_address += trainer_header.size
+            self.individual_trainer_headers.append(trainer_header)
+            #current_address += trainer_header.size
+            current_address = trainer_header.last_address
             size += trainer_header.size
 
         self.last_address = current_address
@@ -3549,8 +3557,8 @@
         self.size = size
 
     def to_asm(self):
-        raise NotImplementedError
-        output += ""
+        output = "\n\n".join(["; "+header.make_name()+" at "+hex(header.address)+"\n"+header.to_asm() for header in self.individual_trainer_headers])
+        return output
 
 class TrainerHeader:
     """
@@ -3579,7 +3587,10 @@
         """ Must occur after parse() is called.
         Constructs a name based on self.parent.group_name and self.name.
         """
-        return self.parent.group_name + "_" + self.name
+        if self.trainer_group_id in [0x14, 0x16, 0x17, 0x18, 0x19, 0x1B, 0x1C, 0x1D, 0x1E, 0x20, 0x21, 0x22, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2B, 0x2C, 0x2D, 0x2F, 0x30, 0x31, 0x32, 0x34, 0x35, 0x36, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x41]:
+            return self.parent.group_name.upper() + "_" + self.name[:-1]
+        else:
+            return self.parent.group_name + "_" + str(self.trainer_id)
 
     def get_dependencies(self, recompute=False, global_dependencies=set()):
         if recompute or self.dependencies == None:
@@ -3616,14 +3627,16 @@
         self.party_mons = party_mon_parser(address=current_address, group_id=self.trainer_group_id, trainer_id=self.trainer_id, parent=self)
 
         # let's have everything in trainer_party_mon_parsers handle the last $FF
-        self.size = self.party_mons.size + 1 + len(self.name)
+        #self.size = self.party_mons.size + 1 + len(self.name)
+        self.size = self.party_mons.last_address - self.address
         self.last_address = self.party_mons.last_address
 
     def to_asm(self):
         output = "db \""+self.name+"\"\n"
         output += "; data type\n"
-        output += "db $%.2x\n"%(self.data_byte)
+        output += "db $%.2x\n"%(self.data_type)
         output += self.party_mons.to_asm()
+        output += "\n; last_address="+hex(self.last_address)+" size="+str(self.size)
         return output
 
 # TODO: MoveParam should map to an actual attack
@@ -3635,7 +3648,6 @@
     """
     id = None
     dependencies = None
-    params = []
     param_types = None
 
     # could go either way on this one.. TrainerGroupHeader.parse would need to be changed
@@ -3648,44 +3660,42 @@
         self.trainer_id = trainer_id
         self.parent = parent
         self.args = {}
-        self.params = {}
+        self.mons = {}
         self.parse()
 
         # pick up the $FF at the end
-        self.size += 1
         self.last_address += 1
 
-    # this is exactly Command.parse
     def parse(self):
-        #id, size (inclusive), param_types
-        #param_type = {"name": each[1], "class": each[0]}
-        if not self.override_byte_check:
-            current_address = self.address+1
-        else:
-            current_address = self.address
-        byte = ord(rom[self.address])
-        if not self.override_byte_check and (not byte == self.id):
-            raise Exception, "byte ("+hex(byte)+") != self.id ("+hex(self.id)+")"
-        i = 0
-        for (key, param_type) in self.param_types.items():
-            name = param_type["name"]
-            klass = param_type["class"]
-            #make an instance of this class, like SingleByteParam()
-            #or ItemLabelByte.. by making an instance, obj.parse() is called
-            obj = klass(address=current_address, name=name, parent=self, **dict([(k,v) for (k, v) in self.args.items() if k not in ["parent"]]))
-            #save this for later
-            self.params[i] = obj
-            #increment our counters
-            current_address += obj.size
-            i += 1
+        current_address = self.address
+        pkmn = 0
+        continuer = True
+        while continuer:
+            self.mons[pkmn] = {}
+            i = 0
+            for (key, param_type) in self.param_types.items():
+                name = param_type["name"]
+                klass = param_type["class"]
+                #make an instance of this class, like SingleByteParam()
+                #or ItemLabelByte.. by making an instance, obj.parse() is called
+                obj = klass(address=current_address, name=name, parent=self, **dict([(k,v) for (k, v) in self.args.items() if k not in ["parent"]]))
+                #save this for later
+                self.mons[pkmn][i] = obj
+                #increment our counters
+                current_address += obj.size
+                i += 1
+            pkmn += 1
+            if ord(rom[current_address]) == 0xFF:
+                break
         self.last_address = current_address
         return True
 
     def to_asm(self):
-        output = "; " + ", ".join([param_type["name"] for param_type in self.param_types]) + "\n"
-        output += "db " + ", ".join([param.to_asm() for (name, param) in self.params.items()])
-        output += "\n"
-        output += "db $FF ; end trainer party mons"
+        output = "; " + ", ".join([param_type["name"] for (key, param_type) in self.param_types.items()]) + "\n"
+        for mon in self.mons:
+            output += "db " + ", ".join([param.to_asm() for (name, param) in self.mons[mon].items()])
+            output += "\n"
+        output += "db $ff ; end trainer party mons"
         return output
 
 class TrainerPartyMonParser0(TrainerPartyMonParser):
@@ -7923,7 +7933,8 @@
     find_trainer_ids_from_scripts()
 
     # and parse the main TrainerGroupTable once we know the max number of trainers
-    trainer_group_header = TrainerGroupTable()
+    global trainer_group_table
+    trainer_group_table = TrainerGroupTable()
 
 #just a helpful alias
 main=run_main