REM > <HeeHeeHee$Dir>.!RunImage

LIBRARY "<HeeHeeHee$Dir>.GameLib"

ON ERROR MODE 12: PROCGameLib_Error
MODE 15: MODE 13: OFF

DIM B% 1000, Stars% 40000
Table_Character% = 0
Table_Bullets%   = 1
Table_Platforms% = 2
Table_Ladders%   = 3
Table_Walls%     = 4
Table_Enemies%   = 5
Table_Xplosions% = 6
Table_Droids%    = 7
Table_Items%     = 8

Total_Droids%    = 100
Size_Droids%     = 44

PROCGameLib_Show(&80000000, "")
PROCGameLib_Text("Choose a level . . .")
PROCGameLib_Text("  1 - James")
PROCGameLib_Text("  2 - James 2")
Level$ = ""
 REPEAT
  a$ = GET$
   CASE a$ OF
    WHEN "1": Level$ = "James"
    WHEN "2": Level$ = "James2"
    OTHERWISE: VDU7
   ENDCASE
 UNTIL Level$ <> ""

PROCGameLib_Show(&80008000, "Loading...")
PROCMakeStars
PROCAssemble
PROCAmnesia_Init(500000)
PROCFastSpr_Load(0, "<HeeHeeHee$Dir>.Grafix")
PROCFastSpr_Load(1, "<HeeHeeHee$Dir>.Icons")
PROCAmnesia_ClaimTable(Table_Character%, 1,    1,  32)
PROCAmnesia_ClaimTable(Table_Bullets%,   1,   10,  32)
PROCAmnesia_ClaimTable(Table_Platforms%, 0, 1000,  32)
PROCAmnesia_ClaimTable(Table_Ladders%,   1,  500,  32)
PROCAmnesia_ClaimTable(Table_Walls%,     1, 1000,  32)
PROCAmnesia_ClaimTable(Table_Enemies%,   1,   10, 32+30*12)
PROCAmnesia_ClaimTable(Table_Xplosions%, 0,   10,  32)
PROCAmnesia_ClaimTable(Table_Droids%,    1, Total_Droids%, Size_Droids%)
PROCAmnesia_ClaimTable(Table_Items%,     1,  100,  32)
PROCAmnesia_SetGravity(0, 1 << 10)
PROCLevel_Init(Level$)
PROCAmnesia_SetWindow(0, 0, 0, Wide% << 16, High% << 16)
PROCAmnesia_SetWindow(1, -1 << 16, -1 << 16, 20 << 16, 15 << 16)
PROCAmnesia_SetWindow(2, 0, 0, Wide% << 16, High% << 16)
PROCGameLib_Fade
PROCFastSpr_Bank(2)
PROCFastSpr_Plot(&01000000, 160, 244)
PROCFastSpr_Bank(1)
PROCFastSpr_Plot(&01000000, 160, 244)
PROCFastSpr_SetClipWindow(0, 0, 320, 240)
PROCFastSpr_SetBackdrop(0)

 CASE USR(Code%) OF
  WHEN 0: PROCGameLib_Show(&00800000, "Level Complete")
  WHEN 1: PROCGameLib_Show(&00008000, "Game Over")
 ENDCASE

T% = TIME: REPEAT: UNTIL TIME > T% + 100
SYS"OS_Byte", 15, 1
IF GET THEN PROCGameLib_Fade
END

REM ˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜

DEF PROCAssemble

fire_delay% = 10
REMrobot_timer% = &00C80001

Size% = 3 * 1024
DIM Code% Size% - 1
L% = Code% + Size% - 1

REM FOR Pass% = 8 TO 11 STEP 3
 FOR Pass% = 8 TO 10 STEP 2
  P% = Code%
