VERSION equ 'ARCANOID II v. 0.30'
;               by jj
;        (jacek jerzy malinowski)
;
;   contact: 4nic8@casiocalc.org
;----------------------------------------
;   Compile with FASM for Menuet
;----------------------------------------

include 'lang.inc'
include 'ascl.inc'
include 'ascgl.inc'
include 'asjc.inc'

X_SIZE equ 400
Y_SIZE equ 300

MAX_LEVEL equ 5

BACK_CL equ 0x00EFEF ; background color

;    THE MAIN PROGRAM:
use32

               org    0x0

               db     'MENUET01'              ; 8 byte id
               dd     0x01                    ; header version
               dd     START                   ; start of code
               dd     I_END                   ; size of image
               dd     0x200000                ; memory for app
               dd     0x7fff0                 ; esp
               dd     0x0 , 0x0               ; I_Param , I_Icon

START:                          ; start of execution

    bmptoimg bmp_file,img_bmp   ; loading ... ;]
    getimg img_bmp,0,0,10,10,img_ball
    getimg img_bmp,20,0,20,10,img_bonus
    getimg img_bmp,0,10,40,20,img_brick1
    getimg img_bmp,0,30,40,20,img_brick2
    getimg img_bmp,0,50,40,20,img_brick3
    getimg img_bmp,0,70,40,20,img_brick4

    call draw_window

still:
    if_e dword [level],0,.no_intro
       call intro
       jmp .no_game
    .no_intro:

    if_e dword [mode],2,.end_if1
       call level_info
       jmp .no_game
    .end_if1:

    if_e dword [mode],4,.end_if2
       call game_over
       jmp .no_game
    .end_if2:

    call fast_gfx ; <-- the main engine
    .no_game:

    mov  eax,11
    int  0x40

    cmp  eax,1                  ; redraw request ?
    je   red
    cmp  eax,2                  ; key in buffer ?
    je   key
    cmp  eax,3                  ; button in buffer ?
    je   button

    jmp  still

  red:                          ; redraw
    call draw_window
    jmp  still

  key:                          ; key
    mov  eax,2                  ; just read it and ignore
    int  0x40
    cmp  ah,key_Esc ; if Esc ?
    jne  .no_q
      mov eax,-1
      int 0x40
    .no_q:

    if_e dword [mode],4,.end_if6
       jmp still
    .end_if6:

    cmp  ah,key_Space
    jne  .no_space
      if_e dword [mode],2,.end_if1
         mov dword [mode],0
         jmp .no_space
      .end_if1:
      mov dword [mode],1
      call fast_gfx
    .no_space:
    xor ebx,ebx
    mov bl,ah
    if_e ebx,key_F1,.no_f1
      inc dword [del]
    .no_f1:
    if_e ebx,key_F2,.no_f2
      if_a dword [del],0,.end_if3
         dec dword [del]
      .end_if3:
    .no_f2:


    jmp  still

  button:                       ; button
    mov  eax,17                 ; get id
    int  0x40

    cmp  ah,1                   ; button id=1 ?
    jne  noclose

    mov  eax,-1                 ; close this program
    int  0x40
  noclose:

    jmp  still

;   *********************************************
;   ******* VIRTUAL SCREEN FUNCTIONS ************
;   *********************************************

show_screen:  ; flips the virtual screen to the window
    push_abc

    mov  eax,7
    mov  ebx,screen
    mov  ecx,X_SIZE*65536+Y_SIZE
    mov  edx,4*65536+20
    int  0x40

    pop_abc
ret

