Source/ObjectActions.c

/*
    File:       ObjectActions.c
 
    Contains:   xxx put contents here xxx
 
    Version:    xxx put version here xxx
 
    Copyright:  © 1998 by Apple Computer, Inc., all rights reserved.
 
    File Ownership:
 
        DRI:                xxx put dri here xxx
 
        Other Contact:      xxx put other contact here xxx
 
        Technology:         xxx put technology here xxx
 
    Writers:
 
        (cjd)   Chris DeSalvo
 
    Change History (most recent first):
 
         <8>      7/1/98    cjd     Cleaned up
*/
 
//¥ ------------------------------------------------------------------------------------------  ¥
//¥
//¥ Copyright © 1996 Apple Computer, Inc., All Rights Reserved
//¥
//¥
//¥     You may incorporate this sample code into your applications without
//¥     restriction, though the sample code has been provided "AS IS" and the
//¥     responsibility for its operation is 100% yours.  However, what you are
//¥     not permitted to do is to redistribute the source as "DSC Sample Code"
//¥     after having made changes. If you're going to re-distribute the source,
//¥     we require that you make it clear in the source that the code was
//¥     descended from Apple Sample Code, but that you've made changes.
//¥
//¥     Authors:
//¥         Chris De Salvo
//¥
//¥ ------------------------------------------------------------------------------------------  ¥
 
//¥ ------------------------------  Includes
 
#include "EventHandler.h"
#include "Graphics.h"
#include "ObjectActions.h"
#include "Particles.h"
#include "SprocketInvaders.h"
#include "CommonStuff.h"
 
//¥ ------------------------------  Private Definitions
 
#define kPlayerTime                 1L  //¥ How much time should pass between player updates
#define kPlayerShotTime             2L  //¥ How much time should pass between player shot updates
#define kPointsTime                 2L  //¥ How much time should pass beteen points updates
 
#define kEnemyShotTime              2L  //¥ How much time should pass between enemy shot updates
#define kEnemyVDrop                 25  //¥ Speed at which enemy shots fall
 
#define kPointsFrames               20  //¥ Number of frames that points sprite will stay visible
#define kNumParticleFrames          200
 
//¥ ------------------------------  Private Types
//¥ ------------------------------  Private Variables
//¥ ------------------------------  Private Functions
//¥ ------------------------------  Public Variables
 
//¥ --------------------    ObjectIdle
//¥
//¥ This object action just moves the object at its current speed
 
void
ObjectIdle(GameObjectPtr theObject)
{
    theObject->time += gDeltaTime;
    if (theObject->time < 1L)
        return;
        
    theObject->time = 0L;
 
    theObject->screenX += theObject->velocityH;
    theObject->screenY += theObject->velocityV;
}
 
//¥ --------------------    ObjectBounce
//¥
//¥ This object action movies the object and bounces it off of its bounds
 
void
ObjectBounce(GameObjectPtr theObject)
{
    theObject->time += gDeltaTime;
    if (theObject->time < 1L)
        return;
        
    theObject->time = 0L;
 
    theObject->screenX += theObject->velocityH;
    theObject->screenY += theObject->velocityV;
 
    //¥ Check left bounds
    if ((theObject->screenX < theObject->bounds.left) && (theObject->velocityH < 0))
        theObject->velocityH *= -1;
 
    //¥ Check top bounds
    if ((theObject->screenY < theObject->bounds.top) && (theObject->velocityV < 0))
        theObject->velocityV *= -1;
 
    //¥ Check right bounds
    if ((theObject->screenX > theObject->bounds.right) && (theObject->velocityH > 0))
        theObject->velocityH *= -1;
 
    //¥ Check bottom bounds
    if ((theObject->screenY > theObject->bounds.bottom) && (theObject->velocityV > 0))
        theObject->velocityV *= -1;
}
 
//¥ --------------------    GreenPlayerAction
 
void
GreenPlayerAction(GameObjectPtr theObject)
{
SInt16  velocity;
 
    theObject->time += gDeltaTime;
    if (theObject->time < kPlayerTime)
        return;
        
    theObject->time = 0L;
 
    if (theObject->refCon > 0)
    {
        theObject->refCon--;
        return;
    }
 
    velocity = 0;
    if (gGameKeys.greenLeft)
        velocity -= theObject->velocityH;
        
    if (gGameKeys.greenRight)
        velocity += theObject->velocityH;
 
    theObject->screenX += velocity;
 
    //¥ Check left bounds
    if (theObject->screenX < theObject->bounds.left)
        theObject->screenX = theObject->bounds.left;
 
    //¥ Check right bounds
    if (theObject->screenX > theObject->bounds.right)
        theObject->screenX = theObject->bounds.right;
 
    //¥ Did player fire?
    if (gGameKeys.greenFire)
        PlayerShoot(theObject);
}
 
//¥ --------------------    RedPlayerAction
 
void
RedPlayerAction(GameObjectPtr theObject)
{
SInt16  velocity;
 
    theObject->time += gDeltaTime;
    if (theObject->time < kPlayerTime)
        return;
        
    theObject->time = 0L;
 
    if (theObject->refCon > 0)
    {
        theObject->refCon--;
        return;
    }
 
    velocity = 0;
    if (gGameKeys.redLeft)
        velocity -= theObject->velocityH;
        
    if (gGameKeys.redRight)
        velocity += theObject->velocityH;
 
    theObject->screenX += velocity;
 
    //¥ Check left bounds
    if (theObject->screenX < theObject->bounds.left)
        theObject->screenX = theObject->bounds.left;
 
    //¥ Check right bounds
    if (theObject->screenX > theObject->bounds.right)
        theObject->screenX = theObject->bounds.right;
 
    //¥ Did player fire?
    if (gGameKeys.redFire)
        PlayerShoot(theObject);
}
 
//¥ --------------------    PlayerShotAction
 
void
PlayerShotAction(GameObjectPtr theObject)
{
    theObject->time += gDeltaTime;
    if (theObject->time < kPlayerShotTime)
        return;
        
    theObject->time = 0L;
    theObject->screenY -= theObject->velocityV;
    
    if (theObject->screenY < theObject->bounds.top)
        theObject->action = PlayerShotDestroy;
}
 
//¥ --------------------    PlayerShotDestroy
 
void
PlayerShotDestroy(GameObjectPtr theObject)
{
    AddParticles(theObject->screenX, theObject->screenY, objectMissileParticles);
 
    if (theObject->kind == objectRedPlayerShot)
        GameObjectRemoveFromList(&gRedPlayerShotList, theObject);
    else
        GameObjectRemoveFromList(&gGreenPlayerShotList, theObject);
 
    GameObjectDispose(theObject);
}
 
//¥ --------------------    EnemyDestroy
 
void
EnemyDestroy(GameObjectPtr theObject)
{
    AddParticles(theObject->screenX, theObject->screenY, objectEnemyParticles);
 
    GameObjectRemoveFromList(&gEnemyList, theObject);
    GameObjectDispose(theObject);
    gNumEnemies--;
}
 
//¥ --------------------    EnemyShotDestroy
 
void
EnemyShotDestroy(GameObjectPtr theObject)
{
    AddParticles(theObject->screenX, theObject->screenY, objectMissileParticles);
 
    GameObjectRemoveFromList(&gEnemyShotList, theObject);
    GameObjectDispose(theObject);
}
 
//¥ --------------------    PointsDestroy
 
void
PointsDestroy(GameObjectPtr theObject)
{
    GameObjectRemoveFromList(&gMiscObjectList, theObject);
    GameObjectDispose(theObject);
}
 
//¥ --------------------    PointsAction
 
void
PointsAction(GameObjectPtr theObject)
{
    theObject->time += gDeltaTime;
    if (theObject->time < kPointsTime)
        return;
        
    theObject->time = 0L;
 
    theObject->screenX += theObject->velocityH;
    theObject->screenY += theObject->velocityV;
    
    theObject->refCon++;
 
    if (theObject->refCon > kPointsFrames)
        theObject->action = PointsDestroy;
}
 
//¥ --------------------    EnemyAction
 
void
EnemyAction(GameObjectPtr theObject)
{
    if (theObject->refCon > gEnemyLevel)
        return;
        
    theObject->refCon++;
    gNumEnemiesProcessed++;
    
    if (theObject->refCon & 1)
        theObject->frame = 1;
    else
        theObject->frame = 0;
 
    //¥ Determine if this enemy needs to shoot
    if (Game_Random((2 * kNumEnemies) - gNumEnemies) == 1)
        EnemyShoot(theObject);
 
    //¥ Adjust screen position depending on whether we're moving left or right
    if (gEnemyTask == kEnemyMovingRight)
    {
        theObject->screenX += gEnemyVelocity;
    }
    else if (gEnemyTask == kEnemyMovingLeft)
    {
        theObject->screenX -= gEnemyVelocity;
    }
    else if (gEnemyTask == kEnemyDropping)
    {
        theObject->screenY += kEnemyVDrop;
    }
        
    //¥ Check for bottom bound
    if (theObject->screenY > theObject->bounds.bottom)
    {
        gNumRedPlayerLives = 0;
        gNumGreenPlayerLives = 0;
        return;
    }
 
    //¥ Check left bounds
    if (theObject->screenX < theObject->bounds.left && (gEnemyTask == kEnemyMovingLeft))
    {
        gEnemiesChangeDirection = kEnemyMovingRight;
        return;
    }
 
    //¥ Check right bounds
    if (theObject->screenX > theObject->bounds.right && (gEnemyTask == kEnemyMovingRight))
    {
        gEnemiesChangeDirection = kEnemyMovingLeft;
        return;
    }
}
 
//¥ --------------------    EnemyShotAction
 
void
EnemyShotAction(GameObjectPtr theObject)
{
    theObject->time += gDeltaTime;
    if (theObject->time < kEnemyShotTime)
        return;
        
    theObject->time = 0L;
    theObject->screenY += theObject->velocityV;
    
    if (theObject->screenY > theObject->bounds.bottom)
        theObject->action = EnemyShotDestroy;
}
 
//¥ --------------------    PlayerDestroy
 
void
PlayerDestroy(GameObjectPtr theObject)
{
    AddParticles(theObject->screenX, theObject->screenY, objectPlayerParticles);
 
    theObject->refCon = kPlayerDeathDelay;
 
    if (theObject->kind == objectRedPlayer)
    {
        theObject->screenX = theObject->bounds.right - 20;
        theObject->action = RedPlayerAction;
    }
    else
    {
        theObject->screenX = theObject->bounds.left + 20;
        theObject->action = GreenPlayerAction;
    }
}
 
//¥ --------------------    ParticleAction
 
void
ParticleAction(GameObjectPtr theObject)
{
UInt32          i, numParticlesAlive;
ParticlesPtr    theParticles;
SpeckPtr        theSpecks;
 
    //¥ Don't process the particles more than 60 times per second
    theObject->time += gDeltaTime;
    if (theObject->time < 1L)
        return;
        
    theObject->time = 0L;
 
    //¥ Get the particle object
    theParticles = theObject->objectData.particles;
    theSpecks = theParticles->specks;
 
    numParticlesAlive = 0;
    
    //¥ Advance the position of all the living particles
    for (i = 0; i < kNumSpecks; i++)
    {
        theSpecks[i].age++;
        
        if (theSpecks[i].age < theSpecks[i].lifeTime)
        {
            theSpecks[i].h += theSpecks[i].speedH;
            theSpecks[i].v += theSpecks[i].speedV;
            
            numParticlesAlive++;
        }
    }
    
    //¥ If all the particles are dead, kill the object
    if (0 == numParticlesAlive)
    {
        GameObjectRemoveFromList(&gMiscObjectList, theObject);
        GameObjectDispose(theObject);
    }
}