All pastes #488453 Raw Edit

Unnamed

public text v1 · immutable
·published 2007-05-15 00:43 UTC
rendered paste body
;----------------------------------------------------------------------
;// PROGRAM DESCIRPTION
;// -=================-
;  This is an interactive battleship game. The user must place their
; ships on the left hand part of the screen, then guess where the
; computer has placed it's ships by shooting at the right hand of the
; screen's grid. The game is played with one user against the computer.
; The game ends when either the computer ships or the users ships have
; all been sunk.
;----------------------------------------------------------------------
;// HIGH-LEVEL ALGORITHIM
;// -===================-
;   seed random number generator
;   load in all sprite data
;   change video mode to 320x200 256color mode (mode 13h)
;   display the title screen to the user
;     wait for the user to hit a key
;   clear the screen
;   display the background for the game
;   enable the mouse
;   limit the mouse to ship placement grid
;   GET THE USER TO ADD SHIPS
;     update display
;     if all ships have been placed
;       end loop
;     check if user has hit mouse button
;     check which ship is being positioned
;     if user pressed right mouse button add 1 to ship value
;     if coordinate is invalid
;       goto GET_THE USER TO ADD SHIPS
;     put the ship at the selected coordinates
;     loop
;   GET THE COMP TO ADD SHIPS
;     if all ships placed
;       end loop
;     check which ship to place
;     get a random number between 0 and 1 to determine if the ship
;       will be vertical or horizontal
;     get a random x and y coordinate between 0 and 9
;     if x and y are not valid
;       goto GET THE COMP TO ADD SHIPS
;     place the ship on to the computer grid at x y
;     loop
;     GAME LOOP
;       draw screen
;       if user wins
;         show picture win.pcx
;       if computer wins
;         show picture lose.pcx
;       wait for a mouse button
;       get the x and y of where the mouse is pointing
;       convert the x and y screen pos to x and y cell
;       read the x and y data from the computer and user grid
;       if cell(x,y) was hit before
;         goto GAME LOOP
;       if computer cell(x,y) = ship
;         put explostion
;         increment the user hit total
;       else
;         put miss
;     MAKE COMPUTER SHOOT
;       get a random x and y between 0 and 9
;       read the x and y data from the computer and user grid
;       if cell(x,y) was hit before
;         goto MAKE COMPUTER SHOOT
;       if user cell(x,y) = ship
;         put explostion
;         increment the computer hit total
;       else
;         put miss
;     loop
;
;     Ask if the user wants to play again
;     if y
;       clear the grids
;        goto GET THE USER TO ADD SHIPS
;     else end the program   
;   
;----------------------------------------------------------------------
;// PROGRAM STATUS
;// -============-
;// * Ship Placement *
;// Ships can be placed verticaly and horizontaly by the user and the
;//  computer with no problem at all.
;// Collision detection works perfect
;// Bounds checking works fine
;// UNUSUAL: Computer tends to add vertical ships VERY often but not
;//          all the time.
;// * Computer and User Shooting *
;// Computer and user only shoot where they havent shot before
;// Impossible to shoot out of bounds
;// Ships are hit propper
;// All necessary updating is done when a ship is hit
;// * End of Game *
;// User can press ESC to quit game any time except when placing ships
;// Actually, user can press any key to quit
;// User can choose not to play another game - works perfect
;// User can choose to play another game - works perfect
;// * Pictures *
;// All pictures display propper
;// Pictures could be of better quality
;// Images are put way too slow, however the lag does not interfere
;//  with the running of the program
;// Special Thanks to Adrian for pointing out that DOS can be real
;//  stupid and not accept file names longer than 8 characters
;----------------------------------------------------------------------
;// REGISTER TABLE
;// -============-
;// AX - Call DOS IO and VIDEO functions 
;// AL - Stores the result of a user input
;// BH - Select page 0 for border color call
;// BL - Select color for border
;// DX - Used to pass the X and Y coordinates for move cursor
;----------------------------------------------------------------------

%TITLE  ""
    
IDEAL
MODEL small
STACK 256
;--------------------------------------------------------
; equate section
;--------------------------------------------------------
DOS_READ                EQU    1
DOS_WRITE               EQU    2
DOS_EXIT                EQU   4Ch
DOScall                 EQU   21h
CR                      EQU   0Dh
LF                      EQU   0Ah
TRUE                    EQU    1
FALSE                   EQU    0
CHANGE_VIDEO            EQU 0000h
DOS_VIDEO               EQU   10h
TEXT_MODE               EQU 0003h
GRAPH_MODE              EQU 0013h
MOUSE_BUTTON_LEFT       EQU 0001h
MOUSE_BUTTON_RIGHT      EQU 0002h
MOUSE_POS_BUTTON        EQU 0003h

DOS_MOUSE               EQU   33h
DOS_VIDEO               EQU   10h

GRID_SIZE               EQU 100
WATER_                  EQU 1

;--------------------------------------------------------
; Macro Section
;--------------------------------------------------------
MACRO Array_2d Array_name, LBR, UBR, LBC, UBC, Size, Init
  dw  LBR
  dw  UBR
  dw  LBC
  dw  UBC
  dw  Size
Array_name dw ( (UBR - LBR + 1)*(UBC - LBC + 1) * Size) DUP (Init)       
endm  Array_2d

MACRO sprite s_name, s_wide, s_high
  dw s_wide
  dw s_high
s_name db ( s_wide * s_high) DUP (3) ;Blue filler
endm sprite

MACRO PushReg registers
  IRP reg, <registers>
    push    reg
  ENDM
ENDM  PushReg

MACRO PopReg registers
  IRP reg, <registers>
    pop    reg
  ENDM
ENDM  PopReg


DATASEG
; User Grid containing users ships and where has been hit on grid
; There are 2 spaces in each cell
;  1) If a ship is in the cell
;  2) If the cell has been hit
; The initialization is all cells set to (0,0)
Array_2d U_Grid, 0, 9, 'a', 'j', 2, 1
; Computer Grid
Array_2d C_Grid, 0, 9, 'a', 'j', 2, 1

;// Create the sprites
sprite ptboat_h , 28, 14
sprite ptboat_v , 14, 28
sprite cruiser_h, 42, 14
sprite cruiser_v, 14, 42
sprite bship_h  , 56, 14
sprite bship_v  , 14, 56
sprite ac_h     , 70, 14
sprite ac_v     , 14, 70
sprite water    , 14, 14
sprite hit1     , 14, 14
sprite miss     , 14, 14

fourteen     db 14

fire          db "fire.pcx",0
water_pcx     db "water.pcx",0
background    db "background.pcx",0
hit1_pcx      db "hit.pcx",0
miss_pcx      db "miss.pcx",0
;// BOATS
ptboat_h_pcx  db "ptboat_h.pcx",0
ptboat_v_pcx  db "ptboat_v.pcx",0
cruiser_h_pcx db "c_h.pcx",0
cruiser_v_pcx db "c_v.pcx",0
bship_h_pcx   db "bship_h.pcx",0
bship_v_pcx   db "bship_v.pcx",0
ac_h_pcx      db "ac_h.pcx",0
ac_v_pcx      db "ac_v.pcx",0

win_pcx       db "win.pcx",0
lose_pcx      db "lose.pcx",0

help_pcx      db "help.pcx",0

c_ship_data   dw ?
c_hit_data    dw ?
u_ship_data   dw ?
u_hit_data    dw ?

comp_hits     dw 0
user_hits     dw 0

curr_ship      dw 0
curr_turn      dw 0
button         dw 0

play_again     db "Do you want to play another game? ", '$'
grid_pos       dw 0