put_bmp_screen: ; eax - y , ebx - x, esi - bmp
    cmp ebx,X_SIZE-5
    jb .ok1
      ret
    .ok1:
    cmp eax,Y_SIZE-5
    jb .ok2
      ret
    .ok2:

    push_abc
    xor  ecx,ecx
    xor  edx,edx
    mov  edi,screen
    mov  ecx,3
    mul  ecx  ; xx = 3*y*X_SIZE+3*x
    mov  ecx,X_SIZE
    mul  ecx
    push eax ; #> 1
    mov  eax,ebx
    mov  ecx,3
    mul  ecx
    mov  ebx,eax
    pop  edx ; #< 1
    add  edx,ebx
    add  edi,edx ; sets the pointer to x,y of the screen

    mov  cx,[si] ; loops 1
    xor  ebx,ebx
    mov  ax,cx
    mov  dx,3
    mul  dx
    mov  bx,ax

    push ebx ;#>4

    add  si,4
    mov  ax,[si] ; loops 2
    mov  cx,[si]
    ;shr  ax,2
    mov  dx,3   ; dx = ax *3
    mul  dx
    mov  bx,ax
    add  si,4


    pop  ebx ;#<4
    .l_y:
       mov ax,cx
       cld
       mov  cx,bx
       rep movs byte [edi],[esi]
       add edi,X_SIZE
       add edi,X_SIZE
       add edi,X_SIZE
       sub edi,ebx
       mov cx,ax
    loop .l_y

    pop_abc
ret

rect_screen: ; eax - y , ebx - x, ecx - size x, edx - size y, si -color
    mov edi,ebx
    add ebx,ecx
    cmp ebx,X_SIZE
    jb .ok1
      ret
    .ok1:
    mov ebx,edi

    mov edi,eax
    add eax,edx
    cmp eax,Y_SIZE
    jb .ok2
      ret
    .ok2:
    mov eax,edi
    push_abc
    push ecx  ;#>2
    push edx  ;#>3

    xor  ecx,ecx
    xor  edx,edx
    mov  edi,screen
    mov  ecx,3
    mul  ecx  ; xx = 3*y*X_SIZE+3*x
    mov  ecx,X_SIZE
    mul  ecx
    push eax ; #> 1
    mov  eax,ebx
    mov  ecx,3
    mul  ecx
    mov  ebx,eax
    pop  edx ; #< 1
    add  edx,ebx

    add  edi,edx ; sets the pointer to x,y of the screen

    pop ecx ; #<3
    pop edx ; #<4
    mov  eax,esi
    .l_y:
       ;mov ax,cx
       push  ecx
       cld
       mov  ecx,edx
       .l_x:
         ;rep movs byte [edi],[esi]
         mov  word [edi],ax
         push eax
         shr  eax,16
         mov  byte [edi+2],al
         add  edi,3
         pop  eax
       loop .l_x

       add edi,X_SIZE
       add edi,X_SIZE
       add edi,X_SIZE
       sub edi,edx
       sub edi,edx
       sub edi,edx
       ;mov cx,ax
       pop  ecx
    loop .l_y

    pop_abc
ret

grad_rect_screen: ; eax - y , ebx - x, ecx - size x, edx - size y, si -color, d
    push edi  ;#>0
    mov edi,ebx
    add ebx,ecx
    cmp ebx,X_SIZE
    jb .ok1
      pop edi ;#<0
      ret
    .ok1:
    mov ebx,edi

    mov edi,eax
    add eax,edx
    cmp eax,Y_SIZE
    jb .ok2
      pop edi ;#<0
      ret
    .ok2:
    mov eax,edi

    pop edi ;#<0
    push_abc

    push edi  ;#>5
    push ecx  ;#>2
    push edx  ;#>3

    xor  ecx,ecx
    xor  edx,edx
    mov  edi,screen
    mov  ecx,3
    mul  ecx  ; xx = 3*y*X_SIZE+3*x
    mov  ecx,X_SIZE
    mul  ecx
    push eax ; #> 1
    mov  eax,ebx
    mov  ecx,3
    mul  ecx
    mov  ebx,eax
    pop  edx ; #< 1
    add  edx,ebx

    add  edi,edx ; sets the pointer to x,y of the screen

    pop ecx ; #<3
    pop edx ; #<2
    mov  eax,esi
    pop esi ; #<5
    .l_y:
       ;mov ax,cx
       push  ecx
       cld
       mov  ecx,edx
       .l_x:
         ;rep movs byte [edi],[esi]
         mov  word [edi],ax
         push eax
         shr  eax,16
         mov  byte [edi+2],al
         add  edi,3
         pop  eax
       loop .l_x

       add edi,X_SIZE
       add edi,X_SIZE
       add edi,X_SIZE
       sub edi,edx
       sub edi,edx
       sub edi,edx
       add eax,esi
       ;mov cx,ax
       pop  ecx
    loop .l_y

    pop_abc
