318 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			318 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
|   | from ..assembler import ASM | ||
|  | from ..roomEditor import RoomEditor, Object, ObjectVertical, ObjectHorizontal, ObjectWarp | ||
|  | from ..utils import formatText | ||
|  | 
 | ||
|  | 
 | ||
|  | def setRequiredInstrumentCount(rom, count): | ||
|  |     rom.texts[0x1A3] = formatText("You need %d instruments" % (count)) | ||
|  |     if count >= 8: | ||
|  |         return | ||
|  |     if count < 0: | ||
|  |         rom.patch(0x00, 0x31f5, ASM("ld a, [$D806]\nand $10\njr z, $25"), ASM(""), fill_nop=True) | ||
|  |         rom.patch(0x20, 0x2dea, ASM("ld a, [$D806]\nand $10\njr z, $29"), ASM(""), fill_nop=True) | ||
|  |         count = 0 | ||
|  | 
 | ||
|  |     # TODO: Music bugs out at the end, unless you have all instruments. | ||
|  |     rom.patch(0x19, 0x0B79, None, "0000")  # always spawn all instruments, we need the last one as that handles opening the egg. | ||
|  |     rom.patch(0x19, 0x0BF4, ASM("jp $3BC0"), ASM("jp $7FE0")) # instead of rendering the instrument, jump to the code below. | ||
|  |     rom.patch(0x19, 0x0BFE, ASM("""
 | ||
|  |         ; Normal check fo all instruments | ||
|  |         ld   e, $08 | ||
|  |         ld   hl, $DB65 | ||
|  |     loop: | ||
|  |         ldi  a, [hl] | ||
|  |         and  $02 | ||
|  |         jr   z, $12 | ||
|  |         dec  e | ||
|  |         jr   nz, loop | ||
|  |     """), ASM(""" | ||
|  |         jp   $7F2B ; jump to the end of the bank, where there is some space for code. | ||
|  |     """), fill_nop=True)
 | ||
|  |     # Add some code at the end of the bank, as we do not have enough space to do this "in place" | ||
|  |     rom.patch(0x19, 0x3F2B, "0000000000000000000000000000000000000000000000000000", ASM("""
 | ||
|  |         ld   d, $00 | ||
|  |         ld   e, $08 | ||
|  |         ld   hl, $DB65 ; start of has instrument memory | ||
|  | loop: | ||
|  |         ld   a, [hl] | ||
|  |         and  $02 | ||
|  |         jr   z, noinc | ||
|  |         inc  d | ||
|  | noinc: | ||
|  |         inc  hl | ||
|  |         dec  e | ||
|  |         jr   nz, loop | ||
|  |         ld   a, d | ||
|  |         cp   $%02x    ; check if we have a minimal of this amount of instruments. | ||
|  |         jp   c, $4C1A ; not enough instruments | ||
|  |         jp   $4C0B    ; enough instruments | ||
|  |     """ % (count)), fill_nop=True)
 | ||
|  |     rom.patch(0x19, 0x3FE0, "0000000000000000000000000000000000000000000000000000", ASM("""
 | ||
|  |     ; Entry point of render code | ||
|  |         ld   hl, $DB65  ; table of having instruments | ||
|  |         push bc | ||
|  |         ldh  a, [$F1] | ||
|  |         ld   c, a | ||
|  |         add  hl, bc | ||
|  |         pop  bc | ||
|  |         ld   a, [hl] | ||
|  |         and  $02        ; check if we have this instrument | ||
|  |         ret  z | ||
|  |         jp   $3BC0 ; jump to render code | ||
|  |     """), fill_nop=True)
 | ||
|  | 
 | ||
|  | 
 | ||
|  | def setSeashellGoal(rom, count): | ||
|  |     rom.texts[0x1A3] = formatText("You need %d {SEASHELL}s" % (count)) | ||
|  | 
 | ||
|  |     # Remove the seashell mansion handler (as it will take your seashells) but put a heartpiece instead | ||
|  |     re = RoomEditor(rom, 0x2E9) | ||
|  |     re.entities = [(4, 4, 0x35)] | ||
|  |     re.store(rom) | ||
|  | 
 | ||