; ------------------------------------------------------------------------
; MAIN
; ------------------------------------------------------------------------
CODESEG
start:
    mov   ax,@data
    mov   ds,ax
    mov   es,ax

    ;// Seed the random number Generator
    call _seed_ran
    
    ; Initialize the sprites
    ; ----- WATER ----------
    push offset water_pcx
    push offset water   
    call load_sprite
    add sp, 4
    ; ---- PATROL BOAT -----
    push offset ptboat_h_pcx
    push offset ptboat_h
    call load_sprite
    add sp, 4
    push offset ptboat_v_pcx
    push offset ptboat_v
    call load_sprite
    add sp, 4
    ; ---- CRUISER -----
    push offset cruiser_h_pcx
    push offset cruiser_h
    call load_sprite
    add sp, 4
    push offset cruiser_v_pcx
    push offset cruiser_v
    call load_sprite
    add sp, 4
    ; ---- BATTLE SHIP -----
    push offset bship_h_pcx
    push offset bship_h
    call load_sprite
    add sp, 4
    push offset bship_v_pcx
    push offset bship_v
    call load_sprite
    add sp, 4
    ; -- AIRCRAFT CARRIER -----
    push offset ac_h_pcx
    push offset ac_h
    call load_sprite
    add sp, 4            
    push offset ac_v_pcx
    push offset ac_v
    call load_sprite
    add sp, 4            
    ; ---- MISS BOAT -----
    push offset miss_pcx
    push offset miss
    call load_sprite
    add sp, 4    
    ; ---- HIT BOAT -----
    push offset hit1_pcx
    push offset hit1
    call load_sprite
    add sp, 4    

restart_game:

    ;// Set the video mode
    mov ah, CHANGE_VIDEO
    mov al, GRAPH_MODE
    int DOS_VIDEO

    ;// show_pcx("fire.pcx",0)
    push offset fire
    call show_pcx
    add sp, 2

    ;// Wait for a keyhit
    mov ah, 7
    int 21h
    
    ;clrscr(0)
    push 0
    call clrscr
    add sp, 2

    ;// show_pcx("background.pcx",0)
    push offset background
    call show_pcx
    add sp, 2

    ;// draw_screen(U_Grid, 5, 5)
    push 5
    push 5
    push offset U_Grid
    call draw_screen
    add sp, 6

    ;// Enable the mouse
    mov ax, 0001h
    int 33h
    ;// Limit the mouse movement
    mov ax, 0007h  ;// Horizontal
    mov cx, 5     ;// MIN
    mov dx, 144    ;// MAX
    shl cx, 1      ;// Multiply by 2 for 640 resolution
    shl dx, 1      ;// Multiply by 2 for 640 resolution
    int 33h
    mov ax, 0008h  ;// Vertical
    mov cx, 5      ;// MIN
    mov dx, 144    ;// MAX
    int 33h
    ;// Position the mouse pointer within the box
    mov ax, 0004h  ;// Mouse pos
    mov cx, 50     ;// Column
    shl cx, 1
    mov dx, 50     ;// Row
    int 33h
    
    ;// Get the user to add ships
loop_put_ship_user:

    mov bx, 0  ;// Clear the mouse output

    ;// draw_screen(U_Grid, 5, 5)
    push 5
    push 5
    push offset U_Grid
    call draw_screen
    add sp, 6

    cmp [curr_turn], 5
    jne not_five
      jmp loop_put_ship_user_done
not_five:
    ;// Reset to the default of left button pressed
    mov [button], MOUSE_BUTTON_LEFT
    
    ;// Check if a mouse button was pressed
    mov ax, MOUSE_POS_BUTTON
    int DOS_MOUSE
    cmp bx, MOUSE_BUTTON_LEFT
    je  left_button_pressed_ship

    cmp bx, MOUSE_BUTTON_RIGHT
    jne loop_put_ship_user
      mov [button], MOUSE_BUTTON_RIGHT
    
left_button_pressed_ship:
 
    ;// Figure out which ship is being placed    
    cmp [curr_turn], 0
    jne not_zero
      mov [curr_ship], 2          
not_zero:
    cmp [curr_turn], 1
    jne not_one
      mov [curr_ship], 2
not_one:
    cmp [curr_turn], 2
    jne not_two
      mov [curr_ship], 4
not_two:
    cmp [curr_turn], 3
    jne not_three
      mov [curr_ship], 6
not_three:
    cmp [curr_turn], 4
    jne not_four
      mov [curr_ship], 8
not_four:
    inc [curr_turn]

;// Check if the ship is vertical or horizontal
    mov ax, [button]
    add [curr_ship], ax
    dec [curr_ship]

    ;// cx contains x
    shr cx, 1     ;// divide x by 2
    sub cx, 5   
    sub dx, 5
   
    mov bx, dx  ;// Store dx so i can do divide
    mov dx, 0
    
    mov ax, cx
    div [fourteen] ;// I couldnt fit 16 on screen
    ;shr ax, 3
    mov cx, 0
    mov cl, al
    mov dx, 0
    mov ax, bx
    div [fourteen]
    ;shr ax, 4
    mov dl, al
    
    ;// Now dx, contains the row and (y)
    ;//     cx, contains the column  (x)    

    ;// ax = validate(U_Grid, [curr_ship], x, y)
    push ax   ;// Make room for return value
    push dx
    push cx
    push [curr_ship]
    push offset U_Grid
    call validate
    add sp, 8
    pop ax    ;// AX knows if the placement is valid

    cmp ax, TRUE
    je valid_position
      dec [curr_turn]
    jmp loop_put_ship_user
valid_position:    

    ;// putship(U_Grid, bship_h, x, y)
    push dx
    push cx
    push [curr_ship] ;// bship_h
    push offset U_Grid
    call put_ship
    add  sp, 8

jmp loop_put_ship_user

loop_put_ship_user_done:

;// ---------- COMPUTER PLACEMENT OF SHIPS ------------------------
;// INITIALIZE THE VARIABLES
    mov [curr_turn], 0    
loop_put_ship_comp:

    mov bx, 0  ;// Clear the mouse output

    ;// draw_screen(C_Grid, 5, 5)
    ;push 5
    ;push 5
    ;push offset C_Grid
    ;call draw_screen
    ;add sp, 6

    ;// DONE INSERTING THE COMPUTERS PLAYERS
    cmp [curr_turn], 5
    jne not_five_comp
      jmp loop_put_ship_comp_done
not_five_comp:
     
    cmp [curr_turn], 0
    jne not_zero_comp
      mov [curr_ship], 2          
not_zero_comp:
    cmp [curr_turn], 1
    jne not_one_comp
      mov [curr_ship], 2
not_one_comp:
    cmp [curr_turn], 2
    jne not_two_comp
      mov [curr_ship], 4
not_two_comp:
    cmp [curr_turn], 3
    jne not_three_comp
      mov [curr_ship], 6
not_three_comp:
    cmp [curr_turn], 4
    jne not_four_comp
      mov [curr_ship], 8
not_four_comp:
    inc [curr_turn]


    ;// Figure out which ship is being placed WITH A RANDOM NUMBER
    ;// button = _get_ran(2)
    push 0    ;// Make room for the return value
    push 2
    call _get_ran
    add  sp, 2
    pop [button]

    mov dx, 0
    mov bx, 2
    div bx
    mov ax, dx
    
;// Check if the ship is vertical or horizontal
;    mov ax, [button]
    add [curr_ship], ax

    ;// GET A RANDOM X NUMBER AND STORE IT TO CX
    ;// ax = _get_ran(8)
    push 0 ;// make room for the return value
    push 8
    call _get_ran
    add sp, 2
    pop ax

    mov dx, 0
    mov bx, 10
    div bx
    mov cx, dx

    ;// GET A RANDOM Y NUMBER AND STORE IT TO DX
    ;// ax = _get_ran(8)
    push 0 ;// make room for the return value
    push 8
    call _get_ran
    add sp, 2
    pop ax

    mov dx, 0
    mov bx, 10
    div bx
    ;// Remainder is stored to DX!

    ;// Now dx, contains the row and (y)
    ;//     cx, contains the column  (x)    

    ;// ax = validate(C_Grid, [curr_ship], x, y)
    push ax   ;// Make room for return value
    push dx
    push cx
    push [curr_ship]
    push offset C_Grid
    call validate
    add sp, 8
    pop ax    ;// AX knows if the placement is valid

    cmp ax, TRUE
    je valid_position_comp
      dec [curr_turn]
    jmp loop_put_ship_comp
valid_position_comp:

    ;// putship(C_Grid, bship_h, x, y)
    push dx
    push cx
    push [curr_ship] ;// bship_h
    push offset C_Grid
    call put_ship
    add  sp, 8

jmp loop_put_ship_comp

loop_put_ship_comp_done:

;------------------------------ DONE COMPUTER PLACEMENT -----------

    ;// Limit the mouse movement ----------------------------------
    mov ax, 0007h  ;// Horizontal
    mov cx, 160    ;// MIN
    mov dx, 300    ;// MAX
    shl cx, 1      ;// Multiply by 2 for 640 resolution
    shl dx, 1      ;// Multiply by 2 for 640 resolution
    int 33h
    mov ax, 0008h  ;// Vertical
    mov cx, 5      ;// MIN
    mov dx, 144    ;// MAX
    int 33h
    ;// Position the mouse pointer within the box
    mov ax, 0004h  ;// Mouse pos
    mov cx, 200    ;// Column
    shl cx, 1
    mov dx, 50     ;// Row
    int 33h


    ;// ----------THIS PART IS THE ACTUALL GAME LOOP!! ------------------
    mov [comp_hits], 0
    mov [user_hits] ,0

loop_key:
    ;// draw_screen(U_Grid, 5, 5)
    push 5
    push 5
    push offset U_Grid
    call draw_screen
    add sp, 6

    ;// CHECK IF THE USER HAS WON (PREFERENCE IS GIVEN TO THE USER)
    cmp [user_hits], 16
    jne not_user_hits
    jmp user_wins
not_user_hits:    
    ;// CHECK IF THE COMPUTER WINS (IN A TIE WIN GOES TO USER
    cmp [comp_hits], 16
    jne not_comp_hits
    jmp comp_wins
not_comp_hits:    


    ;// ------------ LET THE USER TAKE A SHOT -------------------------

    ; Check for mouse button
    mov ax, MOUSE_POS_BUTTON
    int DOS_MOUSE
    cmp bx, MOUSE_BUTTON_LEFT
    je  left_button_pressed
    jmp no_button
left_button_pressed:

    shr cx, 1     ;// divide x by 2

    sub cx, 160
    sub dx, 5
   
    mov bx, dx  ;// Store dx so i can do divide
    mov dx, 0
    
    mov ax, cx
    div [fourteen] ;// I couldnt fit 16 on screen
    ;shr ax, 3
    mov cx, 0
    mov cl, al
    mov dx, 0
    mov ax, bx
    div [fourteen]
    ;shr ax, 4
    mov dl, al
    
    ;// ------- FIRST ADD DATA TO THE COMPUTER GRID ------------
    ;//read_2d(C_Grid,y,x)
    push 0    ;// First return value pos "ship_data"
    push 0    ;// Second return value pos "hit_data"
    push dx
    push cx
    push offset C_Grid
    call read_2d
    add sp, 6
    pop [c_hit_data]
    pop [c_ship_data]

   ;//read_2d(U_Grid,y,x)
    push 0    ;// First return value pos "ship_data"
    push 0    ;// Second return value pos "hit_data"
    push dx
    push cx
    push offset U_Grid
    call read_2d
    add sp, 6
    pop [u_hit_data]
    pop [u_ship_data]

    cmp [u_hit_data], WATER_
    je  hit_water
    jmp loop_key   ;// THEY ALREADY HIT THIS PLACE
hit_water:

    ;//insert(C_Grid, x, y, 0, 1);
    ; Put (1,2) at location (0,1)
    cmp [c_ship_data], WATER_
    jne ship_hit
    push [c_hit_data]
    push 10
    jmp continue_ship_hit    
ship_hit:
    inc [user_hits]
    push [c_hit_data]
    push 11
continue_ship_hit:
    push dx  ;y
    push cx  ;x
    push offset C_Grid
    call insert_2d
    add sp, 10

    ;//insert(U_Grid, x, y, 0, 1);
    ; Put (1,2) at location (0,1)
    cmp [c_ship_data], WATER_
    jne ship_hit2
    push 10
    push [u_ship_data]
    jmp continue_ship_hit2
ship_hit2:
    push 11
    push [u_ship_data]    
continue_ship_hit2:
    push dx  ;y
    push cx  ;x
    push offset U_Grid
    call insert_2d
    add sp, 10

    ;// ------------ LET THE COMPUTER TAKE A SHOT -------------------------

computer_shot:
    ;// GET A RANDOM X NUMBER AND STORE IT TO CX
    ;// ax = _get_ran(8)
    push 0 ;// make room for the return value
    push 8
    call _get_ran
    add sp, 2
    pop ax

    mov dx, 0
    mov bx, 10
    div bx
    mov cx, dx

    ;// GET A RANDOM Y NUMBER AND STORE IT TO DX
    ;// ax = _get_ran(8)
    push 0 ;// make room for the return value
    push 8
    call _get_ran
    add sp, 2
    pop ax

    mov dx, 0
    mov bx, 10
    div bx
    ;// Remainder is stored to DX!

    ;// ------- FIRST ADD DATA TO THE COMPUTER GRID ------------
    ;//read_2d(C_Grid,y,x)
    push 0    ;// First return value pos "ship_data"
    push 0    ;// Second return value pos "hit_data"
    push dx
    push cx
    push offset C_Grid
    call read_2d
    add sp, 6
    pop [c_hit_data]
    pop [c_ship_data]

   ;//read_2d(U_Grid,y,x)
    push 0    ;// First return value pos "ship_data"
    push 0    ;// Second return value pos "hit_data"
    push dx
    push cx
    push offset U_Grid
    call read_2d
    add sp, 6
    pop [u_hit_data]
    pop [u_ship_data]

    ;// Check if that position has already been shot at
    cmp [c_hit_data], WATER_
    je  hit_water_comp
    jmp computer_shot   ;// THEY ALREADY HIT THIS PLACE
hit_water_comp:

    ;//insert(C_Grid, x, y, 0, 1);
    ; Put (1,2) at location (0,1)
    cmp [u_ship_data], WATER_
    jne ship_hit_comp
    push 10
    push [c_ship_data]
    jmp continue_ship_hit_comp
ship_hit_comp:
    inc [comp_hits]
    push 11
    push [c_ship_data]
continue_ship_hit_comp:
    push dx  ;y
    push cx  ;x
    push offset C_Grid
    call insert_2d
    add sp, 10

    ;//insert(U_Grid, x, y, SHIP, HIT);
    ; Put (HIT/MISS,HIT_DATA) at location (x,y)
    cmp [u_ship_data], WATER_
    jne ship_hit2_comp
    push [u_hit_data]
    push 10
    jmp continue_ship_hit2_comp
ship_hit2_comp:
    push [u_hit_data]    
    push 11
continue_ship_hit2_comp:
    push dx  ;y
    push cx  ;x
    push offset U_Grid
    call insert_2d
    add sp, 10
    
no_button:

    ;// Check if there is a key to get
    mov ah, 000Bh;    KEYBOARD_STATUS
    int 21h
    cmp al, 00h
    je  no_key_available
    jmp loop_key_done
no_key_available:

jmp loop_key     ;// END OF GAME LOOP

    ;// Wait for a keyhit
    mov ah, 7
    int 21h
loop_key_done:

jmp done_wins

;// DISPLAY THE USER WIN SCREEN
user_wins:
    ;//clrscr(0);
    push 0
    call clrscr
    add sp, 2

    ;//showpcx("win.pcx");
    push offset win_pcx
    call show_pcx
    add sp, 2    
jmp done_wins


;// DISPLAY THE COMPUTER WIN SCREEN
comp_wins:
    ;//clrscr(0);
    push 0
    call clrscr
    add sp, 2

    ;//showpcx("lose.pcx");
    push offset lose_pcx
    call show_pcx
    add sp, 2
done_wins:

    ;// Wait for the user to hit a key
    ;// Wait for a keyhit
    mov ah, 7
    int 21h


;// CHECK IF THE USER WANTS TO PLAY ANOTHER GAME
    ;// CHANGE SCREEN TO TEXT MODE
    mov ah, CHANGE_VIDEO
    mov al, TEXT_MODE
    int DOS_VIDEO
    
play_again_loop:
    ;// ASK THE USER IF THEY WANT TO PLAY AGAIN
    mov ah, 09h
    mov dx, offset play_again
    int 21h

    mov ah, 01h
    int 21h
    ;// AL now contains the character
    cmp al, 'y'
    je yes
    jmp not_yes
yes:
    ;// Empty out the two grids
    mov [grid_pos], 0
grid_empty:
    ;insert_2d(U_Grid, grid_pos, 0, 1, 1)
    push WATER_
    push WATER_
    push 0
    push [grid_pos]
    push offset U_Grid
    call insert_2d    
    add sp, 10

    ;insert_2d(C_Grid, grid_pos, 0, 1, 1)
    push WATER_
    push WATER_
    push 0
    push [grid_pos]
    push offset C_Grid
    call insert_2d
    add sp, 10

    inc [grid_pos]

    cmp [grid_pos], GRID_SIZE
    jb  grid_empty

    mov [comp_hits], 0
    mov [user_hits], 0

    mov [curr_ship], 0
    mov [curr_turn], 0

    jmp restart_game

not_yes:
    mov   ah, DOS_EXIT
    mov   al, 0
    int   DOSCALL

; ------------------------------------------------------------------------
; A Function to determine if a ship can be placed at a spot
; int validate(int *v_grid, int v_ship, int v_x, int v_y)
; int *v_grid - The grid containing ships, and hits
; int v_ship - The ship to be added to the graph
; int v_x      - The row to add the info to
; int v_y      - The col to add the info to
; -------------------------------
; RETURNS 1 if valid; 0 if invalid
; ------------------------------------------------------------------------
; EQUATE SECTION
V_SIZE        EQU  -2
V_ARRAY_POS   EQU   0
V_PTBOAT_H        EQU  2
V_PTBOAT_V        EQU  3
V_CRUISER_H       EQU  4
V_CRUISER_V       EQU  5
V_BSHIP_H         EQU  6
V_BSHIP_V         EQU  7
V_AC_H            EQU  8
V_AC_V            EQU  9

V_PTBOAT_SIZE     EQU  2
V_CRUISER_SIZE    EQU  3
V_BSHIP_SIZE      EQU  4
V_AC_SIZE         EQU  5
V_WATER           EQU  1
V_GRID_HIGH       EQU 10
V_GRID_WIDE       EQU 10

;// PARAMETERS
V_GRID_POS    EQU   4
V_SHIP_POS    EQU   6
V_X_POS       EQU   8
V_Y_POS       EQU  10
V_RESULT      EQU  12

DATASEG
v_x             dw 0
v_y             dw 0
v_val1          dw 0
v_val2          dw 0
v_size_of_word  dw 2 
v_ship_size     dw ?
v_ship          dw ?
v_curr_size     dw 0

CODESEG
proc validate
  ;// Create a Base Pointer
  push bp;
  mov bp, sp;
  ;// Push Registers Onto Stack
  PushReg <ax,bx,cx,dx,si,di>

  ;// Get The Parameters From the Stack
  mov ax, [bp + V_Y_POS]               ; The row to add information to
  mov [v_y ], ax
  mov ax, [bp + V_X_POS]               ; The col to add information to
  mov [v_x ], ax  
  mov ax, [bp + V_SHIP_POS]              ; Ship Type Information
  mov [v_ship], ax  

  ;// make si point to the start of the grid object
  mov si, [bp + V_GRID_POS]

  ;// Find the size of the ship  
  cmp [v_ship], V_PTBOAT_H
  jne v_not_ptboat_h
    mov [v_ship_size], V_PTBOAT_SIZE
v_not_ptboat_h:
  cmp [v_ship], v_PTBOAT_V
  jne v_not_ptboat_v
    mov [v_ship_size], V_PTBOAT_SIZE
v_not_ptboat_v:
  cmp [v_ship], V_CRUISER_H
  jne v_not_cruiser_h
    mov [v_ship_size], V_CRUISER_SIZE
v_not_cruiser_h:
  cmp [v_ship], V_CRUISER_V
  jne v_not_cruiser_v
    mov [v_ship_size], V_CRUISER_SIZE
v_not_cruiser_v:
  cmp [v_ship], V_BSHIP_H
  jne v_not_bship_h
    mov [v_ship_size], V_BSHIP_SIZE
v_not_bship_h:
  cmp [v_ship], V_BSHIP_V
  jne v_not_bship_v
    mov [v_ship_size], V_BSHIP_SIZE
v_not_bship_v:
  cmp [v_ship], V_AC_H
  jne v_not_ac_h
    mov [v_ship_size], V_AC_SIZE
v_not_ac_h:
  cmp [v_ship], V_AC_V
  jne v_not_ac_v
    mov [v_ship_size], V_AC_SIZE
v_not_ac_v:

;// Initialize the loop
  mov [v_curr_size], 0
  mov [WORD bp + V_RESULT], TRUE

v_loop:
  mov ax, [v_curr_size]
  cmp ax, [v_ship_size]
  jae v_loop_done

  ;// val1 val2 read_2d(sp, v_x, v_y)
  push ax    ; Make room for the return values
  push ax    ;
  push [v_y]
  push [v_x]
  push si
  call read_2d
  add sp, 6

  pop [v_val2]
  pop [v_val1]

  ;// Make sure the ship will sail on water
  cmp [v_val1], V_WATER
  je v_on_water
    mov [WORD bp + V_RESULT], FALSE
    jmp v_loop_done
v_on_water:  

  ;// Set the curr ship to nothing
  inc [v_curr_size]
  mov dx, 0
  mov ax, [v_ship]
  mov bx, 2
  div bx
  cmp dx, 0
  je v_even
  inc [v_y]
  ;// Check if the boat is being placed off the grid
  cmp [v_y], V_GRID_HIGH
  jbe v_on_grid_y
    mov [WORD bp + V_RESULT], FALSE
    jmp v_loop_done  
v_on_grid_y:
  jmp v_loop
v_even:
  inc [v_x]
  cmp [v_x], V_GRID_WIDE
  jbe v_on_grid_x
    mov [WORD bp + V_RESULT], FALSE
    jmp v_loop_done  
v_on_grid_x:
  jmp v_loop

v_loop_done:

  ;// Pop Registers Off the Stack
  PopReg <di,si,dx,cx,bx,ax>
  pop bp;
  ret
endp validate


; ------------------------------------------------------------------------
; A Function to put a ship to a grid
; void insert_2d(int *puts_grid, int puts_ship, int puts_x, int puts_y)
; int *puts_grid - The grid containing ships, and hits
; int puts_ship - The ship to be added to the graph
; int puts_x      - The row to add the info to
; int puts_y      - The col to add the info to
; ------------------------------------------------------------------------
; EQUATE SECTION
PUTS_SIZE        EQU  -2
PUTS_ARRAY_POS   EQU   0
PUTS_PTBOAT_H        EQU  2
PUTS_PTBOAT_V        EQU  3
PUTS_CRUISER_H       EQU  4
PUTS_CRUISER_V       EQU  5
PUTS_BSHIP_H         EQU  6
PUTS_BSHIP_V         EQU  7
PUTS_AC_H            EQU  8
PUTS_AC_V            EQU  9

PUTS_PTBOAT_SIZE     EQU  2
PUTS_CRUISER_SIZE    EQU  3
PUTS_BSHIP_SIZE      EQU  4
PUTS_AC_SIZE         EQU  5

;// PARAMETERS
PUTS_GRID_POS    EQU   4
PUTS_SHIP_POS    EQU   6
PUTS_X_POS       EQU   8
PUTS_Y_POS       EQU  10

DATASEG
puts_x             dw 0
puts_y             dw 0
puts_val1          dw 0
puts_val2          dw 0
puts_size_of_word  dw 2 
puts_ship_size     dw ?
puts_ship          dw ?
puts_curr_size     dw 0

CODESEG
proc put_ship
  ;// Create a Base Pointer
  push bp;
  mov bp, sp;
  ;// Push Registers Onto Stack
  PushReg <ax,bx,cx,dx,si,di>

  ;// Get The Parameters From the Stack
  mov ax, [bp + PUTS_Y_POS]               ; The row to add information to
  mov [puts_y ], ax
  mov ax, [bp + PUTS_X_POS]               ; The col to add information to
  mov [puts_x ], ax  
  mov ax, [bp + PUTS_SHIP_POS]              ; Ship Type Information
  mov [puts_ship], ax  

  ;// make si point to the start of the grid object
  mov si, [bp + PUTS_GRID_POS]

  ;// Find the size of the ship  
  cmp [puts_ship], PUTS_PTBOAT_H
  jne puts_not_ptboat_h
    mov [puts_ship_size], PUTS_PTBOAT_SIZE
