Look, it's Cuzzie the caterpillar!



.....When she was just a little caterpillar, Cuzzie fell from the wet leaf where she had been eating, down into the grass below.  Unable to find her way back up to the tree branches, she was taken in by a family of earthworms who mistook her for a worm.  She had a happy childhood, but always knew that she was different than her earthworm siblings.  As long as she could remember, she had wanted to see the world above ground, and she couldn't explain quite why.  Whenever anyone asked her, she only said, "Because."  That and her fuzzy appearance account for her unique nickname.  As we join her, Cuzzie has just set out to see the world above ground, and face whatever adventures she finds.  If you don't think this game sounds violent, just remember the last time you squashed a bug.  Now, imagine that you're the bug.

.....This is a single player, arcade style game written entirely in assembly language by Mike Kasper, Andrew Kreps, and James Oliver.  To win the game you must lead Cuzzie safely through several different levels of increasing difficulty.  She starts below ground, finds her way above ground, and finally climbs a tree where she will build a cocoon and become a butterfly.  All that she can do is crawl and eat things, but we still think the game will be both a challenge and an interesting way to waste time.  Isn't that really what computer games are all about anyways?  It does get complicated, though.  Cuzzie only has so many chances before she has to start her quest all over.  Every time she is injured by one of her natural enemies, she loses strength, and there is no chance for her to rest until she gets to the end of a level.  More importantly however, she must acquire enough nutrition along the course of her journey to actually become a butterfly, or she will try to fly anyways, with catastrophic results.  The better she eats the bigger of a butterfly she becomes, so that should at least be a challenge for experienced players.

.....The game engine continuously updates the unscrolling screen for each level in response to both player movements and the simple artificial intelligence of the caterpillar's natural enemies.  It also keeps track of the caterpillar's health and calorie point total.  Remember that calories are good for her!  If Cuzzie traverses the screen and catches up with the other caterpillar who she is following, then she advances to the next level.  Calories can be gotten either by eating leaves and berries that occasionally appear, or by killing her natural enemies to defend herself.  As the levels progress, so will the difficulty of navigation, enemy mobility, and the number of things that are out to get her.  It won't be all that easy, but it ought to be fun.  Read on to learn more about this game.

.....The levels are single screen and stored in memory as a grid
of zeros and ones.  Ones can not be moved into, zeros can.  The
appearance of the level is loaded from a PCX file and kept in
memory, but is used independently of this grid.  They just have
to match to make the game playable.  The starting locations of
Cuzzie, her rivals, and her lone ally are all kept in a bugs
array for the specific level.  Thats how the game initializes.
I will explain in more detail.  We used no data structures to represent images.  We only used three 320 by 200 pcx files loaded to and stored in their own segment oof 65,535 bytes in memory.  These were the FontSeg, BackgroundSeg, and BugsSeg.  The data structures for the insects, both Cuzzie and her enemies, were composed of nine byte values, as described below.  By checking and updating the values of these bytes constantly we were able to make a fully functional single screen, multilevel arcade game, which met almost all the expectations we had for it.

.....Further descriptions of all our procedures, are all
provided below.  Besides adding artificial intelligence routines
to differentiate the other bugs from Cuzzie, our program follows
our original write up very closely.  The IO specs for all the code reworked from previous MPs is included with their headings below.  This ought to help in deciphering exactly what we used these functions from our past machine problems to do.  Load PCX loaded our PCX files.  DrawScreen drew the Background to VIDSEG.  InitBuf was not of that much use, but we had to call ModeText and ModeVideo at the beginning and end respectively to switch between the DOS text screen and our 320 by 200 video.

I will go into further detail about the various procedures as they show up in the text below.  As for the procedures that we wrote ourselves, but did not have too much to say about in the first write up, I apologize, but as I thought I had explained, this was due to the fact that we were not sure we would use those procedures at all.  For example, we deleted the GameLoop procedure in favor of a simple loop in the main program which advanced the game to the next level of play as long as the reason for exiting a level was not because they had just died and ought to start over.  I will write in more detail, as need requires in the code below.
DATA STRUCTURES
     
