TGC Codebase Backup



Nibbles Game by SandraD

28th Jun 2004 9:48
Summary

Improved Nibbles game. More commentary.



Description

First a reply to a forum message, this is my first complete game.

Uses windows default sounds, music not implemented.

Now with more comments to explain the code, and increasing speed difficulty during play.

Fixed potential exit error.



Code
                                    ` This code was downloaded from The Game Creators
                                    ` It is reproduced here with full permission
                                    ` http://www.thegamecreators.com
                                    
                                    rem Nibbles Version 1.1
rem by SandraD 06/16/04
rem **main source**

rem 06/28/04 additional comments added
rem to explain what's going on, and added
rem code to increase difficulty during play.

set display mode 800, 600, 16
sync on
randomize timer()
hide mouse

rem Load Sounds -- using windows defaults
load sound "c:\windows\media\ding.wav", 1
load sound "c:\windows\media\recycle.wav",2
rem load music "canyon.mid", 1

rem globals (in DBC, as arrays)
rem just in case I want to use functions for stuff.
dim head(0)
dim tail(0)

rem this is x/y direction....
dim way(1)

rem the skipper value
dim lag(0)

rem a score (of course) and count of worms..
dim score(0)
dim worms(0)

rem put up to 5 targets on screen
rem #6 is a "fast zero"
dim targets(6,3)
dim ts(0)

rem step size/world size/borders
dim xsize(2)
dim ysize(2)

rem world time... twice...
dim tim(1)

rem game timing delay
dim dela(0)

rem I like color globals, saves wear on my brain...
rem plus it's easier to change them this way.
dim white(0)
white(0) = rgb(255, 255, 255)
dim green(0)
green(0) = rgb(0, 128, 0)
dim blue(0)
blue(0) = rgb(0,0,192)
dim gray(0)
gray(0) = rgb(85, 85, 85)
dim brtgrn(0)
brtgrn(0) = rgb(0, 192, 0)
dim red(0)
red(0) = rgb(192, 0, 0)

rem first scale the world, so it looks/acts the same
rem for the most common video resolution settings.
rem steps is desired grid horizontally...
steps = 120
rem divide desired steps into display width
xsize(1) = (screen width() - 20) / steps
rem find size of border left-right
xsize(0) = screen width() - (xsize(1) * steps)
rem find actual size of the horizontital grid
xsize(2) = (screen width() - xsize(0)) / xsize(1)
rem convert to often used zero
xsize(0) = xsize(1) + (xsize(0) / 2)

rem now do the same for y, using previous x size
rem ysize(2) temporarily replaces steps here...
ysize(2) = (screen height() - 40) / xsize(1)
ysize(1) = (screen height() - 40) / ysize(2)
ysize(0) = screen height() - (ysize(1) * ysize(2))
ysize(2) = (screen height() - ysize(0)) / ysize(1)

rem convert to often used zero
ysize(0) = ysize(1) + ysize(0)
ysize(2) = ysize(2) - 8

rem set up world and worm arrays...
a = xsize(2) * ysize(2)
dim worm(a, 1)
dim wormsize(0)
wormsize(0) = a
a = xsize(2) + 1
b = ysize(2) + 1
dim world(a, b)

rem we come here on each start...
start:
worms(0)  = 3

rem a place to re-enter...
rem reset the game for another pass.
restart:
dela(0) = 100
tim(1) = 0
tim(0) = 1
running = 0
whoa = timer()
way(1) = 0
way(0) = 0
for x = 0 to wormsize(0)
  worm(x,0) = 0
  worm(x,1) = 0
next x
for y = 0 to ysize(2)
  for x = 0 to xsize(2)
    world(x, y) = 0
  next x
next y
for x = 0 to 6
  targets(x, 0) = 0
  targets(x, 1) = 0
  targets(x, 2) = 0
  targets(x, 3) = 0
next x
ts(0) = 0

rem print the title....
cls gray(0)
ink white(0), 0
d = text size()
set text font "Arial"
set text size 30
center text screen width()/2,10,"Nibbles by SandraD v1.1"
set text size d

rem set up play area...
ink green(0), 0
c = (xsize(1)*xsize(2))
d = (ysize(1)*ysize(2))
sbox(1, 1, c, d)
ink brtgrn(0), 0
sbox(0, 0, c, ysize(1))
sbox(0, 0, xsize(1), d)
sbox(c, 0, xsize(1), d+ysize(1))
sbox(0, d, c, ysize(1))

rem init starting values...
worm(0, 0) = rnd(xsize(2)-2) + 1
worm(0, 1) = rnd(ysize(2)-2) + 1
world(worm(0, 0), worm(0, 1)) = 1
head(0) = 0
tail(0) = 0
lag(0) = 3

rem show starting position
ink white(0), 0
sbox(worm(0, 0) * xsize(1), worm(0, 1) * ysize(1), xsize(1), ysize(1))

rem because this is a simple game, let's do
rem everything in the main loop ....
rem loop music 1
do

rem I do this for user input...
rem way() is set to inc/dec
loop1:
if upkey()
  if running = 0 then running = 1
  way(0) = 0
  way(1) = -1
endif
if downkey()
  if running = 0 then running = 1
  way(0) = 0
  way(1) = 1
endif
if leftkey()
  if running = 0 then running = 1
  way(0) = -1
  way(1) = 0
endif
if rightkey()
  if running = 0 then running = 1
  way(0) = 1
  way(1) = 0
endif

rem this is a testing display.....
rem it shows the world map in game colors,
rem then waits for a key to continue
if spacekey()
 for y = 0 to ysize(2)
  for x = 0 to xsize(2)
   a = world(x,y)
   if a = 0 then ink green(0),0
   if a = 1 then ink white(0),0
   if a = 2 then ink blue(0),0
   if a>2 or a<0 then ink 0, 0
   sbox(x*xsize(1), y*ysize(1), xsize(1), ysize(1))
   next x
  next y
  sync
 suspend for key
endif

rem this slows the proggie down a little....
if whoa + dela(0) < timer() 
  whoa = timer()
 else
  goto loop1
endif

rem now we handle movement...
rem the worm() array is a ring buffer
rem with the head as input and the tail
rem as output, using the tail for eraser.
rem when the worm grows, the tail
rem lags further and further behind
rem the head.
if running = 1
  head(0) = head(0) + 1
  if head(0) > wormsize(0)
    head(0) = 0
    worm(head(0), 0) = worm(wormsize(0), 0) + way(0)
    worm(head(0), 1) = worm(wormsize(0), 1) + way(1)
  else
    worm(head(0), 0) = worm(head(0)-1, 0) + way(0)
    worm(head(0), 1) = worm(head(0)-1, 1) + way(1)
  endif
  tim(0) = tim(0) + 1
  rem locals to make box comand less complex to read.
  ink white(0), 0
  a = worm(head(0), 0) * xsize(1)
  b = worm(head(0), 1) * ysize(1)
  sbox(a, b, xsize(1), ysize(1))
  if lag(0)
    lag(0) = lag(0) - 1
  else
    ink green(0), 0
    a = worm(tail(0), 0) * xsize(1)
    b = worm(tail(0), 1) * ysize(1)
    sbox(a, b, xsize(1), ysize(1))
    world(worm(tail(0), 0), worm(tail(0), 1)) = 0
    tail(0) = tail(0) + 1
    ink white(0), 0
    if tail(0) > wormsize(0) then tail(0) = 0
  endif

rem now confine to the sides...
  if worm(head(0),0) < 1 or worm(head(0),0) > xsize(2)-1 then running = 3
  if worm(head(0),1) < 1 or worm(head(0),1) > ysize(2)-1 then running = 3
endif

rem next up, creating targets to gobble...
rem first an empty world location is found,
rem then a target value and display time
rem is selected at random.
if running = 1 and ts(0) < 4 and tim(1) < tim(0)
  tim(1) = tim(0) + rnd(100)
  if rnd(75) > 10
    a = rnd(xsize(2) - 4) + 1
    b = rnd(ysize(2) - 4) + 1
    v = 0
    if ts(0) <> 0
      for w = 0 to ts(0)
        if (targets(w, 2) => a) and (targets(w, 2) + 2 <= a) and (targets(w, 3) => b) and (targets(w, 3) + 2 <= b) then v = 1
      next w
    endif
    if v = 0
      c = 0
      for y = 0 to 3
        for x = 0 to 3
         c = c + world(a + x, b + y)
        next x
       next y
      if c=0
        targets(ts(0), 0) = rnd(80) + 100
        targets(ts(0), 1) = rnd(14) + 1
        targets(ts(0), 2) = a
        targets(ts(0), 3) = b
        for y = 0 to 2
          for x = 0 to 2
            world(a+x, b+y) = 2
          next x
        next y
        ink blue(0), 0
        x = a*xsize(1)
        y = b*ysize(1)
        sbox(x, y, xsize(1)*3, ysize(1)*3)
        ink white(0), 0
        f# = .85
        if targets(ts(0), 1) > 9 then f# = .15
        set cursor x+xsize(0)+xsize(1)*f#, y+ysize(0)+ysize(1)*.15
        print targets(ts(0), 1);
        ts(0) = ts(0) + 1
      endif
    endif
  endif
endif

rem here we detect hits....
rem do targets first....
if running = 1
  if world(worm(head(0), 0), worm(head(0), 1)) = 2
    v = 0
    for w = 0 to ts(0)
      if (worm(head(0),0) => targets(w, 2)) and (worm(head(0),0) <= (targets(w, 2) + 3))
        if (worm(head(0),1) => targets(w, 3)) and (worm(head(0),1) <= (targets(w, 3) + 3)) then v = w + 1
      endif
    next w
prise:
    if v
    play sound 1
    score(0) = score(0) + targets(v - 1, 1)
    lag(0) = targets(v - 1, 1)
    targets(v - 1, 0) = 2
    world(worm(head(0), 0), worm(head(0), 1)) = 1
    rem this speeds up movement for each target hit
    if dela(0) > 1 then dela(0) = dela(0) - 1
    endif
  else

rem and now we do the body test...
    if world(worm(head(0), 0), worm(head(0), 1)) = 1
      running = 2
    else

rem if nothing found, set head as body...
      world(worm(head(0), 0), worm(head(0), 1)) = 1
    endif
  endif
endif

rem now we have to un-target...
rem because targets have time values,
rem we decrement them, then remove
rem any target when the time is up.
rem if a target is hit, it's time is dropped
rem to two, so this code removes them
rem too.
if running = 1 and ts(0) <> 0
  v = 0
  for w = 0 to 5
    if targets(w, 0) > 0 then targets(w, 0) = targets(w, 0) - 1
    if targets(w, 0) = 1 and targets(w, 1) <> 0
      a = targets(w, 2)
      b = targets(w, 3)
      for y = 0 to 2
        for x = 0 to 2
          if world(a+x, b+y) = 2
            ink green(0), 0
            world(a+x, b+y) = 0
            sbox((a+x)*xsize(1), (b+y)*ysize(1), xsize(1), ysize(1))
          endif
          if world(a+x, b+y) = 1
            ink white(0), 0
            world(a+x, b+y) = 0
            sbox((a+x)*xsize(1), (b+y)*ysize(1), xsize(1), ysize(1))
          endif
        next x
      next y
      v = 1
    endif
  next w
  if v
    loop2:
    v = 0
    for w = 0 to 5
      if targets(w, 0) = 1 and targets(w, 1) <> 0 then v = 1
      if v
        targets(w, 0) = targets(w+1, 0)
        targets(w, 1) = targets(w+1, 1)
        targets(w, 2) = targets(w+1, 2)
        targets(w, 3) = targets(w+1, 3)
      endif
    next w
    ts(0) = ts(0) - 1
    if ts(0) < 0 then ts(0) = 0
    if v = 1 then goto loop1
  endif
endif

rem score printing...
ink gray(0), 0
box 0, 0, 70, 25
ink white(0), 0
set text size 25
center text 35, 5, str$(score(0))
a$ = "Worms: " + str$(worms(0))
center text screen width() - 85, 5, a$

rem message box calculations...
 a = xsize(2)/4*xsize(1)
 b = ysize(2)/4*ysize(1)
 c = xsize(2)/2*xsize(1)
 d = ysize(2)/3*ysize(1)

rem Now we come to the win/lose...
rem running = 0 if not started
rem    = 1 if crawling
rem    = 2 if biting self
rem    = 3 if at edges
rem    = 4 if exiting
if running = 2
  ink red(0), 0
  sbox(a-xsize(1), b-ysize(1), c, d)
  ink 0, 0
  sbox(a, b, c-2*xsize(1), d-2*ysize(1))
  ink white(0), 0
  set text size 80
  center text 2*xsize(1)+a+c/2, b+d/2, "Ouch!"
  play sound 2
  wait 5000
  running = 4
endif
if running = 3
  ink red(0), 0
  sbox(a-xsize(1), b-ysize(1), c, d)
  ink 0, 0
  sbox(a, b, c-2*xsize(1), d-2*ysize(1))
  ink white(0), 0
  set text size 80
  center text 6*xsize(1)+a+c/2, b+d/2, "Myopia?"
  play sound 2
  wait 5000
  running = 4
endif

if running = 4 then exit
sync
loop
rem stop music 1

rem come here after crashing or quitting....
worms(0) = worms(0) - 1
if worms(0) > 0 then goto restart
if worms(0) = 0
  ink 0, 0
  sbox(a, b, c-2*xsize(1), d-2*ysize(1))
  ink white(0), 0
  set text size 50
  center text 6*xsize(1)+a+c/2, b+d/2, "Play Again?";
getit:
  sync
  a$ = inkey$()
  if a$ = "" then goto getit
  if mid$(a$,1) = "y" then goto start
  if mid$(a$,1) = "Y" then goto start
endif

rem though unnecessary, I like unloading things before exit...
bubye:
 undim head(0)
 undim tail(0)
 undim way(1)
 undim lag(0)
 undim score(0)
 undim worms(0)
 undim targets(6,3)
 undim ts(0)
 undim tim(1)
 undim white(0)
 undim green(0)
 undim blue(0)
 a = xsize(2) + 1
 b = ysize(2) + 1
 undim worm(a, 1)
 undim wormsize(0)
 undim world(a, b)
 undim xsize(2)
 undim ysize(2)
 delete sound 1
 delete sound 2
 rem delete music 1
 show mouse
 set display mode 640, 480, 16
end

rem I don't like end-point box commands, they
rem confuse me. So this one is x, y, wide & high...
function sbox(x, y, w, h)
box x+xsize(0), y+ysize(0), x+w+xsize(0)-1, y+h+ysize(0)-1
endfunction