diff options
Diffstat (limited to 'engine/overworld')
| -rw-r--r-- | engine/overworld/map_sprite_functions1.asm | 390 | ||||
| -rw-r--r-- | engine/overworld/set_blackout_map.asm | 29 | ||||
| -rw-r--r-- | engine/overworld/special_warps.asm | 147 | 
3 files changed, 566 insertions, 0 deletions
| diff --git a/engine/overworld/map_sprite_functions1.asm b/engine/overworld/map_sprite_functions1.asm new file mode 100644 index 00000000..48eed56e --- /dev/null +++ b/engine/overworld/map_sprite_functions1.asm @@ -0,0 +1,390 @@ +_UpdateSprites: ; 4bb7 (1:4bb7) +	ld h, wSpriteStateData1 / $100 +	inc h +	ld a, $e    ; (wSpriteStateData2 + $0e) & $ff +.spriteLoop +	ld l, a +	sub $e +	ld c, a +	ld [H_CURRENTSPRITEOFFSET], a +	ld a, [hl] +	and a +	jr z, .skipSprite   ; tests $c2Xe +	push hl +	push de +	push bc +	call .updateCurrentSprite +	pop bc +	pop de +	pop hl +.skipSprite +	ld a, l +	add $10             ; move to next sprite +	cp $e               ; test for overflow (back at $0e) +	jr nz, .spriteLoop +	ret +.updateCurrentSprite ; 4bd7 (1:4bd7) +	ld a, [H_CURRENTSPRITEOFFSET] +	and a +	jp z, UpdatePlayerSprite +	cp $f0 ; pikachu +	jp z, Func_1552 +	ld a, [hl] + +UpdateNonPlayerSprite: ; 4be3 (1:4be3) +	dec a +	swap a +	ld [$ff93], a  ; $10 * sprite# +	ld a, [wNPCMovementScriptSpriteOffset] ; some sprite offset? +	ld b, a +	ld a, [H_CURRENTSPRITEOFFSET] +	cp b +	jr nz, .unequal +	jp DoScriptedNPCMovement +.unequal +	jp UpdateNPCSprite + +; This detects if the current sprite (whose offset is at H_CURRENTSPRITEOFFSET) +; is going to collide with another sprite by looping over the other sprites. +; The current sprite's offset will be labelled with i (e.g. $c1i0). +; The loop sprite's offset will labelled with j (e.g. $c1j0). +; +; Note that the Y coordinate of the sprite (in [$c1k4]) is one of the following +; 9 values when the sprite is aligned with the grid: $fc, $0c, $1c, $2c, ..., $7c. +; The reason that 4 is added below to the coordinate is to make it align with a +; multiple of $10 to make comparisons easier. +DetectCollisionBetweenSprites: ; 4bf7 (1:4bf7) +	; nop +	 +	ld h, wSpriteStateData1 / $100 +	ld a, [H_CURRENTSPRITEOFFSET] +	ld l, a + +	ld a, [hl] ; a = [$c1i0] (picture) (0 if slot is unused) +	and a ; is this sprite slot slot used? +	ret z ; return if not used + +	ld a, l +	add 3 +	ld l, a + +	ld a, [hli] ; a = [$c1i3] (delta Y) (-1, 0, or 1) +	call SetSpriteCollisionValues + +	ld a, [hli] ; a = [$C1i4] (Y screen coordinate) +	add 4 ; align with multiple of $10 + +; The effect of the following 3 lines is to +; add 7 to a if moving south or +; subtract 7 from a if moving north. +	add b +	and $f0 +	or c + +	ld [$ff90], a ; store Y coordinate adjusted for direction of movement + +	ld a, [hli] ; a = [$c1i5] (delta X) (-1, 0, or 1) +	call SetSpriteCollisionValues +	ld a, [hl] ; a = [$C1i6] (X screen coordinate) + +; The effect of the following 3 lines is to +; add 7 to a if moving east or +; subtract 7 from a if moving west. +	add b +	and $f0 +	or c + +	ld [$ff91], a ; store X coordinate adjusted for direction of movement + +	ld a, l +	add 7 +	ld l, a + +	xor a +	ld [hld], a ; zero [$c1id] XXX what's [$c1id] for? +	ld [hld], a ; zero [$c1ic] (directions in which collisions occurred) + +	ld a, [$ff91] +	ld [hld], a ; [$c1ib] = adjusted X coordinate +	ld a, [$ff90] +	ld [hl], a ; [$c1ia] = adjusted Y coordinate + +	xor a ; zero the loop counter + +.loop +	ld [$ff8f], a ; store loop counter +	swap a +	ld e, a +	ld a, [H_CURRENTSPRITEOFFSET] +	cp e ; does the loop sprite match the current sprite? +	jp z, .next ; go to the next sprite if they match + +	ld d, h +	ld a, [de] ; a = [$c1j0] (picture) (0 if slot is unused) +	and a ; is this sprite slot slot used? +	jp z, .next ; go the next sprite if not used + +	inc e +	inc e +	ld a, [de] ; a = [$c1j2] ($ff means the sprite is offscreen) +	inc a +	jp z, .next ; go the next sprite if offscreen + +	ld a, [H_CURRENTSPRITEOFFSET] +	add 10 +	ld l, a + +	inc e +	ld a, [de] ; a = [$c1j3] (delta Y) +	call SetSpriteCollisionValues + +	inc e +	ld a, [de] ; a = [$C1j4] (Y screen coordinate) +	add 4 ; align with multiple of $10 + +; The effect of the following 3 lines is to +; add 7 to a if moving south or +; subtract 7 from a if moving north. +	add b +	and $f0 +	or c + +	sub [hl] ; subtract the adjusted Y coordinate of sprite i ([$c1ia]) from that of sprite j + +; calculate the absolute value of the difference to get the distance +	jr nc, .noCarry1 +	cpl +	inc a +.noCarry1 +	ld [$ff90], a ; store the distance between the two sprites' adjusted Y values + +; Use the carry flag set by the above subtraction to determine which sprite's +; Y coordinate is larger. This information is used later to set [$c1ic], +; which stores which direction the collision occurred in. +; The following 5 lines set the lowest 2 bits of c, which are later shifted left by 2. +; If sprite i's Y is larger, set lowest 2 bits of c to 10. +; If sprite j's Y is larger or both are equal, set lowest 2 bits of c to 01. +	push af +	rl c +	pop af +	ccf +	rl c + +; If sprite i's delta Y is 0, then b = 7, else b = 9. +	ld b, 7 +	ld a, [hl] ; a = [$c1ia] (adjusted Y coordinate) +	and $f +	jr z, .next1 +	ld b, 9 + +.next1 +	ld a, [$ff90] ; a = distance between adjusted Y coordinates +	sub b +	ld [$ff92], a ; store distance adjusted using sprite i's direction +	ld a, b +	ld [$ff90], a ; store 7 or 9 depending on sprite i's delta Y +	jr c, .checkXDistance + +; If sprite j's delta Y is 0, then b = 7, else b = 9. +	ld b, 7 +	dec e +	ld a, [de] ; a = [$c1j3] (delta Y) +	inc e +	and a +	jr z, .next2 +	ld b, 9 + +.next2 +	ld a, [$ff92] ; a = distance adjusted using sprite i's direction +	sub b ; adjust distance using sprite j's direction +	jr z, .checkXDistance +	jr nc, .next ; go to next sprite if distance is still positive after both adjustments + +.checkXDistance +	inc e +	inc l +	ld a, [de] ; a = [$c1j5] (delta X) + +	push bc + +	call SetSpriteCollisionValues +	inc e +	ld a, [de] ; a = [$c1j6] (X screen coordinate) + +; The effect of the following 3 lines is to +; add 7 to a if moving east or +; subtract 7 from a if moving west. +	add b +	and $f0 +	or c + +	pop bc + +	sub [hl] ; subtract the adjusted X coordinate of sprite i ([$c1ib]) from that of sprite j + +; calculate the absolute value of the difference to get the distance +	jr nc, .noCarry2 +	cpl +	inc a +.noCarry2 +	ld [$ff91], a ; store the distance between the two sprites' adjusted X values + +; Use the carry flag set by the above subtraction to determine which sprite's +; X coordinate is larger. This information is used later to set [$c1ic], +; which stores which direction the collision occurred in. +; The following 5 lines set the lowest 2 bits of c. +; If sprite i's X is larger, set lowest 2 bits of c to 10. +; If sprite j's X is larger or both are equal, set lowest 2 bits of c to 01. +	push af +	rl c +	pop af +	ccf +	rl c + +; If sprite i's delta X is 0, then b = 7, else b = 9. +	ld b, 7 +	ld a, [hl] ; a = [$c1ib] (adjusted X coordinate) +	and $f +	jr z, .next3 +	ld b, 9 + +.next3 +	ld a, [$ff91] ; a = distance between adjusted X coordinates +	sub b +	ld [$ff92], a ; store distance adjusted using sprite i's direction +	ld a, b +	ld [$ff91], a ; store 7 or 9 depending on sprite i's delta X +	jr c, .collision + +; If sprite j's delta X is 0, then b = 7, else b = 9. +	ld b, 7 +	dec e +	ld a, [de] ; a = [$c1j5] (delta X) +	inc e +	and a +	jr z, .next4 +	ld b, 9 + +.next4 +	ld a, [$ff92] ; a = distance adjusted using sprite i's direction +	sub b ; adjust distance using sprite j's direction +	jr z, .collision +	jr nc, .next ; go to next sprite if distance is still positive after both adjustments + +.collision +	ld a, l +	and $f0 ; collision with pikachu? +	jr nz, .asm_4cd9 +	xor a +	ld [wd434], a +	ld a, [$ff8f] +	cp $f +	jr nz, .asm_4cd9 +	call Func_4d0a +	jr .asm_4cef +.asm_4cd9 +	ld a, [$ff91] ; a = 7 or 9 depending on sprite i's delta X +	ld b, a +	ld a, [$ff90] ; a = 7 or 9 depending on sprite i's delta Y +	inc l + +; If delta X isn't 0 and delta Y is 0, then b = %0011, else b = %1100. +; (note that normally if delta X isn't 0, then delta Y must be 0 and vice versa) +	cp b +	jr c, .next5 +	ld b, %1100 +	jr .next6 +.next5 +	ld b, %0011 + +.next6 +	ld a, c ; c has 2 bits set (one of bits 0-1 is set for the X axis and one of bits 2-3 for the Y axis) +	and b ; we select either the bit in bits 0-1 or bits 2-3 based on the calculation immediately above +	or [hl] ; or with existing collision direction bits in [$c1ic] +	ld [hl], a ; store new value +	ld a, c ; useless code because a is overwritten before being used again + +; set bit in [$c1ie] or [$c1if] to indicate which sprite the collision occurred with +	inc l +	inc l +.asm_4cef +	ld a, [$ff8f] ; a = loop counter +	ld de, SpriteCollisionBitTable +	add a +	add e +	ld e, a +	jr nc, .noCarry3 +	inc d +.noCarry3 +	ld a, [de] +	or [hl] +	ld [hli], a +	inc de +	ld a, [de] +	or [hl] +	ld [hl], a + +.next +	ld a, [$ff8f] ; a = loop counter +	inc a +	cp $10 +	jp nz, .loop +	ret + +; takes delta X or delta Y in a +; b = delta X/Y +; c = 0 if delta X/Y is 0 +; c = 7 if delta X/Y is 1 +; c = 9 if delta X/Y is -1 +Func_4d0a: ; 4d0a (1:4d0a) +	ld a, [$ff91] +	ld b, a +	ld a, [$ff90] +	inc l +	cp b +	jr c, .asm_4d17 +	ld b, %1100 +	jr .asm_4d19 +.asm_4d17 +	ld b, %11 +.asm_4d19 +	ld a, c +	and b +	ld [wd434], a +	ld a, c +	inc l +	inc l +	ret +	 +SetSpriteCollisionValues: ; 4d22 (1:4d22) +	and a +	ld b, 0 +	ld c, 0 +	jr z, .done +	ld c, 9 +	cp -1 +	jr z, .ok +	ld c, 7 +	ld a, 0 +.ok +	ld b, a +.done +	ret + +SpriteCollisionBitTable: ; 4d35 (1:4d35) +	db %00000000,%00000001 +	db %00000000,%00000010 +	db %00000000,%00000100 +	db %00000000,%00001000 +	db %00000000,%00010000 +	db %00000000,%00100000 +	db %00000000,%01000000 +	db %00000000,%10000000 +	db %00000001,%00000000 +	db %00000010,%00000000 +	db %00000100,%00000000 +	db %00001000,%00000000 +	db %00010000,%00000000 +	db %00100000,%00000000 +	db %01000000,%00000000 +	db %10000000,%00000000 diff --git a/engine/overworld/set_blackout_map.asm b/engine/overworld/set_blackout_map.asm new file mode 100644 index 00000000..5faef173 --- /dev/null +++ b/engine/overworld/set_blackout_map.asm @@ -0,0 +1,29 @@ +SetLastBlackoutMap: ; 6ef0 (1:6ef0) +; Set the map to return to when +; blacking out or using Teleport or Dig. +; Safari rest houses don't count. + +	push hl +	ld hl, SafariZoneRestHouses +	ld a, [wCurMap] +	ld b, a +.loop +	ld a, [hli] +	cp -1 +	jr z, .notresthouse +	cp b +	jr nz, .loop +	jr .done + +.notresthouse +	ld a, [wLastMap] +	ld [wLastBlackoutMap], a +.done +	pop hl +	ret + +SafariZoneRestHouses: ; 6f0a (1:6f0a) +	db SAFARI_ZONE_REST_HOUSE_2 +	db SAFARI_ZONE_REST_HOUSE_3 +	db SAFARI_ZONE_REST_HOUSE_4 +	db -1
\ No newline at end of file diff --git a/engine/overworld/special_warps.asm b/engine/overworld/special_warps.asm new file mode 100644 index 00000000..29000d98 --- /dev/null +++ b/engine/overworld/special_warps.asm @@ -0,0 +1,147 @@ +SpecialWarpIn: ; 6042 (1:6042) +	call LoadSpecialWarpData +	predef LoadTilesetHeader +	ld hl,wd732 +	bit 2,[hl] ; dungeon warp or fly warp? +	res 2,[hl] +	jr z,.next +; if dungeon warp or fly warp +	ld a,[wDestinationMap] +	jr .next2 +.next +	bit 1,[hl] +	jr z,.next3 +	call EmptyFunc +.next3 +	ld a,0 +.next2 +	ld b,a +	ld a,[wd72d] +	and a +	jr nz,.next4 +	ld a,b +.next4 +	ld hl,wd732 +	bit 4,[hl] ; dungeon warp? +	ret nz +; if not dungeon warp +	ld [wLastMap],a +	ret + +; gets the map ID, tile block map view pointer, tileset, and coordinates +LoadSpecialWarpData: ; 6073 (1:6073) +	ld a, [wd72d] +	cp TRADE_CENTER +	jr nz, .notTradeCenter +	ld hl, TradeCenterSpec1 +	ld a, [hSerialConnectionStatus] +	cp USING_INTERNAL_CLOCK ; which gameboy is clocking determines who is on the left and who is on the right +	jr z, .copyWarpData +	ld hl, TradeCenterSpec2 +	jr .copyWarpData +.notTradeCenter +	cp COLOSSEUM +	jr nz, .notColosseum +	ld hl, ColosseumSpec1 +	ld a, [hSerialConnectionStatus] +	cp USING_INTERNAL_CLOCK +	jr z, .copyWarpData +	ld hl, ColosseumSpec2 +	jr .copyWarpData +.notColosseum +	ld a, [wd732] +	bit 1, a +	jr nz, .notFirstMap +	bit 2, a +	jr nz, .notFirstMap +	ld hl, FirstMapSpec +.copyWarpData +	ld de, wCurMap +	ld c, $7 +.copyWarpDataLoop +	ld a, [hli] +	ld [de], a +	inc de +	dec c +	jr nz, .copyWarpDataLoop +	ld a, [hli] +	ld [wCurMapTileset], a +	xor a +	jr .done +.notFirstMap +	ld a, [wLastMap] +	ld hl, wd732 +	bit 4, [hl] ; used dungeon warp (jumped down hole/waterfall)? +	jr nz, .usedDunegonWarp +	bit 6, [hl] ; return to last pokemon center (or player's house)? +	res 6, [hl] +	jr z, .otherDestination +; return to last pokemon center or player's house +	ld a, [wLastBlackoutMap] +	jr .usedFlyWarp +.usedDunegonWarp +	ld hl, wd72d +	res 4, [hl] +	ld a, [wDungeonWarpDestinationMap] +	ld b, a +	ld [wCurMap], a +	ld a, [wWhichDungeonWarp] +	ld c, a +	ld hl, DungeonWarpList +	ld de, 0 +	ld a, 6 +	ld [wDungeonWarpDataEntrySize], a +.dungeonWarpListLoop +	ld a, [hli] +	cp b +	jr z, .matchedDungeonWarpDestinationMap +	inc hl +	jr .nextDungeonWarp +.matchedDungeonWarpDestinationMap +	ld a, [hli] +	cp c +	jr z, .matchedDungeonWarpID +.nextDungeonWarp +	ld a, [wDungeonWarpDataEntrySize] +	add e +	ld e, a +	jr .dungeonWarpListLoop +.matchedDungeonWarpID +	ld hl, DungeonWarpData +	add hl, de +	jr .copyWarpData2 +.otherDestination +	ld a, [wDestinationMap] +.usedFlyWarp +	ld b, a +	ld [wCurMap], a +	ld hl, FlyWarpDataPtr +.flyWarpDataPtrLoop +	ld a, [hli] +	inc hl +	cp b +	jr z, .foundFlyWarpMatch +	inc hl +	inc hl +	jr .flyWarpDataPtrLoop +.foundFlyWarpMatch +	ld a, [hli] +	ld h, [hl] +	ld l, a +.copyWarpData2 +	ld de, wCurrentTileBlockMapViewPointer +	ld c, $6 +.copyWarpDataLoop2 +	ld a, [hli] +	ld [de], a +	inc de +	dec c +	jr nz, .copyWarpDataLoop2 +	xor a ; OVERWORLD +	ld [wCurMapTileset], a +.done +	ld [wYOffsetSinceLastSpecialWarp], a +	ld [wXOffsetSinceLastSpecialWarp], a +	ld a, $ff ; the player's coordinates have already been updated using a special warp, so don't use any of the normal warps +	ld [wDestinationWarpID], a +	ret
\ No newline at end of file | 
