.....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.