|  |     rom.patch(0x19, 0x0ACB, 0x0C21, ASM("""
 | ||
|  |         ldh  a, [$F8] ; room status | ||
|  |         and  $10 | ||
|  |         ret  nz | ||
|  |         ldh  a, [$F0] ; active entity state | ||
|  |         rst  0 | ||
|  |         dw   state0, state1, state2, state3, state4 | ||
|  | 
 | ||
|  | state0: | ||
|  |         ld   a, [$C124] ; room transition state | ||
|  |         and  a | ||
|  |         ret  nz | ||
|  |         ldh  a, [$99]  ; link position Y | ||
|  |         cp   $70 | ||
|  |         ret  nc | ||
|  |         jp   $3B12  ; increase entity state | ||
|  | 
 | ||
|  | state1: | ||
|  |         call $0C05 ; get entity transition countdown | ||
|  |         jr   nz, renderShells | ||
|  |         ld   [hl], $10 | ||
|  |         call renderShells | ||
|  | 
 | ||
|  |         ld   hl, $C2B0 ; private state 1 table | ||
|  |         add  hl, bc | ||
|  |         ld   a, [wSeashellsCount] | ||
|  |         cp   [hl] | ||
|  |         jp   z, $3B12  ; increase entity state | ||
|  |         ld   a, [hl]   ; increase the amount of compared shells | ||
|  |         inc  a | ||
|  |         daa | ||
|  |         ld   [hl], a | ||
|  |         ld   hl, $C2C0 ; private state 2 table | ||
|  |         add  hl, bc | ||
|  |         inc  [hl] ; increase amount of displayed shells | ||
|  |         ld   a, $2B | ||
|  |         ldh  [$F4], a ; SFX | ||
|  |         ret | ||
|  | 
 | ||
|  | state2: | ||
|  |         ld   a, [wSeashellsCount] | ||
|  |         cp   $%02d | ||
|  |         jr   c, renderShells | ||
|  |         ; got enough shells | ||
|  |         call $3B12 ; increase entity state | ||
|  |         call $0C05 ; get entity transition countdown | ||
|  |         ld   [hl], $40 | ||
|  |         jp   renderShells | ||
|  | 
 | ||
|  | state3: | ||
|  |         ld   a, $23 | ||
|  |         ldh  [$F2], a ; SFX: Dungeon opened | ||
|  |         ld   hl, $D806 ; egg room status | ||
|  |         set  4, [hl] | ||
|  |         ld   a, [hl] | ||
|  |         ldh  [$F8], a ; current room status | ||
|  |         call $3B12 ; increase entity state | ||
|  | 
 | ||
|  |         ld   a, $00 | ||
|  |         jp   $4C2E | ||
|  | 
 | ||
|  | state4: | ||
|  |         ret | ||
|  | 
 | ||
|  | renderShells: | ||
|  |         ld   hl, $C2C0 ; private state 2 table | ||
|  |         add  hl, bc | ||
|  |         ld   a, [hl] | ||
|  |         cp   $14 | ||
|  |         jr   c, .noMax | ||
|  |         ld   a, $14 | ||
|  | .noMax: | ||
|  |         and  a | ||
|  |         ret  z | ||
|  |         ld   c, a | ||
|  |         ld   hl, spriteRect | ||
|  |         call $3CE6 ; RenderActiveEntitySpritesRect | ||
|  |         ret | ||
|  | 
 | ||
|  | spriteRect: | ||
|  |         db $10, $1E, $1E, $0C | ||
|  |         db $10, $2A, $1E, $0C | ||
|  |         db $10, $36, $1E, $0C | ||
|  |         db $10, $42, $1E, $0C | ||
|  |         db $10, $4E, $1E, $0C | ||
|  | 
 | ||
|  |         db $10, $5A, $1E, $0C | ||
|  |         db $10, $66, $1E, $0C | ||
|  |         db $10, $72, $1E, $0C | ||
|  |         db $10, $7E, $1E, $0C | ||
|  |         db $10, $8A, $1E, $0C | ||
|  | 
 | ||
|  |         db $24, $1E, $1E, $0C | ||
|  |         db $24, $2A, $1E, $0C | ||
|  |         db $24, $36, $1E, $0C | ||
|  |         db $24, $42, $1E, $0C | ||
|  |         db $24, $4E, $1E, $0C | ||
|  | 
 | ||
|  |         db $24, $5A, $1E, $0C | ||
|  |         db $24, $66, $1E, $0C | ||
|  |         db $24, $72, $1E, $0C | ||
|  |         db $24, $7E, $1E, $0C | ||
|  |         db $24, $8A, $1E, $0C | ||
|  |     """ % (count), 0x4ACB), fill_nop=True)
 | ||
