If you appreciate the work done within the wiki, please consider supporting The Cutting Room Floor on Patreon. Thanks for all your support!

Urban Strike (Game Boy)

From The Cutting Room Floor
Jump to navigation Jump to search

Title Screen

Urban Strike

Developer: Borta
Publisher: Black Pearl
Platforms: Game Boy, Super Game Boy
Released in US: November 1996
Released in EU: 1996


SourceIcon.png This game has uncompiled source code.
DummyIcon.png This game has unusual dummy files.


Say hello to one of Game Boy's most hideous title screens.

Uncompiled Source Code

Two big chunks of uncompiled code can be found by using a hex editor on the ROM. Note that the formatting seen below matches the formatting seen in the ROM.

0x69E80:

        call    DO_SEQUENCE




START_INTERIOR_CAMPAIGN:

        ld      sp, $dfff                    ; set the stack pointer

        call    LCD_off

        call    InitWorld

        call    PlayGame

;═════════════════════════════════════════════════════════════════════════════

vr_start_wait:

; Waits for the beginning of vertical retrace. Returns immediately if the
; display is turned off. Interrupts must be disabled if this routine is called
; while the display is turned on.

        push    af

        ld      a, (LCDC)
        and     a, %10000000
        jr      z, .exit

.loop:

        ld      a, (LY)
        cp      a, 145 ; 144
        jr      nz, .loop

.exit:

        pop     af

        ret

;─────────────────────────────────────────────────────────────────────────────

vr_end_wait:

; Waits for the end of vertical retrace. Returns immediately if the display is
; turned off. Interrupts must be disabled if this routine is called while the
; display is turned on.

        push    af

        ld      a, (LCDC)
        and     a, %10000000
        jr      z, .exit

.loop:

        ld      a, (LY)
        or      a, a
        jr      nz, .loop

.exit:

        pop     af

        ret

;─────────────────────────────────────────────────────────────────────────────

LCD_off:

; Turns off the video display. Assumes interrupts are disabled.

        push    af

        call    vr_start_wait

        ld      a, (LCDC)
        and     a, %01111100
        ld      (LCDC), a

        pop     af

        ret

;─────────────────────────────────────────────────────────────────────────────

LCD_on:

; Turns on the video display.

        push    af

        ld      a, (LCDC)
        or      a, %10000011
        ld      (LCDC), a

        pop     af

        ret

;─────────────────────────────────────────────────────────────────────────────

;LCD_on_bkgr_off:

; Disables the display of the background but leaves the screen on.

;        push    af
;
;        ld      a, (LCDC)
;        or      a, %10000000
;        and     a, %11111110
;        ld      (LCDC), a
;
;        pop     af
;
;        ret


;─────────────────────────────────────────────────────────────────────────────

bkgr_off:

; Disables the display of the background.

        push    af

        ld      a, (LCDC)
        and     a, %11111110
        ld      (LCDC), a

        pop     af

        ret

;─────────────────────────────────────────────────────────────────────────────

bkgr_on:

; Enables the display of the background.

        push    af

        ld      a, (LCDC)
        or      a, %00000001
        ld      (LCDC), a

        pop     af

        ret

;─────────────────────────────────────────────────────────────────────────────

spr_off:

; Disables the display of sprites.

        push    af

        ld      a, (LCDC)
        and     a, %11111101
        ld      (LCDC), a

        pop     af

        ret

;─────────────────────────────────────────────────────────────────────────────

spr_on:

; Enables the display of sprites.

        push    af

        ld      a, (LCDC)
        or      a, %00000010
        ld      (LCDC), a

        pop     af

        ret




;─────────────────────────────────────────────────────────────────────────────




sound_off:

        push    af

        ld      a, (sound_flags)
        and     a, 254
        ld      (sound_flags), a

        xor     a, a
	ld	(NR52), a

        pop     af

        ret


sound_on:

        push    af

        ld      a, (sound_flags)
        or      a, 1
        ld      (sound_flags), a



        ld      a, %11111111
	ld	(NR51), a
	ld	(NR50), a

        ld      a, %10001000
	ld	(NR52), a


        pop     af

        ret




;─────────────────────────────────────────────────────────────────────────────

cls:

; Clears one of the two VRAM display areas. May be called only when the
; display is turned off.

; call with D = area number (0 or 1)
;           E = clear value

;        push    af
;        push    bc
;        push    hl

        ld      bc, 1024

        ld      hl, $9800

        bit     0, d
        jr      z, .loop

        ld      h, $9c

.loop:

        ld      (hl), e
        inc     hl

        dec     bc
        ld      a, c
        or      a, b
        jr      nz, .loop