puts_not_ptboat_h:
  cmp [puts_ship], PUTS_PTBOAT_V
  jne puts_not_ptboat_v
    mov [puts_ship_size], PUTS_PTBOAT_SIZE
puts_not_ptboat_v:
  cmp [puts_ship], PUTS_CRUISER_H
  jne puts_not_cruiser_h
    mov [puts_ship_size], PUTS_CRUISER_SIZE
puts_not_cruiser_h:
  cmp [puts_ship], PUTS_CRUISER_V
  jne puts_not_cruiser_v
    mov [puts_ship_size], PUTS_CRUISER_SIZE
puts_not_cruiser_v:
  cmp [puts_ship], PUTS_BSHIP_H
  jne puts_not_bship_h
    mov [puts_ship_size], PUTS_BSHIP_SIZE
puts_not_bship_h:
  cmp [puts_ship], PUTS_BSHIP_V
  jne puts_not_bship_v
    mov [puts_ship_size], PUTS_BSHIP_SIZE
puts_not_bship_v:
  cmp [puts_ship], PUTS_AC_H
  jne puts_not_ac_h
    mov [puts_ship_size], PUTS_AC_SIZE
puts_not_ac_h:
  cmp [puts_ship], PUTS_AC_V
  jne puts_not_ac_v
    mov [puts_ship_size], PUTS_AC_SIZE
puts_not_ac_v:

;// Initialize the loop
  mov [puts_curr_size], 0

puts_loop:
  mov ax, [puts_curr_size]
  cmp ax, [puts_ship_size]
  jae puts_loop_done

  mov bx, [puts_ship]
  cmp ax, 0
  je puts_first_cell
  mov bx, 0 
puts_first_cell:
  
  ;// insert_2d(sp, puts_x, puts_y, puts_ship, 1)
  push 1
  push bx ;  The variable [puts_ship] or 0
  push [puts_y]
  push [puts_x]
  push si
  call insert_2d
  add sp, 10

  ;// Set the curr ship to nothing
  inc [puts_curr_size]
  mov dx, 0
  mov ax, [puts_ship]
  mov bx, 2
  div bx
  cmp dx, 0
  je puts_even
  inc [puts_y]
  jmp puts_loop
puts_even:
  inc [puts_x]
  jmp puts_loop

puts_loop_done:

  ;// Pop Registers Off the Stack
  PopReg <di,si,dx,cx,bx,ax>
  pop bp;
  ret
endp put_ship


; ------------------------------------------------------------------------
; A Function to index into a 2D array
; int index(int *i_grid, int i_x, int i_y)
; int *in_grid - The grid containing ships, and hits
; int in_x     - The column to check
; int in_y     - The row to check
; ------------------------------------------------------------------------
; EQUATE SECTION
IN_LBR         EQU -10
IN_UBR         EQU  -8
IN_LBC         EQU  -6
IN_UBC         EQU  -4
IN_SIZE        EQU  -2
IN_ARRAY_POS   EQU   0

IN_SHIP        EQU   0
IN_HIT         EQU   2

;// PARAMETERS
IN_GRID_POS    EQU   4
IN_X_POS       EQU   6
IN_Y_POS       EQU   8
IN_RETURN      EQU  10


DATASEG
in_x             dw 0
in_y             dw 0
in_size_of_word  dw 2 

CODESEG
proc index
  ;// Create a Base Pointer
  push bp;
  mov bp, sp;
  ;// Push Registers Onto Stack
  PushReg <ax,bx,cx,dx,si,di>

  ;// Get The Parameters From the Stack
  mov ax, [bp + IN_Y_POS]               ; The row to add information to
  mov [in_y ], ax
  mov ax, [bp + IN_X_POS]               ; The col to add information to
  mov [in_x ], ax  

  ;// make si point to the start of the grid object
  mov si, [bp + IN_GRID_POS]

  ;// Find the width of each row - store it in bx
  mov bx, [si + IN_UBC]
  sub bx, [si + IN_LBC]
  inc bx   ;// Include '0'            

  ;// Get the row to add the information to
  mov ax, [in_y]

  ;// Multiply the row by the size of a row
  mul bx

  ;// Find out how far right to move in the current row
  mov bx, [in_x]            ;// NOTE: i_x  is a letter like 'a' or 'd'
;  sub bx, [si + IN_LBC]     ;// Convert the char value to a # value
  add ax, bx

  ;// Correct for the size of the cells
  mul [in_size_of_word]     ;// Each data member is a word
  mul [WORD si + IN_SIZE]   ;// The number of elements per cell

  mov [bp + IN_RETURN], ax

  ;// Pop Registers Off the Stack
  PopReg <di,si,dx,cx,bx,ax>
  pop bp;
  ret
endp index

; ------------------------------------------------------------------------
; A Function to Insert into a 2D array
; void insert_2d(int *i_grid, int i_x, int i_y, int i_v1, int i_v2)
; int *i_grid - The grid containing ships, and hits
; int i_x     - The column to add the info to
; int i_y     - The row to add the info to
; int i_v1    - The first data member of the cell (Ship type)
; int i_v2    - The second data member of the cell (Hit info)
; ------------------------------------------------------------------------
; EQUATE SECTION
I_LBR         EQU -10
I_UBR         EQU  -8
I_LBC         EQU  -6
I_UBC         EQU  -4
I_SIZE        EQU  -2
I_ARRAY_POS   EQU   0

I_SHIP        EQU   0
I_HIT         EQU   2

;// PARAMETERS
I_GRID_POS    EQU   4
I_X_POS       EQU   6
I_Y_POS       EQU   8
I_V1_POS      EQU  10
I_V2_POS      EQU  12

DATASEG
i_x           dw 0
i_y           dw 0
i_v1          dw 0
i_v2          dw 0
size_of_word  dw 2 

CODESEG
proc insert_2d
  ;// Create a Base Pointer
  push bp;
  mov bp, sp;
  ;// Push Registers Onto Stack
  PushReg <ax,bx,cx,dx,si,di>

  ;// Get The Parameters From the Stack
  mov ax, [bp + I_Y_POS]               ; The row to add information to
  mov [i_y ], ax
  mov ax, [bp + I_X_POS]               ; The col to add information to
  mov [i_x ], ax  
  mov ax, [bp + I_V1_POS]              ; Ship Type Information
  mov [i_v1], ax  
  mov ax, [bp + I_V2_POS]              ; Grid Hit Information
  mov [i_v2], ax  

  ;// make si point to the start of the grid object
  mov si, [bp + I_GRID_POS]

  ;// ax = index(si, x,y)
  push ax   ;// Create a space for the return value
  push [i_y]
  push [i_x]
  push si
  call index
  add sp, 6
  pop ax
  
  ;// Make si point to the correct place in the array
  add si, ax

  ;// Move the data into its correct place
  mov ax, [i_v1];
  mov [si + I_SHIP], ax;
  mov ax, [i_v2];
  mov [si + I_HIT ], ax;

  ;// Pop Registers Off the Stack
  PopReg <di,si,dx,cx,bx,ax>
  pop bp;
  ret
endp insert_2d

; ------------------------------------------------------------------------
; A Function to read from a 2D array
; int int read_2d(int *i_grid, int i_x, int i_y)
; int *i_grid - The grid containing ships, and hits
; int i_x     - The column to read the info from
; int i_y     - The row to read the info from
; ------------------------------------------------------------------------
; EQUATE SECTION
R_LBR         EQU -10
R_UBR         EQU  -8
R_LBC         EQU  -6
R_UBC         EQU  -4
R_SIZE        EQU  -2
R_ARRAY_POS   EQU   0

R_SHIP        EQU   0
R_HIT         EQU   2

;// PARAMETERS
R_GRID_POS    EQU   4
R_X_POS       EQU   6
R_Y_POS       EQU   8
;// Return Value Positions
R_H_RESULT    EQU  10     ;// The hit result
R_S_RESULT    EQU  12     ;// The ship result

DATASEG
r_x             dw 0
r_y             dw 0
r_size_of_word  dw 2 