Insect STRUCT
  Name     dw ?  ;The offset of the name for the image file
  OldX     db ?  ;
  OldY     db ?  ;The old position 
  NewX     db ?  ; 
  NewY     db ?  ;The new position 
  Speed    db ?  ;Based on the timer interrupt
  Damage   db ?  ;How much this one hurts Cuzzie
  Strength db ?  ;How many hits this one can take
Insect ENDS


VARIABLES

LevelGrids      dw  offset LEVEL1Grid
                dw  offset LEVEL2Grid
                dw  offset LEVEL3Grid
                dw  offset LEVEL4Grid
                dw  offset LEVEL5Grid
                dw  offset LEVEL6Grid
                dw  offset LEVEL7Grid
                dw  offset LEVEL8Grid
                dw  offset LEVEL9Grid
                dw  offset LEVEL10Grid
                dw  offset LEVEL11Grid
                dw  offset LEVEL12Grid
                dw  offset LEVEL13Grid
                dw  offset LEVEL14Grid
                dw  offset LEVEL15Grid
                dw  offset LEVEL16Grid
                dw  offset LEVEL17Grid
                dw  offset LEVEL18Grid                                 



GridSeg ENDS
        
MIDISeg segment 'DATA7'
    MIDIBuffer DB 65536 dup (?)
MIDISeg ENDS

SoundSeg segment 'DATA8'
        SoundBuffer     db      65536 dup (?)
SoundSeg        ENDS
        

stkseg  segment stack                   ; *** STACK SEGMENT ***
        db      128 dup ('STACK   ')     ; 128*8 = 1024 Bytes of Stack
stkseg  ends

;====== Function type declarations ========================================

 extrn rsave:near
 extrn rrest:near
 extrn dosxit:near
 extrn binasc:near

;====== Begin Code/Data segment ==========================================
cseg    segment public 'CODE'  
        assume  cs:cseg, ds:cseg, es:nothing

FontFile      db      'letters.pcx',0   ; Filename of PCX file with font images
ContinueFile  db      'continue.pcx',0
PitifulFile   db      'gameover.pcx',0
PreludeFile   db      'title.pcx',0
PostludeFile  db      'sheflies.pcx',0
BugsFile      db      'cuzzy.pcx',0   ; Cuzzie and all her movements


Level1File    db   'level1.pcx',0
Level2File    db   'level2.pcx',0
Level3File    db   'level3.pcx',0
Level4File    db   'level4.pcx',0
Level5File    db   'level5.pcx',0
Level6File    db   'level6.pcx',0
Level7File    db   'level7.pcx',0
Level8File    db   'level8.pcx',0
Level9File    db   'level9.pcx',0
Level10File   db  'level10.pcx',0
Level11File   db  'level11.pcx',0
Level12File   db  'level12.pcx',0
Level13File   db  'level13.pcx',0
Level14File   db  'level14.pcx',0
Level15File   db  'level15.pcx',0
Level16File   db  'level16.pcx',0
Level17File   db  'level17.pcx',0
Level18File   db  'level18.pcx',0


LevelFiles dw  offset Level1File
           dw  offset Level2File
           dw  offset Level3File
           dw  offset Level4File
           dw  offset Level5File
           dw  offset Level6File
           dw  offset Level7File
           dw  offset Level8File
           dw  offset Level9File
           dw  offset Level10File
           dw  offset Level11File
           dw  offset Level12File
           dw  offset Level13File
           dw  offset Level14File
           dw  offset Level15File
           dw  offset Level16File
           dw  offset Level17File
           dw  offset Level18File                


LevelBugs       dw  offset LEVEL1Bugs
                dw  offset LEVEL2Bugs
                dw  offset LEVEL3Bugs
                dw  offset LEVEL4Bugs
                dw  offset LEVEL5Bugs
                dw  offset LEVEL6Bugs
                dw  offset LEVEL7Bugs
                dw  offset LEVEL8Bugs
                dw  offset LEVEL9Bugs
                dw  offset LEVEL10Bugs
                dw  offset LEVEL11Bugs
                dw  offset LEVEL12Bugs
                dw  offset LEVEL13Bugs
                dw  offset LEVEL14Bugs
                dw  offset LEVEL15Bugs
                dw  offset LEVEL16Bugs
                dw  offset LEVEL17Bugs
                dw  offset LEVEL18Bugs    
 


