Here is GUARDIAN V1.0, the first version of a playable space shooter game...
Note 1: I coded it to adjust to your desktop size. It works well on mine, but let me know if it doesn't seem to be a good fit on yours. You can always press Alt + Enter, to run it full screen, too.
Note 2: Alien's can run off the screen, and come back. What I need to work on now is a method so the last one doesn't run off the screen for too long. Normally it's just a few seconds, but I have had a handful of time it has taken a few minutes, and that's way too long. But that, and a little more A.I. is for another day... after my egg facial wears off from another discussion thread.
Pete
Don't forget, download the soud effects file below, and save it in the same folder.
ASCII Invaders Sound.7z (Size: 1.45 MB / Downloads: 85)
Code: (Select All)
DEFINT H-K
$RESIZE:ON
_RESIZE OFF
RANDOMIZE TIMER
' Note: timer is not adjusted for stroke of midnight event, so don't stay up late playing this.
REM Main
f1 = 22 ' Sets font size to 22 and calculates the max screen height and width for your desktop.
h = (_DESKTOPHEIGHT - 60) \ f1
w = _DESKTOPWIDTH \ (f1 / 1.66)
WIDTH w, h
_SCREENMOVE 0, 0
fontpath$ = ENVIRON$("SYSTEMROOT") + "\fonts\lucon.ttf" 'Find Windows Folder Path.
font& = _LOADFONT(fontpath$, f1, "monospace")
_FONT font&
_DELAY .25
_RESIZE ON , _SMOOTH ' Allows resizing. Note: this is for slight adjustments. As of this version there is no compensatory function to change the font size during screen size changes.
TYPE gen_var
intro AS INTEGER ' Runs a protion of the alien subroutine as part of the intro.
nol AS INTEGER ' Number of game levels.
level AS INTEGER ' Current game level.
level_up AS INTEGER ' Routes code to next game level.
top AS INTEGER ' Top boundary. (Changeable).
bottom AS INTEGER ' Bottom boundary. (Changeable).
left AS INTEGER ' Left boundary. (Changeable).
right AS INTEGER ' Right boundary. (Changeable).
kb_access AS INTEGER ' Routes code to either Guardian/Alien or general keyboard routine. -1 Guardian/Alien, 0 keyboard.
mouse_or_key_move AS INTEGER
mouse_get_screen AS INTEGER
play AS INTEGER
snd1 AS LONG ' Explosion sound effect.
snd2 AS LONG ' Explosion sound effect.
END TYPE
DIM SHARED v AS gen_var
TYPE guardian
num AS INTEGER ' Number of Guardians aka lives.
diry AS INTEGER ' Guardian row move. +1, 0, -1.
dirx AS INTEGER ' Guardian column move. +2, 0, -2. Equals vertical pixel movement. 16x8.
y AS INTEGER ' Guardian coordinates row.
x AS INTEGER ' Guardian coordinates column.
thrusters AS INTEGER ' Guardian speed. (User Determined).
m_max AS INTEGER ' Restricts # of missiles fired in one direction.
m_status AS INTEGER ' Missile status. -1 when fired, 1 while moving.
m_fired AS INTEGER ' The number of missile deployed and still active.
m_n AS INTEGER ' FOR/NEXT counter variable shared by other routines to index through the number of missiles fired in a specific direction.
m_d AS INTEGER ' Missile direction. (1-8).
m_y AS INTEGER ' Missile row advancement increment: +1, 0, -1 Note: Missile row and column coordinates are defined in arrays.
m_x AS INTEGER ' Missile column advancement increment: +2, 0, -2. Equals vertical pixel movement. 16x8.
m_asc AS INTEGER ' ASCII character representing a fired missile.
m_launcher AS STRING
icon AS STRING ' Guardian comm icon. For this edition, it is the same as the flagship: "*"
flagship AS STRING ' Guardian ascii character.
END TYPE
DIM SHARED g AS guardian
TYPE alien
max AS INTEGER ' Maximum # of alien ships on screen.
count AS INTEGER ' Number of alien ships. (Counter).
itr AS INTEGER ' Iteration array number to cycle through the active alien ships. (Counter).
cycle_delay AS SINGLE ' Timer cycle controls how fast alien ships move.
ship AS STRING ' Alien ship ASCII design.
END TYPE
DIM SHARED a AS alien
DO
GOSUB set_arrays
SELECT CASE v.play
CASE 0
CALL set_up
CALL comm
CALL intro
v.intro = 0: a.max = 0
GOSUB set_arrays
v.level = -1: CALL game_level: v.level_up = 0 ' This variable is canceled here so game will play instead of go another level up.
CASE 1
CALL set_up
CALL comm
END SELECT
g.y = (v.bottom - v.top) \ 2 + v.top: g.x = (v.right - v.left + 1) \ 2 + v.left ' Set initial column and row for Guardian craft.
CALL game
GOSUB zero_variables
LOOP
set_arrays:
ii = 15 ' Default max setting for number of alien ships used here to initially dim arrays.
g.m_max = 8 ' * missiles max per direction.
REDIM SHARED a_y(ii), a_x(ii), a_mask_y(ii), a_mask_x(ii), a_inertia(ii) ' Alien movement.
REDIM SHARED a_ran(ii), a_olda_ran(ii), a_y_loc(ii), a_x_loc(ii), a_offscrn(ii) ' Alien movement.
REDIM SHARED m_n(g.m_max), m_x(g.m_max, 8), m_y(g.m_max, 8) ' Guardian missiles.
' Array descriptions and actions.
' a_y() , a_x() Alien ship positions rows and columns.
' a_mask_y(), a_mask_x() Alien ship last position. Masked on next move.
' a_inertia(ii) Number of moves in one direction selected by random for an alien ship.
' a_ran(ii), a_olda_ran(ii) Determines the direction in which the inertia will travel and the prior direction is kept to disallow the same direction twice.
' a_y_loc(ii), a_x_loc(ii) The row and column coordinates of the aliens ships.
' m_n(g.m_max), m_x(g.m_max, 8), m_y(g.m_max, 8) Missile number and Missile index 1 to g.m_max for position. 8 is the fixed number of 8 different directions.
RETURN
zero_variables:
' Zero variables.
g.diry = 0: g.dirx = 0: g.m_status = 0: g.m_fired = 0: g.m_d = 0: g.m_y = 0: g.m_x = 0
a.count = 0: a.itr = 0: a.cycle_delay = 0: v.level_up = 0: v.mouse_or_key_move = 0: g.m_launcher = ""
RETURN
skipintro:
v.intro = 999
BEEP: BEEP
VIEW PRINT v.top TO v.bottom
CLS 2
VIEW PRINT
_DELAY .5
RETURN
' Error handler.
offscreen: ' Prevents error if blast particles row and column are off-screen. Effect is a partial blast on side of screen.
IF ERR = 5 THEN er = -1: RESUME NEXT
PRINT "Opps, unexpected error"; ERR
END
SUB intro
v.mouse_get_screen = 1 ' Allows skip intro by mouse selection.
LOCATE _HEIGHT, _WIDTH - 15
PRINT "[S]kip Intro"; ' Option to skip the intro using the "S" key with ONKEY statement.
KEY 15, CHR$(0) + CHR$(31) 'scancode for S
ON KEY(15) GOSUB skipintro
KEY(15) ON 'turn ON [S]kip intro event trapping.
j = (v.bottom - v.top) \ 2 + v.top
k = (v.right - v.left) \ 2 + v.left
z1 = TIMER
DO
CALL mouse(mouse_event1, mouse_event2)
IF v.intro = 999 THEN KEY(15) OFF: EXIT SUB
LOOP UNTIL ABS(z1 - TIMER) > .33
SOUND 1000, .3
msg$ = " GUARDIAN "
LOCATE j, k - LEN(msg$) \ 2: COLOR 14: PRINT msg$;: COLOR 7
LOCATE , k
z1 = TIMER
DO
CALL mouse(mouse_event1, mouse_event2)
IF v.intro = 999 THEN KEY(15) OFF: EXIT SUB
LOOP UNTIL ABS(z1 - TIMER) > .66
msg$ = SPACE$(LEN(msg$))
LOCATE j, k - LEN(msg$) \ 2: COLOR 7: PRINT msg$;
LOCATE j, k
IF v.intro = 999 THEN KEY(15) OFF: EXIT SUB ELSE CALL explosion
LOCATE j, k: COLOR 15 + 16: PRINT g.flagship;
z1 = TIMER
DO
CALL mouse(mouse_event1, mouse_event2)
IF v.intro = 999 THEN KEY(15) OFF: EXIT SUB
LOOP UNTIL ABS(z1 - TIMER) > .75
v.intro = -1: a.max = 10
FOR i = 1 TO 90
CALL mouse(mouse_event1, mouse_event2)
IF v.intro = 999 THEN KEY(15) OFF: EXIT SUB
SOUND 900, .05
CALL alien_move
LOCATE j, k: COLOR 15: PRINT g.flagship;: COLOR 7
_DELAY .07
NEXT
z1 = TIMER
DO
CALL mouse(mouse_event1, mouse_event2)
IF v.intro = 999 THEN KEY(15) OFF: EXIT SUB
LOOP UNTIL ABS(z1 - TIMER) > 1
LOCATE j, k: PRINT " ";
CALL guardian_abduction
a.max = 0
z1 = TIMER
DO
CALL mouse(mouse_event1, mouse_event2)
IF v.intro = 999 THEN KEY(15) OFF: EXIT SUB
LOOP UNTIL ABS(z1 - TIMER) > .5
KEY(15) OFF
LOCATE v.bottom, _WIDTH - 20: PRINT SPACE$(20);
' Playing Instructions.
REDIM msg$(13)
msg$(1) = CHR$(249) + " " + "Look towards the top of your screen for Guardian ship status."
msg$(2) = CHR$(249) + " " + "Hold arrow keys up/dn/lt/rt or in combination to move diagonally."
msg$(3) = CHR$(249) + " " + "Missiles can be fired simultaneously in 8 different directions."
msg$(4) = CHR$(249) + " " + "Press Tab to fire 1-8 missiles in the direction of movement."
msg$(5) = CHR$(249) + " " + "Press Rt Ctrl to increase thrust, or Rt Alt to reduce thrust."
msg$(6) = ""
msg$(7) = CHR$(249) + " " + "Mouse alternative: "
msg$(8) = CHR$(249) + " " + "Hold right mouse button to move toward mouse pointer."
msg$(9) = CHR$(249) + " " + "Click left mouse button to fire 1-8 missiles in direction of mouse pointer."
msg$(10) = CHR$(249) + " " + "Mouse wheel up for more thrust, wheel down for less."
msg$(11) = CHR$(249) + " " + "Note: Tab and left mouse button cannot be used simultaneously."
msg$(12) = ""
msg$(13) = CHR$(249) + " " + "If you come in contact with an alien ship, your ship and crew get abducted."
j = 0
FOR i = 1 TO UBOUND(msg$)
IF LEN(msg$(i)) > j THEN j = LEN(msg$(i))
NEXT
i = ((v.right - v.left) - j) \ 2
t_mrgn = 6: b_mrgn = _HEIGHT - 4: l_mrgn = i + 1: r_mrgn = v.right - i
LOCATE t_mrgn - 2, l_mrgn - 2: PRINT STRING$(r_mrgn - l_mrgn + 4, CHR$(196));
LOCATE b_mrgn + 2, l_mrgn - 2: PRINT STRING$(r_mrgn - l_mrgn + 4, CHR$(196));
FOR i = 1 TO b_mrgn - t_mrgn + 3
LOCATE t_mrgn - 2 + i, l_mrgn - 2
PRINT CHR$(179);
LOCATE , r_mrgn + 2: PRINT CHR$(179);
NEXT
LOCATE t_mrgn - 2, l_mrgn - 2: PRINT CHR$(218);
LOCATE t_mrgn - 2, r_mrgn + 2: PRINT CHR$(191);
LOCATE b_mrgn + 2, l_mrgn - 2: PRINT CHR$(192);
LOCATE b_mrgn + 2, r_mrgn + 2: PRINT CHR$(217);
msg$ = "<Intro>"
LOCATE t_mrgn - 2, l_mrgn + (r_mrgn - l_mrgn) \ 2 - LEN(msg$) \ 2
PRINT msg$;
msg$ = "You are the Captain of the Guardian, an elite battle cruiser commissioned to protect our planet against alien invaders. You have 3 lives. Every time you are abducted by an alien ship, you lose a life. If you survive, and wipe out all 3 flights of alien attacks, your mission is completed. You saved Earth!"
j = r_mrgn - l_mrgn
LOCATE t_mrgn, l_mrgn
msg$ = RTRIM$(msg$) + " " ' Simple word parser routine.--------
DO
x$ = MID$(msg$, 1, j)
x$ = MID$(x$, 1, _INSTRREV(x$, " ") - 1)
msg$ = LTRIM$(MID$(msg$, LEN(x$) + 1))
LOCATE , l_mrgn: PRINT x$
LOOP UNTIL msg$ = "" '-----------------------------------------
PRINT
FOR i = 1 TO UBOUND(msg$)
LOCATE , l_mrgn
IF LEN(msg$(i)) THEN PRINT msg$(i) ELSE PRINT
NEXT
PRINT: IF CSRLIN < b_mrgn - 1 THEN PRINT
msg$ = "Good luck, Captain! Press any key to begin."
LOCATE , l_mrgn + (r_mrgn - l_mrgn) \ 2 - LEN(msg$) \ 2
PRINT msg$;
DO
_LIMIT 10
WHILE _MOUSEINPUT: WEND
IF _MOUSEBUTTON(1) THEN SOUND 1000, .1: EXIT DO
ky$ = INKEY$
IF ky$ = CHR$(27) THEN SYSTEM
IF LEN(ky$) THEN EXIT DO
LOOP
VIEW PRINT v.top TO v.bottom: CLS 2: VIEW PRINT
END SUB
SUB set_up
v.top = 3: v.bottom = _HEIGHT: v.left = 1: v.right = _WIDTH ' Boundaries.
g.flagship = CHR$(15)
a.ship = "-<>-"
g.num = 3 ' 3 Guardian (lives) to start.
g.thrusters = 10 ' Shows 1/2 thrust at start up on comm.
g.icon = g.flagship
g.m_asc = 250: g.diry = -1: ' Initiate missile ASCII character. g.diry = -1 initiates fire upwards if unmoved.
IF _FILEEXISTS("Thunder1.ogg") AND _FILEEXISTS("Thunder1.ogg") AND _FILEEXISTS("Thunder1.ogg") AND _FILEEXISTS("Thunder1.ogg") THEN ' Sound effects provided by TheBOB, Bob Seguin, from The QBasic Forum.
v.snd1 = _SNDOPEN("Thunder1.ogg", "SYNC")
v.snd2 = _SNDOPEN("Thunder7.ogg", "SYNC")
END IF
v.play = -1 ' Skip into on replay.
LOCATE 2, 1: PRINT STRING$(_WIDTH, CHR$(196));
_KEYCLEAR ' Clear any previous key presses in buffer.
END SUB
SUB game
STATIC mouse_event1, mouse_event2
REM Set mouse_event2 = 0 here to produce constant motion with directional changes.
'Press single or arrow key combo to move. Rt Ctrl = faster / Rt Alt = slower. Tab to fire missles.
g.thrusters = 10 ' Guardian movement delay. (1 to 20). Rt Ctrl = faster / Rt Alt = slower.
SELECT CASE v.level
CASE 1: a.max = 5 ' Sets number of space ships and initiates attack.
CASE 2: a.max = 10
CASE 3: a.max = 15
END SELECT
a.count = a.max
IF a.max < 6 THEN
a.cycle_delay = .005
ELSEIF a.max < 11 THEN a.cycle_delay = .003
ELSE a.cycle_delay = .001
END IF
CALL comm
DO
_LIMIT 60 ' Display at 60 frames per second.
CALL comm
IF g.m_status THEN CALL Guardian_missiles ' g.m_status determines Guardian or alien turn. 1 = Guardian, -1 = alien.
IF a.count = 0 THEN EXIT SUB ' Moving on to next level.
CALL alien_move
' To change thrusters only when guardian moves, remove the timer and move this routine to: IF v.kb_access = -1 THEN
IF ABS(z3 - TIMER) > .1 THEN ' z3 is a keypress delay timer for Guardian thrusters. Check every .1 seconds for a speed change.
IF _KEYDOWN(100307) AND g.thrusters < 20 THEN g.thrusters = g.thrusters + 1 ' Rt Ctrl key. Slows down Guardian ship down.
IF _KEYDOWN(100305) AND g.thrusters > 0 THEN g.thrusters = g.thrusters - 1 ' Rt Alt key. Speeds up Guardian ship.
z3 = TIMER
END IF
IF ABS(z2 - TIMER) > g.thrusters / 100 THEN ' z2 is delay for Guardian movement cycle. Note: Division needed because computer math can't add decimal numbers correctly.
IF v.kb_access = 0 THEN
IF _KEYDOWN(18432) OR _KEYDOWN(19200) OR _KEYDOWN(19712) OR _KEYDOWN(20480) OR mouse_event2 = -1 THEN ' Arrow keys.
v.kb_access = -1 ' Routes code to guardian move. When zero, Guardian move gets bypassed.
z1 = TIMER ' Delay timer for key lag effect in Guardian move routine.
END IF
END IF
END IF
IF v.kb_access = -1 THEN ' Guardian move routine.-----------------------------------------------------------------------------------------------------------------------------
IF ABS(z1 - TIMER) > .05 THEN ' z1 is a key lag time delay to allow guardian to press two keys together within a reasonable amount of time.
DO ' Faux loop added to throw out illegal key combos like up + down.
IF mouse_event2 = 0 THEN ' Bypass this keyboard routine if the right mouse button is in use.
IF mouse_event1 = 0 THEN g.m_x = 0: g.m_y = 0 ' Variables to control length and direction of Guardian movement. Must be reset to zero each cycle so diagonal moves are possible.
IF g.m_x = 0 AND g.m_y = 0 THEN
' Eliminate illegal combos.
IF _KEYDOWN(18432) AND _KEYDOWN(20480) THEN v.kb_access = 0: z2 = TIMER: EXIT DO ' Up + down
IF _KEYDOWN(19712) AND _KEYDOWN(19200) THEN v.kb_access = 0: z2 = TIMER: EXIT DO ' Left + right.
' IF female THEN STOP AND GET #1, directions. Keys that control movement.
IF _KEYDOWN(18432) THEN ' Up-arrow.
g.m_y = -1 ' To move 1-row up.
END IF
IF _KEYDOWN(19712) THEN ' Right-arrow.
g.m_x = 1 ' To move 1-column right.
END IF
IF _KEYDOWN(20480) THEN ' Down-arrow.
g.m_y = 1 ' To move 1-row down.
END IF
IF _KEYDOWN(19200) THEN ' Left-arrow.
g.m_x = -1 ' To move 1-column left.
END IF
IF g.m_x AND g.m_y THEN ' Double key hold. Routine to cancel keys when double hold is lifted. Compensates for both keys not being released at exactly the same time.
combo = -1 ' Double key hold in progress.
ELSE
IF combo THEN combo = 0: v.kb_access = 0: EXIT DO ' Double key hold was just removed, so skip Guardian move and exit.
END IF
END IF
END IF
' Move Guardian. *****************************************************************************************************
IF g.y + g.m_y > v.top AND g.y + g.m_y <= v.bottom AND g.x + 2 * g.m_x > v.left AND g.x + 2 * g.m_x < v.right THEN
LOCATE g.y, g.x
PRINT " ";
g.y = g.y + g.m_y: g.x = g.x + 2 * g.m_x
IF SCREEN(g.y, g.x) <> 32 AND SCREEN(g.y, g.x) <> g.m_asc THEN ' Guardian abducted by bad move. Ignore if you run into your own missile.
CALL guardian_abduction: EXIT SUB
ELSE
LOCATE g.y, g.x
PRINT g.flagship;
END IF
ELSE
BEEP ' Hit boundary.
END IF
v.kb_access = 0 ' Guardian move completed. Returns control to general keyboard next cycle.
z2 = TIMER ' Timer for moving. Lag regulated by "g.thrusters" variable.
EXIT DO ' ************************************************************************************************************
LOOP
END IF '
ELSE ' If you want additional key routines, put them here...------------------------------------------------------------------------------------------------------------------
CALL mouse(mouse_event1, mouse_event2)
ky$ = INKEY$
IF mouse_event1 = -1 THEN ky$ = CHR$(9)
IF LEN(ky$) = 1 THEN ' For demo, exclude keys that start with chr$(0). Note without this arrow keys would still register here.
SELECT CASE ky$
CASE CHR$(9) ' Tab key. Bug note: Space bar will not register with arrow up + arrow v.left.
IF ABS(z8 - TIMER) > .25 THEN
SELECT CASE g.m_launcher
CASE ""
IF mouse_event1 = -1 THEN g.m_launcher = "mouse" ELSE g.m_launcher = "keyboard" ' Initiate.
CASE "keyboard"
IF mouse_event1 = -1 THEN
IF g.m_fired = 0 THEN
g.m_launcher = "mouse" ' Switch.
ELSE
ky$ = ""
END IF
END IF
CASE "mouse"
IF mouse_event1 = 0 THEN ' Tab key was used.
IF g.m_fired = 0 THEN
g.m_launcher = "keyboard" ' Switch
ELSE
ky$ = ""
END IF
END IF
END SELECT
IF LEN(ky$) THEN
g.m_status = -1 ' -1 indicates missile just fired.
IF mouse_event1 = 0 THEN v.mouse_or_key_move = 0: ' Key pressed missile fire clears any previous mouse button missile fire.
END IF
mouse_event1 = 0 ' Completes left mouse missile firing cycle.
z8 = TIMER ' Missile firing delay reset.
END IF
CASE CHR$(27) ' Esc
_DELAY 1: SYSTEM
CASE ELSE
REM PRINT "You pressed key: "; ky$;
END SELECT
END IF
END IF '----------------------------------------------------------------------------------------------------------------------------------------------------------------------
LOOP
END SUB
SUB comm
STATIC middle% ' Local variable.
IF middle% = 0 THEN middle% = v.left + (v.right - v.left) \ 2
msg$ = " Thrusters = " + LTRIM$(STR$(5 * (20 - g.thrusters))) + "% Fired = " + LTRIM$(STR$(g.m_fired)) + " Alien ships = " + LTRIM$(STR$(a.count)) + " Level = " + LTRIM$(STR$(v.level)) + " Guardians: "
LOCATE 1, v.left + middle% - ((LEN(msg$) + 8) \ 2): PRINT msg$;
SELECT CASE g.num
CASE 3
PRINT g.icon; " "; g.icon; " "; g.icon;
CASE 2
PRINT g.icon; " "; g.icon; " ";: COLOR 8, 0: PRINT g.icon;: COLOR 7, 0
CASE 1
PRINT g.icon; " ";: COLOR 8, 0: PRINT g.icon; " "; g.icon;: COLOR 7, 0
CASE 0
COLOR 8, 0: PRINT g.icon; " "; g.icon; " "; g.icon; " ";: COLOR 7, 0
END SELECT
PRINT " "; ' Cut off any former printing caused by length changes in comm report like when numbers change from double to single digits.
END SUB
SUB Guardian_missiles
STATIC z4
DIM direction AS INTEGER ' 8 possible directions. local variable.
IF ABS(z4 - TIMER) > .03 THEN
z4 = TIMER
IF v.mouse_or_key_move = 0 THEN ' GAME OPTION: Remove this first IF/THEN to make it necessary to move Guardian in a direction to fire in that direction.
IF g.m_y <> 0 OR g.m_x <> 0 THEN g.diry = g.m_y: g.dirx = g.m_x ' Initiate by setting row and column missile direction to last column and row movement direction of Guardian location.
END IF
IF g.m_status = -1 THEN
IF g.diry = -1 AND g.dirx = 0 THEN
direction = 1
ELSEIF g.diry = -1 AND g.dirx = 1 THEN
direction = 2
ELSEIF g.diry = 0 AND g.dirx = 1 THEN
direction = 3
ELSEIF g.diry = 1 AND g.dirx = 1 THEN
direction = 4
ELSEIF g.diry = 1 AND g.dirx = 0 THEN
direction = 5
ELSEIF g.diry = 1 AND g.dirx = -1 THEN
direction = 6
ELSEIF g.diry = 0 AND g.dirx = -1 THEN
direction = 7
ELSEIF g.diry = -1 AND g.dirx = -1 THEN
direction = 8
END IF
IF m_n(direction) + 1 <= g.m_max THEN ' Don't fire if out of missiles.
IF g.y > v.top + 1 AND g.y < v.bottom AND g.x > v.left + 1 AND g.x < v.right - 1 THEN ' Don't fire if at a border.
m_n(direction) = m_n(direction) + 1
m_y(m_n(direction), direction) = g.y
m_x(m_n(direction), direction) = g.x
g.m_fired = g.m_fired + 1
SOUND 900, .1
END IF
END IF
g.m_status = 1 ' Code will now execute missile launch.
END IF
IF g.m_status = 1 THEN
FOR g.m_d = 1 TO 8 ' Check all directions.
IF m_n(g.m_d) > 0 THEN
j = m_n(g.m_d)
FOR g.m_n = 1 TO j
IF m_y(g.m_n, g.m_d) = g.y AND m_x(g.m_n, g.m_d) = g.x THEN
ELSE
LOCATE m_y(g.m_n, g.m_d), m_x(g.m_n, g.m_d): PRINT " ";
END IF
SELECT CASE g.m_d ' Missile direction.
CASE 1
IF m_y(g.m_n, g.m_d) - 1 > v.top THEN
m_y(g.m_n, g.m_d) = m_y(g.m_n, g.m_d) - 1
CALL missile_check(k): IF k = -1 THEN EXIT FOR
ELSE
CALL remove_missile: EXIT FOR ' Missile off screen.
END IF
CASE 2
IF m_y(g.m_n, g.m_d) - 1 > v.top AND m_x(g.m_n, g.m_d) + 2 < v.right THEN
m_y(g.m_n, g.m_d) = m_y(g.m_n, g.m_d) - 1
m_x(g.m_n, g.m_d) = m_x(g.m_n, g.m_d) + 2
CALL missile_check(k): IF k = -1 THEN EXIT FOR
ELSE
CALL remove_missile: EXIT FOR
END IF
CASE 3
IF m_x(g.m_n, g.m_d) + 2 < v.right THEN
m_x(g.m_n, g.m_d) = m_x(g.m_n, g.m_d) + 2
CALL missile_check(k): IF k = -1 THEN EXIT FOR
ELSE
CALL remove_missile: EXIT FOR
END IF
CASE 4
IF m_y(g.m_n, g.m_d) + 1 < v.bottom AND m_x(g.m_n, g.m_d) + 2 < v.right THEN
m_y(g.m_n, g.m_d) = m_y(g.m_n, g.m_d) + 1
m_x(g.m_n, g.m_d) = m_x(g.m_n, g.m_d) + 2
CALL missile_check(k): IF k = -1 THEN EXIT FOR
ELSE
CALL remove_missile: EXIT FOR
END IF
CASE 5
IF m_y(g.m_n, g.m_d) + 1 < v.bottom THEN
m_y(g.m_n, g.m_d) = m_y(g.m_n, g.m_d) + 1
CALL missile_check(k): IF k = -1 THEN EXIT FOR
ELSE
CALL remove_missile: EXIT FOR
END IF
CASE 6
IF m_y(g.m_n, g.m_d) + 1 < v.bottom AND m_x(g.m_n, g.m_d) - 2 > v.left THEN
m_y(g.m_n, g.m_d) = m_y(g.m_n, g.m_d) + 1
m_x(g.m_n, g.m_d) = m_x(g.m_n, g.m_d) - 2
CALL missile_check(k): IF k = -1 THEN EXIT FOR
ELSE
CALL remove_missile: EXIT FOR
END IF
CASE 7
IF m_x(g.m_n, g.m_d) - 2 > v.left THEN
m_x(g.m_n, g.m_d) = m_x(g.m_n, g.m_d) - 2
LOCATE m_y(g.m_n, g.m_d), m_x(g.m_n, g.m_d)
CALL missile_check(k): IF k = -1 THEN EXIT FOR
ELSE
CALL remove_missile: EXIT FOR
END IF
CASE 8
IF m_y(g.m_n, g.m_d) - 1 > v.top AND m_x(g.m_n, g.m_d) - 2 > v.left THEN
m_y(g.m_n, g.m_d) = m_y(g.m_n, g.m_d) - 1
m_x(g.m_n, g.m_d) = m_x(g.m_n, g.m_d) - 2
CALL missile_check(k): IF k = -1 THEN EXIT FOR
ELSE
CALL remove_missile: EXIT FOR
END IF
END SELECT
NEXT
IF a.count = 0 THEN EXIT SUB
END IF
NEXT
IF g.m_fired <= 0 THEN g.m_fired = 0: g.m_status = 0 ' All missiles cleared.
END IF
END IF
END SUB
SUB missile_check (k)
LOCATE m_y(g.m_n, g.m_d), m_x(g.m_n, g.m_d) ' Place cursor at current missile position.
k = SCREEN(m_y(g.m_n, g.m_d), m_x(g.m_n, g.m_d)) ' Read the screen.
id_by_color = SCREEN(m_y(g.m_n, g.m_d), m_x(g.m_n, g.m_d), 1)
IF k <> 32 AND k <> g.m_asc AND k <> ASC(g.flagship) THEN ' If screen space is occupied by alien ship then explosion.
CALL remove_missile
CALL explosion
CALL remove_ship(id_by_color)
k = -1 ' A flag to exit the FOR/NEXT loop upon return.
ELSE
COLOR 14: PRINT CHR$(g.m_asc);: COLOR 7 ' Print missile on the screen. Missile advances here. Only place a missile is printed to the screen.
END IF
END SUB
SUB remove_missile
m_n(g.m_d) = m_n(g.m_d) - 1 ' Counter. Reduce the number of missiles fired, in a specific direction, by 1.
FOR k = g.m_n TO m_n(g.m_d) ' Re-stack arrays.
m_y(k, g.m_d) = m_y(k + 1, g.m_d)
m_x(k, g.m_d) = m_x(k + 1, g.m_d)
NEXT
m_y(k, g.m_d) = 0: m_x(k, g.m_d) = 0 'Zero out location variables of the missile removed. A zero removes unnecessary loop checking for other routines.
g.m_fired = g.m_fired - 1 ' Count of number of missiles fired is reduce by 1.
END SUB
SUB mask_missiles
FOR i = 1 TO g.m_max
FOR j = 1 TO 8
IF m_y(i, j) <> 0 THEN LOCATE m_y(i, j), m_x(i, j): PRINT " "; ' Mask missile.
NEXT j, i
m_status = 0: m_fired = 0: m_n = 0: m_d = 0: m_y = 0: m_x = 0
REDIM m_n(g.m_max), m_x(g.m_max, 8), m_y(g.m_max, 8)
END SUB
SUB explosion
soundfile% = 1 ' Local variable turns sound on.
b_y1 = CSRLIN: b_x1 = POS(0)
VIEW PRINT v.top TO v.bottom ' Needed to set print error parameters.
h = 0
ON ERROR GOTO offscreen
DO
IF h = 1 THEN burst$ = " " ELSE burst$ = CHR$(249)
IF v.intro THEN burst$ = "" ' No fireworks, just flash and sound.
h = h + 1
' Flash
IF eflag THEN
IF ABS(z7 - TIMER) > .1 THEN
eflag = 0
PALETTE 0, 0
z7 = TIMER
ELSE
j = -j * -1
IF j = 0 THEN
PALETTE 0, 63
_DELAY .05
ELSE
PALETTE 0, 0
_DELAY .05
END IF
END IF
END IF
IF eflag = 0 THEN
PALETTE 0, 36
IF soundfile% THEN
_SNDPLAY v.snd1
_DELAY .05
PALETTE 0, 0
_SNDPLAY v.snd2
ELSE
_DELAY .075
END IF
eflag = -1
z7 = TIMER
END IF
PALETTE 0, 0 ' End flash.
FOR i = 1 TO 5
SELECT CASE i
CASE 1
COLOR 15
LOCATE b_y1, b_x1: PRINT burst$;
_DELAY .1
CASE 2
IF burst$ = CHR$(249) THEN burst$ = CHR$(250)
COLOR 14, 0
LOCATE b_y1 - 1, b_x1
IF er = 0 THEN PRINT burst$; ELSE er = 0
LOCATE b_y1, b_x1 - 1
IF er = 0 THEN PRINT burst$; ELSE er = 0
LOCATE b_y1, b_x1
IF er = 0 THEN PRINT burst$; ELSE er = 0
LOCATE b_y1, b_x1 + 1
IF er = 0 THEN PRINT burst$; ELSE er = 0
LOCATE b_y1 + 1, b_x1
IF er = 0 THEN PRINT burst$; ELSE er = 0
_DELAY .1
CASE 3
LOCATE b_y1 - 1, b_x1
IF er = 0 THEN PRINT " "; ELSE er = 0
LOCATE b_y1, b_x1 - 1
IF er = 0 THEN PRINT " "; ELSE er = 0
LOCATE b_y1, b_x1
IF er = 0 THEN PRINT " "; ELSE er = 0
LOCATE b_y1, b_x1 + 1
IF er = 0 THEN PRINT " "; ELSE er = 0
LOCATE b_y1 + 1, b_x1
IF er = 0 THEN PRINT " "; ELSE er = 0
CASE 4
COLOR 4
LOCATE b_y1 - 1, b_x1 - 1
IF er = 0 THEN PRINT burst$; ELSE er = 0
LOCATE b_y1 - 1, b_x1 + 1
IF er = 0 THEN PRINT burst$; ELSE er = 0
LOCATE b_y1, b_x1 - 2
IF er = 0 THEN PRINT burst$; ELSE er = 0
LOCATE b_y1, b_x1
IF er = 0 THEN PRINT burst$; ELSE er = 0
LOCATE b_y1, b_x1 + 2
IF er = 0 THEN PRINT burst$; ELSE er = 0
LOCATE b_y1 + 1, b_x1 - 1
IF er = 0 THEN PRINT burst$; ELSE er = 0
LOCATE b_y1 + 1, b_x1 + 1
IF er = 0 THEN PRINT burst$; ELSE er = 0
_DELAY .3
CASE 5
LOCATE b_y1 - 1, b_x1 - 1
IF er = 0 THEN PRINT " "; ELSE er = 0
LOCATE b_y1 - 1, b_x1 + 1
IF er = 0 THEN PRINT " "; ELSE er = 0
LOCATE b_y1, b_x1 - 2
IF er = 0 THEN PRINT " "; ELSE er = 0
LOCATE b_y1, b_x1 - 1
IF er = 0 THEN PRINT " "; ELSE er = 0
LOCATE b_y1, b_x1
IF er = 0 THEN PRINT " "; ELSE er = 0
LOCATE b_y1, b_x1 + 1
IF er = 0 THEN PRINT " "; ELSE er = 0
LOCATE b_y1, b_x1 + 2
IF er = 0 THEN PRINT " "; ELSE er = 0
LOCATE b_y1 + 1, b_x1 - 1
IF er = 0 THEN PRINT " "; ELSE er = 0
LOCATE b_y1 + 1, b_x1 + 1
IF er = 0 THEN PRINT " "; ELSE er = 0
END SELECT
NEXT
IF h = 1 THEN h = 0: EXIT DO
LOOP
VIEW PRINT
ON ERROR GOTO 0
COLOR 7
IF a.count = 1 THEN CALL mask_missiles ' Clear unexploded missiles off the screen when changing levels. Game Option: Remove variable to mask missiles after every explosion.
LOCATE b_y1, b_x1
END SUB
SUB remove_ship (id_by_color) ' Removes ship by color identification.
i = a.itr
ON ERROR GOTO offscreen
LOCATE a_mask_y(id_by_color), a_mask_x(id_by_color): PRINT SPACE$(LEN(a.ship));
LOCATE a_y(id_by_color), a_x(id_by_color): PRINT SPACE$(LEN(a.ship));
ON ERROR GOTO 0
a.itr = id_by_color: CALL a_erase
a_ran(id_by_color) = -1 ' Denotes alien ship was destroyed and removed from battle.
a.itr = i
a.count = a.count - 1 ' a.count = 0 will cause program to exit any unneeded subs/loops after the game level sub is completed.
CALL comm
' Restore any alien ships in blast zone.
FOR i = 1 TO a.max
IF a_ran(i) > 0 THEN
IF a_y(i) > v.top AND a_x(i) > v.left AND a_x(i) + LEN(a.ship) < v.right THEN LOCATE a_y(i), a_x(i): COLOR i: PRINT a.ship;
END IF
NEXT
COLOR 7
LOCATE g.y, g.x: PRINT g.flagship; ' Re-display Guardian.
IF a.count = 0 THEN ' All alien ships destroyed.
IF v.level < 3 THEN
CALL game_level ' Advance to next level.
ELSE
CALL game_over ' Guardian wins! IMPORTANT: Must now exit sub without other conditions.
END IF
END IF
END SUB
SUB alien_move
STATIC z5
y_restore = CSRLIN: x_restore = POS(0) ' Restore column and row upon exit.
IF ABS(z5 - TIMER) > a.cycle_delay OR v.intro THEN ' z5 is a time delay for alien space ship maneuvers. It can be altered in the "game" subroutine.
IF v.intro = 0 THEN h_alien_nom = INT(RND * a.max) + 1 ELSE h_alien_nom = 15
FOR h = 1 TO h_alien_nom ' Local counting variable for alien number of moves in this cycle.
a.itr = a.itr + 1: IF a.itr > a.max THEN a.itr = 1 ' Needed to offset the EXIT DO hover event, which on exit does not affect the a.itr variable.
IF a_ran(a.itr) <> -1 THEN ' This is how a destroyed ship is bypassed. -1 is a destroyed alien ship. Code moves to end of DO:LOOP.
IF a_inertia(a.itr) = 0 THEN ' Determine how many moves in one direction.
a_inertia(a.itr) = INT(RND * (v.bottom - v.top) / 2) + 1 ' How many moves to go in any one direction.
a_ran(a.itr) = INT(RND * 8) + 1 ' Choose 1 of 8 possible directions.
IF a_ran(a.itr) = a_olda_ran(a.itr) OR a_mask_y(a.itr) = 0 AND a_mask_x(a.itr) = 0 AND ran = 1 OR a_mask_y(a.itr) = 0 AND a_mask_x(a.itr) = 0 AND ran = 5 THEN
EXIT FOR ' Just hover if direction was not changed on existing alien space ship or if a new alien space ship is entering from the sides and up or down was generated.
END IF
SELECT CASE a_ran(a.itr) ' Get changes in column and row coordinates.
CASE 1: a_y_loc(a.itr) = -1: a_x_loc(a.itr) = 0 ' Up.
CASE 2: a_y_loc(a.itr) = -1: a_x_loc(a.itr) = 2 ' Up and right.
CASE 3: a_y_loc(a.itr) = 0: a_x_loc(a.itr) = 2 ' Right.
CASE 4: a_y_loc(a.itr) = 1: a_x_loc(a.itr) = 2 ' Down and right.
CASE 5: a_y_loc(a.itr) = 1: a_x_loc(a.itr) = 0 ' Down.
CASE 6: a_y_loc(a.itr) = 1: a_x_loc(a.itr) = -2 ' Down and left.
CASE 7: a_y_loc(a.itr) = 0: a_x_loc(a.itr) = -2 ' Left.
CASE 8: a_y_loc(a.itr) = -1: a_x_loc(a.itr) = -2 ' Up and left.
END SELECT
IF a_y(a.itr) = 0 AND a_x(a.itr) = 0 AND a_ran(a.itr) <> -1 THEN ' New alien space ship enters the screen.
i = RND * (v.bottom - v.top) \ 4
a_y(a.itr) = (v.bottom - v.top) \ 4 + i + v.top
IF a_ran(a.itr) < 5 THEN ' Determine side of entry from initial direction.
IF SCREEN(a_y(a.itr), v.left + LEN(a.ship)) = 32 THEN
a_x(a.itr) = v.left + 1 ' Enter from the left side and go right.
ELSE
CALL a_erase
EXIT FOR
END IF
ELSE
IF SCREEN(a_y(a.itr), v.right - LEN(a.ship) + 1) = 32 THEN
a_x(a.itr) = v.right - LEN(a.ship) ' Enter from the right side and go left.
ELSE
CALL a_erase
EXIT FOR
END IF
END IF
END IF
a_olda_ran(a.itr) = a_ran(a.itr) ' Remember last direction. Another line uses this to disallow any RND that chooses the same direction twice.
ELSE
a_inertia(a.itr) = a_inertia(a.itr) - 1 ' Count down the number of moves in any one direction. When zero, switch direction.
END IF
FOR i = 1 TO a.max
IF i <> a.itr AND a_y(i) <> 0 THEN
IF a_y(a.itr) + a_y_loc(a.itr) = a_y(i) THEN
IF a_x(a.itr) + a_x_loc(a.itr) + LEN(a.ship) > a_x(i) AND a_x(a.itr) + a_x_loc(a.itr) < a_x(i) + LEN(a.ship) THEN
collide = 1
EXIT FOR
END IF
END IF
END IF
NEXT
IF collide = 1 THEN
j = a_y(a.itr): k = a_x(a.itr)
a_y_loc(a.itr) = 0: a_x_loc(a.itr) = 0: a_inertia(a.itr) = 0
collide = 0 ' Collision detection off. Collision was detected and avoided.
ELSE
j = a_y(a.itr) + a_y_loc(a.itr): k = a_x(a.itr) + a_x_loc(a.itr)
END IF
IF j <= v.top OR k <= v.left OR k + LEN(a.ship) > v.right THEN ' Alien ship out of range, off screen.
a_inertia(a.itr) = 0 ' These two lines keep the out of range ship(s) reasonably nearby.
IF j > v.top - 4 AND k < v.right + 3 AND k > v.left - 4 THEN a_y(a.itr) = j: a_x(a.itr) = k
IF a_mask_y(a.itr) <> 0 AND a_mask_x(a.itr) <> 0 THEN
LOCATE a_mask_y(a.itr), a_mask_x(a.itr)
PRINT SPACE$(LEN(a.ship)); ' Mask old position here because the show part of the mask-and-show routine cannot be used when out of range.
END IF
IF a_offscrn(a.itr) > 25 THEN a_y(a.itr) = 0: a_x(a.itr) = 0: a_inertia(a.itr) = 0: a_offscrn(a.itr) = 0
a_mask_y(a.itr) = 0: a_mask_x(a.itr) = 0: a_offscrn(a.itr) = a_offscrn(a.itr) + 1
ELSE
' Check for v.bottom collision and reverse course if detected.
COLOR a.itr
IF j >= v.bottom THEN
a_y_loc(a.itr) = -a_y_loc(a.itr): a_x_loc(a.itr) = -a_x_loc(a.itr)
ELSE
a_y(a.itr) = j: a_x(a.itr) = k ' Next move coordinates.
ii = 0
kk = ASC(g.flagship)
FOR i = 0 TO LEN(a.ship) - 1 ' Check area through width of ship. Remember all or parts of ship are still present on screen.
SELECT CASE SCREEN(j, k + i)
CASE kk
ii = 1 ' Indicates contact with flagship and evokes call abduction routine a few lines down.
EXIT FOR
CASE g.m_asc
ii = 2 ' Indicates ship into missile collision.
EXIT FOR 'Okay to exit as a missile and Guardian craft cannot be present in the same location.
END SELECT
NEXT
IF ii <> 2 THEN ' This will make a move unless a ship into missile event would occur.
'--------------------------------------------Move alien ship-------------------------------------------------
IF a_mask_y(a.itr) <> 0 AND a_mask_x(a.itr) <> 0 THEN LOCATE a_mask_y(a.itr), a_mask_x(a.itr): PRINT SPACE$(LEN(a.ship));
LOCATE j, k: PRINT a.ship;
a_mask_y(a.itr) = j: a_mask_x(a.itr) = k ' Remember these coordinates to erase alien space ship on next loop.
'------------------------------------------------------------------------------------------------------------
END IF
IF ii = 1 THEN CALL guardian_abduction: EXIT FOR ' Exit loop.
END IF
COLOR 7
END IF
END IF ' a_ran(a.itr) > -1 exit point.
IF a.itr = a.max THEN a.itr = 0: EXIT FOR ' Finished loop. Keep this outside the IF/THEN statement.
NEXT h
z5 = TIMER
LOCATE y_restore, x_restore ' Restore entry column and row positions.
END IF ' End time event.
END SUB
SUB guardian_abduction
IF v.intro = 0 THEN
CALL mask_missiles ' Clear unexploded missiles off the screen after alien abduction.
msg$ = "[GUARDIAN ABDUCTED]"
SOUND 500, .4: SOUND 1000, .3: SOUND 1500, .2
PCOPY 0, 1
SCREEN 0, 0, 1, 1
LOCATE (v.bottom - v.top) \ 2 + v.top, v.left + ((v.right - v.left + 1) \ 2) - LEN(msg$) \ 2
COLOR 14 + 16: PRINT msg$;
_DELAY 2
SCREEN 0, 0, 0, 0
END IF
DO
j = 0
FOR i = 1 TO a.max
IF a_y(i) >= v.top AND a_x(i) >= v.left AND a_x(i) <= v.right - LEN(a.ship) THEN
SOUND 500, .04
LOCATE a_y(i), a_x(i): PRINT SPACE$(LEN(a.ship));
IF a_y(i) <> v.top THEN a_y(i) = a_y(i) - 1: LOCATE a_y(i), a_x(i): COLOR i: PRINT a.ship;: _DELAY .02: j = 1
END IF
NEXT
LOOP WHILE j
COLOR 7
IF v.intro THEN EXIT SUB
g.num = g.num - 1
CALL comm
IF g.num = 0 THEN ' Game Over.
CALL comm
CALL game_over
END IF
v.level = -v.level ' Satisfies two conditions. 1) Puts game back to beginning level. 2) Bypasses the part of the game_level routine that reprints the guardian craft.
CALL game_level
_DELAY .75
a.count = 0 ' Needed to exit subs back to main game loop.
END SUB
SUB game_level ' Evaluates both alien defeated on a level and Guardian abduction.
IF v.level > -1 THEN ' Bypass if abducted (v.level = -1) Make a new variable for this if the game is modified to not go back to the starting level.
LOCATE g.y, g.x
PRINT g.flagship;
_DELAY .5
LOCATE g.y, g.x
PRINT " "; ' Mask Guardian craft.
END IF
_DELAY 1
VIEW PRINT v.top TO v.bottom: CLS 2: VIEW PRINT
IF v.level < 0 THEN v.level = ABS(v.level) ELSE v.level = v.level + 1 ' Less than zero if abducted.
msg$ = "[LEVEL " + LTRIM$(STR$(v.level)) + "]"
LOCATE (v.bottom - v.top) \ 2 + v.top, v.left + ((v.right - v.left + 1) \ 2) - LEN(msg$) \ 2
COLOR 14 + 16: PRINT msg$;
j = 0: k = 0
DO
IF ABS(z0 - TIMER) > .15 THEN
IF j = 0 THEN j = 1: SOUND 750, .3: k = k + 1 ELSE j = 0: _DELAY .1
z0 = TIMER
END IF
LOOP UNTIL k = 6
COLOR 7
LOCATE , v.left + ((v.right - v.left + 1) \ 2) - LEN(msg$) \ 2
PRINT msg$;
VIEW PRINT v.top TO v.bottom: CLS 2: VIEW PRINT
_DELAY .75
g.y = (v.bottom - v.top) \ 2 + v.top: g.x = (v.right - v.left + 1) \ 2 + v.left ' Reset column and row for Guardian craft.
LOCATE g.y, g.x
COLOR 15 + 16: PRINT g.flagship;
_DELAY 1.5
COLOR 7: LOCATE g.y, g.x: PRINT g.flagship;
v.level_up = -1
CALL mouse(0, 0) ' Clears the mouse_events.
END SUB
SUB a_erase
a_y(a.itr) = 0: a_x(a.itr) = 0: a_mask_y(a.itr) = 0: a_mask_x(a.itr) = 0: a_inertia(a.itr) = 0: a_ran(a.itr) = 0: a_y_loc(a.itr) = 0: a_x_loc(a.itr) = 0: a_olda_ran(a.itr) = 0
END SUB
SUB mouse (mouse_event1, mouse_event2)
STATIC z9, z10, lb, lb_status ' lb_status keeps track of press/release.
WHILE _MOUSEINPUT
IF ABS(z10 - TIMER) > .1 THEN
z10 = TIMER
IF _MOUSEWHEEL > 0 THEN ' Down
IF g.thrusters < 20 THEN g.thrusters = g.thrusters + 1
ELSEIF _MOUSEWHEEL < 0 THEN ' Up
IF g.thrusters > 0 THEN g.thrusters = g.thrusters - 1
END IF
END IF
WEND
mx = _MOUSEX
my = _MOUSEY
lb = _MOUSEBUTTON(1)
rb = _MOUSEBUTTON(2)
IF lb THEN
IF lb_status = 0 THEN
IF ABS(z9 - TIMER) > .33 THEN
z9 = TIMER
mouse_event1 = -1: lb_status = -1: ' Left button down
END IF
END IF
ELSE
IF lb_status THEN lb_status = 0 ' Left button was released.
END IF
IF v.mouse_get_screen THEN
IF lb_status = -1 THEN
x$ = CHR$(SCREEN(my, mx))
SELECT CASE v.mouse_get_screen
CASE 1 ' Skip intro.
IF x$ = "S" THEN v.intro = 999: SOUND 1000, .3: EXIT SUB
CASE 2 ' Replay
IF x$ = "Y" THEN v.play = 999: SOUND 1000, .1: EXIT SUB
IF x$ = "N" THEN v.play = -999: SOUND 1000, .1: EXIT SUB
END SELECT
END IF
END IF
cx = g.x: cy = g.y ' Angular calculations provided by bplus from the QB64 Phoenix Forum.
stepX = ABS(cx - mx): stepY = ABS(cy - my)
dAng = INT(_R2D(_ATAN2(my - cy, mx - cx)) + .5)
IF dAng < 0 THEN dAng = dAng + 360
IF dAng <= 90 THEN
startA = 0: endA = dAng: ra = dAng
ELSEIF dAng <= 180 THEN
startA = dAng: endA = 180: ra = 90 - (dAng - 90)
ELSEIF dAng <= 270 THEN
startA = 180: endA = dAng: ra = dAng - 180
ELSEIF dAng <= 360 THEN
startA = dAng: endA = 360: ra = 90 - (dAng - 270)
END IF
m_y = 0: m_x = 0
IF ra <= 90 AND ra >= 50 THEN
IF my > g.y THEN
x$ = "down": m_y = 1: m_x = 0 ' Down.
ELSE
x$ = "up": m_y = -1: m_x = 0 ' Up.
END IF
ELSEIF ra < 50 AND ra >= 15 THEN
IF mx > g.x AND my > g.y THEN
x$ = "down right": m_y = 1: m_x = 2 ' Down and right.
ELSEIF mx < g.x AND my > g.y THEN
x$ = "down left": m_y = 1: m_x = -2 ' Down an left.
ELSEIF mx > g.x AND my < g.y THEN
x$ = "up right": m_y = -1: m_x = 2 ' Up and right.
ELSEIF mx < g.x AND my < g.y THEN
x$ = "up left": m_y = -1: m_x = -2 ' Up and left.
END IF
ELSEIF ra < 15 AND ra >= 0 THEN
IF mx > g.x THEN
x$ = "right": m_y = 0: m_x = 2 ' Right
ELSE
x$ = "left": m_y = 0: m_x = -2 ' Left
END IF
END IF
IF rb AND mouse_event2 = 0 THEN
mouse_event2 = -1
g.m_y = m_y: g.m_x = m_x / 2
v.mouse_or_key_move = 1 ' Right mouse button to move.
ELSE
IF mouse_event2 THEN mouse_event2 = 0
END IF
IF mouse_event1 THEN
g.diry = m_y: g.dirx = m_x / 2
v.mouse_or_key_move = -1
END IF
END SUB
SUB game_over
v.mouse_get_screen = 2 ' Allows mouse to select replay options.
_DELAY .5
CALL comm
IF a.count = 0 THEN SOUND 1000, .75: SOUND 500, .75: SOUND 1000, 1.5 ELSE SOUND 1000, .75: SOUND 700, .75: SOUND 500, 1.5
_DELAY .5
VIEW PRINT v.top TO v.bottom: CLS 2: VIEW PRINT
IF a.count = 0 THEN msg$ = "[GUARDIAN WINS]" ELSE msg$ = "[Game Over]"
LOCATE (v.bottom - v.top) \ 2 + v.top - 1, v.left + ((v.right - v.left + 1) \ 2) - LEN(msg$) \ 2
COLOR 14 + 16
PRINT msg$;
_DELAY 2
LOCATE (v.bottom - v.top) \ 2 + v.top - 1, v.left + ((v.right - v.left + 1) \ 2) - LEN(msg$) \ 2
COLOR 14: PRINT msg$;
msg$ = "Replay? Y/N"
_DELAY 1
LOCATE (v.bottom - v.top) \ 2 + v.top + 1, v.left + ((v.right - v.left + 1) \ 2) - LEN(msg$) \ 2
COLOR 8
PRINT msg$;
COLOR 7
DO
_LIMIT 30
CALL mouse(mouse_event1, mouse_event2)
ky$ = INKEY$
IF LEN(ky$) OR v.play = 999 OR v.play = -999 THEN
IF v.play = 999 OR UCASE$(ky$) = "Y" OR ky$ = CHR$(13) THEN v.play = 1: v.level = 0: VIEW PRINT v.top TO v.bottom: CLS 2: VIEW PRINT: EXIT DO
IF v.play = -999 OR UCASE$(ky$) = "N" OR ky$ = CHR$(27) THEN
msg$ = " [Bye Bye] "
LOCATE (v.bottom - v.top) \ 2 + v.top - 1, v.left + ((v.right - v.left + 1) \ 2) - LEN(msg$) \ 2
COLOR 14 + 16: PRINT msg$;
_DELAY 1
LOCATE (v.bottom - v.top) \ 2 + v.top - 1, v.left + ((v.right - v.left + 1) \ 2) - LEN(msg$) \ 2
COLOR 14: PRINT msg$;
_DELAY .5
SYSTEM
END IF
END IF
LOOP
END SUB
Note 1: I coded it to adjust to your desktop size. It works well on mine, but let me know if it doesn't seem to be a good fit on yours. You can always press Alt + Enter, to run it full screen, too.
Note 2: Alien's can run off the screen, and come back. What I need to work on now is a method so the last one doesn't run off the screen for too long. Normally it's just a few seconds, but I have had a handful of time it has taken a few minutes, and that's way too long. But that, and a little more A.I. is for another day... after my egg facial wears off from another discussion thread.
Pete
Don't forget, download the soud effects file below, and save it in the same folder.
ASCII Invaders Sound.7z (Size: 1.45 MB / Downloads: 85)