CODESEG
proc read_2d
  ;// Create a Base Pointer
  push bp;
  mov bp, sp;
  ;// Push Registers Onto Stack
  PushReg <ax,bx,cx,dx,si,di>

  ;// Get The Parameters From the Stack
  mov ax, [bp + R_Y_POS]               ; The row to add information to
  mov [r_y ], ax
  mov ax, [bp + R_X_POS]               ; The col to add information to
  mov [r_x ], ax  

  ;// make si point to the start of the grid object
  mov si, [bp + R_GRID_POS]

  ;// ax = index(si, x,y)
  push ax   ;// Create a space for the return value
  push [r_y]
  push [r_x]
  push si
  call index
  add sp, 6
  pop ax
  ;// Make si point to the correct place in the array
  add si, ax

  ;// Move the data into its correct place
  mov ax, [si + I_SHIP]
  mov [bp + R_S_RESULT], ax
  mov ax, [si + I_HIT ]
  mov [bp + R_H_RESULT], ax

  ;// Pop Registers Off the Stack
  PopReg <di,si,dx,cx,bx,ax>
  pop bp;
  ret
endp read_2d


; ------------------------------------------------------------------------
; A Function to draw a pixel to the screen
; void put_pixel(int pp_x, int pp_y, int pp_color)
; int  pp_x       - The column to add the pixel to
; int  pp_y       - The row to add the pixel to
; int  pp_color   - The color to put at the location
; ------------------------------------------------------------------------
; EQUATE SECTION
;// PARAMETERS
PP_X_POS      EQU   4
PP_Y_POS      EQU   6
PP_COLOR_POS  EQU   8

DATASEG
pp_x           dw 0
pp_y           dw 0
pp_color       dw 0 

CODESEG
proc put_pixel
  ;// Create a Base Pointer
  push bp;
  mov bp, sp;
  ;// Push Registers Onto Stack
  PushReg <ax,cx,dx>


  ;// Get The Parameters From the Stack
  mov ax, [bp + PP_Y_POS]              ; The row to add information to
  mov [pp_y ], ax
  mov ax, [bp + PP_X_POS]              ; The col to add information to
  mov [pp_x ], ax  
  mov ax, [bp + PP_COLOR_POS]          ; Ship Type Information
  mov [pp_color], ax  

  ;// Call the BIOS functoin
  mov ax, [pp_color]
  mov ah, 0Ch         ;// Put Pixel to mode 13 screen
  mov cx, [pp_x]
  mov dx, [pp_y]
  int 10h

  ;// Pop Registers Off the Stack
  PopReg <dx,cx,ax>
  pop bp;
  ret
endp put_pixel

; ------------------------------------------------------------------------
; A Function to clear the screen to a specific color
; void clrscr(char c_color)
; int  c_color   - The color to put to the screen
; ------------------------------------------------------------------------
; EQUATE SECTION
;// PARAMETERS
C_COLOR_POS   EQU   4
C_SCREEN_SIZE EQU   64000

DATASEG
c_color       dw 0
c_x           dw 0

CODESEG
proc clrscr
  ;// Create a Base Pointer
  push bp;
  mov bp, sp;
  ;// Push Registers Onto Stack
  PushReg <ax,bx,cx,dx>

  ;// Get The Parameters From the Stack
  mov ax, [bp + C_COLOR_POS]          ; Color
  mov [c_color], ax  

  ;// Set the x variable
  mov [c_x], 0

c_loop:
  mov bx, [c_x]
  cmp bx, C_SCREEN_SIZE
  jae c_loop_done
  
  ;// Call the BIOS functoin
  mov ax, [c_color]
  mov ah, 0Ch         ;// Put Pixel to mode 13 screen
  mov cx, [c_x]
  mov dx, [0]
  int 10h

  ;// Incriment the pixel count
  inc [c_x]
  jmp c_loop
c_loop_done:

  ;// Pop Registers Off the Stack
  PopReg <dx,cx,bx,ax>
  pop bp;
  ret
endp clrscr


; ------------------------------------------------------------------------
; A Function to show a 320x200 PCX to the screen
; void show_pcx(char* filename)
; char*  sp_filename   - The name of the file to display
; ------------------------------------------------------------------------
; EQUATE SECTION
;// PARAMETERS
SP_PCX_FILENAME     EQU   4
SP_PCX_HEADER_SIZE  EQU   128
SP_PCX_SIZE         EQU   64000

DATASEG
sp_x           dw 0
sp_y           dw 0
sp_color       db 0
sp_count       dw 0
sp_filehandle  dw ?
sp_num_bytes   dw 0
sp_256         dw 0ffh
sp_palette     db 3 dup(60)

CODESEG
proc show_pcx
  ;// Create a Base Pointer
  push bp;
  mov bp, sp;
  ;// Push Registers Onto Stack
  PushReg <ax,bx,cx,dx,si>


  ;// Get The Parameters From the Stack
  mov dx, [bp + SP_PCX_FILENAME]       ; The row to add information to

  ;// Open the file
  mov ah, 3Dh   ;// Open file
  mov al, 00h   ;// Read only
  int 21h       ;// Call BIOS function to open file

  mov [sp_filehandle], ax ; Save the file handle


;// LOAD THE PALETTE
;// Reset the counter
  mov [sp_count],0
;// Move the file pos to the right location
  mov ah, 42h
  mov al, 02h
  mov bx, [sp_filehandle]
  mov dx, 0FD00h
  mov cx, 0FFFFh
  int 21h

;// Load the palette
sp_load_pal:
  cmp [sp_count],255
  jae sp_load_pal_done

  ; Get a character (R)
  mov ah, 3fh
  mov bx, [sp_filehandle]
  mov cx, 3       ;// Read 3 bytes at a time
  mov dx, offset sp_palette
  int 21h

  mov si, offset sp_palette

  mov dx, 3C8h
  mov ax, [sp_count]
  out dx, al
  inc dx
  mov al, [si]
  shr al, 2
  out dx, al
  mov al, [si+1]
  shr al, 2  
  out dx, al
  mov al, [si+2]
  shr al, 2  
  out dx, al  

  inc [sp_count]
  jmp sp_load_pal

sp_load_pal_done:


;// Move the file pos to the right location
  mov ah, 42h
  mov al, 00h
  mov bx, [sp_filehandle]
  mov dx, SP_PCX_HEADER_SIZE
  mov cx, 0
  int 21h


  ;// Set the counter variable
  mov [sp_count], 0
  
sp_loop:  
  mov bx, [sp_count]
  cmp bx, SP_PCX_SIZE
  jae sp_loop_done

  mov ah, 3fh
  mov bx, [sp_filehandle]
  mov cx, 1       ;// Read one byte at a time
  mov dx, offset sp_color
  int 21h

  cmp [sp_color], 192
  jb  sp_raw_data

  ;// Must decode the RLE info
  mov ah, 0
  mov al, [sp_color]
  sub ax, 192
  mov [sp_num_bytes], ax  

  ;// Get another character
  mov ah, 3fh
  mov bx, [sp_filehandle]
  mov cx, 1       ;// Read one byte at a time
  mov dx, offset sp_color
  int 21h

sp_RLE:
  cmp [sp_num_bytes], 0
  jbe sp_loop

  ;// Put pixel
  mov al, [sp_color]
  mov ah, 0Ch         ;// Put Pixel to mode 13 screen
  mov cx, [sp_count]
  mov dx, 0
  int 10h

  inc [sp_count]
  dec [sp_num_bytes]

  jmp sp_RLE

sp_raw_data:
  ;// Call the BIOS function
  mov al, [sp_color]
  mov ah, 0Ch         ;// Put Pixel to mode 13 screen
  mov cx, [sp_count]
  mov dx, 0
  int 10h
  ;// Increment the count
  inc [sp_count]

  jmp sp_loop

sp_loop_done:

  ;// Close the file
  mov ah, 3Eh
  mov bx, [sp_filehandle]
  int 21h       ;// KILL the handle

  ;// Pop Registers Off the Stack
  PopReg <si,dx,cx,bx,ax>
  pop bp;
  ret
endp show_pcx