[OPT     Pass%
; <- R0 = reason for end
;          0 = level complete
;          1 = game over
; --------------------------------------------------------------------------
;initialisation
STMFD   R13!, {R14}
STR     R13, exit
MOV     R0, #1
STR     R0, bank

MOV     R0, #Table_Character%
BL      object_find

; --------------------------------------------------------------------------
.main
LDR     R0, frame
ADD     R0, R0, #1
STR     R0, frame

BL      swap_screen_bank

BL      escape
BL      scan_keys
TST     R0, #(1 << 0) : BLne    move_left
TST     R0, #(1 << 1) : BLne    move_right
TST     R0, #(1 << 2) : BLne    move_jump
TST     R0, #(1 << 4) : BLne    move_down
TST     R0, #(%11)    : BLeq    move_stand
AND     R8, R0, #%1001: CMP     R8, #%1001    : BLeq    fire_left
AND     R8, R0, #%1010: CMP     R8, #%1010    : BLeq    fire_right
AND     R8, R0, #%1000: CMP     R8, #%1000    : BLeq    fire_stand

BL      platforms
BL      droids

BL      screen_background
MOV     R2, #0
MOV     R0, #Table_Platforms% : BL      process_table
MOV     R0, #Table_Walls%     : BL      process_table
MOV     R0, #Table_Ladders%   : BL      process_table
MOV     R0, #Table_Items%     : BL      process_table
MOV     R0, #Table_Character% : BL      process_table
MOV     R0, #Table_Enemies%   : BL      process_Enemies
MOV     R0, #Table_Droids%    : BL      process_Droids
MOV     R0, #Table_Xplosions% : BL      process_table
MOV     R0, #Table_Bullets%   : BL      process_table

BL      stars

BL      collisions_Character_Bullets
BL      collisions_Bullets_Bullets
BL      collisions_Walls_Bullets
BL      collisions_Enemies_Bullets
BL      collisions_Droids_Bullets
BL      collisions_Character_Enemies
BL      collisions_Character_Droids
BL      collisions_Droids_Walls
BL      collisions_Character_Items

B       main

.frame
EQUD    0

; --------------------------------------------------------------------------
.finalisation
MOV     R3, R0
MOV     R0, #15
MOV     R1, #1
SWI     "OS_Byte"
MOV     R0, R3
LDR     R13, exit
LDMFD   R13!, {PC}^

; --------------------------------------------------------------------------
; data
.exit
EQUD    0
.bank
EQUD    0
.energy
EQUD    320

; --------------------------------------------------------------------------
.swap_screen_bank
; -> nothing
; <- no change
STMFD   R13!, {R0-R3}

MOV     R0, #19                 ; WAIT
SWI     "OS_Byte"

LDR     R3, bank                ; load bank from memory

MOV     R0, #113                ; display screen bank
MOV     R1, R3
SWI     "OS_Byte"

RSB     R3, R3, #3              ; swap bank

SUB     R0, R3, #1              ; set bank for FastSpr
SWI     "FastSpr_ScreenBank"

MOV     R0, #112                ; VDU driver screen bank
MOV     R1, R3
SWI     "OS_Byte"

STR     R3, bank                ; save bank to memory

LDMFD   R13!, {R0-R3}
MOV     PC, R14

; --------------------------------------------------------------------------
.screen_background
; -> R0 = backdrop sprite number
; <- no change
STMFD   R13!, {R0-R2}

;LDR     R1, scroll_x
;MOV     R1, R1, ASR#12
;LDR     R2, scroll_y
;MOV     R2, R2, ASR#12
;SWI     "FastSpr_Plot"

SWI     "FastSpr_ClearWindow"

LDMFD   R13!, {R0-R2}
MOV     PC, R14

; --------------------------------------------------------------------------
.escape
; -> nothing
; <- exits if escape was pressed
STMFD   R13!, {R0-R1}

MOV     R0, #121
MOV     R1, #(112 EOR &80)
SWI     "OS_Byte"
CMP     R1, #&FF
LDMneFD R13!, {R0-R1}
MOVne   PC, R14

MOV     R0, #1
B       finalisation

; --------------------------------------------------------------------------
.scan_keys
; -> nothing
; <- R0 = key flags    bit     key
;                       0       left
;                       1       right
;                       2       jump
;                       3       fire
;                       4       down
STMFD   R13!, {R1-R3}

MOV     R3, #0
MOV     R0, #121

MOV     R1, #(97 EOR &80)
SWI     "OS_Byte"
CMP     R1, #&FF
ORReq   R3, R3, #%001

MOV     R1, #(66 EOR &80)
SWI     "OS_Byte"
CMP     R1, #&FF
ORReq   R3, R3, #%010

CMP     R3, #%11
MOVeq   R3, #0

MOV     R1, #(79 EOR &80)
SWI     "OS_Byte"
CMP     R1, #&FF
ORReq   R3, R3, #%100

MOV     R1, #(73 EOR &80)
SWI     "OS_Byte"
CMP     R1, #&FF
ORReq   R3, R3, #%1000

MOV     R1, #(104 EOR &80)
SWI     "OS_Byte"
CMP     R1, #&FF
ORReq   R3, R3, #%10000

MOV     R0, R3

LDMFD   R13!, {R1-R3}
MOV     PC, R14

; --------------------------------------------------------------------------
.object_find
; -> R0 = table
; <- R1 = pointer to first object
STMFD   R13!, {R0, R2}

MOV     R1, #0
MOV     R2, #1
SWI     "Amnesia_SelectTable"

LDMFD   R13!, {R0, R2}
MOV     PC, R14

; --------------------------------------------------------------------------
.move_stand
; -> R1 = pointer to character
; <- no change
STMFD   R13!, {R0, R2}

LDR     R2, move_char_now
ADD     R2, R2, #1
AND     R2, R2, #3
STR     R2, move_char_now
ADR     R0, move_chars
LDR     R0, [R0, R2, LSL #2]
STR     R0, [R1]

LDMFD   R13!, {R0, R2}
MOV     PC, R14

.move_char_now
EQUD    0
.move_chars
EQUD    &00010001       ; 0 left 1
EQUD    &00000001       ; 1 standard
EQUD    &00030001       ; 2 right 1
EQUD    &00000001       ; 3 standard
; left
EQUD    &00030001       ; 6 right 1
EQUD    &00040001       ; 7 right 2
; right
EQUD    &00010001       ; 4 left 1
EQUD    &00020001       ; 5 left 2

; --------------------------------------------------------------------------
.move_left
; -> R1 = pointer to character
; <- no change
STMFD   R13!, {R0-R3, R14}

LDR     R2, move_char_now       ; increment animation
CMP     R2, #3
MOVle   R2, #3
CMP     R2, #6
MOVge   R2, #3
ADD     R2, R2, #1
CMP     R2, #6
MOVeq   R2, #4
STR     R2, move_char_now
ADR     R0, move_chars
LDR     R0, [R0, R2, LSL #2]
STR     R0, [R1]

LDR     R0, [R1, #8]            ; move left
CMP     R0, #(1 << 15)
LDMeqFD R13!, {R0-R3, R14}      ; exit if already at furthest left
MOVeq   PC, R14

MOV     R3, R0
SUB     R0, R0, #(2 << 12)
STR     R0, [R1, #8]

MOV     R2, #0
STR     R2, fire_direction

STMFD   R13!, {R0, R2}
MOV     R0, #Table_Character%
MOV     R2, #1
BL      process_table
LDMFD   R13!, {R0, R2}

BL      collisions_Character_Walls
MOVne   R0, R3
STRne   R0, [R1, #8]

BL      scroll_horizontal

LDMFD   R13!, {R0-R3, R14}
MOV     PC, R14

; --------------------------------------------------------------------------
.move_right
; -> R1 = pointer to character
; <- no change
STMFD   R13!, {R0-R3, R14}

LDR     R2, move_char_now
CMP     R2, #5
MOVle   R2, #5
ADD     R2, R2, #1
CMP     R2, #8
MOVeq   R2, #6
STR     R2, move_char_now
ADR     R0, move_chars
LDR     R0, [R0, R2, LSL #2]
STR     R0, [R1]

LDR     R0, [R1, #8]            ; move right
LDR     R2, move_right_edge
CMP     R0, R2
LDMeqFD R13!, {R0-R3, R14}      ; exit if already at furthest right
MOVeq   PC, R14

MOV     R3, R0
ADD     R0, R0, #(2 << 12)
STR     R0, [R1, #8]

MOV     R2, #1
STR     R2, fire_direction

STMFD   R13!, {R0, R2}
MOV     R0, #Table_Character%
MOV     R2, #1
BL      process_table
LDMFD   R13!, {R0, R2}

BL      collisions_Character_Walls
MOVne   R0, R3
STRne   R0, [R1, #8]

BL      scroll_horizontal

LDMFD   R13!, {R0-R3, R14}
MOV     PC, R14

.move_right_edge
EQUD    0 ;((Wide% - 1) << 16) + (1 << 15)

; --------------------------------------------------------------------------
.scroll_horizontal
; -> R0 = character x position
; <- no change
STMFD   R13!, {R0-R1}

RSB     R0, R0, #0
ADD     R0, R0, #(160 << 12)
CMP     R0, #0
MOVgt   R0, #0
LDR     R1, scroll_x_end
CMP     R0, R1
MOVlt   R0, R1
STR     R0, scroll_x
LDR     R1, scroll_y
SWI     "Amnesia_SetPlotOffset"

LDMFD   R13!, {R0-R1}
MOV     PC, R14

.scroll_x
EQUD    0 ;(Wide% << 16) - (320 << 12)
.scroll_x_end
EQUD    0 ;(Wide% << 16) - (320 << 12)

; --------------------------------------------------------------------------
.scroll_vertical
; -> R1 = character y position
; <- no change
STMFD   R13!, {R0-R1}

RSB     R1, R1, #0
ADD     R1, R1, #(120 << 12)
CMP     R1, #0
MOVgt   R1, #0
LDR     R0, scroll_y_end
CMP     R1, R0
MOVlt   R1, R0
STR     R1, scroll_y
LDR     R0, scroll_x
SWI     "Amnesia_SetPlotOffset"

LDMFD   R13!, {R0-R1}
MOV     PC, R14

.scroll_y
EQUD    0 ;-((High% << 16) - (240 << 12))
.scroll_y_end
EQUD    0 ;-((High% << 16) - (240 << 12))

; --------------------------------------------------------------------------
.move_jump
; -> R1 = pointer to character
; <- no change
STMFD   R13!, {R0, R14}

LDR     R0, [R1, #4]
TST     R0, #(1 << 3)
LDMneFD R13!, {R0, R14}
MOVne   PC, R14

BL      collisions_Character_Ladders
Beq     move_jump_1

LDR     R0, [R1, #12]
SUB     R0, R0, #(2 << 12)
STR     R0, [R1, #12]

STMFD   R13!, {R2}
MOV     R0, #Table_Character%
MOV     R2, #1
BL      process_table
LDMFD   R13!, {R2}

LDMFD   R13!, {R0, R14}
MOV     PC, R14

.move_jump_1
ORR     R0, R0, #(1 << 3)
STR     R0, [R1, #4]
LDR     R0, move_jump_velocity
STR     R0, [R1, #20]

LDMFD   R13!, {R0, R14}
MOV     PC, R14

.move_jump_velocity
EQUD    -(4 << 12)

; --------------------------------------------------------------------------
.move_down
; -> R1 = pointer to character
; <- no change
STMFD   R13!, {R0, R14}

LDR     R0, [R1, #4]
TST     R0, #(1 << 3)
LDMneFD R13!, {R0, R14}
MOVne   PC, R14

;L      collisions_1_8
;DMeqFD R13!, {R0, R14}
;OVeq   PC, R14

LDR     R0, [R1, #12]
ADD     R0, R0, #(2 << 12)
STR     R0, [R1, #12]

STMFD   R13!, {R2}
MOV     R0, #Table_Character%
MOV     R2, #1
BL      process_table
LDMFD   R13!, {R2}

LDMFD   R13!, {R0, R14}
MOV     PC, R14

; --------------------------------------------------------------------------
.fire_left
; -> R1 = pointer to character
; <- no change
STMFD   R13!, {R0-R9}

.fire_left_jump
LDR     R4, fired_frame
LDR     R5, frame
ADD     R4, R4, #fire_delay%
CMP     R5, R4
LDMltFD R13!, {R0-R9}
MOVlt   PC, R14
STR     R5, fired_frame

MOV     R9, R1

MOV     R0, #Table_Bullets%
MOV     R1, #2
LDR     R2, fire_flags
LDR     R3, [R9, #8]
SUB     R3, R3, #(1 << 15)
LDR     R4, [R9, #12]
LDR     R5, fire_left_velocity
MOV     R6, #0
LDR     R7, bullet_timer
MOV     R8, #0
SWI     "Amnesia_MakeObject"

LDMFD   R13!, {R0-R9}
MOV     PC, R14

.fire_left_velocity
EQUD    -(1 << 14)

.fire_flags
EQUD    %11000001011010101

.bullet_timer
EQUD    &00320001

; --------------------------------------------------------------------------
.fire_right
; -> R1 = pointer to character
; <- no change
STMFD   R13!, {R0-R9}

.fire_right_jump
LDR     R4, fired_frame
LDR     R5, frame
ADD     R4, R4, #fire_delay%
CMP     R5, R4
LDMltFD R13!, {R0-R9}
MOVlt   PC, R14
STR     R5, fired_frame

MOV     R9, R1

MOV     R0, #Table_Bullets%
MOV     R1, #2
LDR     R2, fire_flags
LDR     R3, [R9, #8]
ADD     R3, R3, #(1 << 15)
LDR     R4, [R9, #12]
LDR     R5, fire_right_velocity
MOV     R6, #0
LDR     R7, bullet_timer
MOV     R8, #0
SWI     "Amnesia_MakeObject"

LDMFD   R13!, {R0-R9}
MOV     PC, R14

.fire_right_velocity
EQUD    (1 << 14)

; --------------------------------------------------------------------------
.fire_stand
; -> R1 = pointer to character
; <- no change
STMFD   R13!, {R0-R9}

LDR     R0, fire_direction
CMP     R0, #0
Beq     fire_left_jump
B       fire_right_jump

.fire_direction
EQUD    1       ; 0 = left, 1 = right
.fired_frame
EQUD    0

; --------------------------------------------------------------------------
.process_table
; -> R0 = table to process
;    R2 = plot action (0 = plot, 1 = don't)
; <- no change
STMFD   R13!, {R0-R2}

MOV     R1, #0
SWI     "Amnesia_SelectTable"
.process_table_loop
SWI     "Amnesia_ProcessTable"
CMP     R2, #0
Bne     process_table_loop

LDMFD   R13!, {R0-R2}
MOV     PC, R14

; --------------------------------------------------------------------------
.process_Enemies
; -> R0 = table to process
;    R2 = plot action (0 = plot, 1 = don't)
; <- no change
STMFD   R13!, {R0-R3}

MOV     R1, #0
SWI     "Amnesia_SelectTable"
.process_Enemies_loop
SWI     "Amnesia_ProcessTable"
CMP     R2, #0
LDMeqFD R13!, {R0-R3}
MOVeq   PC, R14

TST     R2, #(1 << 8)
Beq     process_Enemies_loop

STMFD   R13!, {R0-R3}

LDR     R0, [R1, #36]   ; increment move
ADD     R0, R0, #1
LDR     R2, [R1, #32]
CMP     R0, R2
MOVeq   R0, #0
STR     R0, [R1, #36]

MOV     R3, #12         ; calculate position
MUL     R2, R0, R3
ADD     R2, R2, #40
ADD     R2, R1, R2

LDR     R0, [R2, #00]   ; copy velocity etc
STR     R0, [R1, #16]
LDR     R0, [R2, #04]
STR     R0, [R1, #20]
LDR     R0, [R2, #08]
STR     R0, [R1, #24]

LDMFD   R13!, {R0-R3}

B       process_Enemies_loop

; --------------------------------------------------------------------------
.process_Droids
; -> R0 = table to process
;    R2 = plot action (0 = plot, 1 = don't)
; <- no change
STMFD   R13!, {R0-R2}

MOV     R1, #0
SWI     "Amnesia_SelectTable"
.process_Droids_loop
SWI     "Amnesia_ProcessTable"
CMP     R2, #0
LDMeqFD R13!, {R0-R2}
MOVeq   PC, R14

TST     R2, #(1 << 8)
Beq     process_Droids_loop

STMFD   R13!, {R0-R3}

LDR     R0, [R1, #00]
AND     R0, R0, #&FF0000
LDR     R2, [R1, #32]
LDR     R3, [R1, #36]
CMP     R0, #0
MOVeq   R0, R2
MOVne   R0, R3
STR     R0, [R1, #24]

LDR     R0, [R1, #00]
EOR     R0, R0, #&10000
STR     R0, [R1, #00]

LDMFD   R13!, {R0-R3}

B       process_Droids_loop

; ----------------------------------------------------------------
.platforms
; -> R1 = pointer to character
; <- no change
STMFD   R13!, {R0-R9, R14}

MOV     R8, R1
MOV     R0, #Table_Platforms%
MOV     R1, #1
MOV     R2, #8
; find all platforms in same x position as char
LDR     R3, [R8, #8]
MOV     R3, R3, LSR #16
MOV     R3, R3, LSL #16
ADD     R3, R3, #(1 << 15)
MOV     R4, #0
SWI     "Amnesia_SelectTable"
.process_platforms
SWI     "Amnesia_ProcessTable"
CMP     R2, #0
Beq     process_platforms_end
; examine y position
LDR     R5, [R8, #12]
ADD     R5, R5, #(1 << 16)
LDR     R6, [R1, #12]
SUB     R6, R6, #(1 << 15)
CMP     R5, R6
Blt     process_platforms_fall
SUB     R5, R5, #(1 << 15)
CMP     R5, R6
Bgt     process_platforms_fall

LDR     R7, [R8, #20]
CMP     R7, #0                  ; filter out rises
Blt     process_platforms
LDR     R7, [R8, #12]
MOV     R7, R7, LSR #16
MOV     R7, R7, LSL #16
STR     R7, [R8, #12]
.process_platforms_nofall
LDR     R7, [R8, #4]
BIC     R7, R7, #(1 << 3)
STR     R7, [R8, #4]
MOV     R7, #0
STR     R7, [R8, #20]
B       process_platforms_end

.process_platforms_fall
BL      collisions_Character_Ladders
Bne     process_platforms_nofall

LDR     R7, [R8, #4]
ORR     R7, R7, #(1 << 3)
STR     R7, [R8, #4]
LDR     R7, [R8, #12]
LDR     R9, platforms_base
CMP     R7, R9
LDMgtFD R13!, {R0-R9, R14}
MOVgt   R0, #1
Bgt     finalisation
B       process_platforms

.platforms_base
EQUD    0 ;(High% << 16)

.process_platforms_end
LDR     R1, [R8, #12]
BL      scroll_vertical

LDMFD   R13!, {R0-R9, R14}
MOV     PC, R14

; --------------------------------------------------------------------------
.collisions_Character_Walls
; -> nothing
; <- flags updated
STMFD   R13!, {R0-R3, R14}

MOV     R0, #Table_Character%
MOV     R1, #Table_Walls%
SWI     "Amnesia_CollisionCheck"
CMP     R0, #0
LDMFD   R13!, {R0-R3, R14}
MOV     PC, R14

; --------------------------------------------------------------------------
.collisions_Character_Ladders
; -> nothing
; <- no change
STMFD   R13!, {R0-R3, R14}

MOV     R0, #Table_Character%
MOV     R1, #Table_Ladders%
SWI     "Amnesia_CollisionCheck"
CMP     R0, #0
LDMFD   R13!, {R0-R3, R14}
MOV     PC, R14

; --------------------------------------------------------------------------
.collisions_Character_Bullets
; -> nothing
; <- no change
STMFD   R13!, {R0-R4, R14}

MOV     R0, #Table_Character%
MOV     R1, #Table_Bullets%
.collisions_Character_Bullets_loop
SWI     "Amnesia_CollisionCheck"
CMP     R0, #0
LDMeqFD R13!, {R0-R4, R14}
MOVeq   PC, R14

STMFD   R13!, {R0}
MOV     R0, #0          ; remove bullet
STR     R0, [R1]
MOV     R0, #80         ; reduce energy
BL      energy_reduce
LDMFD   R13!, {R0}
B       collisions_Character_Bullets_loop

; --------------------------------------------------------------------------
.collisions_Bullets_Bullets
; -> nothing
; <- no change
STMFD   R13!, {R0-R4, R14}

MOV     R0, #Table_Bullets%
MOV     R1, #Table_Bullets%
.collisions_Bullets_Bullets_loop
SWI     "Amnesia_CollisionCheck"
CMP     R0, #0
LDMeqFD R13!, {R0-R4, R14}
MOVeq   PC, R14

MOV     R4, #0
STR     R4, [R0]
STR     R4, [R1]
B       collisions_Bullets_Bullets_loop

; --------------------------------------------------------------------------
.collisions_Walls_Bullets
; -> nothing
; <- no change
STMFD   R13!, {R0-R4, R14}

MOV     R0, #Table_Bullets%
MOV     R1, #Table_Walls%
.collisions_Walls_Bullets_loop
SWI     "Amnesia_CollisionCheck"
CMP     R0, #0
LDMeqFD R13!, {R0-R4, R14}
MOVeq   PC, R14

LDR     R4, [R0, #16]
RSB     R4, R4, #0
STR     R4, [R0, #16]
B       collisions_Walls_Bullets_loop

; --------------------------------------------------------------------------
.collisions_Enemies_Bullets
; -> nothing
; <- no change
STMFD   R13!, {R0-R4, R14}

MOV     R0, #Table_Bullets%
MOV     R1, #Table_Enemies%
.collisions_Enemies_Bullets_loop
SWI     "Amnesia_CollisionCheck"
CMP     R0, #0
LDMeqFD R13!, {R0-R4, R14}
MOVeq   PC, R14

MOV     R4, #0                  ; remove bullet & enemy
STR     R4, [R0]
STR     R4, [R1]

STMFD   R13!, {R0-R8}
LDR     R3, [R1, #08]
LDR     R4, [R1, #12]
MOV     R0, #Table_Xplosions%
LDR     R1, Xplosion1 + 00
LDR     R2, Xplosion1 + 04
MOV     R5, #0
MOV     R6, #0
LDR     R7, Xplosion1 + 08
SWI     "Amnesia_MakeObject"
LDMFD   R13!, {R0-R8}

B       collisions_Enemies_Bullets_loop

.Xplosion1
EQUD    &00000007
EQUD    %1000001001110001
EQUD    &06000080

; --------------------------------------------------------------------------
.collisions_Droids_Bullets
; -> nothing
; <- no change
STMFD   R13!, {R0-R4, R14}

MOV     R0, #Table_Bullets%
MOV     R1, #Table_Droids%
.collisions_Bullets_Droids_loop
SWI     "Amnesia_CollisionCheck"
CMP     R0, #0
LDMeqFD R13!, {R0-R4, R14}
MOVeq   PC, R14

MOV     R4, #0                  ; remove bullet
STR     R4, [R0]

LDR     R4, [R1, #40]           ; droid lives
SUB     R4, R4, #1
STR     R4, [R1, #40]
CMP     R4, #0
Bne     collisions_Bullets_Droids_loop

MOV     R4, #0                  ; remove droid
STR     R4, [R1]

STMFD   R13!, {R0-R8}
LDR     R3, [R1, #08]
LDR     R4, [R1, #12]
MOV     R0, #Table_Xplosions%
LDR     R1, Xplosion2 + 00
LDR     R2, Xplosion2 + 04
MOV     R5, #0
MOV     R6, #0
LDR     R7, Xplosion2 + 08
SWI     "Amnesia_MakeObject"
LDMFD   R13!, {R0-R8}

B       collisions_Bullets_Droids_loop

.Xplosion2
EQUD    &00000009
EQUD    %1000001001110001
EQUD    &04000080

; --------------------------------------------------------------------------
.collisions_Character_Enemies
; -> nothing
; <- no change
STMFD   R13!, {R0-R4, R14}

MOV     R0, #Table_Character%
MOV     R1, #Table_Enemies%
.collisions_Character_Enemies_loop
SWI     "Amnesia_CollisionCheck"
CMP     R0, #0
LDMeqFD R13!, {R0-R4, R14}
MOVeq   PC, R14

STMFD   R13!, {R0}
MOV     R0, #1
BL      energy_reduce
LDMFD   R13!, {R0}
B       collisions_Character_Enemies_loop

; --------------------------------------------------------------------------
.collisions_Character_Droids
; -> nothing
; <- no change
STMFD   R13!, {R0-R4, R14}

MOV     R0, #Table_Character%
MOV     R1, #Table_Droids%
.collisions_Character_Droids_loop
SWI     "Amnesia_CollisionCheck"
CMP     R0, #0
LDMeqFD R13!, {R0-R4, R14}
MOVeq   PC, R14

STMFD   R13!, {R0}
MOV     R0, #2
BL      energy_reduce
LDMFD   R13!, {R0}
B       collisions_Character_Droids_loop

; --------------------------------------------------------------------------
.collisions_Droids_Walls
; -> nothing
; <- no change
STMFD   R13!, {R0-R5, R14}

MOV     R0, #Table_Droids%
MOV     R1, #Table_Walls%
.collisions_Droids_Walls_loop
SWI     "Amnesia_CollisionCheck"
CMP     R0, #0
LDMeqFD R13!, {R0-R5, R14}
MOVeq   PC, R14

LDR     R4, [R0, #08]
LDR     R5, [R0, #16]
SUB     R4, R4, R5
STR     R4, [R0, #08]

B       collisions_Droids_Walls_loop

; --------------------------------------------------------------------------
.collisions_Character_Items
; -> nothing
; <- no change
STMFD   R13!, {R0-R3, R14}

MOV     R0, #Table_Character%
MOV     R1, #Table_Items%
.collisions_Character_Items_loop
SWI     "Amnesia_CollisionCheck"
CMP     R0, #0
LDMeqFD R13!, {R0-R3, R14}
MOVeq   PC, R14

LDR     R0, [R1, #0]
SUB     R0, R0, #10
B       finalisation

; --------------------------------------------------------------------------
.energy_reduce
; -> R0 = amount of energy to reduce by
; <- no change
STMFD   R13!, {R0-R4}

LDR     R1, energy
SUB     R0, R1, R0
STR     R0, energy
CMP     R0, #0
LDMleFD R13!, {R0-R4}
MOVle   R0, #1
Ble     finalisation

MOV     R1, #240
MOV     R2, #320
MOV     R3, #256
SWI     "FastSpr_SetClipWindow"
SWI     "FastSpr_ClearWindow"

LDR     R0, bank                ; load bank from memory
SUB     R0, R0, #1
RSB     R0, R0, #1
SWI     "FastSpr_ScreenBank"
SWI     "FastSpr_ClearWindow"
LDR     R0, bank                ; load bank from memory
SUB     R0, R0, #1              ; set bank for FastSpr
SWI     "FastSpr_ScreenBank"

MOV     R0, #0
MOV     R1, #0
MOV     R2, #320
MOV     R3, #240
SWI     "FastSpr_SetClipWindow"

LDMFD   R13!, {R0-R4}
MOV     PC, R14

.energy_reduce_sprite
EQUD    &01000001

; --------------------------------------------------------------------------
.droids
; -> R1 = pointer to character
; <- no change
STMFD   R13!, {R0-R8, R14}

MOV     R2, R1                  ; R2 -> character

MOV     R0, #Table_Droids%
BL      object_find             ; R1 -> droid

MOV     R0, #Total_Droids%      ; R0 = droid count
.droids_loop
LDR     R4, [R2, #0]
CMP     R4, #0
Beq     droids_next

LDR     R4, [R2, #08]   ; character x
LDR     R5, [R1, #08]   ; droid x
LDR     R6, [R2, #12]   ; character y
LDR     R7, [R1, #12]   ; droid y

LDR     R3, [R1, #04]   ; has it been activated?
TST     R3, #(1 << 2)
BLeq    droids_activate

MOV     R3, #(1 << 12)  ; x
CMP     R4, R5
RSBlt   R3, R3, #0
MOVeq   R3, #0
STR     R3, [R1, #16]

MOV     R3, #(1 << 12)  ; y
CMP     R6, R7
RSBlt   R3, R3, #0
MOVeq   R3, #0
STR     R3, [R1, #20]

.droids_next
SUB     R0, R0, #1
ADD     R1, R1, #Size_Droids%
CMP     R0, #0
Bne     droids_loop

LDMFD   R13!, {R0-R8, R14}
MOV     PC, R14

.droids_activate
CMP     R4, R5          ; find x difference
SUBge   R8, R4, R5
SUBlt   R8, R5, R4
CMP     R8, #(1 << 19)
MOVgt   PC, R14

CMP     R6, R7          ; find y difference
SUBge   R8, R6, R7
SUBlt   R8, R7, R6
CMP     R8, #(1 << 19)
MOVgt   PC, R14

ORR     R3, R3, #(1 << 2)
STR     R3, [R1, #04]
MOV     PC, R14

; --------------------------------------------------------------------------
.stars
STMFD   R13!, {R0-R9, R14}

ADR     R0, stars_block
ADR     R1, screen_base
SWI     "OS_ReadVduVariables"
LDR     R0, screen_base         ; R0 = base of screen memory
LDR     R1, starfield           ; R1 = starfield list

LDR     R2, stars_scroll
ADD     R2, R2, #5
CMP     R2, #(320*240)
MOVeq   R2, #0
STR     R2, stars_scroll        ; R2 = offset of star start from R0

LDR     R9, stars_total
MVN     R3, #3                  ; R3 = position in starfield list
.starloop
ADD     R3, R3, #4

CMP     R3, R9
Beq     stars_exit

LDR     R4, [R1, R3]            ; get distance between stars
ADD     R2, R2, R4              ; add it to screen offset
CMP     R2, #(320*240)          ; wrap round
SUBgt   R2, R2, #(320*240)
LDRB    R5, [R0, R2]
CMP     R5, #0
Bne     starloop

MOV     R5, #208
STRB    R5, [R0, R2]
B       starloop

.stars_exit
LDMFD   R13!, {R0-R9, R14}
MOV     PC, R14

.starfield
EQUD    Stars%
.stars_scroll
EQUD    0
.stars_block
EQUD    148
EQUD    -1
.screen_base
EQUD    0
.stars_total
EQUD    ((Star% - 1) * 4)

; --------------------------------------------------------------------------
;.debug_r0
; -> R0 = number to display
; <- no change
;STMFD   R13!, {R0-R2}
;ADR     R1, buffer
;MOV     R2, #16
;SWI     "OS_ConvertHex8"
;SWI     &100 + 30
;SWI     "OS_Write0"
;LDMFD   R13!, {R0-R2}
;MOV     PC, R14
;.buffer
; --------------------------------------------------------------------------
]
 NEXT

ENDPROC

REM ˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜

DEF PROCLevel_Init(Level$)
Data% = OPENIN("<HeeHeeHee$Dir>.Levels."+Level$+".Data")
Wide% = VAL(GET$#Data%)
High% = VAL(GET$#Data%)
Y% = 0
X% = 0
 REPEAT
  Tile% = BGET#Data%

   CASE Tile% OF

    WHEN 10
     Y% += 1: X% = 0

    WHEN ASC" "
     X% += 1

    WHEN ASC"P"
     PROCAmnesia_MakeObject(Table_Platforms%, 3, %1000000001010001, (X% << 16) + (1 << 15), (Y% << 16) + (1 << 15))
     X% += 1

    WHEN ASC"L"
     Object% = FNAmnesia_MakeObject(Table_Ladders%, 4, %1000000011010001, (X% << 16) + (1 << 15), (Y% << 16) + (1 << 15))
     Object%!28 = &0008000F
     X% += 1

    WHEN ASC"W"
     PROCAmnesia_MakeObject(Table_Walls%, 5, %1000000011010001, (X% << 16) + (1 << 15), (Y% << 16) + (1 << 15))
     X% += 1

    WHEN ASC"*"
     PROCAmnesia_MakeObject(Table_Items%, 11, %1000000011010001, (X% << 16) + (1 << 15), (Y% << 16) + (1 << 15))
     X% += 1

    WHEN ASC"S"
     PROCAmnesia_MakeObject(Table_Character%, 1, %1000000011010101, (X% << 16) + (1 << 15), (Y% << 16))
     PROCAmnesia_SetPlotOffset((X% << 16) + (1 << 15) + (160 << 12), (Y% << 16) - (120 << 12))

    WHEN ASC"F"
     PROCAmnesia_MakeObject(Table_Items%, 10, %1000000011010001, (X% << 16) + (1 << 15), (Y% << 16) + (1 << 15))

   ENDCASE

 UNTIL Y% = High%
CLOSE#Data%


Enem% = OPENIN("<HeeHeeHee$Dir>.Levels."+Level$+".Enemies")
 WHILE NOT EOF#Enem%
  Object% = FNAmnesia_MakeObject(Table_Enemies%, 6, %1000000111010101, (VAL(GET$#Enem%) << 16), (VAL(GET$#Enem%) << 16) + (1 << 15))
  Moves% = 0
  Object%!36 = 0
  Move$ = GET$#Enem%
   REPEAT
    Object%!(40 + 12 * Moves%) = FNCutVal(Move$) << 12
    Object%!(44 + 12 * Moves%) = FNCutVal(Move$) << 12
    Object%!(48 + 12 * Moves%) = ((FNCutVal(Move$) - 1) << 16) + 1
    Moves% += 1
    Move$ = GET$#Enem%
   UNTIL Move$ = ""
  Object%!32 = Moves%
  Object%!16 = Object%!40
  Object%!20 = Object%!44
  Object%!24 = Object%!48
 ENDWHILE
CLOSE#Enem%


Droi% = OPENIN("<HeeHeeHee$Dir>.Levels."+Level$+".Droids")
 WHILE NOT EOF#Droi%
  Object% = FNAmnesia_MakeObject(Table_Droids%, 8, %1000000111010001, (VAL(GET$#Droi%) << 16) + (1 << 15), ((VAL(GET$#Droi%) - 1) << 16) + (1 << 15))
  Object%!24 = &00100001     :REM blue (starts)
  Object%!32 = &00020001     :REM orange
  Object%!36 = &00100001     :REM blue
  Object%!40 = 2             :REM lives
 ENDWHILE
CLOSE#Droi%


!move_right_edge = ((Wide% - 1) << 16) + (1 << 15)
!scroll_x = 0
!scroll_x_end = -((Wide% << 16) - (320 << 12))
!scroll_y = -((High% << 16) - (240 << 12))
!scroll_y_end = -((High% << 16) - (240 << 12))
!platforms_base = (High% << 16)
ENDPROC

DEF FNCutVal(RETURN Text$)
LOCAL Result$
IF INSTR(Text$, ",") = 0 THEN Result$ = Text$: Text$ = "": =VAL(Result$)
Result$ = LEFT$(Text$, INSTR(Text$, ",") - 1)
Text$ = MID$(Text$, INSTR(Text$, ",") + 1)
=VAL(Result$)

DEF PROCMakeStars
Star% = 0
Rand% = RND(500)
Addr% = Rand%
 REPEAT
  Stars%!(Star% * 4) = Rand%
  Star% += 1
  Rand% = RND(500)
  Addr% += Rand%
 UNTIL Addr% > (320*240)
ENDPROC