|  | 
 | ||
|  | 
 | ||
|  | def setRaftGoal(rom): | ||
|  |     rom.texts[0x1A3] = formatText("Just sail away.") | ||
|  | 
 | ||
|  |     # Remove the egg and egg event handler. | ||
|  |     re = RoomEditor(rom, 0x006) | ||
|  |     for x in range(4, 7): | ||
|  |         for y in range(0, 4): | ||
|  |             re.removeObject(x, y) | ||
|  |     re.objects.append(ObjectHorizontal(4, 1, 0x4d, 3)) | ||
|  |     re.objects.append(ObjectHorizontal(4, 2, 0x03, 3)) | ||
|  |     re.objects.append(ObjectHorizontal(4, 3, 0x03, 3)) | ||
|  |     re.entities = [] | ||
|  |     re.updateOverlay() | ||
|  |     re.store(rom) | ||
|  | 
 | ||
|  |     re = RoomEditor(rom, 0x08D) | ||
|  |     re.objects[6].count = 4 | ||
|  |     re.objects[7].x += 2 | ||
|  |     re.objects[7].type_id = 0x2B | ||
|  |     re.objects[8].x += 2 | ||
|  |     re.objects[8].count = 2 | ||
|  |     re.objects[9].x += 1 | ||
|  |     re.objects[11] = ObjectVertical(7, 5, 0x37, 2) | ||
|  |     re.objects[12].x -= 1 | ||
|  |     re.objects[13].x -= 1 | ||
|  |     re.objects[14].x -= 1 | ||
|  |     re.objects[14].type_id = 0x34 | ||
|  |     re.objects[17].x += 3 | ||
|  |     re.objects[17].count -= 3 | ||
|  |     re.updateOverlay() | ||
|  |     re.overlay[7 + 60] = 0x33 | ||
|  |     re.store(rom) | ||
|  | 
 | ||
|  |     re = RoomEditor(rom, 0x0E9) | ||
|  |     re.objects[30].count = 1 | ||
|  |     re.objects[30].x += 2 | ||
|  |     re.overlay[7 + 70] = 0x0E | ||
|  |     re.overlay[8 + 70] = 0x0E | ||
|  |     re.store(rom) | ||
|  |     re = RoomEditor(rom, 0x0F9) | ||
|  |     re.objects = [ | ||
|  |         ObjectHorizontal(4, 0, 0x0E, 6), | ||
|  |         ObjectVertical(9, 0, 0xCA, 8), | ||
|  |         ObjectVertical(8, 0, 0x0E, 8), | ||
|  | 
 | ||
|  |         Object(3, 0, 0x38), | ||
|  |         Object(3, 1, 0x32), | ||
|  |         ObjectHorizontal(4, 1, 0x2C, 3), | ||
|  |         Object(7, 1, 0x2D), | ||
|  |         ObjectVertical(7, 2, 0x38, 5), | ||
|  |         Object(7, 7, 0x34), | ||
|  |         ObjectHorizontal(0, 7, 0x2F, 7), | ||
|  | 
 | ||
|  |         ObjectVertical(2, 3, 0xE8, 4), | ||
|  |         ObjectVertical(3, 2, 0xE8, 5), | ||
|  |         ObjectVertical(4, 2, 0xE8, 2), | ||
|  | 
 | ||
|  |         ObjectVertical(4, 4, 0x5C, 3), | ||
|  |         ObjectVertical(5, 2, 0x5C, 5), | ||
|  |         ObjectVertical(6, 2, 0x5C, 5), | ||
|  | 
 | ||
|  |         Object(6, 4, 0xC6), | ||
|  |         ObjectWarp(1, 0x1F, 0xF6, 136, 112) | ||
|  |     ] | ||
|  |     re.updateOverlay(True) | ||
|  |     re.entities.append((0, 0, 0x41)) | ||
|  |     re.store(rom) | ||
|  |     re = RoomEditor(rom, 0x1F6) | ||
|  |     re.objects[-1].target_x -= 16 | ||
|  |     re.store(rom) | ||
|  | 
 | ||