ret


fill_screen: ; eax - screen color ( 0x00RRGGBB )
    push_abc
    mov  edi,screen
    cld
    mov  ecx,X_SIZE*Y_SIZE
    .lab1:
        mov  [edi],eax
        add  edi,3
    loop .lab1
    pop_abc
ret

grad_fill_screen: ; eax - screen color ( 0x00RRGGBB ), ebx - mack
    push_abc
    mov  edi,screen
    cld
    mov  ecx,Y_SIZE
    mov  dl,0
    .lab1:
       push ecx
       mov ecx,X_SIZE
       .lab2:
         mov  [edi],eax
         add  edi,3
       loop .lab2
       mov dh,1  ; dl = 1 - dl
       sub dh,dl
       mov dl,dh
       cmp dl,0
       jne .no_ch  ; if (dl==0)
         add  eax,ebx ; change gradient
       .no_ch:
       pop ecx
    loop .lab1
    pop_abc
ret


bmp_fill_screen: ; esi - pointer to a backgroung bmp
    push_abc
    mov  edi,screen
    cld
    mov  ecx,X_SIZE*Y_SIZE
      rep movs dword  [edi],[esi]
    pop_abc
ret

;___________________
intro:  ; INTRO    ;
    label 140,200,VERSION,0x100000FF
    label 120,220,'by jj (jacek jerzy malinowski)',0x050505
    label 100,240,'press SPACE to start a new game',0x10FF0800
    label 15,240,'F1 + delay',0xFFA8FF
    label 15,260,'F2 + delay',0xFFA8FF
    delay 10
ret

;___________________
level_info:
    label 170,230,'L E V E L',0x100000FF
    outcount [level],195,250,0x100000FF,2*65536
    label 100,270,'press SPACE to start the level',0x10FF0800
    delay 10
ret

;_________________________
game_over:  ; GAME OVER  ;
    mov  eax,0x00FF00
    mov  ebx,0xFF01
    .g_ok:
    call grad_fill_screen
    call show_screen  ; flips the screen
    label 120,150,'G  A  M  E    O  V  E  R',0x10050505
    label 140,200,'Thanks for playing',0x0FFF800
    delay 20
ret


;-----------------------------;
; THE MAIN THE GAME'S ENGINE ;
;-----------------------------;
fast_gfx:
    ; the background gradient
    if_e  dword [level],0,.no_0
      mov  eax,0xFF
      mov  ebx,0xFEFF
      jmp .g_ok
    .no_0:
    if_e  dword [level],1,.no_1
      mov  eax,BACK_CL
      mov  ebx,0xFFFF
      jmp .g_ok
    .no_1:
    if_e  dword [level],2,.no_2
      mov  eax,0xFF0000
      mov  ebx,0xFF00FF
      jmp .g_ok
    .no_2:

    mov  eax,BACK_CL
    mov  ebx,0xFFFF
    .g_ok:
    call grad_fill_screen

    mov  eax,37  ; get mouse position
    mov  ebx,1
    int  0x40
    shr  eax,16
    mov  [x],eax
    add  eax,[s_x]
    cmp  eax,X_SIZE  ; controls if the pad is in the screen
    jb   .ok
      cmp eax,0x7FFF ; if < 0
      jb  .upper
        mov [x],0
        jmp .ok
      .upper:        ; if > X_SIZE - pad size
      mov dword [x],X_SIZE-1
      mov eax,[s_x]
      sub dword [x],eax
    .ok:
    mov  ebx,[x]
    mov  eax,[y]
    mov  ecx,[s_x]
    mov  edx,15
    mov  esi,0xFF0000
    mov  edi,0xF0000F
    call grad_rect_screen

    call draw_level

    cmp dword [mode],1
    jne .no_go ; is the game started ?
      mov eax,[v_x]
      add dword [b_x],eax
      mov eax,[v_y]
      add dword [b_y],eax
      jmp .go
    .no_go:
      mov eax,[x] ; b_x = x + x_s/2
      mov ebx,[s_x]
      shr ebx,1
      add eax,ebx
      mov dword [b_x],eax
      mov eax,[y] ; b_y = y - 10
      sub eax,10
      mov dword [b_y],eax

      mov dword [v_x],1
      mov dword [v_y],-1
    .go:
    ;TEST WHERE IS THE BALL:
    cmp dword [b_x],0x7FFFFFFF
    jb .b_ok2 ; if out of the screen (left)
      mov dword [b_x],0
      mov eax,0
      sub eax,[v_x]
      mov [v_x],eax
    .b_ok2:
    cmp dword [b_x],X_SIZE-10
    jb .b_ok1 ; if out of the screen (right)
      mov dword [b_x],X_SIZE-11
      mov eax,0
      sub eax,[v_x]
      mov [v_x],eax
    .b_ok1:
    cmp dword [b_y],0x7FFFFFFF
    jb .b_ok3 ; if out of the screen (up)
      mov dword [b_y],0
      mov eax,0
      sub eax,[v_y]
      mov [v_y],eax
    .b_ok3:
    cmp dword [b_y],Y_SIZE-10
    jb .b_ok4 ; if out of the screen (down)
      mov dword [mode],0
      if_e dword [lives],0,.end_if5
         mov dword [mode],4 ; GAME OVER
         jmp still
      .end_if5:
         dec dword [lives]
      .end_else4:
      call draw_window
    .b_ok4:

    imgtoimg img_ball,dword [b_x],dword [b_y],screen_img

    call show_screen  ; flips the screen
    delay dword [del]

    call do_tests ; does all needed tests
