Skip to content

Instantly share code, notes, and snippets.

@luckytyphlosion
Last active May 5, 2021 18:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save luckytyphlosion/e101485c6e5d25f54db2f72c06bab27b to your computer and use it in GitHub Desktop.
Save luckytyphlosion/e101485c6e5d25f54db2f72c06bab27b to your computer and use it in GitHub Desktop.
# =============================================================================
# Copyright(c) 2021 luckytyphlosion
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
# =============================================================================
import sys
from sys import argv
output = ""
id = 98
count = 0
pokemon_list = ["'M","RHYDON","KANGASKHAN","NIDORAN_M","CLEFAIRY","SPEAROW","VOLTORB","NIDOKING","SLOWBRO","IVYSAUR","EXEGGUTOR","LICKITUNG","EXEGGCUTE","GRIMER","GENGAR","NIDORAN_F","NIDOQUEEN","CUBONE","RHYHORN","LAPRAS","ARCANINE","MEW","GYARADOS","SHELLDER","TENTACOOL","GASTLY","SCYTHER","STARYU","BLASTOISE","PINSIR","TANGELA","MISSINGNO_1F","MISSINGNO_20","GROWLITHE","ONIX","FEAROW","PIDGEY","SLOWPOKE","KADABRA","GRAVELER","CHANSEY","MACHOKE","MR_MIME","HITMONLEE","HITMONCHAN","ARBOK","PARASECT","PSYDUCK","DROWZEE","GOLEM","MISSINGNO_32","MAGMAR","MISSINGNO_34","ELECTABUZZ","MAGNETON","KOFFING","MISSINGNO_38","MANKEY","SEEL","DIGLETT","TAUROS","MISSINGNO_3D","MISSINGNO_3E","MISSINGNO_3F","FARFETCH_D","VENONAT","DRAGONITE","MISSINGNO_43","MISSINGNO_44","MISSINGNO_45","DODUO","POLIWAG","JYNX","MOLTRES","ARTICUNO","ZAPDOS","DITTO","MEOWTH","KRABBY","MISSINGNO_4F","MISSINGNO_50","MISSINGNO_51","VULPIX","NINETALES","PIKACHU","RAICHU","MISSINGNO_56","MISSINGNO_57","DRATINI","DRAGONAIR","KABUTO","KABUTOPS","HORSEA","SEADRA","MISSINGNO_5E","MISSINGNO_5F","SANDSHREW","SANDSLASH","OMANYTE","OMASTAR","JIGGLYPUFF","WIGGLYTUFF","EEVEE","FLAREON","JOLTEON","VAPOREON","MACHOP","ZUBAT","EKANS","PARAS","POLIWHIRL","POLIWRATH","WEEDLE","KAKUNA","BEEDRILL","MISSINGNO_73","DODRIO","PRIMEAPE","DUGTRIO","VENOMOTH","DEWGONG","MISSINGNO_79","MISSINGNO_7A","CATERPIE","METAPOD","BUTTERFREE","MACHAMP","MISSINGNO_7F","GOLDUCK","HYPNO","GOLBAT","MEWTWO","SNORLAX","MAGIKARP","MISSINGNO_86","MISSINGNO_87","MUK","MISSINGNO_8A","KINGLER","CLOYSTER","MISSINGNO_8C","ELECTRODE","CLEFABLE","WEEZING","PERSIAN","MAROWAK","MISSINGNO_92","HAUNTER","ABRA","ALAKAZAM","PIDGEOTTO","PIDGEOT","STARMIE","BULBASAUR","VENUSAUR","TENTACRUEL","MISSINGNO_9C","GOLDEEN","SEAKING","MISSINGNO_9F","MISSINGNO_A0","MISSINGNO_A1","MISSINGNO_A2","PONYTA","RAPIDASH","RATTATA","RATICATE","NIDORINO","NIDORINA","GEODUDE","PORYGON","AERODACTYL","MISSINGNO_AC","MAGNEMITE","MISSINGNO_AE","MISSINGNO_AF","CHARMANDER","SQUIRTLE","CHARMELEON","WARTORTLE","CHARIZARD","MISSINGNO_B5","FOSSIL_KABUTOPS","FOSSIL_AERODACTYL","MON_GHOST","ODDISH","GLOOM","VILEPLUME","BELLSPROUT","WEEPINBELL","VICTREEBEL"]
def read_byte(f):
return ord(f.read(1))
def read_ptr(f):
low_byte = read_byte(f)
upper_byte = read_byte(f)
return upper_byte << 8 | low_byte
with open("pokeyellow.gbc", "rb") as f:
for i in range(256):
game_corner_index = (i - 3) & 0xff
if game_corner_index == 2:
continue
f.seek(0x527ae + game_corner_index * 4)
prizes = read_ptr(f)
output += "== GAME CORNER {0} ==\nprize list: ${1:04x}\n".format(i, prizes)
prices = read_ptr(f)
output += "prices: ${0:04x}\n".format(prices)
price_list = []
if prices < 0x8000:
overflow_addr = None
if prices < 0x4000:
overflow_addr = 0x4000
f.seek(prices)
else:
overflow_addr = 0x54000
f.seek(prices + 0x4000 * (0x14 - 1))
for j in range(3):
if f.tell() == overflow_addr:
if overflow_addr == 0x4000:
f.seek(0x50000)
else:
output += "Prices went into VRAM"
while len(price_list) < 3:
price_list.append("VRAM")
break
high_byte = read_byte(f)
if f.tell() == overflow_addr:
if overflow_addr == 0x4000:
f.seek(0x50000)
else:
output += "Prices went into VRAM"
while len(price_list) < 3:
price_list.append("VRAM")
break
low_byte = read_byte(f)
price_list.append("{0:04x}".format(high_byte << 8 | low_byte))
else:
for j in range(3):
price_list.append("[${0:04x}]".format(prices + j * 2))
if prizes < 0x8000:
overflow_addr = None
if prizes < 0x4000:
overflow_addr = 0x4000
f.seek(prizes)
else:
overflow_addr = 0x54000
f.seek(prizes + 0x4000 * (0x14 - 1))
for prize_count in range(3):
byte = read_byte(f)
if byte > 190:
output += "Prize {0} GLITCH_{1:02x} costs {2} coins.\n".format(prize_count+1, byte, price_list[prize_count])
else:
output += "Prize {0} {1} [${2:02x} / {2}] costs {3} coins.\n".format(prize_count+1, pokemon_list[byte], byte, price_list[prize_count])
if byte == 0x50:
break
if f.tell() == overflow_addr:
if overflow_addr == 0x4000:
f.seek(0x50000)
else:
output += "Rest of prizes in VRAM\n"
break
else:
output += "Buffer overflow: "
while True:
if f.tell() == overflow_addr:
if overflow_addr == 0x4000:
f.seek(0x50000)
else:
output += "[VRAM], "
break
byte = read_byte(f)
output += "${0:02x}, ".format(byte)
if byte == 0x50:
break
output = output[:-2] + "\n"
elif prices < 0x8000:
output += "Price list: "
for price in price_list:
output += price + ", "
output = output[:-2] + "\n"
output += "\n"
with open("yellow_game_corner_glitch.txt", "w+") as f:
f.write(output)
# =============================================================================
# Copyright(c) 2020 luckytyphlosion
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
# =============================================================================
BANK = 0x17
def read_byte(f):
return ord(f.read(1))
def zfill_hex(num, pad):
return ("%x" % num).zfill(pad)
def format_addr(offset):
comment_bank = offset / 0x4000
if comment_bank != 0:
comment_bank_addr = (offset % 0x4000) + 0x4000
else:
comment_bank_addr = offset
return "%s:%s" % (zfill_hex(comment_bank, 2), zfill_hex(comment_bank_addr, 4))
def convert_addr_to_16bit(addr):
return i if i < 0x4000 else (i - 0x4000 * (BANK - 1))
output = ""
count = 0
possible_game_corner_addrs = []
game_corner_addrs = []
with open("pokered.gb", "rb") as f:
addrs = [0, BANK * 0x4000]
for addr in addrs:
f.seek(addr)
for i in range(addr, addr + 0x4000):
byte = read_byte(f)
if byte == 0xf7:
possible_game_corner_addrs.append(convert_addr_to_16bit(i))
for addr in addrs:
f.seek(addr)
for i in range(addr, addr + 0x4000):
temp_pos = f.tell()
low_byte = read_byte(f)
high_byte = read_byte(f)
ptr = high_byte << 8 | low_byte
if ptr in possible_game_corner_addrs:
game_corner_addrs.append([convert_addr_to_16bit(temp_pos), ptr])
f.seek(temp_pos+1)
for ptr_pair in game_corner_addrs:
output += "${:04x} works (pointer at ${:04x} is ${:04x})\n".format((ptr_pair[0] - 0x3a * 2) & 0xffff, ptr_pair[0], ptr_pair[1])
with open("game_corner_pointers.txt", "w+") as f:
f.write(output)
# =============================================================================
# Copyright (c) 2021 luckytyphlosion
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
# AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
# OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
# =============================================================================
def corrupts_dex(addr, addr_end):
return addr <= 0xd31c and 0xd2f7 <= addr_end
def corrupts_cur_map(addr, addr_end):
return addr <= 0xd35e <= addr_end
# addr = x
# num = y
def corrupts_map_script_ptr(addr, addr_end):
return addr <= 0xd36f and 0xd36e <= addr_end
def corrupts_north_conn_dest(addr, addr_end):
return addr <= 0xd375 and 0xd374 <= addr_end
def pm(x, datatype):
if datatype == "p":
slot = (x - 0xd16b)//0x2c
elif datatype == "o":
slot = (x - 0xd273)//11
elif datatype == "n":
slot = (x - 0xd2b5)//11
else:
return None
party_mon_addr = 0xd16b + slot * 0x2c
party_mon_addr_end = party_mon_addr + 0x2b
ot_addr = 0xd273 + slot * 11
ot_addr_end = ot_addr + 10
nick_addr = 0xd2b5 + slot * 11
nick_addr_end = nick_addr + 10
output = f"slot {slot}/{slot:02x} (0in): partymon: {party_mon_addr:x}-{party_mon_addr_end:x}, OT: {ot_addr:x}-{ot_addr_end:x}, nick: {nick_addr:x}-{nick_addr_end:x}"
if corrupts_dex(party_mon_addr, party_mon_addr_end):
output += "\n (partymon corrupts dex!)"
if corrupts_cur_map(party_mon_addr, party_mon_addr_end):
output += "\n (partymon corrupts map!)"
if corrupts_map_script_ptr(party_mon_addr, party_mon_addr_end):
output += "\n (partymon corrupts script!)"
if corrupts_north_conn_dest(party_mon_addr, party_mon_addr_end):
output += "\n (partymon corrupts north!)"
if corrupts_dex(ot_addr, ot_addr_end):
output += "\n (OT corrupts dex!)"
if corrupts_cur_map(ot_addr, ot_addr_end):
output += "\n (OT corrupts map!)"
if corrupts_map_script_ptr(ot_addr, ot_addr_end):
output += "\n (OT corrupts script!)"
if corrupts_north_conn_dest(ot_addr, ot_addr_end):
output += "\n (OT corrupts north!)"
if corrupts_dex(nick_addr, nick_addr_end):
output += "\n (nick corrupts dex!)"
if corrupts_cur_map(nick_addr, nick_addr_end):
output += "\n (nick corrupts map!)"
if corrupts_map_script_ptr(nick_addr, nick_addr_end):
output += "\n (nick corrupts script!)"
if corrupts_north_conn_dest(nick_addr, nick_addr_end):
output += "\n (nick corrupts north!)"
print(output)
#return output
def ps(x, datatype=None):
#if datatype == "p":
# addr = 0xd16b + x * 0x2c
#elif datatype == "o":
# addr = 0xd273 + x * 11
#elif datatype == "n":
# addr = 0xd2b5 + x * 11
#else:
# return None
addr = 0xd16b + x * 0x2c
return pm(addr, "p")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment