rem prepare environment
set display mode 1024, 768, 32
draw to front : randomize timer()
sync on : sync rate 0 : color backdrop 0
 
rem show loading screen
cls : center text screen width() / 2, screen height() / 2, "LOADING" : sync
 
rem load dll for sound effects
load dll "kernel32.dll", 1
 
rem game settings
sound = 1
move_speed# = 0.3
game_time = 1
rate_of_fire = 100
ai_rate_of_fire = 800
max_enemies = 16
max_shots = 200
 
rem global variables
enemies_killed = 0
enemy_sprite_image = make_enemy_sprite()
dim enemy_x#(max_enemies)
dim enemy_y#(max_enemies)
dim enemy_fire_again(max_enemies)
dim enemy_life(max_enemies)
dim enemy_sprite(max_enemies)
player_health = 100
player_energy = 100
player_sprite = 0
player_sprite_image = make_player_sprite()
player_fire_again = 0
current_shots = 0
dim shot_sprite_image(1)
shot_sprite_image(0) = make_shot_sprite()
shot_sprite_image(1) = make_secondary_shot_sprite()
dim shot_angle#(max_shots)
dim shot_life(max_shots)
dim shot_from_sprite(max_shots)
dim shot_sprite(max_shots)
dim shot_type(max_shots)
pause_press_again = 0
paused = 0 : sound_count = 0
sound_press = 0
 
rem make and position enemies
for a = 1 to max_enemies
 enemy_x#(a) = rnd(screen width())
 enemy_y#(a) = rnd(300) - 400
 enemy_life(a) = 1
 enemy_fire_again(a) = rnd(2 * ai_rate_of_fire)
 enemy_sprite(a) = free_sprite()
 sprite enemy_sprite(a), enemy_x#(a), enemy_y#(a), enemy_sprite_image
next a
 
rem positon player sprite
player_sprite = free_sprite()
sprite player_sprite, player_x#, player_y#, player_sprite_image
player_x# = (screen width() / 2) - (sprite width(player_sprite) / 2)
player_y# = screen height() - (screen height() / 4)
sprite player_sprite, player_x#, player_y#, player_sprite_image
 
rem display instructions and hide mouse
cls : hide all sprites : ink RGB(255, 255, 255), RGB(255, 255, 255)
text 0, 0, "Use the arrowkeys to fly your ship and spacebar to shoot"
text 0, 10, "the main weapon, alt key to shoot secondary power shot."
text 0, 20, "You can pause the game by pressing the P key and toggle"
text 0, 30, "sound effects on / off with the e key."
text 0, 40, "Alternate controls are the WASD keys and the control key"
text 0, 50, "to shoot main weapon, alt for secondary. The Alternate"
text 0, 60, "controls are recommended (they are faster and more sensitive)."
text 0, 80, "Press any key to continue."
sync : wait key : hide mouse : show all sprites
 
rem record game start time
game_time = 0 : loop_count = 0
 
rem draw hud at bottom of screen
rem show game time, health and enemies killed
text 0, screen height() - 16, "Game Time: " + str$(game_time / 1000) + " seconds"
text 200, screen height() - 16, "Player Health: " + str$(player_health)
text 360, screen height() - 16, "Enemies Killed: " + str$(enemies_killed)
text 550, screen height() - 16, "Sound: "
text 600, screen height() - 16, "ON"
center text screen width() / 2, screen height() / 2, "START"
 
rem play start melody
sync : play_start_melody()
 
rem main program loop
do
 
 rem used in counting the seconds
 loop_count = timer()
 
 rem pause controls
 if pause_press_again > 0 then pause_press_again = pause_press_again - 1
 if keystate(25) = 1 and pause_press_again = 0
  if paused = 0
   paused = 1
  else
   paused = 0
  endif
  pause_press_again = 200
 endif
 
 rem only execute main game loop if game isn't paused
 if paused = 0
 
 rem control ship with arrowkeys
 if (keystate(205) = 1 or keystate(32) = 1) then player_x# = player_x# + (move_speed# * 1.5)
 if (keystate(203) = 1 or keystate(30) = 1) then player_x# = player_x# - (move_speed# * 1.5)
 if (keystate(200) = 1 or keystate(17) = 1) then player_y# = player_y# - (move_speed# * 1.5)
 if (keystate(208) = 1 or keystate(31) = 1) then player_y# = player_y# + (move_speed# * 1.5)
 
 rem make sure player sprite is still on the screen
 if player_x# < 0 then player_x# = 0
 if player_x# > (screen width() - sprite width(player_sprite)) then player_x# = (screen width() - sprite width(player_sprite))
 if player_y# < 100 then player_y# = 100
 if player_y# > (screen height() - sprite height(player_sprite) - 18) then player_y# = (screen height() - sprite height(player_sprite) - 18)
 
 rem toggle sound effects
 if sound_press > 0 then sound_press = sound_press - 1
 if keystate(18) = 1 and sound_press = 0 `e
  if sound = 0
   sound = 1
  else
   sound = 0
  endif
  sound_press = 200
 endif
 
 rem update player sprite
 sprite player_sprite, player_x#, player_y#, player_sprite_image
 
 rem fire using the spacebar or control key main weapon
 if player_fire_again > 0 then player_fire_again = player_fire_again - 1
 if (keystate(57) = 1 or controlkey() = 1) and player_fire_again = 0
  rem fire one shot if max shots hasn't been achieved
  if current_shots < max_shots
   current_shots = current_shots + 1
   a = 1
   while shot_life(a) > 0
    a = a + 1
   endwhile
   shot_life(a) = 1
   shot_angle#(a) = 0
   shot_from_sprite(a) = player_sprite
   shot_sprite(a) = free_sprite()
   shot_type(a) = 0
   sprite shot_sprite(a), player_x# + 13, player_y# - 10, shot_sprite_image(shot_type(a))
   rotate sprite shot_sprite(a), shot_angle#(a)
   move sprite shot_sprite(a), move_speed#
   player_fire_again = rate_of_fire
   if sound = 1 then sound_count = play_shoot_sound(sound_count)
  endif
 endif
 
 rem fire using the alternate key the secondary weapon
 if (keystate(56) = 1 or keystate(184) = 1) and player_fire_again = 0
  rem fire one shot if max shots hasn't been achieved
  if current_shots < max_shots
   current_shots = current_shots + 1
   a = 1
   while shot_life(a) > 0
    a = a + 1
   endwhile
   shot_life(a) = 1
   shot_angle#(a) = 0
   shot_from_sprite(a) = player_sprite
   shot_sprite(a) = free_sprite()
   shot_type(a) = 1
   sprite shot_sprite(a), player_x# + 13, player_y# - 10, shot_sprite_image(shot_type(a))
   rotate sprite shot_sprite(a), shot_angle#(a)
   move sprite shot_sprite(a), move_speed#
   player_fire_again = 7 * rate_of_fire
   if sound = 1 then sound_count = play_bomb_sound(sound_count)
  endif
 endif
 
 rem update enemy sprites / do enemy ai
 for a = 1 to max_enemies
  if enemy_life(a) > 0
   if enemy_fire_again(a) > 0 then enemy_fire_again(a) = enemy_fire_again(a) - 1
   enemy_y#(a) = enemy_y#(a) + (move_speed# / 4)
   if enemy_y#(a) >= (screen height() - 18 - sprite height(enemy_sprite(a)))
    enemy_y#(a) = -10
    enemy_x#(a) = rnd(screen width())
   endif
   if enemy_x#(a) > (screen width() - sprite width(enemy_sprite(a))) then enemy_x#(a) = 0
   if enemy_x#(a) < 0 then enemy_x#(a) = (screen width() - sprite width(enemy_sprite(a)))
   rem check for collision with player
   if sprite collision(enemy_sprite(a), player_sprite) > 0
    player_health = player_health - 5
    enemy_x#(a) = rnd(screen width())
    enemy_y#(a) = rnd(300) - 400
    enemy_fire_again(a) = 0
    if sound = 1 then sound_count = play_explode_sound(sound_count)
   endif
   rem fire at player if on screen
   if enemy_fire_again(a) = 0 and enemy_y#(a) > 0
    rem fire a shot downward if the player is below and max_shots hasnt been achieved
    if current_shots < max_shots  and player_y# > enemy_y#(a)
     current_shots = current_shots + 1
     b = 1
     while shot_life(b) > 0
      b = b + 1
     endwhile
     shot_life(b) = 1
     shot_angle#(b) = 180
     shot_from_sprite(b) = enemy_sprite(a)
     shot_sprite(b) = free_sprite()
     if game_time > 60000
      shot_type(b) = 1
      enemy_fire_again(a) = 2 * ai_rate_of_fire
      if sound = 1 then sound_count = play_bomb_sound(sound_count)
     else
      shot_type(b) = 0
      enemy_fire_again(a) = ai_rate_of_fire
      if sound = 1 then sound_count = play_shoot_sound(sound_count)
     endif
     sprite shot_sprite(b), enemy_x#(a) + (sprite width(enemy_sprite(a)) / 2), enemy_y#(a) + 12, shot_sprite_image(shot_type(b))
     rotate sprite shot_sprite(b), shot_angle#(b)
     move sprite shot_sprite(b), move_speed#
    endif
   endif
   sprite enemy_sprite(a), enemy_x#(a), enemy_y#(a), enemy_sprite_image
  endif
 next a
 
 rem update shot sprites
 for a = 1 to max_shots
  if shot_life(a) > 0
   rem move the bullet
   move sprite shot_sprite(a), move_speed# * 1.5
   rem check to see if it's still on screen
   if sprite x(shot_sprite(a)) < 0 or sprite x(shot_sprite(a)) > screen width() or sprite y(shot_sprite(a)) < 0 or sprite y(shot_sprite(a)) > screen height()
    shot_life(a) = 0
   endif
   rem check for collision
   b = sprite collision(shot_sprite(a), 0)
   if b > 0 and shot_life(a) > 0
    rem the bullet hit something, check to make-sure it wasn't self-injury
    if shot_from_sprite(a) <> b
     rem it's valid, check to see if the player has been hit
     if b = player_sprite
      rem the player has been hit by an enemy,
      rem subtract health
      if shot_type(a) = 0
       player_health = player_health - 1
      else
       player_health = player_health - 8
      endif
      shot_life(a) = 0
     else
      if shot_from_sprite(a) = player_sprite
       rem an enemy has been hit by the player,
       rem find out which one and kill it
       for c = 1 to max_enemies
        if enemy_sprite(c) = b
         rem enemy found, deal with him and exit the loop
         if shot_type(a) = 0 then shot_life(a) = 0
         enemy_x#(c) = rnd(screen width())
         enemy_y#(c) = rnd(300) - 400
         enemy_fire_again(c) = 0
         enemies_killed = enemies_killed + 1
         if sound = 1 then sound_count = play_explode_sound(sound_count)
        endif
       next c
      endif
     endif
    endif
   endif
   if shot_life(a) = 0
    delete sprite shot_sprite(a)
    current_shots = current_shots - 1
   endif
  endif
 next a
 
 rem set the text color to white and the background to black
 ink RGB(255, 255, 255), 0
 
 rem check for end of game (player_health <= 0)
 if player_health <= 0
  rem end game
  cls : center text screen width() / 2, screen height() / 2, "END GAME"
  center text screen width() / 2, (screen height() / 2) + 20, "PLEASE WAIT FOR YOUR STATS"
  sync
  rem play death melody
  play_death_melody()
  wait 3000 : hide all sprites : cls
  text 0, 0, "Your Statistics: "
  text 0, 20, "Game Time: " + str$(game_time / 1000) + " seconds"
  text 0, 40, "Enemies Killed: " + str$(enemies_killed)
  text 0, 60, "Press any key to exit the game."
  sync : wait key : end
 endif
 
 rem end of pause ifthen statement
 endif
 
 rem draw hud at bottom of screen
 rem show game time, health and enemies killed
 text 0, screen height() - 16, "Game Time: " + str$(game_time / 1000) + " seconds"
 text 200, screen height() - 16, "Player Health: " + str$(player_health)
 text 360, screen height() - 16, "Enemies Killed: " + str$(enemies_killed)
 text 550, screen height() - 16, "Sound: "
 if sound = 1
  text 600, screen height() - 16, "ON"
 else
  text 600, screen height() - 16, "OFF"
 endif
 
 rem if game is paused, draw pause text
 if paused = 1 then center text screen width() / 2, screen height() / 2, "PAUSED"
 if paused = 0 then game_time = game_time + (timer() - loop_count)
 
 rem refresh the screen
 sync
 
loop
 
rem generic functions
function free_sprite()
 retval = 1
 while sprite exist(retval) = 1
  retval = retval + 1
 endwhile
endfunction retval
 
function free_image()
 retval = 1
 while image exist(retval) = 1
  retval = retval + 1
 endwhile
endfunction retval
 
rem sound functions
function beep(frequency, duration)
 call dll 1, "Beep", frequency, duration
endfunction
 
function play_explode_sound(count)
 if timer() >= count
  beep(100, 10) : delay = timer() + 10
 endif
endfunction delay
 
function play_shoot_sound(count)
 if timer() >= count
  beep(350, 2) : delay = timer() + 2
 endif
endfunction delay
 
function play_bomb_sound(count)
 if timer() >= count
  beep(280, 2) : delay = timer() + 2
 endif
endfunction delay
 
function play_start_melody()
 for f = 300 to 400 step 5
  beep(f, 5) : wait 5
 next f
endfunction
 
function play_death_melody()
 for f = 0 to 100 step 5
  rf = 400 - f
  beep(rf, 5) : wait 5
 next f
endfunction
 
rem sprite functions
function make_player_sprite()
 create bitmap 1, 32, 35
 ink RGB(0, 0, 255), 0
 text 0, 0, "/--\"
 text 0, 10, "|  |"
 text 0, 20, "\--/"
 image_number = free_image()
 get image image_number, 0, 0, 32, 35
 delete bitmap 1
 set current bitmap 0
endfunction image_number
 
function make_enemy_sprite()
 create bitmap 1, 16, 16
 ink RGB(255, 0, 0), 0
 text 0, 0, "[]"
 image_number = free_image()
 get image image_number, 0, 0, 16, 16
 delete bitmap 1
 set current bitmap 0
endfunction image_number
 
function make_shot_sprite()
 create bitmap 1, 10, 10
 ink RGB(255, 255, 255), 0
 text 0, 0, "*"
 image_number = free_image()
 get image image_number, 0, 4, 8, 10
 delete bitmap 1
 set current bitmap 0
endfunction image_number
 
function make_secondary_shot_sprite()
 create bitmap 1, 14, 14
 ink RGB(255, 255, 0), 0
 text 0, 0, "@"
 image_number = free_image()
 get image image_number, 0, 2, 9, 12
 delete bitmap 1
 set current bitmap 0
endfunction image_number