ret
;----------------------;
; BALL & BRICKS EVENTS ;
;----------------------;
MAX_SPEED equ 3
do_tests:
    ; BALL <-> PAD
    mov eax,[b_x]
    add eax,10
    cmp eax,[x] ; if (b_x+10)>[pad x]
    jb .skip        ; &&
    mov eax,[b_x]
    mov ebx,[s_x]
    add ebx,[x]
    cmp eax,ebx ; if b_x < x + s_x
    ja .skip     ; &&
    mov eax,[b_y]
    add eax,10
    cmp eax,[y] ; if (b_y+10) > y
    jb .skip
    sub eax,15
    cmp eax,[y] ; if b_y < y+15
    ja .skip
      cmp dword [v_y],0x7FFFFF ; if v_y > 0
      ja .skip
      cmp dword [v_y],MAX_SPEED; speedup:
      ja .skip_s
        inc dword [speed_t]
        cmp dword [speed_t],5
        jb .skip_s
        inc dword [v_y]
        mov dword [speed_t],0
      .skip_s:
      inc dword [speed_t]
      mov eax,0
      sub eax,[v_y]
      mov [v_y],eax
      ;counting v_x:--------
      mov eax,[b_x]
      sub eax,[x]
      sub eax,5
      mov ecx,eax
      if_a eax,100,.end_if3
        mov eax,0
        sub eax,[v_x]
        mov [v_x],eax
        jmp .skip
      .end_if3:
      if_a eax,20,.end_if2
        sub eax,20
        shr eax,2
        mov [v_x],eax
        jmp .skip
      .end_if2:
        mov ebx,20
        sub ebx,ecx
        shr ebx,2
        mov dword [v_x],0
        sub dword [v_x],ebx
    .skip:

    ; BALL <-> BRICK
    mov dword [coliz],0
    call colision
    if_e dword [coliz],1,.end_if6
       ;abs dword [v_y]
       ;abs dword [v_x]
       ret
    .end_if6:
    add dword [b_x],10
    call colision
    sub dword [b_x],10
    if_e dword [coliz],1,.end_if7
       ;abs dword [v_y]
       ;abs dword [v_x]
       ch_sign dword [v_x]
       ret
    .end_if7:
    add dword [b_y],10
    call colision
    sub dword [b_y],10
    if_e dword [coliz],1,.end_if8
       ;abs dword [v_y]
       ;abs dword [v_x]
       ;ch_sign dword [v_y]
       ret
    .end_if8:
    add dword [b_x],10
    add dword [b_y],10
    call colision
    sub dword [b_x],10
    sub dword [b_y],10
    if_e dword [coliz],1,.end_if9
       ;abs dword [v_y]
       ;abs dword [v_x]
       ;ch_sign dword [v_x]
       ;ch_sign dword [v_y]

       ret
    .end_if9:


ret

colision:

    mov  esi,levels
    mov  eax,[level] ; eax = levels*100
    mov  bx,100
    mul  bx
    add  esi,eax
    ;--------------
    xor  edx,edx
    mov  eax,[b_x]
    mov  ebx,40
    div  ebx
    mov  ecx,eax
    push edx ;#>1

    xor edx,edx
    mov  eax,[b_y]
    mov  ebx,20
    div  ebx
    push edx ;#>2
    cmp  eax,9 ; out of the bricks board
    ja .ok2
    mov  ebx,10
    mul  ebx
    add  eax,ecx
    add  esi,eax

    cmp byte [esi],0 ; 0 - no brick
    je .ok2
      if_ne byte [esi],4,.end_if1
        dec byte [esi]
      .end_if1:
      mov dword [coliz],1
      pop ebx ;#<2
      pop eax ;#<1
      cmp ecx,8 ; x < 5 || x >35 - x inv
      jb  .inv
      cmp ecx,33
      ja  .inv
      jmp .no_inv
      .inv:
        mov eax,0
        sub eax,[v_x]
        mov [v_x],eax
        ;jmp .no_ok
      .no_inv:
      cmp ebx,6 ; if y < 5 || y>15 - y inv
      jb .inv_y
      cmp ebx,14
      ja .inv_y
      jmp .no_ok
        .inv_y:
        mov eax,0
        sub eax,[v_y]
        mov [v_y],eax
      .no_ok:
      jmp .ok
    .ok2:
      pop eax ;#<1
      pop eax ;#<2
    .ok:


ret

;-----------------------------------;
; DRAWS CURRENT LEVEL ON THE SCREEN ;
;-----------------------------------;
draw_level:
    mov  esi,levels
    mov  eax,[level] ; eax = levels*100
    mov  bx,100
    mul  bx
    add  esi,eax
    mov  ecx,10
    mov  eax,0
    mov dword [l_end],1
    .l_y:
      push ecx ;#>1
      mov ebx,0
      mov ecx,10
      .l_x:
        cmp byte [esi],1 ; if 1 ?
        push esi;#>2
        jne .no_1
          mov  esi,img_brick1
          call put_bmp_screen
          mov dword [l_end],0
        .no_1:
        cmp byte [esi],2 ; if 2 ?
        jne .no_2
          mov  esi,img_brick2
          call put_bmp_screen
          mov dword [l_end],0
        .no_2:
        cmp byte [esi],3 ; if 3 ?
        jne .no_3
          mov  esi,img_brick3
          call put_bmp_screen
          mov dword [l_end],0
        .no_3:
        cmp byte [esi],4 ; if 4 ?
        jne .no_4
          mov  esi,img_brick4
          call put_bmp_screen
        .no_4:

        add ebx,40
        pop esi ;#<2
        inc esi
      loop .l_x
      add eax,20 ;#<1
      pop  ecx
    loop .l_y
;----------------
; NEXT LEVEL
    if_e dword [l_end],1,.end_if ; all bricks are taken
    if_e dword [mode],1,.end_if
        add dword [level],1
        if_a dword [level],MAX_LEVEL,.end_if2
           mov dword [mode],4 ; game over
           jmp still
        .end_if2:
        call fast_gfx
        mov dword [mode],2
    .end_if:
ret

;   *********************************************
;   *******  WINDOW DEFINITIONS AND DRAW ********
;   *********************************************


draw_window:

    startwd

    window 100,100,X_SIZE+8,Y_SIZE+21,0x03ffffff
    label 8,8,VERSION,cl_White+font_Big
    label 200,8,'LIVES:',0x10ddeeff
    outcount dword [lives],250,8,0x10ddeeff,65536

    call fast_gfx

    endwd

    ret

;-----------;####################
; DATA AREA ;####################
;-----------;####################

 lives dd 5
 mode dd 0
 l_end dd 0 ; if 1 the level is over
; PAD x:
 x   dd 20
 y   dd Y_SIZE-20
; PAD length:
 s_x dd 40

