Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members  

BattleGroup.cpp

Go to the documentation of this file.
00001 /*
00002 CS Senior Project 2003
00003 Team : Leftfield
00004 Project : ModernWarfare
00005 Members :
00006 - Russ Christensen              <rchriste@cs.utah.edu>
00007 - Todd Smith                    <tcsmith@cs.utah.edu>
00008 - Usit Duongsaa                 <duongsaa@cs.utah.edu>
00009 Copyright 2003 Russ Christensen, Usit Duongsaa, and Todd Smith. All rights reserved.
00010 
00011 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
00012 
00013 Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 
00014 Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 
00015 THIS SOFTWARE IS PROVIDED BY RUSS CHRISTENSEN, USIT DUONGSAA, AND TODD SMITH ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RUSS, USIT, TODD OR OTHER CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00016 */
00017 
00021 #include "BattleGroup.h"
00022 #include "BattleState.h"
00023 #include "BattleUnitStat.h"
00024 #include "BattleUnitData.h"
00025 #include "Sound.h"
00026 #include "GameState.h"
00027 
00028 //------------------------------------------------------------------------------------
00029 // helpers for conditional voices stuffs
00030 // isActive => whether this battle is being watched by the player
00031 void playVoiceContact(BattleState &BS, bool isActive)
00032 {
00033         float vol = Sound::getMasterSFXVol();
00034         if( !isActive ) vol *= 0.92f;
00035         Vec3D playerCol( GameState::consolePlayer()->color() );
00036         if( BS.teamAColor!=playerCol && BS.teamBColor!=playerCol ) vol = 0.0f;
00037         
00038         if( BS.m_cvLastContact > 240 )
00039                 if( BS.m_cvLastPanick > 240 )
00040                         if( sys_localRandInt()%25==0 )
00041                         {
00042                                 BS.m_cvLastContact = 0;
00043                                 Sound::playRandomSound( Sound::CLASS_BATTLE_CONTACT, vol );
00044                         }
00045 }
00046 //------------------------------------------------------------------------------------
00047 void playVoiceStress(BattleState &BS, bool isActive)
00048 {
00049         float vol = Sound::getMasterSFXVol();
00050         if( !isActive ) vol *= 0.92f;
00051         Vec3D playerCol( GameState::consolePlayer()->color() );
00052         if( BS.teamAColor!=playerCol && BS.teamBColor!=playerCol ) vol = 0.0f;
00053 
00054         if( BS.m_cvLastStress > 240 )
00055                 if( BS.m_cvLastPanick > 180 )
00056                         if( sys_localRandInt()%2==0 )
00057                         {
00058                                 BS.m_cvLastStress = 0;
00059                                 Sound::playRandomSound( Sound::CLASS_BATTLE_STRESS, vol );
00060                         }
00061 }
00062 //------------------------------------------------------------------------------------
00063 void playVoicePanick(BattleState &BS, bool isActive)
00064 {
00065         float vol = Sound::getMasterSFXVol();
00066         if( !isActive ) vol *= 0.92f;
00067         Vec3D playerCol( GameState::consolePlayer()->color() );
00068         if( BS.teamAColor!=playerCol && BS.teamBColor!=playerCol ) vol = 0.0f;
00069 
00070         if( BS.m_cvLastStress > 180 )           
00071                 if( sys_localRandInt()%1==0 )
00072                 {
00073                         BS.m_cvLastStress = 0;
00074                         Sound::playRandomSound( Sound::CLASS_BATTLE_PANICK, vol );
00075                 }
00076 }
00077 //------------------------------------------------------------------------------------
00078 BattleGroup::BattleGroup( Vec3D pos, Vec3D dir, char team, Vec3D color, int unitType, int numUnits, int overheadForceNumber )
00079 {
00080         assert(unitType>=0 && unitType<UnitTypes::COUNT );
00081         m_team = team;
00082         m_pos = pos;
00083         m_size = BattleUnitData::getObj().tightFormationSize()[unitType];
00084         m_dir = dir;
00085         m_color = color;
00086         m_unitType = unitType;
00087         m_unitArraySize = numUnits;
00088         m_numUnits = numUnits;
00089         m_overheadForceNumber = overheadForceNumber;
00090 
00091         Vec3D halfSize = m_size * 0.5f;
00092         int rows = BattleUnitData::getObj().numRows()[m_unitType];
00093         int cols = BattleUnitData::getObj().numCols()[m_unitType];
00094         FLOAT backDelta  = m_size.x / rows;
00095         FLOAT rightDelta = m_size.y / cols;
00096         Vec3D frontLeftPt = math_translateObjectToWorld( m_pos, m_dir, Vec3D( halfSize.x,halfSize.y,0.0f) );
00097         Vec3D backVec     = math_translateObjectToWorld( m_pos, m_dir, Vec3D( halfSize.x-backDelta,halfSize.y,0.0f) ) - frontLeftPt;
00098         Vec3D rightVec    = math_translateObjectToWorld( m_pos, m_dir, Vec3D( halfSize.x,halfSize.y-rightDelta,0.0f) ) - frontLeftPt;
00099 
00100         for( int i=0; i<m_unitArraySize; i++ )
00101         {
00102                 FLOAT col = (FLOAT)(i%cols) + 0.5f;
00103                 FLOAT row = (FLOAT)(i/cols) + 0.5f;
00104                 m_units[i].m_pos = frontLeftPt + backVec*row + rightVec*col;
00105                 m_units[i].m_dir = m_dir;
00106                 m_units[i].m_turretDir = Vec3D(0,0,0);
00107                 m_units[i].m_target = m_units[i].m_pos;
00108                 m_units[i].m_firingDelay = 0;
00109                 m_units[i].m_health = BattleUnitData::getObj().armor()[m_unitType];
00110                 m_units[i].m_recvHitIndex = 0;
00111         }
00112 
00113         m_statFiringRange = BattleUnitData::getObj().firingRange()[m_unitType];
00114         m_primaryTarget = -1;
00115         m_isStrictPrimaryTarget = false;
00116         m_isChasePrimaryTarget = false;
00117 }
00118 //------------------------------------------------------------------------------------
00119 void BattleGroup::addWaypoint( const Vec3D pt )
00120 {
00121         if(m_waypoints.size()<12 ) m_waypoints.push_back(pt);
00122 }
00123 //------------------------------------------------------------------------------------
00124 void BattleGroup::moveBattleGroup()
00125 {
00126         // TEMP DEBUG INFO
00127         //sys_console() << "BG " << m_pos.x << ' ' << m_pos.y << ' ' << terrain_getHeight(BS->terrain,m_pos.x,m_pos.y)
00128         //                << ' ' << m_dir.x << endl;
00129 
00130 
00131         if(m_numUnits==0) return;
00132 
00133         if( m_primaryTarget!=-1 && m_isChasePrimaryTarget )                                     // home in on primary target
00134         {
00135                 Vec3D pt( BS->groups[ m_primaryTarget ].m_pos );
00136                 m_waypoints.resize(0);
00137                 m_waypoints.push_back(pt);
00138         }
00139 
00140         if( m_waypoints.size() == 0 ) return;
00141         
00142         Vec3D targetVec = m_waypoints[0] - m_pos;
00143         FLOAT targetDir = clipAngle( 90-D3DXToDegree( atan2f( targetVec.x, targetVec.y ) ) );
00144         FLOAT currentDir = m_dir[0];
00145         FLOAT delta;                            // signed (+CW,-CCW) smallest-magnitude difference in angle
00146         if( targetDir<0.0f ) targetDir += 360.0f;
00147         else if( targetDir>=360.0f ) targetDir -= 360.0f;
00148         if(targetDir>currentDir)
00149         {
00150                 delta = targetDir - currentDir;
00151                 if(delta>180.0f) delta = delta - 360.0f;
00152         }
00153         else
00154         {
00155                 delta = targetDir - currentDir;
00156                 if(delta<-180.0f) delta = 360.0f - delta;
00157         }               
00158         
00159         const FLOAT turnRate = BattleUnitData::getObj().BGTurnRate()[m_unitType];
00160         FLOAT turnAngle = delta;
00161         if( delta > turnRate ) turnAngle = turnRate;
00162         else if( delta < -turnRate ) turnAngle = -turnRate;
00163         else turnAngle = delta;
00164         m_dir[0] = clipAngle( currentDir + turnAngle );                         // turn
00165 
00166         // move if we're heading roughly the right way
00167         FLOAT speed = 0.0f;
00168         if( absf(delta)<10.0f ) speed = BattleUnitData::getObj().BGFullSpeed()[m_unitType];
00169         else if( absf(delta)<30.0f ) speed = BattleUnitData::getObj().BGHalfSpeed()[m_unitType];
00170         
00171         if( m_maxUnitDist > 4.0f ) speed = speed * 0.25f;       // slow down if units are out of formation
00172 
00173         if(speed>0.0f)
00174         {
00175                 FLOAT rad = D3DXToRadian( m_dir[0] );
00176                 m_pos += speed * Vec3D( cosf(rad), sinf(rad), 0.0f );
00177 
00178                 // delete waypoint once we reach it
00179                 if( math_dist3D(m_pos,m_waypoints[0]) < 1.0f )
00180                         m_waypoints.erase( m_waypoints.begin() );
00181         }
00182 }
00183 //------------------------------------------------------------------------------------
00184 void BattleGroup::moveUnits()
00185 {
00186         if(m_numUnits==0) return;
00187 
00188         // update each unit's target
00189         Vec3D halfSize = m_size * 0.5f;
00190         int rows = BattleUnitData::getObj().numRows()[m_unitType];
00191         int cols = BattleUnitData::getObj().numCols()[m_unitType];
00192         FLOAT backDelta  = m_size.x / rows;
00193         FLOAT rightDelta = m_size.y / cols;
00194         Vec3D frontLeftPt = math_translateObjectToWorld( m_pos, m_dir, Vec3D( halfSize.x,halfSize.y,0.0f) );
00195         Vec3D backVec     = math_translateObjectToWorld( m_pos, m_dir, Vec3D( halfSize.x-backDelta,halfSize.y,0.0f) ) - frontLeftPt;
00196         Vec3D rightVec    = math_translateObjectToWorld( m_pos, m_dir, Vec3D( halfSize.x,halfSize.y-rightDelta,0.0f) ) - frontLeftPt;
00197         for( int i=0; i<m_unitArraySize; i++ )
00198         {
00199                 FLOAT col = (FLOAT)(i%cols) + 0.5f;
00200                 FLOAT row = (FLOAT)(i/cols) + 0.5f;             
00201                 m_units[i].m_target = frontLeftPt + backVec*row + rightVec*col;
00202         }
00203 
00204         m_maxUnitDist = 0.0f;
00205         for( int i=0; i<m_unitArraySize; i++ )
00206         {
00207                 BattleUnit &u = m_units[i];
00208                 if( u.m_health<=0 ) continue;
00209 
00210                 // dec firing delay
00211                 u.m_firingDelay--;
00212 
00213                 // dec hit flare time
00214                 for( int i=0; i<MAX_RECV_HIT; i++ )             
00215                         u.m_recvHits[i].timeRemaining--;
00216 
00217                 FLOAT dist = math_dist3D(u.m_pos, u.m_target);
00218                 if( dist > m_maxUnitDist ) m_maxUnitDist = dist;
00219                 if( dist > 0.1f )
00220                 {
00221                         Vec3D targetVec = u.m_target - u.m_pos;
00222                         FLOAT targetDir = clipAngle( 90-D3DXToDegree( atan2f(targetVec.x,targetVec.y) ));
00223                         FLOAT currentDir = u.m_dir[0];
00224                         FLOAT delta;
00225                         if(targetDir>currentDir)
00226                         {
00227                                 delta = targetDir - currentDir;
00228                                 if(delta>180.0f) delta = delta - 360.0f;
00229                         }
00230                         else
00231                         {
00232                                 delta = targetDir - currentDir;
00233                                 if(delta<-180.0f) delta = 360.0f - delta;
00234                         }
00235                         const FLOAT turnRate = BattleUnitData::getObj().turnRate()[m_unitType];
00236                         FLOAT turnAngle = delta;
00237                         if( delta > turnRate ) turnAngle = turnRate;
00238                         else if( delta < -turnRate ) turnAngle = -turnRate;
00239                         else turnAngle = delta;
00240                         u.m_dir[0] = clipAngle( currentDir + turnAngle );                               // turn
00241 
00242                         // move if we're heading roughly the right way
00243                         FLOAT speed = 0.0f;
00244                         if( absf(delta)<10.0f ) speed = BattleUnitData::getObj().fullSpeed()[m_unitType];
00245                         else if( absf(delta)<30.0f ) speed = BattleUnitData::getObj().halfSpeed()[m_unitType];
00246                         if(speed>0.0f)
00247                         {
00248                                 FLOAT rad = D3DXToRadian( u.m_dir[0] );
00249                                 u.m_pos += speed * Vec3D( cosf(rad), sinf(rad), 0.0f );
00250                         }                       
00251                 }
00252                 else            // we're already close enough to target
00253                 {
00254                         u.m_dir = u.m_dir*0.99f + m_dir*0.01f;
00255                 }
00256         }
00257 }
00258 //------------------------------------------------------------------------------------
00259 void BattleGroup::acquireGroupTargets()
00260 {
00261         if(m_numUnits==0) return;
00262         m_targetGroups.resize(0);
00263         for( UINT i=0; i<BS->groups.size(); i++ )
00264                 if( m_team!=BS->groups[i].m_team && BS->groups[i].m_numUnits > 0)               // check if of different team
00265                         if( BS->groups[i].m_numUnits > 0 )
00266                         {
00267                                 FLOAT dist = math_dist3D( m_pos, BS->groups[i].m_pos );
00268                                 if( dist < m_statFiringRange*1.3f )                                                                     // check if near firing range
00269                                 {
00270                                         Vec3D dirVec = BS->groups[i].m_pos - m_pos;
00271                                         FLOAT angle = clipAngle( 90-D3DXToDegree( atan2f( dirVec.x, dirVec.y ) ) );
00272                                         FLOAT delta;
00273                                         if(angle>m_dir.x)
00274                                         {
00275                                                 delta = angle - m_dir.x;
00276                                                 if(delta>180.0f) delta = delta - 360.0f;
00277                                         }
00278                                         else
00279                                         {
00280                                                 delta = angle - m_dir.x;
00281                                                 if(delta<-180.0f) delta = 360.0f - delta;
00282                                         }
00283                                         if( absf(delta) < BattleUnitData::getObj().firingArc()[m_unitType] )    // check if in firing arc
00284                                                 m_targetGroups.push_back(i);
00285                                 }
00286                         }
00287 
00288         if( (m_primaryTarget==-1 && m_targetGroups.size()>0)            // if have no primary target, pick one randomly
00289                 || !m_isStrictPrimaryTarget )
00290         {
00291                 FLOAT minDist = 999999.0f;
00292                 int   bestIndex = 0;
00293                 for( int i=0; i<(int)m_targetGroups.size(); i++ )
00294                 {
00295                         int targetIndex = m_targetGroups[i];
00296                         FLOAT dist = math_distPlanar3D( m_pos, BS->groups[targetIndex].m_pos );
00297                         if( dist < minDist )
00298                         {
00299                                 bestIndex = targetIndex;
00300                                 minDist = dist;
00301                         }
00302                 }               
00303                 m_isChasePrimaryTarget = false;
00304                 m_isStrictPrimaryTarget = false;
00305                 m_primaryTarget = bestIndex;
00306         }
00307 
00308         if( m_targetGroups.size()==0 && !m_isStrictPrimaryTarget )
00309                 m_primaryTarget = -1;
00310 
00311 }
00312 //------------------------------------------------------------------------------------
00313 void BattleGroup::destroyUnit( BattleUnit &u )
00314 {
00315         if( BS->synch_firstKillTick == -1 )
00316         {
00317                 BS->synch_firstKillTick = currGameTick;
00318                 sys_console() << "BATTLE First Kill at tick = " << currGameTick << endl;
00319         }
00320 
00321         sys_console() << "BATTLE Boom pos=" << u.m_pos.x << ' ' << u.m_pos.y << ' ' << u.m_pos.z << endl;
00322         bool isActive = false;                                          // if this battle is active (player's watching it)
00323         if( GameState::activeBattle() )
00324                 if( GameState::activeBattle()->getBSPtr() == BS ) isActive = true;
00325         float vol = Sound::getMasterSFXVol();
00326         if( !isActive ) vol *= 0.92f;
00327         Vec3D playerCol( GameState::consolePlayer()->color() );
00328         if( BS->teamAColor!=playerCol && BS->teamBColor!=playerCol ) vol = 0.0f;
00329 
00330         // conditional voice
00331         Vec3D playerColor( GameState::consolePlayer()->color() );
00332         if( m_numUnits < 10 && m_color==playerColor )  playVoicePanick(*BS,isActive);
00333         if( m_numUnits < 20 && m_color==playerColor )  playVoiceStress(*BS,isActive);
00334 
00335         Vec3D pos = u.m_pos;
00336         pos.z += terrain_getHeight(BS->terrain, pos.x, pos.y );
00337         BS->sprites.push_back( BattleSprite( pos, 45, BattleSpriteTypes::EXPLO_LARGE ));
00338         BS->sprites.push_back( BattleSprite( pos, 75, BattleSpriteTypes::SMOKE_LARGE ));
00339         int numParticles = 2 + sys_randInt()%4;
00340         int numSmokes    = 2 + sys_randInt()%3;
00341         for( int i=0; i<numParticles; i++ )
00342         {
00343                 Vec3D pos2 = pos + Vec3D( 4*sys_randFloat(), 4*sys_randFloat(), sys_randFloat() );
00344                 BS->sprites.push_back( BattleSprite( pos2, 20, BattleSpriteTypes::EXPLO_SMALL ));
00345         }
00346         for( int i=0; i<numSmokes; i++ )
00347         {
00348                 Vec3D pos2 = pos + Vec3D( 6*sys_randFloat(), 6*sys_randFloat(), 2*sys_randFloat() );
00349                 BS->sprites.push_back( BattleSprite( pos2, 65, BattleSpriteTypes::SMOKE_SMALL ));
00350         }
00351 
00352         // debris
00353         int debrisType = sys_randInt()%2;
00354         Vec3D speed = Vec3D( 0.3f*sys_randFloat(), 0.3f*sys_randFloat(), 0.16f*(sys_randFloat()+1.0f) );        
00355         FLOAT dirSpeed = 3.5f;
00356         BS->debris.push_back( BattleDebris(pos,speed,dirSpeed,debrisType) );
00357 
00358         // vibration
00359         if( GameState::activeBattle() )
00360                 if( GameState::activeBattle()->getBSPtr() == BS )                       // we're participating in this battle
00361                         camera_addVibration(5.0f);
00362 
00363         // sound effect
00364         Sound::play(Sound::SMPL_SFX_EXPLOSION_LARGE,vol);
00365 }
00366 //------------------------------------------------------------------------------------
00367 void BattleGroup::fireAntiAir()
00368 {
00369         for( UINT i=0; i<BS->jets.size(); i++ )
00370         {
00371                 BattleJets &J = BS->jets[i];
00372                 if( math_distPlanar3D( m_pos, J.m_pos) < 100.0f )
00373                 {
00374                         for( int i=0; i<m_unitArraySize; i++ )
00375                         {
00376                                 BattleUnit &b = m_units[i];
00377                                 if( b.m_health<=0 ) continue;
00378                                 if( b.m_firingDelay>0 ) continue;
00379                                 if( sys_randInt()%10 < 9 ) continue;
00380                                 Vec3D bulletPos = b.m_pos;
00381                                 bulletPos.z += terrain_getHeight( BS->terrain, b.m_pos.x, b.m_pos.y );
00382                                 BS->addBullet( BattleBullet( BulletTypes::ANTIAIR, m_team, i, bulletPos, J.m_pos ));
00383                                 b.m_firingDelay = BattleUnitData::getObj().firingDelay()[ UnitTypes::LAUNCHER ];
00384                         }
00385                 }
00386         }
00387 }
00388 //------------------------------------------------------------------------------------
00389 void BattleGroup::fire()
00390 {
00391         if(m_numUnits==0) return;
00392         //if(m_unitType==UnitTypes::LAUNCHER) fireAntiAir();                            // launchers fire at jets
00393         if( m_primaryTarget==-1 ) return;
00394         if( BS->groups[m_primaryTarget].m_numUnits == 0 )                                       // need new target
00395         {
00396                 m_primaryTarget = -1;
00397                 return;
00398         }
00399         if(m_targetGroups.size()==0)  return;
00400 
00401         BattleGroup &targetGroup = BS->groups[m_primaryTarget];
00402         if( targetGroup.m_numUnits <= 0 ) return;
00403 
00404         bool isActive = false;                                          // if this battle is active (player's watching it)
00405         if( GameState::activeBattle() )
00406                 if( GameState::activeBattle()->getBSPtr() == BS ) isActive = true;      
00407         float vol = Sound::getMasterSFXVol();
00408         if( !isActive ) vol *= 0.92f;
00409         Vec3D playerCol( GameState::consolePlayer()->color() );
00410         if( BS->teamAColor!=playerCol && BS->teamBColor!=playerCol ) vol = 0.0f;
00411 
00412         const bool hasTurretArray[5] = { true, true, false, true, false };
00413         bool hasTurret = hasTurretArray[ m_unitType];
00414         FLOAT firingArc = BattleUnitData::getObj().firingArc()[m_unitType];
00415 
00416         for( int i=0; i<m_unitArraySize; i++ )
00417         {
00418                 BattleUnit &b = m_units[i];
00419                 if( b.m_health<=0 ) continue;
00420                 if( b.m_firingDelay>0 ) continue;
00421                 if( sys_randInt()%10 < 9 ) continue;            // add randomness so that not everyone fires at the same time
00422 
00423                 int targetNum = sys_randInt() % targetGroup.m_unitArraySize;
00424                 int attempt = 12;
00425                 while( targetGroup.m_units[targetNum].m_health <= 0 && attempt-->0 )
00426                         targetNum = (targetNum+1) % targetGroup.m_unitArraySize;
00427                 if( attempt <= 0 ) continue;                                                    // can't find a non-dead target
00428 
00429                 BattleUnit &target = targetGroup.m_units[targetNum];
00430                 
00431                 FLOAT targetDir = math_getDir( b.m_pos, target.m_pos );                 // check if in firing arc + rotate turret
00432                 FLOAT turretDir = b.m_dir.x + b.m_turretDir.x;
00433                 FLOAT deltaDir = math_deltaDir( turretDir, targetDir );
00434                 if( hasTurret )
00435                 {
00436                         const FLOAT turretArc = 5.0f;
00437                         const FLOAT turretTurnRate = 3.0f;
00438                         if( deltaDir < -turretArc || deltaDir > turretArc )                             // rotate turret
00439                         {
00440                                 deltaDir = min(deltaDir,turretTurnRate);
00441                                 deltaDir = max(deltaDir,-turretTurnRate);
00442                                 b.m_turretDir.x += deltaDir;
00443                                 b.m_turretDir.x = min( b.m_turretDir.x, firingArc );
00444                                 b.m_turretDir.x = max( b.m_turretDir.x, -firingArc );
00445                                 continue;
00446                         }
00447                 }
00448                 else
00449                 {
00450                         if( deltaDir < -firingArc || deltaDir > firingArc ) continue;           // out of firing arc
00451                 }
00452 
00453                 if( math_distPlanar3D(b.m_pos, target.m_pos) > m_statFiringRange ) continue;    // only fire if in range
00454 
00455                 if( m_color == GameState::consolePlayer()->color() )  playVoiceContact(*BS,isActive);
00456                 
00457                 if( BS->synch_firstShotTick == -1 )
00458                 {
00459                         BS->synch_firstShotTick = currGameTick;
00460                         sys_console() << "BATTLE First Shot Fired at tick = " << currGameTick << endl;
00461                 }       
00462                 
00463                 //sys_console() << "BATTLE Firing pos=" << b.m_pos.x << ' ' << b.m_pos.y << ' ' << b.m_pos.z
00464                 //                        << " turret = " << b.m_turretDir.x << endl;
00465 
00466                 Vec3D bulletPos = b.m_pos;
00467                 bulletPos.z += terrain_getHeight( BS->terrain, b.m_pos.x, b.m_pos.y );
00468                 Vec3D targetPos = target.m_pos;
00469                 targetPos.z += terrain_getHeight( BS->terrain, target.m_pos.x, target.m_pos.y );
00470 
00471                 switch(m_unitType)
00472                 {
00473                 case UnitTypes::LIGHT_TANK :
00474                         {
00475                                 target.m_health -= BattleUnitData::getObj().baseDamage()[m_unitType];
00476                                 target.m_recvHits[ target.m_recvHitIndex ] = RecvHitEntry( b.m_pos, BattleUnitData::getObj().lightTankHitFlareTime() );
00477                                 target.m_recvHitIndex = (target.m_recvHitIndex+1) % MAX_RECV_HIT;
00478                                 if( target.m_health<=0 )
00479                                 {
00480                                         destroyUnit(target);                                    
00481                                         targetGroup.m_numUnits--;
00482                                 }
00483                                 b.m_firingDelay = BattleUnitData::getObj().firingDelay()[ m_unitType ];
00484                                 Sound::play(Sound::SMPL_SFX_FIRE_LIGHTTANK,vol);
00485                         }
00486                         break;
00487 
00488                 case UnitTypes::HEAVY_TANK :
00489                         {
00490                                 target.m_health -= BattleUnitData::getObj().baseDamage()[m_unitType];
00491                                 target.m_recvHits[ target.m_recvHitIndex ] = RecvHitEntry( b.m_pos, BattleUnitData::getObj().lightTankHitFlareTime() );
00492                                 target.m_recvHitIndex = (target.m_recvHitIndex+1) % MAX_RECV_HIT;
00493                                 if( target.m_health<=0 )
00494                                 {
00495                                         destroyUnit(target);
00496                                         targetGroup.m_numUnits--;
00497                                 }
00498                                 b.m_firingDelay = BattleUnitData::getObj().firingDelay()[ m_unitType ];
00499                                 Sound::play(Sound::SMPL_SFX_FIRE_LIGHTTANK,vol);
00500                         }
00501                         break;
00502 
00503                 case UnitTypes::LAUNCHER :
00504                         {
00505                                 BS->addBullet( BattleBullet( BulletTypes::ROCKET, m_team, m_primaryTarget, bulletPos, targetPos ));
00506                                 b.m_firingDelay = BattleUnitData::getObj().firingDelay()[ m_unitType ];
00507                                 Sound::play(Sound::SMPL_SFX_FIRE_LAUNCHER,vol);
00508                         }
00509                         break;
00510 
00511                 case UnitTypes::ARTILLERY :
00512                         {                               
00513                                 BS->addBullet( BattleBullet( BulletTypes::SHELL, m_team, m_primaryTarget, bulletPos, targetPos ));
00514                                 b.m_firingDelay = BattleUnitData::getObj().firingDelay()[ m_unitType ];
00515                                 Sound::play(Sound::SMPL_SFX_FIRE_ARTILLERY,vol);
00516                         }
00517                         break;
00518 
00519                 case UnitTypes::JET :                   
00520                         break;
00521                         
00522                 }
00523                 
00524         }       
00525 }
00526 //------------------------------------------------------------------------------------
00527 void BattleGroup::takeHit( const BattleBullet &b )
00528 {
00529         if(b.m_type==BulletTypes::SHELL)
00530                 BS->sprites.push_back( BattleSprite( b.m_pos, 15,  BattleSpriteTypes::ARTIL_SHELL ));
00531 
00532         if(m_numUnits==0) return;
00533 
00534         for( int i=0; i<m_unitArraySize; i++ )
00535         {
00536                 BattleUnit &u = m_units[i];
00537                 if( u.m_health<=0 ) continue;
00538 
00539                 Vec3D delta = u.m_pos - b.m_pos;
00540                 FLOAT dist = sqrtf( delta.x*delta.x + delta.y*delta.y );
00541                 if( dist<8.0f )
00542                 {
00543                         u.m_health -= 50000;
00544                         u.m_recvHits[ u.m_recvHitIndex ] = RecvHitEntry( b.m_pos, 20 );
00545                         u.m_recvHitIndex = (u.m_recvHitIndex+1) % MAX_RECV_HIT;
00546                         if( u.m_health<=0 )
00547                         {
00548                                 destroyUnit(u);
00549                                 m_numUnits--;
00550                         }
00551                 }               
00552         }
00553 }
00554 //------------------------------------------------------------------------------------
00555 FLOAT triArea( Vec2D &p0, Vec2D &p1, Vec2D &p2 );       // use a helper function from ATerrain.cpp
00556 //------------------------------------------------------------------------------------
00557 bool BattleGroup::isContain2DPoint( Vec2D pt )
00558 {
00559         if(m_numUnits==0) return false;
00560 
00561         // calc the 4 corner pts of the box
00562         Vec3D halfSize = m_size * 0.5f;
00563         Vec3D pt3D1 = math_translateObjectToWorld( m_pos, m_dir, Vec3D( -halfSize.x, -halfSize.y,0.0f) );
00564         Vec3D pt3D2 = math_translateObjectToWorld( m_pos, m_dir, Vec3D( +halfSize.x, -halfSize.y,0.0f) );
00565         Vec3D pt3D3 = math_translateObjectToWorld( m_pos, m_dir, Vec3D( +halfSize.x, +halfSize.y,0.0f) );
00566         Vec3D pt3D4 = math_translateObjectToWorld( m_pos, m_dir, Vec3D( -halfSize.x, +halfSize.y,0.0f) );
00567         pt3D1.z += terrain_getHeight( BS->terrain, pt3D1.x, pt3D1.y );
00568         pt3D2.z += terrain_getHeight( BS->terrain, pt3D2.x, pt3D2.y );
00569         pt3D3.z += terrain_getHeight( BS->terrain, pt3D3.x, pt3D3.y );
00570         pt3D4.z += terrain_getHeight( BS->terrain, pt3D4.x, pt3D4.y );
00571         Vec2D pt2D1 = math_translateWorldToScreen(pt3D1);
00572         Vec2D pt2D2 = math_translateWorldToScreen(pt3D2);
00573         Vec2D pt2D3 = math_translateWorldToScreen(pt3D3);
00574         Vec2D pt2D4 = math_translateWorldToScreen(pt3D4);
00575         int outsideCount = 0;
00576         if( pt2D1.x<0 || pt2D1.x>1 || pt2D1.y<0 || pt2D1.y>1 ) outsideCount++;
00577         if( pt2D2.x<0 || pt2D2.x>1 || pt2D2.y<0 || pt2D2.y>1 ) outsideCount++;
00578         if( pt2D3.x<0 || pt2D3.x>1 || pt2D3.y<0 || pt2D3.y>1 ) outsideCount++;
00579         if( pt2D4.x<0 || pt2D4.x>1 || pt2D4.y<0 || pt2D4.y>1 ) outsideCount++;
00580         if(outsideCount==4) return false;
00581         FLOAT triAreas = triArea(pt2D1,pt2D2,pt) + triArea(pt2D2,pt2D3,pt)
00582                            + triArea(pt2D3,pt2D4,pt) + triArea(pt2D4,pt2D1,pt);
00583         FLOAT rectArea = triArea(pt2D1,pt2D2,pt2D3) + triArea(pt2D3,pt2D4,pt2D1);
00584         return triAreas <= rectArea * 1.05f;
00585 }
00586 //------------------------------------------------------------------------------------
00587 void BattleGroup::drawOutlineBox( Vec3D c )
00588 {
00589         if(m_numUnits==0) return;
00590         // calc the 4 corner pts of the box
00591         Vec3D halfSize = m_size * 0.5f;
00592         Vec3D pt3D1 = math_translateObjectToWorld( m_pos, m_dir, Vec3D( -halfSize.x, -halfSize.y,0.0f) );
00593         Vec3D pt3D2 = math_translateObjectToWorld( m_pos, m_dir, Vec3D( +halfSize.x, -halfSize.y,0.0f) );
00594         Vec3D pt3D3 = math_translateObjectToWorld( m_pos, m_dir, Vec3D( +halfSize.x, +halfSize.y,0.0f) );
00595         Vec3D pt3D4 = math_translateObjectToWorld( m_pos, m_dir, Vec3D( -halfSize.x, +halfSize.y,0.0f) );
00596         pt3D1.z += terrain_getHeight( BS->terrain, pt3D1.x, pt3D1.y );
00597         pt3D2.z += terrain_getHeight( BS->terrain, pt3D2.x, pt3D2.y );
00598         pt3D3.z += terrain_getHeight( BS->terrain, pt3D3.x, pt3D3.y );
00599         pt3D4.z += terrain_getHeight( BS->terrain, pt3D4.x, pt3D4.y );
00600         Vec2D pt2D1 = math_translateWorldToScreen(pt3D1);
00601         Vec2D pt2D2 = math_translateWorldToScreen(pt3D2);
00602         Vec2D pt2D3 = math_translateWorldToScreen(pt3D3);
00603         Vec2D pt2D4 = math_translateWorldToScreen(pt3D4);
00604         overlay_line(pt2D1, pt2D2, c );
00605         overlay_line(pt2D2, pt2D3, c );
00606         overlay_line(pt2D3, pt2D4, c );
00607         overlay_line(pt2D4, pt2D1, c );
00608 }
00609 //------------------------------------------------------------------------------------
00610 void BattleGroup::render()
00611 {
00612         if( m_numUnits<=0 ) return;
00613         
00614         AMesh chasis=-1, turret=-1;
00615         ATexture texture=-1;
00616         Vec3D chasisSize, turretSize;
00617         Vec3D shadowVec = camera_getVec();                      // offset for shadow position
00618         FLOAT shadowSize;
00619         shadowVec.z = 0.0f;
00620 
00621         switch(m_unitType)
00622         {
00623         case UnitTypes::LIGHT_TANK :
00624                 chasis     = artWork->lightTank_mesh;
00625                 turret     = artWork->lightTankTurret_mesh;
00626                 texture    = artWork->lightTank_texture;
00627                 chasisSize = BattleUnitData::getObj().lightTankSize();
00628                 turretSize = BattleUnitData::getObj().lightTankTurretSize();
00629                 shadowSize = 6.0f;
00630                 break;
00631         case UnitTypes::HEAVY_TANK :
00632                 chasis     = artWork->heavyTank_mesh;
00633                 turret     = artWork->heavyTankTurret_mesh;
00634                 texture    = artWork->heavyTank_texture;
00635                 chasisSize = BattleUnitData::getObj().heavyTankSize();
00636                 turretSize = BattleUnitData::getObj().heavyTankTurretSize();
00637                 shadowSize = 7.0f;
00638                 break;
00639         case UnitTypes::LAUNCHER :
00640                 chasis     = artWork->launcher_mesh;
00641                 texture    = artWork->launcher_texture;
00642                 chasisSize = BattleUnitData::getObj().launcherSize();
00643                 shadowSize = 6.0f;
00644                 break;
00645         case UnitTypes::ARTILLERY :
00646                 chasis     = artWork->artillery_mesh;
00647                 turret     = artWork->artilleryTurret_mesh;
00648                 texture    = artWork->artillery_texture;
00649                 chasisSize = BattleUnitData::getObj().artillerySize();
00650                 turretSize = BattleUnitData::getObj().artilleryTurretSize();
00651                 shadowSize = 6.0f;
00652                 break;
00653         case UnitTypes::JET :
00654                 chasis     = artWork->jet_mesh;
00655                 texture    = artWork->jet_texture;
00656                 chasisSize = BattleUnitData::getObj().jetSize();
00657                 shadowSize = 6.0f;
00658                 break;
00659         }
00660 
00661 
00662         for( int i=0; i<m_unitArraySize; i++ )
00663         {
00664                 BattleUnit &u = m_units[i];
00665                 if( u.m_health<=0 ) continue;
00666                 Vec3D pos = u.m_pos;
00667                 pos.z += 0.32f + terrain_getHeight(BS->terrain,pos.x, pos.y);
00668                 
00669                 // chasis & (optional) turret
00670                 mesh_render( chasis, pos, chasisSize, u.m_dir, texture, NULL, m_color );
00671                 if(turret!=-1) mesh_render( turret, pos, turretSize, u.m_dir+u.m_turretDir, texture, NULL, m_color );
00672 
00673                 // unit shadow          
00674                 const Vec4D mult(1,1,1,0.33f);
00675                 sprite_add(artWork->shadow, BlendModes::MIX, pos+shadowVec, mult, shadowSize );
00676 
00677                 // firing flare
00678                 const Vec4D noBlend(1.0f,1.0f,1.0f,1.0f);
00679                 int fireDelay = BattleUnitData::getObj().firingDelay()[ m_unitType];
00680                 if( (m_unitType==UnitTypes::LIGHT_TANK && u.m_firingDelay > fireDelay-5) ||
00681                         (m_unitType==UnitTypes::HEAVY_TANK && u.m_firingDelay > fireDelay-5) )
00682                 {                       
00683                         FLOAT rad = D3DXToRadian( u.m_dir[0] );
00684                         Vec3D target = pos + Vec3D( cosf(rad), sinf(rad), 0.5f );
00685                         flare_addParticle( pos, target, noBlend, 3.0f, 0.3f*(fireDelay-u.m_firingDelay) );
00686                         flare_addParticle( pos, target, noBlend, 5.0f, 0.5f*(fireDelay-u.m_firingDelay) );
00687                 }
00688 
00689                 // hit flare
00690                 for( int i=0; i<MAX_RECV_HIT; i++ )
00691                 {
00692                         static Vec4D mult(1,1,1,1);
00693                         RecvHitEntry &e = u.m_recvHits[i];
00694                         mult.w = (20.0f-e.timeRemaining) / 32.0f;
00695                         if( e.timeRemaining > 0 )
00696                                 flare_addParticle( pos, e.from, mult, 2.0f, 6.0f );
00697                 }
00698         }
00699 
00700         // battle group icon
00701         //mesh_render( artWork->battleGroupMesh, m_pos - Vec3D(0.0f,0.0f,0.6f), m_size,m_dir, artWork->battleGroupTexture );
00702         
00703         Vec3D prevPt = m_pos;                                                                                   // waypoints
00704         for( UINT i=0; i<m_waypoints.size(); i++ )
00705         {
00706                 Vec3D pt13D(prevPt), pt23D(m_waypoints[i]), pt33D(m_waypoints[i]);
00707                 pt13D.z += terrain_getHeight(BS->terrain, pt13D.x, pt13D.y );
00708                 pt23D.z += terrain_getHeight(BS->terrain, pt23D.x, pt23D.y );
00709                 Vec2D pt1 = math_translateWorldToScreen( pt13D );
00710                 Vec2D pt2 = math_translateWorldToScreen( pt23D );
00711                 Vec2D pt3 = math_translateWorldToScreen( pt33D );
00712                 overlay_line( pt1, pt2, Colors::green );
00713                 overlay_line( pt2, pt3, Colors::gray );
00714                 overlay_point( pt2, 2.0f, Colors::red );
00715                 prevPt = m_waypoints[i];
00716         }
00717 
00718         // primary target
00719         if( m_primaryTarget!=-1 )
00720         {
00721                 Vec3D pt13D( m_pos );
00722                 pt13D.z += terrain_getHeight(BS->terrain, pt13D.x, pt13D.y );
00723                 Vec2D pt1 = math_translateWorldToScreen( pt13D );
00724         
00725                 Vec3D pt23D( BS->groups[ m_primaryTarget ].m_pos );
00726                 pt23D.z += terrain_getHeight(BS->terrain, pt23D.x, pt23D.y );
00727                 Vec2D pt2 = math_translateWorldToScreen( pt23D );
00728                 overlay_line( pt1, pt2, Colors::red );
00729         }
00730 }
00731 //------------------------------------------------------------------------------------

Generated on Wed Apr 23 05:50:14 2003 for Modern Warfare by doxygen1.3-rc2