NumBugs  db 7,8,9,10,11,12,7,8,9,10,11,12,7,8,9,10,11,12

MoveTable       dw      offset DeadMove
                dw      offset UpLtMove
                dw      offset UpRtMove
                dw      offset DnLtMove
                dw      offset DnRtMove
                dw      offset LtUpMove
                dw      offset LtDnMove
                dw      offset RtUpMove
                dw      offset RtDnMove
                dw      offset ZombieMove

BugFunctions dw offset MoveCuzzie     ;MoveCuzzie
             dw offset MoveFuzzie   ;Really just animate
             dw offset MoveEarwig
             dw offset MoveSpider
             dw offset MoveHornet
             dw offset MoveSlug
             dw offset MoveFly
             dw offset MoveAnt
             dw offset MoveTermite
             dw offset MoveTussie
                           


            
            
; FontMap is a 320x200 PCX File containing 8x8 letters
; ABCDEFGHIJKLMNOPQRSTUVWXYZ
; abcdefghijklmnopqrstuvwxyz
; 01234567890
;
; Letters is a 256-word lookup table that
; maps each ASCII value to a location in FontMap
; Our program need only map letters, digits, space, and period.


Letters dw      32 dup ((320*16)+(8*11))
        dw      (320*16)+(8*12) ; ' '
        dw      13 dup ((320*16)+(8*11))
        dw      (320*16)+(8*10) ; '.'
        dw      (320*16)+(8*11)
        dw      (320*16)+(8*0)  ; '0'
        dw      (320*16)+(8*1)  ; '1'               
        dw      (320*16)+(8*2)  ; '2'
        dw      (320*16)+(8*3)  ; '3'
        dw      (320*16)+(8*4)  ; '4'
        dw      (320*16)+(8*5)  ; '5'
        dw      (320*16)+(8*6)  ; '6'
        dw      (320*16)+(8*7)  ; '7'
        dw      (320*16)+(8*8)  ; '8'
        dw      (320*16)+(8*9)  ; '9'
        dw      7 dup ((320*16)+(8*11))
        dw      (320*0)+(8*0)   ; 'A'
        dw      (320*0)+(8*1)   ; 'B'
        dw      (320*0)+(8*2)   ; 'C'
        dw      (320*0)+(8*3)   ; 'D'
        dw      (320*0)+(8*4)   ; 'E'
        dw      (320*0)+(8*5)   ; 'F'
        dw      (320*0)+(8*6)   ; 'G'
        dw      (320*0)+(8*7)   ; 'H'
        dw      (320*0)+(8*8)   ; 'I'
        dw      (320*0)+(8*9)   ; 'J'   
        dw      (320*0)+(8*10)  ; 'K'
        dw      (320*0)+(8*11)  ; 'L'
        dw      (320*0)+(8*12)  ; 'M'
        dw      (320*0)+(8*13)  ; 'N'
        dw      (320*0)+(8*14)  ; 'O'
        dw      (320*0)+(8*15)  ; 'P'
        dw      (320*0)+(8*16)  ; 'Q'
        dw      (320*0)+(8*17)  ; 'R'
        dw      (320*0)+(8*18)  ; 'S'
        dw      (320*0)+(8*19)  ; 'T'
        dw      (320*0)+(8*20)  ; 'U'
        dw      (320*0)+(8*21)  ; 'V'
        dw      (320*0)+(8*22)  ; 'W'
        dw      (320*0)+(8*23)  ; 'X'
        dw      (320*0)+(8*24)  ; 'Y'
        dw      (320*0)+(8*25)  ; 'Z'
        dw      6 dup ((320*16)+(8*11))
        dw      (320*8)+(8*0)   ; 'a'
        dw      (320*8)+(8*1)   ; 'b'
        dw      (320*8)+(8*2)   ; 'c'
        dw      (320*8)+(8*3)   ; 'd'
        dw      (320*8)+(8*4)   ; 'e'
        dw      (320*8)+(8*5)   ; 'f'
        dw      (320*8)+(8*6)   ; 'g'
        dw      (320*8)+(8*7)   ; 'h'
        dw      (320*8)+(8*8)   ; 'i'
        dw      (320*8)+(8*9)   ; 'j'   
        dw      (320*8)+(8*10)  ; 'k'
        dw      (320*8)+(8*11)  ; 'l'
        dw      (320*8)+(8*12)  ; 'm'
        dw      (320*8)+(8*13)  ; 'n'
        dw      (320*8)+(8*14)  ; 'o'
        dw      (320*8)+(8*15)  ; 'p'
        dw      (320*8)+(8*16)  ; 'q'
        dw      (320*8)+(8*17)  ; 'r'
        dw      (320*8)+(8*18)  ; 's'
        dw      (320*8)+(8*19)  ; 't'
        dw      (320*8)+(8*20)  ; 'u'
        dw      (320*8)+(8*21)  ; 'v'
        dw      (320*8)+(8*22)  ; 'w'
        dw      (320*8)+(8*23)  ; 'x'
        dw      (320*8)+(8*24)  ; 'y'
        dw      (320*8)+(8*25)  ; 'z'
        dw      132 dup ((320*16)+(8*12))