;        pop     hl
;        pop     bc
;        pop     af

        ret


;─────────────────────────────────────────────────────────────────────────────

get_buttons:

; Returns with A = status of the buttons.

        push    bc

        ld      c, 0

        ld      a, $20
        ld      (c), a                 ; select direction buttons

        ld      a, (c)
        ld      a, (c)
        ld      a, (c)

        and     a, $0f                 ; A = 0000dulr
        ld      b, a                   ; B = 0000dulr

        ld      a, $10
        ld      (c), a                 ; select other buttons

        ld      a, (c)
        ld      a, (c)
        ld      a, (c)
        ld      a, (c)
        ld      a, (c)
        ld      a, (c)
        ld      a, (c)
        ld      a, (c)
        ld      a, (c)

        and     a, $0f                 ; A = 0 0 0 0 sta sel b a
        swap    a                      ; A = sta sel b a 0 0 0 0
        or      a, b                   ; A = sta sel b a d u l r
        cpl

        pop     bc

        ret




;─────────────────────────────────────────────────────────────────────────────

fill_copy_proc:

; call with B  =  total bytes of data / 2; B must be <= 144
;           DE -> second-to-last byte of data
;           the correct bank selected

; Before jumping to copy_proc, set SP -> byte after last destination byte, and
; HL = return address.

        push    af
        push    bc
        push    de
        push    hl

        ld      hl, copy_proc

.loop:

        inc     hl

        ld      a, (de)
        inc     de
        ld      (hli), a

        ld      a, (de)
        dec     de
        dec     de
        dec     de
        ld      (hli), a

        inc     hl

        dec     b
        jr      nz, .loop

        ld      a, (jp_addr)
        ld      e, a
        ld      a, (jp_addr + 1)
        ld      d, a
        ld      a, $11
        ld      (de), a                ; "erase" previous "jp (hl)" instr.

        ld      a, $e9                 ; $e9 = "jp (hl)"
        ld      (hl), a                ; insert "jp (hl)" instruction

        ld      a, l
        ld      (jp_addr), a
        ld      a, h
        ld      (jp_addr + 1), a

        pop     hl
        pop     de
        pop     bc
        pop     af

        ret

;─────────────────────────────────────────────────────────────────────────────

load_chars:

; call with (dest_addr) -> byte after last destination byte

; May be called only when the display is turned off or during v-blank. If
; (dest_addr + 1) = 0, then load_chars does nothing. load_chars sets
; (dest_addr + 1) = 0.


        ld      (stack_save), sp
        ld      sp, hl                 ; SP = (dest_addr)

        ld      hl, .back

        jp      copy_proc

.back:

        ld      hl, stack_save
        ld      a, (hli)
        ld      h, (hl)
        ld      l, a                   ; HL = (stack_save)
        ld      sp, hl                 ; SP = (stack_save)


        ret

;─────────────────────────────────────────────────────────────────────────────

RAMMoveSpriteObject:

; call with A = total sprites in object
;           C = number of first sprite (0 - 39)
;           D = dy
;           E = dx

        push    af
        push    bc
        push    hl

        ld      b, a                   ; B = total sprites in object

        ld      a, c                   ; A = number of first sprite
        add     a, a
        add     a, a                   ; A = number of first sprite * 4

        ld      l, a
        ld      h, $c0                 ; HL -> sprite in RAM sprite table

.loop:

        ld      a, (hl)                ; A = sprite y-coordinate
        cp      a, $e0
        jr      z, .skip

        add     a, d
        ld      (hli), a

        ld      a, (hl)                ; A = sprite x-coordi

0x6EB0B:

ld      b, 11

.ENCODE_LOOP:

        ld      a, (hl)

        ld      de, PASS_CHAR

        add     a, e
        ld      e, a
        ld      a, d
        adc     a, 0
        ld      d, a

        ld      a, (de)

        ld      (hli), a

        dec     b
        jr      nz, .ENCODE_LOOP



        ret







;*******************************************************
;*******************************************************
;*******************************************************
;*******************************************************
;*******************************************************

; password decoding








;*******************************************************
; PASS_DECODE:
;*******************************************************

PASS_DECODE:

        ; copy PASSWD to PASSWD_TEMP, reduce to 0-31 range

        ld      hl, PWString
        ld      de, PWTemp
        ld      b, 11

.REDUCE_LOOP:

        ld      a, (hli)                ; a = character from p.w. string

        push    bc
        push    hl

        ld      hl, PASS_CHAR + 30   ; 28 ; 31

        ld      b, 31       ; 29 ; 32

