game.cpp

Go to the documentation of this file.
00001 
00002 //
00003 // Das Tank - Copyright (C) 2006, 2007 Windsor Schmidt <windsor@windsorworld.net>
00004 //
00005 // This program is free software; you can redistribute it and/or modify it
00006 // under the terms of the GNU General Public License as published by the Free
00007 // Software Foundation; either version 2 of the License, or (at your option)
00008 // any later version.
00009 //
00010 // This program is distributed in the hope that it will be useful, but WITHOUT
00011 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00012 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
00013 // more details.
00014 //
00015 // You should have received a copy of the GNU General Public License along with
00016 // this program; if not, write to the Free Software Foundation, Inc., 59 Temple
00017 // Place, Suite 330, Boston, MA 02111-1307 USA
00018 //
00020 
00021 
00022 #ifndef STDAFX
00023 #include "stdafx.h"
00024 #endif
00025 
00026 
00035 void RemoveDeadObjects(CWorld * ThisWorld)
00036 {
00037        CObject * Current = ThisWorld->Objects;
00038        CObject * Other = ThisWorld->Objects;
00039 
00040        // for every object
00041        while(Current != NULL)
00042        {
00043               if((Current->iHealth <= 0) && Current->bVisible) // if current object is 'dead'
00044               {
00045                      // play the objects 'removal' sound effect
00046                      PlaySound(Current->iRemovalSound);
00047 
00048                      // get ready to create an effect at the dead object's position
00049                      Vector vTemp1, vTemp2;
00050                      CEffect * NewEffect = NULL;
00051 
00052                      vTemp1.x = Current->Position.x;  // dead object's position
00053                      vTemp1.y = Current->Position.y;
00054                      vTemp1.z = 0;
00055 
00056                      vTemp2.x = .04; // dead object's velocity
00057                      vTemp2.y = 0;
00058                      vTemp2.z = 0;
00059 
00060                      for(int i=0; i < Current->iRemovalEffects; i++)
00061                      {
00062                             // see which effect this object wants
00063                             switch(Current->iRemovalEffect[i])
00064                             {
00065                             case EFFECTID_PSYSTEM:
00066                                    NewEffect = new CEffect(EFFECTID_PSYSTEM);
00067                                    NewEffect->PSys = new PSystem(vTemp1, vTemp2 * 0.2, 2*PI, 1.05, 2, 100);
00068                                    NewEffect->PSys->SetColor(1.0, 0.6, 0.2);
00069                                    break;
00070 
00071                             case EFFECTID_SHOCKWAVE:
00072                                    NewEffect = new CEffect(EFFECTID_SHOCKWAVE);
00073                                    NewEffect->SWave = new Shockwave(vTemp1, 1);
00074                                    NewEffect->SWave->SetColor(0.8, 0.3, 0.6);
00075                                    break;
00076 
00077                             case EFFECTID_MINISHOCK:
00078                                    NewEffect = new CEffect(EFFECTID_MINISHOCK);
00079                                    NewEffect->MShock = new MiniShock(vTemp1, 1);
00080                                    NewEffect->MShock->SetColor(0.8, 0.3, 0.6);
00081                                    break;
00082 
00083                             case EFFECTID_TILESTORM:
00084                                    NewEffect = new CEffect(EFFECTID_TILESTORM);
00085                                    NewEffect->TStorm = new TileStorm(vTemp1, vTemp2, 2*PI, 1.005, 2, 12, TEXID_EZRAS_HEAD);
00086                                    break;
00087 
00088                             case EFFECTID_TILEANIM:
00089                                    NewEffect = new CEffect(EFFECTID_TILEANIM);
00090                                    NewEffect->TAnim = new TileAnim(vTemp1,0,Current->iLingerTime,
00091                                                                                            Current->iRemovalAnim,200, 0, false);
00092                                    break;
00093                             }
00094 
00095                             // add the new effect
00096                             Current->ParentWorld->AddEffect(NewEffect);
00097                      }
00098 
00099                      // special case when object explodes
00100                      if(Current->iType == TYPEID_SUPER_BULLET)
00101                      {
00102                             DamageRadius(ThisWorld, Current->Position, 2, Current->iDamage);
00103                      }
00104 
00105                      // special case when object explodes
00106                      if(Current->iType == TYPEID_TNT_BLOCK)
00107                      {
00108                             DamageRadius(ThisWorld, Current->Position, 5, Current->iDamage);
00109                      }
00110 
00111                      // special case when the dead object is a tank (player)
00112                      if(Current->iType == TYPEID_TANK)
00113                      {
00114                             // play a nice sound effect
00115                             PlaySound(SOUNDID_SCREAM);
00116 
00117                             // zero input before turning off player input =)
00118                             for(int i=0; i<8; i++)
00119                             {
00120                                    ThisWorld->Player[0]->iInput[i] = false;
00121                                    ThisWorld->Player[1]->iInput[i] = false;
00122                             }
00123 
00124                             // stop the player
00125                             Current->Velocity.x = 0;
00126                             Current->Velocity.y = 0;
00127                             Current->Velocity.z = 0;
00128 
00129                             ThisWorld->bTakeInput = false;
00130                             ThisWorld->iStartingState = STARTINGSTATE_VICTORY;
00131 
00132                             Current->bVisible = false;
00133 
00134                             // clean up any bullets still on the playfield
00135                             Current = ThisWorld->Objects;
00136                             while(Current != NULL)
00137                             {
00138                                    if(Current->Owner != NULL)
00139                                    {
00140                                           Current->Owner->iOwnCount --;
00141                                           Other = Current->Next; // place holder (next object in list)
00142                                           ThisWorld->RemoveObject(Current); // kill this object
00143                                           Current = Other; // and continue with place holder
00144                                    }
00145                                    else
00146                                    {
00147                                           Current = Current->Next; // object had no owner, continue to next object
00148                                    }
00149                             }
00150                             break;
00151 
00152                      }
00153                      else
00154                      {
00155                             Other = Current->Next; // place holder (next object in list)
00156                             ThisWorld->RemoveObject(Current); // kill this object
00157                             Current = Other; // and continue with place holder
00158                      }
00159               }
00160               else
00161               {
00162                      Current = Current->Next; // object had health, continue to next object
00163               }
00164        }
00165 }
00166 
00167 
00175 void GameLogicDamage(CObject * Obj, CObject * ObjRef)
00176 {
00177        PlaySound(Obj->iDamageSound);
00178        Obj->iHealth -= ObjRef->iDamage;
00179        if(Obj->iHealth > MAX_HEALTH) { Obj->iHealth = MAX_HEALTH; } // clamp to a max value
00180 }
00181 
00182 
00188 void GameLogicDamageVal(CObject * Obj, int damageVal)
00189 {
00190        PlaySound(Obj->iDamageSound);
00191        Obj->iHealth -= damageVal;
00192 }
00193 
00194 
00200 void GameLogicEquip(CObject * Obj, CObject * ObjRef)
00201 {
00202        switch(ObjRef->iType) // which powerup was it?
00203        {
00204        case TYPEID_POWERUP_PS:
00205               PlaySound(SOUNDID_POWERUP);
00206               Obj->iWeapon = WEAPONID_PEA_SHOT;
00207               Obj->iAmmo = DEFAULT_PS_AMMO;
00208               break;
00209 
00210        case TYPEID_POWERUP_BS:
00211               PlaySound(SOUNDID_POWERUP);
00212               Obj->iWeapon = WEAPONID_BOUNCY_SHOT;
00213               Obj->iAmmo = DEFAULT_BS_AMMO;
00214               break;
00215 
00216        case TYPEID_POWERUP_SB:
00217               PlaySound(SOUNDID_POWERUP);
00218               Obj->iWeapon = WEAPONID_SUPER_BULLET;
00219               Obj->iAmmo = DEFAULT_SB_AMMO;
00220               break;
00221 
00222        case TYPEID_POWERUP_LM:
00223               PlaySound(SOUNDID_POWERUP);
00224               Obj->iWeapon = WEAPONID_LAND_MINE;
00225               Obj->iAmmo = DEFAULT_LM_AMMO;
00226               break;
00227 
00228        case TYPEID_POWERUP_HS:
00229               PlaySound(SOUNDID_POWERUP);
00230               Obj->iWeapon = WEAPONID_HEAT_SEEKER;
00231               Obj->iAmmo = DEFAULT_HS_AMMO;
00232               break;
00233        }
00234        ObjRef->iHealth = 0; // kill the powerup so it's removed from the game
00235 }
00236 
00237 
00245 void GameLogicFire(CObject * Obj)
00246 {
00247        int thisType = 0; // the object type of our new projectile
00248        Vector vTemp3;
00249        Vector vTemp1; // used to figure muzzle flash position
00250        Vector vTemp2; // used to figure muzzle flash trajectory
00251 
00252        if(Obj->iAmmo == 0) // no ammo
00253        {
00254               PlaySound(SOUNDID_CLICK);
00255               return;
00256        }
00257 
00258        CObject * NewObject; // pointer to hold the weapon object before we insert it in the list
00259        CEffect * NewEffect; // pointer to hold the weapon object before we insert it in the list
00260 
00261        switch(Obj->iWeapon) // play a sound effect
00262        {
00263        case WEAPONID_NULL:
00264               break;
00265 
00266        case WEAPONID_PEA_SHOT:
00267               PlaySound(SOUNDID_FIRE_PS);
00268               NewObject = new CObject(TYPEID_PEA_SHOT, Obj->ParentWorld);
00269               NewObject->Position.x = Obj->Position.x + cos(Obj->fSubAngle * (2*PI/360)) * 1.7;
00270               NewObject->Position.y = Obj->Position.y + sin(Obj->fSubAngle * (2*PI/360)) * 1.7;
00271               NewObject->fAngle = Obj->fAngle;
00272               NewObject->Velocity.x = cos(Obj->fSubAngle * (2*PI/360)) * .2;
00273               NewObject->Velocity.y = sin(Obj->fSubAngle * (2*PI/360)) * .2;
00274               NewObject->iTexture = TEXID_PEA_SHOT;
00275               NewObject->iDamageSound = SOUNDID_HIT;
00276               NewObject->iRemovalSound = SOUNDID_CRUNCH;
00277               NewObject->iRemovalEffects = 1;
00278               NewObject->iRemovalEffect[0] = EFFECTID_MINISHOCK;
00279               break;
00280 
00281        case WEAPONID_BOUNCY_SHOT:
00282               PlaySound(SOUNDID_FIRE_BS);
00283               NewObject = new CObject(TYPEID_BOUNCY_SHOT, Obj->ParentWorld);
00284               NewObject->Position.x = Obj->Position.x + cos(Obj->fSubAngle * (2*PI/360)) * 1.7;
00285               NewObject->Position.y = Obj->Position.y + sin(Obj->fSubAngle * (2*PI/360)) * 1.7;
00286               NewObject->fAngle = Obj->fAngle;
00287               NewObject->Velocity.x = cos(Obj->fSubAngle * (2*PI/360)) * .4;
00288               NewObject->Velocity.y = sin(Obj->fSubAngle * (2*PI/360)) * .4;
00289               NewObject->iDamageSound = SOUNDID_HIT;
00290               NewObject->iRemovalSound = SOUNDID_CRUNCH;
00291               NewObject->iRemovalEffects = 1;
00292               NewObject->iRemovalEffect[0] = EFFECTID_MINISHOCK;
00293               break;
00294 
00295        case WEAPONID_SUPER_BULLET:
00296               PlaySound(SOUNDID_FIRE_SB);
00297               NewObject = new CObject(TYPEID_SUPER_BULLET, Obj->ParentWorld);
00298               NewObject->Position.x = Obj->Position.x + cos(Obj->fSubAngle * (2*PI/360)) * 1.7;
00299               NewObject->Position.y = Obj->Position.y + sin(Obj->fSubAngle * (2*PI/360)) * 1.7;
00300               NewObject->fAngle = Obj->fAngle;
00301               NewObject->Velocity.x = cos(Obj->fSubAngle * (2*PI/360)) * .3;
00302               NewObject->Velocity.y = sin(Obj->fSubAngle * (2*PI/360)) * .3;
00303               NewObject->iDamageSound = SOUNDID_HIT;
00304               NewObject->iRemovalSound = SOUNDID_EXPLOSION;
00305               NewObject->iRemovalEffects = 1;
00306               NewObject->iRemovalEffect[0] = EFFECTID_PSYSTEM;
00307 
00308               vTemp3.x = cos((DegreesToRadians(Obj->fSubAngle)));
00309               vTemp3.y = sin((DegreesToRadians(Obj->fSubAngle)));
00310               vTemp3.Normalize();
00311 
00312               Obj->Velocity -= vTemp3 * 0.5;
00313 
00314               break;
00315 
00316        case WEAPONID_LAND_MINE:
00317               PlaySound(SOUNDID_FIRE_LM);
00318               NewObject = new CObject(TYPEID_LAND_MINE, Obj->ParentWorld);
00319               NewObject->Position.x = Obj->Position.x - cos(Obj->fSubAngle * (2*PI/360)) * 1.7;
00320               NewObject->Position.y = Obj->Position.y - sin(Obj->fSubAngle * (2*PI/360)) * 1.7;
00321               NewObject->fAngle = Obj->fAngle;
00322               NewObject->iRemovalSound = SOUNDID_EXPLOSION;
00323               break;
00324 
00325        case WEAPONID_HEAT_SEEKER:
00326               PlaySound(SOUNDID_FIRE_HS);
00327               NewObject = new CObject(TYPEID_HEAT_SEEKER, Obj->ParentWorld);
00328               NewObject->Position.x = Obj->Position.x + cos(Obj->fSubAngle * (2*PI/360)) * 1.7;
00329               NewObject->Position.y = Obj->Position.y + sin(Obj->fSubAngle * (2*PI/360)) * 1.7;
00330               NewObject->fAngle = Obj->fAngle;
00331               NewObject->Velocity.x = cos(Obj->fSubAngle * (2*PI/360)) * .06;
00332               NewObject->Velocity.y = sin(Obj->fSubAngle * (2*PI/360)) * .06;
00333               NewObject->iDamageSound = SOUNDID_HIT;
00334               NewObject->iRemovalSound = SOUNDID_EXPLOSION;
00335               break;
00336        }
00337 
00338        // decrease the amount of ammo this object has
00339        Obj->iAmmo--;
00340 
00341        if(Obj->iAmmo < -1) { Obj->iAmmo = -1; } // clamp neg value otherwise it looks goofy
00342        
00343        // reset to pea shooter if object has run out of ammo
00344        if(Obj->iAmmo == 0)
00345        {
00346               Obj->iWeapon = WEAPONID_PEA_SHOT;
00347               Obj->iAmmo = -1;
00348        }
00349        
00350        // set the owner of this bullet
00351        NewObject->Owner = Obj;
00352        // and increase the player's object ownership count by one
00353        Obj->iOwnCount++;
00354        // set object's tint color to match it's owners (red tank gets red bullets)
00355        NewObject->iTint = Obj->iTint;
00356        // add bullet to world
00357        Obj->ParentWorld->AddObject(NewObject);
00358 
00359        vTemp1.x = NewObject->Position.x;
00360        vTemp1.y = NewObject->Position.y;
00361        vTemp1.z = 0;
00362 
00363        vTemp2.x = 0.005;
00364        vTemp2.y = 0;
00365        vTemp2.z = 0;
00366 
00367        vTemp2 = VRotate2D(DegreesToRadians(Obj->fAngle), vTemp2);
00368 
00369        NewEffect = new CEffect(EFFECTID_PSYSTEM);
00370        NewEffect->PSys = new PSystem(vTemp1, vTemp2, 0.01, 1.01, 1, 50);
00371        NewEffect->PSys->SetColor(1,.6,.2);
00372 
00373        Obj->ParentWorld->AddEffect(NewEffect);
00374 }

 

Copyright Windsor Schmidt 2006 - All rights reserved.