; ------------------------------------------------------------------------
; A Function to load a sprite from a pcx file
; void load_sprite(char* ls_sprite, char* ls_filename, int ls_wide,
;                  int ls_high)
; int  ls_sprite   - The memory location to save the sprite to
; int  ls_filename - The name of the file containing the sprite
; int  ls_wide     - The width of the pcx file
; int  ls_high     - The height of the pcx file
; ------------------------------------------------------------------------
; EQUATE SECTION
;// PARAMETERS
LS_SPRITE_POS       EQU   4
LS_FILENAME_POS     EQU   6
LS_WIDE_POS         EQU  -4
LS_HIGH_POS         EQU  -2
LS_PCX_HEADER_SIZE  EQU   128

DATASEG
ls_color       dw 0
ls_count       dw 0
ls_total       dw 0
ls_filehandle  dw 0
ls_num_bytes   dw 0
ls_wide        dw 0
ls_x           dw 0

CODESEG
proc load_sprite
  ;// Create a Base Pointer
  push bp;
  mov bp, sp;
  ;// Push Registers Onto Stack
  PushReg <ax,bx,cx,dx,si>

  ;// Get The Parameters From the Stack
  mov dx, [bp + LS_FILENAME_POS]

  ;// Open the file
  mov ah, 3Dh   ;// Open file
  mov al, 00h   ;// Read only
  int 21h       ;// Call BIOS function to open file

  mov [ls_filehandle], ax ;// Store the file handle

;// Move the file pos to the right location
  mov ah, 42h
  mov al, 00h
  mov bx, [ls_filehandle]
  mov dx, LS_PCX_HEADER_SIZE
  mov cx, 0
  int 21h

  ;// Set the counter variable
  mov [ls_count], 0
  mov [ls_x], 0

  ;// Find the number of bytes in the pic
  mov si, [bp + LS_SPRITE_POS]
  mov ax, [si + LS_WIDE_POS]
  mov [ls_wide], ax
  mov bx, [WORD si + LS_HIGH_POS]
  mul bx
  mov [ls_total], ax

ls_loop:  
  mov bx, [ls_count]
  cmp bx, [ls_total]
  jb  ls_loop_continue
  jmp ls_loop_done
ls_loop_continue:

  mov ah, 3fh
  mov bx, [ls_filehandle]
  mov cx, 1       ;// Read one byte at a time
  mov dx, offset ls_color
  int 21h

  cmp [ls_color], 192
  jb  ls_raw_data
 
  ;// Must decode the RLE info
  mov ax, [ls_color]
  sub ax, 192
  mov [ls_num_bytes], ax  

  ;// Get another character
  mov ah, 3fh
  mov bx, [ls_filehandle]
  mov cx, 1       ;// Read one byte at a time
  mov dx, offset ls_color
  int 21h

ls_RLE:
  cmp [ls_num_bytes], 0
  jbe ls_loop

  ;// Store the byte to the sprite
  mov ax, [ls_color]
  mov [si], al

  inc [ls_count]  
  inc si
  inc [ls_x]
  dec [ls_num_bytes]
jmp ls_RLE

ls_raw_data:  
  mov ax, [ls_color]
  mov [si], al

  inc si
  inc [ls_count]
  inc [ls_x]
jmp ls_loop

ls_loop_done:

  ;// Close the file
  mov ah, 3Eh
  mov bx, [ls_filehandle]
  int 21h       ;// KILL the handle

  ;// Pop Registers Off the Stack
  PopReg <si,dx,cx,bx,ax>
  pop bp;
  ret
endp load_sprite

; ------------------------------------------------------------------------
; A Function to put a sprite to the screen
; void put_sprite(char* ps_sprite, int ps_x, int ps_y)
; char*  ps_sprite   - The picture to show to the screen
; int    ps_x        - The x pos to show the pic to
; int    ps_y        - The y pos to show the pic to
; ------------------------------------------------------------------------
; EQUATE SECTION
;// PARAMETERS
PS_SPRITE_POS       EQU   4
PS_X_POS            EQU   6
PS_Y_POS            EQU   8
PS_WIDE_POS         EQU  -4
PS_HIGH_POS         EQU  -2

DATASEG
ps_x           dw 0
ps_x_start     dw 0
ps_y           dw 0
ps_wide        dw 0
ps_color       db 0
ps_count       dw 0
ps_total       dw 0

CODESEG
proc put_sprite
  ;// Create a Base Pointer
  push bp;
  mov bp, sp;
  ;// Push Registers Onto Stack
  PushReg <ax,bx,cx,dx,si>

  ;// Get the parameters
  mov ax, [bp + PS_X_POS]
  mov [ps_x], ax
  mov [ps_x_start], ax
  mov ax, [bp + PS_Y_POS]
  mov [ps_y], ax
  mov si, [bp + PS_SPRITE_POS]

  ;// The total bytes in the image
  mov ax, [si + PS_WIDE_POS]
  mov [ps_wide], ax
  mul [WORD si + PS_HIGH_POS]
  mov [ps_total], ax

  ;// Set the counter variable
  mov [ps_count], 0  

ps_loop:  
  mov bx, [ps_count]
  cmp bx, [ps_total]
  jae ps_loop_done  

  ;// Get the current color
  mov al, [si]
  mov [ps_color], al

  ;// Put pixel
  mov al, [ps_color]
  mov ah, 0Ch         ;// Put Pixel to mode 13 screen
  mov cx, [ps_x]
  mov dx, [ps_y]
  int 10h

  ;// Increment all the variables
  inc [ps_count]
  inc [ps_x]
  inc si

  mov ax, [ps_x]
  sub ax, [ps_x_start]
  cmp ax, [ps_wide]
  jb ps_loop
  mov ax, [ps_x_start]
  mov [ps_x], ax
  inc [ps_y]
  jmp ps_loop

ps_loop_done:

  ;// Pop Registers Off the Stack
  PopReg <si,dx,cx,bx,ax>
  pop bp;
  ret
endp put_sprite


; ------------------------------------------------------------------------
; A Function to draw the screen
; void draw_screen(char* ds_dgrid, int ds_x_pos, int ds_y_pos)
; char*  ds_grid     - The defense grid
; int    ds_x_pos    - The col to place the grid at
; int    ds_y_pos    - The row to place the grid at
; ------------------------------------------------------------------------
; EQUATE SECTION
;// PARAMETERS
DS_Y_PARAMETER     EQU   8
DS_X_PARAMETER     EQU   6
DS_GRID_POS        EQU   4
DS_CELL_SIZE       EQU  14
DS_DGRID_X         EQU   5
DS_DGRID_Y         EQU   5
DS_TGRID_X         EQU 160
DS_TGRID_Y         EQU   5

DS_NOTHING         EQU  0
DS_WATER           EQU  1
DS_PTBOAT_H        EQU  2
DS_PTBOAT_V        EQU  3
DS_CRUISER_H       EQU  4
DS_CRUISER_V       EQU  5
DS_BSHIP_H         EQU  6
DS_BSHIP_V         EQU  7
DS_AC_H            EQU  8
DS_AC_V            EQU  9
DS_MISS            EQU 10
DS_HIT1            EQU 11

DS_GRID_LBR        EQU -10
DS_GRID_UBR        EQU  -8
DS_GRID_LBC        EQU  -6
DS_GRID_UBC        EQU  -4
DS_GRID_SIZE       EQU  -2

DATASEG
ds_x           dw 0
ds_x_pos       dw 0
ds_x_start     dw 0
ds_y           dw 0
ds_y_pos       dw 0
ds_ship        dw 0
ds_hit         dw 0
ds_count       dw 0
ds_size        dw ?

ds_d_LBR       dw ?
ds_d_UBR       dw ?
ds_d_LBC       dw ?
ds_d_UBC       dw ?
ds_d_grid_wide dw ?
ds_d_total           dw ?
ds_d_grid_cell_wide  dw ?