.search:

        ld      c, (hl)
        dec     hl

        cp      a, c

        jr      z, .match

        dec     b
        jr      nz, .search

        pop     hl
        pop     bc

        jp      .FAIL

.match:

        dec     b
        ld      a, b

        ld      (de), a
        inc     de

        pop     hl
        pop     bc

        dec     b
        jr      nz, .REDUCE_LOOP







.DECODE:

        ld      a, (PWTemp_5)
        sra     a
        ld      b, a
        ld      (nibble_2), a

        ld      a, (PWTemp_10)
        sub     a, b
        ld      b, a
        ld      (nibble_5), a

        ld      a, (PWTemp_1)
        sub     a, b
        ld      b, a
        ld      (nibble_3), a

        ld      a, (PWTemp_4)
        sub     a, b
        ld      b, a
        ld      (nibble_0), a

        ld      a, (PWTemp_7)
        sub     a, b
        ld      b, a
        ld      (nibble_1), a

        ld      a, (PWTemp_8)
        sub     a, b
        ld      b, a
        ld      (nibble_7), a

        ld      a, (PWTemp_0)
        sub     a, b
        ld      b, a
        ld      (nibble_4), a

        ld      a, (PWTemp_9)
        sub     a, b
        ld      b, a
        ld      (nibble_6), a

        ld      a, (PWTemp_2)
        sub     a, b
        ld      b, a
        ld      (nibble_8), a





.CHECK:

        ld      hl, nibble
        ld      de, 0
        ld      b, 9

.CHECK_LOOP:

        ld      a, (hl)
        add     a, d
        ld      d, a

        ld      a, (hli)
        xor     a, e
        ld      e, a

        dec     b
        jr      nz, .CHECK_LOOP

        ld      a, (PWTemp_3)
        ld      c, a
        ld      a, d

;        and     a, 01Fh

.loop:

        cp      a, 31
        jr      c, .ok

        sub     a, 31
        jr      .loop

.ok:


        cp      c
        jr      NZ, .FAIL

        ld      a, (PWTemp_6)
        ld      c, a
        ld      a, e
        sla     a
        cp      c
        jr      NZ, .FAIL





.UNMANGLE:

        ld      de, GameScore
        ld      hl, CRYPTO
        STORE_HL_TO      TEMPW_2
        
        ld      hl, nibble
        
        ld      b, 4


.UNMANGLE_LOOP:

        ld      a, (hli)
        ld      c, a

        ld      a, (hli)
        sla     a
        sla     a
        sla     a
        sla     a
        or      a, c

        push    hl
        push    af
        LOAD_HL_FROM     TEMPW_2
        pop     af

        xor     a, (hl)
        inc     hl

        ld      (de), a
        inc     de

        STORE_HL_TO      TEMPW_2
        pop     hl



        dec     b
        jr      nz, .UNMANGLE_LOOP


        ; check level < FINAL_WORLD

        ld      a, (hl)
        cp      a, FINAL_WORLD + 3      ; allow view game end (=10) , credits (=11), fail on (=12)
        jr      NC, .FAIL

        ld      (CURR_WORLD), a

        and     a, a
        
        ret

.FAIL:

 jr .FAIL


        ; zero out the current world and game score

        xor     a
        ld      hl, GameScore
        ld      (hli), a
        ld      (hli), a
        ld      (hli), a
        ld      (hli), a
        ld      (CURR_WORLD), a


        scf
        
        ret

cp      a, FINAL_WORLD + 3      ; allow view game end (=10) , credits (=11), fail on (=12)
        jr      NC, .FAIL

        ld      (CURR_WORLD), a

        and     a, a
        
        ret

.FAIL:

 jr .FAIL


        ; z

ZIP Archives

Two corrupted ZIP archives that probably contained more source code of the game can be found in the ROM. The last modified dates of the files they contain range between 6 to 10 months before the final US release date.

0x27F8C:

Contains a file named OSTRUCT4.ASM with a last modified date of 1996-05-09 10:49:00 in UTC time that can't be extracted due to the ZIP file's corruption.

0x4FEFE:

Contains two files: one of them is named OSTRUCT.INC, has a last modified date of 1996-01-17 08:36:16 in UTC time and can't be extracted for the same reason of the precedent one. The other file, UDATA.INC, was last modified on 1996-03-13 10:59:30 UTC and can be extracted:

PASS_CHAR:

;                db      "0123456789ABCDEFGHJKMNPQRTUVWXYZ"

                db       "0123456789BCDFGHJKLMNPQRSTVWXYZ"



From the commented-out instruction it can be seen that at some point of the development A, E and U were valid password characters before being replaced with L and S in the final game (one character was removed in the final version).

(Discovery of the ZIP archives: WaluigiBSOD)