ECE 291 Final Project:
Team Members:
Shane Ryoo: Introduction, Menus, Timing, Credits
Paul Voelker: Networking
Bob Waldrop: Graphics & Game Engine
Jeff Gomberg: Game Engine / Physics
Darrell Micheli: Music & Sound FX
Introduction
In the olden days, people played Asteroids, a game
where one pilots a starship through the midst of asteroids,
attempting to destroy them before they destroy the pilot. And
there would be UFOs flying around, trying to destroy you as well.
However, humanity always fights among itself. And thus...
Description of Game
This two player game is very similar to any other space duel
that you may be familiar with. Two ships with equal
capabilities (not necessarily equal in all categories) fight each
other on a single space map. A nearby gravity well (a
planet) gravitationally affects space travel and makes the game
play more interesting. The game concludes with the
destruction of an opponent or a cry for uncle by hitting the
escape key. Network and sound enchanced play make the
battle more realistic and a choice of five different ships make
game play more random. This game is essentially a two
player Asteroids or Comet Busters without the asteroids.
This is more advanced than anything we're seen in the 291
final projects, because it will have a gravity well, multiple
ship types, and the destruction beam (which is basically a
lightsaber from Star Wars, except for a spaceship). Music
and good sound FX will be included, networking (via NetBIOS) will
be an option (although it was not integrated at the time of
handin), and the graphics will be encoded in PCX format.
Implementation
The best way to describe the general workings of this project
is to point out how the work has been divided among the team
members. Five members of the team are in charge of the
following segments of work: Non-game code (intro, menus,
credits, etc.), sound, physics, graphics and networking.
The game first loads with the THX header seen in movie
theaters. Then a "Productions" screen, and then the
title screen (at the beginning of the page) comes up. These all
fade in and/or out, using several subroutines. Next, the menu
screen fades in. It allows players to choose one of five
different ship types. Each of the ships will have different
abilities including thrust, angular velocity, number of special
weapons and shields, but all ship abilities will be normalized
(e.g. a faster ship may have fewer shields than in its slower
counterpart or a ship with more special weapons may have a slower
angular velocity). This is accomplished with a large array
of values for each ship description (in the form of a look up
table). This is important, as ships that turn very fast have
fewer images to cycle through when turning than ships that turn
more slowly. The graphics holding all the different directions of
two different ships are shown below.
Each ship is designated by a number, with the first number
pressed being assigned to Player One, the next to Player Two, and
it toggles back and forth. For a networked game, the server will
take the ship it selected for Player One, and the client will
take the ship it selected for player Two.Then the players choose
the type of game they want: Non-networked, networked server, or
networked client (although with the way our network code was
developing, one networked selection would have been sufficient).
One can also look at the instructions, or exit.
The playing field for the ships is a 320 X 200 resolution
screen background with a singular, fixed light source.
Thus, when a ship's image is loaded at a particular angle, the
graphic (sprite) will be lit on the side facing the fixed light
source. The light source intensities will not change with
distance from the source (for simplicity). There will also
be a gravity well that will affect/hinder travel. Ships that fly
off of the screen will be looped back around to the next part of
the screen using location mod screen height/width (and a few
other modifications). The physics section of the game
(along with the graphics section) will determine ship positions
and angles (along with the weaponry) based on the gravity well
and user inputs. As soon as position calculations finish and the
network has been updated, the changes will be posted to the CRT.
Lastly, the sounds corresponding to a hit, explosion and
potentially a collision will be sent to the sound card.
Graphically, ships and explosions are drawn from offsets into
a PCX file. The relevant part of the explosions file is to the
right.
The networked part of the game will set up one machine as the
server and another as a client. The client machine will
send interrupt data from the keyboard/mouse to the server for
processing. The server will then return calculated data
concerning ship (and weapon fire) location and sound to the
client, for refreshing. The variables changed by interrupts on
the server machine (by the player on the server) will be used
along with the client data to determine new ship positions and
weapon fire. A large array will be the medium for updates
on both machines. The data sent to the server will, of
course, also be used to update the server's CRT.
As stated before, the program itself begins with an
introduction. Then a graphical menu comes with options for ships,
and to start a game as either the game server, game client, or a
dual-player single computer game. There are also options for
instructions or exiting.
The empty combat area is displayed to the right. Status bars,
ships, and destruction beams are drawn separately.
At the beginning of a match, Player One starts in the upper
left part of the screen, and Player Two starts in the lower left
part of the screen. The planet is in the middle right of the
screen. The match continues until one of the players dies or the
escape key is hit. If a player died, a "Player #"
screen comes up. In any case, the program returns to the menu
screen, and everything starts over again.
When exiting is selected, the program simply fades in and out
several different pcx files.
We have included pseudocode for the game engine for perusal.
Screen Shots
Action Shot With
Line Clip

Action
Shot--Special Weapon

Exploding Ship Screen
Shot

Main Menu
Selection Shot

void GAME_ENGINE (global variables){
setup_game_data();
install_key_interrupt handler();
load_background_screen();
load_selected_ships_into_buffer();
while(!esc_key){
update_ship_locations(); //calls physics calculations
update_weapon_fire();
//checks for collision with planet/ship
//and updates shields
update_statistics();
if(ship == destroyed){
do_explosion();
break;
//and makes the appropriate sound calls.
//This only changes the ship of interest
}
if(ship == hit){
update_shields_block();
//shows the shields blocking the fire
//from reaching the hull. (another sprite)
if(network_is_on)
send(global_array);
erase_old_ship_locations();
erase_old_weapon_fire();
draw_ship_locations(); //to screen buffer
draw_weapon_fire(); //to screen buffer
display_changes(); //to Vid segment
play_sounds(); //to card
}
Updated game engine loop:
void GAME_ENGINE (global variables){
setup_game_data();
install_key_interrupt handler();
load_background_screen();
load_selected_ships_into_buffer();
while(!esc_key){
adjustangles();
update_ship_locations(); //calls physics calculations
erase_old_ship_locations();
erase_old_weapon_fire();
drawship();
drawlaser(); //if interrupt called
play_laser_sound();
if(ship == hit){
update_shields_block(); //shows the shields blocking the fire
//from reaching the hull. (another sprite)
if(ship == collision)
update_shields_block();
if(ship == destroyed){
do_explosion(); //This only changes the ship of interest
break; //and makes the appropriate sound calls.
}
update_statistics();
drawship(); //must be done because the laser is overlapping
//draws ship according to calculations in collision attack
}
Here are the segments used by the program.
VIDSEG--has the actual Screen Segment
SBSEG--has the ScreenBuffer
SHAPES_SEG--(may need two+ of these for our five ships) holds the
sprites of the various ships.
TEST_SEG--contains a two color map of objects that can be checked
for collisions
Here are the general variables used by the program.
Picture variables
KeyPic db 'grphx/Keys.PCX', 0
TestPic db 'grphx/Test.PCX', 0
ShipOne db 'grphx/ShipOne.PCX' , 0
ShipTwo db 'grphx/ShipTwo.PCX' , 0
ShipThree db 'grphx/ShipTh~1.PCX' , 0
ShipFour db 'grphx/ShipFour.PCX' , 0
ShipFive db 'grphx/ShipFive.PCX' , 0
ExplodePic db 'grphx/Explos~1.PCX' , 0
BackgroundPic db 'grphx/backgr~1.PCX' , 0
TestgroundPic db 'grphx/testgr~1.PCX' , 0
OneWon db 'grphx/onewins.pcx', 0
TwoWon db 'grphx/twowins.pcx', 0
Sound variables
TempSound db 'sound/laser.wav', 0
ST_EXP db 'sound/ST_EXP.wav', 0
Kombat db 'sound/mktheme.xmi', 0
Collide db 'sound/crash.wav', 0
Variables for velocities of different
ships (word length)
MAX_VELOCITY_ONE = 7
MIN_VELOCITY_ONE = -7
MAX_VELOCITY_TWO = 7
MIN_VELOCITY_TWO = -7
Temporary variables (word-length)
temp
tempx1
tempx2
tempy1
tempy2
tempgravityx
tempgravityy
Ship statistics (word-length)
ship_one_gravity_x
ship_one_gravity_y
ship_two_gravity_x
ship_two_gravity_y
ship_one_thrust = 10
ship_one_velx
ship_one_vely
ship_two_velx
ship_two_vely
twelve = 12
shipvelx1 (24 words long)
shipvely1 (24 words long)
shipvelx2 (24 words long)
shipvely2 (24 words long)
ship_two_thrust = 10
planetx = 220
planety = 80
planetr = 16
Graphics Variables (byte-length)
Color_Red
Color_Green
Color_Black
Color_White
GRAPHIC_ROW_LENGTH
GRAPHIC_ROW_LENGTHX2
SHIP_COLOR
Explosion variable (word-length)
END_OF_HORIZ_BLOW
Test variables
SHIP_ONE_TEST_OFFSET (word)
SHIP_TWO_TEST_OFFSET (word)
SHIP_TEST_OFFSET (word)
SHIP_TEST_COLOR (byte)
Collision variables (byte-length)
SHIP_ONE_HIT
SHIP_TWO_HIT
SHIP_ONE_DEAD
SHIP_TWO_DEAD
ship1planet
ship2planet
shipcollision
TransparentTable (3 words)
ShipTable (5 words) - offsets of the
ships
Region Variables
TopMargin (word)
BotMargin (word)
LeftMargin (word)
RightMargin (word)
RegionCode (byte)
EndPointDrawX (word)
EndPointDrawY (word)
RegionTable (13 words) - contains
offsets of
State Variables
SHIP_ONE (byte)
SHIP_TWO (byte)
SHIP_ONE_R (byte)
SHIP_TWO_R (byte)
SHIP_ONE_R_WORD (word)
SHIP_TWO_R_WORD (word)
SHIP_ONE_ROWS (byte)
SHIP_TWO_ROWS (byte)
SHIP_ONE_ROWS_WORD (word)
SHIP_TWO_ROWS_WORD (word)
SHIP Position/Orientation variables.
MAX_ANGLE_ONE (byte)
MAX_ANGLE_TWO (byte)
ANGLE_ONE (byte)
ANGLE_TWO (byte)
PLAYER_ONE_X (word)
PLAYER_ONE_Y (word)
PLAYER_TWO_X (word)
PLAYER_TWO_Y (word)
ROTATE_AMOUNT_ONE (word)
ROTATE_AMOUNT_TWO (word)
ROTATE_AMOUNT_ONE_MINUS (word)
ROTATE_AMOUNT_TWO_MINUS (word)
Old Position/Orientation variables
OLD_PLAYER_ONE_X (word)
OLD_PLAYER_ONE_Y (word)
OLD_PLAYER_TWO_X (word)
OLD_PLAYER_TWO_Y (word)
OLD_ANGLE_ONE (byte)
OLD_ANGLE_TWO (byte)
Keyboard Interrupt Variables
OldKeyBoardSegment - segment location of old handler
OldKeyBoardOffset - offset of old key handler
Key Flags (all byte-length)
ESC_KEY
ROTATE_LEFT_ONE
ROTATE_LEFT_TWO
ROTATE_RIGHT_ONE
ROTATE_RIGHT_TWO
THRUST_ONE
THRUST_TWO
FIRE_ONE
FIRE_TWO
SPECIAL_FIRE_ONE
SPECIAL_FIRE_TWO
EXTENDED_KEY_HIT
Line Drawing Values (all word-length)
LASER_DELTA_X
LASER_DELTA_Y
LASER_START_X
LASER_START_Y
LASER_END_X
LASER_END_Y
LASER_COLOR
LASER_PK_SMALL
LASER_PK_BIG
X_STANDARD_ADD
Y_STANDARD_ADD
X_SPEC_SMALL_ADD
Y_SPEC_SMALL_ADD
X_SPEC_BIG_ADD
Y_SPEC_BIG_ADD
PK_IF_SMALL
PK_IF_BIG
Constants
ThreeTwenty = 320
MAX_LASER_R = 55
Timer variables
Delta_Time (word) - increments every 1/18.2 sec.
FadeTimeDelay (word)
Old_Timer (double word) - stores the segment and offset of the
old timer interrupt
Fading variables
Palette (768 bytes) - stores the values of the palette registers
in the video card
BoxOffset (5 words) - stores the offset locations of the menu
boxes
Menu/key variables
ShipType (word) - contains the ship number for players one and
two
GameType (byte) - determines where to go from the menu screen
Continue (byte) - flag to exit quickly during the intro and
credits
Keyboard interrupt variables
(word-length)
MenuKeySeg - old keyboard interrupt's segment
MenuKeyOff - old keyboard interrupt's offset
Networking Variables
PlayerName - unique name for player on NetBIOS
PlayerNum - number for game player assigned by NetBIOS
GroupName - unique name for game group on NetBIOS
GroupNum - number for NetBIOS group assigned by NetBIOS
SendPacket - send NCB
ReceivePacket - receive NCB
SendBuffer - data structure for sending data
ReceiveBuffer - data structure for receiving data
Server - flag indicating whether or not system is the game server
Connected - connection status flag
Procedures
Game Physics Procedures
All code in this section written by Jeff Gomberg.
BuildTables
- Purpose: To construct initial lookup tables for
moving ships and bullets around the screen.
- Inputs: none
- Outputs: shipvelx1, 2 and shipvely1, 2 are filled
- Calls: none
- Description: This function uses the FPU to make
the tables used for calculating the ships' velocity in
the x and y directions in shipvelx1 and 2 and shipvely 1
and 2. The tables correspond to a direction variable 0
through 23 which corresponds to direction*12/pi radians
for the ship pointing direction.
CalcDistance
- Purpose: takes two positions (tempx1, tempy1) and
(tempx2, tempy2), and gives a rough approximation of the
pixel distance between them.
- Inputs: tempx1, tempy1, tempx2, tempy2
- Outputs: ax - distance
- Calls: none
- Description: Uses the FPU. Used for
CollisionDetect.
CalcGravity
- Purpose: Puts in the change of velocity due to the
gravity of the planet at a point tempx1,tempy1 into
tempgravityx and tempgravityy.
- Inputs: tempx1, tempy1, planetx, planety
- Outputs: tempgravityx, tempgravityy
- Calls: CalcDistance.
CollisionDetect
- Purpose: Detects any collisions.
- Inputs: planetx,planety,planetr,all ship
variables.
- Outputs: to the flag variables
ship1planet,ship2planet,shipcollision
- Calls: CalcDistance.
CalculateMovement
- Purpose: Finds the final velocity vectors of the
ships, including gravity.
- Inputs: ship_one,two_velx,y shipvelx,y
angle_one,two Thrust_one, Thrust_two
- Outputs: ship_one,two_velx,vely
ship_one,two_gravity_x,y
- Calls: CalcGravity.
ProcessMovement
- Purpose: Changes the coordinates of the ships,
boundary checks it and changes velocities if a collision
occurs.
- Inputs:
player_one_x,player_one_y,player_two_x,player_two_y,
gravity variables, velocities
- Outputs:
ship_one_old_x,ship_one_old_y,ship_two_old_x,ship_two_old_y,
ship_one_x,ship_one_y,ship_two_x,ship_two_y
- Calls: CollisionDetect
Game Graphics and Keyboard Procedures
Code written by Bob Waldrop.
Run_Game
- Purpose: calls for game initialization and
variables and then loops the game play
- Inputs: All variables and sements pertaining to
game play are used by this function or a function which
it calls.
- Outputs: Display of the game, setup of game data
- Description: This function contains the main game
looper loop exits if the escape key is hit.
- Notes: Calls DrawShip, CheckLasers,
UpdateStatistics, SetUpGame, EraseShips, etc.
Inst_Key
- Purpose: Install a key interrupt handler for the
game play
- Inputs: Via Dos interrupts, the pointer to the
original handler
- Outputs: Places the KEY_HANDLER function pointer
in the interrupt table. Also saves the old function
pointer to... OLD_KEY_OFFSET OLD_KEY_SEG
- Notes: Takes all keyboard values for
game loop and play for both players
Remove_Key
- Purpose: Removes the custom key handler fxn.
pointer from the Vector table and restores the old one.
- Inputs:
- OLD_KEY_OFFSET
- OLD_KEY_SEG
- Outputs: Restores old handler to table.
Key_Handler
- Purpose: Handles the key detection for game play
- Inputs: ESC_KEY, ROTATE_LEFT_ONE, ROTATE_LEFT_TWO,
ROTATE_RIGHT_ONE, ROTATE_RIGHT_TWO, THRUST_ONE,
THRUST_TWO, FIRE_ONE, FIRE_TWO SPECIAL_ONE, SPECIAL_TWO
- Outputs: These variables are adjusted
appropriately
Update_Statistics
- Purpose: Change each player's statistics on the
screen
- Inputs: SHIELDS_ONE, SHIELDS_TWO, SPECIALS_ONE,
SPECIALS_TWO, SBSEG
- Outputs: Screen statistics for each player are
changed.
- Notes: calls UpdateDisplay to show the
actually green and red pixel values for the shields and
special weapons
ExchangeBuffer
- Purpose: Load a given buffer into another buffer
- Inputs: ax has source buffer, bx has destination
buffer
- Outputs: ax = ax, and bx = ax
- Description: This can be used for taking the SBSeg
to VIDSEG or TESTseg to ScRSeg, etc.
Test
segment test example map

Draw_Ship
- Purpose: Set up the loop for drawing or erasing a
ship at a particular X, Y with a particular angle
- Inputs: SBSEG, SHIP_#_X, SHIP_#_Y, ANGLE_#,
OLD_SHIP_#_X, OLD_SHIP_#_Y, SHIP_#_TEST_OFFSET,
SHIP_#_TEST, SHIP_#_R and various color constants.
- Outputs: The ship(s) is drawn/erased to/from the
ScreenBuffer and Test segment with the correct
orientation and position
- Description: See note about collisions above.
- SPECIAL CLIPPING NOTE: Special region
code testing was performed to see how to clip the ships.
There were nine regions tested with region codes as shown
in the graphic below.

DrawLaser
- Purpose: Set up the loop for drawing/erase lasers
to/from the SBSeg and TESTseg to PLAYER_#_X, PLAYER_#_Y
- Inputs: Too many to list but all Angle#Offsets,
ANGLE_#, OLD_ANGLE_#, OLD_PLAYER_#_X, OLD_PLAYER_#_Y,
PLAYER_#_X, PLAYER_#_Y, etc.
- Register inputs include: ah = 0 means
erase, ah = 1 means with player colors, ah = 2 means with
special color, al contains the player#
- Outputs: A laser drawn/erase to/from the SBSEG and
TESTseg
- Description: This was performed using the midpoint
line algorithm derivation for high speed integer
graphics which can be generalized to many function shapes
such as circles, parabolas, etc.
Explode_Ship
- Purpose: Show the ship blowing up.
- Inputs: SBSEG, SHIP_#, SHIP_#_X, SHIP_#_Y
- Outputs: An animated explosion of the ship.
- Description: We make the explosion look the same
regardless of the ship. (calls BlowUpProc)
UpdateDisplay
- Purpose: Update the status bar of game
display
- Inputs: Shield#Offset, Special#Offset,
StatusBarLengths
- Outputs: Status levels updated on screen
- Notes: Used in Run_Game
SetUpGame
- Purpose: Initialize game variables for
game play
- Inputs: Nearly every variable above
- Outputs: Variables set to appropriate
values
- Notes: called before game loop
SetupAngleOffsets
- Purpose: Create a tables of all of the
ships offsets in Ship segments
- Inputs: AngleOneOffset, AngleTwoOffset,
SHIP_ROWS, SHIP_RADII
- Outputs: Angle###Offset arrays set up
- Notes: called by SetUpGame
AdjustAngles
- Purpose: Adjust ANGLE_# variables if
keyboard variables are changed
- Inputs: ROTATE_LEFT_#, ROTATE_RIGHT_#
- Outputs: ANGLE_#
- Notes: called in game loop
CheckLasers
- Purpose: Check key variables for laser
fire and then display if appropriate
- Inputs: SPECIAL_FIRE_#, FIRE_#
- Outputs: calls DrawLaser
- Notes: Used in Run_Game
SetUpLaserDeltas
- Purpose: Set up tables for
LASER_DELTA_X, LASER_DELTA_Y
- Inputs: COS_TABLE, SIN_TABLE (offsets),
MAX_LASER_R
- Outputs: COS_TABLEGOOD, SIN_TABLEGOOD
- Notes: Uses the fpu
ExplodeShip
- Purpose: Show the ship blowing up.
- Inputs: SBSEG, SHIP_#, SHIP_#_X,
SHIP_#_Y
- Outputs: An animated explosion of the
ship.
- Notes: We make the explosion look the
same regardless of the ship.
BlowUpProc
- Purpose: Draw a sprite for ship
explosion
- Inputs: EXPLOSION_OFFSET,
EXPLOSION_RADIUS
- Outputs: Sprite on the screen at X, Y of
loser
- Notes: Explosion looks the same
regardless of ship
ExchangeBuffer
- Purpose: Changes the location of a
buffer's data to that of another
- Inputs: ax has source bx has destination
- Outputs: Swaps the buffers
- Notes: Modification of mp4's
ShowScreenBuffer
Introductory and Menu Procedures
Code written by Shane Ryoo.
Timer Interrupts
- See inside the networking section.
LoadFADEPCX
- Inputs:
- ax - destination segment address
- dx - pointer to a null-terminated string
containing the filename
- Outputs:
- Palette - array containing the palette entries of
the PCX file
- DestSeg:0 is filled with image data
- VGA palette registers store image colors
- ScratchPad holds compressed image data
- Description: loads a PCX file similar to MP4, but
saves the palette values in the Palette array.
ShowScreenBuffer
- Purpose: Move 320x200 pixels of screen data to
screen
- Inputs: ScreenBuffer
- Outputs: none
- Description: transfers the contents of the
graphics buffer to the screen. Most other drawing will be
done directly to video memory.
Blackout
- Purpose: Blacks out the screen in preparation for
a fade to values in Palette
- Inputs: none.
- Outputs: Sets all video palette registers to
black.
Fade
- Purpose: Fades the screen in a certain way,
depending on inputs.
- Inputs: ax =
- bl =
- -1 - fade to black
- 0 - fade to colors in palette
- 1 - fade to white
- Palette - array containing the palette values
- Outputs: screen, Palette (destroyed when fading to
black or white)
- Description: This accesses Palette, an array
containing the palette values of the currently loaded
graphic, to create fading. Values in the palette
registers (on the video card) are either incremented or
decremented to get to the appropriate values.
DrawBoxes
- Purpose: Draw a green box around Player One's
ship, a red box around Player Two's ship, and nothing
around the others.
- Input: ShipType
- Output: screen
- Calls: DrawBox, DrawBigBox
- Description: First, it draws black around all ship
graphics, then uses a jump table to draw the boxes in the
correct places.
DrawBox
- Purpose: Draw a box of set size and color with
palette entry in dx, with its upper left corner at an
offset in bx
- Inputs:
- dx - palette entry of color of box
- bx - offset of the upper left corner of the box
- Output: screen
DrawBigBox
- Purpose: Draw a box of set size (larger than
DrawBox) and color with palette entry in dx, with its
upper left corner at an offset in bx
- Inputs:
- dx - palette entry of color of box
- bx - offset of the upper left corner of the box
- Output: screen
MenuKeyInt
- Purpose: IRQ 9 keyboard interrupt handler
- Input: buttons on keyboard
- Outputs: ShipType, GameType, Continue
InstMenuKey
- Purpose: Install new keyboard interrupt and saves
old one.
- Inputs: none.
- Outputs: MenuKeyOff, MenuKeySeg
DeInstallMenuKey
- Purpose: Deinstall keyboard interrupt and restore
previous one.
- Inputs: MenuKeyOff, MenuKeySeg
- Outputs: none.
Networking Procedures
Code written by Paul Voelker.
Networking Implementation: For all game data
transmission over the network we were going to use NetBIOS.
Professor Lockwood's example code, the "CBIS Net BIOS
Programmer's Reference" by Tom Thompson, and the lecture
notes were about the only sources of information available.
Figuring out just how it all worked took quite a bit of time. The
networking did not involve too much code, but it involved much
more research and scratch work. Commands for NetBIOS are issued
by using the NCB (Network Control Block) format. Game data would
have been sent in structures containing critical information
needed by the server or client. The following is a list of
variables related directly to the networking procedures:
- SendPacket NCB <> ;Send network control block
- ReceivePacket NCB <> ;Receive network control block
- SendBuffer SSDD <> ;Data structure for sending game
data
- ReceiveBuffer SSDD <> ;Data structure for receiving
game data
- GroupName db 'UltraSpaceDuel##' ;Unique group name
for game networking
- GroupNum db ? ;Number for group assigned by NetBIOS
at runtime
- PlayerName db 'DuelSpaceCadet?#' ;Unique player name
for game networking
- PlayerNum db ? ;Number for player assigned by NetBIOS
at runtime
- Received dw 0 ;Total number of network packets
received
- Sent dw 0 ;Total number of network packetes sent
- BadPosts dw 0 ;Number of bad posts that occurs (bad
packets)
- Server db 0 ;Flag indicating if machine is the server
or the client
- Connected db 0 ;Connection status flag (0 no
connection / 1 to server / 2 to client)
The model that we were going to use to transfer data over the
network was the server/client model. Originally we thought about
using a peer-to-peer type of model. However, after conversing
with several previous ECE 291 students, we found we would have
big problems with synchronization. One system would get ahead of
the other resulting in program errors or unrealistic game play.
Basically the one system, the server, handles all calculations
and event handling. The client sends data the server needs for
calculations (which is primarily just keyboard presses) and gets
information back so the display and sound can be maintained.
However, due to complications and lack of time, the networking
procedures were not integrated into the main program. They were
however coded and fully tested on an independant basis. The file
called "network.exe" is the executable demo of the
networking procedures and "network.asm" is the
associated source code.
AddNetGroup
- Purpose: Adds game group to NetBIOS
- Variables: SendPacket - send NCB
- Inputs: SI - offset of group name to add (must be
16 bytes long and assumes located in code segment)
- Outputs:
- AL - NetBIOS error code, 0 if no error
- AH - assigned number for net group
- Description: Using the send packet NCB and NetBIOS
command 036h, the group name for the game is added to the
NetBIOS table. If the group name already exists, the
procedure exits with an error code in AL other than 0.
NetBIOS automatically assigns a number to the group,
which is returned in AH.
AddNetName
- Purpose: Adds player name to NetBIOS
- Variables: SendPacket - send NCB
- Inputs: SI - offset of player name to add (must be
16 bytes long and assumes located in code segment)
- Outputs:
- AL - NetBIOS error code, 0 if no error
- AH - assigned number for player
- Description: This procedure in very similar to
AddNetGroup. Using the send packet NCB and NetBIOS
command 0B6h, the name pointed to by register SI is added
to the NetBIOS table. If the player name already exists,
the procedure exits with an error code in AL other than
0. Again, NetBIOS automatically assigns a number to the
name which is returned in register AH.
RemoveNetName
- Purpose: Removes player or group name from NetBIOS
- Variables: SendPacket - send NCB
- Inputs: SI - offset of name to remove from NetBIOS
- Outputs: AL - NetBIOS error code, 0 if no error
- Description: This procedure handles removing both
group and player names from the NetBIOS table. The send
packet NCB and NetBIOS command 031h is how it is
accomplished. If the remove was unsuccessful, an error
code other than 0 will show up in register AL. This
procedure will only remove the one player or group name
pointed to by SI in one call.
SetupPackets
- Purpose: Sets up NCB packets and game data packets
- Variables:
- SendBuffer - data structure for sending game data
- SendPacket - send NCB
- ReceivePacket - receive NCB
- PlayerNum - name number assigned by NetBIOS
- GroupNum - group number assigned by NetBIOS
- Server - server identification, 1 if server and 0
if client
- Inputs: none
- Outputs: none
- Description: The receive NCB, send NCB, and game
data packets are initialized in that order. The following
lists show the data modified:
Receive NCB Packet
- command <===== NetBIOS receive datagram command (0A1h)
- num <========= group number
- buffer_off <== offset of receive game data packet
- buffer_seg <== segment of receive game data packet
- buffer_len <== length of game data packet
- post_off
<==== offset of post interrupt handler
- post_seg <==== segment of post interrupt handler
Send NCB Packet
- command <===== NetBIOS send datagram command (0A0h)
- num <========= player number
- callname <==== name of group (UltraSpaceDuel##)
- buffer_off <== offset of send game data packet
- buffer_seg
<== segment of send game data packet
- buffer_len <== length of game data packet
- post_off <==== set to 0 since no post required
- post_seg <==== set to 0 since no post required
Send
Game Data Packet
- PlayerID <=== 1 if server / 0 if client
InitGame
- Purpose: Initializes
communication over network for
game play
- Variables:
- SendBuffer - data
structure for sending
data
- RecieveBuffer - data
structure for receiving
data
- SendPacket - send NCB
- ReceivePacket - receive
NCB
- PlayerNum - name number
assigned by NetBIOS
- GroupNum - group number
assigned by NetBIOS
- Server - server
identification, 1 if
server and 0 if client
- GroupName - unique name
for game group
(UltraSpaceDuel##)
- PlayerName - unique name
for player
(DuelSpaceCadet?#)
- Connected - NetBIOS
connection flag (0 none /
1 to server / 2 to
client)
- Inputs: none
- Outputs: none
- Description: First the
procedure attempts to add the
game group name by making a call
to AddNetGroup. If an error
occurs a message is displayed on
the screen by NetBIOSMessage and
the procedure is ended. Else the
player name is added. Two player
names are possible since there
are two players in the game.
First the primary player (or
server) is attempted. If not
successful, the secondary player
(or client) is attempted. If that
fails a message is displayed by
NetBIOSMessage, the group is
removed and the procedure is
terminated. Next SetupPackets is
called and the data connection
process begins. If the player is
the server, they will send out a
game request signal every 1/2
second until a acknowledgment is
received from a client. ESC may
be pressed while waiting for a
client in case of problems. If
the player is the client, they
wait for a request game signal
from a server and then the client
sends an acknowledgment back.
Again ESC may be pressed to halt
waiting for the server. If this
is all successful, the send game
data command is set to update
data mode and a message is
displayed confirming a network
connection. Also a connection
flag (Connected) is set, where 0
means no connection, 1 means a
connection to a server, and 2
means a connection to a client.
Network game play can now occur.
TermGame
- Purpose: Terminates
communication over network
- Variables:
- PlayerName - unique name
for player
- GroupName - unique name
for game group
- Connected - NetBIOS
connection flag (0 none /
1 to server / 2 to
client)
- Inputs: none
- Outputs: none
- Description: Calls
RemoveNetName for player name and
group name on NetBIOS. In case of
error, messages are displayed
using NetBIOSMessage. Upon
completed termination, a message
is displayed confirming this and
Connected is set to 0.
PostReceive
- Purpose: ISR for incoming
packets from network
- Variables:
- ReceivePacket - receive
NCB
- ReceiveBuffer - data
structure for receiving
data
- Connected - NetBIOS
connection flag (0 none /
1 to server / 2 to
client)
- BadPosts - statistical
counter for number of bad
posts received
- Received - statistical
counter for number of
post received total
- Game data variables
- Inputs: none
- Outputs: none
- Description: This is an
interrupt routine called any time
data packets come in from the
network. The type of data is
determined and handle accordingly
(initiate game, end game, and
games data for either players).
Bad posts are detected by looking
at retcode in ReceivePacket. At
the end NetBIOS is reset to
receive data.
ReceiveNetData
- Purpose: Instructs system
to keep aware of incoming network
packets
- Variables: none
- Inputs: none
- Outputs:none
- Description: This
procedure initializes the system
to receive network data packets
over NetBIOS. Execution of
NetBIOS command 0A1h does this.
PostReceive handles any packets
that come in.
SendNetData
- Purpose: Sends game data
across network
- Variables:
- SendBuffer - data
structure for sending
data
- Connected - NetBIOS
connection flag (0 none /
1 to server / 2 to
client)
- Server - server
identification, 1 if
server and 0 if client
- Sent - statistical
counter for total number
of packets sent
- Game data variables
- Inputs: none
- Outputs: none
- Description: This
procedure sends data across the
network based on if the player is
the client or server. Data is
sent by using the send NCB, game
data packets and NetBIOS command
0A0h.
NetBIOSMessage
Timer Interrupt Procedures
Code written by Paul Voelker (also
written by Shane Ryoo, but scrapped
because it had exactly the same
functionality).
GameTimer
- Purpose: Timer for game
- Variables:
- Delta_Time - clock tick
counter
- Old_Timer - location of
original timer interrupt
- Inputs: none
- Outputs: none
- Description: Every 1/18th
of a second Delta_Time is
incremented. Note that the
original timer interrupt is
called.
InstallTimer
- Purpose: Installs game
timer interrupt
- Variables: Old_Timer -
location of original timer
interrupt
- Inputs: none
- Outputs: none
- Description: Installs game
timer interrupt and saves
location of original interrupt in
Old_Timer.
DeinstallTimer
- Purpose: Removes game
timer interrupt and restores
original one
- Variables: Old_Timer -
location of original timer
interrupt
- Inputs: none
- Outputs: none
- Description: Removes game
timer interrupt and restore
original one by calling int 21h.
Sound Procedures
Code written by Darrell Micheli.
LoadSound
- Purpose: Load a Midi file
into memory.
- Inputs:
- AX - Segment where sound
is to be held in memory.
- DI - Offset to memory
location for sound
storage.
- CX - Length of sound to
loaded (in bytes).
- DX - Offset to string
with filename.
- Outputs: none
- Description: This function
uses the DOS file command to read
from a specified file and load it
into a specified memory segment
that contains only Midi sound
files. Initially, it utilizes
function 3Dh of int 21h to open
the specified file in the
designated directory. A handle is
returned that can be used by the
program for subsequent access to
the file. Next, function 3Fh is
used to transfer data at the
current file pointer position
from the file into the buffer and
then updates the file pointer
position. Finally, function 3Eh
flushes all internal buffers
associated with the file to disk,
closes the file, and releases the
handle for reuse.
RegisterXMIDI
- Purpose: Registers XMIDI
data.
- Inputs:
- CX - Segment address of
SoundSeg.
- BX - Offset of selected
midi file.
- Outputs: none
- Description: This function
stores the XMIDI data to be
played in Midpak's interal buffer
by using the midipak driver
function 704h on INT 66h.
PlaySequence
- Purpose: Play the
currently registered midi file.
- Outputs: sound (midi file)
- Description: This function
starts the playing of a selected
midi file by using the midipak
driver function 702h on INT 66h.
StopMidi
- Purpose: Stops the
currently playing xmidi file.
- Description: This function
stops the playing of the current
xmidi data by use of Midpak's
function 705h on INT 66h.
SetSoundSettings
LoadWave
- Purpose: Load a selected
wave file to Buffer.
- Inputs: DX - Offset to
string with filename.
- Outputs: Skips header in
wave file and loads the rest in
the designated buffer segment.
- Description: This function
uses the DOS file command to read
from a specified file and load it
into a specified memory segment
that contains only Midi sound
files. Initially, it utilizes
function 3Dh of int 21h to open
the specified file in the
designated directory. A handle is
returned that can be used by the
program for subsequent access to
the file. However, before we can
transfer data we need to skip
over the "Header" of
the wave file since it is not
executable. Next, function 3Fh is
used to transfer data at the
current file pointer position
from the file into the buffer and
then updates the file pointer
position. Finally, function 3Eh
flushes all internal buffers
associated with the file to disk,
closes the file, and releases the
handle for reuse.
RSTDSP
- Purpose: To reset the DSP.
- Inputs: None
- Outputs: Resets the DSP.
- Description: This function
is straight forward in following
an algorithm to reset the DSP.
First we write a 1 to the reset
port. Next, we wait 3
microseconds. Then we write a
zero to the reset port. Finally
we read from the data port
(should be Aah).
DMAInit
- Purpose: Sets up the DMA
Controller in preparation for a
transfer.
- Inputs: None
- Outputs: Sets up
Controller
- Description: This
procedure performs a number of
steps in a defined order. Before
we begin, we calculate the Page
and offset for the DMA
Controller. Next, we start to
setup the DMA Controller by
Masking the DMA Channel. After
this, we clear the Flip Flop.
Third, we write the transfer
MODE. Our next step is to write
the DMA_PAGE Number followed by
the DMA_BASEADDR and DMA_COUNT
Number to their respective ports.
Finally, we Demask the Channel
and exit the procedure.
PlaySound
- Purpose: Play the desired
wave file
- Inputs: None
- Outputs: Plays sound
- Description: First, this
procedure set ups a time
Constant. Next, it programs the
transfer for HIGHSPEED, autoinit
DMA. The transfer is completed by
setting up the DMA Buffersize and
then setting the playmode
correctly.
Operation
The version of Ultra Space Duel
that we handed in runs on a single
computer and two players at the same
keyboard. Given more time, we would have
integrated the networking and had two
players at two different computers, both
having NetBIOS capabilities. One player
starts as the server, the other as the
client. After both players are done
setting up, the game begins. The game
continues until a player quits or dies.
The server will be doing all of the
movement calculations. For more
specifics, see previous sections.
Distribution
Ultra Space Duel is
freeware. If we ever have time to work
some more on it, we might. However, being
ECE majors, we probably won't. The game,
from what we understand, is University
property, as we are doing this as part of
a class. Thus, we cannot license the
rights of the game to anyone, nor can
anyone "borrow" the idea. We
are sorry.
This page was created
and maintained by Shane Ryoo
This page was last updated Friday, May
1st, 1998 A.D. at 0520 hours CST.
(c) Shane Ryoo, Up-All-Night Productions
Asteroids (c) Atari Corporation