|  |     # Fix the raft graphics (this overrides some unused graphic tiles) | ||
|  |     rom.banks[0x31][0x21C0:0x2200] = rom.banks[0x2E][0x07C0:0x0800] | ||
|  | 
 | ||
|  |     # Patch the owl entity to run our custom end handling. | ||
|  |     rom.patch(0x06, 0x27F5, 0x2A77, ASM("""
 | ||
|  |         ld  a, [$DB95] | ||
|  |         cp  $0B | ||
|  |         ret nz | ||
|  |         ; If map is not fully loaded, return | ||
|  |         ld  a, [$C124] | ||
|  |         and a | ||
|  |         ret nz | ||
|  |         ; Check if we are moving off the bottom of the map | ||
|  |         ldh a, [$99] | ||
|  |         cp  $7D | ||
|  |         ret c | ||
|  |         ; Move link back so it does not move off the map | ||
|  |         ld  a, $7D | ||
|  |         ldh [$99], a | ||
|  |          | ||
|  |         xor a | ||
|  |         ld  e, a | ||
|  |         ld  d, a | ||
|  | 
 | ||
|  | raftSearchLoop: | ||
|  |         ld  hl, $C280 | ||
|  |         add hl, de | ||
|  |         ld  a, [hl] | ||
|  |         and a | ||
|  |         jr  z, .skipEntity | ||
|  |          | ||
|  |         ld  hl, $C3A0 | ||
|  |         add hl, de | ||
|  |         ld  a, [hl] | ||
|  |         cp  $6A | ||
|  |         jr  nz, .skipEntity | ||
|  | 
 | ||
|  |         ; Raft found, check if near the bottom of the screen. | ||
|  |         ld  hl, $C210 | ||
|  |         add hl, de | ||
|  |         ld  a, [hl] | ||
|  |         cp  $70 | ||
|  |         jr  nc, raftOffWorld | ||
|  | 
 | ||
|  | .skipEntity: | ||
|  |         inc e | ||
|  |         ld  a, e | ||
|  |         cp  $10 | ||
|  |         jr  nz, raftSearchLoop | ||
|  |         ret | ||
|  | 
 | ||
|  | raftOffWorld: | ||
|  |         ; Switch to the end credits | ||
|  |         ld  a, $01 | ||
|  |         ld  [$DB95], a | ||
|  |         ld  a, $00 | ||
|  |         ld  [$DB96], a | ||
|  |         ret | ||
|  |     """), fill_nop=True)
 | ||
|  | 
 | ||
|  |     # We need to run quickly trough part of the credits, or else it bugs out | ||
|  |     # Skip the whole windfish part. | ||
|  |     rom.patch(0x17, 0x0D39, None, ASM("ld a, $18\nld [$D00E], a\nret")) | ||
|  |     # And skip the zoomed out laying on the log | ||
|  |     rom.patch(0x17, 0x20ED, None, ASM("ld a, $00")) | ||
|  |     # Finally skip some waking up on the log. | ||
|  |     rom.patch(0x17, 0x23BC, None, ASM("jp $4CD9")) | ||
|  |     rom.patch(0x17, 0x2476, None, ASM("jp $4CD9")) |