| 
									
										
										
										
											2023-03-21 01:26:03 +09:00
										 |  |  | import os | 
					
						
							|  |  |  | import binascii | 
					
						
							|  |  |  | from ..assembler import ASM | 
					
						
							|  |  |  | from ..utils import formatText | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-06 11:06:34 -07:00
										 |  |  | import pkgutil | 
					
						
							| 
									
										
										
										
											2023-03-21 01:26:03 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | def hasBank3E(rom): | 
					
						
							|  |  |  |     return rom.banks[0x3E][0] != 0x00 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def generate_name(l, i): | 
					
						
							|  |  |  |     if i < len(l): | 
					
						
							|  |  |  |         name = l[i] | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         name = f"player {i}" | 
					
						
							|  |  |  |     name = name[:16] | 
					
						
							|  |  |  |     assert(len(name) <= 16) | 
					
						
							|  |  |  |     return 'db "' + name + '"' + ', $ff' * (17 - len(name)) + '\n' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Bank $3E is used for large chunks of custom code. | 
					
						
							|  |  |  | #   Mainly for new chest and dropped items handling. | 
					
						
							|  |  |  | def addBank3E(rom, seed, player_id, player_name_list): | 
					
						
							|  |  |  |     # No default text for getting the bow, so use an unused slot. | 
					
						
							|  |  |  |     rom.texts[0x89] = formatText("Found the {BOW}!") | 
					
						
							|  |  |  |     rom.texts[0xD9] = formatText("Found the {BOOMERANG}!")  # owl text slot reuse | 
					
						
							|  |  |  |     rom.texts[0xBE] = rom.texts[0x111]  # owl text slot reuse to get the master skull message in the first dialog group | 
					
						
							|  |  |  |     rom.texts[0xC8] = formatText("Found {BOWWOW}! Which monster put him in a chest? He is a good boi, and waits for you at the Swamp.") | 
					
						
							|  |  |  |     rom.texts[0xC9] = 0xC0A0  # Custom message slot | 
					
						
							|  |  |  |     rom.texts[0xCA] = formatText("Found {ARROWS_10}!") | 
					
						
							|  |  |  |     rom.texts[0xCB] = formatText("Found a {SINGLE_ARROW}... joy?") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Create a trampoline to bank 0x3E in bank 0x00. | 
					
						
							|  |  |  |     # There is very little room in bank 0, so we set this up as a single trampoline for multiple possible usages. | 
					
						
							|  |  |  |     # the A register is preserved and can directly be used as a jumptable in page 3E. | 
					
						
							|  |  |  |     # Trampoline at rst 8 | 
					
						
							|  |  |  |     # the A register is preserved and can directly be used as a jumptable in page 3E. | 
					
						
							|  |  |  |     rom.patch(0, 0x0008, "0000000000000000000000000000", ASM("""
 | 
					
						
							|  |  |  |         ld   h, a | 
					
						
							|  |  |  |         ld   a, [$DBAF] | 
					
						
							|  |  |  |         push af | 
					
						
							|  |  |  |         ld   a, $3E | 
					
						
							|  |  |  |         call $080C ; switch bank | 
					
						
							|  |  |  |         ld   a, h | 
					
						
							|  |  |  |         jp $4000 | 
					
						
							|  |  |  |     """), fill_nop=True)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Special trampoline to jump to the damage-entity code, we use this from bowwow to damage instead of eat. | 
					
						
							|  |  |  |     rom.patch(0x00, 0x0018, "000000000000000000000000000000", ASM("""
 | 
					
						
							|  |  |  |         ld   a, $03 | 
					
						
							|  |  |  |         ld   [$2100], a | 
					
						
							|  |  |  |         call $71C0 | 
					
						
							|  |  |  |         ld   a, [$DBAF] | 
					
						
							|  |  |  |         ld   [$2100], a | 
					
						
							|  |  |  |         ret | 
					
						
							|  |  |  |     """))
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-06 11:06:34 -07:00
										 |  |  |     def get_asm(name): | 
					
						
							| 
									
										
										
										
											2024-12-08 19:59:40 -05:00
										 |  |  |         return pkgutil.get_data(__name__, "bank3e.asm/" + name).decode().replace("\r", "") | 
					
						
							| 
									
										
										
										
											2023-04-06 11:06:34 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-21 01:26:03 +09:00
										 |  |  |     rom.patch(0x3E, 0x0000, 0x2F00, ASM("""
 | 
					
						
							|  |  |  |         call MainJumpTable | 
					
						
							|  |  |  |         pop af | 
					
						
							|  |  |  |         jp $080C ; switch bank and return to normal code. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | MainJumpTable: | 
					
						
							|  |  |  |         rst  0 ; JUMP TABLE | 
					
						
							|  |  |  |         dw   MainLoop                             ; 0 | 
					
						
							|  |  |  |         dw   RenderChestItem                      ; 1 | 
					
						
							|  |  |  |         dw   GiveItemFromChest                    ; 2 | 
					
						
							|  |  |  |         dw   ItemMessage                          ; 3 | 
					
						
							|  |  |  |         dw   RenderDroppedKey                     ; 4 | 
					
						
							|  |  |  |         dw   RenderHeartPiece                     ; 5 | 
					
						
							|  |  |  |         dw   GiveItemFromChestMultiworld          ; 6 | 
					
						
							|  |  |  |         dw   CheckIfLoadBowWow                    ; 7 | 
					
						
							|  |  |  |         dw   BowwowEat                            ; 8 | 
					
						
							|  |  |  |         dw   HandleOwlStatue                      ; 9 | 
					
						
							|  |  |  |         dw   ItemMessageMultiworld                ; A | 
					
						
							|  |  |  |         dw   GiveItemAndMessageForRoom            ; B | 
					
						
							|  |  |  |         dw   RenderItemForRoom                    ; C | 
					
						
							|  |  |  |         dw   StartGameMarinMessage                ; D | 
					
						
							|  |  |  |         dw   GiveItemAndMessageForRoomMultiworld  ; E | 
					
						
							|  |  |  |         dw   RenderOwlStatueItem                  ; F | 
					
						
							|  |  |  |         dw   UpdateInventoryMenu                  ; 10 | 
					
						
							|  |  |  |         dw   LocalOnlyItemAndMessage              ; 11 | 
					
						
							|  |  |  | StartGameMarinMessage: | 
					
						
							|  |  |  |         ; Injection to reset our frame counter | 
					
						
							|  |  |  |         call $27D0 ; Enable SRAM | 
					
						
							|  |  |  |         ld   hl, $B000 | 
					
						
							|  |  |  |         xor  a | 
					
						
							|  |  |  |         ldi  [hl], a ;subsecond counter | 
					
						
							|  |  |  |         ld   a, $08  ;(We set the counter to 8 seconds, as it takes 8 seconds before link wakes up and marin talks to him) | 
					
						
							|  |  |  |         ldi  [hl], a ;second counter | 
					
						
							|  |  |  |         xor  a | 
					
						
							|  |  |  |         ldi  [hl], a ;minute counter | 
					
						
							|  |  |  |         ldi  [hl], a ;hour counter | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         ld   hl, $B010 | 
					
						
							| 
									
										
										
										
											2024-12-19 22:17:41 -05:00
										 |  |  |         ld   a, $01  ;tarin's gift gets skipped for some reason, so inflate count by 1 | 
					
						
							| 
									
										
										
										
											2023-03-21 01:26:03 +09:00
										 |  |  |         ldi  [hl], a ;check counter low | 
					
						
							| 
									
										
										
										
											2024-12-19 22:17:41 -05:00
										 |  |  |         xor  a | 
					
						
							| 
									
										
										
										
											2023-03-21 01:26:03 +09:00
										 |  |  |         ldi  [hl], a ;check counter high | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         ; Show the normal message | 
					
						
							|  |  |  |         ld   a, $01 | 
					
						
							|  |  |  |         jp $2385 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TradeSequenceItemData: | 
					
						
							|  |  |  |     ; tile attributes | 
					
						
							|  |  |  |     db $0D, $0A, $0D, $0D, $0E, $0E, $0D, $0D, $0D, $0E, $09, $0A, $0A, $0D | 
					
						
							|  |  |  |     ; tile index | 
					
						
							|  |  |  |     db $1A, $B0, $B4, $B8, $BC, $C0, $C4, $C8, $CC, $D0, $D4, $D8, $DC, $E0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | UpdateInventoryMenu: | 
					
						
							|  |  |  |         ld   a, [wTradeSequenceItem] | 
					
						
							|  |  |  |         ld   hl, wTradeSequenceItem2 | 
					
						
							|  |  |  |         or   [hl] | 
					
						
							|  |  |  |         ret  z | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         ld   hl, TradeSequenceItemData | 
					
						
							|  |  |  |         ld   a, [$C109] | 
					
						
							|  |  |  |         ld   e, a | 
					
						
							|  |  |  |         ld   d, $00 | 
					
						
							|  |  |  |         add  hl, de | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         ; Check if we need to increase the counter | 
					
						
							|  |  |  |         ldh  a, [$E7] ; frame counter | 
					
						
							|  |  |  |         and  $0F | 
					
						
							|  |  |  |         jr   nz, .noInc | 
					
						
							|  |  |  |         ld   a, e | 
					
						
							|  |  |  |         inc  a | 
					
						
							|  |  |  |         cp   14 | 
					
						
							|  |  |  |         jr   nz, .noWrap | 
					
						
							|  |  |  |         xor  a | 
					
						
							|  |  |  | .noWrap: | 
					
						
							|  |  |  |         ld   [$C109], a | 
					
						
							|  |  |  | .noInc: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         ; Check if we have the item | 
					
						
							|  |  |  |         ld   b, e | 
					
						
							|  |  |  |         inc  b | 
					
						
							|  |  |  |         ld   a, $01 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         ld   de, wTradeSequenceItem | 
					
						
							|  |  |  | .shiftLoop: | 
					
						
							|  |  |  |         dec  b | 
					
						
							|  |  |  |         jr   z, .shiftLoopDone | 
					
						
							|  |  |  |         sla  a | 
					
						
							|  |  |  |         jr   nz, .shiftLoop | 
					
						
							|  |  |  |         ; switching to second byte | 
					
						
							|  |  |  |         ld   de, wTradeSequenceItem2 | 
					
						
							|  |  |  |         ld   a, $01 | 
					
						
							|  |  |  |         jr   .shiftLoop | 
					
						
							|  |  |  | .shiftLoopDone: | 
					
						
							|  |  |  |         ld   b, a | 
					
						
							|  |  |  |         ld   a, [de] | 
					
						
							|  |  |  |         and  b | 
					
						
							|  |  |  |         ret  z ; skip this item | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         ld   b, [hl] | 
					
						
							|  |  |  |         push hl | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         ; Write the tile attribute data | 
					
						
							|  |  |  |         ld   a, $01 | 
					
						
							|  |  |  |         ldh  [$4F], a | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         ld   hl, $9C6E | 
					
						
							|  |  |  |         call WriteToVRAM | 
					
						
							|  |  |  |         inc  hl   | 
					
						
							|  |  |  |         call WriteToVRAM | 
					
						
							|  |  |  |         ld   de, $001F | 
					
						
							|  |  |  |         add  hl, de | 
					
						
							|  |  |  |         call WriteToVRAM | 
					
						
							|  |  |  |         inc  hl   | 
					
						
							|  |  |  |         call WriteToVRAM | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         ; Write the tile data | 
					
						
							|  |  |  |         xor  a | 
					
						
							|  |  |  |         ldh  [$4F], a | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         pop  hl | 
					
						
							|  |  |  |         ld   de, 14 | 
					
						
							|  |  |  |         add  hl, de | 
					
						
							|  |  |  |         ld   b, [hl] | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         ld   hl, $9C6E | 
					
						
							|  |  |  |         call WriteToVRAM | 
					
						
							|  |  |  |         inc  b | 
					
						
							|  |  |  |         inc  b | 
					
						
							|  |  |  |         inc  hl   | 
					
						
							|  |  |  |         call WriteToVRAM | 
					
						
							|  |  |  |         ld   de, $001F | 
					
						
							|  |  |  |         add  hl, de | 
					
						
							|  |  |  |         dec  b | 
					
						
							|  |  |  |         call WriteToVRAM | 
					
						
							|  |  |  |         inc  hl   | 
					
						
							|  |  |  |         inc  b | 
					
						
							|  |  |  |         inc  b | 
					
						
							|  |  |  |         call WriteToVRAM | 
					
						
							|  |  |  |         ret | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | WriteToVRAM: | 
					
						
							|  |  |  |         ldh  a, [$41] | 
					
						
							|  |  |  |         and  $02 | 
					
						
							|  |  |  |         jr   nz, WriteToVRAM | 
					
						
							|  |  |  |         ld   [hl], b | 
					
						
							|  |  |  |         ret | 
					
						
							|  |  |  | LocalOnlyItemAndMessage: | 
					
						
							|  |  |  |         call GiveItemFromChest | 
					
						
							|  |  |  |         call ItemMessage | 
					
						
							|  |  |  |         ret | 
					
						
							| 
									
										
										
										
											2023-04-06 11:06:34 -07:00
										 |  |  |     """ + get_asm("multiworld.asm")
 | 
					
						
							|  |  |  |         + get_asm("link.asm") | 
					
						
							|  |  |  |         + get_asm("chest.asm") | 
					
						
							|  |  |  |         + get_asm("bowwow.asm") | 
					
						
							|  |  |  |         + get_asm("message.asm") | 
					
						
							|  |  |  |         + get_asm("itemnames.asm") | 
					
						
							| 
									
										
										
										
											2023-03-21 01:26:03 +09:00
										 |  |  |         + "".join(generate_name(["The Server"] + player_name_list, i ) for i in range(100)) # allocate | 
					
						
							|  |  |  |         + 'db "another world", $ff\n' | 
					
						
							| 
									
										
										
										
											2023-04-06 11:06:34 -07:00
										 |  |  |         + get_asm("owl.asm"), 0x4000), fill_nop=True) | 
					
						
							| 
									
										
										
										
											2023-03-21 01:26:03 +09:00
										 |  |  |     # 3E:3300-3616: Multiworld flags per room (for both chests and dropped keys) | 
					
						
							|  |  |  |     # 3E:3800-3B16: DroppedKey item types | 
					
						
							|  |  |  |     # 3E:3B16-3E2C: Owl statue or trade quest items | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     # Put 20 rupees in all owls by default. | 
					
						
							|  |  |  |     rom.patch(0x3E, 0x3B16, "00" * 0x316, "1C" * 0x316) | 
					
						
							|  |  |  |     | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Prevent the photo album from crashing due to serial interrupts | 
					
						
							|  |  |  |     rom.patch(0x28, 0x00D2, ASM("ld a, $09"), ASM("ld a, $01")) |