CODESEG
proc draw_screen
  ;// Create a Base Pointer
  push bp;
  mov bp, sp;
  ;// Push Registers Onto Stack
  PushReg <ax,bx,cx,dx,si>

  ;// Get the grid
  mov si, [bp + DS_GRID_POS]

  mov ax, [si + DS_GRID_SIZE]
  mov [ds_size], ax
  mov ax, [si + DS_GRID_LBR]
  mov [ds_d_LBR], ax
  mov ax, [si + DS_GRID_UBR]
  mov [ds_d_UBR], ax
  mov ax, [si + DS_GRID_LBC]
  mov [ds_d_LBC], ax
  mov ax, [si + DS_GRID_UBC]
  mov [ds_d_UBC], ax

  ;// Get the screen position to add the graph to
  mov ax, [bp + DS_X_PARAMETER]
  mov [ds_x_pos], ax
  mov ax, [bp + DS_Y_PARAMETER]
  mov [ds_y_pos], ax

  ;// Find the width of the grid
  mov ax, [ds_d_UBC]
  sub ax, [ds_d_LBC]
  inc ax ; Include '0'
  mov [ds_d_grid_wide], ax

  mov ax, [ds_d_UBR]
  sub ax, [ds_d_LBR]
  inc ax  ;  Include '0'
  mul [ds_d_grid_wide]
  mov [ds_d_total], ax
  mov ax, DS_CELL_SIZE
  mul [ds_d_grid_wide]
  mov [ds_d_grid_cell_wide], ax
  
  ;// Put the grid to the screen
  ;// Set the counter variable
  mov [ds_count], 0
  mov [ds_x], 0
  mov [ds_y], 0

ds_loop:  
  mov ax, [ds_count]
  cmp ax, [ds_d_total]
  jb  ds_continue 
  jmp ds_loop_done  ; Relative jump fix
ds_continue:

  ;// Get the current Ship Data
  mov ax, [si]
  mov [ds_ship], ax
  ;// Get the current Hit Data
  add si, [ds_size]
  mov ax, [si]
  mov [ds_hit], ax

  ;// Check if anything needs to be drawn
  cmp [ds_ship], DS_NOTHING
  jne ds_do_put_sprite
  jmp ds_no_put_sprite
ds_do_put_sprite:

  ;// Put Ship Data
    mov ax, [ds_y]
    add ax, [ds_y_pos] ;// Offset from edge of screen
    push ax
    mov ax, [ds_x]
    add ax, [ds_x_pos] ;// Offset from edge of screen
    push ax

    ;// Figure out what to draw
    cmp [ds_ship], DS_PTBOAT_H
    jne ds_not_ptboat_h
    push offset ptboat_h
ds_not_ptboat_h:          
    cmp [ds_ship], DS_PTBOAT_V
    jne ds_not_ptboat_v
    push offset ptboat_v
ds_not_ptboat_v:
    cmp [ds_ship], DS_CRUISER_H
    jne ds_not_cruiser_h
    push offset cruiser_h
ds_not_cruiser_h:          
    cmp [ds_ship], DS_CRUISER_V
    jne ds_not_cruiser_v
    push offset cruiser_v
ds_not_cruiser_v:
    cmp [ds_ship], DS_BSHIP_H
    jne ds_not_bship_h
    push offset bship_h
ds_not_bship_h:          
    cmp [ds_ship], DS_BSHIP_V
    jne ds_not_bship_v
    push offset bship_v
ds_not_bship_v:
    cmp [ds_ship], DS_AC_H
    jne ds_not_ac_h
    push offset ac_h
ds_not_ac_h:
    cmp [ds_ship], DS_AC_V
    jne ds_not_ac_v
    push offset ac_v
ds_not_ac_v:
    cmp [ds_ship], DS_MISS
    jne ds_not_miss
    push offset miss
ds_not_miss:
    cmp [ds_ship], DS_WATER
    jne ds_not_water
    push offset water
ds_not_water:
    cmp [ds_ship], DS_HIT1
    jne ds_not_hit1
    push offset hit1
ds_not_hit1:  

    call put_sprite
    add sp, 6  

ds_no_put_sprite:

  ;// Put Hit Data
    ;// put_sprite(water, DS_DGRID_X + ds_x, DS_DGRID_Y + ds_y)
    mov ax, [ds_y]
    add ax, DS_TGRID_Y
    push ax
    mov ax, [ds_x]
    add ax, DS_TGRID_X
    push ax

    cmp [ds_hit], DS_WATER
    jne ds_not_water2
    push offset water
ds_not_water2:  
    cmp [ds_hit], DS_HIT1
    jne ds_not_hit2  
    push offset hit1
ds_not_hit2:    
    cmp [ds_hit], DS_MISS
    jne ds_not_miss2
    push offset miss
ds_not_miss2:    
    call put_sprite
    add sp, 6  

  ;// Increment all the variables
  inc [ds_count]
  add [ds_x], DS_CELL_SIZE
  add si, [ds_size]
  ;// Check if it is time to move down a row
  mov ax, [ds_x]
  cmp ax, [ds_d_grid_cell_wide]
  jae ds_wrap
  jmp ds_loop
ds_wrap:
  ;// The end of the line has been reached
  ;// Move y down 1 and reset x
  mov [ds_x], 0
  add [ds_y], DS_CELL_SIZE
  jmp ds_loop

ds_loop_done:

  ;// Pop Registers Off the Stack
  PopReg <si,dx,cx,bx,ax>
  pop bp;
  ret
endp draw_screen




;=====================================================================
; Random Number Subroutines Implementation by: R.F. Genovese, Ph.D.
;                    TEKNOMETRIKA
;                    L-15, S-123
;                    11160 Veirs Mill Road
;                    Wheaton, MD 20902
;=====================================================================
;we used tasm /ml /w
;---------------------------------------------------------------------
; void _seed_ran(void)
; unsigned int _get_ran(unsigned char bitsize)
;---------------------------------------------------------------------
        DATASEG
        PUBLIC  _r_seed
_r_seed DD      55aaaaaah               ;31 bit shift register
        CODESEG
;---------------------------------------------------------------------
; void _seed_ran(void)
; seeds the 31 bit shift register used by the pseudorandom generator
; from  BIOS ticks counter at 40h:6ch
;---------------------------------------------------------------------
PROC    _seed_ran
        mov     ax,40h                  ;BIOS segment
        mov     es,ax
        mov     ax,[es:6ch]             ;get ticks
        mov     [WORD LOW _r_seed],ax   ;into lsw shift register
; we rather cheaply toggle ax and stick it in the high word
        not     ax
        mov     [WORD HIGH _r_seed],ax  ;into msw shift register
        ret                             ;that's it
ENDP    _seed_ran
;---------------------------------------------------------------------
; unsigned int _get_ran(unsigned char bitsize)
; returns a pseudorandom number as an unsigned integer with
; bitsize number of bits.  Maximum value of bitsize is 16.  Larger
; values will be truncated to 16 bits (i.e. unsigned int size) as
; will a bitsize=0.
;---------------------------------------------------------------------
GR_BITSIZE  EQU   4
GR_RESULT   EQU   6
PROC    _get_ran
        push    bp
        mov     bp,sp
        push    cx
        push    bx
        push    ax
;first get and check bitsize from caller
        mov     cl,[bp + GR_BITSIZE]
        xor     ch,ch
        jcxz    @@truncate
        cmp     cx,10h
        jle     @@size_ok
@@truncate:
        mov     cx,10h                  ;force 16 bit size
@@size_ok:
        xor     ax,ax                   ;initalize return value
@@gen_num:
;generate bitsize pseudorandom bits into ax by the result of
;(bit three xor bit six) of the high byte of the shift register
;the result is shifted into the cf and then into ax.
        mov     bx,[WORD HIGH _r_seed]
        and     bh,048h                 ;08h or 40h is result=1 else 0
        cmp     bh,08h
        jz      xor1
        cmp     bh,40h
        jz      xor1
        clc                             ;xor result=0 so clear carry
        jmp     short shift_bits
xor1:
        stc                             ;xor result=1 so set carry
;rotate the shift register with the cf becoming the lsb.
shift_bits:
        rcl     [WORD LOW  _r_seed],1
        rcl     [WORD HIGH _r_seed],1
;rotate cf into our pseudorandom number in ax.
        rcl     ax,1
        loop    @@gen_num               ;get all of the bits
        mov     [bp + GR_RESULT], ax
        pop     cx
        pop     bx
        pop     ax
        pop     bp                      ;clean up and pass the
        ret                             ;number in ax to C
ENDP    _get_ran
;webedone

    END    start