KeyDir          db      STATIONARY      ;set by MyKeyHandler

pbuf            db      7 dup (?) ;buffer for BINASC

oldTimerV       dd      ?       ;far pointer to default 08h
                                ;  interrupt function
oldKeyV         dd      ?       ;far pointer to default key
                                ;  interrupt function                                
timerCount      db      0       ;counter (to be incremented every 1/72 sec) 

gameSpeed       db      3      ;value that TimerCount should reach before


TargetX db ?
TargetY db ?

Counter         db      ?

corner          db      0

Frozen          db      ?

escPressed      db      0

spcPressed      db      0

playball        db      0
hititoff        db      0
trustme         db      0
CurrentGrid     db      12*18   dup     (?)  ;Grid for the current level
;Bugs     Insect 16 dup ({})  ;Up to sixteen insects per level


Bugs            Insect  12      dup     (<0,0,0,0,0,0,0,0,0>)

  ;    Insect 
  ;    Insect 
  ;    Insect 
  ;    Insect 
  ;    Insect 
  ;    Insect 
  ;    Insect 



CurrentLevel db ?  ;Useful information in byte size
SoundEffect  db ?  ;Noise to be played if any in GamePlay
Nutrition    dw ?  ;This tracks how much Cuzzie has eaten
Health       db ?  ;This determines when Cuzzie dies 
Lives        db ?  ;How many chances are left
Bonus        db ?  ;Possible bonus features
JustDied     db ?
ReallyQuit   db ?

;Speed        db ?  ;How fast is the game

Trigger db ?

JustWon db 0

KeyWait dw 0 ; Control variable for KeyPrompt MACRO

XPos    dw ?
YPos    dw ? ; Very very useful.

X1Pos   dw ?
Y1Pos   dw ?

XMargin   dw ?  ;Tiles need these
YMargin   dw ?
mainFrame db 0
herFrame  db 0

Attack    db 0

oldXer db 0
oldYer db 0
newXer db 0
newYer db 0

levelmsg        db      'Level ','$'
blankmsg        db      '    ','$'
OldNutrition    dw      0
OldHealth       db      99
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;  Sound Variables and Jump Tables
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Walking db  'Walking.xmi',0
Mario   db      'Mario.xmi',0
WalkSize    dw  20516
MarioSize       dw    11956                  ; though we ended up only
                                             ; using one MIDI file, the info
PlayWalking     dw      0                    ; for the other was left to avoid
PlayMario       dw      2                    ; changing any variables
MIDISelection   dw      0 

MIDISongs       dw      offset  Walking
                dw      offset  Mario
                
MIDISize        dw      offset  WalkSize
                dw      offset  MarioSize
                
;; file names for each sound effect
fight   db      'sounds\attack.wav',0
bugle   db      'sounds\bugle.wav',0
chord   db      'sounds\chord.wav',0
death   db      'sounds\death.wav',0
gong    db      'sounds\gong.wav',0
hurt    db      'sounds\hurt.wav',0
kiss    db      'sounds\kiss.wav',0
level   db      'sounds\level.wav',0
prizes  db      'sounds\prizes.wav',0

