diff --git a/extras/crystal.py b/extras/crystal.py index d2689e811..316030d5c 100644 --- a/extras/crystal.py +++ b/extras/crystal.py @@ -359,18 +359,1198 @@ def calculate_bank(address): if type(address) == str: address = int(address, 16) return int(address) / 0x4000 - def calculate_pointer(short_pointer, bank): """calculates the full address given a 4-byte pointer and bank byte""" short_pointer = int(short_pointer) bank = int(bank) pointer = short_pointer - 0x4000 + (bank * 0x4000) return pointer +def calculate_pointer_from_bytes_at(address, bank=False): + """calculates a pointer from 2 bytes at a location + or 3-byte pointer [bank][2-byte pointer] if bank=True""" + if bank == True: + bank = ord(rom[address]) + address += 1 + elif bank == False: + bank = calculate_bank(address) + elif bank == "reverse" or bank == "reversed": + bank = ord(rom[address+2]) + else: + raise "bad bank given to calculate_pointer_from_bytes_at" + byte1 = ord(rom[address]) + byte2 = ord(rom[address+1]) + temp = byte1 + (byte2 << 8) + return calculate_pointer(temp, bank) + +def command_debug_information(command_byte=None, map_group=None, map_id=None, address=None): + return "parsing command byte " + hex(command_byte) + " for map " + \ + str(map_group) + "." + str(map_id) + " at " + hex(address) def parse_script_at(address): """parses a script-engine script""" + global rom + if rom == None: + load_rom() return {} + commands = {} + offset = address + end = False + while not end: + command_byte = ord(rom[offset]) + command = {"type": command_byte, "start_address": offset} + print command_debug_information(command_byte=command_byte, map_group=map_group, map_id=map_id, address=offset) + + #size is the total size including the command byte + #last_byte_address is offset+size-1 + start_address = offset + + if command_byte == 0x00: #Pointer code [2b+ret] + #2byte pointer points to script; when pointed script ends --> return to old script + #[code][2 byte pointer] + size = 3 + start_address = offset + last_byte_address = offset + size - 1 + command["pointer"] = calculate_pointer_from_bytes_at(start_address+1) + #XXX should we also parse this target script? + elif command_byte == 0x01: #Pointer code [3b+ret] + #3byte pointer points to script; when pointed script ends --> return to old script + #[Code][resp. pointer(2byte or 3byte)] + size = 4 + command["pointer"] = calculate_pointer_from_bytes_at(start_address+1, bank=True) + elif command_byte == 0x02: #Pointer code [2b+3b+ret] + #2byte pointer points to 3byte pointer; when pointed script --> return to old script + #[Code][resp. pointer(2byte or 3byte)] + size = 3 + command["pointer"] = calculate_pointer_from_bytes_at(start_address+1) + elif command_byte == 0x03: #Pointer code [2b] + #XXX what does "new script is part of main script" mean? + #2byte pointer points to script; new script is part of main script + #[Code][resp. pointer(2byte or 3byte)] + size = 3 + command["pointer"] = calculate_pointer_from_bytes_at(start_address+1) + elif command_byte == 0x04: #Pointer code [3b] + #3byte pointer points to script; new script is part of main script + #[Code][resp. pointer(2byte or 3byte)] + size = 4 + command["pointer"] = calculate_pointer_from_bytes_at(start_address+1, bank=True) + elif command_byte == 0x05: #Pointer code [2b+3b] + #2byte pointer points to 3byte pointer; new script is part of main script + #[Code][resp. pointer(2byte or 3byte)] + size = 3 + command["pointer"] = calculate_pointer_from_bytes_at(start_address+1) + elif command_byte == 0x06: #RAM check [=byte] + #When the conditional is true... + #.. then go to pointed script, else resume interpreting after the pointer + size = 3 + command["pointer"] = calculate_pointer_from_bytes_at(start_address+1) + elif command_byte == 0x07: #RAM check [<>byte] + #When the conditional is true... + #.. then go to pointed script, else resume interpreting after the pointer + size = 3 + command["pointer"] = calculate_pointer_from_bytes_at(start_address+1) + elif command_byte == 0x08: #RAM check [=0] + #When the conditional is true... + #.. then go to pointed script, else resume interpreting after the pointer + size = 3 + command["pointer"] = calculate_pointer_from_bytes_at(start_address+1) + elif command_byte == 0x09: #RAM check [<>0] + #When the conditional is true... + #.. then go to pointed script, else resume interpreting after the pointer + size = 3 + command["pointer"] = calculate_pointer_from_bytes_at(start_address+1) + elif command_byte == 0x0A: #RAM check [byte] + #When the conditional is true... + #.. then go to pointed script, else resume interpreting after the pointer + size = 3 + command["pointer"] = calculate_pointer_from_bytes_at(start_address+1) + elif command_byte == 0x0C: #0C codes [xxyy] + #Calls predefined scripts. After this code the script ends. + #[0C][xxyy] + size = 3 + end = True + byte1 = ord(rom[offset+1]) + byte2 = ord(rom[offset+2]) + number = byte1 + (byte2 << 8) + #0000 to 000AD ... XXX how should these be handled? + command["predefined_script_number"] = number + elif command_byte == 0x0D: #0D codes [xxyy] + #Calls predefined scripts. Exactly like $0C except the script does not end. + size = 3 + byte1 = ord(rom[offset+1]) + byte2 = ord(rom[offset+2]) + number = byte1 + (byte2 << 8) + #0000 to 000AD ... XXX how should these be handled? + command["predefined_script_number"] = number + elif command_byte == 0x0E: #ASM code1 [3b] + #Calls a predefined routine by interpreting the ASM the pointer points to. + #[0E][3byte pointer] + size = 4 + command["pointer"] = calculate_pointer_from_bytes_at(start_address+1, bank=True) + #XXX should we dissassemble the asm at the target location? + elif command_byte == 0x0F: #0F codes [xxyy] + #Calls predefined scripts. + #[0F][xxyy] + #NOTE: For (some) dialogues the font needs to be loaded with the Text box&font code. + size = 3 + byte1 = ord(rom[offset+1]) + byte2 = ord(rom[offset+2]) + number = byte1 + (byte2 << 8) + command["predefined_script_number"] = number + elif command_byte == 0x10: #ASM code2 [2b] + #Call an ASM script via a 2byte pointer pointing to a 3byte pointer. + #[10][2byte pointer pointing to 3byte pointer pointing to ASM script] + size = 3 + command["pointer"] = calculate_pointer_from_bytes_at(start_address+1, bank=False) + #XXX should i include the 3-byte pointer at the target location? + #XXX should we dissassemble the asm at the target location? + elif command_byte == 0x11: #Trigger event check1 [xxyy] + #Check the current number of the trigger event on map (map bank/map no). + #[11][MapBank][MapNo] + size = 3 + command["map_group"] = ord(rom[start_address+1]) + command["map_id"] = ord(rom[start_address+2]) + elif command_byte == 0x12: #Activate trigger event from afar [xxyyzz] + #Changes trigger event number on map (map bank/map no) to xx. + #xx = trigger event number that should be activated + #[12][MapBank][MapNo][xx] + size = 4 + command["map_group"] = ord(rom[start_address+1]) + command["map_id"] = ord(rom[start_address+2]) + command["trigger_number"] = ord(rom[start_address+3]) + elif command_byte == 0x13: #Trigger event check + #Checks the number of the trigger events on the current map. + #[13] + size = 1 + elif command_byte == 0x14: #De-/activate trigger event [xx] + #Changes trigger event number on current map to xx. + #xx = trigger event number that should be activated + #[14][xx] + #deactivate? Just activate a different trigger event number. There's a limit of 1 active trigger. + size = 2 + command["trigger_number"] = ord(rom[start_address+1]) + elif command_byte == 0x15: #Load variable into RAM [xx] + #[15][xx] + size = 2 + command["variable"] = ord(rom[start_address+1]) + elif command_byte == 0x16: #Add variables [xx] + #Adds xx and the variable in RAM. + #[16][xx] + size = 2 + command["variable"] = ord(rom[start_address+1]) + elif command_byte == 0x17: #Random number [xx] + #Reads xx and creates a random number between 00 and xx -1. + #According to this xx can be all but 00. Random number = [00; xx) + #The nearer the random number is to xx, the rarer it occurs. + #Random number gets written to RAM. + size = 2 + command["rarest"] = ord(rom[start_address+1]) + elif command_byte == 0x18: #Version check + #Check if version is gold or silver. Gives feedback. + #00 = Gold + #01 = Silver + #[18] + size = 1 + elif command_byte == 0x19: #Copy variable code1 [xxyy] + #Writes variable from ram address to RAM. + #[19][2-byte RAM address] + size = 3 + command["pointer"] = calculate_pointer_from_bytes_at(start_address+1, bank=False) + elif command_byte == 0x1A: #Copy variable code2 [xxyy] + #Writes variable from RAM to actual RAM address. + #[1A][2-byte RAM address] + size = 3 + command["pointer"] = calculate_pointer_from_bytes_at(start_address+1, bank=False) + elif command_byte == 0x1B: #Load variable [xxyyzz] + #Writes zz to ram address. + #[1B][2-byte RAM address][zz] + size = 4 + command["pointer"] = calculate_pointer_from_bytes_at(start_address+1, bank=False) + command["value"] = ord(rom[start_address+3]) + elif command_byte == 0x1C: #Check codes [xx] + #XXX no idea what's going on in this one :( + #Checks special game-technical values and writes then into RAM. + #[1C][following part][Ram check (when <> 08/09 see „numbers“ in list of following parts)] + #following part (and then hex values) + #01 = PKMN count in party + # 00 - 06 + #02 = ??? + #03 = Battle type of wild PKMN + #04 = ??? + #05 = PokéDex caught + # 00 - FA + #06 = PokéDex seen + # 00 - FA + #07 = Badge count + # 00 - 10 + #08 = Movement + # 00 = walk + # 01 = bike + # 02 = slipping + # 04 = surfer + # 08 = surfing pikachu + #09 = HIRO direction + # 00 (d) + # 01 (u) + # 02 (l) + # 03 (r) + #0A = Time in hours + # 00 - 18 + #0B = Day + # 00 (Mo) - 06 (Su) + #0C = Map bank of current map + #0D = Map no of current map + #0E = Num. of diff. unowns seen + # 00 - 1A + #0F = Action byte of map + #10 = Amount of free spaces in pkmn box + # 00 - 14 + #11 = Minutes until end bug contest + # 00 - 14 + #12 = X position of HIRO + #13 = Y position of HIRO + #14 = phone call number + size = 2 #i think? + command["following_part"] = ord(rom[start_address+1]) + elif command_byte == 0x1D: #Input code1 [xx] + #Writes variable from RAM to special game-technical value offsets. + #[1D][following part] + #where [following part] is the same as 0x1C + size = 2 + command["following_part"] = ord(rom[start_address+1]) + elif command_byte == 0x1E: #Input code2 [xxyy] + #Writes variable xx to special game-technical value offsets. + #[1E][following part][xx] + #where [following part] is the same as 0x1C + size = 3 + command["following_part"] = ord(rom[start_address+1]) + command["value"] = ord(rom[start_address+2]) + elif command_byte == 0x1F: #Give item code [xxyy] + #Gives item (item no) amount times. + #feedback: + # 00 = bag full + # 01 = OK + #[1F][item no][amount] + size = 3 + command["item_id"] = ord(rom[start_address+1]) + command["quantity"] = ord(rom[start_address+2]) + elif command_byte == 0x20: #Take item code [xxyy] + #Gives item (item no) amount times + #feedback: + # 00 = not enough items + #[20][item no][amount] + size = 3 + command["item_id"] = ord(rom[start_address+1]) + command["quantity"] = ord(rom[start_address+2]) + elif command_byte == 0x21: #Check for item code [xx] + #Checks if item is possessed. + #feedback: + # 00 = does not have item + # 01 = has item + #[21][item no] + size = 2 + command["item_id"] = ord(rom[start_address+1]) + elif command_byte == 0x22: #Give money code [xxyyzzaa] + #Gives zzyyxx money to HIRO/account. + #zzyyxx = amount of money (000000 - 0F423F) + #[22][00-HIRO/01-account][xxyyzz] + size = 5 + bytes = rom_interval(start_address, size, strings=False) + command["account"] = bytes[1] + raise NotImplementedError, "don't know if zzyyxx is a decimal or hex value" + elif command_byte == 0x23: #Take money code [xxyyzzaa] + #Takes zzyyxx money from HIRO/account. + #zzyyxx = amount of money (000000 - 0F423F) + #[23][00-HIRO/01-account][xxyyzz] + size = 5 + bytes = rom_interval(start_address, size, strings=False) + command["account"] = bytes[1] + raise NotImplementedError, "don't know if zzyyxx is a decimal or hex value" + elif command_byte == 0x24: #Check for money code [xxyyzzaa] + #Checks if HIRO/account has got zzyyxx money. + #feedback: + # 00 = enough money + # 01 = exact amount + # 02 = less money + #zzyyxx = amount of money (000000 - 0F423F) + #[24][00-HIRO/01-account][xxyyzz] + size = 5 + bytes = rom_interval(start_address, size, strings=False) + command["account"] = bytes[1] + raise NotImplementedError, "don't know if zzyyxx is a decimal or hex value" + elif command_byte == 0x25: #Give coins code [xxyy] + #Gives coins to HIRO. + #yyxx = amount of coins (0000 - 270F) + #[25][xxyy] + size = 3 + bytes = rom_interval(start_address, size, strings=False) + command["quantity"] = bytes[1] + (bytes[2] << 8) + elif command_byte == 0x26: #Take coins code [xxyy] + #Takes coins away from HIRO. + #yyxx = amount of coins (0000 - 270F) + #[26][xxyy] + size = 3 + bytes = rom_interval(start_address, size, strings=False) + command["quantity"] = bytes[1] + (bytes[2] << 8) + elif command_byte == 0x27: #Check for coins code [xxyy] + #Checks if HIRO has enough coins. + #feedback: + # 00 = has enough coins + # 01 = has exact amount + # 02 = does not have enough + #yyxx = amount of coins necessary (0000 - 270F) + #[27][xxyy] + size = 3 + bytes = rom_interval(start_address, size, strings=False) + command["quantity"] = bytes[1] + (bytes[2] << 8) + elif command_byte == 0x28: #Give cell phone number [xx] + #Gives number to HIRO. + #feedback: + # 00 = number was added successfully + # 01 = Number already added, or no memory + #xx = number of person + #[28][xx] + #01 = mother + #02 = bike store + #03 = bll + #04 = elm + size = 2 + command["number"] = ord(rom[start_address+1]) + elif command_byte == 0x29: #Take cell phone number [xx] + #Deletes a number from the list. + #feedback: + # 00 = number deleted successfully + # 01 = number wasn't in list + #xx = number of person + #[29][xx] + size = 2 + command["number"] = ord(rom[start_address+1]) + elif command_byte == 0x2A: #Check for cell phone number [xx] + #Checks if a number is in the list. + #feedback: + # 00 = number is in list + # 01 = number not in list + #xx = number to look for + #[2A][xx] + size = 2 + command["number"] = ord(rom[start_address+1]) + elif command_byte == 0x2B: #Check time of day [xx] + #Checks the time of day. + #feedback: + # 00 = time of day is the same + # 01 = time of day is not the same + #[2B][time of day (01morn-04night)] + size = 2 + command["time_of_day"] = ord(rom[start_address+1]) + elif command_byte == 0x2C: #Check for PKMN [xx] + #Checks if there is a certain PKMN in team. + #feedback: + # 00 = in team + # 01 = not in team + #xx = pkmn id + #[2C][xx] + size = 2 + command["pokemon_id"] = ord(rom[start_address+1]) + elif command_byte == 0x2D: #Give PKMN [xxyyzzaa(+2b +2b)] + #Gives a PKMN if there's space + #feedback: + # trainer id + #[2D][PKMN][PKMNlvl][PKMNitem][TRAINER] + #trainer: + # 00 = HIRO + # 01 = after the main code there are 4 bytes added + # [2byte pointer to trainer's name (max.0x0A figures + 0x50)][2byte pointer to nickname (max.0x0A figures + 0x50)] + size = 5 + bytes = rom_interval(start_address, size, strings=False) + command["pokemon_id"] = bytes[1] + command["pokemon_level"] = bytes[2] + command["held_item_id"] = bytes[3] + command["trainer"] = bytes[4] + if command["trainer"] == 0x01: + size += 4 + bytes = rom_interval(start_address, size, strings=False) + command["trainer_name_pointer"] = calculate_pointer_from_bytes_at(start_address+5, bank=False) + command["pokemon_nickname_pointer"] = calculate_pointer_from_bytes_at(start_address+7, bank=False) + elif command_byte == 0x2E: #Give EGG [xxyy] + #Gives egg if there's space. + #feedback: + # 00 = OK + # 02 = transaction not complete + #[2E][PKMN][PKMNlvl] + size = 3 + command["pokemon_id"] = ord(rom[start_address+1]) + command["pokemon_level"] = ord(rom[start_address+2]) + elif command_byte == 0x2F: #Attach item code [2B] + #Gives last PKMN in list an item and letter text if applicable. Replaces existing items. + #[2F][2byte pointer to item no + 0x20 bytes letter text] + size = 3 + command["item_pointer"] = calculate_pointer_from_bytes_at(start_address+1, bank=False) + #XXX are those 20 bytes supposed to happen here? or at the pointer's destination? + elif command_byte == 0x30: #Check letter code [2b] + #Opens a PKMN list. Selected PKMN must have the right letter + the right contents. If OK, then PKMN is taken away + #feedback: + # 00 = wrong letter + # 01 = OK + # 02 = Cancelled + # 03 = Chosen PKMN has no letter + # 04 = Chosen PKMN is the only one in the list. + #[30][2byte pointer to letter item no + 0x20 bytes letter text] + size = 3 + command["item_pointer"] = calculate_pointer_from_bytes_at(start_address+1, bank=False) + elif command_byte == 0x31: #BitTable1 check [xxyy] + #Checks whether a bit of BitTable1 has the value 0 or 1. + #feedback: + # 00 = value 0 (off) + # 01 = value 1 (on) + #[31][2-byte bit number] + #XXX what format is the 2-byte number in? + size = 3 + bytes = rom_interval(start_address+1, size-1, strings=False) + command["bit_number_bytes"] = bytes + #raise NotImplementedError, "what format is the 2-byte number in?" + elif command_byte == 0x32: #BitTable1 reset [xxyy] + #Sets a bit of BitTable1 to value 0. + #[32][Bit no (2byte)] + size = 3 + bytes = rom_interval(start_address+1, size-1, strings=False) + command["bit_number_bytes"] = bytes + elif command_byte == 0x33: #BitTable1 set [xxyy] + #Sets a bit of BitTable1 to value 1. + #[33][Bit-No (2byte)] + size = 3 + bytes = rom_interval(start_address+1, size-1, strings=False) + command["bit_number_bytes"] = bytes + elif command_byte == 0x34: #BitTable2 check [xxyy] + #Checks whether a bit of BitTable2 has the value 0 or 1. + #feedback: + # 00 = value 0 (off) + # 01 = value 1 (on) + #[34][Bit no (2byte)] + size = 3 + bytes = rom_interval(start_address+1, size-1, strings=False) + command["bit_number_bytes"] = bytes + elif command_byte == 0x35: #BitTable2 reset [xxyy] + #Sets a bit of BitTable2 to value 0. + #[35][Bit no (2byte)] + size = 3 + bytes = rom_interval(start_address+1, size-1, strings=False) + command["bit_number_bytes"] = bytes + elif command_byte == 0x36: #BitTable2 set [xxyy] + #Sets a bit of BitTable2 to value 1. + #[36][Bit no (2byte)] + size = 3 + bytes = rom_interval(start_address+1, size-1, strings=False) + command["bit_number_bytes"] = bytes + elif command_byte == 0x37: #Deactivate PKMN battles + #This code turns all wild PKMN battles off. + #[37] + size = 1 + elif command_byte == 0x38: #Activate PKMN battles + #This code turns all wild PKMN battles on. + size = 1 + elif command_byte == 0x39: #X/Y comparison [xxyy] + #This code is buggy (Bug fix: 0x3021 --> C6) and can't used as + #described without fix. This code compares the X and Y coordinates of + #HIRO with the ones in a table (max. 20h XY pairs) on the current map. + #It sets or resets the 4 bytes D17C to D17F accordingly to this table, + #1 bit for every table entry. To be useful, this code can only be used + #in a command queue, because with every regular move of HIRO the bits + #are reset again. This code is an alternative to the trigger events and + #can be used via the command queue code. + size = 3 + command["table_pointer"] = rom_interval(start_address+1, size-1, strings=False) + #See Write command queue, Additional documentation: 3:4661 with c= index in table (start=00), hl=D171, b=01, d=00. + elif command_byte == 0x3A: #Warp modifier [xxyyzz] + #Changes warp data for all warps of the current map that have a 0xFF for warp-to data. + #[3A][Nee warp-to][New map bank][New map no] + size = 4 + bytes = rom_interval(start_address+1, size-1, strings=False) + command["nee_warp_to"] = bytes[0] + command["map_group"] = bytes[1] + command["map_id"] = bytes[2] + elif command_byte == 0x3B: #Blackout modifier [xxyy] + #Changes the map HIRO arrives at, after having a blackout. + #There needs to be flying data for that map. + #[3B][Map bank][Map no] + size = 3 + command["map_group"] = ord(rom[start_address+1]) + command["map_id"] = ord(rom[start_address+2]) + elif command_byte == 0x3C: #Warp code [xxyyzzaa] + #Warps to another map. + #If all data is 00s, then the current map is reloaded with + #the current X and Y coordinates. Old script is not finished + #without a [90]. + #[3C][Map bank][Map no][X][Y] + size = 5 + command["map_group"] = ord(rom[start_address+1]) + command["map_id"] = ord(rom[start_address+2]) + command["x"] = ord(rom[start_address+3]) + command["y"] = ord(rom[start_address+4]) + elif command_byte == 0x3D: #Account code [xxyy] + #Reads amount of money in accounts of HIRO and mother and writes + #it to MEMORY1, 2 or 3 for later use in text. + #[3D][00 = HIRO| <> 00 = Mother][00-02 MEMORY] + #see http://hax.iimarck.us/files/scriptingcodes_eng.htm#InText01 + size = 3 + command["account_id"] = ord(rom[start_address+1]) + command["memory_id"] = ord(rom[start_address+2]) + elif command_byte == 0x3E: #Coin case code [xx] + #Reads amount of coins in coin case and writes it to MEMORY 1, 2, + #or 3 for later use in text. + #[3E][00-02 MEMORY] + size = 2 + command["memory_id"] = ord(rom[start_address+1]) + elif command_byte == 0x3F: #Display RAM [xx] + #Reads RAM value and writes it to MEMORY1, 2 or 3 for later use in text. + #[3F][00-02 MEMORY] + size = 2 + command["memory_id"] = ord(rom[start_address+1]) + elif command_byte == 0x40: #Display pokémon name [xxyy] + #Writes PokéMon name to MEMORY1, 2 or 3 for later use in text. + #[40][PKMN no][00-02 MEMORY] + size = 3 + command["map_id"] = ord(rom[start_address+1]) + command["memory_id"] = ord(rom[start_address+2]) + elif command_byte == 0x41: #Display item name [xxyy] + #Writes item name to MEMORY1, 2 or 3 for later use in text. + #[41][Item no][00-02 MEMORY] + size = 3 + command["item_id"] = ord(rom[start_address+1]) + command["memory_id"] = ord(rom[start_address+2]) + elif command_byte == 0x42: #Display location name [xx] + #Writes current location's name to MEMORY1, 2 or 3 for later use in text. + #[42][00-02 MEMORY] + size = 2 + command["memory_id"] = ord(rom[start_address+1]) + elif command_byte == 0x43: #Display trainer name [xxyyzz] + #Writes trainer name to MEMORY1, 2 or 3 for later use in text. + #[43][Trainer number][Trainer group][00-02 MEMORY] + size = 4 + command["trainer_id"] = ord(rom[start_address+1]) + command["trainer_group"] = ord(rom[start_address+2]) + command["memory_id"] = ord(rom[start_address+3]) + elif command_byte == 0x44: #Display strings [2b + xx] + #Writes string to MEMORY1, 2 or 3 for later use in text. + #[44][2byte pointer to string (max. 0x0C figures + 0x50)][00-02 MEMORY] + #See 0C codes: 0C2900, 0C2A00, 0C1B00, 0C2200, Usage of variable strings in text. + size = 4 + command["pointer"] = calculate_pointer_from_bytes_at(start_address+1, bank=False) + command["memory_id"] = ord(rom[start_address+3]) + elif command_byte == 0x45: #Stow away item code + #Text box: "HIRO put the ITEMNAME in the ITEMPOCKET." + #The item number has to have been loaded beforehand + #(e.g. by Give item code). + size = 1 + elif command_byte == 0x46: #Full item pocket code + #Text box: "ITEMPOCKET is full..." The item number has to have + #been loaded beforehand (e.g. by Give item code). + size = 1 + elif command_byte == 0x47: #Text box&font code + #Loads the font into the ram and opens a text box. + size = 1 + elif command_byte == 0x48: #Refresh code [xx] + #Executes a complete screen refresh. + #[48][xx] + #xx is a dummy byte + size = 2 + command["dummy"] = ord(rom[start_address+1]) + elif command_byte == 0x49: #Load moving sprites + #Loads moving sprites for person events into ram. + size = 1 + elif command_byte == 0x4A: #Load byte to C1CE [xx] + #Loads a byte to C1CE. Seems to have no function in the game. + #[4A][Byte] + command["byte"] = ord(rom[start_address+1]) + elif command_byte == 0x4B: #Display text [3b] + #Opens a text box and writes text. Doesn't load font. + #[4B][Text bank][2byte text pointer] + size = 4 + command["text_group"] = ord(rom[start_address+1]) + command["pointer"] = calculate_pointer_from_bytes_at(start_address+1, bank=True) + elif command_byte == 0x4C: #Display text [2b] + #Opens a text box and writes text. Doesn't load font. + #[4C][2byte text pointer] + size = 3 + command["pointer"] = calculate_pointer_from_bytes_at(start_address+1, bank=False) + elif command_byte == 0x4D: #Repeat text [xxyy] + #Opens a text box and writes the text written latest resp. whose address was put statically to D175-D177. + #Doesn't load font. + #[4D][FF][FF] + #Without FF for both bytes, no operation occurs + size = 3 + command["bytes"] = rom_interval(start_address+1, 2, strings=False) + elif command_byte == 0x4E: #YES/No box + #Displays a YES/NO box at X0F/Y07 + #feedback: + # 00 = no + # 01 = yes + size = 1 + elif command_byte == 0x4F: #Menu data code [2b] + #Loads data for menus + #[4F][2byte pointer to menu data] + #see http://hax.iimarck.us/files/scriptingcodes_eng.htm#ZusatzDatA4F + size = 3 + command["menu_pointer"] = calculate_pointer_from_bytes_at(start_address+1, bank=False) + elif command_byte == 0x50: #Write backup code + #Writes backup of parts of the screen the box was overlapping. + size = 1 + elif command_byte == 0x51: #Text1 code [2b] + #Displays a text and lets person turn to HIRO. + #Afterwards there is no other script interpreted. + #Corresponds to 6A + 47 + 4C + 53 + 49 + 90 + #[51][2byte textpointer] + size = 3 + command["text_pointer"] = calculate_pointer_from_bytes_at(start_address+1, bank=False) + elif command_byte == 0x52: #Text2 code [2b] + #Displays a text. Afterwards there is no other script interpreted. + #Corresponds to 47 + 4C + 53 + 49 + 90 + #[52][2byte textpointer] + size = 3 + command["text_pointer"] = calculate_pointer_from_bytes_at(start_address+1, bank=False) + elif command_byte == 0x53: #Close text box code + #Closes a text box which was opened by 47 resp. 4B/4C/4D. + size = 1 + elif command_byte == 0x54: #Keep text box open code + #Keeps a text box open which was opened by 47 resp. 4B/4C/4D. + size = 1 + elif command_byte == 0x55: #Pokémon picture code [xx] + #Opens a box and puts a Pokémon picture into it. + #[55][xx] + #xx: + # <>00 : Pokémon no + # =00 : Pokémon no gets read from RAM + size = 2 + command["byte"] = ord(rom[start_address+1]) + elif command_byte == 0x56: #Pokémon picture YES/NO code + #Displays a YES/NO box at X08/Y05. + #feedback: + # 00 = no chosen + # 01 = yes chosen + size = 1 + elif command_byte == 0x57: #Menu interpreter 1 + #Interprets menu data loaded by 4F. + #see also http://hax.iimarck.us/files/scriptingcodes_eng.htm#ZusatzDatA57 + size = 1 + elif command_byte == 0x58: #Menu interpreter 2 + #Interprets menu data loaded by 4F. + #see also http://hax.iimarck.us/files/scriptingcodes_eng.htm#Marke57 + #see also http://hax.iimarck.us/files/scriptingcodes_eng.htm#ZusatzDatA58 + size = 1 + elif command_byte == 0x59: #Load Pikachu data + #Loads 0x19 (Pikachu) to PokéRAM and level 5 to LevelRAM. + size = 1 + elif command_byte == 0x5A: #Delete FightRAM/reset person check + #Deletes the value in BattleRAM. + #Turns off the check if the battle was started by entering + #a trainer's area of view. + size = 1 + elif command_byte == 0x5B: #Load trainer data1 + #Loads trainer data when HIRO is in a trainer's range of sight. + #Trainer group is read from CF2E and written to + #TrRAM1, the trainer number is read from CF2F and written to + #TrRAM2. 81 is written to BattleRAM. + size = 1 + elif command_byte == 0x5C: #Load Pokémon data [xxyy] + #Loads Pokémon data. Writes 80 to BattleRAM. + #[5C][Poke no][Level] + size = 3 + command["pokemon_id"] = ord(rom[start_address+1]) + command["pokemon_level"] = ord(rom[start_address+2]) + elif command_byte == 0x5D: #Load trainer data2 [xxyy] + #Loads trainer data. Trainer group --> TrRAM1, + #trainer number --> TrRAM2. Writes 81 to BattleRAM. + #[5D][Trainer group][Trainer no] + size = 3 + command["trainer_group"] = ord(rom[start_address+1]) + command["trainer_id"] = ord(rom[start_address+2]) + elif command_byte == 0x5E: #Start battle + #Starts trainer or Pokémon battle. BattleRAM: 80 = Poké battle; 81 = Trainer battle. + #feedback: + # 00 = win + # 01 = lose + size = 1 + elif command_byte == 0x5F: #Return to In game engine after battle + #Returns to ingame engine and evaluates battle. When lost then return to last Pokémon Center etc. + size = 1 + elif command_byte == 0x60: #Learn how to catch PKMN [xx] + #Starts a learn-how-to-catch battle with a Pokémon, whose data needs to be loaded beforehand + #see http://hax.iimarck.us/files/scriptingcodes_eng.htm#Marke5C + #Player has to have at least 1 Pokémon for it to work. + #Items that are statically used: 1xPotion, 5xPoké ball. + #[60][xx] + #xx: Between 01 and 03. If <> 03 then HIRO sprite instead of dude sprite and kills + #itself when using the item system. + size = 2 + command["byte"] = ord(rom[start_address+1]) + elif command_byte == 0x61: #Trainer text code + #Interprets the data of a in the event structure defined trainer. Xx decides which text to use. + #see http://hax.iimarck.us/files/scriptingcodes_eng.htm#Eventaufbau + #[61][xx] + #xx: Between 00 and 03. + size = 2 + command["byte"] = ord(rom[start_address+1]) + elif command_byte == 0x62: #Trainer status code [xx] + #Checks/changes the status of a in the event structure defined trainer. + #see http://hax.iimarck.us/files/scriptingcodes_eng.htm#Eventaufbau + #[62][xx] + #xx is: + # 00 = deactivate + # 01 = activate + # 02 = check + size = 2 + command["byte"] = ord(rom[start_address+1]) + elif command_byte == 0x63: #Pointer Win/Loss [2b + 2b] + #Writes the win/loss pointer of a battle into the ram. + #[63][2byte pointer to text Win][2byte pointer to text Loss*] + #* When pointer = 0000 then "Blackout" instead of return to gameplay. + size = 5 + command["won_pointer"] = calculate_pointer_from_bytes_at(start_address+1, bank=False) + command["lost_pointer"] = calculate_pointer_from_bytes_at(start_address+3, bank=False) + elif command_byte == 0x64: #Script talk-after + #Interprets which script is going to be run, when a in the event-structure-defined + #trainer is talked to again. + #see http://hax.iimarck.us/files/scriptingcodes_eng.htm#Eventaufbau + #[64] + size = 1 + elif command_byte == 0x65: #Script talk-after-cancel + #Cancels the talk-after script of the in the event-structure-defined + #trainer when talk-after script is executed just after the battle. + #[65] + size = 1 + elif command_byte == 0x66: #Script talk-after-check + #Checks if the talk-after script of the event structure defined trainer + #is executed just after the battle or at a later point in time. + #feedback: + # 00 = no + # 01 = yes + #[66] + size = 1 + elif command_byte == 0x67: #Set talked-to person [xx] + #Sets the number of the last person talked to. + #[67][person] + size = 2 + command["person_id"] = ord(rom[start_address+1]) + elif command_byte == 0x68: #Moving code [xx + 2b] + #Moves the person using moving data. + #[68][Person][2byte pointer to moving data] + #see also http://hax.iimarck.us/files/scriptingcodes_eng.htm#ZusatzB68bis69 + size = 4 + command["person_id"] = ord(rom[start_address+1]) + command["moving_data_pointer"] = calculate_pointer_from_bytes_at(start_address+2, bank=False) + elif command_byte == 0x69: #Moving code for talked-to person [2b] + #Moves talked-to person using moving data. + #[69][2byte pointer to moving data] + size = 3 + command["moving_data_pointer"] = calculate_pointer_from_bytes_at(start_address+1, bank=False) + elif command_byte == 0x6A: #Talk-to facing code + #Turns the heads of the talked-to persons to HIRO. + #[6A] + size = 1 + elif command_byte == 0x6B: #Facing of people code [xxyy] + #Turns the head of person1 to another person2. + #[6B][Person2][Person1] + #Person2 = If number is greater than 0xFD, then use number of talked-to person. + #Person1 = If number equals 0xFE, then take number of talked-to person. + size = 3 + command["person2_id"] = ord(rom[start_address+1]) + command["person1_id"] = ord(rom[start_address+2]) + elif command_byte == 0x6C: #Variable sprites [xxyy] + #Writes a number to the variable sprite RAM from D555 to D564 (see Compendium on the sprite system). + #[6C][xx][Sprite no] + #xx: Number between 0x00 and 0x0F + size = 3 + command["number"] = ord(rom[start_address+1]) + command["sprite_id"] = ord(rom[start_address+2]) + elif command_byte == 0x6D: #Hide person [xx] + #Hides a person. + #[6D][person id] + size = 2 + command["person_id"] = ord(rom[start_address+1]) + elif command_byte == 0x6E: #Show person [xx] + #Shows a hidden person again. + #[6E][person id] + size = 2 + command["person_id"] = ord(rom[start_address+1]) + elif command_byte == 0x6F: #Following code1 [xxyy] + #A person1 follows another person2. The person1 that follows + #just repeats the movement of person2, even if the persons are + #not directly next to each other. + #[6F][Leader Person2][Follower Person1] + size = 3 + command["leader_person_id"] = ord(rom[start_address+1]) + command["follower_person_id"] = ord(rom[start_address+2]) + elif command_byte == 0x70: #Stop following code + #Ends all current follow codes. + size = 1 + elif command_byte == 0x71: #Move person [xxyyzz] + #Sets the X/Y values of a person anew. + #The person doesn't get shown immediately. Use hide&show. + #[71][Person][X][Y] + size = 4 + command["person_id"] = ord(rom[start_address+1]) + command["x"] = ord(rom[start_address+2]) + command["y"] = ord(rom[start_address+3]) + elif command_byte == 0x72: #Write person location [xx] (lock person location?) + #Writes the current X/Y values of a person into the ram. + #The person is going to stand at its current location even when + #it's out of HIRO's sight and is not going to return to its old + #location until the next map load. + #[72][person] + size = 2 + command["person_id"] = ord(rom[start_address+1]) + elif command_byte == 0x73: #Load emoticons [xx] + #Loads the emoticon bubble depending on the given bubble number. + #[73][bubble number] + #xx: If xx = FF then take number from RAM. + #00 = Exclamation mark + #01 = Question mark + #02 = Happy + #03 = Sad + #04 = Heart + #05 = Flash + #06 = Snoring + #07 = Fish + size = 2 + command["bubble_number"] = ord(rom[start_address+1]) + elif command_byte == 0x74: #Display emoticon [xxyyzz] + #Displays the bubble above a persons head for the given time period. + #Attention: Bubbles get loaded into ram! + #[74][Bubble][Person][Time] + #for bubble ids see 0x73 + size = 4 + command["bubble_number"] = ord(rom[start_address+1]) + command["person_id"] = ord(rom[start_address+2]) + command["time"] = ord(rom[start_address+3]) + elif command_byte == 0x75: #Change facing [xxyy] + #Changes the facing direction of a person. + #[75][person][facing] + size = 3 + command["person_id"] = ord(rom[start_address+1]) + command["facing"] = ord(rom[start_address+2]) + elif command_byte == 0x76: #Following code2 [xxyy] + #A person1 follows a person2. The following person1 automatically clings to person2. + #Person1 just follows person2, but doesn't make the exact same movements at person2. + #[76][Leader Person2][Follower Person1] + size = 3 + command["leader_person_id"] = ord(rom[start_address+1]) + command["follower_person_id"] = ord(rom[start_address+2]) + elif command_byte == 0x77: #Earth quake [xx] + #The screen shakes. xx gives time as well as displacement of the screen. + #[77][xx] + size = 2 + command["shake_byte"] = ord(rom[start_address+1]) + elif command_byte == 0x78: #Exchange map [3b] + #This code draws another whole map as wide and high as the + #current map over the current map. + #The 3byte pointer points to the new map. + #[78][3byte pointer to new map data] + size = 4 + command["map_data_pointer"] = calculate_pointer_from_bytes_at(start_address+1, bank=True) + elif command_byte == 0x79: #Change block code [xxyyzz] + #Changes a block on the current map by giving the new block + #number and its X/Y values measured in half-blocks. + #[79][X][Y][Block] + size = 4 + command["x"] = ord(rom[start_address+1]) + command["y"] = ord(rom[start_address+2]) + command["block"] = ord(rom[start_address+3]) + elif command_byte == 0x7A: #Reload map code + #Reloads and re-displays the map completely. + #Loads tileset and all map data anew. Screen gets light. + #[7A] + size = 1 + elif command_byte == 0x7B: #Reload map part code + #Reloads and re-displays the part of the map HIRO is on, + #without reloading any other map data or the tileset. + #[7B] + size = 1 + elif command_byte == 0x7C: #Write command queue + #Writes a command queue to the next free slot in ram. + #Max 4 command queues à 5 bytes. This code is buggy (bug fix: 25:7C74 --> 12). + #[7C][2byte pointer to 5byte command queue] + #see http://hax.iimarck.us/files/scriptingcodes_eng.htm#ZusatzDok25_7CC9 + size = 3 + command["command_queue_pointer"] = calculate_pointer_from_bytes_at(start_address+1, bank=False) + elif command_byte == 0x7D: #Delete command queue + #Deletes a command queue and frees a slot in ram. + #[7D][First command of the resp. queue] + #XXX wtf? + size = 2 + command["first_command"] = ord(rom[start_address+1]) + elif command_byte == 0x7E: #Song code1 [xxyy] + #Immediately plays the music. + #[7E][Music no (2byte)] + #Music no: See the music archive that should accompany + #this document Thanks to Filb. He dumped all the songs + #via gameboy player and gave them to me. + size = 3 + #XXX what is the format of this music data? + command["music_number"] = rom_interval(start_address+1, size-1, strings=False) + elif command_byte == 0x7F: #Song code2 + #Plays the music of the trainer group in TrRAM1. + #Takes music numbers from list at 3A:5027. + #[7F] + size = 1 + elif command_byte == 0x80: #Music fade-out code [xxyy][zz] + #The current music is faded out and the new music is played afterwards. + #[80][Music no (2byte)][Time to fade out (00-7F)] + size = 4 + command["music_number"] = rom_interval(start_address+1, 2, strings=False) + command["fade_time"] = ord(rom[start_address+3]) + elif command_byte == 0x81: #Play map music code + #Starts playing the original map music. + #Includes special check for surfer and bug contest song. + #[81] + size = 1 + elif command_byte == 0x82: #Map reload music code + #After a map reload no music is played. + #[82] + size = 1 + elif command_byte == 0x83: #Cry code [xx00] + #Plays the Pokémon's cry. + #[83][Cry no][00] + #If the cry no = 00 then the number is taken from RAM. + size = 3 + command["cry_number"] = ord(rom[start_address+1]) + command["other_byte"] = ord(rom[start_address+2]) + elif command_byte == 0x84: #Sound code [xxyy] + #Plays the sound. + #[84][Sound no (2byte)] + #Sound no: See the music archive that should accompany this document + #Thanks to philb for this matter. He helped me to record a big + #part of these sounds. + size = 3 + command["sound_number"] = rom_interval(start_address+1, 2, strings=False) + elif command_byte == 0x85: #Key-down code + #Waits for the Player to press a button. + #[85] + size = 1 + elif command_byte == 0x86: #Warp sound + #Evaluates which sound is played when HIRO enters a Warp field. + #Usage via script ingame is rather not useful. + #[86] + size = 1 + elif command_byte == 0x87: #Special sound + #When last given/checked Item was a TM then it plays sound 0x9B. If not, then 0x01. + #[87] + size = 1 + elif command_byte == 0x88: #Engine remote control [2b] + #This code controls the engine via "data stream". + #[88][3byte pointer to control structure] + #see http://hax.iimarck.us/files/scriptingcodes_eng.htm#ZusatzDatA88 + size = 4 + command["data_stream_pointer"] = calculate_pointer_from_bytes_at(start_address+1, bank=True) + elif command_byte == 0x89: #Load map anew [xx] + #The number decides which map loading process is used. + #The number must be 0xF0 + process number to work correctly. + #[89][Number] + #see map loading process: + # http://hax.iimarck.us/files/scriptingcodes_eng.htm#ZusatzDok5_5550 + size = 2 + command["number"] = ord(rom[start_address+1]) + elif command_byte == 0x8A: #Waiting code [xx] + #This code lets the game wait for 2 * xx time intervals. + #[8A][xx] + #xx: Numbers from 0x01 to 0xFF. + #If 0x00 is chosen then the time can be manipulated by previously loading a number to RAM2. + size = 2 + command["time"] = ord(rom[start_address+1]) + elif command_byte == 0x8B: #Deactivate static facing [xx] + #Deactivates static facings on all persons on the screen after a time xx. + #[8B][xx] + size = 2 + command["time"] = ord(rom[start_address+1]) + elif command_byte == 0x8C: #Priority jump1 [2b] + #The pointer acts like code 00, but with this higher + #functions like the bike etc. are not paid attention to, + #while the script is running. + #[8C][2byte pointer to script] + size = 3 + command["script_pointer"] = calculate_pointer_from_bytes_at(start_address+1, bank=False) + elif command_byte == 0x8D: #Warp check + #If HIRO is entering or leaving a warp then this code reactivates all the engine-checks. + #[8D] + size = 1 + elif command_byte == 0x8E: #Priority jump2 [2b] + #The pointer acts like code 03, but with this code all + #higher functions wait for a cycle before the script gets interpreted. + #[8E][2byte pointer to script] + size = 3 + command["script_pointer"] = calculate_pointer_from_bytes_at(start_address+1, bank=False) + elif command_byte == 0x8F: #Return code1 + #Ends the current script and loads the backup offset for "linked" + #scripts if applicable. The sophisticated functions are not affected + #and run like before the code. This code is mostly used for scripts + #called by the 2nd part of the script header, because else malfunctions + #occur. + #[8F] + size = 1 + end = True + elif command_byte == 0x90: #Return code2 + #Ends the current script and loads the backup offset for "linked" + #scripts if applicable. The sophisticated functions get reset if + #no backup offset was loaded. This code is used to end most scripts. + #[90] + size = 1 + end = True + elif command_byte == 0x91: #Return code3 + #Reloads the map completely like the code 0x7A + #and else acts completely like Return code2 + #[91] + #see reload map code + # http://hax.iimarck.us/files/scriptingcodes_eng.htm#Marke7A + #see 0x90 + size = 1 + #XXX does this end the script?? "else acts like 0x90" + # else? what's the "if"? + end = True + elif command_byte == 0x92: #Reset sophisticated functions + #Resets all sophisticated functions to 0. + #[92] + size = 1 + elif command_byte == 0x93: #Mart menu [xxyyzz] + #Displays a whole mart menu, however, doesn't load font to ram. + #[93][Dialog no][Mart no (2byte)] + #see http://hax.iimarck.us/files/scriptingcodes_eng.htm#AwBsp93 + #see http://hax.iimarck.us/files/scriptingcodes_eng.htm#ZusatzB93 + size = 4 + command["dialog_number"] = ord(rom[start_address+1]) + command["mart_number"] = rom_interval(start_address+2, 2, strings=False) + elif command_byte == 0x94: #Elevator menu [2b] + #Displays a whole elevator menu, but it doesn't load font to ram. + #Only works with warps with warp-to = 0xFF. + #[94][2byte pointer to floor list] + size = 3 + command["floor_list_pointer"] = calculate_pointer_from_bytes_at(start_address+1, bank=False) + elif command_byte == 0x95: #Trade menu [xx] + #Displays a whole trade menu, but it doesn't load font to ram. + #[95][trade no] + #see http://hax.iimarck.us/files/scriptingcodes_eng.htm#ZusatzDokTausch + size = 2 + command["trade_number"] = ord(rom[start_address+1]) + elif command_byte == 0x96: #Give cell phone number with YES/NO [xx] + #Gives a telephone number but asks for decision beforehand. + #feedback: + # 00 = ok chosen + # 01 = Cell phone number already registered/Memory full + # 02 = no chosen + #[96][Cell phone number] + size = 2 + #maybe this next param should be called "phone_number" + command["number"] = ord(rom[start_address+1]) + elif command_byte == 0x97: #Call code [2b] + #Displays the upper cell phone box and displays a freely selectable name. + #[97][2byte pointer to name of caller] + size = 3 + command["caller_name_pointer"] = calculate_pointer_from_bytes_at(start_address+1, bank=False) + elif command_byte == 0x98: #Hang-up code + #Simulates the hanging-up. + #[98] + size = 1 + elif command_byte == 0x99: #Decoration code [xx] + #Displays monologues according to the selected ornament. + #[99][xx] + #xx values: + # 00 = Map/Poster + # 01 = Ornament left + # 02 = Ornament right + # 03 = Huge doll + # 04 = Console + size = 2 + command["ornament"] = ord(rom[start_address+1]) + elif command_byte == 0x9A: #Berry tree code [xx] + #Creates a typical berry tree monologue. + #There is a maximum of 32 berry trees in the game. + #After this code the script ends. + #[9A][Fruit tree number] + #Fruit tree number + 11:4091 is the offset where the item no of the berry is defined. + size = 2 + end = True + command["tree_id"] = ord(rom[start_address+1]) + elif command_byte == 0x9B: #Cell phone call code [xx00] + #Initiates with the next step on a outer world map (permission byte) a phone call. + #[9B][Call no][00] + #call no: + # 01 = PokéRus + # 02 = Pokémon stolen + # 03 = Egg examined/ Assistant in Viola City + # 04 = Team Rocket on the radio + # 05 = PROF. ELM has got something for HIRO + # 06 = Bike shop gives bike away + # 07 = Mother is unhappy that HIRO didn't talk to her before leaving + # 08 = PROF. ELM has got something for HIRO a second time + size = 3 + command["call_id"] = ord(rom[start_address+1]) + command["byte"] = ord(rom[start_address+2]) + elif command_byte == 0x9C: #Check cell phone call code + #Checks if a phone call is "in the line". + #feedback: + # 00 = no + # <>00 = call number + #[9C] + size = 1 + elif command_byte == 0x9D: #Commented give item code [xxyy] + #The same as 0x1F but this code comments where + #HIRO puts what item in a short monologue. + #[9D][Item][Amount] + size = 3 + command["item_id"] = ord(rom[start_address+1]) + command["quantity"] = ord[rom[start_address+2]) + elif command_byte == 0x9E: #Load special wild PKMN data [xxyy] + #Activates the checks in the special tables for the wild pokémon data. + #[9E][Mapbank][Map no] + #see also http://hax.iimarck.us/files/scriptingcodes_eng.htm#ZusatzDok3E_66ED + size = 3 + command["map_group"] = ord(rom[start_address+1]) + command["map_id"] = ord(rom[start_address+2]) + elif command_byte == 0x9F: #Hall of Fame code + #Saves and enters HIRO's complete Team in the Hall of Fame. + #Shows the credits and restarts the game with HIRO located in New Bark Town. + #[9F] + size = 1 + elif command_byte == 0xA0: #Credits code + #Shows the credits and HIRO is located on the Silver mountain plateau. + #[A0] + size = 1 + elif command_byte == 0xA1: #Facing warp + #Acts like code 0x3C but defines the desired facing of HIRO. + #[A1][Facing (00-03)][Map bank][Map no][X][Y] + size = 6 + command["facing"] = ord(rom[start_address+1]) + command["map_group"] = ord(rom[start_address+2]) + command["map_id"] = ord(rom[start_addresss+3]) + command["x"] = ord(rom[start_address+4]) + command["y"] = ord(rom[start_address+5]) + elif command_byte == 0xA2: #MEMORY code [2b + Bank + xx] + #MEMORY1, 2 or 3 can directly be filled with a string from + #a different rom bank. + #[A2][2byte pointer][Bank][00-02 MEMORY] + size = 5 + command["string_pointer"] = calculate_pointer_from_bytes_at(start_address+1, bank="reversed") + command["string_pointer_bank"] = ord(rom[start_address+3]) + command["memory_id"] = ord(rom[start_address+4]) + elif command_byte == 0xA3: #Display any location name [xx] + #By the location number the name of that location is written to TEMPMEMORY1. + #[A3][Location no] + size = 2 + command["location_number"] = ord(rom[start_address+1]) + #store the size of the command + command["size"] = size + #the end address is just offset + size - 1 (because size includes command byte) + offset += size - 1 + #the end address is the last byte belonging to this command + command["last_byte_address"] = offset + #we also add the size of the command byte to get to the next command + offset += 1 + #add the command into the command list please + commands[len(commands.keys())] = command + return commands + def parse_warp_bytes(some_bytes): """parse some number of warps from the data""" assert len(some_bytes) % warp_byte_size == 0, "wrong number of bytes"