· 7 years ago · Sep 05, 2018, 01:24 AM
1import io
2import json
3import logging
4import os
5import platform
6import struct
7import subprocess
8import random
9import copy
10
11from Hints import buildGossipHints, buildBossRewardHints, buildGanonText
12from Utils import local_path, default_output_path
13from Items import ItemFactory, item_data
14from Messages import *
15from OcarinaSongs import Song, replace_songs, subsong
16
17TunicColors = {
18 "Kokiri Green": [0x1E, 0x69, 0x1B],
19 "Goron Red": [0x64, 0x14, 0x00],
20 "Zora Blue": [0x00, 0x3C, 0x64],
21 "Black": [0x30, 0x30, 0x30],
22 "White": [0xF0, 0xF0, 0xFF],
23 "Purple": [0x95, 0x30, 0x80],
24 "Yellow": [0xE0, 0xD8, 0x60],
25 "Orange": [0xE0, 0x79, 0x40],
26 "Pink": [0xFF, 0x90, 0xB3],
27 "Gray": [0xA0, 0xA0, 0xB0],
28 "Brown": [0x95, 0x59, 0x0A],
29 "Gold": [0xD8, 0xB0, 0x60],
30 "Silver": [0xD0, 0xF0, 0xFF],
31 "Beige": [0xC0, 0xA0, 0xA0],
32 "Teal": [0x30, 0xD0, 0xB0],
33 "Royal Blue": [0x40, 0x00, 0x90],
34 "Sonic Blue": [0x50, 0x90, 0xE0],
35 "Blood Red": [0x30, 0x10, 0x10],
36 "Blood Orange": [0xF0, 0x30, 0x30],
37 "NES Green": [0x00, 0xD0, 0x00],
38 "Dark Green": [0x00, 0x25, 0x18],
39 "Only": [80, 140, 240],
40}
41
42NaviColors = {
43 "White": [0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00],
44 "Green": [0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00],
45 "Light Blue": [0x96, 0x96, 0xFF, 0xFF, 0x96, 0x96, 0xFF, 0x00],
46 "Yellow": [0xFF, 0xFF, 0x00, 0xFF, 0xC8, 0x9B, 0x00, 0x00],
47 "Red": [0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00],
48 "Magenta": [0xFF, 0x00, 0xFF, 0xFF, 0xC8, 0x00, 0x9B, 0x00],
49 "Black": [0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00],
50 "Tatl": [0xFF, 0xFF, 0xFF, 0xFF, 0xC8, 0x98, 0x00, 0x00],
51 "Tael": [0x49, 0x14, 0x6C, 0xFF, 0xFF, 0x00, 0x00, 0x00],
52}
53
54
55def get_tunic_colors():
56 return list(TunicColors.keys())
57
58
59def get_tunic_color_options():
60 return ["Random Choice", "Completely Random"] + get_tunic_colors()
61
62
63def get_navi_colors():
64 return list(NaviColors.keys())
65
66
67def get_navi_color_options():
68 return ["Random Choice", "Completely Random"] + get_navi_colors()
69
70
71class LocalRom(object):
72 def __init__(self, settings, patch=True):
73 self.last_address = None
74
75 file = settings.rom
76 decomp_file = 'ZOOTDEC.z64'
77
78 os.chdir(os.path.dirname(os.path.realpath(__file__)))
79 # os.chdir(output_path(os.path.dirname(os.path.realpath(__file__))))
80
81 try:
82 # Read decompressed file if it exists
83 with open(decomp_file, 'rb') as stream:
84 self.buffer = read_rom(stream)
85 # This is mainly for validation testing, but just in case...
86 self.decompress_rom_file(decomp_file, decomp_file)
87 except Exception as ex:
88 # No decompressed file, instead read Input ROM
89 with open(file, 'rb') as stream:
90 self.buffer = read_rom(stream)
91 self.decompress_rom_file(file, decomp_file)
92
93 # Add file to maximum size
94 self.buffer.extend(bytearray([0x00] * (0x4000000 - len(self.buffer))))
95
96 def decompress_rom_file(self, file, decomp_file):
97 validCRC = [
98 [0xEC, 0x70, 0x11, 0xB7, 0x76, 0x16, 0xD7, 0x2B], # Compressed
99 [0x70, 0xEC, 0xB7, 0x11, 0x16, 0x76, 0x2B, 0xD7], # Byteswap compressed
100 [0x93, 0x52, 0x2E, 0x7B, 0xE5, 0x06, 0xD4, 0x27], # Decompressed
101 ]
102
103 # Validate ROM file
104 file_name = os.path.splitext(file)
105 romCRC = list(self.buffer[0x10:0x18])
106 if romCRC not in validCRC:
107 # Bad CRC validation
108 raise RuntimeError('ROM file %s is not a valid OoT 1.0 US ROM.' % file)
109 elif len(self.buffer) < 0x2000000 or len(self.buffer) > (0x4000000) or file_name[1] not in ['.z64', '.n64']:
110 # ROM is too big, or too small, or not a bad type
111 raise RuntimeError('ROM file %s is not a valid OoT 1.0 US ROM.' % file)
112 elif len(self.buffer) == 0x2000000:
113 # If Input ROM is compressed, then Decompress it
114 if platform.system() == 'Windows':
115 if 8 * struct.calcsize("P") == 64:
116 subprocess.call(["Decompress\\Decompress.exe", file, decomp_file])
117 else:
118 subprocess.call(["Decompress\\Decompress32.exe", file, decomp_file])
119 with open(decomp_file, 'rb') as stream:
120 self.buffer = read_rom(stream)
121 elif platform.system() == 'Linux':
122 subprocess.call(["Decompress/Decompress", file])
123 with open(("ZOOTDEC.z64"), 'rb') as stream:
124 self.buffer = read_rom(stream)
125 elif platform.system() == 'Darwin':
126 subprocess.call(["Decompress/Decompress.out", file])
127 with open(("ZOOTDEC.z64"), 'rb') as stream:
128 self.buffer = read_rom(stream)
129 else:
130 raise RuntimeError(
131 'Unsupported operating system for decompression. Please supply an already decompressed ROM.')
132 else:
133 # ROM file is a valid and already uncompressed
134 pass
135
136 def seek_address(self, address):
137 self.last_address = address
138
139 def read_byte(self, address):
140 self.last_address = address + 1
141 return self.buffer[address]
142
143 def read_bytes(self, address, len):
144 self.last_address = address + len
145 return self.buffer[address: address + len]
146
147 def read_int16(self, address):
148 return bytes_as_int16(self.read_bytes(address, 2))
149
150 def read_int24(self, address):
151 return bytes_as_int24(self.read_bytes(address, 3))
152
153 def read_int32(self, address):
154 return bytes_as_int32(self.read_bytes(address, 4))
155
156 def write_byte(self, address, value):
157 if address == None:
158 address = self.last_address
159 self.buffer[address] = value
160 self.last_address = address + 1
161
162 def write_int16(self, address, value):
163 if address == None:
164 address = self.last_address
165 self.write_bytes(address, int16_as_bytes(value))
166
167 def write_int24(self, address, value):
168 if address == None:
169 address = self.last_address
170 self.write_bytes(address, int24_as_bytes(value))
171
172 def write_int32(self, address, value):
173 if address == None:
174 address = self.last_address
175 self.write_bytes(address, int32_as_bytes(value))
176
177 def write_bytes(self, startaddress, values):
178 if startaddress == None:
179 startaddress = self.last_address
180 for i, value in enumerate(values):
181 self.write_byte(startaddress + i, value)
182
183 def write_int16s(self, startaddress, values):
184 if startaddress == None:
185 startaddress = self.last_address
186 for i, value in enumerate(values):
187 self.write_int16(startaddress + (i * 2), value)
188
189 def write_int24s(self, startaddress, values):
190 if startaddress == None:
191 startaddress = self.last_address
192 for i, value in enumerate(values):
193 self.write_int24(startaddress + (i * 3), value)
194
195 def write_int32s(self, startaddress, values):
196 if startaddress == None:
197 startaddress = self.last_address
198 for i, value in enumerate(values):
199 self.write_int32(startaddress + (i * 4), value)
200
201 def write_to_file(self, file):
202 self.update_crc()
203 with open(file, 'wb') as outfile:
204 outfile.write(self.buffer)
205
206 def update_crc(self):
207 t1 = t2 = t3 = t4 = t5 = t6 = 0xDF26F436
208 u32 = 0xFFFFFFFF
209
210 cur = 0x1000
211 while cur < 0x00101000:
212 d = self.read_int32(cur)
213
214 if ((t6 + d) & u32) < t6:
215 t4 += 1
216
217 t6 = (t6 + d) & u32
218 t3 ^= d
219 shift = d & 0x1F
220 r = ((d << shift) | (d >> (32 - shift))) & u32
221 t5 = (t5 + r) & u32
222
223 if t2 > d:
224 t2 ^= r
225 else:
226 t2 ^= t6 ^ d
227
228 data2 = self.read_int32(0x750 + (cur & 0xFF))
229 t1 += data2 ^ d
230 t1 &= u32
231
232 cur += 4
233
234 crc0 = t6 ^ t4 ^ t3
235 crc1 = t5 ^ t2 ^ t1
236
237 # Finally write the crc back to the rom
238 self.write_int32s(0x10, [crc0, crc1])
239
240
241def read_rom(stream):
242 "Reads rom into bytearray"
243 buffer = bytearray(stream.read())
244 return buffer
245
246
247def int16_as_bytes(value):
248 value = value & 0xFFFF
249 return [(value >> 8) & 0xFF, value & 0xFF]
250
251
252def int24_as_bytes(value):
253 value = value & 0xFFFFFFFF
254 return [(value >> 16) & 0xFF, (value >> 8) & 0xFF, value & 0xFF]
255
256
257def int32_as_bytes(value):
258 value = value & 0xFFFFFFFF
259 return [(value >> 24) & 0xFF, (value >> 16) & 0xFF, (value >> 8) & 0xFF, value & 0xFF]
260
261
262def bytes_as_int16(values):
263 return (values[0] << 8) | values[1]
264
265
266def bytes_as_int24(values):
267 return (values[0] << 16) | (values[1] << 8) | values[2]
268
269
270def bytes_as_int32(values):
271 return (values[0] << 24) | (values[1] << 16) | (values[2] << 8) | values[3]
272
273
274def patch_rom(world, rom):
275 with open(local_path('data/base2current.json'), 'r') as stream:
276 patches = json.load(stream)
277 for patch in patches:
278 if isinstance(patch, dict):
279 for baseaddress, values in patch.items():
280 rom.write_bytes(int(baseaddress), values)
281
282 # Can always return to youth
283 rom.write_byte(0xCB6844, 0x35)
284 rom.write_byte(0x253C0E2, 0x03) # Moves sheik from pedestal
285
286 # Fix child shooting gallery reward to be static
287 rom.write_bytes(0xD35EFC, [0x00, 0x00, 0x00, 0x00])
288
289 # Fix target in woods reward to be static
290 rom.write_bytes(0xE59CD4, [0x00, 0x00, 0x00, 0x00])
291
292 # Fix GS rewards to be static
293 rom.write_bytes(0xEA3934, [0x00, 0x00, 0x00, 0x00])
294 rom.write_bytes(0xEA3940, [0x10, 0x00])
295
296 # Fix horseback archery rewards to be static
297 rom.write_byte(0xE12BA5, 0x00)
298 rom.write_byte(0xE12ADD, 0x00)
299
300 # Fix adult shooting gallery reward to be static
301 rom.write_byte(0xD35F55, 0x00)
302
303 # Fix deku theater rewards to be static
304 rom.write_bytes(0xEC9A7C, [0x00, 0x00, 0x00, 0x00]) # Sticks
305 rom.write_byte(0xEC9CD5, 0x00) # Nuts
306
307 # Fix deku scrub who sells stick upgrade
308 rom.write_bytes(0xDF8060, [0x00, 0x00, 0x00, 0x00])
309
310 # Fix deku scrub who sells nut upgrade
311 rom.write_bytes(0xDF80D4, [0x00, 0x00, 0x00, 0x00])
312
313 # Fix rolling goron as child reward to be static
314 rom.write_bytes(0xED2960, [0x00, 0x00, 0x00, 0x00])
315
316 # Fix proximity text boxes (Navi) (Part 1)
317 rom.write_bytes(0xDF8B84, [0x00, 0x00, 0x00, 0x00])
318
319 # Fix final magic bean to cost 99
320 rom.write_byte(0xE20A0F, 0x63)
321 rom.write_bytes(0x94FCDD, [0x08, 0x39, 0x39])
322
323 # Remove intro cutscene
324 rom.write_bytes(0xB06BBA, [0x00, 0x00])
325
326 # Remove locked door to Boss Key Chest in Fire Temple
327 rom.write_byte(0x22D82B7, 0x3F)
328
329 # Change Bombchi Shop to be always open
330 rom.write_int32(0xC6CEDC, 0x240B0001) # li t3, 1
331
332 if world.bombchus_in_logic:
333 # Change Bowling Alley check to bombchus (Part 1)
334 rom.write_bytes(0x00E2D714, [0x81, 0xEF, 0xA6, 0x4C])
335 rom.write_bytes(0x00E2D720, [0x24, 0x18, 0x00, 0x09, 0x11, 0xF8, 0x00, 0x06])
336
337 # Change Bowling Alley check to bombchus (Part 2)
338 rom.write_bytes(0x00E2D890, [0x81, 0x6B, 0xA6, 0x4C, 0x24, 0x0C, 0x00, 0x09, 0x51, 0x6C, 0x00, 0x0A])
339
340 # Cannot buy bombchu refills without Bombchus
341 rom.write_int32s(0xC01078,
342 [0x3C098012, # lui t1, 0x8012
343 0x812AA64C, # lb t2, -0x59B4(t1) ; bombchu item (SAVE_CONTEXT + 0x7C)
344 0x340B0009, # li t3, 9
345 0x114B0002, # beq t2, t3, @@return ; if has bombchu, return 1 (can buy)
346 0x34020000, # li v0, 0
347 0x34020002]) # li v0, 2 ; else, return 2 (can't buy)
348 else:
349 # Change Bowling Alley check to Bomb Bag (Part 1)
350 rom.write_bytes(0x00E2D716, [0xA6, 0x72])
351 rom.write_byte(0x00E2D723, 0x18)
352
353 # Change Bowling Alley check to Bomb Bag (Part 2)
354 rom.write_bytes(0x00E2D892, [0xA6, 0x72])
355 rom.write_byte(0x00E2D897, 0x18)
356
357 # Change Bazaar check to Bomb Bag (Child?)
358 rom.write_bytes(0x00C0082A, [0x00, 0x18])
359 rom.write_bytes(0x00C0082C, [0x00, 0x0E, 0X74, 0X02])
360 rom.write_byte(0x00C00833, 0xA0)
361
362 # Change Bazaar check to Bomb Bag (Adult?)
363 rom.write_bytes(0x00DF7A8E, [0x00, 0x18])
364 rom.write_bytes(0x00DF7A90, [0x00, 0x0E, 0X74, 0X02])
365 rom.write_byte(0x00DF7A97, 0xA0)
366
367 # Change Goron Shop check to Bomb Bag
368 rom.write_bytes(0x00C6ED86, [0x00, 0xA2])
369 rom.write_bytes(0x00C6ED8A, [0x00, 0x18])
370
371 # Change graveyard graves to not allow grabbing on to the ledge
372 rom.write_byte(0x0202039D, 0x20)
373 rom.write_byte(0x0202043C, 0x24)
374
375 # Fix Link the Goron to always work
376 rom.write_bytes(0xED2FAC, [0x80, 0x6E, 0x0F, 0x18])
377 rom.write_bytes(0xED2FEC, [0x24, 0x0A, 0x00, 0x00])
378 rom.write_bytes(0xAE74D8, [0x24, 0x0E, 0x00, 0x00])
379
380 # Fix King Zora Thawed to always work
381 rom.write_bytes(0xE55C4C, [0x00, 0x00, 0x00, 0x00])
382 rom.write_bytes(0xE56290, [0x00, 0x00, 0x00, 0x00])
383 rom.write_bytes(0xE56298, [0x00, 0x00, 0x00, 0x00])
384
385 # Fix Castle Courtyard to check for meeting Zelda, not Zelda fleeing, to block you
386 rom.write_bytes(0xCD5E76, [0x0E, 0xDC])
387 rom.write_bytes(0xCD5E12, [0x0E, 0xDC])
388
389 # Cutscene for all medallions never triggers when leaving shadow or spirit temples(hopefully stops warp to colossus on shadow completion with boss reward shuffle)
390 rom.write_byte(0xACA409, 0xAD)
391 rom.write_byte(0xACA49D, 0xCE)
392
393 # Speed Zelda's Letter scene
394
395
396 # Speed Zelda escaping from Hyrule Castle
397
398
399 # Speed learning Zelda's Lullaby
400 rom.write_int32s(0x02E8E90C, [0x000003E8, 0x00000001]) # Terminator Execution
401 if world.shuffle_song_items:
402 rom.write_int16s(None, [0x0073, 0x001, 0x0002, 0x0002]) # ID, start, end, end
403 else:
404 rom.write_int16s(None, [0x0073, 0x003B, 0x003C, 0x003C]) # ID, start, end, end
405
406 rom.write_int32s(0x02E8E91C, [0x00000013, 0x0000000C]) # Textbox, Count
407 if world.shuffle_song_items:
408 rom.write_int16s(None, [0xFFFF, 0x0000, 0x0010, 0xFFFF, 0xFFFF, 0xFFFF]) # ID, start, end, type, alt1, alt2
409 else:
410 rom.write_int16s(None,
411 [0x0017, 0x0000, 0x0010, 0x0002, 0x088B, 0xFFFF]) # ID, start, end, type, alt1, alt2
412 rom.write_int16s(None, [0x00D4, 0x0011, 0x0020, 0x0000, 0xFFFF, 0xFFFF]) # ID, start, end, type, alt1, alt2
413
414 # Speed learning Sun's Song
415 if world.shuffle_song_items:
416 rom.write_int32(0x0332A4A4, 0xFFFFFFFF) # Header: frame_count
417 else:
418 rom.write_int32(0x0332A4A4, 0x0000003C) # Header: frame_count
419
420 rom.write_int32s(0x0332A868, [0x00000013, 0x00000008]) # Textbox, Count
421 rom.write_int16s(None, [0x0018, 0x0000, 0x0010, 0x0002, 0x088B, 0xFFFF]) # ID, start, end, type, alt1, alt2
422 rom.write_int16s(None, [0x00D3, 0x0011, 0x0020, 0x0000, 0xFFFF, 0xFFFF]) # ID, start, end, type, alt1, alt2
423
424 # Speed learning Saria's Song
425 if world.shuffle_song_items:
426 rom.write_int32(0x020B1734, 0xFFFFFFFF) # Header: frame_count
427 else:
428 rom.write_int32(0x020B1734, 0x0000003C) # Header: frame_count
429
430 rom.write_int32s(0x20B1DA8, [0x00000013, 0x0000000C]) # Textbox, Count
431 rom.write_int16s(None, [0x0015, 0x0000, 0x0010, 0x0002, 0x088B, 0xFFFF]) # ID, start, end, type, alt1, alt2
432 rom.write_int16s(None, [0x00D1, 0x0011, 0x0020, 0x0000, 0xFFFF, 0xFFFF]) # ID, start, end, type, alt1, alt2
433
434 rom.write_int32s(0x020B19C0, [0x0000000A, 0x00000006]) # Link, Count
435 rom.write_int16s(0x020B19C8, [0x0011, 0x0000, 0x0010, 0x0000]) # action, start, end, ????
436 rom.write_int16s(0x020B19F8, [0x003E, 0x0011, 0x0020, 0x0000]) # action, start, end, ????
437 rom.write_int32s(None, [0x80000000, # ???
438 0x00000000, 0x000001D4, 0xFFFFF731, # start_XYZ
439 0x00000000, 0x000001D4, 0xFFFFF712]) # end_XYZ
440
441 # Speed learning Epona's Song
442 rom.write_int32s(0x029BEF60, [0x000003E8, 0x00000001]) # Terminator Execution
443 if world.shuffle_song_items:
444 rom.write_int16s(None, [0x005E, 0x0001, 0x0002, 0x0002]) # ID, start, end, end
445 else:
446 rom.write_int16s(None, [0x005E, 0x000A, 0x000B, 0x000B]) # ID, start, end, end
447
448 rom.write_int32s(0x029BECB0, [0x00000013, 0x00000002]) # Textbox, Count
449 if world.shuffle_song_items:
450 rom.write_int16s(None, [0xFFFF, 0x0000, 0x0009, 0xFFFF, 0xFFFF, 0xFFFF]) # ID, start, end, type, alt1, alt2
451 else:
452 rom.write_int16s(None, [0x00D2, 0x0000, 0x0009, 0x0000, 0xFFFF, 0xFFFF]) # ID, start, end, type, alt1, alt2
453 rom.write_int16s(None, [0xFFFF, 0x000A, 0x003C, 0xFFFF, 0xFFFF, 0xFFFF]) # ID, start, end, type, alt1, alt2
454
455 # Speed learning Song of Time
456 rom.write_int32s(0x0252FB98, [0x000003E8, 0x00000001]) # Terminator Execution
457 if world.shuffle_song_items:
458 rom.write_int16s(None, [0x0035, 0x0001, 0x0002, 0x0002]) # ID, start, end, end
459 else:
460 rom.write_int16s(None, [0x0035, 0x003B, 0x003C, 0x003C]) # ID, start, end, end
461
462 rom.write_int32s(0x0252FC80, [0x00000013, 0x0000000C]) # Textbox, Count
463 if world.shuffle_song_items:
464 rom.write_int16s(None, [0xFFFF, 0x0000, 0x0010, 0xFFFF, 0xFFFF, 0xFFFF]) # ID, start, end, type, alt1, alt2
465 else:
466 rom.write_int16s(None,
467 [0x0019, 0x0000, 0x0010, 0x0002, 0x088B, 0xFFFF]) # ID, start, end, type, alt1, alt2
468 rom.write_int16s(None, [0x00D5, 0x0011, 0x0020, 0x0000, 0xFFFF, 0xFFFF]) # ID, start, end, type, alt1, alt2
469
470 rom.write_int32(0x01FC3B84, 0xFFFFFFFF) # Other Header?: frame_count
471
472 # Speed learning Song of Storms
473 if world.shuffle_song_items:
474 rom.write_int32(0x03041084, 0xFFFFFFFF) # Header: frame_count
475 else:
476 rom.write_int32(0x03041084, 0x0000000A) # Header: frame_count
477
478 rom.write_int32s(0x03041088, [0x00000013, 0x00000002]) # Textbox, Count
479 rom.write_int16s(None, [0x00D6, 0x0000, 0x0009, 0x0000, 0xFFFF, 0xFFFF]) # ID, start, end, type, alt1, alt2
480 rom.write_int16s(None, [0xFFFF, 0x00BE, 0x00C8, 0xFFFF, 0xFFFF, 0xFFFF]) # ID, start, end, type, alt1, alt2
481
482 # Speed learning Minuet of Forest
483 if world.shuffle_song_items:
484 rom.write_int32(0x020AFF84, 0xFFFFFFFF) # Header: frame_count
485 else:
486 rom.write_int32(0x020AFF84, 0x0000003C) # Header: frame_count
487
488 rom.write_int32s(0x020B0800, [0x00000013, 0x0000000A]) # Textbox, Count
489 rom.write_int16s(None, [0x000F, 0x0000, 0x0010, 0x0002, 0x088B, 0xFFFF]) # ID, start, end, type, alt1, alt2
490 rom.write_int16s(None, [0x0073, 0x0011, 0x0020, 0x0000, 0xFFFF, 0xFFFF]) # ID, start, end, type, alt1, alt2
491
492 rom.write_int32s(0x020AFF88, [0x0000000A, 0x00000005]) # Link, Count
493 rom.write_int16s(0x020AFF90, [0x0011, 0x0000, 0x0010, 0x0000]) # action, start, end, ????
494 rom.write_int16s(0x020AFFC1, [0x003E, 0x0011, 0x0020, 0x0000]) # action, start, end, ????
495
496 rom.write_int32s(0x020B0488, [0x00000056, 0x00000001]) # Music Change, Count
497 rom.write_int16s(None, [0x003F, 0x0021, 0x0022, 0x0000]) # action, start, end, ????
498
499 rom.write_int32s(0x020B04C0, [0x0000007C, 0x00000001]) # Music Fade Out, Count
500 rom.write_int16s(None, [0x0004, 0x0000, 0x0000, 0x0000]) # action, start, end, ????
501
502 # Speed learning Bolero of Fire
503 if world.shuffle_song_items:
504 rom.write_int32(0x0224B5D4, 0xFFFFFFFF) # Header: frame_count
505 else:
506 rom.write_int32(0x0224B5D4, 0x0000003C) # Header: frame_count
507
508 rom.write_int32s(0x0224D7E8, [0x00000013, 0x0000000A]) # Textbox, Count
509 rom.write_int16s(None, [0x0010, 0x0000, 0x0010, 0x0002, 0x088B, 0xFFFF]) # ID, start, end, type, alt1, alt2
510 rom.write_int16s(None, [0x0074, 0x0011, 0x0020, 0x0000, 0xFFFF, 0xFFFF]) # ID, start, end, type, alt1, alt2
511
512 rom.write_int32s(0x0224B5D8, [0x0000000A, 0x0000000B]) # Link, Count
513 rom.write_int16s(0x0224B5E0, [0x0011, 0x0000, 0x0010, 0x0000]) # action, start, end, ????
514 rom.write_int16s(0x0224B610, [0x003E, 0x0011, 0x0020, 0x0000]) # action, start, end, ????
515
516 rom.write_int32s(0x0224B7F0, [0x0000002F, 0x0000000E]) # Sheik, Count
517 rom.write_int16s(0x0224B7F8, [0x0000]) # action
518 rom.write_int16s(0x0224B828, [0x0000]) # action
519 rom.write_int16s(0x0224B858, [0x0000]) # action
520 rom.write_int16s(0x0224B888, [0x0000]) # action
521
522 # Speed learning Serenade of Water
523 if world.shuffle_song_items:
524 rom.write_int32(0x02BEB254, 0xFFFFFFFF) # Header: frame_count
525 else:
526 rom.write_int32(0x02BEB254, 0x0000003C) # Header: frame_count
527
528 rom.write_int32s(0x02BEC880, [0x00000013, 0x00000010]) # Textbox, Count
529 rom.write_int16s(None, [0x0011, 0x0000, 0x0010, 0x0002, 0x088B, 0xFFFF]) # ID, start, end, type, alt1, alt2
530 rom.write_int16s(None, [0x0075, 0x0011, 0x0020, 0x0000, 0xFFFF, 0xFFFF]) # ID, start, end, type, alt1, alt2
531
532 rom.write_int32s(0x02BEB258, [0x0000000A, 0x0000000F]) # Link, Count
533 rom.write_int16s(0x02BEB260, [0x0011, 0x0000, 0x0010, 0x0000]) # action, start, end, ????
534 rom.write_int16s(0x02BEB290, [0x003E, 0x0011, 0x0020, 0x0000]) # action, start, end, ????
535
536 rom.write_int32s(0x02BEB530, [0x0000002F, 0x00000006]) # Sheik, Count
537 rom.write_int16s(0x02BEB538, [0x0000, 0x0000, 0x018A, 0x0000]) # action, start, end, ????
538 rom.write_int32s(None, [0x1BBB0000, # ???
539 0xFFFFFB10, 0x8000011A, 0x00000330, # start_XYZ
540 0xFFFFFB10, 0x8000011A, 0x00000330]) # end_XYZ
541
542 rom.write_int32s(0x02BEC848, [0x00000056, 0x00000001]) # Music Change, Count
543 rom.write_int16s(None, [0x0059, 0x0021, 0x0022, 0x0000]) # action, start, end, ????
544
545 # Speed learning Nocturne of Shadow
546 rom.write_int32s(0x01FFE458, [0x000003E8, 0x00000001]) # Other Scene? Terminator Execution
547 rom.write_int16s(None, [0x002F, 0x0001, 0x0002, 0x0002]) # ID, start, end, end
548
549 rom.write_int32(0x01FFFDF4, 0x0000003C) # Header: frame_count
550
551 rom.write_int32s(0x02000FD8, [0x00000013, 0x0000000E]) # Textbox, Count
552 if world.shuffle_song_items:
553 rom.write_int16s(None, [0xFFFF, 0x0000, 0x0010, 0xFFFF, 0xFFFF, 0xFFFF]) # ID, start, end, type, alt1, alt2
554 else:
555 rom.write_int16s(None, [0x0013, 0x0000, 0x0010, 0x0002, 0x088B, 0xFFFF]) # ID, start, end, type, alt1, alt2
556 rom.write_int16s(None, [0x0077, 0x0011, 0x0020, 0x0000, 0xFFFF, 0xFFFF]) # ID, start, end, type, alt1, alt2
557
558 rom.write_int32s(0x02000128, [0x000003E8, 0x00000001]) # Terminator Execution
559 if world.shuffle_song_items:
560 rom.write_int16s(None, [0x0032, 0x0001, 0x0002, 0x0002]) # ID, start, end, end
561 else:
562 rom.write_int16s(None, [0x0032, 0x003A, 0x003B, 0x003B]) # ID, start, end, end
563
564 # Speed learning Requiem of Spirit
565 rom.write_int32(0x0218AF14, 0x0000003C) # Header: frame_count
566
567 rom.write_int32s(0x0218C574, [0x00000013, 0x00000008]) # Textbox, Count
568 if world.shuffle_song_items:
569 rom.write_int16s(None,
570 [0xFFFF, 0x0000, 0x0010, 0xFFFF, 0xFFFF, 0xFFFF]) # ID, start, end, type, alt1, alt2
571 else:
572 rom.write_int16s(None,
573 [0x0012, 0x0000, 0x0010, 0x0002, 0x088B, 0xFFFF]) # ID, start, end, type, alt1, alt2
574 rom.write_int16s(None, [0x0076, 0x0011, 0x0020, 0x0000, 0xFFFF, 0xFFFF]) # ID, start, end, type, alt1, alt2
575
576 rom.write_int32s(0x0218B478, [0x000003E8, 0x00000001]) # Terminator Execution
577 if world.shuffle_song_items:
578 rom.write_int16s(None, [0x0030, 0x0001, 0x0002, 0x0002]) # ID, start, end, end
579 else:
580 rom.write_int16s(None, [0x0030, 0x003A, 0x003B, 0x003B]) # ID, start, end, end
581
582 rom.write_int32s(0x0218AF18, [0x0000000A, 0x0000000B]) # Link, Count
583 rom.write_int16s(0x0218AF20, [0x0011, 0x0000, 0x0010, 0x0000]) # action, start, end, ????
584 rom.write_int32s(None, [0x40000000, # ???
585 0xFFFFFAF9, 0x00000008, 0x00000001, # start_XYZ
586 0xFFFFFAF9, 0x00000008, 0x00000001, # end_XYZ
587 0x0F671408, 0x00000000, 0x00000001]) # normal_XYZ
588 rom.write_int16s(0x0218AF50, [0x003E, 0x0011, 0x0020, 0x0000]) # action, start, end, ????
589
590 # Speed learning Prelude of Light
591 if world.shuffle_song_items:
592 rom.write_int32(0x0252FD24, 0xFFFFFFFF) # Header: frame_count
593 else:
594 rom.write_int32(0x0252FD24, 0x0000003C) # Header: frame_count
595
596 rom.write_int32s(0x02531320, [0x00000013, 0x0000000E]) # Textbox, Count
597 rom.write_int16s(None, [0x0014, 0x0000, 0x0010, 0x0002, 0x088B, 0xFFFF]) # ID, start, end, type, alt1, alt2
598 rom.write_int16s(None, [0x0078, 0x0011, 0x0020, 0x0000, 0xFFFF, 0xFFFF]) # ID, start, end, type, alt1, alt2
599
600 rom.write_int32s(0x0252FF10, [0x0000002F, 0x00000009]) # Sheik, Count
601 rom.write_int16s(0x0252FF18, [0x0006, 0x0000, 0x0000, 0x0000]) # action, start, end, ????
602
603 rom.write_int32s(0x025313D0, [0x00000056, 0x00000001]) # Music Change, Count
604 rom.write_int16s(None, [0x003B, 0x0021, 0x0022, 0x0000]) # action, start, end, ????
605
606 # Speed scene after Deku Tree
607
608
609 # Speed scene after Dodongo's Cavern
610
611
612 # Speed obtaining Fairy Ocarina
613 rom.write_bytes(0x2150CD0, [0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x30])
614 Block_code = [0xFF, 0xFF, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
615 0xFF, 0xFF, 0x00, 0x3C, 0x00, 0x81, 0xFF, 0xFF]
616 rom.write_bytes(0x2151240, Block_code)
617 rom.write_bytes(0x2150E20, [0xFF, 0xFF, 0xFA, 0x4C])
618
619 # Speed Zelda Light Arrow cutscene
620
621
622 # Speed Bridge of Light cutscene
623
624
625 # Remove remaining owls
626 rom.write_bytes(0x1FE30CE, [0x01, 0x4B])
627 rom.write_bytes(0x1FE30DE, [0x01, 0x4B])
628 rom.write_bytes(0x1FE30EE, [0x01, 0x4B])
629 rom.write_bytes(0x205909E, [0x00, 0x3F])
630 rom.write_byte(0x2059094, 0x80)
631
632 # Darunia will dance
633 #rom.write_bytes(0x22769E4, [0xFF, 0xFF, 0xFF, 0xFF])
634
635 # Zora moves quickly
636 rom.write_bytes(0xE56924, [0x00, 0x00, 0x00, 0x00])
637
638 # Speed Jabu Jabu swallowing Link
639 #rom.write_bytes(0xCA0784, [0x00, 0x18, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02])
640
641 # Ruto no longer points to Zora Sapphire
642 #rom.write_bytes(0xD03BAC, [0xFF, 0xFF, 0xFF, 0xFF])
643
644 # Ruto never disappears from Jabu Jabu's Belly
645 rom.write_byte(0xD01EA3, 0x00)
646
647 # Speed up Epona race start
648 rom.write_bytes(0x29BE984, [0x00, 0x00, 0x00, 0x02])
649 rom.write_bytes(0x29BE9CA, [0x00, 0x01, 0x00, 0x02])
650
651 # Speed start of Horseback Archery
652 # rom.write_bytes(0x21B2064, [0x00, 0x00, 0x00, 0x02])
653 # rom.write_bytes(0x21B20AA, [0x00, 0x01, 0x00, 0x02])
654
655 # Speed up Epona escape
656 #rom.write_bytes(0x1FC8B36, [0x00, 0x2A])
657
658 # Speed up draining the well
659
660
661 # Speed up opening the royal tomb for both child and adult
662
663
664 # Speed opening of Door of Time
665 #rom.write_bytes(0xE0A176, [0x00, 0x02])
666 #rom.write_bytes(0xE0A35A, [0x00, 0x01, 0x00, 0x02])
667
668 # Poacher's Saw no longer messes up Deku Theater
669 rom.write_bytes(0xAE72CC, [0x00, 0x00, 0x00, 0x00])
670
671 # Learning Serenade tied to opening chest in room
672 Block_code = [0x3C, 0x0F, 0x80, 0x1D, 0x81, 0xE8, 0xA1, 0xDB, 0x24, 0x19, 0x00, 0x04,
673 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8C, 0xA2, 0x1C, 0x44,
674 0x00, 0x00, 0x00, 0x00]
675 rom.write_bytes(0xC7BCF0, Block_code)
676
677 # Dampe Chest spawn condition looks at chest flag instead of having obtained hookshot
678 Block_code = [0x93, 0x18, 0xAE, 0x7E, 0x27, 0xA5, 0x00, 0x24, 0x33, 0x19, 0x00, 0x01,
679 0x00, 0x00, 0x00, 0x00]
680 rom.write_bytes(0xDFEC40, Block_code)
681
682 # Darunia sets an event flag and checks for it
683 Block_code = [0x24, 0x19, 0x00, 0x40, 0x8F, 0x09, 0xB4, 0xA8, 0x01, 0x39, 0x40, 0x24,
684 0x01, 0x39, 0xC8, 0x25, 0xAF, 0x19, 0xB4, 0xA8, 0x24, 0x09, 0x00, 0x06]
685 rom.write_bytes(0xCF1AB8, Block_code)
686
687 # Change Prelude CS to check for medallion
688 rom.write_bytes(0x00C805E6, [0x00, 0xA6])
689 rom.write_bytes(0x00C805F2, [0x00, 0x01])
690
691 # Change Nocturne CS to check for medallions
692 rom.write_bytes(0x00ACCD8E, [0x00, 0xA6])
693 rom.write_bytes(0x00ACCD92, [0x00, 0x01])
694 rom.write_bytes(0x00ACCD9A, [0x00, 0x02])
695 rom.write_bytes(0x00ACCDA2, [0x00, 0x04])
696
697 # Change King Zora to move even if Zora Sapphire is in inventory
698 rom.write_bytes(0x00E55BB0, [0x85, 0xCE, 0x8C, 0x3C])
699 rom.write_bytes(0x00E55BB4, [0x84, 0x4F, 0x0E, 0xDA])
700
701 # Remove extra Forest Temple medallions
702 rom.write_bytes(0x00D4D37C, [0x00, 0x00, 0x00, 0x00])
703
704 # Remove extra Fire Temple medallions
705 rom.write_bytes(0x00AC9754, [0x00, 0x00, 0x00, 0x00])
706 rom.write_bytes(0x00D0DB8C, [0x00, 0x00, 0x00, 0x00])
707
708 # Remove extra Water Temple medallions
709 rom.write_bytes(0x00D57F94, [0x00, 0x00, 0x00, 0x00])
710
711 # Remove extra Spirit Temple medallions
712 rom.write_bytes(0x00D370C4, [0x00, 0x00, 0x00, 0x00])
713 rom.write_bytes(0x00D379C4, [0x00, 0x00, 0x00, 0x00])
714
715 # Remove extra Shadow Temple medallions
716 rom.write_bytes(0x00D116E0, [0x00, 0x00, 0x00, 0x00])
717
718 # Change Mido, Saria, and Kokiri to check for Deku Tree complete flag
719 # bitwise pointer for 0x80
720 kokiriAddresses = [0xE52836, 0xE53A56, 0xE51D4E, 0xE51F3E, 0xE51D96, 0xE51E1E, 0xE51E7E, 0xE51EDE, 0xE51FC6,
721 0xE51F96, 0xE293B6, 0xE29B8E, 0xE62EDA, 0xE630D6, 0xE62642, 0xE633AA, 0xE6369E]
722 for kokiri in kokiriAddresses:
723 rom.write_bytes(kokiri, [0x8C, 0x0C])
724 # Kokiri
725 rom.write_bytes(0xE52838, [0x94, 0x48, 0x0E, 0xD4])
726 rom.write_bytes(0xE53A58, [0x94, 0x49, 0x0E, 0xD4])
727 rom.write_bytes(0xE51D50, [0x94, 0x58, 0x0E, 0xD4])
728 rom.write_bytes(0xE51F40, [0x94, 0x4B, 0x0E, 0xD4])
729 rom.write_bytes(0xE51D98, [0x94, 0x4B, 0x0E, 0xD4])
730 rom.write_bytes(0xE51E20, [0x94, 0x4A, 0x0E, 0xD4])
731 rom.write_bytes(0xE51E80, [0x94, 0x59, 0x0E, 0xD4])
732 rom.write_bytes(0xE51EE0, [0x94, 0x4E, 0x0E, 0xD4])
733 rom.write_bytes(0xE51FC8, [0x94, 0x49, 0x0E, 0xD4])
734 rom.write_bytes(0xE51F98, [0x94, 0x58, 0x0E, 0xD4])
735 # Saria
736 rom.write_bytes(0xE293B8, [0x94, 0x78, 0x0E, 0xD4])
737 rom.write_bytes(0xE29B90, [0x94, 0x68, 0x0E, 0xD4])
738 # Mido
739 rom.write_bytes(0xE62EDC, [0x94, 0x6F, 0x0E, 0xD4])
740 rom.write_bytes(0xE630D8, [0x94, 0x4F, 0x0E, 0xD4])
741 rom.write_bytes(0xE62644, [0x94, 0x6F, 0x0E, 0xD4])
742 rom.write_bytes(0xE633AC, [0x94, 0x68, 0x0E, 0xD4])
743 rom.write_bytes(0xE636A0, [0x94, 0x48, 0x0E, 0xD4])
744
745 # Change adult Kokiri Forest to check for Forest Temple complete flag
746 rom.write_bytes(0xE5369E, [0xB4, 0xAC])
747 rom.write_bytes(0xD5A83C, [0x80, 0x49, 0x0E, 0xDC])
748
749 # Change adult Goron City to check for Fire Temple complete flag
750 rom.write_bytes(0xED59DC, [0x80, 0xC9, 0x0E, 0xDC])
751
752 # Change Pokey to check DT complete flag
753 rom.write_bytes(0xE5400A, [0x8C, 0x4C])
754 rom.write_bytes(0xE5400E, [0xB4, 0xA4])
755 if world.open_forest:
756 rom.write_bytes(0xE5401C, [0x14, 0x0B])
757
758 # Fix Shadow Temple to check for different rewards for scene
759 rom.write_bytes(0xCA3F32, [0x00, 0x00, 0x25, 0x4A, 0x00, 0x10])
760
761 # Fix Spirit Temple to check for different rewards for scene
762 rom.write_bytes(0xCA3EA2, [0x00, 0x00, 0x25, 0x4A, 0x00, 0x08])
763
764 # Fix Biggoron to check a different flag.
765 rom.write_byte(0xED329B, 0x72)
766 rom.write_byte(0xED43E7, 0x72)
767 rom.write_bytes(0xED3370, [0x3C, 0x0D, 0x80, 0x12])
768 rom.write_bytes(0xED3378, [0x91, 0xB8, 0xA6, 0x42, 0xA1, 0xA8, 0xA6, 0x42])
769 rom.write_bytes(0xED6574, [0x00, 0x00, 0x00, 0x00])
770
771 # Remove the check on the number of days that passed for claim check.
772 rom.write_bytes(0xED4470, [0x00, 0x00, 0x00, 0x00])
773 rom.write_bytes(0xED4498, [0x00, 0x00, 0x00, 0x00])
774
775 # Fixed reward order for Bombchu Bowling
776 rom.write_bytes(0xE2E698, [0x80, 0xAA, 0xE2, 0x64])
777 rom.write_bytes(0xE2E6A0, [0x80, 0xAA, 0xE2, 0x4C])
778 rom.write_bytes(0xE2D440, [0x24, 0x19, 0x00, 0x00])
779
780 # Make fishing less obnoxious
781 Block_code = [0x3C, 0x0A, 0x80, 0x12, 0x8D, 0x4A, 0xA5, 0xD4, 0x14, 0x0A, 0x00, 0x06,
782 0x31, 0x78, 0x00, 0x01, 0x14, 0x18, 0x00, 0x02, 0x3c, 0x18, 0x42, 0x30,
783 0x3C, 0x18, 0x42, 0x50, 0x03, 0xe0, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
784 0x14, 0x18, 0x00, 0x02, 0x3C, 0x18, 0x42, 0x10, 0x3C, 0x18, 0x42, 0x38,
785 0x03, 0xE0, 0x00, 0x08]
786 rom.write_bytes(0x3480C00, Block_code)
787 rom.write_bytes(0xDBF434, [0x44, 0x98, 0x90, 0x00, 0xE6, 0x52, 0x01, 0x9C])
788 rom.write_bytes(0xDBF484, [0x00, 0x00, 0x00, 0x00])
789 rom.write_bytes(0xDBF4A8, [0x00, 0x00, 0x00, 0x00])
790 rom.write_bytes(0xDCBEAA, [0x42, 0x48]) # set adult fish size requirement
791 rom.write_bytes(0xDCBF26, [0x42, 0x48]) # set adult fish size requirement
792 rom.write_bytes(0xDCBF32, [0x42, 0x30]) # set child fish size requirement
793 rom.write_bytes(0xDCBF9E, [0x42, 0x30]) # set child fish size requirement
794
795 # Dampe always digs something up and first dig is always the Piece of Heart
796 rom.write_bytes(0xCC3FA8, [0xA2, 0x01, 0x01, 0xF8])
797 rom.write_bytes(0xCC4024, [0x00, 0x00, 0x00, 0x00])
798
799 # Allow owl to always carry the kid down Death Mountain
800 rom.write_bytes(0xE304F0, [0x24, 0x0E, 0x00, 0x01])
801
802 # Forbid Sun's Song from a bunch of cutscenes
803 Suns_scenes = [0x2016FC9, 0x2017219, 0x20173D9, 0x20174C9, 0x2017679, 0x20C1539, 0x20C15D9, 0x21A0719, 0x21A07F9,
804 0x2E90129, 0x2E901B9, 0x2E90249, 0x225E829, 0x225E939, 0x306D009]
805 for address in Suns_scenes:
806 rom.write_byte(address, 0x01)
807
808 # Remove forcible text triggers
809 Wonder_text = [0x27C00C6, 0x27C00D6, 0x27C00E6, 0x27C00F6, 0x27C0106, 0x27C0116, 0x27C0126, 0x27C0136]
810 for address in Wonder_text:
811 rom.write_byte(address, 0x02)
812 rom.write_byte(0x27CE08A, 0x09)
813 rom.write_byte(0x27CE09A, 0x0F)
814 Wonder_text = [0x288707A, 0x288708A, 0x288709A, 0x289707A, 0x28C713E, 0x28D91C6]
815 for address in Wonder_text:
816 rom.write_byte(address, 0x0C)
817 Wonder_text = [0x28A60FE, 0x28AE08E, 0x28B917E, 0x28BF172, 0x28BF182, 0x28BF192]
818 for address in Wonder_text:
819 rom.write_byte(address, 0x0D)
820 rom.write_byte(0x28A114E, 0x0E)
821 rom.write_byte(0x28A610E, 0x0E)
822 Wonder_text = [0x9367F6, 0x93673D, 0x93679D]
823 for address in Wonder_text:
824 rom.write_byte(address, 0x08)
825 Wonder_text = [0x289707B, 0x28AE08F, 0x28C713F]
826 for address in Wonder_text:
827 rom.write_byte(address, 0xAF)
828 rom.write_byte(0x28A114F, 0x6F)
829 rom.write_byte(0x28B917F, 0x6F)
830 rom.write_byte(0x28A60FF, 0xEF)
831 rom.write_byte(0x28D91C7, 0xEF)
832 Wonder_text = [0x28A610F, 0x28BF173, 0x28BF183, 0x28BF193]
833 for address in Wonder_text:
834 rom.write_byte(address, 0x2F)
835 Wonder_text = [0x27CE08B, 0x27C00C7, 0x27C00D7, 0x27C0117, 0x27C0127]
836 for address in Wonder_text:
837 rom.write_byte(address, 0x3D)
838 rom.write_byte(0x27C00E7, 0x7D)
839 rom.write_byte(0x27C00F7, 0x7D)
840 rom.write_byte(0x27C0107, 0xBD)
841 rom.write_byte(0x27C0137, 0xBD)
842 Wonder_text = [0x27C00BC, 0x27C00CC, 0x27C00DC, 0x27C00EC, 0x27C00FC, 0x27C010C, 0x27C011C, 0x27C012C, 0x27CE080,
843 0x27CE090, 0x2887070, 0x2887080, 0x2887090, 0x2897070, 0x28C7134, 0x28D91BC, 0x28A60F4, 0x28AE084,
844 0x28B9174, 0x28BF168, 0x28BF178, 0x28BF188, 0x28A1144, 0x28A6104]
845 for address in Wonder_text:
846 rom.write_byte(address, 0xFE)
847
848 # Speed dig text for Dampe
849 rom.write_bytes(0x9532F8, [0x08, 0x08, 0x08, 0x59])
850
851 # Make item descriptions into a single box
852 Short_item_descriptions = [0x92EC84, 0x92F9E3, 0x92F2B4, 0x92F37A, 0x92F513, 0x92F5C6, 0x92E93B, 0x92EA12]
853 for address in Short_item_descriptions:
854 rom.write_byte(address, 0x02)
855
856 # Fix text for Pocket Cucco.
857 rom.write_byte(0xBEEF45, 0x0B)
858 rom.write_byte(0x92D41A, 0x2E)
859 Block_code = [0x59, 0x6f, 0x75, 0x20, 0x67, 0x6f, 0x74, 0x20, 0x61, 0x20, 0x05, 0x41,
860 0x50, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x20, 0x43, 0x75, 0x63, 0x63, 0x6f,
861 0x2c, 0x20, 0x05, 0x40, 0x6f, 0x6e, 0x65, 0x01, 0x6f, 0x66, 0x20, 0x41,
862 0x6e, 0x6a, 0x75, 0x27, 0x73, 0x20, 0x70, 0x72, 0x69, 0x7a, 0x65, 0x64,
863 0x20, 0x68, 0x65, 0x6e, 0x73, 0x21, 0x20, 0x49, 0x74, 0x20, 0x66, 0x69,
864 0x74, 0x73, 0x20, 0x01, 0x69, 0x6e, 0x20, 0x79, 0x6f, 0x75, 0x72, 0x20,
865 0x70, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x02]
866 rom.write_bytes(0x92D41C, Block_code)
867
868 # DMA in extra code
869 Block_code = [0xAF, 0xBF, 0x00, 0x1C, 0xAF, 0xA4, 0x01, 0x40, 0x3C, 0x05, 0x03, 0x48,
870 0x3C, 0x04, 0x80, 0x40, 0x0C, 0x00, 0x03, 0x7C, 0x24, 0x06, 0x50, 0x00,
871 0x0C, 0x10, 0x02, 0x00]
872 rom.write_bytes(0xB17BB4, Block_code)
873 Block_code = [0x3C, 0x02, 0x80, 0x12, 0x24, 0x42, 0xD2, 0xA0, 0x24, 0x0E, 0x01, 0x40,
874 0xAC, 0x2E, 0xE5, 0x00, 0x03, 0xE0, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00]
875 rom.write_bytes(0x3480800, Block_code)
876 rom.write_bytes(0xD270, [0x03, 0x48, 0x00, 0x00, 0x03, 0x48, 0x50, 0x00, 0x03, 0x48, 0x00, 0x00])
877
878 # Set hooks for various code
879 rom.write_bytes(0xDBF428, [0x0C, 0x10, 0x03, 0x00]) # Set Fishing Hook
880
881 # will be populated with data to be written to initial save
882 # see initial_save.asm and config.asm for more details on specifics
883 # or just use the following functions to add an entry to the table
884 initial_save_table = []
885
886 # will set the bits of value to the offset in the save (or'ing them with what is already there)
887 def write_bits_to_save(offset, value, filter=None):
888 nonlocal initial_save_table
889
890 if filter and not filter(value):
891 return
892
893 initial_save_table += [(offset & 0xFF00) >> 8, offset & 0xFF, 0x00, value]
894
895 # will overwrite the byte at offset with the given value
896 def write_byte_to_save(offset, value, filter=None):
897 nonlocal initial_save_table
898
899 if filter and not filter(value):
900 return
901
902 initial_save_table += [(offset & 0xFF00) >> 8, offset & 0xFF, 0x01, value]
903
904 # will overwrite the byte at offset with the given value
905 def write_bytes_to_save(offset, bytes, filter=None):
906 for i, value in enumerate(bytes):
907 write_byte_to_save(offset + i, value, filter)
908
909 # will overwrite the byte at offset with the given value
910 def write_save_table(rom):
911 nonlocal initial_save_table
912
913 table_len = len(initial_save_table)
914 if table_len > 0x400:
915 raise Exception("The Initial Save Table has exceeded it's maximum capacity: 0x%03X/0x400" % table_len)
916 rom.write_bytes(0x3481800, initial_save_table)
917
918 # Initial Save Data
919 write_bits_to_save(0x003F, 0x02) # Some Biggoron's Sword flag?
920
921 write_bits_to_save(0x00D4 + 0x00 * 0x1C + 0x04 + 0x0, 0x80) # Deku tree switch flag (navi text?)
922 write_bits_to_save(0x00D4 + 0x00 * 0x1C + 0x04 + 0x1, 0x02) # Deku tree switch flag (navi text?)
923 write_bits_to_save(0x00D4 + 0x00 * 0x1C + 0x04 + 0x2, 0x80) # Deku tree switch flag (navi text?)
924 write_bits_to_save(0x00D4 + 0x00 * 0x1C + 0x04 + 0x2, 0x04) # Deku tree switch flag (navi text?)
925 write_bits_to_save(0x00D4 + 0x01 * 0x1C + 0x04 + 0x2, 0x40) # Dodongo's Cavern switch flag (navi text?)
926 write_bits_to_save(0x00D4 + 0x01 * 0x1C + 0x04 + 0x2, 0x08) # Dodongo's Cavern switch flag (navi text?)
927 write_bits_to_save(0x00D4 + 0x01 * 0x1C + 0x04 + 0x2, 0x01) # Dodongo's Cavern switch flag (navi text?)
928 write_bits_to_save(0x00D4 + 0x02 * 0x1C + 0x04 + 0x0, 0x08) # Inside Jabu-Jabu's Belly switch flag (ruto?)
929 write_bits_to_save(0x00D4 + 0x02 * 0x1C + 0x04 + 0x0, 0x04) # Inside Jabu-Jabu's Belly switch flag (ruto?)
930 write_bits_to_save(0x00D4 + 0x02 * 0x1C + 0x04 + 0x0, 0x02) # Inside Jabu-Jabu's Belly switch flag (ruto?)
931 write_bits_to_save(0x00D4 + 0x02 * 0x1C + 0x04 + 0x0, 0x01) # Inside Jabu-Jabu's Belly switch flag (ruto?)
932 write_bits_to_save(0x00D4 + 0x02 * 0x1C + 0x04 + 0x1, 0x01) # Inside Jabu-Jabu's Belly switch flag (ruto?)
933 write_bits_to_save(0x00D4 + 0x03 * 0x1C + 0x04 + 0x0, 0x08) # Forest Temple switch flag (poes?)
934 write_bits_to_save(0x00D4 + 0x03 * 0x1C + 0x04 + 0x0, 0x01) # Forest Temple switch flag (poes?)
935 write_bits_to_save(0x00D4 + 0x03 * 0x1C + 0x04 + 0x2, 0x02) # Forest Temple switch flag (poes?)
936 write_bits_to_save(0x00D4 + 0x03 * 0x1C + 0x04 + 0x2, 0x01) # Forest Temple switch flag (poes?)
937 write_bits_to_save(0x00D4 + 0x04 * 0x1C + 0x04 + 0x1, 0x08) # Fire Temple switch flag (First locked door?)
938 write_bits_to_save(0x00D4 + 0x05 * 0x1C + 0x04 + 0x1, 0x01) # Water temple switch flag (navi text?)
939 write_bits_to_save(0x00D4 + 0x0B * 0x1C + 0x04 + 0x2, 0x01) # Gerudo Training Ground switch flag (command text?)
940 write_bits_to_save(0x00D4 + 0x51 * 0x1C + 0x04 + 0x2, 0x08) # Hyrule Field switch flag (???)
941 write_bits_to_save(0x00D4 + 0x55 * 0x1C + 0x04 + 0x0, 0x80) # Kokiri Forest switch flag (???)
942 write_bits_to_save(0x00D4 + 0x56 * 0x1C + 0x04 + 0x2, 0x40) # Sacred Forest Meadow switch flag (???)
943 write_bits_to_save(0x00D4 + 0x5B * 0x1C + 0x04 + 0x2, 0x01) # Lost Woods switch flag (???)
944 write_bits_to_save(0x00D4 + 0x5B * 0x1C + 0x04 + 0x3, 0x80) # Lost Woods switch flag (???)
945 write_bits_to_save(0x00D4 + 0x5C * 0x1C + 0x04 + 0x0, 0x80) # Desert Colossus switch flag (???)
946 write_bits_to_save(0x00D4 + 0x5F * 0x1C + 0x04 + 0x3, 0x20) # Hyrule Castle switch flag (???)
947
948 write_bits_to_save(0x0ED4, 0x10) # "Met Deku Tree"
949 write_bits_to_save(0x0ED5, 0x20) # "Deku Tree Opened Mouth"
950 #write_bits_to_save(0x0ED6, 0x08) # "Rented Horse From Ingo"
951 #write_bits_to_save(0x0EDA, 0x08) # "Began Nabooru Battle"
952 #write_bits_to_save(0x0EDC, 0x80) # "Entered the Master Sword Chamber"
953 #write_bits_to_save(0x0EDD, 0x20) # "Pulled Master Sword from Pedestal"
954 #write_bits_to_save(0x0EE0, 0x80) # "Spoke to Kaepora Gaebora by Lost Woods"
955 #write_bits_to_save(0x0EE7, 0x20) # "Nabooru Captured by Twinrova"
956 #write_bits_to_save(0x0EE7, 0x10) # "Spoke to Nabooru in Spirit Temple"
957 #write_bits_to_save(0x0EED, 0x20) # "Sheik, Spawned at Master Sword Pedestal as Adult"
958 #write_bits_to_save(0x0EED, 0x01) # "Nabooru Ordered to Fight by Twinrova"
959 #write_bits_to_save(0x0EF9, 0x01) # "Greeted by Saria"
960 #write_bits_to_save(0x0F0A, 0x04) # "Spoke to Ingo Once as Adult"
961 #write_bits_to_save(0x0F1A, 0x04) # "Met Darunia in Fire Temple"
962
963 #write_bits_to_save(0x0ED7, 0x01) # "Spoke to Child Malon at Castle or Market"
964 #write_bits_to_save(0x0ED7, 0x20) # "Spoke to Child Malon at Ranch"
965 #write_bits_to_save(0x0ED7, 0x40) # "Invited to Sing With Child Malon"
966 #write_bits_to_save(0x0F09, 0x10) # "Met Child Malon at Castle or Market"
967 #write_bits_to_save(0x0F09, 0x20) # "Child Malon Said Epona Was Scared of You"
968
969 #write_bits_to_save(0x0F21, 0x04) # "Ruto in JJ (M3) Talk First Time"
970 #write_bits_to_save(0x0F21, 0x02) # "Ruto in JJ (M2) Meet Ruto"
971
972
973
974
975 # Make the Kakariko Gate not open with the MS
976 if not world.open_kakariko:
977 rom.write_int32(0xDD3538, 0x34190000) # li t9, 0
978
979 # Make all chest opening animations fast
980 if world.fast_chests:
981 rom.write_int32(0xBDA2E8, 0x240AFFFF) # addiu t2, r0, -1
982 # replaces # lb t2, 0x0002 (t1)
983
984 # Set up for Rainbow Bridge dungeons condition
985 Block_code = [0x15, 0x41, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x80, 0xEA, 0x00, 0xA5,
986 0x24, 0x01, 0x00, 0x1C, 0x31, 0x4A, 0x00, 0x1C, 0x08, 0x07, 0x88, 0xD9]
987 rom.write_bytes(0x3480820, Block_code)
988
989 # Gossip stones resond to stone of agony
990 Block_code = [0x3C, 0x01, 0x80, 0x12, 0x80, 0x21, 0xA6, 0x75, 0x30, 0x21, 0x00, 0x20,
991 0x03, 0xE0, 0x00, 0x08]
992 # Gossip stones always respond
993 if (world.hints == 'always'):
994 Block_code = [0x24, 0x01, 0x00, 0x20, 0x03, 0xE0, 0x00, 0x08]
995 rom.write_bytes(0x3480840, Block_code)
996
997 # Set up Rainbow Bridge conditions
998 if world.bridge == 'medallions':
999 Block_code = [0x80, 0xEA, 0x00, 0xA7, 0x24, 0x01, 0x00, 0x3F,
1000 0x31, 0x4A, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00]
1001 rom.write_bytes(0xE2B454, Block_code)
1002 elif world.bridge == 'open':
1003 write_bits_to_save(0xEDC, 0x20) # "Rainbow Bridge Built by Sages"
1004 elif world.bridge == 'dungeons':
1005 Block_code = [0x80, 0xEA, 0x00, 0xA7, 0x24, 0x01, 0x00, 0x3F,
1006 0x08, 0x10, 0x02, 0x08, 0x31, 0x4A, 0x00, 0x3F]
1007 rom.write_bytes(0xE2B454, Block_code)
1008
1009 if world.open_forest:
1010 write_bits_to_save(0xED5, 0x10) # "Showed Mido Sword & Shield"
1011
1012 if world.open_door_of_time:
1013 write_bits_to_save(0xEDC, 0x08) # "Opened the Door of Time"
1014
1015 # "fast-ganon" stuff
1016 if world.no_escape_sequence:
1017 rom.write_bytes(0xD82A12, [0x05, 0x17]) # Sets exit from Ganondorf fight to entrance to Ganon fight
1018 if world.unlocked_ganondorf:
1019 write_bits_to_save(0x00D4 + 0x0A * 0x1C + 0x04 + 0x1, 0x10) # Ganon's Tower switch flag (unlock boss key door)
1020 if world.skipped_trials['Forest']:
1021 write_bits_to_save(0x0EEA, 0x08) # "Completed Forest Trial"
1022 if world.skipped_trials['Fire']:
1023 write_bits_to_save(0x0EEA, 0x40) # "Completed Fire Trial"
1024 if world.skipped_trials['Water']:
1025 write_bits_to_save(0x0EEA, 0x10) # "Completed Water Trial"
1026 if world.skipped_trials['Spirit']:
1027 write_bits_to_save(0x0EE8, 0x20) # "Completed Spirit Trial"
1028 if world.skipped_trials['Shadow']:
1029 write_bits_to_save(0x0EEA, 0x20) # "Completed Shadow Trial"
1030 if world.skipped_trials['Light']:
1031 write_bits_to_save(0x0EEA, 0x80) # "Completed Light Trial"
1032 if world.trials == 0:
1033 write_bits_to_save(0x0EED, 0x08) # "Dispelled Ganon's Tower Barrier"
1034
1035 # open gerudo fortress
1036 if world.gerudo_fortress == 'open':
1037 write_bits_to_save(0x00A5, 0x40) # Give Gerudo Card
1038 write_bits_to_save(0x0EE7, 0x0F) # Free all 4 carpenters
1039 write_bits_to_save(0x00D4 + 0x0C * 0x1C + 0x04 + 0x1,
1040 0x0F) # Thieves' Hideout switch flags (started all fights)
1041 write_bits_to_save(0x00D4 + 0x0C * 0x1C + 0x04 + 0x2,
1042 0x01) # Thieves' Hideout switch flags (heard yells/unlocked doors)
1043 write_bits_to_save(0x00D4 + 0x0C * 0x1C + 0x04 + 0x3,
1044 0xFE) # Thieves' Hideout switch flags (heard yells/unlocked doors)
1045 write_bits_to_save(0x00D4 + 0x0C * 0x1C + 0x0C + 0x2,
1046 0xD4) # Thieves' Hideout collection flags (picked up keys, marks fights finished as well)
1047 elif world.gerudo_fortress == 'fast':
1048 write_bits_to_save(0x0EE7, 0x0E) # Free 3 carpenters
1049 write_bits_to_save(0x00D4 + 0x0C * 0x1C + 0x04 + 0x1,
1050 0x0D) # Thieves' Hideout switch flags (started all fights)
1051 write_bits_to_save(0x00D4 + 0x0C * 0x1C + 0x04 + 0x2,
1052 0x01) # Thieves' Hideout switch flags (heard yells/unlocked doors)
1053 write_bits_to_save(0x00D4 + 0x0C * 0x1C + 0x04 + 0x3,
1054 0xDC) # Thieves' Hideout switch flags (heard yells/unlocked doors)
1055 write_bits_to_save(0x00D4 + 0x0C * 0x1C + 0x0C + 0x2,
1056 0xC4) # Thieves' Hideout collection flags (picked up keys, marks fights finished as well)
1057
1058 # Revert change that Skips the Epona Race
1059 if not world.no_epona_race:
1060 rom.write_int32(0xA9E838, 0x03E00008)
1061
1062 # skip castle guard stealth sequence
1063 if world.no_guard_stealth:
1064 # change the exit at child/day crawlspace to the end of zelda's goddess cutscene
1065 rom.write_bytes(0x21F60DE, [0x05, 0xF0])
1066
1067 ### Load Shop File
1068 from MQ import File, update_dmadata, insert_space, add_relocations
1069 # Move shop actor file to free space
1070 shop_item_file = File({
1071 'Name': 'En_GirlA',
1072 'Start': '00C004E0',
1073 'End': '00C02E00',
1074 'RemapStart': '03485000',
1075 })
1076 shop_item_file.relocate(rom)
1077
1078 # Increase the shop item table size
1079 shop_item_vram_start = rom.read_int32(0x00B5E490 + (0x20 * 4) + 0x08)
1080 insert_space(rom, shop_item_file, shop_item_vram_start, 1, 0x3C + (0x20 * 50), 0x20 * 50)
1081
1082 # Add relocation entries for shop item table
1083 new_relocations = []
1084 for i in range(50, 100):
1085 new_relocations.append(shop_item_file.start + 0x1DEC + (i * 0x20) + 0x04)
1086 new_relocations.append(shop_item_file.start + 0x1DEC + (i * 0x20) + 0x14)
1087 new_relocations.append(shop_item_file.start + 0x1DEC + (i * 0x20) + 0x1C)
1088 add_relocations(rom, shop_item_file, new_relocations)
1089
1090 # update actor table
1091 rom.write_int32s(0x00B5E490 + (0x20 * 4),
1092 [shop_item_file.start,
1093 shop_item_file.end,
1094 shop_item_vram_start,
1095 shop_item_vram_start + (shop_item_file.end - shop_item_file.start)])
1096
1097 # Update DMA Table
1098 update_dmadata(rom, shop_item_file)
1099
1100 # Create 2nd Bazaar Room
1101 bazaar_room_file = File({
1102 'Name': 'shop1_room_1',
1103 'Start': '028E4000',
1104 'End': '0290D7B0',
1105 'RemapStart': '03489000',
1106 })
1107 bazaar_room_file.dma_key = 0x03472000
1108 bazaar_room_file.relocate(rom)
1109 # Update DMA Table
1110 update_dmadata(rom, bazaar_room_file)
1111
1112 # Add new Bazaar Room to Bazaar Scene
1113 rom.write_int32s(0x28E3030, [0x00010000, 0x02000058]) # reduce position list size
1114 rom.write_int32s(0x28E3008, [0x04020000, 0x02000070]) # expand room list size
1115
1116 rom.write_int32s(0x28E3070, [0x028E4000, 0x0290D7B0,
1117 bazaar_room_file.start, bazaar_room_file.end]) # room list
1118 rom.write_int16s(0x28E3080, [0x0000, 0x0001]) # entrance list
1119 rom.write_int16(0x28E4076, 0x0005) # Change shop to Kakariko Bazaar
1120 # rom.write_int16(0x3489076, 0x0005) # Change shop to Kakariko Bazaar
1121
1122 # Load Message and Shop Data
1123 messages = read_messages(rom)
1124 shop_items = read_shop_items(rom, shop_item_file.start + 0x1DEC)
1125 remove_unused_messages(messages)
1126
1127 # Set Big Poe count to get reward from buyer
1128 if world.big_poe_count == 'random':
1129 world.big_poe_count = str(random.randint(1, 10))
1130 poe_points = int(world.big_poe_count) * 100
1131 rom.write_int16(0xEE69CE, poe_points)
1132 # update dialogue
1133 if world.big_poe_count != 10:
1134 new_message = "\x1AOh, you brought a Poe today!\x04\x1AHmmmm!\x04\x1AVery interesting!\x01This is a \x05\x41Big Poe\x05\x40!\x04\x1AI'll buy it for \x05\x4150 Rupees\x05\x40.\x04On top of that, I'll put \x05\x41100\x01points \x05\x40on your card.\x04\x1AIf you earn \x05\x41%d points\x05\x40, you'll\x01be a happy man! Heh heh." % poe_points
1135 update_message_by_id(messages, 0x70f7, new_message)
1136 new_message = "\x1AWait a minute! WOW!\x04\x1AYou have earned \x05\x41%d points\x05\x40!\x04\x1AYoung man, you are a genuine\x01\x05\x41Ghost Hunter\x05\x40!\x04\x1AIs that what you expected me to\x01say? Heh heh heh!\x04\x1ABecause of you, I have extra\x01inventory of \x05\x41Big Poes\x05\x40, so this will\x01be the last time I can buy a \x01ghost.\x04\x1AYou're thinking about what I \x01promised would happen when you\x01earned %d points. Heh heh.\x04\x1ADon't worry, I didn't forget.\x01Just take this." % (
1137 poe_points, poe_points)
1138 update_message_by_id(messages, 0x70f8, new_message)
1139
1140 # Sets hooks for gossip stone changes
1141 if world.hints != 'none':
1142 if world.hints != 'mask':
1143 rom.write_bytes(0xEE7B84, [0x0C, 0x10, 0x02, 0x10])
1144 rom.write_bytes(0xEE7B8C, [0x24, 0x02, 0x00, 0x20])
1145 buildGossipHints(world, messages)
1146
1147 # Set hints for boss reward shuffle
1148 rom.write_bytes(0xE2ADB2, [0x70, 0x7A])
1149 rom.write_bytes(0xE2ADB6, [0x70, 0x57])
1150 buildBossRewardHints(world, messages)
1151
1152 # build silly ganon lines
1153 buildGanonText(world, messages)
1154
1155 # Write item overrides
1156 override_table = get_override_table(world)
1157 rom.write_bytes(0x3481000, sum(override_table, []))
1158 rom.write_byte(0x03481C00, world.id + 1) # Write player ID
1159
1160 # Revert Song Get Override Injection
1161 if not world.shuffle_song_items:
1162 # general get song
1163 rom.write_int32(0xAE5DF8, 0x240200FF)
1164 rom.write_int32(0xAE5E04, 0xAD0F00A4)
1165 # requiem of spirit
1166 rom.write_int32s(0xAC9ABC, [0x3C010001, 0x00300821])
1167 # sun song
1168 rom.write_int32(0xE09F68, 0x8C6F00A4)
1169 rom.write_int32(0xE09F74, 0x01CFC024)
1170 rom.write_int32(0xE09FB0, 0x240F0001)
1171 # epona
1172 rom.write_int32(0xD7E77C, 0x8C4900A4)
1173 rom.write_int32(0xD7E784, 0x8D088C24)
1174 rom.write_int32s(0xD7E8D4, [0x8DCE8C24, 0x8C4F00A4])
1175 rom.write_int32s(0xD7E140, [0x8DCE8C24, 0x8C6F00A4])
1176 rom.write_int32(0xD7EBBC, 0x14410008)
1177 rom.write_int32(0xD7EC1C, 0x17010010)
1178 # song of time
1179 rom.write_int32(0xDB532C, 0x24050003)
1180
1181 # Set Default targeting option to Hold
1182 if world.default_targeting == 'hold':
1183 rom.write_bytes(0xB07200, [0x20, 0x0C, 0x00, 0x01])
1184
1185 # Set OHKO mode
1186 if world.difficulty == 'ohko':
1187 rom.write_int32(0xAE80A8, 0xA4A00030) # sh zero,48(a1)
1188 rom.write_int32(0xAE80B4, 0x06000003) # bltz s0, +0003
1189
1190 # Patch songs and boss rewards
1191 for location in world.get_locations():
1192 item = location.item
1193 itemid = copy.copy(item.code)
1194 locationaddress = location.address
1195 secondaryaddress = location.address2
1196
1197 if itemid is None or location.address is None:
1198 continue
1199
1200 if location.type == 'Song' and not world.shuffle_song_items:
1201 rom.write_byte(locationaddress, itemid[0])
1202 itemid[0] = itemid[0] + 0x0D
1203 rom.write_byte(secondaryaddress, itemid[0])
1204 if location.name == 'Impa at Castle':
1205 impa_fix = 0x65 - itemid[1]
1206 rom.write_byte(0xD12ECB, impa_fix)
1207 rom.write_byte(0x2E8E931, item_data[item.name]) # Fix text box
1208 elif location.name == 'Song from Malon':
1209 if item.name == 'Suns Song':
1210 rom.write_byte(locationaddress, itemid[0])
1211 malon_fix = 0x8C34 - (itemid[1] * 4)
1212 malon_fix_high = malon_fix >> 8
1213 malon_fix_low = malon_fix & 0x00FF
1214 rom.write_bytes(0xD7E142, [malon_fix_high, malon_fix_low])
1215 rom.write_bytes(0xD7E8D6, [malon_fix_high,
1216 malon_fix_low]) # I really don't like hardcoding these addresses, but for now.....
1217 rom.write_bytes(0xD7E786, [malon_fix_high, malon_fix_low])
1218 rom.write_byte(0x29BECB9, item_data[item.name]) # Fix text box
1219 elif location.name == 'Song from Composer Grave':
1220 sun_fix = 0x8C34 - (itemid[1] * 4)
1221 sun_fix_high = sun_fix >> 8
1222 sun_fix_low = sun_fix & 0x00FF
1223 rom.write_bytes(0xE09F66, [sun_fix_high, sun_fix_low])
1224 rom.write_byte(0x332A87D, item_data[item.name]) # Fix text box
1225 elif location.name == 'Song from Saria':
1226 saria_fix = 0x65 - itemid[1]
1227 rom.write_byte(0xE2A02B, saria_fix)
1228 rom.write_byte(0x20B1DBD, item_data[item.name]) # Fix text box
1229 elif location.name == 'Song from Ocarina of Time':
1230 rom.write_byte(0x252FC95, item_data[item.name]) # Fix text box
1231 elif location.name == 'Song at Windmill':
1232 windmill_fix = 0x65 - itemid[1]
1233 rom.write_byte(0xE42ABF, windmill_fix)
1234 rom.write_byte(0x3041091, item_data[item.name]) # Fix text box
1235 elif location.name == 'Sheik Forest Song':
1236 minuet_fix = 0x65 - itemid[1]
1237 rom.write_byte(0xC7BAA3, minuet_fix)
1238 rom.write_byte(0x20B0815, item_data[item.name]) # Fix text box
1239 elif location.name == 'Sheik at Temple':
1240 prelude_fix = 0x65 - itemid[1]
1241 rom.write_byte(0xC805EF, prelude_fix)
1242 rom.write_byte(0x2531335, item_data[item.name]) # Fix text box
1243 elif location.name == 'Sheik in Crater':
1244 bolero_fix = 0x65 - itemid[1]
1245 rom.write_byte(0xC7BC57, bolero_fix)
1246 rom.write_byte(0x224D7FD, item_data[item.name]) # Fix text box
1247 elif location.name == 'Sheik in Ice Cavern':
1248 serenade_fix = 0x65 - itemid[1]
1249 rom.write_byte(0xC7BD77, serenade_fix)
1250 rom.write_byte(0x2BEC895, item_data[item.name]) # Fix text box
1251 elif location.name == 'Sheik in Kakariko':
1252 nocturne_fix = 0x65 - itemid[1]
1253 rom.write_byte(0xAC9A5B, nocturne_fix)
1254 rom.write_byte(0x2000FED, item_data[item.name]) # Fix text box
1255 elif location.name == 'Sheik at Colossus':
1256 rom.write_byte(0x218C589, item_data[item.name]) # Fix text box
1257 elif location.type == 'Boss':
1258 if location.name == 'Links Pocket':
1259 write_bits_to_save(item_data[item.name][1], item_data[item.name][0])
1260 else:
1261 rom.write_byte(locationaddress, itemid)
1262 rom.write_byte(secondaryaddress, item_data[item.name][2])
1263 if location.name == 'Bongo Bongo':
1264 rom.write_bytes(0xCA3F32, [item_data[item.name][3][0], item_data[item.name][3][1]])
1265 rom.write_bytes(0xCA3F36, [item_data[item.name][3][2], item_data[item.name][3][3]])
1266 elif location.name == 'Twinrova':
1267 rom.write_bytes(0xCA3EA2, [item_data[item.name][3][0], item_data[item.name][3][1]])
1268 rom.write_bytes(0xCA3EA6, [item_data[item.name][3][2], item_data[item.name][3][3]])
1269
1270 # add a cheaper bombchu pack to the bombchu shop
1271 # describe
1272 update_message_by_id(messages, 0x80FE,
1273 '\x08\x05\x41Bombchu (5 pieces) 60 Rupees\x01\x05\x40This looks like a toy mouse, but\x01it\'s actually a self-propelled time\x01bomb!\x09\x0A',
1274 0x03)
1275 # purchase
1276 update_message_by_id(messages, 0x80FF,
1277 '\x08Bombchu 5 Pieces 60 Rupees\x01\x01\x1B\x05\x42Buy\x01Don\'t buy\x05\x40\x09', 0x03)
1278 rbl_bombchu = shop_items[0x0018]
1279 rbl_bombchu.price = 60
1280 rbl_bombchu.pieces = 5
1281 rbl_bombchu.get_item_id = 0x006A
1282 rbl_bombchu.description_message = 0x80FE
1283 rbl_bombchu.purchase_message = 0x80FF
1284
1285 # Reduce 10 Pack Bombchus from 100 to 99 Rupees
1286 shop_items[0x0015].price = 99
1287 shop_items[0x0019].price = 99
1288 shop_items[0x001C].price = 99
1289 update_message_by_id(messages, shop_items[0x001C].description_message,
1290 "\x08\x05\x41Bombchu (10 pieces) 99 Rupees\x01\x05\x40This looks like a toy mouse, but\x01it's actually a self-propelled time\x01bomb!\x09\x0A")
1291 update_message_by_id(messages, shop_items[0x001C].purchase_message,
1292 "\x08Bombchu 10 pieces 100 Rupees\x09\x01\x01\x1B\x05\x42Buy\x01Don't buy\x05\x40")
1293
1294 if world.shopsanity == 'off':
1295 # Add more bombchus to make them more accessible
1296 if world.bombchus_in_logic:
1297 rom.write_int16(world.get_location('Kokiri Shop Item 8').address,
1298 ItemFactory('Buy Bombchu (5)').index)
1299 rom.write_int16(world.get_location('Castle Town Bazaar Item 8').address,
1300 ItemFactory('Buy Bombchu (5)').index)
1301 rom.write_int16(world.get_location('Kakariko Bazaar Item 8').address,
1302 ItemFactory('Buy Bombchu (5)').index)
1303
1304 # Revert Deku Scrubs changes
1305 rom.write_int32s(0xEBB85C, [
1306 0x24010002, # addiu at, zero, 2
1307 0x3C038012, # lui v1, 0x8012
1308 0x14410004, # bne v0, at, 0xd8
1309 0x2463A5D0, # addiu v1, v1, -0x5a30
1310 0x94790EF0]) # lhu t9, 0xef0(v1)
1311 rom.write_int32(0xDF7CB0,
1312 0xA44F0EF0) # sh t7, 0xef0(v0)
1313 else:
1314 # kokiri shop
1315 shop_objs = place_shop_items(rom, shop_items, messages,
1316 world.get_region('Kokiri Shop').locations, True)
1317 shop_objs |= {0x00FC, 0x00B2, 0x0101, 0x0102, 0x00FD, 0x00C5} # Shop objects
1318 rom.write_byte(0x2587029, len(shop_objs))
1319 rom.write_int32(0x258702C, 0x0300F600)
1320 rom.write_int16s(0x2596600, list(shop_objs))
1321
1322 # kakariko bazaar
1323 shop_objs = place_shop_items(rom, shop_items, messages,
1324 world.get_region('Kakariko Bazaar').locations)
1325 shop_objs |= {0x005B, 0x00B2, 0x00C5, 0x0107, 0x00C9, 0x016B} # Shop objects
1326 rom.write_byte(0x28E4029, len(shop_objs))
1327 rom.write_int32(0x28E402C, 0x03007A40)
1328 rom.write_int16s(0x28EBA40, list(shop_objs))
1329
1330 # castle town bazaar
1331 shop_objs = place_shop_items(rom, shop_items, messages,
1332 world.get_region('Castle Town Bazaar').locations)
1333 shop_objs |= {0x005B, 0x00B2, 0x00C5, 0x0107, 0x00C9, 0x016B} # Shop objects
1334 rom.write_byte(0x3489029, len(shop_objs))
1335 rom.write_int32(0x348902C, 0x03007A40)
1336 rom.write_int16s(0x3490A40, list(shop_objs))
1337
1338 # goron shop
1339 shop_objs = place_shop_items(rom, shop_items, messages,
1340 world.get_region('Goron Shop').locations)
1341 shop_objs |= {0x00C9, 0x00B2, 0x0103, 0x00AF} # Shop objects
1342 rom.write_byte(0x2D33029, len(shop_objs))
1343 rom.write_int32(0x2D3302C, 0x03004340)
1344 rom.write_int16s(0x2D37340, list(shop_objs))
1345
1346 # zora shop
1347 shop_objs = place_shop_items(rom, shop_items, messages,
1348 world.get_region('Zora Shop').locations)
1349 shop_objs |= {0x005B, 0x00B2, 0x0104, 0x00FE} # Shop objects
1350 rom.write_byte(0x2D5B029, len(shop_objs))
1351 rom.write_int32(0x2D5B02C, 0x03004B40)
1352 rom.write_int16s(0x2D5FB40, list(shop_objs))
1353
1354 # kakariko potion shop
1355 shop_objs = place_shop_items(rom, shop_items, messages,
1356 world.get_region('Kakariko Potion Shop Front').locations)
1357 shop_objs |= {0x0159, 0x00B2, 0x0175, 0x0122} # Shop objects
1358 rom.write_byte(0x2D83029, len(shop_objs))
1359 rom.write_int32(0x2D8302C, 0x0300A500)
1360 rom.write_int16s(0x2D8D500, list(shop_objs))
1361
1362 # market potion shop
1363 shop_objs = place_shop_items(rom, shop_items, messages,
1364 world.get_region('Castle Town Potion Shop').locations)
1365 shop_objs |= {0x0159, 0x00B2, 0x0175, 0x00C5, 0x010C, 0x016B} # Shop objects
1366 rom.write_byte(0x2DB0029, len(shop_objs))
1367 rom.write_int32(0x2DB002C, 0x03004E40)
1368 rom.write_int16s(0x2DB4E40, list(shop_objs))
1369
1370 # bombchu shop
1371 shop_objs = place_shop_items(rom, shop_items, messages,
1372 world.get_region('Castle Town Bombchu Shop').locations)
1373 shop_objs |= {0x0165, 0x00B2} # Shop objects
1374 rom.write_byte(0x2DD8029, len(shop_objs))
1375 rom.write_int32(0x2DD802C, 0x03006A40)
1376 rom.write_int16s(0x2DDEA40, list(shop_objs))
1377
1378 if world.shuffle_scrubs:
1379 # Rebuild Deku Salescrub Item Table
1380 scrub_items = [0x30, 0x31, 0x3E, 0x33, 0x34, 0x37, 0x38, 0x39, 0x3A, 0x77, 0x79]
1381 rom.seek_address(0xDF8684)
1382 for scrub_item in scrub_items:
1383 rom.write_int16(None, 10) # Price
1384 rom.write_int16(None, 1) # Count
1385 rom.write_int32(None, scrub_item) # Item
1386 rom.write_int32(None, 0x80A74FF8) # Can_Buy_Func
1387 rom.write_int32(None, 0x80A75354) # Buy_Func
1388
1389 # update actor IDs
1390 set_deku_salesman_data(rom)
1391
1392 # Fix item chest animations
1393 chestAnimations = {
1394 0x3D: 0xED, # 0x13 #Heart Container
1395 0x3E: 0xEC, # 0x14 #Piece of Heart
1396 0x42: 0x02, # 0xFE #Small Key
1397 0x48: 0xF7, # 0x09 #Recovery Heart
1398 0x4F: 0xED, # 0x13 #Heart Container
1399 0x76: 0xEC, # 0x14 #WINNER! Piece of Heart
1400 }
1401 if world.bombchus_in_logic:
1402 # Fix bombchu chest animations
1403 chestAnimations[0x6A] = 0x28 # 0xD8 #Bombchu (5)
1404 chestAnimations[0x03] = 0x28 # 0xD8 #Bombchu (10)
1405 chestAnimations[0x6B] = 0x28 # 0xD8 #Bombchu (20)
1406 for item_id, gfx_id in chestAnimations.items():
1407 rom.write_byte(0xBEEE8E + (item_id * 6) + 2, gfx_id)
1408
1409 # Update chest type sizes
1410 if world.correct_chest_sizes:
1411 update_chest_sizes(rom, override_table)
1412
1413 # Move Ganon's Castle's Zelda's Lullaby Chest back so is reachable if large
1414 rom.write_int16(0x321B176, 0xFC40) # original 0xFC48
1415
1416 # give dungeon items the correct messages
1417 message_patch_for_dungeon_items(messages, shop_items, world)
1418 # update happy mask shop to use new SOLD OUT text id
1419 rom.write_int16(0xC01C06, shop_items[0x26].description_message)
1420
1421 # add song messages
1422 add_song_messages(messages, world)
1423
1424 # reduce item message lengths
1425 update_item_messages(messages, world)
1426
1427 # Add 3rd Wallet Upgrade
1428 rom.write_int16(0xB6D57E, 0x0003)
1429 rom.write_int16(0xB6EC52, 999)
1430 update_message_by_id(messages, 0x00F8,
1431 "\x08\x13\x57You got a \x05\x43Tycoon's Wallet\x05\x40!\x01Now you can hold\x01up to \x05\x46999\x05\x40 \x05\x46Rupees\x05\x40.",
1432 0x23)
1433
1434 repack_messages(rom, messages)
1435 write_shop_items(rom, shop_item_file.start + 0x1DEC, shop_items)
1436
1437 # text shuffle
1438 if world.text_shuffle == 'except_hints':
1439 shuffle_messages(rom, True)
1440 elif world.text_shuffle == 'complete':
1441 shuffle_messages(rom, False)
1442
1443 # output a text dump, for testing...
1444 # with open('keysanity_' + str(world.seed) + '_dump.txt', 'w', encoding='utf-16') as f:
1445 # messages = read_messages(rom)
1446 # f.write('item_message_strings = {\n')
1447 # for m in messages:
1448 # f.write("\t0x%04X: \"%s\",\n" % (m.id, m.get_python_string()))
1449 # f.write('}\n')
1450
1451 scarecrow_song = None
1452 if world.free_scarecrow:
1453 original_songs = [
1454 'LURLUR',
1455 'ULRULR',
1456 'DRLDRL',
1457 'RDURDU',
1458 'RADRAD',
1459 'ADUADU',
1460 'AULRLR',
1461 'DADALDLD',
1462 'ADRRL',
1463 'ADALDA',
1464 'LRRALRD',
1465 'URURLU'
1466 ]
1467
1468 note_map = {
1469 'A': 0,
1470 'D': 1,
1471 'R': 2,
1472 'L': 3,
1473 'U': 4
1474 }
1475
1476 if len(world.scarecrow_song) != 8:
1477 raise Exception('Scarecrow Song must be 8 notes long')
1478
1479 if len(set(world.scarecrow_song.upper())) == 1:
1480 raise Exception('Scarecrow Song must contain at least two different notes')
1481
1482 notes = []
1483 for c in world.scarecrow_song.upper():
1484 if c not in note_map:
1485 raise Exception('Invalid note %s. Valid notes are A, D, R, L, U' % c)
1486
1487 notes.append(note_map[c])
1488 scarecrow_song = Song(activation=notes)
1489
1490 if not world.ocarina_songs:
1491 for original_song in original_songs:
1492 song_notes = []
1493 for c in original_song:
1494 song_notes.append(note_map[c])
1495 song = Song(activation=song_notes)
1496
1497 if subsong(scarecrow_song, song):
1498 raise Exception('You may not have the Scarecrow Song contain an existing song')
1499
1500 write_bits_to_save(0x0EE6, 0x10) # Played song as adult
1501 write_byte_to_save(0x12C5, 0x01) # Song is remembered
1502 write_bytes_to_save(0x12C6, scarecrow_song.playback_data[:(16 * 8)], lambda v: v != 0)
1503
1504 if world.ocarina_songs:
1505 replace_songs(rom, scarecrow_song)
1506
1507 # actually write the save table to rom
1508 write_save_table(rom)
1509
1510 # disable music
1511 if world.disable_music:
1512 rom.write_bytes(0xB3CB18, [0x00, 0x00, 0x20, 0x25])
1513
1514 # re-seed for aesthetic effects. They shouldn't be affected by the generation seed
1515 random.seed()
1516
1517 # patch tunic colors
1518 # Custom color tunic stuff
1519 Tunics = []
1520 Tunics.append(0x00B6DA38) # Kokiri Tunic
1521 Tunics.append(0x00B6DA3B) # Goron Tunic
1522 Tunics.append(0x00B6DA3E) # Zora Tunic
1523 colorList = get_tunic_colors()
1524 randomColors = random.choices(colorList, k=3)
1525
1526 for i in range(len(Tunics)):
1527 # get the color option
1528 thisColor = world.tunic_colors[i]
1529 # handle true random
1530 randColor = [random.getrandbits(8), random.getrandbits(8), random.getrandbits(8)]
1531 if thisColor == 'Completely Random':
1532 color = randColor
1533 else:
1534 # handle random
1535 if world.tunic_colors[i] == 'Random Choice':
1536 thisColor = randomColors[i]
1537 # grab the color from the list
1538 color = TunicColors[thisColor]
1539 rom.write_bytes(Tunics[i], color)
1540
1541 # patch navi colors
1542 Navi = []
1543 Navi.append([0x00B5E184]) # Default
1544 Navi.append([0x00B5E19C, 0x00B5E1BC]) # Enemy, Boss
1545 Navi.append([0x00B5E194]) # NPC
1546 Navi.append([0x00B5E174, 0x00B5E17C, 0x00B5E18C, 0x00B5E1A4, 0x00B5E1AC, 0x00B5E1B4, 0x00B5E1C4, 0x00B5E1CC,
1547 0x00B5E1D4]) # Everything else
1548 naviList = get_navi_colors()
1549 randomColors = random.choices(naviList, k=4)
1550
1551 for i in range(len(Navi)):
1552 # do everything in the inner loop so that "true random" changes even for subcategories
1553 for j in range(len(Navi[i])):
1554 # get the color option
1555 thisColor = world.navi_colors[i]
1556 # handle true random
1557 randColor = [random.getrandbits(8), random.getrandbits(8), random.getrandbits(8), 0xFF,
1558 random.getrandbits(8), random.getrandbits(8), random.getrandbits(8), 0x00]
1559 if thisColor == 'Completely Random':
1560 color = randColor
1561 else:
1562 # handle random
1563 if world.navi_colors[i] == 'Random Choice':
1564 thisColor = randomColors[i]
1565 # grab the color from the list
1566 color = NaviColors[thisColor]
1567 rom.write_bytes(Navi[i][j], color)
1568
1569 # Navi hints
1570 NaviHint = []
1571 NaviHint.append([0xAE7EF2, 0xC26C7E]) # Overworld Hint
1572 NaviHint.append([0xAE7EC6]) # Enemy Target Hint
1573 naviHintSFXList = ['Default', 'Notification', 'Rupee', 'Timer', 'Tamborine', 'Recovery Heart', 'Carrot Refill',
1574 'Navi - Hey!', 'Navi - Random', 'Zelda - Gasp', 'Cluck', 'Mweep!', 'None']
1575 randomNaviHintSFX = random.choices(naviHintSFXList, k=2)
1576
1577 for i in range(len(NaviHint)):
1578 for j in range(len(NaviHint[i])):
1579 thisNaviHintSFX = world.navi_hint_sounds[i]
1580 if thisNaviHintSFX == 'Random Choice':
1581 thisNaviHintSFX = randomNaviHintSFX[i]
1582 if thisNaviHintSFX == 'Notification':
1583 naviHintSFX = [0x48, 0x20]
1584 elif thisNaviHintSFX == 'Rupee':
1585 naviHintSFX = [0x48, 0x03]
1586 elif thisNaviHintSFX == 'Timer':
1587 naviHintSFX = [0x48, 0x1A]
1588 elif thisNaviHintSFX == 'Tamborine':
1589 naviHintSFX = [0x48, 0x42]
1590 elif thisNaviHintSFX == 'Recovery Heart':
1591 naviHintSFX = [0x48, 0x0B]
1592 elif thisNaviHintSFX == 'Carrot Refill':
1593 naviHintSFX = [0x48, 0x45]
1594 elif thisNaviHintSFX == 'Navi - Hey!':
1595 naviHintSFX = [0x68, 0x5F]
1596 elif thisNaviHintSFX == 'Navi - Random':
1597 naviHintSFX = [0x68, 0x43]
1598 elif thisNaviHintSFX == 'Zelda - Gasp':
1599 naviHintSFX = [0x68, 0x79]
1600 elif thisNaviHintSFX == 'Cluck':
1601 naviHintSFX = [0x28, 0x12]
1602 elif thisNaviHintSFX == 'Mweep!':
1603 naviHintSFX = [0x68, 0x7A]
1604 elif thisNaviHintSFX == 'None':
1605 naviHintSFX = [0x00, 0x00]
1606 if thisNaviHintSFX != 'Default':
1607 rom.write_bytes(NaviHint[i][j], naviHintSFX)
1608
1609 # Low health beep
1610 healthSFXList = ['Default', 'Softer Beep', 'Rupee', 'Timer', 'Tamborine', 'Recovery Heart', 'Carrot Refill',
1611 'Navi - Hey!', 'Zelda - Gasp', 'Cluck', 'Mweep!', 'None']
1612 randomSFX = random.choice(healthSFXList)
1613 address = 0xADBA1A
1614
1615 if world.healthSFX == 'Random Choice':
1616 thisHealthSFX = randomSFX
1617 else:
1618 thisHealthSFX = world.healthSFX
1619 if thisHealthSFX == 'Default':
1620 healthSFX = [0x48, 0x1B]
1621 elif thisHealthSFX == 'Softer Beep':
1622 healthSFX = [0x48, 0x04]
1623 elif thisHealthSFX == 'Rupee':
1624 healthSFX = [0x48, 0x03]
1625 elif thisHealthSFX == 'Timer':
1626 healthSFX = [0x48, 0x1A]
1627 elif thisHealthSFX == 'Tamborine':
1628 healthSFX = [0x48, 0x42]
1629 elif thisHealthSFX == 'Recovery Heart':
1630 healthSFX = [0x48, 0x0B]
1631 elif thisHealthSFX == 'Carrot Refill':
1632 healthSFX = [0x48, 0x45]
1633 elif thisHealthSFX == 'Navi - Hey!':
1634 healthSFX = [0x68, 0x5F]
1635 elif thisHealthSFX == 'Zelda - Gasp':
1636 healthSFX = [0x68, 0x79]
1637 elif thisHealthSFX == 'Cluck':
1638 healthSFX = [0x28, 0x12]
1639 elif thisHealthSFX == 'Mweep!':
1640 healthSFX = [0x68, 0x7A]
1641 elif thisHealthSFX == 'None':
1642 healthSFX = [0x00, 0x00, 0x00, 0x00]
1643 address = 0xADBA14
1644 rom.write_bytes(address, healthSFX)
1645
1646 return rom
1647
1648
1649def get_override_table(world):
1650 override_entries = []
1651 for location in world.get_locations():
1652 override_entries.append(get_override_entry(location))
1653 override_entries.sort()
1654 return override_entries
1655
1656
1657def get_override_entry(location):
1658 scene = location.scene
1659 default = location.default
1660 item_id = location.item.index
1661 if None in [scene, default, item_id]:
1662 return []
1663
1664 player_id = (location.item.world.id + 1) << 3
1665
1666 if location.type in ['NPC', 'BossHeart', 'Song']:
1667 return [scene, player_id | 0x00, default, item_id]
1668 elif location.type == 'Chest':
1669 flag = default & 0x1F
1670 return [scene, player_id | 0x01, flag, item_id]
1671 elif location.type == 'Collectable':
1672 return [scene, player_id | 0x02, default, item_id]
1673 elif location.type == 'GS Token':
1674 return [scene, player_id | 0x03, default, item_id]
1675 elif location.type == 'Shop' and location.item.type != 'Shop':
1676 return [scene, player_id | 0x00, default, item_id]
1677 elif location.type == 'GrottoNPC' and location.item.type != 'Shop':
1678 return [scene, player_id | 0x04, default, item_id]
1679 else:
1680 return []
1681
1682
1683chestTypeMap = {
1684 # small big boss
1685 0x0000: [0x5000, 0x0000, 0x2000], # Large
1686 0x1000: [0x7000, 0x1000, 0x1000], # Large, Appears, Clear Flag
1687 0x2000: [0x5000, 0x0000, 0x2000], # Boss Key’s Chest
1688 0x3000: [0x8000, 0x3000, 0x3000], # Large, Falling, Switch Flag
1689 0x4000: [0x6000, 0x4000, 0x4000], # Large, Invisible
1690 0x5000: [0x5000, 0x0000, 0x2000], # Small
1691 0x6000: [0x6000, 0x4000, 0x4000], # Small, Invisible
1692 0x7000: [0x7000, 0x1000, 0x1000], # Small, Appears, Clear Flag
1693 0x8000: [0x8000, 0x3000, 0x3000], # Small, Falling, Switch Flag
1694 0x9000: [0x9000, 0x9000, 0x9000], # Large, Appears, Zelda's Lullaby
1695 0xA000: [0xA000, 0xA000, 0xA000], # Large, Appears, Sun's Song Triggered
1696 0xB000: [0xB000, 0xB000, 0xB000], # Large, Appears, Switch Flag
1697 0xC000: [0x5000, 0x0000, 0x2000], # Large
1698 0xD000: [0x5000, 0x0000, 0x2000], # Large
1699 0xE000: [0x5000, 0x0000, 0x2000], # Large
1700 0xF000: [0x5000, 0x0000, 0x2000], # Large
1701}
1702
1703chestAnimationExtendedFast = [
1704 0x87, # Progressive Nut Capacity
1705 0x88, # Progressive Stick Capacity
1706 0xB6, # Recovery Heart
1707 0xB7, # Arrows (5)
1708 0xB8, # Arrows (10)
1709 0xB9, # Arrows (30)
1710 0xBA, # Bombs (5)
1711 0xBB, # Bombs (10)
1712 0xBC, # Bombs (20)
1713 0xBD, # Deku Nuts (5)
1714 0xBE, # Deku Nuts (10)
1715]
1716
1717
1718def room_get_actors(rom, actor_func, room_data, scene, alternate=None):
1719 actors = {}
1720 room_start = alternate or room_data
1721 command = 0
1722 while command != 0x14: # 0x14 = end header
1723 command = rom.read_byte(room_data)
1724 if command == 0x01: # actor list
1725 actor_count = rom.read_byte(room_data + 1)
1726 actor_list = room_start + (rom.read_int32(room_data + 4) & 0x00FFFFFF)
1727 for _ in range(0, actor_count):
1728 entry = actor_func(rom, actor_list, scene)
1729 if entry:
1730 actors[actor_list] = entry
1731 actor_list = actor_list + 16
1732 if command == 0x18 and scene >= 81 and scene <= 99: # Alternate header list
1733 header_list = room_start + (rom.read_int32(room_data + 4) & 0x00FFFFFF)
1734 for alt_id in range(0, 2):
1735 header_data = room_start + (rom.read_int32(header_list + 4) & 0x00FFFFFF)
1736 if header_data != 0 and not alternate:
1737 actors.update(room_get_actors(rom, actor_func, header_data, scene, room_start))
1738 header_list = header_list + 4
1739 room_data = room_data + 8
1740 return actors
1741
1742
1743def scene_get_actors(rom, actor_func, scene_data, scene, alternate=None, processed_rooms=[]):
1744 actors = {}
1745 scene_start = alternate or scene_data
1746 command = 0
1747 while command != 0x14: # 0x14 = end header
1748 command = rom.read_byte(scene_data)
1749 if command == 0x04: # room list
1750 room_count = rom.read_byte(scene_data + 1)
1751 room_list = scene_start + (rom.read_int32(scene_data + 4) & 0x00FFFFFF)
1752 for _ in range(0, room_count):
1753 room_data = rom.read_int32(room_list);
1754
1755 if not room_data in processed_rooms:
1756 actors.update(room_get_actors(rom, actor_func, room_data, scene))
1757 processed_rooms.append(room_data)
1758 room_list = room_list + 8
1759 if command == 0x18 and scene >= 81 and scene <= 99: # Alternate header list
1760 header_list = scene_start + (rom.read_int32(scene_data + 4) & 0x00FFFFFF)
1761 for alt_id in range(0, 2):
1762 header_data = scene_start + (rom.read_int32(header_list + 4) & 0x00FFFFFF)
1763 if header_data != 0 and not alternate:
1764 actors.update(scene_get_actors(rom, actor_func, header_data, scene, scene_start, processed_rooms))
1765 header_list = header_list + 4
1766
1767 scene_data = scene_data + 8
1768 return actors
1769
1770
1771def get_actor_list(rom, actor_func):
1772 actors = {}
1773 scene_table = 0x00B71440
1774 for scene in range(0x00, 0x65):
1775 scene_data = rom.read_int32(scene_table + (scene * 0x14));
1776 actors.update(scene_get_actors(rom, actor_func, scene_data, scene))
1777 return actors
1778
1779
1780def get_override_itemid(override_table, scene, type, flags):
1781 for entry in override_table:
1782 if len(entry) == 4 and entry[0] == scene and (entry[1] & 0x07) == type and entry[2] == flags:
1783 return entry[3]
1784 return None
1785
1786
1787def update_chest_sizes(rom, override_table):
1788 def get_chest(rom, actor, scene):
1789 actor_id = rom.read_int16(actor);
1790 if actor_id == 0x000A: # Chest Actor
1791 actor_var = rom.read_int16(actor + 14)
1792 return [scene, actor_var & 0x001F]
1793
1794 chest_list = get_actor_list(rom, get_chest)
1795 for actor, [scene, flags] in chest_list.items():
1796 item_id = get_override_itemid(override_table, scene, 1, flags)
1797
1798 if None in [actor, scene, flags, item_id]:
1799 continue
1800
1801 itemType = 0 # Item animation
1802
1803 if item_id >= 0x80: # if extended item, always big except from exception list
1804 itemType = 0 if item_id in chestAnimationExtendedFast else 1
1805 elif rom.read_byte(0xBEEE8E + (item_id * 6) + 2) & 0x80: # get animation from rom, ice trap is big
1806 itemType = 0 # No animation, small chest
1807 else:
1808 itemType = 1 # Long animation, big chest
1809 # Don't use boss chests
1810
1811 default = rom.read_int16(actor + 0x14)
1812 chestType = default & 0xF000
1813 newChestType = chestTypeMap[chestType][itemType]
1814 default = (default & 0x0FFF) | newChestType
1815 rom.write_int16(actor + 0x14, default)
1816
1817
1818def set_deku_salesman_data(rom):
1819 def set_deku_salesman_and_grotto_id(rom, actor, scene):
1820 actor_id = rom.read_int16(actor);
1821 if actor_id == 0x009B: # Grotto
1822 actor_zrot = rom.read_int16(actor + 12)
1823 actor_var = rom.read_int16(actor + 14);
1824 grotto_scene = actor_var >> 12
1825 grotto_entrance = actor_zrot & 0x000F
1826 grotto_id = actor_var & 0x00FF
1827
1828 if grotto_scene == 0 and grotto_entrance in [2, 4, 7, 10]:
1829 grotto_scenes.add(scene)
1830 rom.write_byte(actor + 15, len(grotto_scenes))
1831 elif actor_id == 0x0195: # Salesman
1832 actor_var = rom.read_int16(actor + 14)
1833 if actor_var == 6:
1834 rom.write_int16(actor + 14, 0x0003)
1835
1836 grotto_scenes = set()
1837
1838 get_actor_list(rom, set_deku_salesman_and_grotto_id)
1839
1840
1841def place_shop_items(rom, shop_items, messages, locations, init_shop_id=False):
1842 if init_shop_id:
1843 place_shop_items.shop_id = 0x32
1844
1845 shop_objs = {0x0148} # Sold Out
1846 messages
1847 for location in locations:
1848 shop_objs.add(location.item.object)
1849 if location.item.type == 'Shop':
1850 rom.write_int16(location.address, location.item.index)
1851 else:
1852 shop_id = place_shop_items.shop_id
1853 rom.write_int16(location.address, shop_id)
1854 shop_item = shop_items[shop_id]
1855
1856 shop_item.object = location.item.object
1857 shop_item.model = location.item.model - 1
1858 shop_item.price = location.price
1859 shop_item.pieces = 1
1860 shop_item.get_item_id = location.default
1861 shop_item.func1 = 0x808648CC
1862 shop_item.func2 = 0x808636B8
1863 shop_item.func3 = 0x00000000
1864 shop_item.func4 = 0x80863FB4
1865
1866 message_id = (shop_id - 0x32) * 2
1867 shop_item.description_message = 0x8100 + message_id
1868 shop_item.purchase_message = 0x8100 + message_id + 1
1869 update_message_by_id(messages, shop_item.description_message,
1870 '\x08\x05\x41%s %d Rupees\x01\x05\x40Special deal! ONE LEFT!\x01Get it while it lasts!\x09\x0A\x02' % (
1871 location.item.name, location.price), 0x03)
1872 update_message_by_id(messages, shop_item.purchase_message,
1873 '\x08%s %d Rupees\x09\x01\x01\x1B\x05\x42Buy\x01Don\'t buy\x05\x40\x02' % (
1874 location.item.name, location.price), 0x03)
1875
1876 place_shop_items.shop_id += 1
1877
1878 return shop_objs