;; table for all the sound effect filenames
Waves   dw      offset  fight
        dw      offset  bugle
        dw      offset  chord
        dw      offset  death
        dw      offset  gong
        dw      offset  hurt
        dw      offset  kiss
        dw      offset  level
        dw      offset  prizes
        
;;  sizes of all the wav files (including headers)
WaveSizes       dw      16774
                dw      65498
                dw      12160
                dw      45000
                dw      45446
                dw      24868
                dw      10786       
                dw      58524
                dw      19796

;;  size of header file that must be skipped before playing file
WavHeader       dw      44


public fontfile, letters

;====== Procedures ==========================================

;
; Procedures
;

ResetDSP - by Andrew Kreps
Inputs: none
Outputs: al = 0 for fail, and AAh for successful reset
Method: resets the DSP by sending one to the reset port for a period
of time, then switching back to zero.  The DSP will read AAh on the data
port if it is reset properly.

SetupDMATransfer - by Andrew Kreps
Inputs:   dx = segment of the data to be transfered
          si = offset of the data to be transfered
          translength = length of the transfer (already decremented by 1)
Outputs:  none but many values sent to the registers to setup the transfer
Method:   convert segment-offset address to page-offset address and store
this in the appropriate registers.  Set the length of the transfer and
put the chip in playback mode.

PlaySound - by Andrew Kreps
Inputs: number = the declared constant for which sound is desired
Outputs: cool sound effects for attacking, hurting, and dying
Method: Use LoadSound to move the wave file into the soundbuffer.  Then
reset the DSP and setup the DMA transfer using the adjusted file length.
Give the DSP the start message.

LoadSound - by Andrew Kreps
Inputs: dx = offset to sound filename
Outputs: none
Method: Uses DOS interrupts to open, load, and close the given file.
The data is loaded into the SoundBuffer in the SoundSegment

LoadMIDI - by Andrew Kreps
Inputs: bp = song number (again redundant since only one file used)
Outputs: none
Method: Loads a MIDI file into the buffer and uses MidPak's interrupt 66h
to register the data.

PlayMIDI - by Andrew Kreps
Inputs: bx = sequence number (a bit redundant since there is only one)
Outputs: MIDI music through your speakers
Method: Uses MidPak's interrupt 66h to start playback of the MIDI file

StopMIDI - by Andrew Kreps
Inputs: none
Outputs: prevents hearing that wonderful MIDI music
Method: Uses MidPak's interrupt 66h to stop playback 

UpdateStatus - by Andrew Kreps
Inputs: OldHealth and OldNutrition to determine if it is necessary
Outputs: the status bar at the top of the screen
Method: Redraw the status bar if information has changed regarding
Cuzzie's health or score.  Uses DrawText by Andrew Kreps from MP4

The following few functions were all taken from MP4

DrawText  - used from MP4 by Andrew Kreps
  
ModeGraph  - from MP4 by Mike Kasper
Switches to 320x200x256 VGA using a VBIOS Mode 13h call

ModeText  - from MP4 by Mike Kasper
Switches to 80x50 text mode

LoadPCX  - from MP4 by Mike Kasper
Loads (decompresses) a .PCX image into a specified segment.
INPUTS
    AX = offset of segment to write into
    DX = offset of string to filename to read from


InitBuf  - modified from MP4 by Mike Kasper
Initializes the ScreenBuffer to Black pixels
Outputs: Writes to ScreenBuffer 

DrawPoint - modified from MP4 by Mike Kasper
Inputs: (X,Y,Color) 
Outputs: Writes a color value to ScreenBuffer

DrawScreen - modified from MP4 by Mike Kasper
Blasts ScreenBuffer onto the video page.
Outputs: Writes directly to Video RAM 

InstTimer - Taken from MP3 by Mike Kasper
Outputs : oldTimerV

DeInstTimer - Taken from MP3 by Mike Kasper
Inputs : oldTimerV

MyTimerHandler - Taken from MP3 by Mike Kasper
Increment the timerCount

InstKey - Taken from MP3 by Mike Kasper
Outputs : OldKeyV

DeInstKey - Taken from MP3 by Mike Kasper
Inputs : OldKeyV

MyKeyHandler - Modified from MP3 by James Oliver

DrawTile - by Mike Kasper
Inputs: X:byte, Y:byte, Orientation:byte, Location:word
Outputs: writes the graphical tile to ScreenBuffer
Using the coordinates of the upper-right hand corner of the tile on the screen
and the location in bugs.pcx of the tile to put there, this function draws the
image, or at least call DrawPoint to draw it, all in the right orientations.

ShakeItBaby - by Mike Kasper
Inputs: X1:byte, Y1:byte, X2:byte, Y2:byte, BugName:byte, Facing:byte, Frame:byte  
Outputs: causes all the bugs (including cuzzie) on the screen to move towards their
         next locations
Using the positions on the screen of the tiles to redraw, the name of the bug to draw,
its orientation in space, and the frame number from zero to seven, this program block
tells the DrawTiles procedure what to draw and where. Specifically it gives the memory
location in the BugsSeg to be draw to position (X*20,Y*20) in the VIDSEG.

GamePlay - by Mike Kasper
Inputs : CurrentLevel, LevelGrid, Bugs  
Outputs : The next level of the game
Purpose : Actually produces the game interface

    Using the LevelGrid and Bugs starting locations, GamePlay
gets the bugs new locatations by calling functions to move them.
Once it has these, GamePlay calls UpdateStatus, then uses the
timer interrupt to cycle through the different frames for each
bug in motion, producing the visual effect of movement.  After
animation is completed, by calling DrawMoves at each timer
increment, GamePlay loops back to keep Cuzzie on the move.
Cuzzie can begin movement independent of the other frames.

CheckGrid - By Mike Kasper
Inputs  : DH,X  DL,Y
Outputs : DX,0 or 1  
Purpose: Simply determines if a square is a wall

TheExterminator - By Mike Kasper
;With inputs of Bugs the array, it determines if Cuzzie
;kills anyone when she attacks based on all their positions
;And the direction that she is facing when she attacks
 
MoveEarwig - by James Oliver
;Purpose: update the earwig's next position
;and hurt Cuzzie if they come in contact
Inputs: Bugs the original
Outputs: Bugs the updated

MoveSpider - by James Oliver
;This procedure functions the same as MoveEarwig,
; but instead of moving left and right,
;spiders move up and down
Inputs: Bugs the original
Outputs: Bugs the updated

MoveHornet - by James Oliver
;Functions like MoveEarwig, but doesn't move 
;on the ground so it only needs to 
; check for the wall case
Inputs: Bugs the original
Outputs: Bugs the updated

MoveSlug - by James Oliver
;Functions like MoveSpider, but has to check
;for four possible positions intead of 2
;it still moves up and down, but has to check
;what the feet positions are.
Inputs: Bugs the original
Outputs: Bugs the updated

MoveFly - by James Oliver
Inputs: Bugs the original
Outputs: Bugs the update
Simply calls MoveHornet since flies
and hornets will use the same AI

MoveAnt - by James Oliver
Inputs: Bugs the original
Outputs: Bugs the updated
Simply calls MoveEarwig since earwigs
and ants will use the same AI

MoveTermite - by James Oliver
Inputs: Bugs the original
Outputs: Bugs the updated
Simply calls MoveEarwig since termites
will also use the same AI as earwigs

MoveTussie - by James Oliver
This stub function never got used for anything
but it's still here because it
holds a place in the functions jump table

MoveFuzzie - by Jame Oliver
Same as MoveTussie, never used but stub exists

MoveCuzzie - by James Oliver
;Purpose: take care of the cases when the bug
;reaches a corner or wall and
;changes the orientation


CuzzieAttack - by James Oliver
Later rewritten as TheExterminator but left 
as evidence of the work involved

main  ;By Mike Kasper

     Main calls GamePlay, the introduction and the final screen,
stops the MIDI at the end and take scare of globals like those.  This handles moving between  levels and dying in the end.



 
To find out more about this curious caterpillar,
email
mkasper@uiuc.edu.