00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
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
00030
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
00127
00128
00129
00130
00131 if(m_numUnits==0) return;
00132
00133 if( m_primaryTarget!=-1 && m_isChasePrimaryTarget )
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;
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 );
00165
00166
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;
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
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
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
00211 u.m_firingDelay--;
00212
00213
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 );
00241
00242
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
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)
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 )
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] )
00284 m_targetGroups.push_back(i);
00285 }
00286 }
00287
00288 if( (m_primaryTarget==-1 && m_targetGroups.size()>0)
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;
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
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
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
00359 if( GameState::activeBattle() )
00360 if( GameState::activeBattle()->getBSPtr() == BS )
00361 camera_addVibration(5.0f);
00362
00363
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
00393 if( m_primaryTarget==-1 ) return;
00394 if( BS->groups[m_primaryTarget].m_numUnits == 0 )
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;
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;
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;
00428
00429 BattleUnit &target = targetGroup.m_units[targetNum];
00430
00431 FLOAT targetDir = math_getDir( b.m_pos, target.m_pos );
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 )
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;
00451 }
00452
00453 if( math_distPlanar3D(b.m_pos, target.m_pos) > m_statFiringRange ) continue;
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
00464
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 );
00556
00557 bool BattleGroup::isContain2DPoint( Vec2D pt )
00558 {
00559 if(m_numUnits==0) return false;
00560
00561
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
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();
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
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
00674 const Vec4D mult(1,1,1,0.33f);
00675 sprite_add(artWork->shadow, BlendModes::MIX, pos+shadowVec, mult, shadowSize );
00676
00677
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
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
00701
00702
00703 Vec3D prevPt = m_pos;
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
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