; the ball stuff ;-)
 b_x dd 100
 b_y dd 250
 v_y dd 0
 v_x dd 3

 speed_t dd 0 ; 1/10 times speedup
 del dd 1 ; delay

 coliz dd 0 ; if 1 then colizion with a brick

; LEVELS:
level dd 0
levels:
;LEVEL 0:
db 0,0,0,0,0,0,0,0,0,0
db 0,4,0,0,4,4,0,0,0,4
db 4,0,4,0,4,0,4,0,4,0
db 4,0,4,0,4,0,4,0,4,0
db 4,4,4,0,4,4,0,0,4,0
db 4,0,4,0,4,0,4,0,4,0
db 4,0,4,0,4,0,4,0,0,4
db 0,0,0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0,0,0

;LEVEL 1:
db 1,1,1,1,1,1,1,1,1,1
db 0,3,0,0,3,3,0,0,0,3
db 3,0,3,0,3,0,3,0,3,0
db 3,0,3,0,3,0,3,0,3,0
db 3,3,3,0,3,3,0,0,3,0
db 3,0,3,0,3,0,3,0,3,0
db 3,0,3,0,3,0,3,0,0,3
db 2,2,2,2,2,2,2,2,2,2
db 1,1,1,1,1,1,1,1,1,1
db 1,1,1,1,1,1,1,1,1,1
;LEVEL 2:
db 3,3,3,3,0,0,3,3,3,3
db 3,1,1,1,0,0,1,1,1,3
db 3,1,2,1,3,3,1,2,1,3
db 0,1,0,1,3,3,1,0,1,0
db 2,1,2,1,1,1,1,2,1,2
db 0,1,0,1,2,2,1,0,1,0
db 2,1,2,1,1,1,1,2,1,2
db 0,1,0,1,1,1,1,0,1,0
db 0,0,0,1,0,0,1,0,0,0
db 0,0,0,1,0,0,1,0,0,0
;LEVEL 3:
db 1,2,3,1,2,3,1,3,2,1
db 2,3,1,2,3,1,3,3,1,2
db 3,1,2,3,1,2,3,1,2,3
db 1,2,3,1,2,3,1,3,2,1
db 2,3,1,2,3,1,3,3,1,2
db 3,1,2,3,1,2,3,1,2,3
db 1,2,1,2,1,2,1,2,1,2
db 1,0,1,0,1,0,1,0,1,0
db 0,0,3,0,0,0,0,3,0,0
db 0,0,3,0,0,0,0,3,0,0
;LEVEL 4:
db 0,0,0,1,1,1,1,0,0,0
db 0,0,1,2,2,2,2,1,0,0
db 1,1,1,2,2,2,2,1,1,1
db 1,0,1,0,2,2,0,1,0,1
db 0,1,1,2,2,2,2,1,1,0
db 0,0,1,2,2,2,2,1,0,0
db 0,0,1,2,2,2,2,1,0,0
db 0,0,1,2,3,3,2,1,0,0
db 0,0,1,2,2,2,2,1,0,0
db 0,0,0,1,1,1,1,0,0,0
;LEVEL 5:
db 1,1,1,1,1,1,1,1,1,1
db 1,2,0,0,3,2,0,0,2,1
db 1,2,0,0,2,3,0,0,2,1
db 2,2,0,0,3,2,0,0,2,2
db 0,0,0,0,2,3,0,0,0,0
db 0,0,0,1,1,1,1,0,0,0
db 0,0,1,1,0,0,1,1,0,0
db 0,0,1,1,0,0,1,1,0,0
db 2,1,2,1,2,1,2,1,2,1
db 1,2,1,2,1,2,1,2,1,2


; BITMAPs and IMAGEs
bmp_file:
    file 'arcanii.bmp'

img_bmp:
    rb 40*90*3+8
img_brick1:
    rb 40*20*3+8
img_brick2:
    rb 40*20*3+8
img_brick3:
    rb 40*20*3+8
img_brick4:
    rb 40*20*3+8
img_ball:
    rb 10*10*3+8
img_bonus:
    rb 20*10*3+8


screen_img:
    dd X_SIZE
    dd Y_SIZE
screen:
    rb X_SIZE*Y_SIZE*3

I_END:

