SPACE FIGHTER ORANGE - FINAL WRITE UP
Grant Farrand
Bruce Huang
Avon Fernandes
Megan Neumann
Functions written by Grant Farrand
_InitializeTheGame
Inputs: None
Outputs: None
Calls: _ArrayInitialize
Purpose: This function sets the variables in the program to their appropriate initial conditions. The call to _ArrayInitialize will deactivate all enemies on the screen so that the next time through the game there are no “ghost” ships, bullets, or explosions. Various counters that the program uses are reset to 0. The main ship in the game is set back to its starting point at the bottom of the screen, the life and shield energies are set to full, and the life and shield bar pictures are reloaded. The _EnemyArray, containing all the enemies that will be present during game play, is given the following data: positions, velocities, accelerations, and activity. This array will be accessed many times over in the rest of the program. The _BossArray (only containing one element) is initialized as well.
_DoIntro
Inputs: None
Outputs: None
Calls: _CopyToScreen (Lib function), _SB16_Stop, _START, _SUMMER, _CopyFromBackgroundBufferToScreenBuffer
Purpose: This function holds the game at its introduction. It plays the corresponding music and displays the intro picture. It waits for user input via the keyboard (ESC, 1, 2, 3, Space) and acts appropriately. From this function, the user can get to the credits screen, or to the game itself.
_DoGameWin
Inputs: None
Outputs: None
Calls: _CopyToScreen (Lib function), _SB16_Stop, _SUMMER, _CopyFromBackgroundBufferToScreenBuffer
Purpose: This function holds the game at its game win state. It plays the corresponding music and displays the “you win” picture. It waits for user input via the keyboard (ESC or Space) and acts appropriately. From this function, the user can get to the credits screen, or to the introduction.
_DoGameOver
Inputs: None
Outputs: None
Calls: _CopyToScreen (Lib function), _SB16_Stop, _SUMMER, _CopyFromBackgroundBufferToScreenBuffer
Purpose: This function holds the game at its game over state. It plays the corresponding music and displays the “game over” picture. It waits for user input via the keyboard (ESC or Space) and acts appropriately. From this function, the user can get to the credits screen, or to the introduction.
_CopyFromBackgroundBufferToScreenBuffer
Inputs: .src Source buffer pointer (where the pixels are coming
from)
.dst Destination Pointer (where the pixels are going)
Outputs: None
Calls: None
Purpose: This function takes two input pointers, one to the source buffer and the other to the destination buffer. It makes use of one of the MMX registers for the fast transfer of pixels from the source to the destination. Unfortunately, this functions had not been appropriately named. It can be, and is, used as a general buffer to buffer copy function. Its initial intention was for the “scrolling” effect. The source pointer would point to an arbitrary place in a very large picture, and this function copied a small sub-screen of that picture into the destination buffer. The source and destination were to be the background picture and the _ScreenBuf respectively.
_AddBarsToScreen
Inputs: .shld_bar First of two source buffers
.life_bar Second of two source buffers
.dst Destination Pointer (where the pixels are going)
Outputs: None
Calls: None
Purpose: This function copies the two source pictures directly onto the _ScreenBuf. Alpha-Blending was not used here because a direct move is all that is needed (because we didn’t want enemy ships or bullets flying through the life and shield bars) and it is much faster.
_UpdateEnergyBars
Inputs:
.shld_nrg Number between 0-459 that tells gives amount of shield left
.life_nrg Number
between 0-459 that tells gives amount of life left
.shld_src Pointer
to the shield bar picture
.life_src Pointer
to the life bar picture
Outputs: None
Calls: _BlendSpriteOntoBackground
Purpose: This function zeros out the alpha channels in certain rows of the two input pictures according to the two input energies. This gives the effect of the two energy bars draining as the ship takes damage.
_BlendSpriteOntoBackground
Inputs: .src Pointer to the picture to be alpha-blended
onto the screen
.src_Width Width of the source picture
.src_Height Height of the source picture
.dst Pointer to the destination buffer (usually
_ScreenBuf)
.dst_Left X-coordinate of source picture in the
destination buffer
.dst_Top Y-coordinate of source picture in the
destination buffer
Outputs: None
Calls: None
Purpose: This function takes the source picture and alpha-blends it onto the background using the alpha channel of the source. It also utilizes all MMX registers to do two pixels at once. Any general picture can be blended onto any general background picture.
_ActivateEnemies
Inputs: None
Outputs: None
Calls: None
Purpose: This function compares the _EnemyCounter to many predetermined values and sets the .IsActive field of certain enemies to one as the game progresses. It can activate 1, 2, 3, 4, or 7 enemies at one time. The .IsActive field is used to determine whether or not a given enemy should be drawn onto the screen. This function is nothing more than a very large switch statement.
_UpdateEnemyPositions
Inputs: None
Outputs: None
Calls: None
Purpose: This function updates an enemy’s velocity and acceleration each time through the main function. It checks to see if the given enemy has moved off of the viewing area and if so, deletes it.
_DrawAllEnemies
Inputs: None
Outputs: None
Calls: _BlendSpriteOntoBackground
Purpose: This function simply traverses through the _EnemyArray and checks the .IsActive field of each enemy. If it is set, then _BlendSpriteOntoBackground is called and the enemy is drawn onto the viewing area.
_ScoreToText
Inputs: None
Outputs: None
Calls: _DisplayOneScoreDigit
Purpose: This function divides the _Score variable by 10 four separate times and displays the corresponding digit on the screen by calling _DisplayOneScoreDigit with the appropriate inputs.
_DisplayOneScoreDigit
Inputs: .number The actual digit to draw
.place Where to draw it (ones, tens, hundreds… etc.)
Outputs: None
Calls: _BlendSpriteOntoBackground
Purpose: This function takes the number input and does a switch on it. It finds the correct picture for the input number and calls _BlendSpriteOntoBackground according to the .place input.
_KeyboardISR
Inputs: None
Outputs: None
Calls: None
Purpose: This function is a modified keyboard ISR from MP5. The main structure is the same but a few things have been changed. The function simply gets the scancode from the keyboard, translates it into a 1 or 0 in a table called _kbdInputs. It also sets special flags such as _Quit (on ESC), _START (on 1, 2, or 3) and _Space (on the space bar).
Functions written by Bruce Huang
_ArrayInitialize
Inputs: None
Outputs: None
Calls: None
Purpose: Goes through the _movingBullets, _enemyBullets, _ExplodeArray, _EnemyArray
and resets them so that when we reset the game with [esc] they are not drawn
onto the screen by accident
_ShipExplosion
Inputs: None
Outputs: None
Calls: _BlendSpriteOntoBackground
Purpose: this function goes through the 25 different frames of the ship
explosion by comparing the status flag of the ship struct
_EnemyDie
Inputs: .XPos x position of enemy that died
.YPos y position of enemy that died
.XVel x velocity of enemy that died
.YVel y velocity of enemy that died
edi index of the explosion to use
Outputs: None
Calls: None
Purpose: this function is called when a certain enemy dies, and places an
explosion at the same index in the explosion array as the enemy array
_UpdateExplosion
Inputs: None
Outputs: None
Calls: _BlendSpriteOntoBackground
Purpose: this function goes through the enemy explode array and updates each
explosion due to the status in the enemyExplode struct
_UpdateBossExplosion
Inputs: None
Outputs: None
Calls: _BlendSpriteOntoBackground
Purpose: this function checks the status flag in the Boss struct to find out
which explosion frame to draw when the boss dies
_CheckforBossFire
Inputs: None
Outputs: None
Calls: _FireBossBullet
Purpose: uses a random number generator to find out if a turret on the boss
should fire a bullet, if it does, it calls _FireBossBullet to fire the bullet
_UpdateBossBulletPosition
Inputs: None
Outputs: None
Calls: _BlendSpriteOntoBackground
Purpose: Goes through the _enemyBullets array and draws the boss bullet in the
right place. It then updates each bullet according to its velocity
_FireBossBullet
Inputs: .Xspot arg 4 x pos of turret
.Yspot arg 4 y pos of turret
.Xvel arg 4 x vel of turret
.Yvel arg 4 y vel of turret
.width arg 4 width of turret
.height arg 4 height of turret
Outputs: None
Calls: None
Purpose: Creates a bullet at the turret position passed into the function.
compares the turret position with the ship position to determine which direction
the bullet should be fired
_CheckforEnemyFire
Inputs: None
Outputs: None
Calls: _FireEnemyBullet
Purpose: uses a random number generator to determine if an enemy in the _EnemyArray
should fire a bullet, then calls _FireEnemyBullet to fire the bullet
_UpdateEnemyBulletPosition
Inputs: None
Outputs: None
Calls: _BlendSpriteOntoBackground
Purpose: goes through the _enemyBullets array and draws the enemy bullet in the
right place. It then updates each bullet according to its velocity
_FireEnemyBullet
Inputs: .Xspot arg 4 x pos of enemy
.Yspot arg 4 y pos of enemy
.Xvel arg 4 x vel of enemy
.Yvel arg 4 y vel of enemy
.width arg 4 width of enemy
.height arg 4 height of enemy
Outputs: None
Calls: None
Purpose: Creates a bullet at the enemy position passed into the function.
Compares the enemy position with the ship position to determine which direction
the bullet should be fired
_CheckforFire
Inputs: None
Outputs: None
Calls: _FireBullet
Purpose: Checks the keyboard for the fire button [CTRL], calls _FireBullet to
fire the bullet
_FireBullet
Inputs: .Xspot arg 4 x pos of ship
.Yspot arg 4 y pos of ship
Outputs: None
Calls: None
Purpose: fires a bullet from each of the turrets on top of the ship straight
forward, writes their properties into the _movingBullets array
_UpdateBulletPosition
Inputs: None
Outputs: None
Calls: _BlendSpriteOntoBackground
Purpose: goes through the _movingBullets array and updates each bullet's
position and draws it in the right place
Functions written by Avon Fernandes
_DrawBoss
Inputs: None
Outputs: None
Calls: _BlendSpriteOntoBackground
Purpose: The function draws the boss in such a way that it follows a diamond shaped path as it moves on the screen. This is achieved by the use of a constant called MAGICNUMBER. Each time the loop through main (in the no scrolling segment) is traversed, the value of _BossCounter is incremented. This function checks the value of _BossCounter and compares it to the four quarters of MAGICNUMBER; MAGICNUMBER/4, MAGICNUMBER/2, 3*MAGICNUMBER/4 and MAGICNUMBER itself. Based on these comparisons, the position of the boss is changed by adding the current position in the x and y direction with the velocities in the x and y directions respectively. The values of the sites in the Boss struct are also added accordingly, so that their relative position doesn’t change as the boss moves on the screen. Once all the additions are done, the function calls _BlendSpriteOntoBackground to draw the boss with its updated position on the screen.
_MoveObject
Inputs: width, height
Outputs: -1 in eax if there was no move
Calls: None
Purpose: The objective of the function is to move the ship on the screen depending on the value in Ship.direction. When the user selects one or multiple arrow keys on the keyboard, this will be translated as unique code that is put into the direction field when the _CalcNewCoordinates function is running. So the first few comparisons in this function are to determine which of the directions the ship is supposed to move in. For the up, down, left and right directions, the position of the ship is checked for boundary conditions. This determines whether or not the ship is able to move in the specified direction given the conditions. If this test is passed, then the predefined speed is added (or subtracted) to the value of PosX or PosY and the new position is determined. In the case of the ship moving in a diagonal, two checks are done before calculating the new position. In any given direction, both the boundaries have to be checked before we can determine that the move is possible. If so, then the positions are updated accordingly. If, at any stage, the move is not possible, eax returns -1. Before exiting the function, the direction field is reset, so that the main function can take a new position.
_CalcNewCoordinates
Inputs: None
Outputs: None
Calls: _MoveObject, _BlendSpriteOntoBackground
Purpose: _CalcNewCoordinates determines which direction the ship needs to move depending on the key/combination of keys that are pressed by the user. The Ship.direction field is updated with a relevant constant depending on the direction. Then the _MoveObject function is called which calculates the new coordinates of the ship depending on the velocity and boundary conditions. If this function returns -1 in eax, then _BlendSpriteOntoBackground is called, and the old coordinates are drawn on the screen. Otherwise _BlendSpriteOntoBackground is called with the new coordinates.
_CheckCollisionFBE
Inputs: None
Outputs: None
Calls: _CalculateCollision, _EnemyDie
Purpose: Determines whether there was a collision between the friendly bullets fired by the ship and the enemies present on the screen. The register esi acts as a counter and increments until it has covered all the bullets on the screen. For each bullet, it will check its active field and determine whether a particular bullet is active or not. If active, it jumps to another part of the program. Now the register edi acts as a counter and traverses through the Enemy Array. For each enemy, it checks to see if that particular enemy is active or not. If so, then there is a possibility of a collision. _CalculateCollision is called with the relevant parameters and returns a -1 in eax if there has been no collision. If there was a collision, then the following operations are carried out:
· The bullet that had collided with the enemy is removed from the screen (by setting the active field to zero)
· The enemy’s life is decreased by five. If this results in the enemy’s life going to zero, then _EnemyDie is invoked, which draws the explosion animation on the screen and removes the enemy from the screen.
· The score is updated depending on the enemy that was shot down.
The enemy counter is incremented and the same procedure is carried out. Once the function has traversed through all the enemies, then it increments the bullet counter accordingly. In effect each active bullet is checked against each active enemy to determine whether there has been a collision.
_CheckCollisionES
Inputs: None
Outputs: None
Calls: _CalculateCollision, _EnemyDie, _ BlendSpriteOntoBackground
Purpose: This function determines whether there was a collision between the ship and any of the enemies on the screen. The working of this function is similar to the previous one. The enemy array is checked to see whether any of the enemies are active. If so, then the relevant parameters from the active enemy and the ship are sent to the _CalculateCollision function which will determine whether the enemy has collided with the ship. If there has been a collision, the following are executed:
· The ShipShield animation is carried out if there is enough shield energy for the ship. The LifeDrain animation is displayed if there is no shield energy left.
· The enemy’s active field is set to zero. _EnemyDie is invoked, which draws the explosion animation on the screen.
· The Shield or Life Energy is decreased accordingly depending on the life of the enemy that the ship collided with.
_CheckCollisionEBS
Inputs: None
Outputs: None
Calls: _CalculateCollision, _BlendSpriteOntoBackground
Purpose: Checks to see whether the enemy bullet has hit the ship. The Enemy Bullet Array is traversed to see whether a bullet is active. If so, then the parameters for the enemy bullet and the ship are sent to the _CalculateCollision function which determines whether a collision has occurred. If there has been a collision between the enemy bullet and the ship, the following are executed:
· The bullet is taken off the screen by setting the active field to zero.
· The ShipShield animation is carried out if there is enough shield energy for the ship. The LifeDrain animation is displayed if there is no shield energy left.
· The shield energy is decreased by 20 if there is enough shield energy. Otherwise the life energy is decreased by 5.
_CheckCollisionFBBoss
Inputs: None
Outputs: None
Calls: _CalculateCollision
Purpose: This function checks to see whether the bullets fired by the ship have hit the boss, which appears at the end of the game. First the bullets array is traversed to see which bullets are active. For the active bullets and the boss, the _CalculateCollision function is called with the relevant inputs, and this function determines whether a friendly bullet has collided into the boss. If there has been a collision, the following occurs:
· The bullet’s active field is set to zero.
· The Boss’s life is subtracted by 5.
· The users score is incremented.
_CheckCollisionSBoss
Inputs: None
Outputs: None
Calls: _CalculateCollision
Purpose: Checks whether there is a collision between the ship and boss. Since they are both unary objects, the characteristics of each is sent to the function _CalculateCollision. If there is a collision, the Shield Energy is decreased by 30 or the Life Energy is decreased by 20, depending on the relative contents of each.
_CalculateCollision
Inputs: x1 – x-position of the first object on the screen
w1 – width of the first object
y1 – y-position of the first object on the screen
h1 – height of the first object
x2 – x-position of the second object on the screen
w2 – width of the second object
y2 – y-position of the second object on the screen
h2 – height of the second object
Outputs: eax returns 0 if there was a collision
eax returns -1 if there was no collision
Calls: None
Purpose: This function determines whether two objects have collided or not given the inputs. By the way this collision algorithm works, object 1 has to be smaller than object 2. A collision is calculated is there is an overlap between the two objects in question. The following four comparisons are performed. If one of them fails, then there is no collision.
1) x-position of object 1 + width of object 1 ≥ x-position of object 2
2) x-position of object 1 ≤ x-position of object 2 + width of object 2
3) y-position of object 1 + height of object 1 ≥ y-position of object 2
4) y-position of object 1 ≤ y-position of object 2 + height of object 2
If all the tests pass, then eax returns 0. If one of them fails, then eax returns -1.
Functions written by Megan Neumann
Sound Functions:
The following functions allow for music to both play continuously, as well as play one time, depending on the song. The songs include an intro song, a game play, an explosion, game win song, loose song and a credits song.
Files are read and stored into memory and then placed into a DMA buffer that once it is half way through playing what is in the buffer, will signal for an interrupt which will cause the DMA buffer to be refilled with more information from the song till the song is over. Once the song is over, it will either end, or it will loop to the beginning of the song, and replay.
_MoveSoundLocalMem
Inputs: wavefile
Outputs: _WaveBuffer
Calls: _OpenFile, _ReadFile, _CloseFile
Purpose:
Gets Dos Handler for opened file, Reads file into _WaveBuffer, outputs # bytes
read compared that to actual size of Wavefile (WAVE_SIZE_CONST), then closed the
file, Load the sound data into local memory
_DMABufferCopy
Inputs: buffer you are using
Outputs: none
Calls: none
Purpose:
to refill the DMA buffer full when using a new or different song, file read into
_WaveBuffer, now need to copy to DMA buffer.
_PlayThatFunkyMusicFormat
Inputs: bitrate, frequency, stereo/mono
Outputs: none
Calls: _PlayThatFunkyMusic
Purpose:
Set the format and make a call to start up the music
_PlayThatFunkyMusic
Inputs: none
Outputs: none
Calls: _SB16_GetChannel, _SB16_SetFormat, _DMA_Start, _PlayThatFunkyMusic
Purpose:
Start music playing
_StopMusic
Inputs: none
Outputs: none
Calls: _DMA_Stop, _SB16_Stop, _SB16_Exit
Purpose:
Put everything back to normal so we won't crash out. This is called when you
exit from the game
_DMARefill
Inputs: none
Outputs: none
Calls: _DoSingleCyle when at the end of a song
Purpose:
Refills half of the buffer when an interrupt is signaled. This is called by the
ISR interrupt to make sure that there will be information for the DMA buffer to
read so the song will play continuously
_DoSingleCycle
Inputs: none
Outputs: none
Calls: _SB16_Stop, _SB16_Start, _DMARefill, _PlayThatFunkyMusicFormat
Purpose:
fills DMA buffer with remains of the song, and resets to point to beginning of
song in songs that repeat
_ResetBytesToRead
Inputs: none
Outputs: none
Calls: none
Purpose:
Reset the number of bytes
that are needed to read, that way you can replay a song without re-reading the
song
_START
Inputs: none
Outputs: none
Calls: _MoveSoundLocalMem, _PlayThatFunkyMusicFormat
Purpose:
to keep the main code as simple as possible, this sets up to play the song for
the beginning to keep code nice
_GAMEEXPLODE
Inputs: none
Outputs: none
Calls: _MoveSoundLocalMem, _PlayThatFunkyMusicFormat
Purpose:
Allows to play explosion and to keep code simple in the main, it plays only once
through as a provision taken care of in the _DoSingleCyle function.
_SUMMER
Inputs: none
Outputs: none
Calls: _MoveSoundLocalMem, _PlayThatFunkyMusicFormat, _BlendSpriteOntoBackground, _CopyToScreen
Purpose:
Allows playing the summer song, and placing a loading picture on bottom of
screen
_GAMEPLAY
Inputs: none
Outputs: none
Calls: _MoveSoundLocalMem, _PlayThatFunkyMusicFormat, _BlendSpriteOntoBackground, _CopyToScreen, _SB16_Stop
Purpose:
Allows playing the game song, and placing a loading picture on bottom of screen
_GAMEDIE
Inputs: none
Outputs: none
Calls: _SB16_Stop, _MoveSoundLocalMem, _PlayThatFunkyMusicFormat
Purpose:
Allows for the dying game song to play
_GAMEWIN
Inputs: none
Calls: _SB16_Stop, _MoveSoundLocalMem, _PlayThatFunkyMusicFormat
Outputs: none
Purpose:
Allows for the winning game to be played
_Sound_ISR
Inputs: none
Outputs: none
Calls: _DMARefill
Purpose: Fills the DMA buffer after an interrupt is signaled so that the code does not need to be continuously called to check if a flag has been set.
*** External Credits ***
Sprites Inc. (http://dynamic4.gamespy.com/~mmm/spritesinc/)
for the explosion animations
Agnes Lo: for the Rand subroutine
Captain Tsubasa 5 (SNES game): for the Gameover screen music
_InstallKeyboardISR
Inputs: None
Outputs: None
Calls: None
Purpose: Installs a local interrupt service routine that replaces the built-in system ISR. Allows us to write and run our own keyboard ISR.
Author: ECE 291 TAs… I think Derek King
_RemoveKeyboardISR
Inputs: None
Outputs: None
Calls: None
Purpose: Removes the local interrupt service routine so the system can run its initial ISR upon program exit.
Author: ECE 291 TAs… I think Derek King