ref: 2a22a91cbb639c2eeb2644e40234bcf8a18eca4b
parent: 651d8017342e9bbd9f491d8df4c84a84e86a3ee4
author: Bryan Bishop <[email protected]>
date: Sun Mar 25 21:47:58 EDT 2012
committing unfinished code (forgive me)
--- a/constants.asm
+++ b/constants.asm
@@ -528,3 +528,137 @@
ICE EQU $19
DRAGON EQU $1A
DARK EQU $1B
+
+; item constants
+MASTER_BALL EQU $01
+BRIGHTPOWDER EQU $03
+MOON_STONE EQU $08
+ANTIDOTE EQU $09
+BURN_HEAL EQU $0A
+ICE_HEAL EQU $0B
+AWAKENING EQU $0C
+PARALYZ_HEAL EQU $0D
+FULL_RESTORE EQU $0E
+MAX_POTION EQU $0F
+HYPER_POTION EQU $10
+SUPER_POTION EQU $11
+POTION EQU $12
+ESCAPE_ROPE EQU $13
+REPEL EQU $14
+MAX_ELIXER EQU $15
+FIRE_STONE EQU $16
+THUNDER_STONE EQU $17
+WATER_STONE EQU $18
+HP_UP EQU $1A
+PROTEIN EQU $1B
+IRON EQU $1C
+CARBOS EQU $1D
+LUCKY_PUNCH EQU $1E
+CALCIUM EQU $1F
+RARE_CANDY EQU $20
+X_ACCURACY EQU $21
+LEAF_STONE EQU $22
+METALPOWDER EQU $23
+NUGGET EQU $24
+POKE_DOLL EQU $25
+FULL_HEAL EQU $26
+REVIVE EQU $27
+MAX_REVIVE EQU $28
+GUARD_SPEC EQU $29
+SUPER_REPEL EQU $2A
+MAX_REPEL EQU $2B
+DIRE_HIT EQU $2C
+FRESH_WATER EQU $2E
+SODA_POP EQU $2F
+LEMONADE EQU $30
+X_ATTACK EQU $31
+X_DEFEND EQU $33
+X_SPEED EQU $34
+X_SPECIAL EQU $35
+SILVER_LEAF EQU $3C
+PP_UP EQU $3E
+ETHER EQU $3F
+MAX_ETHER EQU $40
+ELIXER EQU $41
+MOOMOO_MILK EQU $48
+QUICK_CLAW EQU $49
+PSNCUREBERRY EQU $4A
+GOLD_LEAF EQU $4B
+SOFT_SAND EQU $4C
+SHARP_BEAK EQU $4D
+PRZCUREBERRY EQU $4E
+BURNT_BERRY EQU $4F
+ICE_BERRY EQU $50
+POISON_BARB EQU $51
+KINGS_ROCK EQU $52
+BITTER_BERRY EQU $53
+MINT_BERRY EQU $54
+RED_APRICORN EQU $55
+TINY_MUSHROOM EQU $56
+BIG_MUSHROOM EQU $57
+SILVERPOWDER EQU $58
+BLU_APRICORN EQU $59
+AMULENT_COIN EQU $5B
+YLW_APRICORN EQU $5C
+GRN_APRICORN EQU $5D
+CLEANSE_TAG EQU $5E
+MYSTIC_WATER EQU $5F
+TWISTED_SPOON EQU $60
+WHT_APRICORN EQU $61
+BLACKBELT EQU $62
+BLK_APRICORN EQU $63
+PNK_APRICORN EQU $65
+BLACKGLASSES EQU $66
+SLOWPOKETAIL EQU $67
+PINK_BOW EQU $68
+STICK EQU $69
+SMOKE_BALL EQU $6A
+NEVERMELTICE EQU $6B
+MAGNET EQU $6C
+MIRACLEBERRY EQU $6D
+PEARL EQU $6E
+BIG_PEARL EQU $6F
+EVER_STONE EQU $70
+SPELL_TAG EQU $71
+RAGECANDYBAR EQU $72
+MIRACLE_SEED EQU $75
+THICK_CLUB EQU $76
+FOCUS_BAND EQU $77
+ENERGYPOWDER EQU $79
+ENERGY_ROOT EQU $7A
+HEAL_POWDER EQU $7B
+REVIVAL_HERB EQU $7C
+HARD_STONE EQU $7D
+LUCKY_EGG EQU $7E
+STARDUST EQU $83
+STAR_PIECE EQU $84
+CHARCOAL EQU $8A
+BERRYJUICE EQU $8B
+SCOPE_LENS EQU $8C
+METAL_COAT EQU $8F
+DRAGON_FANG EQU $90
+LEFTOVERS EQU $92
+MYSTERYBERRY EQU $96
+DRAGON_SCALE EQU $97
+BERSERK_GENE EQU $98
+SACRED_ASH EQU $9C
+FLOWER_MAIL EQU $9E
+LIGHT_BALL EQU $A3
+NORMAL_BOX EQU $A7
+GORGEOUS_BOX EQU $A8
+SUN_STONE EQU $A9
+POLKADOT_BOW EQU $AA
+UPGRADE EQU $AC
+BERRY EQU $AD
+GOLD_BERRY EQU $AE
+SQUIRTBOTTLE EQU $AF
+BRICK_PIECE EQU $B4
+SURF_MAIL EQU $B5
+LITEBLUEMAIL EQU $B6
+PORTRAIT_MAIL EQU $B7
+LOVELY_MAIL EQU $B8
+EON_MAIL EQU $B9
+MORPH_MAIL EQU $BA
+BLUESKY_MAIL EQU $BB
+MUSIC_MAIL EQU $BC
+MIRAGE_MAIL EQU $BD
--- a/extras/crystal.py
+++ b/extras/crystal.py
@@ -308,6 +308,20 @@
if key not in chars.keys():
chars[key] = value
+class Size():
+ """a simple way to track whether or not a size
+ includes the first value or not, like for
+ whether or not the size of a command in a script
+ also includes the command byte or not"""
+ def __init__(self, size, inclusive=False):
+ self.inclusive = inclusive
+ if inclusive: size = size-1
+ self.size = size
+ def inclusive(self):
+ return self.size + 1
+ def exclusive(self):
+ return self.size
+
class IntervalMap(object):
"""
This class maps a set of intervals to a set of values.
@@ -418,6 +432,7 @@
replace(")", "").\
replace("'", "").\
replace("/", "").\
+ replace(",", "").\
replace(".", "").\
replace("Pokémon Center", "PokeCenter").\
replace(" ", "")
@@ -457,6 +472,14 @@
returns: [[1, 2], [3, 4]]"""
return [some_list[i:i+count] for i in range(0, len(some_list), count)]
+def is_valid_address(address):
+ """is_valid_rom_address"""
+ if address == None: return False
+ if type(address) == str:
+ address = int(address, 16)
+ if 0 <= address <= 2097152: return True
+ else: return False
+
def rom_interval(offset, length, strings=True, debug=True):
"""returns hex values for the rom starting at offset until offset+length"""
global rom
@@ -1138,6 +1161,554 @@
like for 0x112110"""
return "".join([chr(x) for x in rom_interval(address, count, strings=False)])
+def get_map_constant_label(map_group=None, map_id=None):
+ """returns PALLET_TOWN for some map group/id pair"""
+ if map_group == None: raise Exception, "need map_group"
+ if map_id == None: raise Exception, "need map_id"
+ global map_internal_ids
+ for (id, each) in map_internal_ids.items():
+ if each["map_group"] == map_group and each["map_id"] == map_id:
+ return each["label"]
+ return None
+def get_map_constant_label_by_id(global_id):
+ """returns a map constant label for a particular map id"""
+ global map_internal_ids
+ return map_internal_ids[global_id]["label"]
+def get_id_for_map_constant_label(label):
+ """returns some global id for a given map constant label
+ PALLET_TOWN = 1, for instance."""
+ global map_internal_ids
+ for (id, each) in map_internal_ids.items():
+ if each["label"] == label: return id
+ return None
+def generate_map_constant_labels():
+ """generates the global for this script
+ mapping ids to map groups/ids/labels"""
+ global map_internal_ids
+ map_internal_ids = {}
+ i = 0
+ for map_group in map_names.keys():
+ for map_id in map_names[map_group].keys():
+ cmap = map_names[map_group][map_id]
+ name = cmap["name"]
+ name = name.replace("Pokémon Center", "PokeCenter").\
+ replace(" ", "_")
+ constant_label = map_name_cleaner(name).upper()
+ map_internal_ids[i] = {"label": constant_label,
+ "map_id": map_id,
+ "map_group": map_group}
+ i += 1
+ return map_internal_ids
+#see generate_map_constant_labels() later
+def generate_map_constants():
+ """generates content for constants.asm
+ this will generate two macros: GROUP and MAP"""
+ global map_internal_ids
+ if map_internal_ids == None or map_internal_ids == {}:
+ generate_map_constant_labels()
+ globals, groups, maps = "", "", ""
+ for (id, each) in map_internal_ids.items():
+ groups += "GROUP_"+each["label"] + " EQU $%.2x" % (each["map_group"])
+ groups += "\n"
+ maps += "MAP_"+each["label"] + " EQU $%.2x" % (each["map_id"])
+ maps += "\n"
+ globals += each["label"] + " EQU $%.2x" % (id)
+ globals += "\n"
+ #for multi-byte constants:
+ #print each["label"] + " EQUS \"$%.2x,$%.2x\"" % (each["map_group"], each["map_id"])
+ print globals
+ print groups
+ print maps
+
+pokemon_constants = {
+1: "BULBASAUR",
+2: "IVYSAUR",
+3: "VENUSAUR",
+4: "CHARMANDER",
+5: "CHARMELEON",
+6: "CHARIZARD",
+7: "SQUIRTLE",
+8: "WARTORTLE",
+9: "BLASTOISE",
+10: "CATERPIE",
+11: "METAPOD",
+12: "BUTTERFREE",
+13: "WEEDLE",
+14: "KAKUNA",
+15: "BEEDRILL",
+16: "PIDGEY",
+17: "PIDGEOTTO",
+18: "PIDGEOT",
+19: "RATTATA",
+20: "RATICATE",
+21: "SPEAROW",
+22: "FEAROW",
+23: "EKANS",
+24: "ARBOK",
+25: "PIKACHU",
+26: "RAICHU",
+27: "SANDSHREW",
+28: "SANDSLASH",
+29: "NIDORAN_F",
+30: "NIDORINA",
+31: "NIDOQUEEN",
+32: "NIDORAN_M",
+33: "NIDORINO",
+34: "NIDOKING",
+35: "CLEFAIRY",
+36: "CLEFABLE",
+37: "VULPIX",
+38: "NINETALES",
+39: "JIGGLYPUFF",
+40: "WIGGLYTUFF",
+41: "ZUBAT",
+42: "GOLBAT",
+43: "ODDISH",
+44: "GLOOM",
+45: "VILEPLUME",
+46: "PARAS",
+47: "PARASECT",
+48: "VENONAT",
+49: "VENOMOTH",
+50: "DIGLETT",
+51: "DUGTRIO",
+52: "MEOWTH",
+53: "PERSIAN",
+54: "PSYDUCK",
+55: "GOLDUCK",
+56: "MANKEY",
+57: "PRIMEAPE",
+58: "GROWLITHE",
+59: "ARCANINE",
+60: "POLIWAG",
+61: "POLIWHIRL",
+62: "POLIWRATH",
+63: "ABRA",
+64: "KADABRA",
+65: "ALAKAZAM",
+66: "MACHOP",
+67: "MACHOKE",
+68: "MACHAMP",
+69: "BELLSPROUT",
+70: "WEEPINBELL",
+71: "VICTREEBEL",
+72: "TENTACOOL",
+73: "TENTACRUEL",
+74: "GEODUDE",
+75: "GRAVELER",
+76: "GOLEM",
+77: "PONYTA",
+78: "RAPIDASH",
+79: "SLOWPOKE",
+80: "SLOWBRO",
+81: "MAGNEMITE",
+82: "MAGNETON",
+83: "FARFETCH_D",
+84: "DODUO",
+85: "DODRIO",
+86: "SEEL",
+87: "DEWGONG",
+88: "GRIMER",
+89: "MUK",
+90: "SHELLDER",
+91: "CLOYSTER",
+92: "GASTLY",
+93: "HAUNTER",
+94: "GENGAR",
+95: "ONIX",
+96: "DROWZEE",
+97: "HYPNO",
+98: "KRABBY",
+99: "KINGLER",
+100: "VOLTORB",
+101: "ELECTRODE",
+102: "EXEGGCUTE",
+103: "EXEGGUTOR",
+104: "CUBONE",
+105: "MAROWAK",
+106: "HITMONLEE",
+107: "HITMONCHAN",
+108: "LICKITUNG",
+109: "KOFFING",
+110: "WEEZING",
+111: "RHYHORN",
+112: "RHYDON",
+113: "CHANSEY",
+114: "TANGELA",
+115: "KANGASKHAN",
+116: "HORSEA",
+117: "SEADRA",
+118: "GOLDEEN",
+119: "SEAKING",
+120: "STARYU",
+121: "STARMIE",
+122: "MR__MIME",
+123: "SCYTHER",
+124: "JYNX",
+125: "ELECTABUZZ",
+126: "MAGMAR",
+127: "PINSIR",
+128: "TAUROS",
+129: "MAGIKARP",
+130: "GYARADOS",
+131: "LAPRAS",
+132: "DITTO",
+133: "EEVEE",
+134: "VAPOREON",
+135: "JOLTEON",
+136: "FLAREON",
+137: "PORYGON",
+138: "OMANYTE",
+139: "OMASTAR",
+140: "KABUTO",
+141: "KABUTOPS",
+142: "AERODACTYL",
+143: "SNORLAX",
+144: "ARTICUNO",
+145: "ZAPDOS",
+146: "MOLTRES",
+147: "DRATINI",
+148: "DRAGONAIR",
+149: "DRAGONITE",
+150: "MEWTWO",
+151: "MEW",
+152: "CHIKORITA",
+153: "BAYLEEF",
+154: "MEGANIUM",
+155: "CYNDAQUIL",
+156: "QUILAVA",
+157: "TYPHLOSION",
+158: "TOTODILE",
+159: "CROCONAW",
+160: "FERALIGATR",
+161: "SENTRET",
+162: "FURRET",
+163: "HOOTHOOT",
+164: "NOCTOWL",
+165: "LEDYBA",
+166: "LEDIAN",
+167: "SPINARAK",
+168: "ARIADOS",
+169: "CROBAT",
+170: "CHINCHOU",
+171: "LANTURN",
+172: "PICHU",
+173: "CLEFFA",
+174: "IGGLYBUFF",
+175: "TOGEPI",
+176: "TOGETIC",
+177: "NATU",
+178: "XATU",
+179: "MAREEP",
+180: "FLAAFFY",
+181: "AMPHAROS",
+182: "BELLOSSOM",
+183: "MARILL",
+184: "AZUMARILL",
+185: "SUDOWOODO",
+186: "POLITOED",
+187: "HOPPIP",
+188: "SKIPLOOM",
+189: "JUMPLUFF",
+190: "AIPOM",
+191: "SUNKERN",
+192: "SUNFLORA",
+193: "YANMA",
+194: "WOOPER",
+195: "QUAGSIRE",
+196: "ESPEON",
+197: "UMBREON",
+198: "MURKROW",
+199: "SLOWKING",
+200: "MISDREAVUS",
+201: "UNOWN",
+202: "WOBBUFFET",
+203: "GIRAFARIG",
+204: "PINECO",
+205: "FORRETRESS",
+206: "DUNSPARCE",
+207: "GLIGAR",
+208: "STEELIX",
+209: "SNUBBULL",
+210: "GRANBULL",
+211: "QWILFISH",
+212: "SCIZOR",
+213: "SHUCKLE",
+214: "HERACROSS",
+215: "SNEASEL",
+216: "TEDDIURSA",
+217: "URSARING",
+218: "SLUGMA",
+219: "MAGCARGO",
+220: "SWINUB",
+221: "PILOSWINE",
+222: "CORSOLA",
+223: "REMORAID",
+224: "OCTILLERY",
+225: "DELIBIRD",
+226: "MANTINE",
+227: "SKARMORY",
+228: "HOUNDOUR",
+229: "HOUNDOOM",
+230: "KINGDRA",
+231: "PHANPY",
+232: "DONPHAN",
+233: "PORYGON2",
+234: "STANTLER",
+235: "SMEARGLE",
+236: "TYROGUE",
+237: "HITMONTOP",
+238: "SMOOCHUM",
+239: "ELEKID",
+240: "MAGBY",
+241: "MILTANK",
+242: "BLISSEY",
+243: "RAIKOU",
+244: "ENTEI",
+245: "SUICUNE",
+246: "LARVITAR",
+247: "PUPITAR",
+248: "TYRANITAR",
+249: "LUGIA",
+250: "HO_OH",
+251: "CELEBI",
+}
+def get_pokemon_constant_by_id(id):
+ return pokemon_constants[id]
+
+item_constants = {1: 'MASTER_BALL',
+2: 'ULTRA_BALL',
+3: 'BRIGHTPOWDER',
+4: 'GREAT_BALL',
+5: 'POKE_BALL',
+7: 'BICYCLE',
+8: 'MOON_STONE',
+9: 'ANTIDOTE',
+10: 'BURN_HEAL',
+11: 'ICE_HEAL',
+12: 'AWAKENING',
+13: 'PARLYZ_HEAL',
+14: 'FULL_RESTORE',
+15: 'MAX_POTION',
+16: 'HYPER_POTION',
+17: 'SUPER_POTION',
+18: 'POTION',
+19: 'ESCAPE_ROPE',
+20: 'REPEL',
+21: 'MAX_ELIXER',
+22: 'FIRE_STONE',
+23: 'THUNDERSTONE',
+24: 'WATER_STONE',
+26: 'HP_UP',
+27: 'PROTEIN',
+28: 'IRON',
+29: 'CARBOS',
+30: 'LUCKY_PUNCH',
+31: 'CALCIUM',
+32: 'RARE_CANDY',
+33: 'X_ACCURACY',
+34: 'LEAF_STONE',
+35: 'METAL_POWDER',
+36: 'NUGGET',
+37: 'POKE_DOLL',
+38: 'FULL_HEAL',
+39: 'REVIVE',
+40: 'MAX_REVIVE',
+41: 'GUARD_SPEC.',
+42: 'SUPER_REPEL',
+43: 'MAX_REPEL',
+44: 'DIRE_HIT',
+46: 'FRESH_WATER',
+47: 'SODA_POP',
+48: 'LEMONADE',
+49: 'X_ATTACK',
+51: 'X_DEFEND',
+52: 'X_SPEED',
+53: 'X_SPECIAL',
+54: 'COIN_CASE',
+55: 'ITEMFINDER',
+57: 'EXP.SHARE',
+58: 'OLD_ROD',
+59: 'GOOD_ROD',
+60: 'SILVER_LEAF',
+61: 'SUPER_ROD',
+62: 'PP_UP',
+63: 'ETHER',
+64: 'MAX_ETHER',
+65: 'ELIXER',
+66: 'RED_SCALE',
+67: 'SECRETPOTION',
+68: 'S.S.TICKET',
+69: 'MYSTERY_EGG',
+70: 'CLEAR_BELL',
+71: 'SILVER_WING',
+72: 'MOOMOO_MILK',
+73: 'QUICK_CLAW',
+74: 'PSNCUREBERRY',
+75: 'GOLD_LEAF',
+76: 'SOFT_SAND',
+77: 'SHARP_BEAK',
+78: 'PRZCUREBERRY',
+79: 'BURNT_BERRY',
+80: 'ICE_BERRY',
+81: 'POISON_BARB',
+82: "KING'S_ROCK",
+83: 'BITTER_BERRY',
+84: 'MINT_BERRY',
+85: 'RED_APRICORN',
+86: 'TINYMUSHROOM',
+87: 'BIG_MUSHROOM',
+88: 'SILVERPOWDER',
+89: 'BLU_APRICORN',
+91: 'AMULET_COIN',
+92: 'YLW_APRICORN',
+93: 'GRN_APRICORN',
+94: 'CLEANSE_TAG',
+95: 'MYSTIC_WATER',
+96: 'TWISTEDSPOON',
+97: 'WHT_APRICORN',
+98: 'BLACKBELT',
+99: 'BLK_APRICORN',
+101: 'PNK_APRICORN',
+102: 'BLACKGLASSES',
+103: 'SLOWPOKETAIL',
+104: 'PINK_BOW',
+105: 'STICK',
+106: 'SMOKE_BALL',
+107: 'NEVERMELTICE',
+108: 'MAGNET',
+109: 'MIRACLEBERRY',
+110: 'PEARL',
+111: 'BIG_PEARL',
+112: 'EVERSTONE',
+113: 'SPELL_TAG',
+114: 'RAGECANDYBAR',
+115: 'GS_BALL',
+116: 'BLUE_CARD',
+117: 'MIRACLE_SEED',
+118: 'THICK_CLUB',
+119: 'FOCUS_BAND',
+121: 'ENERGYPOWDER',
+122: 'ENERGY_ROOT',
+123: 'HEAL_POWDER',
+124: 'REVIVAL_HERB',
+125: 'HARD_STONE',
+126: 'LUCKY_EGG',
+127: 'CARD_KEY',
+128: 'MACHINE_PART',
+129: 'EGG_TICKET',
+130: 'LOST_ITEM',
+131: 'STARDUST',
+132: 'STAR_PIECE',
+133: 'BASEMENT_KEY',
+134: 'PASS',
+138: 'CHARCOAL',
+139: 'BERRY_JUICE',
+140: 'SCOPE_LENS',
+143: 'METAL_COAT',
+144: 'DRAGON_FANG',
+146: 'LEFTOVERS',
+150: 'MYSTERYBERRY',
+151: 'DRAGON_SCALE',
+152: 'BERSERK_GENE',
+156: 'SACRED_ASH',
+157: 'HEAVY_BALL',
+158: 'FLOWER_MAIL',
+159: 'LEVEL_BALL',
+160: 'LURE_BALL',
+161: 'FAST_BALL',
+163: 'LIGHT_BALL',
+164: 'FRIEND_BALL',
+165: 'MOON_BALL',
+166: 'LOVE_BALL',
+167: 'NORMAL_BOX',
+168: 'GORGEOUS_BOX',
+169: 'SUN_STONE',
+170: 'POLKADOT_BOW',
+172: 'UP_GRADE',
+173: 'BERRY',
+174: 'GOLD_BERRY',
+175: 'SQUIRTBOTTLE',
+177: 'PARK_BALL',
+178: 'RAINBOW_WING',
+180: 'BRICK_PIECE',
+181: 'SURF_MAIL',
+182: 'LITEBLUEMAIL',
+183: 'PORTRAITM_AIL',
+184: 'LOVELY_MAIL',
+185: 'EON_MAIL',
+186: 'MORPH_MAIL',
+187: 'BLUESKY_MAIL',
+188: 'MUSIC_MAIL',
+189: 'MIRAGE_MAIL',
+191: 'TM_01',
+192: 'TM_02',
+193: 'TM_03',
+194: 'TM_04',
+196: 'TM_05',
+197: 'TM_06',
+198: 'TM_07',
+199: 'TM_08',
+200: 'TM_09',
+201: 'TM_10',
+202: 'TM_11',
+203: 'TM_12',
+204: 'TM_13',
+205: 'TM_14',
+206: 'TM_15',
+207: 'TM_16',
+208: 'TM_17',
+209: 'TM_18',
+210: 'TM_19',
+211: 'TM_20',
+212: 'TM_21',
+213: 'TM_22',
+214: 'TM_23',
+215: 'TM_24',
+216: 'TM_25',
+217: 'TM_26',
+218: 'TM_27',
+219: 'TM_28',
+221: 'TM_29',
+222: 'TM_30',
+223: 'TM_31',
+224: 'TM_32',
+225: 'TM_33',
+226: 'TM_34',
+227: 'TM_35',
+228: 'TM_36',
+229: 'TM_37',
+230: 'TM_38',
+231: 'TM_39',
+232: 'TM_40',
+233: 'TM_41',
+234: 'TM_42',
+235: 'TM_43',
+236: 'TM_44',
+237: 'TM_45',
+238: 'TM_46',
+239: 'TM_47',
+240: 'TM_48',
+241: 'TM_49',
+242: 'TM_50',
+243: 'HM_01',
+244: 'HM_02',
+245: 'HM_03',
+246: 'HM_04',
+247: 'HM_05',
+248: 'HM_06',
+249: 'HM_07'}
+def find_item_label_by_id(id):
+ if id in item_constants.keys():
+ return item_constants[id]
+ else: return None
+def generate_item_constants():
+ """make a list of items to put in constants.asm"""
+ for (id, item) in item_constants.items():
+ val = ("$%.2x"%id).upper()
+ while len(item)<13: item+= " "
+ print item + " EQU " + val
+
def find_all_text_pointers_in_script_engine_script(script, bank=None, debug=False):
"""returns a list of text pointers
based on each script-engine script command"""
@@ -1211,7 +1782,8 @@
0x16: "addvar",
0x17: "random",
0x19: "copybytetovar",
- 0x1A: "copyvartobyte", #loadvar ?
+ 0x1A: "copyvartobyte",
+ 0x1B: "loadvar",
0x1C: "checkcode",
0x1E: "writecode",
0x1F: "giveitem",
@@ -1354,7 +1926,8 @@
0x16: "addvar",
0x17: "random",
0x19: "copybytetovar",
- 0x1A: "copyvartobyte", #loadvar?
+ 0x1A: "copyvartobyte",
+ 0x1B: "loadvar",
0x1C: "checkcode",
0x1E: "writecode",
0x1F: "giveitem",
@@ -1482,6 +2055,481 @@
0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
]
+class Command():
+ def __init__(self, address=None):
+ raise Exception, "i don't think anything actually calls this?"
+ self.params = {}
+ if not is_valid_address(address):
+ raise Exception, "address is invalid"
+ self.address = address
+ def to_asm(self):
+ #start with the rgbasm macro name for this command
+ output = self.macro_name
+ #return if there are no params
+ if len(self.param_types.keys()) == 0: return output
+ #first one will have no prefixing comma
+ first = True
+ #start reading the bytes after the command byte
+ current_address = self.address+1
+ #add each param
+ for param in self.params:
+ name = param.name
+ #the first param shouldn't have ", " prefixed
+ if first: first = False
+ #but all other params should
+ else: output += ", "
+ #now add the asm-compatible param string
+ output += obj.to_asm()
+ current_address += obj.size
+ #for param_type in self.param_types:
+ # name = param_type["name"]
+ # klass = param_type["klass"]
+ # #create an instance of this type
+ # #tell it to begin parsing at this latest byte
+ # obj = klass(address=current_address)
+ # #the first param shouldn't have ", " prefixed
+ # if first: first = False
+ # #but all other params should
+ # else: output += ", "
+ # #now add the asm-compatible param string
+ # output += obj.to_asm()
+ # current_address += obj.size
+ return output
+ def parse(self):
+ #id, size (inclusive), param_types
+ #param_type = {"name": each[1], "class": each[0]}
+ self.params = {}
+ current_address = self.address+1
+ byte = int(rom[self.address])
+ if not byte == self.id:
+ raise Exception, "this should never happen"
+ 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)
+ #save this for later
+ self.params[i] = obj
+ #increment our counters
+ current_address += obj.size
+ i += 1
+ return True
+class GivePoke(Command):
+ id = 0x2D
+ size = 4 #minimum
+ param_types = {
+ 0: {"name": "pokemon", "class": PokemonParam},
+ 1: {"name": "level", "class": SingleByteParam},
+ 2: {"name": "item", "class": ItemLabelByte},
+ 3: {"name": "trainer", "class": SingleByteParam},
+ 4: {"name": "trainer_name_pointer", "class": MultiByteParam}, #should probably use TextLabelParam
+ 5: {"name": "pkmn_nickname", "class": MultiByteParam}, #XXX TextLabelParam ?
+ ]
+ def parse(self):
+ self.params = {}
+ byte = int(rom[self.address])
+ if not byte == self.id:
+ raise Exception, "this should never happen"
+ current_address = self.address+1
+ i = 0
+ for (key, param_type) in self.param_types.items():
+ #stop executing after the 4th byte unless it == 0x1
+ if i == 4 and self.params[-1].byte != 1: break
+ 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)
+ #save this for later
+ self.params[i] = obj
+ #increment our counters
+ current_address += obj.size
+ i += 1
+ return True
+
+class SingleByteParam():
+ """or SingleByte(CommandParam)"""
+ size = 1
+ should_be_decimal = False
+ def __init__(self, *args, **kwargs):
+ for (key, value) in kwargs:
+ setattr(self, key, value)
+ #check address
+ if not hasattr(self, "address"):
+ raise Exception, "an address is a requirement")
+ elif self.address == None:
+ raise Exception, "address must not be None"
+ elif not is_valid_address(self.address):
+ raise Exception, "address must be valid"
+ #check size
+ if not hasattr(self, "size") or self.size == None:
+ raise Exception, "size is probably 1?"
+ #parse bytes from ROM
+ self.parse()
+ def parse(self): self.byte = int(rom[self.address], 16)
+ def to_asm(self):
+ if not self.should_be_decimal: return hex(self.byte).replace("0x", "$")
+ else: return str(self.byte)
+class HexByte(SingleByteParam):
+ def to_asm(self): return hex(self.byte)
+class DollarSignByte(SingleByteParam):
+ #def to_asm(self): return "$%.2x"%self.byte
+ def to_asm(self): return hex(self.byte).replace("0x", "$")
+class ItemLabelByte(DollarSignByte):
+ def to_asm(self):
+ label = find_item_label_by_id(self.byte)
+ if label: return label
+ elif not label: return DollarSignByte.to_asm(self)
+class DecimalByte(SingleByteParam):
+ should_be_decimal = True
+
+class MultiByteParam():
+ """or MultiByte(CommandParam)"""
+ size = 2
+ should_be_decimal = False
+ def __init__(self, *args, **kwargs):
+ self.prefix = "$" #default.. feel free to set 0x in kwargs
+ for (key, value) in kwargs:
+ setattr(self, key, value)
+ #check address
+ if not hasattr(self, "address") or self.address == None:
+ raise Exception, "an address is a requirement")
+ elif not is_valid_address(self.address):
+ raise Exception, "address must be valid"
+ #check size
+ if not hasattr(self, "size") or self.size == None:
+ raise Exception, "don't know how many bytes to read (size)"
+ self.parse()
+ def parse(self): self.bytes = rom_interval(self.address, self.size, strings=False)
+ #you won't actually use this to_asm because it's too generic
+ #def to_asm(self): return ", ".join([(self.prefix+"%.2x")%x for x in self.bytes])
+ def to_asm(self):
+ if not self.should_be_decimal:
+ return self.prefix+"".join([("%.2x")%x for x in reversed(self.bytes)])
+ elif self.should_be_decimal:
+ decimal = int("0x"+"".join([("%.2x")%x for x in reversed(self.bytes)]), 16)
+ return str(decimal)
+class PointerLabelParam(MultiByteParam):
+ #default size is 2 bytes
+ default_size = 2
+ size = 2
+ #default is to not parse out a bank
+ bank = False
+ def __init__(self, *args, **kwargs):
+ #bank can be overriden
+ if "bank" in kwargs.keys():
+ if kwargs["bank"] != False and kwargs["bank"] != None:
+ #not +=1 because child classes set size=3 already
+ self.size = self.default_size + 1
+ if kwargs["bank"] not in [None, False, True, "reverse"]:
+ raise Exception, "bank cannot be: " + str(bank)
+ if self.size > 3:
+ raise Exception, "param size is too large"
+ #continue instantiation.. self.bank will be set down the road
+ MultiByteParam.__init__(self, *args, **kwargs)
+ def to_asm(self):
+ bank = self.bank
+ #we pass bank= for whether or not to include a bank byte when reading
+ #.. it's not related to caddress
+ caddress = calculate_pointers_from_bytes_at(self.address+1, bank=self.bank)
+ label = get_label_for(caddress)
+ pointer_part = label #use the label, if it is found
+ #setup output bytes if the label was not found
+ if not label:
+ #pointer_part = (", ".join([(self.prefix+"%.2x")%x for x in reversed(self.bytes[1:])]))
+ pointer_part = self.prefix+("%.2x"%self.bytes[2])+("%.2x"%self.bytes[1])
+ #bank positioning matters!
+ if bank == True or bank == "reverse": #bank, pointer
+ #possibly use BANK(LABEL) if we know the bank
+ if not label:
+ bank_part = ((self.prefix+"%.2x")%bank)
+ else:
+ bank_part = "BANK("+label+")"
+ #return the asm based on the order the bytes were specified to be in
+ if bank == "reverse": #pointer, bank
+ return pointer_part+", "+bank_part
+ elif bank == True: #bank, pointer
+ return bank_part+", "+pointer_part
+ else: raise Exception, "this should never happen"
+ raise Exception, "this should never happen"
+ #this next one will either return the label or the raw bytes
+ elif bank == False or bank == None: #pointer
+ return pointer_part #this could be the same as label
+ else:
+ raise Exception, "this should never happen"
+ raise Exception, "this should never happen"
+class PointerLabelBeforeBank(PointerLabelParam):
+ bank = True #bank appears first, see calculate_pointer_from_bytes_at
+ size = 3
+class PointerLabelAfterBank(PointerLabelParam):
+ bank = "reverse" #bank appears last, see calculate_pointer_from_bytes_at
+ size = 3
+class ScriptPointerLabelParam(PointerLabelParam): pass
+class ScriptPointerLabelBeforeBank(PointerLabelBeforeBank): pass
+class ScriptPointerLabelAfterBank(PointerLabelAfterBank): pass
+def _parse_script_pointer_bytes(self):
+ PointerLabelParam.parse(self)
+ address = calculate_pointer_from_bytes_at(self.address, bank=self.bank)
+ self.script = parse_script_engine_script_at(address)
+ScriptPointerLabelParam = _parse_script_pointer_bytes
+ScriptPointerLabelBeforeBank.parse = _parse_script_pointer_bytes
+ScriptPointerLabelAfterBank.parse = _parse_script_pointer_bytes
+class PointerLabelToScriptPointer(PointerLabelParam):
+ def parse(self):
+ PointerLabelParam.parse(self)
+ address = calculate_pointer_from_bytes_at(self.address, bank=self.bank)
+ address2 = calculate_pointer_from_bytes_at(address, bank="reverse") #maybe not "reverse"?
+ self.script = parse_script_engine_script_at(address2, origin=False)
+class AsmPointerParam(PointerLabelBeforeBank):
+ def parse(self):
+ PointerLabelBeforeBank.parse(self)
+ address = calculate_pointer_from_bytes_at(self.address, bank=self.bank) #3-byte pointer
+ self.asm = parse_script_asm_at(address) #might end in some specific way?
+class PointerToAsmPointerParam(PointerLabelParam):
+ def parse(self):
+ PointerLabelParam.parse(self)
+ address = calculate_pointer_from_bytes_at(self.address, bank=self.bank) #2-byte pointer
+ address2 = calculate_pointer_from_bytes_at(address, bank="reverse") #maybe not "reverse"?
+ self.asm = parse_script_asm_at(address) #might end in some specific way?
+class RAMAddressParam(MultiByteParam):
+ def to_asm(self):
+ address = calculate_pointer_from_bytes_at(self.address, bank=False)
+ label = get_ram_label(address)
+ if label: return "["+label+"]"
+ else: return "[$"+"".join(["%.2x"%x for x in self.bytes])+"]"
+class MoneyByteParam(MultiByteParam):
+ size = 3
+ max_value = 0x0F423F
+ should_be_decimal = True
+class CoinByteParam(MultiByteParam):
+ size = 2
+ max_value = 0x270F
+ should_be_decimal = True
+class MapGroupParam(SingleByteParam):
+ def to_asm(self):
+ map_id = ord(rom[self.address+1])
+ map_constant_label = get_map_constant_label(map_id=map_id, map_group=self.byte) #like PALLET_TOWN
+ if map_constant_label == None: return str(self.byte)
+ #else: return "GROUP("+map_constant_label+")"
+ else: return "GROUP_"+map_constant_label
+class MapIdParam(SingleByteParam):
+ def parse(self):
+ SingleByteParam.parse(self)
+ self.map_group = ord(rom[self.address-1])
+ def to_asm(self):
+ map_group = ord(rom[self.address-1])
+ map_constant_label = get_map_constant_label(map_id=self.byte, map_group=map_group)
+ if map_constant_label == None: return str(self.byte)
+ #else: return "MAP("+map_constant_label+")"
+ else: return "MAP_"+map_constant_label
+class MapGroupIdParam(MultiByteParam):
+ def parse(self):
+ MultiByteParam.parse(self)
+ self.map_group = self.bytes[0]
+ self.map_id = self.bytes[1]
+ def to_asm(self):
+ map_group = self.map_group
+ map_id = self.map_id
+ label = get_map_constant_label(map_group=map_group, map_id=map_id)
+ return label
+class PokemonParam(SingleByteParam):
+ def to_asm(self):
+ pokemon_constant = get_pokemon_constant_by_id(self.byte)
+ if pokemon_constant: return pokemon_constant
+ else: return str(self.byte)
+class PointerParamToItemAndLetter(MultiByteParam):
+ raise NotImplementedError, bryan_message
+ #[2F][2byte pointer to item no + 0x20 bytes letter text]
+class TrainerIdParam(SingleByteParam):
+ raise NotImplementedError, bryan_message
+class TrainerGroupParam(SingleByteParam):
+ raise NotImplementedError, bryan_message
+
+SingleByteParam, HexByte, DollarSignByte, ItemLabelByte
+PointerLabelParam, PointerLabelBeforeBank, PointerLabelAfterBank
+
+#byte: [name, [param1 name, param1 type], [param2 name, param2 type], ...]
+#0x9E: ["verbosegiveitem", ["item", ItemLabelByte], ["quantity", SingleByteParam]],
+pksv_crystal_more = {
+ 0x00: ["2call", ["pointer", ScriptPointerLabelParam]],
+ 0x01: ["3call", ["pointer", ScriptPointerLabelBeforeBank]],
+ 0x02: ["2ptcall", ["pointer", PointerLabelToScriptPointer]],
+ 0x03: ["2jump", ["pointer", ScriptPointerLabelParam]],
+ 0x04: ["3jump", ["pointer", ScriptPointerLabelBeforeBank]],
+ 0x05: ["2ptjump", ["pointer", PointerLabelToScriptPointer]],
+ 0x06: ["if equal", ["byte", SingleByteParam], ["pointer", ScriptPointerLabelParam]],
+ 0x07: ["if not equal", ["byte", SingleByteParam], ["pointer", ScriptPointerLabelParam]],
+ 0x08: ["if false", ["pointer", ScriptPointerLabelParam]],
+ 0x09: ["if true", ["pointer", ScriptPointerLabelParam]],
+ 0x0A: ["if less than", ["byte", SingleByteParam], ["pointer", ScriptPointerLabelParam]],
+ 0x0B: ["if greater than", ["byte", SingleByteParam], ["pointer", ScriptPointerLabelParam]],
+ 0x0C: ["jumpstd", ["predefined_script", MultiByteParam]],
+ 0x0D: ["callstd", ["predefined_script", MultiByteParam]],
+ 0x0E: ["3callasm", ["asm", AsmPointerParam]],
+ 0x0F: ["special", ["predefined_script", MultiByteParam]],
+ 0x10: ["2ptcallasm", ["asm", PointerToAsmPointerParam]],
+ #should map_group/map_id be dealt with in some special way in the asm?
+ 0x11: ["checkmaptriggers", ["map_group", SingleByteParam], ["map_id", SingleByteParam]],
+ 0x12: ["domaptrigger", ["map_group", MapGroupParam], ["map_id", MapIdParam], ["trigger_id", SingleByteParam]],
+ 0x13: ["checktriggers"],
+ 0x14: ["dotrigger", ["trigger_id", SingleByteParam]],
+ 0x15: ["writebyte", ["value", SingleByteParam]],
+ 0x16: ["addvar", ["value", SingleByteParam]],
+ 0x17: ["random", ["input", SingleByteParam]],
+ 0x19: ["copybytetovar", ["address", RAMAddressParam]],
+ 0x1A: ["copyvartobyte", ["address", RAMAddressParam]],
+ 0x1B: ["loadvar", ["address", RAMAddressParam], ["value", SingleByteParam]],
+ 0x1C: ["checkcode", ["variable_id", SingleByteParam]],
+ 0x1E: ["writecode", ["variable_id", SingleByteParam], ["value", SingleByteParam]],
+ 0x1F: ["giveitem", ["item", ItemLabelByte], ["quantity", SingleByteParam]],
+ 0x20: ["takeitem", ["item", ItemLabelByte], ["quantity", SingleByteParam]],
+ 0x21: ["checkitem", ["item", ItemLabelByte]],
+ 0x22: ["givemoney", ["account", SingleByteParam], ["money", MoneyByteParam]],
+ 0x23: ["takemoney", ["account", SingleByteParam], ["money", MoneyByteParam]],
+ 0x24: ["checkmonkey", ["account", SingleByteParam], ["money", MoneyByteParam]],
+ 0x25: ["givecoins", ["coins", CoinByteParam]],
+ 0x26: ["takecoins", ["coins", CoinByteParam]],
+ 0x27: ["checkcoins", ["coins", CoinByteParam]],
+ #0x28-0x2A not from pksv
+ 0x28: ["addcellnum", ["person", SingleByteParam]],
+ 0x29: ["delcellnum", ["person", SingleByteParam]],
+ 0x2A: ["checkcellnum", ["person", SingleByteParam]],
+ #back on track...
+ 0x2B: ["checktime", ["time", SingleByteParam]],
+ 0x2C: ["checkpoke", ["pkmn", PokemonParam]],
+#0x2D: ["givepoke", ], .... see GivePoke class
+ 0x2E: ["giveegg", ["pkmn", PokemonParam], ["level", DecimalByte]],
+ 0x2F: ["givepokeitem", ["pointer", PointerParamToItemAndLetter]],
+ 0x30: ["checkpokeitem", ["pointer", PointerParamToItemAndLetter]], #not pksv
+ 0x31: ["checkbit1", ["bit_number", SingleByteParam]],
+ 0x32: ["clearbit1", ["bit_number", SingleByteParam]],
+ 0x33: ["setbit1", ["bit_number", SingleByteParam]],
+ 0x34: ["checkbit2", ["bit_number", SingleByteParam]],
+ 0x35: ["clearbit2", ["bit_number", SingleByteParam]],
+ 0x36: ["setbit2", ["bit_number", SingleByteParam]],
+ 0x37: ["wildoff"],
+ 0x38: ["wildon"],
+ 0x39: ["xycompare", ["pointer", MultiByteParam]],
+ 0x3A: ["warpmod", ["warp_id", SingleByteParam], ["map_group", MapGroupParam], ["map_id", MapIdParam]],
+ 0x3B: ["blackoutmod", ["map_group", MapGroupParam], ["map_id", MapIdParam]],
+ 0x3C: ["warp", ["map_group", MapGroupParam], ["map_id", MapIdParam], ["x", SingleByteParam], ["y", SingleByteParam]],
+ 0x3D: ["readmoney", ["account", SingleByteParam], ["memory", SingleByteParam]], #not pksv
+ 0x3E: ["readcoins", ["memory", SingleByteParam]], #not pksv
+ 0x3F: ["RAM2MEM", ["memory", SingleByteParam]], #not pksv
+ 0x40: ["pokenamemem", ["pokemon", PokemonParam], ["memory", SingleByteParam]], #not pksv
+ 0x41: ["itemtotext", ["item", ItemLabelByte], ["memory", SingleByteParam]],
+ 0x42: ["mapnametotext", ["memory", SingleByteParam]], #not pksv
+ 0x43: ["trainertotext", ["trainer_id", TrainerIdParam], ["trainer_group", TrainerGroupParam], ["memory", SingleByteParam]],
+ 0x44: ["stringtotext", ],
+ 0x45: ["itemnotify", ],
+ 0x46: ["pocketisfull", ],
+ 0x47: ["loadfont", ],
+ 0x48: ["refreshscreen", ],
+ 0x49: ["loadmovesprites", ],
+ 0x4B: ["3writetext", ],
+ 0x4C: ["2writetext", ],
+ 0x4E: ["yesorno", ],
+ 0x4F: ["loadmenudata", ],
+ 0x50: ["writebackup", ],
+ 0x51: ["jumptextfaceplayer", ],
+ 0x53: ["jumptext", ],
+ 0x54: ["closetext", ],
+ 0x55: ["keeptextopen", ],
+ 0x56: ["pokepic", ],
+ 0x57: ["pokepicyesorno", ],
+ 0x58: ["interpretmenu", ],
+ 0x59: ["interpretmenu2", ],
+ 0x5D: ["loadpokedata", ],
+ 0x5E: ["loadtrainer", ],
+ 0x5F: ["startbattle", ],
+ 0x60: ["returnafterbattle", ],
+ 0x61: ["catchtutorial", ],
+ 0x64: ["winlosstext", ],
+ 0x66: ["talkaftercancel", ],
+ 0x68: ["setlasttalked", ],
+ 0x69: ["applymovement", ],
+ 0x6B: ["faceplayer", ],
+ 0x6C: ["faceperson", ],
+ 0x6D: ["variablesprite", ],
+ 0x6E: ["disappear", ],
+ 0x6F: ["appear", ],
+ 0x70: ["follow", ],
+ 0x71: ["stopfollow", ],
+ 0x72: ["moveperson", ],
+ 0x75: ["showemote", ],
+ 0x76: ["spriteface", ],
+ 0x77: ["follownotexact", ],
+ 0x78: ["earthquake", ],
+ 0x7A: ["changeblock", ],
+ 0x7B: ["reloadmap", ],
+ 0x7C: ["reloadmappart", ],
+ 0x7D: ["writecmdqueue", ],
+ 0x7E: ["delcmdqueue", ],
+ 0x7F: ["playmusic", ],
+ 0x80: ["playrammusic", ],
+ 0x81: ["musicfadeout", ],
+ 0x82: ["playmapmusic", ],
+ 0x83: ["reloadmapmusic", ],
+ 0x84: ["cry", ],
+ 0x85: ["playsound", ],
+ 0x86: ["waitbutton", ],
+ 0x87: ["warpsound", ],
+ 0x88: ["specialsound", ],
+ 0x89: ["passtoengine", ],
+ 0x8A: ["newloadmap", ],
+ 0x8B: ["pause", ],
+ 0x8C: ["deactivatefacing", ],
+ 0x8D: ["priorityjump", ],
+ 0x8E: ["warpcheck", ],
+ 0x8F: ["ptpriorityjump", ],
+ 0x90: ["return", ],
+ 0x91: ["end", ],
+ 0x92: ["reloadandreturn", ],
+ 0x93: ["resetfuncs", ],
+ 0x94: ["pokemart", ],
+ 0x95: ["elevator", ],
+ 0x96: ["trade", ],
+ 0x97: ["askforphonenumber", ],
+ 0x98: ["phonecall", ],
+ 0x99: ["hangup", ],
+ 0x9A: ["describedecoration", ],
+ 0x9B: ["fruittree", ],
+ 0x9C: ["specialphonecall", ],
+ 0x9D: ["checkphonecall", ],
+ 0x9E: ["verbosegiveitem", ],
+ 0xA0: ["loadwilddata", ],
+ 0xA1: ["halloffame", ],
+ 0xA2: ["credits", ],
+ 0xA3: ["warpfacing", ],
+ 0xA4: ["storetext", ],
+ 0xA5: ["displaylocation", ],
+}
+#these cause the script to end; used in create_command_classes
+pksv_crystal_more_enders = [0x03, 0x04, 0x05, 0x0C, 0x51, 0x53,
+ 0x8D, 0x8F, 0x90, 0x91, 0x92, 0x9B]
+def create_command_classes():
+ """creates some classes for each command byte"""
+ klasses = []
+ for (byte, cmd) in pksv_crystal_more.items():
+ cmd_name = cmd[0]
+ params = {"id": byte, "size": 1, "end": byte in pksv_crystal_more_enders}
+ if len(cmd) > 1:
+ param_types = cmd[1:]
+ params["param_types"] = {}
+ for (i, each) in enumerate(param_types):
+ thing = {"name": each[0], "class": each[1]}
+ params["param_types"][i] = thing
+ params["size"] += thing["class"].size
+ klass_name = cmd_name+"Command"
+ klass = classobj(klass_name, (Command,), params)
+ globals()[klass_name] = klass
+ klasses = append(klass)
+ #later an individual klass will be instantiated to handle something
+ return klasses
+create_command_classes()
+
#use this to keep track of commands without pksv names
pksv_no_names = {}
def pretty_print_pksv_no_names():
@@ -4514,6 +5562,8 @@
cleaned_name = map_name_cleaner(map_data["name"])
#set the value in the original dictionary
map_names[map_group_id][map_id]["label"] = cleaned_name
+#generate map constants (like 1=PALLET_TOWN)
+generate_map_constant_labels()
#### pretty printing ###
#texts: TextScript.to_asm_at
@@ -5594,6 +6644,8 @@
for (name, func) in funcs:
#we don't care about some of these
if name in avoid_funcs: continue
+ #skip functions beginning with _
+ if name[0] == "_": continue
#check if this function has a test named after it
has_test = check_has_test(name, tested_names)
if not has_test: