GameSource/MissileSprite.c

#include "ZAM.h"
#include "GameAEvents.h"
#include "MissileSprite.h"
#include "SpriteFrameRates.h"
#include "TankSprite.h"
#include "GameSounds.h"
#include "ZAMProtos.h"
 
 
spriteLayerPtr MissileLayer;
spriteLayerPtr RemoteMissileLayer;
frameSetPtr MissileFrameSetList;
spritePtr   MissileSpriteList[kMaxMissiles];
spritePtr   RemoteMissileSpriteList[kMaxMissiles];
 
typedef struct {
    short   flags;
    fixPt   loc;
    fixPt   vel;
} aeMissileInfo;
 
OSErr AppendMissilePositions(AppleEvent *ae)
{
    OSErr               err = 0;
    short               index;
    aeMissileInfo       missilePosList[kMaxMissiles];
        
    for(index = 0; index < kMaxMissiles; index++) {
    
        if(MissileSpriteList[index]->spriteFlags & kRemoteSpawn) {
            MissileSpriteList[index]->spriteFlags &= ~kRemoteSpawn;
            missilePosList[index].flags = 1;
        } else if( MissileSpriteList[index]->spriteFlags & kRemoteDead ) {
            MissileSpriteList[index]->spriteFlags &= ~kRemoteDead;
            missilePosList[index].flags = 2;
            MissileSpriteList[index]->inUse = false;
        } else if(MissileSpriteList[index]->spriteFlags & kRemoteKilled) {
            MissileSpriteList[index]->spriteFlags &= ~kRemoteKilled;
            missilePosList[index].flags = 3;
        } else {
            missilePosList[index].flags = 0;
        }
        
        missilePosList[index].loc = MissileSpriteList[index]->loc;
        missilePosList[index].vel = MissileSpriteList[index]->vel;
    }
    
    if(err == noErr) {
        AEPutParamPtr(ae, keyMissilePos, typefixPtList, 
                            &missilePosList, sizeof(missilePosList));
        if(err != noErr) {
            ErrMsgCode("\p Failure: AppendMissilePositions AEPutParamPtr",err);
        }
    }
                
    return err;
}
 
 
OSErr ProcessMissilePositions(AppleEvent *ae)
{
    OSErr           err= 0;
    short           index;
    aeMissileInfo   missilePosList[kMaxMissiles];
    long            len;
    DescType        actualType;
    
    err = AEGetParamPtr(ae, keyMissilePos, typefixPtList, &actualType, 
            &missilePosList, sizeof(missilePosList), &len);
    if(err != noErr) {
        ErrMsgCode("\p Failed: AEMoveRemoteMissile keyDir, typeShortInteger",err);
    }
    
    if(err == noErr) {
        for(index = 0; index < kMaxMissiles; index++) {
            if(missilePosList[index].flags == 1) {
                FireMissileVelocity(&missilePosList[index].vel,
                            missilePosList[index].loc.h, missilePosList[index].loc.v, 
                            true, index);           
            } else if(missilePosList[index].flags == 2) {
                RemoteMissileSpriteList[index]->inUse = false;
                RemoteMissileSpriteList[index]->visible = false;
                RemoteMissileSpriteList[index]->spriteFlags |= kNeedsToBeErased;
                RemoteMissileSpriteList[index]->ownerLayer->layerFlags |= kLayerDirty;
                RemoteMissileSpriteList[index]->inUse = false;
                StartExplosionHere(gGame, missilePosList[index].loc.h, missilePosList[index].loc.v);
            } else if(missilePosList[index].flags == 3) {
                StopAllSounds();
                SoundDisable();
                gDead = true;
                gDeadTime = TickCount();
            } else if(RemoteMissileSpriteList[index]->inUse) {
                RemoteMissileSpriteList[index]->moveTask.taskFlag = true;
                RemoteMissileSpriteList[index]->remoteLoc = missilePosList[index].loc;
            }
        }   
    }
    return err;
}
 
void CheckMissileColissions(gamePtr game)
{
    if(MissileLayer->activeCount)
        CollideSpriteLayer( MissileLayer, gTankLayer[game->remoteTankIndex]);
}
 
void MissileColissionHandler( spritePtr spr, spritePtr obj, Rect *colArea)
{
    if( (RECT_WD(*colArea) >= kCollThresh) && (RECT_HT(*colArea) >= kCollThresh) ) {
        spr->visible = false;
        spr->spriteFlags |= kNeedsToBeErased;
        spr->ownerLayer->layerFlags |= kLayerDirty;
        StartExplosionHere(gGame, spr->loc.h, spr->loc.v);
        SetSpriteFrameCallback(spr,GetNextSpriteFrameIndex(spr),HaltMissileFrameTask);
        spr->spriteFlags |= kRemoteDead;
    }
}
 
Boolean HaltMissileFrameTask(spritePtr spr)
{
    SetSpriteFrameCallback(spr,spr->frameList->finfo.frameIndex,nil);
    spr->visible = false;
    spr->ownerLayer->activeCount--;
    return false;
}
 
Boolean MissileMoveFilter(spritePtr spr)
{
    Rect    junk;
    gamePtr game;
    Boolean result = true;
    
    game = (gamePtr)spr->refCon;
    
    spr->data--;
    /* should also check if the sprite has left the screen and then kill it */
    if(!spr->data  )  {
        spr->visible = false;
        spr->spriteFlags |= kNeedsToBeErased | kRemoteDead;
        spr->ownerLayer->layerFlags |= kLayerDirty;
        SetSpriteFrameCallback(spr,GetNextSpriteFrameIndex(spr),HaltMissileFrameTask);
        StartExplosionHere(gGame, spr->loc.h, spr->loc.v);
        spr->spriteFlags |= kRemoteDead;
        result = false;
    }
 
    return result;
}
 
 
void LoadMissileSprites(gamePtr game)
{
    OSErr           err;
    short           ref;
    short           i,iconID;
    frameSetPtr     missileFrameSet;
    short           numMissileFrames;
    
    
    ref = OpenResFile("\pFireBallFrames.rsrc");
    if(err = ResError()) {
        ErrMsgCode("\pCould Not Open MissileFrames file!.",err);
        ExitToShell();
    }
    
    numMissileFrames = Count1Resources('cicn');
    
    if(err == noErr) {
        if(err == noErr) {
            err = CreatePICTIconFrameSet(&MissileFrameSetList, 128, numMissileFrames);
            if(err != noErr) {
                ErrMsgCode("\pCreateColorIconFrameSet failed.",err);
            }
            /*
                Setting the ctseed to the same as the other color tables,
                so that no colors will be mapped.
            */
            if(err == noErr)
                SetFrameSetCTSeed(MissileFrameSetList,game->gameCTSeed);
 
        }
    }
 
 
    CloseResFile(ref);
 
    err = CreateSpriteLayer(&MissileLayer, game->tween,game->backdrop, game->gameWind);
    if(err != noErr) {
        ErrMsgCode("\pCreateSpriteLayer failed.",err);
        ExitToShell();
    }
    
    for(i = 0; i < kMaxMissiles; i++) {
    
        if(err == noErr) {
            err = CreateEmptySprite(MissileLayer,
                                &MissileSpriteList[i],  /* returned sprite here */
                                kDefaultFrameAdvance,
                                kMissileMoveTime,   /* time between movement */
                                kMissileFrameTime,  /* time between frame change */
                                (long)game);
    
            if(err != noErr) {
                ErrMsgCode("\pCreateEmptySprite failed.",err);
            } else {
                err = CreateEmptyFrameSet(&MissileSpriteList[i]->frameList,numMissileFrames);
            }
 
            MissileSpriteList[i]->moveHandler = MissileMoveFilter;
            MissileSpriteList[i]->spriteID = i;
            MissileSpriteList[i]->inUse = false;
            MissileSpriteList[i]->collideHandler = (collisionProc)MissileColissionHandler;
        }
    }
 
 
    err = CreateSpriteLayer(&RemoteMissileLayer, game->tween, game->backdrop, game->gameWind);
    if(err != noErr) {
        ErrMsgCode("\pCreateSpriteLayer failed.",err);
        ExitToShell();
    }
 
    /* now build remote missiles */
    for(i = 0; i < kMaxMissiles; i++) {
    
        if(err == noErr) {
            err = CreateEmptySprite(RemoteMissileLayer,
                                &RemoteMissileSpriteList[i],    /* returned sprite here */
                                 kRemoteSprite | kDefaultFrameAdvance | kRemoteUpdate,
                                // kDefaultFrameAdvance ,
                                kMissileFrameTime,  /* time between frame change */
                                kMissileMoveTime,   /* time between movement */
                                (long)game);
    
            if(err != noErr) {
                ErrMsgCode("\pCreateEmptySprite failed.",err);
            } else {
                err = CreateEmptyFrameSet(&RemoteMissileSpriteList[i]->frameList,numMissileFrames);
            }
            RemoteMissileSpriteList[i]->spriteID = i;
            RemoteMissileSpriteList[i]->moveHandler = MissileMoveFilter;
        }
        
    }
    
}
 
 
 
spritePtr GetMissileSprite(Boolean network)
{
    short i;
    
    for(i = 0; i < kMaxMissiles; i++)
        if(MissileSpriteList[i]->inUse == false) {
            MissileSpriteList[i]->inUse = true;
            MissileSpriteList[i]->ownerLayer->activeCount++;
            return MissileSpriteList[i];
        }
    
    return nil;
}
 
void FireMissileVelocity(fixPt *vel, Fixed h, Fixed v, Boolean network, short missileNum)
{
    FireMissile(VelocityToDirection(vel),h,v,network,missileNum);
}
 
void FireMissile( short dir, Fixed h, Fixed v, Boolean network, short missileNum)
{
    fixPt       vel;
    spritePtr   missile;
    
 
    if(network == false)
        missile = GetMissileSprite(network);
    else {
        missile = RemoteMissileSpriteList[missileNum];
        missile->ownerLayer->activeCount++;
        missile->inUse = true;
        missile->remoteLoc.h = h;
        missile->remoteLoc.v = v;
    }
    
    if(missile) {
        (void)PlaySndAsynchChannel( kFireSnd, kShotChan, kStdPriority);
//
//  taking out because adding kRemoteSpawn bit
//      if(network == false) 
//          NetworkFireMissile(gGame, dir, h, v, missile->spriteID);
 
        if(network == false)
            missile->spriteFlags |= kRemoteSpawn;
 
        missile->data = kMissileLife;
        if( ((missile->frameTask.timer.qType & TaskActiveFlag) != 0) 
            ||  ((missile->moveTask.timer.qType & TaskActiveFlag) != 0)) {
            HideSprite(missile);
            StopSpriteAction(missile);  
        }
        
        SetSpriteFrameSet(missile,MissileFrameSetList);
    
        DirectionToVelocity( dir, &vel);
        
        vel.h = FixMul(vel.h,ff(12));
        vel.v = FixMul(vel.v,ff(12));
        SetSpriteVelocity(missile, vel.h , vel.v);
    
        SetSpriteLoc(missile, h, v);
    
        missile->visible = true;
 
        if(network) {
            StartRemoteSpriteAction(missile);
        } else {
            StartSpriteAction(missile);
        }
        
    }
}