Advertisement
Guest User

Untitled

a guest
Sep 29th, 2010
244
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 32.05 KB | None | 0 0
  1. #include maps\mp\_utility;
  2. #include maps\mp\killstreaks\_harrier;
  3. #include maps\mp\gametypes\_hud_util;
  4. #include common_scripts\utility;
  5.  
  6. init()
  7. {
  8. precacheLocationSelector( "map_artillery_selector" );
  9. precacheString( &"MP_WAR_AIRSTRIKE_INBOUND_NEAR_YOUR_POSITION" );
  10. precacheString( &"MP_WAR_AIRSTRIKE_INBOUND" );
  11. precacheString( &"MP_CIVILIAN_AIR_TRAFFIC" );
  12. precacheString( &"MP_AIR_SPACE_TOO_CROWDED" );
  13. precacheItem( "stealth_bomb_mp" );
  14. precacheItem( "artillery_mp" );
  15. precacheItem("harrier_missile_mp");
  16. precacheModel( "vehicle_av8b_harrier_jet_mp" );
  17. precacheModel( "vehicle_av8b_harrier_jet_opfor_mp" );
  18. precacheModel( "weapon_minigun" );
  19. precacheModel( "vehicle_b2_bomber" );
  20. PrecacheVehicle( "harrier_mp" );
  21. precacheTurret( "harrier_FFAR_mp" );
  22. PrecacheMiniMapIcon( "compass_objpoint_airstrike_friendly" );
  23. PrecacheMiniMapIcon( "compass_objpoint_airstrike_busy" );
  24. PrecacheMiniMapIcon( "compass_objpoint_b2_airstrike_friendly" );
  25. PrecacheMiniMapIcon( "compass_objpoint_b2_airstrike_enemy" );
  26. PrecacheMiniMapIcon( "hud_minimap_harrier_green" );
  27. PrecacheMiniMapIcon( "hud_minimap_harrier_red" );
  28.  
  29.  
  30. level.onfirefx = loadfx ("fire/fire_smoke_trail_L");
  31. level.airstrikefx = loadfx ("explosions/clusterbomb");
  32. level.mortareffect = loadfx ("explosions/artilleryExp_dirt_brown");
  33. level.bombstrike = loadfx ("explosions/wall_explosion_pm_a");
  34. level.stealthbombfx = loadfx ("explosions/stealth_bomb_mp");
  35.  
  36. level.airplane = [];
  37. level.harriers = [];
  38. level.planes = 0;
  39.  
  40. level.harrier_smoke = loadfx("fire/jet_afterburner_harrier_damaged");
  41. level.harrier_deathfx = loadfx ("explosions/aerial_explosion_harrier");
  42. level.harrier_afterburnerfx = loadfx ("fire/jet_afterburner_harrier");
  43. level.fx_airstrike_afterburner = loadfx ("fire/jet_afterburner");
  44. level.fx_airstrike_contrail = loadfx ("smoke/jet_contrail");
  45.  
  46. // airstrike danger area is the circle of radius artilleryDangerMaxRadius
  47. // stretched by a factor of artilleryDangerOvalScale in the direction of the incoming airstrike,
  48. // moved by artilleryDangerForwardPush * artilleryDangerMaxRadius in the same direction.
  49. // use scr_Airstrikedebug to visualize.
  50.  
  51. level.dangerMaxRadius["stealth"] = 900;
  52. level.dangerMinRadius["stealth"] = 750;
  53. level.dangerForwardPush["stealth"] = 1;
  54. level.dangerOvalScale["stealth"] = 6.0;
  55.  
  56. level.dangerMaxRadius["default"] = 550;
  57. level.dangerMinRadius["default"] = 300;
  58. level.dangerForwardPush["default"] = 1.5;
  59. level.dangerOvalScale["default"] = 6.0;
  60.  
  61. level.dangerMaxRadius["precision"] = 550;
  62. level.dangerMinRadius["precision"] = 300;
  63. level.dangerForwardPush["precision"] = 2.0;
  64. level.dangerOvalScale["precision"] = 6.0;
  65.  
  66. level.dangerMaxRadius["harrier"] = 550;
  67. level.dangerMinRadius["harrier"] = 300;
  68. level.dangerForwardPush["harrier"] = 1.5;
  69. level.dangerOvalScale["harrier"] = 6.0;
  70.  
  71. level.artilleryDangerCenters = [];
  72.  
  73. level.killStreakFuncs["airstrike"] = ::tryUseAirstrike;
  74. level.killStreakFuncs["precision_airstrike"] = ::tryUsePrecisionAirstrike;
  75. level.killStreakFuncs["super_airstrike"] = ::tryUseSuperAirstrike;
  76. level.killStreakFuncs["harrier_airstrike"] = ::tryUseHarrierAirstrike;
  77. level.killStreakFuncs["stealth_airstrike"] = ::tryUseStealthAirstrike;
  78. }
  79.  
  80.  
  81. tryUsePrecisionAirstrike( lifeId )
  82. {
  83. return tryUseAirstrike( lifeId, "precision" );
  84. }
  85.  
  86. tryUseStealthAirstrike( lifeId )
  87. {
  88. return tryUseAirstrike( lifeId, "stealth" );
  89. }
  90.  
  91. tryUseSuperAirstrike( lifeId )
  92. {
  93. return tryUseAirstrike( lifeId, "super" );
  94. }
  95.  
  96. tryUseHarrierAirstrike( lifeId )
  97. {
  98. return tryUseAirstrike( lifeId, "harrier" );
  99. }
  100.  
  101.  
  102. tryUseAirstrike( lifeId, airStrikeType )
  103. {
  104. if ( isDefined( level.civilianJetFlyBy ) )
  105. {
  106. self iPrintLnBold( &"MP_CIVILIAN_AIR_TRAFFIC" );
  107. return false;
  108. }
  109.  
  110. if ( self isUsingRemote() )
  111. {
  112. return false;
  113. }
  114.  
  115. if ( !isDefined( airStrikeType ) )
  116. airStrikeType = "none";
  117.  
  118. switch( airStrikeType )
  119. {
  120. case "precision":
  121. break;
  122. case "stealth":
  123. break;
  124. case "harrier":
  125. if ( level.planes > 1 )
  126. {
  127. self iPrintLnBold( &"MP_AIR_SPACE_TOO_CROWDED" );
  128. return false;
  129. }
  130. break;
  131. case "super":
  132. break;
  133. }
  134.  
  135. result = self selectAirstrikeLocation( lifeId, airStrikeType );
  136.  
  137. if ( !isDefined( result ) || !result )
  138. return false;
  139.  
  140. return true;
  141. }
  142.  
  143.  
  144. doAirstrike( lifeId, origin, yaw, owner, team )
  145. {
  146. assert( isDefined( origin ) );
  147. assert( isDefined( yaw ) );
  148.  
  149. if ( isDefined( self.airStrikeType ) )
  150. airstrikeType = self.airStrikeType;
  151. else
  152. airstrikeType = "default";
  153.  
  154. if ( airStrikeType == "harrier" )
  155. level.planes++;
  156.  
  157. if ( isDefined( level.airstrikeInProgress ) )
  158. {
  159. while ( isDefined( level.airstrikeInProgress ) )
  160. level waittill ( "begin_airstrike" );
  161.  
  162. level.airstrikeInProgress = true;
  163. wait ( 2.0 );
  164. }
  165.  
  166. if ( !isDefined( owner ) )
  167. {
  168. if ( airStrikeType == "harrier" )
  169. level.planes--;
  170.  
  171. return;
  172. }
  173.  
  174. level.airstrikeInProgress = true;
  175.  
  176. num = 17 + randomint(3);
  177. trace = bullettrace(origin, origin + (0,0,-1000000), false, undefined);
  178. targetpos = trace["position"];
  179.  
  180. if ( level.teambased )
  181. {
  182. players = level.players;
  183.  
  184. for ( i = 0; i < level.players.size; i++ )
  185. {
  186. player = level.players[i];
  187. playerteam = player.pers["team"];
  188. if ( isdefined( playerteam ) )
  189. {
  190. if ( playerteam == team && self.airStrikeType != "stealth" )
  191. player iprintln( &"MP_WAR_AIRSTRIKE_INBOUND", owner );
  192. }
  193. }
  194. }
  195. else
  196. {
  197. if ( !level.hardcoreMode )
  198. {
  199. if ( pointIsInAirstrikeArea( owner.origin, targetpos, yaw, airstrikeType ) )
  200. owner iprintlnbold(&"MP_WAR_AIRSTRIKE_INBOUND_NEAR_YOUR_POSITION");
  201. }
  202. }
  203.  
  204. dangerCenter = spawnstruct();
  205. dangerCenter.origin = targetpos;
  206. dangerCenter.forward = anglesToForward( (0,yaw,0) );
  207. dangerCenter.airstrikeType = airstrikeType;
  208.  
  209. level.artilleryDangerCenters[ level.artilleryDangerCenters.size ] = dangerCenter;
  210. /# level thread debugArtilleryDangerCenters( airstrikeType ); #/
  211.  
  212. harrierEnt = callStrike( lifeId, owner, targetpos, yaw );
  213.  
  214. wait( 1.0 );
  215. level.airstrikeInProgress = undefined;
  216. owner notify ( "begin_airstrike" );
  217. level notify ( "begin_airstrike" );
  218.  
  219. wait 7.5;
  220.  
  221. found = false;
  222. newarray = [];
  223. for ( i = 0; i < level.artilleryDangerCenters.size; i++ )
  224. {
  225. if ( !found && level.artilleryDangerCenters[i].origin == targetpos )
  226. {
  227. found = true;
  228. continue;
  229. }
  230.  
  231. newarray[ newarray.size ] = level.artilleryDangerCenters[i];
  232. }
  233. assert( found );
  234. assert( newarray.size == level.artilleryDangerCenters.size - 1 );
  235. level.artilleryDangerCenters = newarray;
  236.  
  237. if ( airStrikeType != "harrier" )
  238. return;
  239.  
  240. while ( isDefined( harrierEnt ) )
  241. wait ( 0.1 );
  242.  
  243. level.planes--;
  244. }
  245.  
  246.  
  247. clearProgress( delay )
  248. {
  249. wait ( 2.0 );
  250.  
  251. level.airstrikeInProgress = undefined;
  252. }
  253.  
  254.  
  255. /#
  256. debugArtilleryDangerCenters( airstrikeType )
  257. {
  258. level notify("debugArtilleryDangerCenters_thread");
  259. level endon("debugArtilleryDangerCenters_thread");
  260.  
  261. if ( getdvarint("scr_airstrikedebug") != 1 && getdvarint("scr_spawnpointdebug") == 0 )
  262. {
  263. return;
  264. }
  265.  
  266. while( level.artilleryDangerCenters.size > 0 )
  267. {
  268. for ( i = 0; i < level.artilleryDangerCenters.size; i++ )
  269. {
  270. origin = level.artilleryDangerCenters[i].origin;
  271. forward = level.artilleryDangerCenters[i].forward;
  272.  
  273. origin += forward * level.dangerForwardPush[airstrikeType] * level.dangerMaxRadius[airstrikeType];
  274.  
  275. previnnerpos = (0,0,0);
  276. prevouterpos = (0,0,0);
  277. for ( j = 0; j <= 40; j++ )
  278. {
  279. frac = (j * 1.0) / 40;
  280. angle = frac * 360;
  281. dir = anglesToForward((0,angle,0));
  282. forwardPart = vectordot( dir, forward ) * forward;
  283. perpendicularPart = dir - forwardPart;
  284. pos = forwardPart * level.dangerOvalScale[airstrikeType] + perpendicularPart;
  285. innerpos = pos * level.dangerMinRadius[airstrikeType];
  286. innerpos += origin;
  287. outerpos = pos * level.dangerMaxRadius[airstrikeType];
  288. outerpos += origin;
  289.  
  290. if ( j > 0 )
  291. {
  292. line( innerpos, previnnerpos, (1, 0, 0) );
  293. line( outerpos, prevouterpos, (1,.5,.5) );
  294. }
  295.  
  296. previnnerpos = innerpos;
  297. prevouterpos = outerpos;
  298. }
  299. }
  300. wait .05;
  301. }
  302. }
  303. #/
  304.  
  305. getAirstrikeDanger( point )
  306. {
  307. danger = 0;
  308. for ( i = 0; i < level.artilleryDangerCenters.size; i++ )
  309. {
  310. origin = level.artilleryDangerCenters[i].origin;
  311. forward = level.artilleryDangerCenters[i].forward;
  312. airstrikeType = level.artilleryDangerCenters[i].airstrikeType;
  313.  
  314. danger += getSingleAirstrikeDanger( point, origin, forward, airstrikeType );
  315. }
  316. return danger;
  317. }
  318.  
  319. getSingleAirstrikeDanger( point, origin, forward, airstrikeType )
  320. {
  321. center = origin + level.dangerForwardPush[airstrikeType] * level.dangerMaxRadius[airstrikeType] * forward;
  322.  
  323. diff = point - center;
  324. diff = (diff[0], diff[1], 0);
  325.  
  326. forwardPart = vectorDot( diff, forward ) * forward;
  327. perpendicularPart = diff - forwardPart;
  328.  
  329. circlePos = perpendicularPart + forwardPart / level.dangerOvalScale[airstrikeType];
  330.  
  331. /* /#
  332. if ( getdvar("scr_airstrikedebug") == "1" )
  333. {
  334. thread airstrikeLine( center, center + perpendicularPart, (1,1,1), 50 );
  335. thread airstrikeLine( center + perpendicularPart, center + circlePos, (1,1,1), 50 );
  336. thread airstrikeLine( center + circlePos, point, (.5,.5,.5), 50 );
  337. }
  338. #/ */
  339.  
  340. distsq = lengthSquared( circlePos );
  341.  
  342. if ( distsq > level.dangerMaxRadius[airstrikeType] * level.dangerMaxRadius[airstrikeType] )
  343. return 0;
  344.  
  345. if ( distsq < level.dangerMinRadius[airstrikeType] * level.dangerMinRadius[airstrikeType] )
  346. return 1;
  347.  
  348. dist = sqrt( distsq );
  349. distFrac = (dist - level.dangerMinRadius[airstrikeType]) / (level.dangerMaxRadius[airstrikeType] - level.dangerMinRadius[airstrikeType]);
  350.  
  351. assertEx( distFrac >= 0 && distFrac <= 1, distFrac );
  352.  
  353. return 1 - distFrac;
  354. }
  355.  
  356.  
  357. pointIsInAirstrikeArea( point, targetpos, yaw, airstrikeType )
  358. {
  359. return distance2d( point, targetpos ) <= level.dangerMaxRadius[airstrikeType] * 1.25;
  360. // TODO
  361. //return getSingleAirstrikeDanger( point, targetpos, yaw ) > 0;
  362. }
  363.  
  364.  
  365. losRadiusDamage( pos, radius, max, min, owner, eInflictor, sWeapon )
  366. {
  367. ents = maps\mp\gametypes\_weapons::getDamageableEnts(pos, radius, true);
  368.  
  369. glassRadiusDamage( pos, radius, max, min );
  370.  
  371. for (i = 0; i < ents.size; i++)
  372. {
  373. if (ents[i].entity == self)
  374. continue;
  375.  
  376. dist = distance(pos, ents[i].damageCenter);
  377.  
  378. if ( ents[i].isPlayer || ( isDefined( ents[i].isSentry ) && ents[i].isSentry ) )
  379. {
  380. // check if there is a path to this entity 130 units above his feet. if not, they're probably indoors
  381. indoors = !BulletTracePassed( ents[i].entity.origin, ents[i].entity.origin + (0,0,130), false, undefined );
  382. if ( indoors )
  383. {
  384. indoors = !BulletTracePassed( ents[i].entity.origin + (0,0,130), pos + (0,0,130 - 16), false, undefined );
  385. if ( indoors )
  386. {
  387. // give them a distance advantage for being indoors.
  388. dist *= 4;
  389. if ( dist > radius )
  390. continue;
  391. }
  392. }
  393. }
  394.  
  395. ents[i].damage = int(max + (min-max)*dist/radius);
  396. ents[i].pos = pos;
  397. ents[i].damageOwner = owner;
  398. ents[i].eInflictor = eInflictor;
  399. level.airStrikeDamagedEnts[level.airStrikeDamagedEntsCount] = ents[i];
  400. level.airStrikeDamagedEntsCount++;
  401. }
  402.  
  403. thread airstrikeDamageEntsThread( sWeapon );
  404. }
  405.  
  406.  
  407. airstrikeDamageEntsThread( sWeapon )
  408. {
  409. self notify ( "airstrikeDamageEntsThread" );
  410. self endon ( "airstrikeDamageEntsThread" );
  411.  
  412. for ( ; level.airstrikeDamagedEntsIndex < level.airstrikeDamagedEntsCount; level.airstrikeDamagedEntsIndex++ )
  413. {
  414. if ( !isDefined( level.airstrikeDamagedEnts[level.airstrikeDamagedEntsIndex] ) )
  415. continue;
  416.  
  417. ent = level.airstrikeDamagedEnts[level.airstrikeDamagedEntsIndex];
  418.  
  419. if ( !isDefined( ent.entity ) )
  420. continue;
  421.  
  422. if ( !ent.isPlayer || isAlive( ent.entity ) )
  423. {
  424. ent maps\mp\gametypes\_weapons::damageEnt(
  425. ent.eInflictor, // eInflictor = the entity that causes the damage (e.g. a claymore)
  426. ent.damageOwner, // eAttacker = the player that is attacking
  427. ent.damage, // iDamage = the amount of damage to do
  428. "MOD_PROJECTILE_SPLASH", // sMeansOfDeath = string specifying the method of death (e.g. "MOD_PROJECTILE_SPLASH")
  429. sWeapon, // sWeapon = string specifying the weapon used (e.g. "claymore_mp")
  430. ent.pos, // damagepos = the position damage is coming from
  431. vectornormalize(ent.damageCenter - ent.pos) // damagedir = the direction damage is moving in
  432. );
  433.  
  434. level.airstrikeDamagedEnts[level.airstrikeDamagedEntsIndex] = undefined;
  435.  
  436. if ( ent.isPlayer )
  437. wait ( 0.05 );
  438. }
  439. else
  440. {
  441. level.airstrikeDamagedEnts[level.airstrikeDamagedEntsIndex] = undefined;
  442. }
  443. }
  444. }
  445.  
  446.  
  447. radiusArtilleryShellshock(pos, radius, maxduration, minduration, team )
  448. {
  449. players = level.players;
  450.  
  451. foreach ( player in level.players )
  452. {
  453. if ( !isAlive( player ) )
  454. continue;
  455.  
  456. if ( player.team == team || player.team == "spectator" )
  457. continue;
  458.  
  459. playerPos = player.origin + (0,0,32);
  460. dist = distance( pos, playerPos );
  461.  
  462. if ( dist > radius )
  463. continue;
  464.  
  465. duration = int(maxduration + (minduration-maxduration)*dist/radius);
  466. player thread artilleryShellshock( "default", duration );
  467. }
  468. }
  469.  
  470.  
  471. artilleryShellshock(type, duration)
  472. {
  473. self endon ( "disconnect" );
  474.  
  475. if (isdefined(self.beingArtilleryShellshocked) && self.beingArtilleryShellshocked)
  476. return;
  477. self.beingArtilleryShellshocked = true;
  478.  
  479. self shellshock(type, duration);
  480. wait(duration + 1);
  481.  
  482. self.beingArtilleryShellshocked = false;
  483. }
  484.  
  485.  
  486. /#
  487. airstrikeLine( start, end, color, duration )
  488. {
  489. frames = duration * 20;
  490. for ( i = 0; i < frames; i++ )
  491. {
  492. line(start,end,color);
  493. wait .05;
  494. }
  495. }
  496.  
  497.  
  498. traceBomb()
  499. {
  500. self endon("death");
  501. prevpos = self.origin;
  502. while(1)
  503. {
  504. thread airstrikeLine( prevpos, self.origin, (.5,1,0), 40 );
  505. prevpos = self.origin;
  506. wait .2;
  507. }
  508. }
  509. #/
  510.  
  511.  
  512. doBomberStrike( lifeId, owner, requiredDeathCount, bombsite, startPoint, endPoint, bombTime, flyTime, direction, airStrikeType )
  513. {
  514. // plane spawning randomness = up to 125 units, biased towards 0
  515. // radius of bomb damage is 512
  516.  
  517. if ( !isDefined( owner ) )
  518. return;
  519.  
  520. startPathRandomness = 100;
  521. endPathRandomness = 150;
  522.  
  523. pathStart = startPoint + ( (randomfloat(2) - 1)*startPathRandomness, (randomfloat(2) - 1)*startPathRandomness, 0 );
  524. pathEnd = endPoint + ( (randomfloat(2) - 1)*endPathRandomness , (randomfloat(2) - 1)*endPathRandomness , 0 );
  525.  
  526. // Spawn the planes
  527. plane = spawnplane( owner, "script_model", pathStart, "compass_objpoint_b2_airstrike_friendly", "compass_objpoint_b2_airstrike_enemy" );
  528.  
  529. plane playLoopSound( "veh_b2_dist_loop" );
  530. plane setModel( "vehicle_b2_bomber" );
  531. plane thread handleEMP( owner );
  532. plane.lifeId = lifeId;
  533.  
  534. plane.angles = direction;
  535. forward = anglesToForward( direction );
  536. plane moveTo( pathEnd, flyTime, 0, 0 );
  537.  
  538. thread stealthBomber_killCam( plane, pathEnd, flyTime, airStrikeType );
  539.  
  540. thread bomberDropBombs( plane, bombsite, owner );
  541.  
  542. // Delete the plane after its flyby
  543. wait ( flyTime );
  544. plane notify( "delete" );
  545. plane delete();
  546. }
  547.  
  548.  
  549. bomberDropBombs( plane, bombSite, owner )
  550. {
  551. while ( !targetIsClose( plane, bombsite, 5000 ) )
  552. wait ( 0.05 );
  553.  
  554. //playfxontag( level.stealthbombfx, plane, "tag_left_alamo_missile" );
  555. //playfxontag( level.stealthbombfx, plane, "tag_right_alamo_missile" );
  556.  
  557. showFx = true;
  558. sonicBoom = false;
  559.  
  560. plane notify ( "start_bombing" );
  561.  
  562. plane thread playBombFx();
  563.  
  564. for ( dist = targetGetDist( plane, bombsite ); dist < 5000; dist = targetGetDist( plane, bombsite ) )
  565. {
  566. if ( dist < 1500 && !sonicBoom )
  567. {
  568. plane playSound( "veh_b2_sonic_boom" );
  569. sonicBoom = true;
  570. }
  571.  
  572. showFx = !showFx;
  573. if ( dist < 4500 )
  574. plane thread callStrike_bomb( plane.origin, owner, (0,0,0), showFx );
  575. wait ( 0.1 );
  576. }
  577.  
  578. plane notify ( "stop_bombing" );
  579.  
  580. //stopfxontag( level.stealthbombfx, plane, "tag_left_alamo_missile" );
  581. //stopfxontag( level.stealthbombfx, plane, "tag_right_alamo_missile" );
  582. }
  583.  
  584.  
  585. playBombFx()
  586. {
  587. self endon ( "stop_bombing" );
  588.  
  589. for ( ;; )
  590. {
  591. playFxOnTag( level.stealthbombfx, self, "tag_left_alamo_missile" );
  592. playFxOnTag( level.stealthbombfx, self, "tag_right_alamo_missile" );
  593.  
  594. wait ( 0.5 );
  595. }
  596. }
  597.  
  598.  
  599. stealthBomber_killCam( plane, pathEnd, flyTime, typeOfStrike )
  600. {
  601. plane waittill ( "start_bombing" );
  602.  
  603. planedir = anglesToForward( plane.angles );
  604.  
  605. killCamEnt = spawn( "script_model", plane.origin + (0,0,100) - planedir * 200 );
  606. plane.killCamEnt = killCamEnt;
  607. plane.airstrikeType = typeOfStrike;
  608. killCamEnt.startTime = gettime();
  609. killCamEnt thread deleteAfterTime( 15.0 );
  610.  
  611. killCamEnt linkTo( plane, "tag_origin", (-256,768,768), ( 0,0,0 ) );
  612. }
  613.  
  614.  
  615. callStrike_bomb( coord, owner, offset, showFx )
  616. {
  617. if ( !isDefined( owner ) || owner isEMPed() )
  618. {
  619. self notify( "stop_bombing" );
  620. return;
  621. }
  622.  
  623. accuracyRadius = 512;
  624.  
  625. randVec = ( 0, randomint( 360 ), 0 );
  626. bombPoint = coord + vector_multiply( anglestoforward( randVec ), randomFloat( accuracyRadius ) );
  627. trace = bulletTrace( bombPoint, bombPoint + (0,0,-10000), false, undefined );
  628.  
  629. bombPoint = trace["position"];
  630.  
  631. bombHeight = distance( coord, bombPoint );
  632.  
  633. if ( bombHeight > 5000 )
  634. return;
  635.  
  636. wait ( 0.85 * (bombHeight / 2000) );
  637.  
  638. if ( !isDefined( owner ) || owner isEMPed() )
  639. {
  640. self notify( "stop_bombing" );
  641. return;
  642. }
  643.  
  644. if ( showFx )
  645. {
  646. playFx( level.mortareffect, bombPoint );
  647.  
  648. PlayRumbleOnPosition( "grenade_rumble", bombPoint );
  649. earthquake( 1.0, 0.6, bombPoint, 2000 );
  650. }
  651.  
  652. thread playSoundInSpace( "exp_airstrike_bomb", bombPoint );
  653. radiusArtilleryShellshock( bombPoint, 512, 8, 4, owner.team );
  654. losRadiusDamage( bombPoint + (0,0,16), 896, 300, 50, owner, self, "stealth_bomb_mp" ); // targetpos, radius, maxdamage, mindamage, player causing damage
  655. }
  656.  
  657.  
  658. doPlaneStrike( lifeId, owner, requiredDeathCount, bombsite, startPoint, endPoint, bombTime, flyTime, direction, typeOfStrike )
  659. {
  660. // plane spawning randomness = up to 125 units, biased towards 0
  661. // radius of bomb damage is 512
  662.  
  663. if ( !isDefined( owner ) )
  664. return;
  665.  
  666. startPathRandomness = 100;
  667. endPathRandomness = 150;
  668.  
  669. pathStart = startPoint + ( (randomfloat(2) - 1)*startPathRandomness, (randomfloat(2) - 1)*startPathRandomness, 0 );
  670. pathEnd = endPoint + ( (randomfloat(2) - 1)*endPathRandomness , (randomfloat(2) - 1)*endPathRandomness , 0 );
  671.  
  672. // Spawn the planes
  673. if( typeOfStrike == "harrier" )
  674. plane = spawnplane( owner, "script_model", pathStart, "hud_minimap_harrier_green", "hud_minimap_harrier_red" );
  675. else
  676. plane = spawnplane( owner, "script_model", pathStart, "compass_objpoint_airstrike_friendly", "compass_objpoint_airstrike_busy" );
  677.  
  678. if( typeOfStrike == "harrier" )
  679. {
  680. if ( owner.team == "allies" )
  681. plane setModel( "vehicle_av8b_harrier_jet_mp" );
  682. else
  683. plane setModel( "vehicle_av8b_harrier_jet_opfor_mp" );
  684. }
  685. else
  686. plane setModel( "vehicle_mig29_desert" );
  687.  
  688. plane playloopsound( "veh_mig29_dist_loop" );
  689. plane thread handleEMP( owner );
  690.  
  691. plane.lifeId = lifeId;
  692.  
  693. plane.angles = direction;
  694. forward = anglesToForward( direction );
  695. plane thread playPlaneFx();
  696. plane moveTo( pathEnd, flyTime, 0, 0 );
  697.  
  698. /#
  699. if ( getdvar("scr_airstrikedebug") == "1" )
  700. thread airstrikeLine( pathStart, pathEnd, (1,1,1), 20 );
  701. #/
  702.  
  703. //thread callStrike_planeSound( plane, bombsite );
  704. thread callStrike_bombEffect( plane, pathEnd, flyTime, bombTime - 1.0, owner, requiredDeathCount, typeOfStrike );
  705.  
  706. // Delete the plane after its flyby
  707. wait flyTime;
  708. plane notify( "delete" );
  709. plane delete();
  710. }
  711.  
  712. callStrike_bombEffect( plane, pathEnd, flyTime, launchTime, owner, requiredDeathCount, typeOfStrike )
  713. {
  714. wait ( launchTime );
  715.  
  716. if ( !isDefined( owner )|| owner isEMPed() )
  717. return;
  718.  
  719. plane playSound( "veh_mig29_sonic_boom" );
  720. planedir = anglesToForward( plane.angles );
  721.  
  722. bomb = spawnbomb( plane.origin, plane.angles );
  723. bomb moveGravity( vector_multiply( anglestoforward( plane.angles ), 7000/1.5 ), 3.0 );
  724.  
  725. bomb.lifeId = requiredDeathCount;
  726.  
  727. killCamEnt = spawn( "script_model", plane.origin + (0,0,100) - planedir * 200 );
  728. bomb.killCamEnt = killCamEnt;
  729. bomb.airstrikeType = typeOfStrike;
  730. killCamEnt.startTime = gettime();
  731. killCamEnt thread deleteAfterTime( 15.0 );
  732. killCamEnt.angles = planedir;
  733. killCamEnt moveTo( pathEnd + (0,0,100), flyTime, 0, 0 );
  734.  
  735. /#
  736. if ( getdvar("scr_airstrikedebug") == "1" )
  737. bomb thread traceBomb();
  738. #/
  739.  
  740. wait .4;
  741. //plane stoploopsound();
  742. killCamEnt moveTo( killCamEnt.origin + planedir * 4000, 1, 0, 0 );
  743.  
  744. wait .45;
  745. killCamEnt moveTo( killCamEnt.origin + (planedir + (0,0,-.2)) * 3500, 2, 0, 0 );
  746.  
  747. wait ( 0.15 );
  748.  
  749. newBomb = spawn( "script_model", bomb.origin );
  750. newBomb setModel( "tag_origin" );
  751. newBomb.origin = bomb.origin;
  752. newBomb.angles = bomb.angles;
  753.  
  754. bomb setModel( "tag_origin" );
  755. wait (0.10); // wait two server frames before playing fx
  756.  
  757. bombOrigin = newBomb.origin;
  758. bombAngles = newBomb.angles;
  759. playfxontag( level.airstrikefx, newBomb, "tag_origin" );
  760.  
  761. wait .05;
  762. killCamEnt moveTo( killCamEnt.origin + (planedir + (0,0,-.25)) * 2500, 2, 0, 0 );
  763.  
  764. wait .25;
  765. killCamEnt moveTo( killCamEnt.origin + (planedir + (0,0,-.35)) * 2000, 2, 0, 0 );
  766.  
  767. wait .2;
  768. killCamEnt moveTo( killCamEnt.origin + (planedir + (0,0,-.45)) * 1500, 2, 0, 0 );
  769.  
  770.  
  771. wait ( 0.5 );
  772.  
  773. repeat = 12;
  774. minAngles = 5;
  775. maxAngles = 55;
  776. angleDiff = (maxAngles - minAngles) / repeat;
  777.  
  778. hitpos = (0,0,0);
  779.  
  780. for( i = 0; i < repeat; i++ )
  781. {
  782. traceDir = anglesToForward( bombAngles + (maxAngles-(angleDiff * i),randomInt( 10 )-5,0) );
  783. traceEnd = bombOrigin + vector_multiply( traceDir, 10000 );
  784. trace = bulletTrace( bombOrigin, traceEnd, false, undefined );
  785.  
  786. traceHit = trace["position"];
  787. hitpos += traceHit;
  788.  
  789. /#
  790. if ( getdvar("scr_airstrikedebug") == "1" )
  791. thread airstrikeLine( bombOrigin, traceHit, (1,0,0), 40 );
  792. #/
  793.  
  794. thread losRadiusDamage( traceHit + (0,0,16), 512, 200, 30, owner, bomb, "artillery_mp" ); // targetpos, radius, maxdamage, mindamage, player causing damage, entity that player used to cause damage
  795.  
  796. if ( i%3 == 0 )
  797. {
  798. thread playsoundinspace( "exp_airstrike_bomb", traceHit );
  799. playRumbleOnPosition( "artillery_rumble", traceHit );
  800. earthquake( 0.7, 0.75, traceHit, 1000 );
  801. }
  802.  
  803. wait ( 0.05 );
  804. }
  805.  
  806. hitpos = hitpos / repeat + (0,0,128);
  807. killCamEnt moveto( bomb.killCamEnt.origin * .35 + hitpos * .65, 1.5, 0, .5 );
  808.  
  809. wait ( 5.0 );
  810. newBomb delete();
  811. bomb delete();
  812. }
  813.  
  814.  
  815. spawnbomb( origin, angles )
  816. {
  817. bomb = spawn( "script_model", origin );
  818. bomb.angles = angles;
  819. bomb setModel( "projectile_cbu97_clusterbomb" );
  820.  
  821. return bomb;
  822. }
  823.  
  824.  
  825. deleteAfterTime( time )
  826. {
  827. self endon ( "death" );
  828. wait ( 10.0 );
  829.  
  830. self delete();
  831. }
  832.  
  833. playPlaneFx()
  834. {
  835. self endon ( "death" );
  836.  
  837. wait( 0.5);
  838. playfxontag( level.fx_airstrike_afterburner, self, "tag_engine_right" );
  839. wait( 0.5);
  840. playfxontag( level.fx_airstrike_afterburner, self, "tag_engine_left" );
  841. wait( 0.5);
  842. playfxontag( level.fx_airstrike_contrail, self, "tag_right_wingtip" );
  843. wait( 0.5);
  844. playfxontag( level.fx_airstrike_contrail, self, "tag_left_wingtip" );
  845. }
  846.  
  847. callStrike( lifeId, owner, coord, yaw )
  848. {
  849.  
  850. heightEnt = undefined;
  851. planeBombExplodeDistance = 0;
  852. // Get starting and ending point for the plane
  853. direction = ( 0, yaw, 0 );
  854. heightEnt = GetEnt( "airstrikeheight", "targetname" );
  855.  
  856. if ( self.airStrikeType == "stealth" )
  857. {
  858. thread teamPlayerCardSplash( "used_stealth_airstrike", owner, owner.team );
  859.  
  860. planeHalfDistance = 12000;
  861. planeFlySpeed = 2000;
  862.  
  863. if ( !isDefined( heightEnt ) )//old system
  864. {
  865. println( "NO DEFINED AIRSTRIKE HEIGHT SCRIPT_ORIGIN IN LEVEL" );
  866. planeFlyHeight = 950;
  867. planeBombExplodeDistance = 1500;
  868. if ( isdefined( level.airstrikeHeightScale ) )
  869. planeFlyHeight *= level.airstrikeHeightScale;
  870. }
  871. else
  872. {
  873. planeFlyHeight = heightEnt.origin[2];
  874. planeBombExplodeDistance = getExplodeDistance( planeFlyHeight );
  875. }
  876.  
  877. }
  878. else
  879. {
  880. planeHalfDistance = 24000;
  881. planeFlySpeed = 7000;
  882.  
  883. if ( !isDefined( heightEnt ) )//old system
  884. {
  885. println( "NO DEFINED AIRSTRIKE HEIGHT SCRIPT_ORIGIN IN LEVEL" );
  886. planeFlyHeight = 850;
  887. planeBombExplodeDistance = 1500;
  888. if ( isdefined( level.airstrikeHeightScale ) )
  889. planeFlyHeight *= level.airstrikeHeightScale;
  890. }
  891. else
  892. {
  893. planeFlyHeight = heightEnt.origin[2];
  894. planeBombExplodeDistance = getExplodeDistance( planeFlyHeight );
  895. }
  896. }
  897.  
  898. startPoint = coord + vector_multiply( anglestoforward( direction ), -1 * planeHalfDistance );
  899.  
  900. if ( isDefined( heightEnt ) )// used in the new height system
  901. startPoint *= (1,1,0);
  902.  
  903. startPoint += ( 0, 0, planeFlyHeight );
  904.  
  905. if ( self.airStrikeType == "stealth" )
  906. endPoint = coord + vector_multiply( anglestoforward( direction ), planeHalfDistance*4 );
  907. else
  908. endPoint = coord + vector_multiply( anglestoforward( direction ), planeHalfDistance );
  909.  
  910. if ( isDefined( heightEnt ) )// used in the new height system
  911. endPoint *= (1,1,0);
  912.  
  913. endPoint += ( 0, 0, planeFlyHeight );
  914.  
  915. // Make the plane fly by
  916. d = length( startPoint - endPoint );
  917. flyTime = ( d / planeFlySpeed );
  918.  
  919. // bomb explodes planeBombExplodeDistance after the plane passes the center
  920. d = abs( d/2 + planeBombExplodeDistance );
  921. bombTime = ( d / planeFlySpeed );
  922.  
  923. assert( flyTime > bombTime );
  924.  
  925. owner endon("disconnect");
  926.  
  927. requiredDeathCount = lifeId;
  928.  
  929. level.airstrikeDamagedEnts = [];
  930. level.airStrikeDamagedEntsCount = 0;
  931. level.airStrikeDamagedEntsIndex = 0;
  932.  
  933. if ( self.airStrikeType == "harrier" )
  934. {
  935. level thread doPlaneStrike( lifeId, owner, requiredDeathCount, coord, startPoint+(0,0,randomInt(500)), endPoint+(0,0,randomInt(500)), bombTime, flyTime, direction, self.airStrikeType );
  936.  
  937. wait randomfloatrange( 1.5, 2.5 );
  938. maps\mp\gametypes\_hostmigration::waitTillHostMigrationDone();
  939. level thread doPlaneStrike( lifeId, owner, requiredDeathCount, coord, startPoint+(0,0,randomInt(200)), endPoint+(0,0,randomInt(200)), bombTime, flyTime, direction, self.airStrikeType );
  940.  
  941. wait randomfloatrange( 1.5, 2.5 );
  942. maps\mp\gametypes\_hostmigration::waitTillHostMigrationDone();
  943. harrier = beginHarrier( lifeId, startPoint, coord );
  944. owner thread defendLocation( harrier );
  945.  
  946. return harrier;
  947. //owner thread harrierMissileStrike( startPoint, coord );
  948.  
  949. }
  950. else if ( self.airStrikeType == "stealth" )
  951. {
  952. level thread doBomberStrike( lifeId, owner, requiredDeathCount, coord, startPoint+(0,0,randomInt(1000)), endPoint+(0,0,randomInt(1000)), bombTime, flyTime, direction, self.airStrikeType );
  953. }
  954. else //common airstrike
  955. {
  956. level thread doPlaneStrike( lifeId, owner, requiredDeathCount, coord, startPoint+(0,0,randomInt(500)), endPoint+(0,0,randomInt(500)), bombTime, flyTime, direction, self.airStrikeType );
  957.  
  958. wait randomfloatrange( 1.5, 2.5 );
  959. maps\mp\gametypes\_hostmigration::waitTillHostMigrationDone();
  960. level thread doPlaneStrike( lifeId, owner, requiredDeathCount, coord, startPoint+(0,0,randomInt(200)), endPoint+(0,0,randomInt(200)), bombTime, flyTime, direction, self.airStrikeType );
  961.  
  962. wait randomfloatrange( 1.5, 2.5 );
  963. maps\mp\gametypes\_hostmigration::waitTillHostMigrationDone();
  964. level thread doPlaneStrike( lifeId, owner, requiredDeathCount, coord, startPoint+(0,0,randomInt(200)), endPoint+(0,0,randomInt(200)), bombTime, flyTime, direction, self.airStrikeType );
  965.  
  966. if ( self.airStrikeType == "super" )
  967. {
  968. wait randomfloatrange( 2.5, 3.5 );
  969. maps\mp\gametypes\_hostmigration::waitTillHostMigrationDone();
  970. level thread doPlaneStrike( lifeId, owner, requiredDeathCount, coord, startPoint+(0,0,randomInt(200)), endPoint+(0,0,randomInt(200)), bombTime, flyTime, direction, self.airStrikeType );
  971. }
  972. }
  973. }
  974.  
  975.  
  976. getExplodeDistance( height )
  977. {
  978. standardHeight = 850;
  979. standardDistance = 1500;
  980. distanceFrac = standardHeight/height;
  981.  
  982. newDistance = distanceFrac * standardDistance;
  983.  
  984. return newDistance;
  985. }
  986.  
  987.  
  988. targetGetDist( other, target )
  989. {
  990. infront = targetisinfront( other, target );
  991. if( infront )
  992. dir = 1;
  993. else
  994. dir = -1;
  995. a = flat_origin( other.origin );
  996. b = a+vector_multiply( anglestoforward(flat_angle(other.angles)), (dir*100000) );
  997. point = pointOnSegmentNearestToPoint(a,b, target);
  998. dist = distance(a,point);
  999.  
  1000. return dist;
  1001. }
  1002.  
  1003. targetisclose(other, target, closeDist)
  1004. {
  1005. if ( !isDefined( closeDist ) )
  1006. closeDist = 3000;
  1007.  
  1008. infront = targetisinfront(other, target);
  1009. if(infront)
  1010. dir = 1;
  1011. else
  1012. dir = -1;
  1013. a = flat_origin(other.origin);
  1014. b = a+vector_multiply(anglestoforward(flat_angle(other.angles)), (dir*100000));
  1015. point = pointOnSegmentNearestToPoint(a,b, target);
  1016. dist = distance(a,point);
  1017. if (dist < closeDist)
  1018. return true;
  1019. else
  1020. return false;
  1021. }
  1022.  
  1023.  
  1024. targetisinfront(other, target)
  1025. {
  1026. forwardvec = anglestoforward(flat_angle(other.angles));
  1027. normalvec = vectorNormalize(flat_origin(target)-other.origin);
  1028. dot = vectordot(forwardvec,normalvec);
  1029. if(dot > 0)
  1030. return true;
  1031. else
  1032. return false;
  1033. }
  1034.  
  1035. waitForAirstrikeCancel()
  1036. {
  1037. self waittill( "cancel_location" );
  1038. self setblurforplayer( 0, 0.3 );
  1039. }
  1040.  
  1041.  
  1042. selectAirstrikeLocation( lifeId, airStrikeType )
  1043. {
  1044. assert( isDefined( airStrikeType ) );
  1045.  
  1046. self.airStrikeType = airStrikeType;
  1047.  
  1048. if ( airStrikeType == "precision" || airStrikeType == "stealth" )
  1049. chooseDirection = true;
  1050. else
  1051. chooseDirection = false;
  1052.  
  1053. targetSize = level.mapSize / 5.625; // 138 in 720
  1054. if ( level.splitscreen )
  1055. targetSize *= 1.5;
  1056.  
  1057. self beginLocationSelection( "map_artillery_selector", chooseDirection, targetSize );
  1058. self.selectingLocation = true;
  1059.  
  1060. self setblurforplayer( 4.0, 0.3 );
  1061. self thread waitForAirstrikeCancel();
  1062.  
  1063. self thread endSelectionOn( "cancel_location" );
  1064. self thread endSelectionOn( "death" );
  1065. self thread endSelectionOn( "disconnect" );
  1066. self thread endSelectionOn( "used" ); // so that this thread doesn't kill itself when we use an airstrike
  1067. self thread endSelectionOnGameEnd();
  1068. self thread endSelectionOnEMP();
  1069.  
  1070. self endon( "stop_location_selection" );
  1071.  
  1072. // wait for the selection. randomize the yaw if we're not doing a precision airstrike.
  1073. self waittill( "confirm_location", location, directionYaw );
  1074. if ( !chooseDirection )
  1075. directionYaw = randomint(360);
  1076.  
  1077. self setblurforplayer( 0, 0.3 );
  1078.  
  1079. if ( airStrikeType == "harrier" && level.planes > 1 )
  1080. {
  1081. self notify ( "cancel_location" );
  1082. self iPrintLnBold( &"MP_AIR_SPACE_TOO_CROWDED" );
  1083. return false;
  1084. }
  1085.  
  1086. self thread finishAirstrikeUsage( lifeId, location, directionYaw );
  1087. return true;
  1088. }
  1089.  
  1090. finishAirstrikeUsage( lifeId, location, directionYaw )
  1091. {
  1092. self notify( "used" );
  1093.  
  1094. // find underside of top of skybox
  1095. trace = bullettrace( level.mapCenter + (0,0,1000000), level.mapCenter, false, undefined );
  1096. location = (location[0], location[1], trace["position"][2] - 514);
  1097.  
  1098. thread doAirstrike( lifeId, location, directionYaw, self, self.pers["team"] );
  1099. }
  1100.  
  1101.  
  1102. endSelectionOn( waitfor )
  1103. {
  1104. self endon( "stop_location_selection" );
  1105. self waittill( waitfor );
  1106. self thread stopAirstrikeLocationSelection( (waitfor == "disconnect") );
  1107. }
  1108.  
  1109.  
  1110. endSelectionOnGameEnd()
  1111. {
  1112. self endon( "stop_location_selection" );
  1113. level waittill( "game_ended" );
  1114. self thread stopAirstrikeLocationSelection( false );
  1115. }
  1116.  
  1117.  
  1118. endSelectionOnEMP()
  1119. {
  1120. self endon( "stop_location_selection" );
  1121. for ( ;; )
  1122. {
  1123. level waittill( "emp_update" );
  1124.  
  1125. if ( !self isEMPed() )
  1126. continue;
  1127.  
  1128. self thread stopAirstrikeLocationSelection( false );
  1129. return;
  1130. }
  1131. }
  1132.  
  1133.  
  1134. stopAirstrikeLocationSelection( disconnected )
  1135. {
  1136. if ( !disconnected )
  1137. {
  1138. self setblurforplayer( 0, 0.3 );
  1139. self endLocationSelection();
  1140. self.selectingLocation = undefined;
  1141. }
  1142. self notify( "stop_location_selection" );
  1143. }
  1144.  
  1145.  
  1146. useAirstrike( lifeId, pos, yaw )
  1147. {
  1148. }
  1149.  
  1150.  
  1151. handleEMP( owner )
  1152. {
  1153. self endon ( "death" );
  1154.  
  1155. if ( owner isEMPed() )
  1156. {
  1157. playFxOnTag( level.onfirefx, self, "tag_engine_right" );
  1158. playFxOnTag( level.onfirefx, self, "tag_engine_left" );
  1159. return;
  1160. }
  1161.  
  1162. for ( ;; )
  1163. {
  1164. level waittill ( "emp_update" );
  1165.  
  1166. if ( !owner isEMPed() )
  1167. continue;
  1168.  
  1169. playFxOnTag( level.onfirefx, self, "tag_engine_right" );
  1170. playFxOnTag( level.onfirefx, self, "tag_engine_left" );
  1171. }
  1172. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement