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