Advertisement
NachosEater

_weapons

Nov 19th, 2011
327
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 87.07 KB | None | 0 0
  1. #include common_scripts\utility;
  2. #include maps\mp\_utility;
  3. #include maps\mp\gametypes\_equipment;
  4.  
  5. attachmentGroup( attachmentName )
  6. {
  7. return tableLookup( "mp/attachmentTable.csv", 4, attachmentName, 2 );
  8. }
  9.  
  10. getAttachmentList()
  11. {
  12. attachmentList = [];
  13.  
  14. index = 0;
  15. attachmentName = tableLookup( "mp/attachmentTable.csv", 9, index, 4 );
  16.  
  17. while ( attachmentName != "" )
  18. {
  19. attachmentList[attachmentList.size] = attachmentName;
  20.  
  21. index++;
  22. attachmentName = tableLookup( "mp/attachmentTable.csv", 9, index, 4 );
  23. }
  24.  
  25. return alphabetize( attachmentList );
  26. }
  27.  
  28. init()
  29. {
  30. level.scavenger_altmode = true;
  31. level.scavenger_secondary = true;
  32.  
  33. // 0 is not valid
  34. level.maxPerPlayerExplosives = max( getIntProperty( "scr_maxPerPlayerExplosives", 2 ), 1 );
  35. level.riotShieldXPBullets = getIntProperty( "scr_riotShieldXPBullets", 15 );
  36.  
  37. switch ( getIntProperty( "perk_scavengerMode", 0 ) )
  38. {
  39. case 1: // disable altmode
  40. level.scavenger_altmode = false;
  41. break;
  42.  
  43. case 2: // disable secondary
  44. level.scavenger_secondary = false;
  45. break;
  46.  
  47. case 3: // disable altmode and secondary
  48. level.scavenger_altmode = false;
  49. level.scavenger_secondary = false;
  50. break;
  51. }
  52.  
  53. attachmentList = getAttachmentList();
  54.  
  55. // assigns weapons with stat numbers from 0-149
  56. // attachments are now shown here, they are per weapon settings instead
  57.  
  58. max_weapon_num = 149;
  59.  
  60. level.weaponList = [];
  61. for( weaponId = 0; weaponId <= max_weapon_num; weaponId++ )
  62. {
  63. weapon_name = tablelookup( "mp/statstable.csv", 0, weaponId, 4 );
  64.  
  65. if( weapon_name == "" )
  66. continue;
  67.  
  68. if ( !isSubStr( tableLookup( "mp/statsTable.csv", 0, weaponId, 2 ), "weapon_" ) )
  69. continue;
  70.  
  71. if ( IsSubStr( weapon_name, "iw5_" ) )
  72. {
  73. weaponTokens = StrTok( weapon_name, "_" );
  74. weapon_name = weaponTokens[0] + "_" + weaponTokens[1] + "_mp";
  75.  
  76. level.weaponList[level.weaponList.size] = weapon_name ;
  77. continue;
  78. }
  79. else
  80. level.weaponList[level.weaponList.size] = weapon_name + "_mp";
  81.  
  82. /#
  83. if ( getDvar( "scr_dump_weapon_assets" ) != "" )
  84. {
  85. printLn( "" );
  86. printLn( "// " + weapon_name + " real assets" );
  87. printLn( "weapon,mp/" + weapon_name + "_mp" );
  88. }
  89. #/
  90.  
  91. // the alphabetize function is slow so we try not to do it for every weapon/attachment combo; a code solution would be better.
  92. attachmentNames = [];
  93. for ( innerLoopCount = 0; innerLoopCount < 10; innerLoopCount++ )
  94. {
  95. // generating attachment combinations
  96. attachmentName = tablelookup( "mp/statStable.csv", 0, weaponId, innerLoopCount + 11 );
  97.  
  98. if( attachmentName == "" )
  99. break;
  100.  
  101. attachmentNames[attachmentName] = true;
  102. }
  103.  
  104. // generate an alphabetized attachment list
  105. attachments = [];
  106. foreach ( attachmentName in attachmentList )
  107. {
  108. if ( !isDefined( attachmentNames[attachmentName] ) )
  109. continue;
  110.  
  111. level.weaponList[level.weaponList.size] = weapon_name + "_" + attachmentName + "_mp";
  112. attachments[attachments.size] = attachmentName;
  113. /#
  114. if ( getDvar( "scr_dump_weapon_assets" ) != "" )
  115. println( "weapon,mp/" + weapon_name + "_" + attachmentName + "_mp" );
  116. #/
  117. }
  118.  
  119. attachmentCombos = [];
  120. for ( i = 0; i < (attachments.size - 1); i++ )
  121. {
  122. colIndex = tableLookupRowNum( "mp/attachmentCombos.csv", 0, attachments[i] );
  123. for ( j = i + 1; j < attachments.size; j++ )
  124. {
  125. if ( tableLookup( "mp/attachmentCombos.csv", 0, attachments[j], colIndex ) == "no" )
  126. continue;
  127.  
  128. attachmentCombos[attachmentCombos.size] = attachments[i] + "_" + attachments[j];
  129. }
  130. }
  131.  
  132. /#
  133. if ( getDvar( "scr_dump_weapon_assets" ) != "" && attachmentCombos.size )
  134. println( "// " + weapon_name + " virtual assets" );
  135. #/
  136.  
  137. foreach ( combo in attachmentCombos )
  138. {
  139. /#
  140. if ( getDvar( "scr_dump_weapon_assets" ) != "" )
  141. println( "weapon,mp/" + weapon_name + "_" + combo + "_mp" );
  142. #/
  143.  
  144. level.weaponList[level.weaponList.size] = weapon_name + "_" + combo + "_mp";
  145. }
  146.  
  147. }
  148.  
  149. foreach ( weaponName in level.weaponList )
  150. {
  151. precacheItem( weaponName );
  152.  
  153. /#
  154. if ( getDvar( "scr_dump_weapon_assets" ) != "" )
  155. {
  156. altWeapon = weaponAltWeaponName( weaponName );
  157. if ( altWeapon != "none" )
  158. println( "weapon,mp/" + altWeapon );
  159. }
  160. #/
  161. }
  162.  
  163. precacheItem( "flare_mp" );
  164. precacheItem( "scavenger_bag_mp" );
  165. precacheItem( "frag_grenade_short_mp" );
  166. precacheItem( "c4death_mp" );
  167. precacheItem( "destructible_car" );
  168. precacheItem( "destructible_toy" );
  169. precacheItem( "bouncingbetty_mp" );
  170. precacheItem( "scrambler_mp" );
  171. precacheItem( "portable_radar_mp" );
  172.  
  173. precacheShellShock( "default" );
  174. precacheShellShock( "concussion_grenade_mp" );
  175. thread maps\mp\_flashgrenades::main();
  176. thread maps\mp\_entityheadicons::init();
  177. thread maps\mp\_empgrenade::init();
  178.  
  179. claymoreDetectionConeAngle = 70;
  180. level.claymoreDetectionDot = cos( claymoreDetectionConeAngle );
  181. level.claymoreDetectionMinDist = 20;
  182. level.claymoreDetectionGracePeriod = .75;
  183. level.claymoreDetonateRadius = 192;
  184.  
  185. level.mineDetectionGracePeriod = .3;
  186. level.mineDetectionRadius = 100;
  187. level.mineDetectionHeight = 20;
  188. level.mineDamageRadius = 256;
  189. level.mineDamageMin = 70;
  190. level.mineDamageMax = 210;
  191. level.mineDamageHalfHeight = 46;
  192. level.mineSelfDestructTime = 120;
  193. level.mine_launch = loadfx( "impacts/bouncing_betty_launch_dirt" );
  194. level.mine_spin = loadfx( "dust/bouncing_betty_swirl" );
  195. level.mine_explode = loadfx( "explosions/bouncing_betty_explosion" );
  196. level.mine_beacon["enemy"] = loadfx( "misc/light_c4_blink" );
  197. level.mine_beacon["friendly"] = loadfx( "misc/light_mine_blink_friendly" );
  198. level.empGrenadeExplode = loadfx("explosions/emp_grenade");
  199.  
  200. level.delayMineTime = 3.0;
  201.  
  202. level.sentry_fire = loadfx( "muzzleflashes/shotgunflash" );
  203.  
  204. // this should move to _stinger.gsc
  205. level.stingerFXid = loadfx ("explosions/aerial_explosion_large");
  206.  
  207. // generating weapon type arrays which classifies the weapon as primary (back stow), pistol, or inventory (side pack stow)
  208. // using mp/statstable.csv's weapon grouping data ( numbering 0 - 149 )
  209. level.primary_weapon_array = [];
  210. level.side_arm_array = [];
  211. level.grenade_array = [];
  212. level.missile_array = [];
  213. level.inventory_array = [];
  214. level.mines = [];
  215.  
  216. //*precacheModel( "weapon_claymore_bombsquad" );
  217. //*precacheModel( "weapon_c4_bombsquad" );
  218. //*precacheModel( "projectile_m67fraggrenade_bombsquad" );
  219. //*precacheModel( "projectile_semtex_grenade_bombsquad" );
  220. //*precacheModel( "weapon_light_stick_tactical_bombsquad" );
  221. precacheModel( "projectile_bouncing_betty_grenade" );
  222. //*precacheModel( "projectile_bouncing_betty_grenade_bombsquad" );
  223. precacheModel( "projectile_bouncing_betty_trigger" );
  224. precacheModel( "weapon_jammer" );
  225. //*precacheModel( "weapon_jammer_bombsquad" );
  226. precacheModel( "weapon_radar" );
  227. //*precacheModel( "weapon_radar_bombsquad" );
  228. PreCacheModel( "mp_trophy_system" );
  229. //*PreCacheModel( "mp_trophy_system_bombsquad" );
  230.  
  231. //PrecacheMpAnim( "bouncing_betty_detonate" );
  232.  
  233. level._effect[ "equipment_explode" ] = LoadFX( "explosions/sparks_a" );
  234.  
  235. level._effect[ "sniperDustLarge" ] = LoadFX( "dust/sniper_dust_kickup" );
  236. level._effect[ "sniperDustSmall" ] = LoadFX( "dust/sniper_dust_kickup_minimal" );
  237. level._effect[ "sniperDustLargeSuppress" ] = LoadFX( "dust/sniper_dust_kickup_accum_suppress" );
  238. level._effect[ "sniperDustSmallSuppress" ] = LoadFX( "dust/sniper_dust_kickup_accum_supress_minimal" );
  239.  
  240. level thread onPlayerConnect();
  241.  
  242. level.c4explodethisframe = false;
  243.  
  244. array_thread( getEntArray( "misc_turret", "classname" ), ::turret_monitorUse );
  245.  
  246. // thread dumpIt();
  247. }
  248.  
  249.  
  250. dumpIt()
  251. {
  252.  
  253. wait ( 5.0 );
  254. /#
  255. max_weapon_num = 149;
  256.  
  257. for( weaponId = 0; weaponId <= max_weapon_num; weaponId++ )
  258. {
  259. weapon_name = tablelookup( "mp/statstable.csv", 0, weaponId, 4 );
  260. if( weapon_name == "" )
  261. continue;
  262.  
  263. if ( !isSubStr( tableLookup( "mp/statsTable.csv", 0, weaponId, 2 ), "weapon_" ) )
  264. continue;
  265.  
  266. if ( getDvar( "scr_dump_weapon_challenges" ) != "" )
  267. {
  268. /*
  269. sharpshooter
  270. marksman
  271. veteran
  272. expert
  273. master
  274. */
  275.  
  276. weaponLStringName = tableLookup( "mp/statsTable.csv", 0, weaponId, 3 );
  277. weaponRealName = tableLookupIString( "mp/statsTable.csv", 0, weaponId, 3 );
  278.  
  279. prefix = "WEAPON_";
  280. weaponCapsName = getSubStr( weaponLStringName, prefix.size, weaponLStringName.size );
  281.  
  282. weaponGroup = tableLookup( "mp/statsTable.csv", 0, weaponId, 2 );
  283.  
  284. weaponGroupSuffix = getSubStr( weaponGroup, prefix.size, weaponGroup.size );
  285.  
  286. /*
  287. iprintln( "REFERENCE TITLE_" + weaponCapsName + "_SHARPSHOOTER" );
  288. iprintln( "LANG_ENGLISH ", weaponRealName, ": Sharpshooter" );
  289. iprintln( "" );
  290. iprintln( "REFERENCE TITLE_" + weaponCapsName + "_MARKSMAN" );
  291. iprintln( "LANG_ENGLISH ", weaponRealName, ": Marksman" );
  292. iprintln( "" );
  293. iprintln( "REFERENCE TITLE_" + weaponCapsName + "_VETERAN" );
  294. iprintln( "LANG_ENGLISH ", weaponRealName, ": Veteran" );
  295. iprintln( "" );
  296. iprintln( "REFERENCE TITLE_" + weaponCapsName + "_EXPERT" );
  297. iprintln( "LANG_ENGLISH ", weaponRealName, ": Expert" );
  298. iprintln( "" );
  299. iprintln( "REFERENCE TITLE_" + weaponCapsName + "_Master" );
  300. iprintln( "LANG_ENGLISH ", weaponRealName, ": Master" );
  301. */
  302.  
  303. iprintln( "cardtitle_" + weapon_name + "_sharpshooter,PLAYERCARDS_TITLE_" + weaponCapsName + "_SHARPSHOOTER,cardtitle_" + weaponGroupSuffix + "_sharpshooter,1,1,1" );
  304. iprintln( "cardtitle_" + weapon_name + "_marksman,PLAYERCARDS_TITLE_" + weaponCapsName + "_MARKSMAN,cardtitle_" + weaponGroupSuffix + "_marksman,1,1,1" );
  305. iprintln( "cardtitle_" + weapon_name + "_veteran,PLAYERCARDS_TITLE_" + weaponCapsName + "_VETERAN,cardtitle_" + weaponGroupSuffix + "_veteran,1,1,1" );
  306. iprintln( "cardtitle_" + weapon_name + "_expert,PLAYERCARDS_TITLE_" + weaponCapsName + "_EXPERT,cardtitle_" + weaponGroupSuffix + "_expert,1,1,1" );
  307. iprintln( "cardtitle_" + weapon_name + "_master,PLAYERCARDS_TITLE_" + weaponCapsName + "_MASTER,cardtitle_" + weaponGroupSuffix + "_master,1,1,1" );
  308.  
  309. wait ( 0.05 );
  310. }
  311. }
  312. #/
  313. }
  314.  
  315. bombSquadWaiter()
  316. {
  317. self endon ( "disconnect" );
  318.  
  319. for ( ;; )
  320. {
  321. self waittill ( "grenade_fire", weaponEnt, weaponName );
  322.  
  323. team = level.otherTeam[self.team];
  324.  
  325. if ( weaponName == "c4_mp" )
  326. weaponEnt thread createBombSquadModel( "weapon_c4", "tag_origin", team, self );
  327. else if ( weaponName == "claymore_mp" )
  328. weaponEnt thread createBombSquadModel( "weapon_claymore", "tag_origin", team, self );
  329. else if ( weaponName == "frag_grenade_mp" )
  330. weaponEnt thread createBombSquadModel( "projectile_m67fraggrenade", "tag_weapon", team, self );
  331. else if ( weaponName == "frag_grenade_short_mp" )
  332. weaponEnt thread createBombSquadModel( "projectile_m67fraggrenade", "tag_weapon", team, self );
  333. else if ( weaponName == "semtex_mp" )
  334. weaponEnt thread createBombSquadModel( "projectile_semtex_grenade", "tag_weapon", team, self );
  335. }
  336. }
  337.  
  338.  
  339. createBombSquadModel( modelName, tagName, teamName, owner )
  340. {
  341. bombSquadModel = spawn( "script_model", (0,0,0) );
  342. bombSquadModel hide();
  343. wait ( 0.05 );
  344.  
  345. if (!isDefined( self ) ) //grenade model may not be around if picked up
  346. return;
  347.  
  348. bombSquadModel thread bombSquadVisibilityUpdater( teamName, owner );
  349. bombSquadModel setModel( modelName );
  350. bombSquadModel linkTo( self, tagName, (0,0,0), (0,0,0) );
  351. bombSquadModel SetContents( 0 );
  352. bombSquadModel SetSwitchToObjective( 1 );
  353.  
  354. self waittill ( "death" );
  355.  
  356. if ( isDefined(self.trigger) )
  357. self.trigger delete();
  358.  
  359. bombSquadModel delete();
  360. }
  361.  
  362.  
  363. bombSquadVisibilityUpdater( teamName, owner )
  364. {
  365. self endon ( "death" );
  366.  
  367. foreach ( player in level.players )
  368. {
  369. if ( level.teamBased )
  370. {
  371. if ( player.team == teamName && player _hasPerk( "specialty_detectexplosive" ) )
  372. self showToPlayer( player );
  373. }
  374. else
  375. {
  376. if ( isDefined( owner ) && player == owner )
  377. continue;
  378.  
  379. if ( !player _hasPerk( "specialty_detectexplosive" ) )
  380. continue;
  381.  
  382. self showToPlayer( player );
  383. }
  384. }
  385.  
  386. for ( ;; )
  387. {
  388. level waittill_any( "joined_team", "player_spawned", "changed_kit" );
  389.  
  390. self hide();
  391.  
  392. foreach ( player in level.players )
  393. {
  394. if ( level.teamBased )
  395. {
  396. if ( player.team == teamName && player _hasPerk( "specialty_detectexplosive" ) )
  397. self showToPlayer( player );
  398. }
  399. else
  400. {
  401. if ( isDefined( owner ) && player == owner )
  402. continue;
  403.  
  404. if ( !player _hasPerk( "specialty_detectexplosive" ) )
  405. continue;
  406.  
  407. self showToPlayer( player );
  408. }
  409. }
  410. }
  411. }
  412.  
  413.  
  414. onPlayerConnect()
  415. {
  416. for(;;)
  417. {
  418. level waittill("connected", player);
  419.  
  420. player.hits = 0;
  421. player.hasDoneCombat = false;
  422.  
  423. player KC_RegWeaponForFXRemoval( "remotemissile_projectile_mp" );
  424.  
  425. player thread onPlayerSpawned();
  426. player thread bombSquadWaiter();
  427. player thread watchMissileUsage();
  428. player thread sniperDustWatcher();
  429. }
  430. }
  431.  
  432. onPlayerSpawned()
  433. {
  434. self endon("disconnect");
  435.  
  436. for(;;)
  437. {
  438. self waittill("spawned_player");
  439.  
  440. self.currentWeaponAtSpawn = self getCurrentWeapon(); // optimization so these threads we start don't have to call it.
  441.  
  442. self.empEndTime = 0;
  443. self.concussionEndTime = 0;
  444. self.hits = 0;
  445. self.hasDoneCombat = false;
  446. if( !isdefined( self.trackingWeaponName ) )
  447. {
  448. self.trackingWeaponName = "";
  449. self.trackingWeaponName = "none";
  450. self.trackingWeaponShots = 0;
  451. self.trackingWeaponKills = 0;
  452. self.trackingWeaponHits = 0;
  453. self.trackingWeaponHeadShots = 0;
  454. self.trackingWeaponDeaths = 0;
  455. }
  456. self thread watchWeaponUsage();
  457. self thread watchGrenadeUsage();
  458. self thread watchWeaponChange();
  459. self thread watchStingerUsage();
  460. self thread watchJavelinUsage();
  461. self thread watchSentryUsage();
  462. self thread watchWeaponReload();
  463. self thread watchMineUsage();
  464. self thread maps\mp\gametypes\_class::trackRiotShield();
  465. self thread watchTrophyUsage();
  466. self thread stanceRecoilAdjuster();
  467.  
  468. self.lastHitTime = [];
  469.  
  470. self.droppedDeathWeapon = undefined;
  471. self.tookWeaponFrom = [];
  472.  
  473. self thread updateSavedLastWeapon();
  474.  
  475. self thread updateWeaponRank();
  476.  
  477. if ( self hasWeapon( "semtex_mp" ) )
  478. self thread monitorSemtex();
  479.  
  480. self.currentWeaponAtSpawn = undefined;
  481. self.trophyRemainingAmmo = undefined;
  482. }
  483. }
  484.  
  485. sniperDustWatcher()
  486. {
  487. self endon ( "death" );
  488. self endon ( "disconnect" );
  489. level endon ( "game_ended" );
  490.  
  491. lastLargeShotFiredTime = undefined;
  492.  
  493. for (;;)
  494. {
  495. self waittill( "weapon_fired" );
  496.  
  497. if( getWeaponClass( self GetCurrentWeapon() ) != "weapon_sniper" )
  498. continue;
  499.  
  500. if ( self GetStance() != "prone" )
  501. continue;
  502.  
  503. playerForward = AnglesToForward( self.angles );
  504. //self thread drawLine( self.origin, ( self.origin + (0,0,10) ) + playerForward * 50, 10000, (1,0,0));
  505.  
  506. if ( !isDefined(lastLargeShotFiredTime) || ( getTime() - lastLargeShotFiredTime ) > 2000 )
  507. {
  508. playFX( level._effect[ "sniperDustLarge" ], ( self.origin + (0,0,10) ) + playerForward * 50 , playerForward );
  509. lastLargeShotFiredTime = GetTime();
  510. }
  511. else
  512. {
  513. playFX( level._effect[ "sniperDustLargeSuppress" ], ( self.origin + (0,0,10) ) + playerForward * 50 , playerForward );
  514. }
  515. }
  516. }
  517.  
  518.  
  519. WatchStingerUsage()
  520. {
  521. self maps\mp\_stinger::StingerUsageLoop();
  522. }
  523.  
  524.  
  525. WatchJavelinUsage()
  526. {
  527. self maps\mp\_javelin::JavelinUsageLoop();
  528. }
  529.  
  530. watchWeaponChange()
  531. {
  532. self endon("death");
  533. self endon("disconnect");
  534.  
  535. self thread watchStartWeaponChange();
  536. self.lastDroppableWeapon = self.currentWeaponAtSpawn;
  537. self.hitsThisMag = [];
  538.  
  539. weapon = self getCurrentWeapon();
  540.  
  541. if ( isCACPrimaryWeapon( weapon ) && !isDefined( self.hitsThisMag[ weapon ] ) )
  542. self.hitsThisMag[ weapon ] = weaponClipSize( weapon );
  543.  
  544. self.bothBarrels = undefined;
  545.  
  546. if ( isSubStr( weapon, "ranger" ) )
  547. self thread watchRangerUsage( weapon );
  548.  
  549. while(1)
  550. {
  551. self waittill( "weapon_change", weaponName );
  552.  
  553. if( weaponName == "none" )
  554. continue;
  555.  
  556. if( weaponName == "briefcase_bomb_mp" || weaponName == "briefcase_bomb_defuse_mp" )
  557. continue;
  558.  
  559. if( isKillstreakWeapon( weaponName ) )
  560. continue;
  561.  
  562. weaponTokens = StrTok( weaponName, "_" );
  563.  
  564. self.bothBarrels = undefined;
  565.  
  566. if ( isSubStr( weaponName, "ranger" ) )
  567. self thread watchRangerUsage( weaponName );
  568.  
  569. //if ( weaponTokens[0] == "iw5" )
  570. //weaponName = weaponTokens[0] + "_" + weaponTokens[1];
  571. if ( weaponTokens[0] == "alt" )
  572. {
  573. tmp = GetSubStr( weaponName, 4 );
  574. weaponName = tmp;
  575. weaponTokens = StrTok( weaponName, "_" );
  576. }
  577. else if ( weaponTokens[0] != "iw5" )
  578. weaponName = weaponTokens[0];
  579.  
  580. if ( weaponName != "none" && weaponTokens[0] != "iw5" )
  581. {
  582. if ( isCACPrimaryWeapon( weaponName ) && !isDefined( self.hitsThisMag[ weaponName + "_mp" ] ) )
  583. self.hitsThisMag[ weaponName + "_mp" ] = weaponClipSize( weaponName + "_mp" );
  584. }
  585. else if( weaponName != "none" && weaponTokens[0] == "iw5")
  586. {
  587. if ( isCACPrimaryWeapon( weaponName ) && !isDefined( self.hitsThisMag[ weaponName ] ) )
  588. self.hitsThisMag[ weaponName ] = weaponClipSize( weaponName );
  589. }
  590.  
  591. self.changingWeapon = undefined;
  592.  
  593. if ( weaponTokens[0] == "iw5" )
  594. self.lastDroppableWeapon = weaponName;
  595. else if ( weaponName != "none" && mayDropWeapon( weaponName + "_mp" ) )
  596. self.lastDroppableWeapon = weaponName + "_mp";
  597.  
  598. // we need to manage the weapon buffs here, if the new weapon has a buff then give, if not, take
  599. if( IsDefined( self.class_num ) )
  600. {
  601. // since we stripped _mp off of the weapon name if it doesn't start with iw5, we need it back for this
  602. if( weaponTokens[0] != "iw5" )
  603. weaponName += "_mp";
  604.  
  605. if( IsDefined( self.loadoutPrimaryBuff ) && self.loadoutPrimaryBuff != "specialty_null" )
  606. {
  607. if( weaponName == self.primaryWeapon && !( self _hasPerk( self.loadoutPrimaryBuff ) ) )
  608. {
  609. self givePerk( self.loadoutPrimaryBuff, true );
  610. }
  611. if( weaponName != self.primaryWeapon && self _hasPerk( self.loadoutPrimaryBuff ) )
  612. {
  613. self _unsetPerk( self.loadoutPrimaryBuff );
  614. }
  615. }
  616.  
  617. if( IsDefined( self.loadoutSecondaryBuff ) && self.loadoutSecondaryBuff != "specialty_null" )
  618. {
  619. if( weaponName == self.secondaryWeapon && !( self _hasPerk( self.loadoutSecondaryBuff ) ) )
  620. {
  621. self givePerk( self.loadoutSecondaryBuff, true );
  622. }
  623. if( weaponName != self.secondaryWeapon && self _hasPerk( self.loadoutSecondaryBuff ) )
  624. {
  625. self _unsetPerk( self.loadoutSecondaryBuff );
  626. }
  627. }
  628. }
  629. }
  630. }
  631.  
  632.  
  633. watchStartWeaponChange()
  634. {
  635. self endon("death");
  636. self endon("disconnect");
  637. self.changingWeapon = undefined;
  638.  
  639. while(1)
  640. {
  641. self waittill( "weapon_switch_started", newWeapon );
  642. self.changingWeapon = newWeapon;
  643.  
  644. // there's an issue where self.changingWeapon can get stuck on "none" if the owner captures but a full weapon_change doesn't happen
  645. if( newWeapon == "none" && IsDefined( self.isCapturingCrate ) && self.isCapturingCrate )
  646. {
  647. while( self.isCapturingCrate )
  648. wait( 0.05 );
  649.  
  650. self.changingWeapon = undefined;
  651. }
  652. }
  653. }
  654.  
  655. watchWeaponReload()
  656. {
  657. self endon("death");
  658. self endon("disconnect");
  659.  
  660. for ( ;; )
  661. {
  662. self waittill( "reload" );
  663.  
  664. weaponName = self getCurrentWeapon();
  665.  
  666. self.bothBarrels = undefined;
  667.  
  668. if ( !isSubStr( weaponName, "ranger" ) )
  669. continue;
  670.  
  671. self thread watchRangerUsage( weaponName );
  672. }
  673. }
  674.  
  675.  
  676. watchRangerUsage( rangerName )
  677. {
  678. rightAmmo = self getWeaponAmmoClip( rangerName, "right" );
  679. leftAmmo = self getWeaponAmmoClip( rangerName, "left" );
  680.  
  681. self endon ( "reload" );
  682. self endon ( "weapon_change" );
  683.  
  684. for ( ;; )
  685. {
  686. self waittill ( "weapon_fired", weaponName );
  687.  
  688. if ( weaponName != rangerName )
  689. continue;
  690.  
  691. self.bothBarrels = undefined;
  692.  
  693. if ( isSubStr( rangerName, "akimbo" ) )
  694. {
  695. newLeftAmmo = self getWeaponAmmoClip( rangerName, "left" );
  696. newRightAmmo = self getWeaponAmmoClip( rangerName, "right" );
  697.  
  698. if ( leftAmmo != newLeftAmmo && rightAmmo != newRightAmmo )
  699. self.bothBarrels = true;
  700.  
  701. if ( !newLeftAmmo || !newRightAmmo )
  702. return;
  703.  
  704.  
  705. leftAmmo = newLeftAmmo;
  706. rightAmmo = newRightAmmo;
  707. }
  708. else if ( rightAmmo == 2 && !self getWeaponAmmoClip( rangerName, "right" ) )
  709. {
  710. self.bothBarrels = true;
  711. return;
  712. }
  713. }
  714. }
  715.  
  716.  
  717. isHackWeapon( weapon )
  718. {
  719. if ( weapon == "radar_mp" || weapon == "airstrike_mp" || weapon == "helicopter_mp" )
  720. return true;
  721. if ( weapon == "briefcase_bomb_mp" )
  722. return true;
  723. return false;
  724. }
  725.  
  726.  
  727. mayDropWeapon( weapon )
  728. {
  729. if ( weapon == "none" )
  730. return false;
  731.  
  732. if ( isSubStr( weapon, "ac130" ) )
  733. return false;
  734.  
  735. if ( isSubStr( weapon, "uav" ) )
  736. return false;
  737.  
  738. if ( isSubStr( weapon, "killstreak" ) )
  739. return false;
  740.  
  741. invType = WeaponInventoryType( weapon );
  742.  
  743. if ( invType != "primary" )
  744. return false;
  745.  
  746. return true;
  747. }
  748.  
  749. dropWeaponForDeath( attacker )
  750. {
  751. if ( isDefined( level.blockWeaponDrops ) )
  752. return;
  753.  
  754. if ( isdefined( self.droppedDeathWeapon ) )
  755. return;
  756.  
  757. if ( level.inGracePeriod )
  758. return;
  759.  
  760. weapon = self.lastDroppableWeapon;
  761. if ( !isdefined( weapon ) )
  762. {
  763. /#
  764. if ( getdvar("scr_dropdebug") == "1" )
  765. println( "didn't drop weapon: not defined" );
  766. #/
  767. return;
  768. }
  769.  
  770. if ( weapon == "none" )
  771. {
  772. /#
  773. if ( getdvar("scr_dropdebug") == "1" )
  774. println( "didn't drop weapon: weapon == none" );
  775. #/
  776. return;
  777. }
  778.  
  779. if ( !( self hasWeapon( weapon ) ) )
  780. {
  781. /#
  782. if ( getdvar("scr_dropdebug") == "1" )
  783. println( "didn't drop weapon: don't have it anymore (" + weapon + ")" );
  784. #/
  785. return;
  786. }
  787.  
  788. // don't drop juggernaut weapons
  789. if( self isJuggernaut() )
  790. return;
  791.  
  792. tokens = strTok( weapon, "_" );
  793.  
  794. //passing weapon if the weapon is in alt mode.
  795. if ( tokens[0] == "alt" )
  796. {
  797. for( i = 0; i < tokens.size; i++ )
  798. {
  799. if( i > 0 && i < 2 )
  800. weapon += ( tokens[i] );
  801. else if( i > 0 )
  802. weapon += ( "_" + tokens[i] );
  803. else
  804. weapon = "";
  805. }
  806. }
  807.  
  808. if ( weapon != "riotshield_mp" )
  809. {
  810. if ( !(self AnyAmmoForWeaponModes( weapon )) )
  811. {
  812. /#
  813. if ( getdvar("scr_dropdebug") == "1" )
  814. println( "didn't drop weapon: no ammo for weapon modes" );
  815. #/
  816. return;
  817. }
  818.  
  819. clipAmmoR = self GetWeaponAmmoClip( weapon, "right" );
  820. clipAmmoL = self GetWeaponAmmoClip( weapon, "left" );
  821. if ( !clipAmmoR && !clipAmmoL )
  822. {
  823. /#
  824. if ( getdvar("scr_dropdebug") == "1" )
  825. println( "didn't drop weapon: no ammo in clip" );
  826. #/
  827. return;
  828. }
  829.  
  830. stockAmmo = self GetWeaponAmmoStock( weapon );
  831. stockMax = WeaponMaxAmmo( weapon );
  832. if ( stockAmmo > stockMax )
  833. stockAmmo = stockMax;
  834.  
  835. item = self dropItem( weapon );
  836. if ( !isDefined( item ) )
  837. return;
  838.  
  839. item ItemWeaponSetAmmo( clipAmmoR, stockAmmo, clipAmmoL );
  840. }
  841. else
  842. {
  843. item = self dropItem( weapon );
  844. if ( !isDefined( item ) )
  845. return;
  846. item ItemWeaponSetAmmo( 1, 1, 0 );
  847. }
  848.  
  849. /#
  850. if ( getdvar("scr_dropdebug") == "1" )
  851. println( "dropped weapon: " + weapon );
  852. #/
  853.  
  854. self.droppedDeathWeapon = true;
  855.  
  856. item.owner = self;
  857. item.ownersattacker = attacker;
  858.  
  859. item thread watchPickup();
  860.  
  861. item thread deletePickupAfterAWhile();
  862. }
  863.  
  864.  
  865. detachIfAttached( model, baseTag )
  866. {
  867. attachSize = self getAttachSize();
  868.  
  869. for ( i = 0; i < attachSize; i++ )
  870. {
  871. attach = self getAttachModelName( i );
  872.  
  873. if ( attach != model )
  874. continue;
  875.  
  876. tag = self getAttachTagName( i );
  877. self detach( model, tag );
  878.  
  879. if ( tag != baseTag )
  880. {
  881. attachSize = self getAttachSize();
  882.  
  883. for ( i = 0; i < attachSize; i++ )
  884. {
  885. tag = self getAttachTagName( i );
  886.  
  887. if ( tag != baseTag )
  888. continue;
  889.  
  890. model = self getAttachModelName( i );
  891. self detach( model, tag );
  892.  
  893. break;
  894. }
  895. }
  896. return true;
  897. }
  898. return false;
  899. }
  900.  
  901.  
  902. deletePickupAfterAWhile()
  903. {
  904. self endon("death");
  905.  
  906. wait 60;
  907.  
  908. if ( !isDefined( self ) )
  909. return;
  910.  
  911. self delete();
  912. }
  913.  
  914. getItemWeaponName()
  915. {
  916. classname = self.classname;
  917. assert( getsubstr( classname, 0, 7 ) == "weapon_" );
  918. weapname = getsubstr( classname, 7 );
  919. return weapname;
  920. }
  921.  
  922. watchPickup()
  923. {
  924. self endon("death");
  925.  
  926. weapname = self getItemWeaponName();
  927.  
  928. while(1)
  929. {
  930. self waittill( "trigger", player, droppedItem );
  931.  
  932. if ( isdefined( droppedItem ) )
  933. break;
  934. // otherwise, player merely acquired ammo and didn't pick this up
  935. }
  936.  
  937. /#
  938. if ( getdvar("scr_dropdebug") == "1" )
  939. println( "picked up weapon: " + weapname + ", " + isdefined( self.ownersattacker ) );
  940. #/
  941.  
  942. assert( isdefined( player.tookWeaponFrom ) );
  943.  
  944. // make sure the owner information on the dropped item is preserved
  945. droppedWeaponName = droppedItem getItemWeaponName();
  946. if ( isdefined( player.tookWeaponFrom[ droppedWeaponName ] ) )
  947. {
  948. droppedItem.owner = player.tookWeaponFrom[ droppedWeaponName ];
  949. droppedItem.ownersattacker = player;
  950. player.tookWeaponFrom[ droppedWeaponName ] = undefined;
  951. }
  952. droppedItem thread watchPickup();
  953.  
  954. // take owner information from self and put it onto player
  955. if ( isdefined( self.ownersattacker ) && self.ownersattacker == player )
  956. {
  957. player.tookWeaponFrom[ weapname ] = self.owner;
  958. }
  959. else
  960. {
  961. player.tookWeaponFrom[ weapname ] = undefined;
  962. }
  963. }
  964.  
  965. itemRemoveAmmoFromAltModes()
  966. {
  967. origweapname = self getItemWeaponName();
  968.  
  969. curweapname = weaponAltWeaponName( origweapname );
  970.  
  971. altindex = 1;
  972. while ( curweapname != "none" && curweapname != origweapname )
  973. {
  974. self itemWeaponSetAmmo( 0, 0, 0, altindex );
  975. curweapname = weaponAltWeaponName( curweapname );
  976. altindex++;
  977. }
  978. }
  979.  
  980.  
  981. handleScavengerBagPickup( scrPlayer )
  982. {
  983. self endon( "death" );
  984. level endon ( "game_ended" );
  985.  
  986. assert( isDefined( scrPlayer ) );
  987.  
  988. // Wait for the pickup to happen
  989. self waittill( "scavenger", destPlayer );
  990. assert( isDefined ( destPlayer ) );
  991.  
  992. destPlayer notify( "scavenger_pickup" );
  993. destPlayer playLocalSound( "scavenger_pack_pickup" );
  994.  
  995. offhandWeapons = destPlayer getWeaponsListOffhands();
  996. foreach ( offhand in offhandWeapons )
  997. {
  998. if ( offhand != "throwingknife_mp" )
  999. continue;
  1000.  
  1001. currentClipAmmo = destPlayer GetWeaponAmmoClip( offhand );
  1002. destPlayer SetWeaponAmmoClip( offhand, currentClipAmmo + 1);
  1003. }
  1004.  
  1005. primaryWeapons = destPlayer getWeaponsListPrimaries();
  1006. foreach ( primary in primaryWeapons )
  1007. {
  1008. if ( !isCACPrimaryWeapon( primary ) && !level.scavenger_secondary )
  1009. continue;
  1010.  
  1011. if ( isSubStr( primary, "alt" ) && ( isSubStr( primary, "m320" ) || isSubStr( primary, "gl" ) || isSubStr( primary, "gp25" ) || isSubStr( primary, "hybrid" ) ) )
  1012. continue;
  1013.  
  1014. //MW3 Scavenger no longer refills explosives
  1015. if ( getWeaponClass( primary )== "weapon_projectile" )
  1016. continue;
  1017.  
  1018. currentStockAmmo = destPlayer GetWeaponAmmoStock( primary );
  1019. addStockAmmo = weaponClipSize( primary );
  1020.  
  1021. destPlayer setWeaponAmmoStock( primary, currentStockAmmo + addStockAmmo );
  1022. }
  1023.  
  1024. destPlayer maps\mp\gametypes\_damagefeedback::updateDamageFeedback( "scavenger" );
  1025. }
  1026.  
  1027.  
  1028. dropScavengerForDeath( attacker )
  1029. {
  1030. if ( level.inGracePeriod )
  1031. return;
  1032.  
  1033. if( !isDefined( attacker ) )
  1034. return;
  1035.  
  1036. if( attacker == self )
  1037. return;
  1038.  
  1039. dropBag = self dropScavengerBag( "scavenger_bag_mp" );
  1040. dropBag thread handleScavengerBagPickup( self );
  1041.  
  1042. }
  1043.  
  1044. getWeaponBasedGrenadeCount(weapon)
  1045. {
  1046. return 2;
  1047. }
  1048.  
  1049. getWeaponBasedSmokeGrenadeCount(weapon)
  1050. {
  1051. return 1;
  1052. }
  1053.  
  1054. getFragGrenadeCount()
  1055. {
  1056. grenadetype = "frag_grenade_mp";
  1057.  
  1058. count = self getammocount(grenadetype);
  1059. return count;
  1060. }
  1061.  
  1062. getSmokeGrenadeCount()
  1063. {
  1064. grenadetype = "smoke_grenade_mp";
  1065.  
  1066. count = self getammocount(grenadetype);
  1067. return count;
  1068. }
  1069.  
  1070. setWeaponStat( name, incValue, statName )
  1071. {
  1072. self maps\mp\gametypes\_gamelogic::setWeaponStat( name, incValue, statName );
  1073. }
  1074.  
  1075. watchWeaponUsage( weaponHand )
  1076. {
  1077. self endon( "death" );
  1078. self endon( "disconnect" );
  1079. level endon ( "game_ended" );
  1080.  
  1081. for ( ;; )
  1082. {
  1083. self waittill ( "weapon_fired", weaponName );
  1084.  
  1085. self.hasDoneCombat = true;
  1086.  
  1087. if ( !maps\mp\gametypes\_weapons::isPrimaryWeapon( weaponName ) && !maps\mp\gametypes\_weapons::isSideArm( weaponName ) )
  1088. continue;
  1089.  
  1090. if ( isDefined( self.hitsThisMag[ weaponName ] ) )
  1091. self thread updateMagShots( weaponName );
  1092.  
  1093. totalShots = self maps\mp\gametypes\_persistence::statGetBuffered( "totalShots" ) + 1;
  1094. hits = self maps\mp\gametypes\_persistence::statGetBuffered( "hits" );
  1095.  
  1096. assert( totalShots > 0 );
  1097. accuracy = Clamp( float( hits ) / float( totalShots ), 0.0, 1.0 ) * 10000.0;
  1098.  
  1099. self maps\mp\gametypes\_persistence::statSetBuffered( "totalShots", totalShots );
  1100. self maps\mp\gametypes\_persistence::statSetBuffered( "accuracy", int( accuracy ) );
  1101. self maps\mp\gametypes\_persistence::statSetBuffered( "misses", int( totalShots - hits ) );
  1102.  
  1103. if ( isDefined( self.lastStandParams ) && self.lastStandParams.lastStandStartTime == getTime() )
  1104. {
  1105. self.hits = 0;
  1106. return;
  1107. }
  1108.  
  1109. shotsFired = 1;
  1110. self setWeaponStat( weaponName , shotsFired, "shots" );
  1111. self setWeaponStat( weaponName , self.hits, "hits");
  1112.  
  1113. self.hits = 0;
  1114. }
  1115. }
  1116.  
  1117.  
  1118. updateMagShots( weaponName )
  1119. {
  1120. self endon ( "death" );
  1121. self endon ( "disconnect" );
  1122. self endon ( "updateMagShots_" + weaponName );
  1123.  
  1124. self.hitsThisMag[ weaponName ]--;
  1125.  
  1126. wait ( 0.05 );
  1127.  
  1128. self.hitsThisMag[ weaponName ] = weaponClipSize( weaponName );
  1129. }
  1130.  
  1131.  
  1132. checkHitsThisMag( weaponName )
  1133. {
  1134. self endon ( "death" );
  1135. self endon ( "disconnect" );
  1136.  
  1137. self notify ( "updateMagShots_" + weaponName );
  1138. waittillframeend;
  1139.  
  1140. if ( isDefined( self.hitsThisMag[ weaponName ] ) && self.hitsThisMag[ weaponName ] == 0 )
  1141. {
  1142. weaponClass = getWeaponClass( weaponName );
  1143.  
  1144. maps\mp\gametypes\_missions::genericChallenge( weaponClass );
  1145.  
  1146. self.hitsThisMag[ weaponName ] = weaponClipSize( weaponName );
  1147. }
  1148. }
  1149.  
  1150.  
  1151. checkHit( weaponName, victim )
  1152. {
  1153. if( isStrStart( weaponName, "alt_" ) )
  1154. {
  1155. tokens = strTok( weaponName, "_" );
  1156. foreach( token in tokens )
  1157. {
  1158. if ( token == "shotgun" )
  1159. {
  1160. tmpWeaponName = GetSubStr( weaponName, 0, 4 );
  1161. if ( !maps\mp\gametypes\_weapons::isPrimaryWeapon( tmpWeaponName ) && !maps\mp\gametypes\_weapons::isSideArm( tmpWeaponName ) )
  1162. self.hits = 1;
  1163. }
  1164. else if ( token == "hybrid" )
  1165. {
  1166. tmp = GetSubStr( weaponName, 4 );
  1167. weaponName = tmp;
  1168. }
  1169. }
  1170. }
  1171.  
  1172. if ( !maps\mp\gametypes\_weapons::isPrimaryWeapon( weaponName ) && !maps\mp\gametypes\_weapons::isSideArm( weaponName ) )
  1173. return;
  1174.  
  1175. switch ( weaponClass( weaponName ) )
  1176. {
  1177. case "rifle":
  1178. case "pistol":
  1179. case "mg":
  1180. case "smg":
  1181. self.hits++;
  1182. break;
  1183. case "spread":
  1184. self.hits = 1;
  1185. break;
  1186. default:
  1187. break;
  1188. }
  1189.  
  1190. // sometimes the "weapon_fired" notify happens after we hit the guy...
  1191. waittillframeend;
  1192.  
  1193. if ( isDefined( self.hitsThisMag[ weaponName ] ) )
  1194. self thread checkHitsThisMag( weaponName );
  1195.  
  1196. if ( !isDefined( self.lastHitTime[ weaponName ] ) )
  1197. self.lastHitTime[ weaponName ] = 0;
  1198.  
  1199. // already hit with this weapon on this frame
  1200. if ( self.lastHitTime[ weaponName ] == getTime() )
  1201. return;
  1202.  
  1203. self.lastHitTime[ weaponName ] = getTime();
  1204.  
  1205. totalShots = self maps\mp\gametypes\_persistence::statGetBuffered( "totalShots" );
  1206. hits = self maps\mp\gametypes\_persistence::statGetBuffered( "hits" ) + 1;
  1207.  
  1208. if ( hits <= totalShots )
  1209. {
  1210. self maps\mp\gametypes\_persistence::statSetBuffered( "hits", hits );
  1211. self maps\mp\gametypes\_persistence::statSetBuffered( "misses", int(totalShots - hits) );
  1212. self maps\mp\gametypes\_persistence::statSetBuffered( "accuracy", int(hits * 10000 / totalShots) );
  1213. }
  1214. }
  1215.  
  1216.  
  1217. attackerCanDamageItem( attacker, itemOwner )
  1218. {
  1219. return friendlyFireCheck( itemOwner, attacker );
  1220. }
  1221.  
  1222. // returns true if damage should be done to the item given its owner and the attacker
  1223. friendlyFireCheck( owner, attacker, forcedFriendlyFireRule )
  1224. {
  1225. if ( !isdefined( owner ) )// owner has disconnected? allow it
  1226. return true;
  1227.  
  1228. if ( !level.teamBased )// not a team based mode? allow it
  1229. return true;
  1230.  
  1231. attackerTeam = attacker.team;
  1232.  
  1233. friendlyFireRule = level.friendlyfire;
  1234. if ( isdefined( forcedFriendlyFireRule ) )
  1235. friendlyFireRule = forcedFriendlyFireRule;
  1236.  
  1237. if ( friendlyFireRule != 0 )// friendly fire is on? allow it
  1238. return true;
  1239.  
  1240. if ( attacker == owner )// owner may attack his own items
  1241. return true;
  1242.  
  1243. if ( !isdefined( attackerTeam ) )// attacker not on a team? allow it
  1244. return true;
  1245.  
  1246. if ( attackerTeam != owner.team )// attacker not on the same team as the owner? allow it
  1247. return true;
  1248.  
  1249. return false;// disallow it
  1250. }
  1251.  
  1252. watchGrenadeUsage()
  1253. {
  1254. self endon( "death" );
  1255. self endon( "disconnect" );
  1256.  
  1257. self.throwingGrenade = undefined;
  1258. self.gotPullbackNotify = false;
  1259.  
  1260. if ( getIntProperty( "scr_deleteexplosivesonspawn", 1 ) == 1 )
  1261. {
  1262. // delete c4 from previous spawn
  1263. if ( isdefined( self.c4array ) )
  1264. {
  1265. for ( i = 0; i < self.c4array.size; i++ )
  1266. {
  1267. if ( isdefined( self.c4array[ i ] ) )
  1268. {
  1269. if ( isdefined( self.c4array[i].trigger ) )
  1270. self.c4array[i].trigger delete();
  1271.  
  1272. self.c4array[ i ] delete();
  1273. }
  1274. }
  1275. }
  1276. self.c4array = [];
  1277. // delete claymores from previous spawn
  1278. if ( isdefined( self.claymorearray ) )
  1279. {
  1280. for ( i = 0; i < self.claymorearray.size; i++ )
  1281. {
  1282. if ( isdefined( self.claymorearray[ i ] ) )
  1283. {
  1284. if ( isdefined( self.claymorearray[i].trigger ) )
  1285. self.claymorearray[i].trigger delete();
  1286.  
  1287. self.claymorearray[ i ] delete();
  1288. }
  1289. }
  1290. }
  1291. self.claymorearray = [];
  1292.  
  1293. //delete bouncing bettys from previous spawn
  1294. if ( isdefined( self.bouncingbettyArray ) )
  1295. {
  1296. for ( i = 0; i < self.bouncingbettyArray.size; i++ )
  1297. {
  1298. if ( isdefined( self.bouncingbettyArray[ i ] ) )
  1299. {
  1300.  
  1301. if ( isdefined( self.bouncingbettyArray[i].trigger ) )
  1302. self.bouncingbettyArray[i].trigger delete();
  1303.  
  1304. self.bouncingbettyArray[ i ] delete();
  1305. }
  1306. }
  1307. }
  1308. self.bouncingbettyArray = [];
  1309. }
  1310. else
  1311. {
  1312. if ( !isdefined( self.c4array ) )
  1313. self.c4array = [];
  1314. if ( !isdefined( self.claymorearray ) )
  1315. self.claymorearray = [];
  1316. if ( !isdefined( self.bouncingbettyArray ) )
  1317. self.bouncingbettyArray = [];
  1318. }
  1319.  
  1320. thread watchC4();
  1321. thread watchC4Detonation();
  1322. thread watchC4AltDetonation();
  1323. thread watchClaymores();
  1324. thread deleteC4AndClaymoresOnDisconnect();
  1325.  
  1326. self thread watchForThrowbacks();
  1327.  
  1328. for ( ;; )
  1329. {
  1330. self waittill( "grenade_pullback", weaponName );
  1331.  
  1332. self setWeaponStat( weaponName, 1, "shots" );
  1333.  
  1334. self.hasDoneCombat = true;
  1335.  
  1336. if ( weaponName == "claymore_mp" )
  1337. continue;
  1338.  
  1339. self.throwingGrenade = weaponName;
  1340. self.gotPullbackNotify = true;
  1341.  
  1342. if ( weaponName == "c4_mp" )
  1343. self beginC4Tracking();
  1344. else
  1345. self beginGrenadeTracking();
  1346.  
  1347. self.throwingGrenade = undefined;
  1348. }
  1349. }
  1350.  
  1351. beginGrenadeTracking()
  1352. {
  1353. self endon( "death" );
  1354. self endon( "disconnect" );
  1355. self endon( "offhand_end" );
  1356. self endon( "weapon_change" );
  1357.  
  1358. startTime = getTime();
  1359.  
  1360. self waittill( "grenade_fire", grenade, weaponName );
  1361.  
  1362. if ( ( getTime() - startTime > 1000 ) && weaponName == "frag_grenade_mp" )
  1363. grenade.isCooked = true;
  1364.  
  1365. self.changingWeapon = undefined;
  1366.  
  1367. grenade.owner = self;
  1368.  
  1369. switch( weaponName )
  1370. {
  1371. case "frag_grenade_mp":
  1372. case "semtex_mp":
  1373. grenade thread maps\mp\gametypes\_shellshock::grenade_earthQuake();
  1374. grenade.originalOwner = self;
  1375. break;
  1376. case "flash_grenade_mp":
  1377. case "concussion_grenade_mp":
  1378. grenade thread empExplodeWaiter();
  1379. break;
  1380. case "smoke_grenade_mp":
  1381. grenade thread watchSmokeExplode();
  1382. break;
  1383. }
  1384. }
  1385.  
  1386. watchSmokeExplode() // self == smoke grenade
  1387. {
  1388. level endon( "smokeTimesUp" );
  1389.  
  1390. owner = self.owner;
  1391. owner endon( "disconnect" );
  1392.  
  1393. self waittill( "explode", position );
  1394.  
  1395. smokeRadius = 128;
  1396. smokeTime = 8;
  1397. level thread waitSmokeTime( smokeTime, smokeRadius, position );
  1398.  
  1399. /#
  1400. //maps\mp\killstreaks\_ac130::debug_circle( position, smokeRadius, smokeTime, ( 0, 0, 1 ) );
  1401. #/
  1402.  
  1403. while( true )
  1404. {
  1405. if( !IsDefined( owner ) )
  1406. break;
  1407.  
  1408. foreach( player in level.players )
  1409. {
  1410. if( !IsDefined( player ) )
  1411. continue;
  1412.  
  1413. if( level.teamBased && player.team == owner.team )
  1414. continue;
  1415.  
  1416. if( DistanceSquared( player.origin, position ) < smokeRadius * smokeRadius )
  1417. player.inPlayerSmokeScreen = owner;
  1418. else
  1419. player.inPlayerSmokeScreen = undefined;
  1420. }
  1421.  
  1422. wait( 0.05 );
  1423. }
  1424. }
  1425.  
  1426. waitSmokeTime( smokeTime, smokeRadius, position )
  1427. {
  1428. maps\mp\gametypes\_hostmigration::waitLongDurationWithHostMigrationPause( smokeTime );
  1429. level notify( "smokeTimesUp" );
  1430. waittillframeend;
  1431.  
  1432. foreach( player in level.players )
  1433. {
  1434. if( IsDefined( player ) )
  1435. {
  1436. player.inPlayerSmokeScreen = undefined;
  1437. }
  1438. }
  1439.  
  1440. }
  1441.  
  1442. AddMissileToSightTraces( team )
  1443. {
  1444. self.team = team;
  1445. level.missilesForSightTraces[ level.missilesForSightTraces.size ] = self;
  1446.  
  1447. self waittill( "death" );
  1448.  
  1449. newArray = [];
  1450. foreach( missile in level.missilesForSightTraces )
  1451. {
  1452. if ( missile != self )
  1453. newArray[ newArray.size ] = missile;
  1454. }
  1455. level.missilesForSightTraces = newArray;
  1456. }
  1457.  
  1458. watchMissileUsage()
  1459. {
  1460. self endon( "disconnect" );
  1461.  
  1462. for ( ;; )
  1463. {
  1464. self waittill( "missile_fire", missile, weaponName );
  1465.  
  1466. if ( isSubStr( weaponName, "gl_" ) )
  1467. {
  1468. missile.primaryWeapon = self getCurrentPrimaryWeapon();
  1469. missile thread maps\mp\gametypes\_shellshock::grenade_earthQuake();
  1470. }
  1471.  
  1472. switch ( weaponName )
  1473. {
  1474. case "at4_mp":
  1475. case "iw5_smaw_mp":
  1476. case "stinger_mp":
  1477. level notify ( "stinger_fired", self, missile, self.stingerTarget );
  1478. self thread setAltSceneObj( missile, "tag_origin", 65 );
  1479. break;
  1480. case "uav_strike_projectile_mp":
  1481. case "remote_mortar_missile_mp":
  1482. case "javelin_mp":
  1483. level notify ( "stinger_fired", self, missile, self.javelinTarget );
  1484. self thread setAltSceneObj( missile, "tag_origin", 65 );
  1485. break;
  1486. default:
  1487. break;
  1488. }
  1489.  
  1490. switch ( weaponName )
  1491. {
  1492. case "at4_mp":
  1493. case "iw5_smaw_mp":
  1494. case "uav_strike_projectile_mp":
  1495. case "remote_mortar_missile_mp":
  1496. case "javelin_mp":
  1497. case "rpg_mp":
  1498. case "ac130_105mm_mp":
  1499. case "ac130_40mm_mp":
  1500. case "remotemissile_projectile_mp":
  1501. missile thread maps\mp\gametypes\_shellshock::grenade_earthQuake();
  1502. default:
  1503. break;
  1504. }
  1505. }
  1506. }
  1507.  
  1508.  
  1509. watchSentryUsage()
  1510. {
  1511. self endon( "death" );
  1512. self endon( "disconnect" );
  1513.  
  1514. for ( ;; )
  1515. {
  1516. self waittill( "sentry_placement_finished", sentry );
  1517.  
  1518. self thread setAltSceneObj( sentry, "tag_flash", 65 );
  1519. }
  1520. }
  1521.  
  1522.  
  1523. empExplodeWaiter()
  1524. {
  1525. self thread maps\mp\gametypes\_shellshock::endOnDeath();
  1526. self endon( "end_explode" );
  1527.  
  1528. self waittill( "explode", position );
  1529.  
  1530. ents = getEMPDamageEnts( position, 512, false );
  1531.  
  1532. foreach ( ent in ents )
  1533. {
  1534. if ( isDefined( ent.owner ) && !friendlyFireCheck( self.owner, ent.owner ) )
  1535. continue;
  1536.  
  1537. ent notify( "emp_damage", self.owner, 8.0 );
  1538. }
  1539. }
  1540.  
  1541.  
  1542. beginC4Tracking()
  1543. {
  1544. self endon( "death" );
  1545. self endon( "disconnect" );
  1546.  
  1547. self waittill_any( "grenade_fire", "weapon_change", "offhand_end" );
  1548.  
  1549. // need to clear the changing weapon because it'll get stuck on c4_mp and player will stop spawning because we get locked in isChangingWeapon() loop when a killstreak is earned
  1550. self.changingWeapon = undefined;
  1551. }
  1552.  
  1553.  
  1554. watchForThrowbacks()
  1555. {
  1556. self endon( "death" );
  1557. self endon( "disconnect" );
  1558.  
  1559. for ( ;; )
  1560. {
  1561. self waittill( "grenade_fire", grenade, weapname );
  1562.  
  1563. if ( self.gotPullbackNotify )
  1564. {
  1565. self.gotPullbackNotify = false;
  1566. continue;
  1567. }
  1568. if ( !isSubStr( weapname, "frag_" ) && !isSubStr( weapname, "semtex_" ) )
  1569. continue;
  1570.  
  1571. // no grenade_pullback notify! we must have picked it up off the ground.
  1572. grenade.threwBack = true;
  1573. self thread incPlayerStat( "throwbacks", 1 );
  1574.  
  1575. grenade thread maps\mp\gametypes\_shellshock::grenade_earthQuake();
  1576. grenade.originalOwner = self;
  1577. }
  1578. }
  1579.  
  1580.  
  1581. watchC4()
  1582. {
  1583. self endon( "spawned_player" );
  1584. self endon( "disconnect" );
  1585.  
  1586. //maxc4 = 2;
  1587.  
  1588. while ( 1 )
  1589. {
  1590. self waittill( "grenade_fire", c4, weapname );
  1591. if ( weapname == "c4" || weapname == "c4_mp" )
  1592. {
  1593. if ( !self.c4array.size )
  1594. self thread watchC4AltDetonate();
  1595.  
  1596. if ( self.c4array.size )
  1597. {
  1598. self.c4array = array_removeUndefined( self.c4array );
  1599.  
  1600. if( self.c4array.size >= level.maxPerPlayerExplosives )
  1601. {
  1602. self.c4array[0] detonate();
  1603. }
  1604. }
  1605.  
  1606. self.c4array[ self.c4array.size ] = c4;
  1607. c4.owner = self;
  1608. c4.team = self.team;
  1609. c4.activated = false;
  1610. c4.weaponName = weapname;
  1611.  
  1612. c4 thread maps\mp\gametypes\_shellshock::c4_earthQuake();
  1613. c4 thread c4Activate();
  1614. c4 thread c4Damage();
  1615. c4 thread c4EMPDamage();
  1616. c4 thread c4EMPKillstreakWait();
  1617.  
  1618. c4 waittill ( "missile_stuck" ); //to spawn pickup trigger in the correct location
  1619. c4.trigger = spawn( "script_origin", c4.origin );
  1620. c4 thread equipmentWatchUse( self );
  1621.  
  1622. //c4 thread c4DetectionTrigger( self.pers[ "team" ] );
  1623. }
  1624. }
  1625. }
  1626.  
  1627.  
  1628. c4EMPDamage()
  1629. {
  1630. self endon( "death" );
  1631.  
  1632. for ( ;; )
  1633. {
  1634. self waittill( "emp_damage", attacker, duration );
  1635.  
  1636. playfxOnTag( getfx( "sentry_explode_mp" ), self, "tag_origin" );
  1637.  
  1638. self.disabled = true;
  1639. self notify( "disabled" );
  1640.  
  1641. wait( duration );
  1642.  
  1643. self.disabled = undefined;
  1644. self notify( "enabled" );
  1645. }
  1646. }
  1647.  
  1648.  
  1649. c4EMPKillstreakWait()
  1650. {
  1651. self endon( "death" );
  1652.  
  1653. for ( ;; )
  1654. {
  1655. level waittill( "emp_update" );
  1656.  
  1657. if ( (level.teamBased && level.teamEMPed[self.team]) || (!level.teamBased && isDefined( level.empPlayer ) && level.empPlayer != self.owner ) )
  1658. {
  1659. self.disabled = true;
  1660. self notify( "disabled" );
  1661. }
  1662. else
  1663. {
  1664. self.disabled = undefined;
  1665. self notify( "enabled" );
  1666. }
  1667. }
  1668. }
  1669.  
  1670.  
  1671. setClaymoreTeamHeadIcon( team )
  1672. {
  1673. self endon( "death" );
  1674. wait .05;
  1675. if ( level.teamBased )
  1676. self maps\mp\_entityheadicons::setTeamHeadIcon( team, ( 0, 0, 20 ) );
  1677. else if ( isDefined( self.owner ) )
  1678. self maps\mp\_entityheadicons::setPlayerHeadIcon( self.owner, (0,0,20) );
  1679. }
  1680.  
  1681.  
  1682. watchClaymores()
  1683. {
  1684. self endon( "spawned_player" );
  1685. self endon( "disconnect" );
  1686.  
  1687. self.claymorearray = [];
  1688. while ( 1 )
  1689. {
  1690. self waittill( "grenade_fire", claymore, weapname );
  1691. if ( weapname == "claymore" || weapname == "claymore_mp" )
  1692. {
  1693. if( !IsAlive( self ) )
  1694. {
  1695. claymore delete();
  1696. return;
  1697. }
  1698.  
  1699. // need to see if this is being placed far away from the player and not let it do that
  1700. // this will fix a legacy bug where you can stand on a ledge and plant a claymore down on the ground far below you
  1701. claymore Hide();
  1702. claymore waittill( "missile_stuck" );
  1703. distanceZ = 40;
  1704.  
  1705. if( distanceZ * distanceZ < DistanceSquared( claymore.origin, self.origin ) )
  1706. {
  1707. secTrace = bulletTrace( self.origin, self.origin - (0, 0, distanceZ), false, self );
  1708.  
  1709. if( secTrace["fraction"] == 1 )
  1710. {
  1711. // there's nothing under us so don't place the claymore up in the air
  1712. claymore delete();
  1713. self SetWeaponAmmoStock( "claymore_mp", self GetWeaponAmmoStock( "claymore_mp" ) + 1 );
  1714. continue;
  1715. }
  1716. claymore.origin = secTrace["position"];
  1717. }
  1718. claymore Show();
  1719.  
  1720. self.claymorearray = array_removeUndefined( self.claymorearray );
  1721.  
  1722. if( self.claymoreArray.size >= level.maxPerPlayerExplosives )
  1723. self.claymoreArray[0] detonate();
  1724.  
  1725. self.claymorearray[ self.claymorearray.size ] = claymore;
  1726. claymore.owner = self;
  1727. claymore.team = self.team;
  1728. claymore.weaponName = weapname;
  1729. claymore.trigger = spawn( "script_origin", claymore.origin );
  1730.  
  1731. level.mines[level.mines.size] = claymore;
  1732. claymore thread c4Damage();
  1733. claymore thread c4EMPDamage();
  1734. claymore thread c4EMPKillstreakWait();
  1735. claymore thread claymoreDetonation();
  1736. claymore thread equipmentWatchUse( self );
  1737. //claymore thread claymoreDetectionTrigger_wait( self.pers[ "team" ] );
  1738. claymore thread setClaymoreTeamHeadIcon( self.pers[ "team" ] );
  1739.  
  1740. // need to clear the changing weapon because it'll get stuck on claymore_mp and player will stop spawning because we get locked in isChangingWeapon() loop when a killstreak is earned
  1741. self.changingWeapon = undefined;
  1742.  
  1743. /#
  1744. if ( getdvarint( "scr_claymoredebug" ) )
  1745. {
  1746. claymore thread claymoreDebug();
  1747. }
  1748. #/
  1749. }
  1750. }
  1751. }
  1752.  
  1753. equipmentWatchUse( owner )
  1754. {
  1755. self endon( "spawned_player" );
  1756. self endon( "disconnect" );
  1757.  
  1758. self.trigger setCursorHint( "HINT_NOICON" );
  1759.  
  1760. if ( self.weaponname == "c4_mp" )
  1761. self.trigger setHintString( &"MP_PICKUP_C4" );
  1762. else if (self.weaponname == "claymore_mp" )
  1763. self.trigger setHintString( &"MP_PICKUP_CLAYMORE" );
  1764. else if ( self.weaponname == "bouncingbetty_mp" )
  1765. self.trigger setHintString( &"MP_PICKUP_BOUNCING_BETTY" );
  1766.  
  1767. self.trigger setSelfUsable( owner );
  1768. self.trigger thread notUsableForJoiningPlayers( self );
  1769.  
  1770. for ( ;; )
  1771. {
  1772. self.trigger waittill ( "trigger", owner );
  1773.  
  1774. owner playLocalSound( "scavenger_pack_pickup" );
  1775.  
  1776. owner SetWeaponAmmoStock( self.weaponname, owner GetWeaponAmmoStock( self.weaponname ) + 1 );
  1777.  
  1778. self.trigger delete();
  1779. self delete();
  1780. self notify( "death" );
  1781. }
  1782. }
  1783.  
  1784. /#
  1785. claymoreDebug()
  1786. {
  1787. self waittill( "missile_stuck" );
  1788. self thread showCone( acos( level.claymoreDetectionDot ), level.claymoreDetonateRadius, ( 1, .85, 0 ) );
  1789. self thread showCone( 60, 256, ( 1, 0, 0 ) );
  1790. }
  1791.  
  1792. vectorcross( v1, v2 )
  1793. {
  1794. return( v1[ 1 ] * v2[ 2 ] - v1[ 2 ] * v2[ 1 ], v1[ 2 ] * v2[ 0 ] - v1[ 0 ] * v2[ 2 ], v1[ 0 ] * v2[ 1 ] - v1[ 1 ] * v2[ 0 ] );
  1795. }
  1796.  
  1797. showCone( angle, range, color )
  1798. {
  1799. self endon( "death" );
  1800.  
  1801. start = self.origin;
  1802. forward = anglestoforward( self.angles );
  1803. right = vectorcross( forward, ( 0, 0, 1 ) );
  1804. up = vectorcross( forward, right );
  1805.  
  1806. fullforward = forward * range * cos( angle );
  1807. sideamnt = range * sin( angle );
  1808.  
  1809. while ( 1 )
  1810. {
  1811. prevpoint = ( 0, 0, 0 );
  1812. for ( i = 0; i <= 20; i++ )
  1813. {
  1814. coneangle = i / 20.0 * 360;
  1815. point = start + fullforward + sideamnt * ( right * cos( coneangle ) + up * sin( coneangle ) );
  1816. if ( i > 0 )
  1817. {
  1818. line( start, point, color );
  1819. line( prevpoint, point, color );
  1820. }
  1821. prevpoint = point;
  1822. }
  1823. wait .05;
  1824. }
  1825. }
  1826. #/
  1827.  
  1828. claymoreDetonation()
  1829. {
  1830. self endon( "death" );
  1831.  
  1832. //self waittill( "missile_stuck" );
  1833.  
  1834. damagearea = spawn( "trigger_radius", self.origin + ( 0, 0, 0 - level.claymoreDetonateRadius ), 0, level.claymoreDetonateRadius, level.claymoreDetonateRadius * 2 );
  1835. self thread deleteOnDeath( damagearea );
  1836.  
  1837. while ( 1 )
  1838. {
  1839. damagearea waittill( "trigger", player );
  1840.  
  1841. if ( getdvarint( "scr_claymoredebug" ) != 1 )
  1842. {
  1843. if ( isdefined( self.owner ) && player == self.owner )
  1844. continue;
  1845. if ( !friendlyFireCheck( self.owner, player, 0 ) )
  1846. continue;
  1847. }
  1848. if ( lengthsquared( player getEntityVelocity() ) < 10 )
  1849. continue;
  1850.  
  1851. zDistance = abs( player.origin[2] - self.origin[2] );
  1852.  
  1853. if ( zDistance > 128)
  1854. continue;
  1855.  
  1856. if ( !player shouldAffectClaymore( self ) )
  1857. continue;
  1858.  
  1859. if ( player damageConeTrace( self.origin, self ) > 0 )
  1860. break;
  1861. }
  1862.  
  1863. self playsound ("claymore_activated");
  1864.  
  1865. if ( IsPlayer( player ) && player _hasPerk( "specialty_delaymine" ) )
  1866. {
  1867. player notify( "triggered_claymore" );
  1868. wait level.delayMineTime;
  1869. }
  1870. else
  1871. wait level.claymoreDetectionGracePeriod;
  1872.  
  1873. if ( isDefined( self.trigger ) )
  1874. self.trigger delete();
  1875.  
  1876. self detonate();
  1877. }
  1878.  
  1879. shouldAffectClaymore( claymore )
  1880. {
  1881. if ( isDefined( claymore.disabled ) )
  1882. return false;
  1883.  
  1884. pos = self.origin + ( 0, 0, 32 );
  1885.  
  1886. dirToPos = pos - claymore.origin;
  1887. claymoreForward = anglesToForward( claymore.angles );
  1888.  
  1889. dist = vectorDot( dirToPos, claymoreForward );
  1890. if ( dist < level.claymoreDetectionMinDist )
  1891. return false;
  1892.  
  1893. dirToPos = vectornormalize( dirToPos );
  1894.  
  1895. dot = vectorDot( dirToPos, claymoreForward );
  1896. return( dot > level.claymoreDetectionDot );
  1897. }
  1898.  
  1899. deleteOnDeath( ent )
  1900. {
  1901. self waittill( "death" );
  1902. wait .05;
  1903.  
  1904. if ( isdefined( ent ) )
  1905. {
  1906. if ( isDefined( ent.trigger ) )
  1907. ent.trigger delete();
  1908.  
  1909. ent delete();
  1910. }
  1911. }
  1912.  
  1913. c4Activate()
  1914. {
  1915. self endon( "death" );
  1916.  
  1917. self waittill( "missile_stuck" );
  1918.  
  1919. wait 0.05;
  1920.  
  1921. self notify( "activated" );
  1922. self.activated = true;
  1923. }
  1924.  
  1925. watchC4AltDetonate()
  1926. {
  1927. self endon( "death" );
  1928. self endon( "disconnect" );
  1929. self endon( "detonated" );
  1930. level endon( "game_ended" );
  1931.  
  1932. buttonTime = 0;
  1933. for ( ;; )
  1934. {
  1935. if ( self UseButtonPressed() )
  1936. {
  1937. buttonTime = 0;
  1938. while ( self UseButtonPressed() )
  1939. {
  1940. buttonTime += 0.066;
  1941. wait( 0.066 );
  1942. }
  1943.  
  1944. println( "pressTime1: " + buttonTime );
  1945. if ( buttonTime >= 0.5 )
  1946. continue;
  1947.  
  1948. buttonTime = 0;
  1949. while ( !self UseButtonPressed() && buttonTime < 0.5 )
  1950. {
  1951. buttonTime += 0.066;
  1952. wait( 0.066 );
  1953. }
  1954.  
  1955. println( "delayTime: " + buttonTime );
  1956. if ( buttonTime >= 0.5 )
  1957. continue;
  1958.  
  1959. if ( !self.c4Array.size )
  1960. return;
  1961.  
  1962. self notify( "alt_detonate" );
  1963. }
  1964. wait( 0.066 );
  1965. }
  1966. }
  1967.  
  1968. watchC4Detonation()
  1969. {
  1970. self endon( "death" );
  1971. self endon( "disconnect" );
  1972.  
  1973. while ( 1 )
  1974. {
  1975. self waittillmatch( "detonate", "c4_mp" );
  1976. newarray = [];
  1977. for ( i = 0; i < self.c4array.size; i++ )
  1978. {
  1979. c4 = self.c4array[ i ];
  1980. if ( isdefined( self.c4array[ i ] ) )
  1981. c4 thread waitAndDetonate( 0.1 );
  1982. }
  1983. self.c4array = newarray;
  1984. self notify( "detonated" );
  1985. }
  1986. }
  1987.  
  1988.  
  1989. watchC4AltDetonation()
  1990. {
  1991. self endon( "death" );
  1992. self endon( "disconnect" );
  1993.  
  1994. while ( 1 )
  1995. {
  1996. self waittill( "alt_detonate" );
  1997. weap = self getCurrentWeapon();
  1998. if ( weap != "c4_mp" )
  1999. {
  2000. newarray = [];
  2001. for ( i = 0; i < self.c4array.size; i++ )
  2002. {
  2003. c4 = self.c4array[ i ];
  2004. if ( isdefined( self.c4array[ i ] ) )
  2005. c4 thread waitAndDetonate( 0.1 );
  2006. }
  2007. self.c4array = newarray;
  2008. self notify( "detonated" );
  2009. }
  2010. }
  2011. }
  2012.  
  2013.  
  2014. waitAndDetonate( delay )
  2015. {
  2016. self endon( "death" );
  2017. wait delay;
  2018.  
  2019. self waitTillEnabled();
  2020.  
  2021. self detonate();
  2022. }
  2023.  
  2024. deleteC4AndClaymoresOnDisconnect()
  2025. {
  2026. self endon( "death" );
  2027. self waittill( "disconnect" );
  2028.  
  2029. c4array = self.c4array;
  2030. claymorearray = self.claymorearray;
  2031.  
  2032. wait .05;
  2033.  
  2034. for ( i = 0; i < c4array.size; i++ )
  2035. {
  2036. if ( isdefined( c4array[ i ] ) )
  2037. c4array[ i ] delete();
  2038. }
  2039. for ( i = 0; i < claymorearray.size; i++ )
  2040. {
  2041. if ( isdefined( claymorearray[ i ] ) )
  2042. claymorearray[ i ] delete();
  2043. }
  2044. }
  2045.  
  2046. c4Damage()
  2047. {
  2048. self endon( "death" );
  2049.  
  2050. self setcandamage( true );
  2051. self.maxhealth = 100000;
  2052. self.health = self.maxhealth;
  2053.  
  2054. attacker = undefined;
  2055.  
  2056. while ( 1 )
  2057. {
  2058. self waittill( "damage", damage, attacker, direction_vec, point, type, modelName, tagName, partName, iDFlags, weapon );
  2059. if ( !isPlayer( attacker ) )
  2060. continue;
  2061.  
  2062. // don't allow people to destroy C4 on their team if FF is off
  2063. if ( !friendlyFireCheck( self.owner, attacker ) )
  2064. continue;
  2065.  
  2066. if( IsDefined( weapon ) )
  2067. {
  2068. switch( weapon )
  2069. {
  2070. case "concussion_grenade_mp":
  2071. case "flash_grenade_mp":
  2072. case "smoke_grenade_mp":
  2073. continue;
  2074. }
  2075. }
  2076.  
  2077. break;
  2078. }
  2079.  
  2080. if ( level.c4explodethisframe )
  2081. wait .1 + randomfloat( .4 );
  2082. else
  2083. wait .05;
  2084.  
  2085. if ( !isdefined( self ) )
  2086. return;
  2087.  
  2088. level.c4explodethisframe = true;
  2089.  
  2090. thread resetC4ExplodeThisFrame();
  2091.  
  2092. if ( isDefined( type ) && ( isSubStr( type, "MOD_GRENADE" ) || isSubStr( type, "MOD_EXPLOSIVE" ) ) )
  2093. self.wasChained = true;
  2094.  
  2095. if ( isDefined( iDFlags ) && ( iDFlags & level.iDFLAGS_PENETRATION ) )
  2096. self.wasDamagedFromBulletPenetration = true;
  2097.  
  2098. self.wasDamaged = true;
  2099.  
  2100. if( isPlayer( attacker ) )
  2101. {
  2102. attacker maps\mp\gametypes\_damagefeedback::updateDamageFeedback( "c4" );
  2103. }
  2104.  
  2105. if ( level.teamBased )
  2106. {
  2107. // "destroyed_explosive" notify, for challenges
  2108. if ( isdefined( attacker ) && isdefined( attacker.pers[ "team" ] ) && isdefined( self.owner ) && isdefined( self.owner.pers[ "team" ] ) )
  2109. {
  2110. if ( attacker.pers[ "team" ] != self.owner.pers[ "team" ] )
  2111. attacker notify( "destroyed_explosive" );
  2112. }
  2113. }
  2114. else
  2115. {
  2116. // checking isDefined attacker is defensive but it's too late in the project to risk issues by not having it
  2117. if ( isDefined( self.owner ) && isDefined( attacker ) && attacker != self.owner )
  2118. attacker notify( "destroyed_explosive" );
  2119. }
  2120.  
  2121. if ( isDefined( self.trigger ) )
  2122. self.trigger delete();
  2123.  
  2124. self detonate( attacker );
  2125. // won't get here; got death notify.
  2126. }
  2127.  
  2128. resetC4ExplodeThisFrame()
  2129. {
  2130. wait .05;
  2131. level.c4explodethisframe = false;
  2132. }
  2133.  
  2134. saydamaged( orig, amount )
  2135. {
  2136. for ( i = 0; i < 60; i++ )
  2137. {
  2138. print3d( orig, "damaged! " + amount );
  2139. wait .05;
  2140. }
  2141. }
  2142.  
  2143. waitTillEnabled()
  2144. {
  2145. if ( !isDefined( self.disabled ) )
  2146. return;
  2147.  
  2148. self waittill( "enabled" );
  2149. assert( !isDefined( self.disabled ) );
  2150. }
  2151.  
  2152.  
  2153. c4DetectionTrigger( ownerTeam )
  2154. {
  2155. self waittill( "activated" );
  2156.  
  2157. trigger = spawn( "trigger_radius", self.origin - ( 0, 0, 128 ), 0, 512, 256 );
  2158. trigger.detectId = "trigger" + getTime() + randomInt( 1000000 );
  2159.  
  2160. trigger.owner = self;
  2161. trigger thread detectIconWaiter( level.otherTeam[ ownerTeam ] );
  2162.  
  2163. self waittill( "death" );
  2164. trigger notify( "end_detection" );
  2165.  
  2166. if ( isDefined( trigger.bombSquadIcon ) )
  2167. trigger.bombSquadIcon destroy();
  2168.  
  2169. trigger delete();
  2170. }
  2171.  
  2172.  
  2173. //claymoreDetectionTrigger_wait( ownerTeam )
  2174. //{
  2175. // self endon( "death" );
  2176. // self waittill( "missile_stuck" );
  2177. //
  2178. // self thread claymoreDetectionTrigger( ownerTeam );
  2179. //}
  2180.  
  2181. claymoreDetectionTrigger( ownerTeam )
  2182. {
  2183. trigger = spawn( "trigger_radius", self.origin - ( 0, 0, 128 ), 0, 512, 256 );
  2184. trigger.detectId = "trigger" + getTime() + randomInt( 1000000 );
  2185.  
  2186. trigger.owner = self;
  2187. trigger thread detectIconWaiter( level.otherTeam[ ownerTeam ] );
  2188.  
  2189. self waittill( "death" );
  2190. trigger notify( "end_detection" );
  2191.  
  2192. if ( isDefined( trigger.bombSquadIcon ) )
  2193. trigger.bombSquadIcon destroy();
  2194.  
  2195. trigger delete();
  2196. }
  2197.  
  2198.  
  2199. detectIconWaiter( detectTeam )
  2200. {
  2201. self endon( "end_detection" );
  2202. level endon( "game_ended" );
  2203.  
  2204. while ( !level.gameEnded )
  2205. {
  2206. self waittill( "trigger", player );
  2207.  
  2208. if ( !player.detectExplosives )
  2209. continue;
  2210.  
  2211. if ( level.teamBased && player.team != detectTeam )
  2212. continue;
  2213. else if ( !level.teamBased && player == self.owner.owner )
  2214. continue;
  2215.  
  2216. if ( isDefined( player.bombSquadIds[ self.detectId ] ) )
  2217. continue;
  2218.  
  2219. player thread showHeadIcon( self );
  2220. }
  2221. }
  2222.  
  2223.  
  2224. setupBombSquad()
  2225. {
  2226. self.bombSquadIds = [];
  2227.  
  2228. if ( self.detectExplosives && !self.bombSquadIcons.size )
  2229. {
  2230. for ( index = 0; index < 4; index++ )
  2231. {
  2232. self.bombSquadIcons[ index ] = newClientHudElem( self );
  2233. self.bombSquadIcons[ index ].x = 0;
  2234. self.bombSquadIcons[ index ].y = 0;
  2235. self.bombSquadIcons[ index ].z = 0;
  2236. self.bombSquadIcons[ index ].alpha = 0;
  2237. self.bombSquadIcons[ index ].archived = true;
  2238. self.bombSquadIcons[ index ] setShader( "waypoint_bombsquad", 14, 14 );
  2239. self.bombSquadIcons[ index ] setWaypoint( false, false );
  2240. self.bombSquadIcons[ index ].detectId = "";
  2241. }
  2242. }
  2243. else if ( !self.detectExplosives )
  2244. {
  2245. for ( index = 0; index < self.bombSquadIcons.size; index++ )
  2246. self.bombSquadIcons[ index ] destroy();
  2247.  
  2248. self.bombSquadIcons = [];
  2249. }
  2250. }
  2251.  
  2252.  
  2253. showHeadIcon( trigger )
  2254. {
  2255. triggerDetectId = trigger.detectId;
  2256. useId = -1;
  2257. for ( index = 0; index < 4; index++ )
  2258. {
  2259. detectId = self.bombSquadIcons[ index ].detectId;
  2260.  
  2261. if ( detectId == triggerDetectId )
  2262. return;
  2263.  
  2264. if ( detectId == "" )
  2265. useId = index;
  2266. }
  2267.  
  2268. if ( useId < 0 )
  2269. return;
  2270.  
  2271. self.bombSquadIds[ triggerDetectId ] = true;
  2272.  
  2273. self.bombSquadIcons[ useId ].x = trigger.origin[ 0 ];
  2274. self.bombSquadIcons[ useId ].y = trigger.origin[ 1 ];
  2275. self.bombSquadIcons[ useId ].z = trigger.origin[ 2 ] + 24 + 128;
  2276.  
  2277. self.bombSquadIcons[ useId ] fadeOverTime( 0.25 );
  2278. self.bombSquadIcons[ useId ].alpha = 1;
  2279. self.bombSquadIcons[ useId ].detectId = trigger.detectId;
  2280.  
  2281. while ( isAlive( self ) && isDefined( trigger ) && self isTouching( trigger ) )
  2282. wait( 0.05 );
  2283.  
  2284. if ( !isDefined( self ) )
  2285. return;
  2286.  
  2287. self.bombSquadIcons[ useId ].detectId = "";
  2288. self.bombSquadIcons[ useId ] fadeOverTime( 0.25 );
  2289. self.bombSquadIcons[ useId ].alpha = 0;
  2290. self.bombSquadIds[ triggerDetectId ] = undefined;
  2291. }
  2292.  
  2293.  
  2294. // these functions are used with scripted weapons (like c4, claymores, artillery)
  2295. // returns an array of objects representing damageable entities (including players) within a given sphere.
  2296. // each object has the property damageCenter, which represents its center (the location from which it can be damaged).
  2297. // each object also has the property entity, which contains the entity that it represents.
  2298. // to damage it, call damageEnt() on it.
  2299. getDamageableEnts( pos, radius, doLOS, startRadius )
  2300. {
  2301. ents = [];
  2302.  
  2303. if ( !isdefined( doLOS ) )
  2304. doLOS = false;
  2305.  
  2306. if ( !isdefined( startRadius ) )
  2307. startRadius = 0;
  2308.  
  2309. radiusSq = radius * radius;
  2310.  
  2311. // players
  2312. players = level.players;
  2313. for ( i = 0; i < players.size; i++ )
  2314. {
  2315. if ( !isalive( players[ i ] ) || players[ i ].sessionstate != "playing" )
  2316. continue;
  2317.  
  2318. playerpos = get_damageable_player_pos( players[ i ] );
  2319. distSq = distanceSquared( pos, playerpos );
  2320. if ( distSq < radiusSq && ( !doLOS || weaponDamageTracePassed( pos, playerpos, startRadius, players[ i ] ) ) )
  2321. {
  2322. ents[ ents.size ] = get_damageable_player( players[ i ], playerpos );
  2323. }
  2324. }
  2325.  
  2326. // grenades
  2327. grenades = getentarray( "grenade", "classname" );
  2328. for ( i = 0; i < grenades.size; i++ )
  2329. {
  2330. entpos = get_damageable_grenade_pos( grenades[ i ] );
  2331. distSq = distanceSquared( pos, entpos );
  2332. if ( distSq < radiusSq && ( !doLOS || weaponDamageTracePassed( pos, entpos, startRadius, grenades[ i ] ) ) )
  2333. {
  2334. ents[ ents.size ] = get_damageable_grenade( grenades[ i ], entpos );
  2335. }
  2336. }
  2337.  
  2338. destructibles = getentarray( "destructible", "targetname" );
  2339. for ( i = 0; i < destructibles.size; i++ )
  2340. {
  2341. entpos = destructibles[ i ].origin;
  2342. distSq = distanceSquared( pos, entpos );
  2343. if ( distSq < radiusSq && ( !doLOS || weaponDamageTracePassed( pos, entpos, startRadius, destructibles[ i ] ) ) )
  2344. {
  2345. newent = spawnstruct();
  2346. newent.isPlayer = false;
  2347. newent.isADestructable = false;
  2348. newent.entity = destructibles[ i ];
  2349. newent.damageCenter = entpos;
  2350. ents[ ents.size ] = newent;
  2351. }
  2352. }
  2353.  
  2354. destructables = getentarray( "destructable", "targetname" );
  2355. for ( i = 0; i < destructables.size; i++ )
  2356. {
  2357. entpos = destructables[ i ].origin;
  2358. distSq = distanceSquared( pos, entpos );
  2359. if ( distSq < radiusSq && ( !doLOS || weaponDamageTracePassed( pos, entpos, startRadius, destructables[ i ] ) ) )
  2360. {
  2361. newent = spawnstruct();
  2362. newent.isPlayer = false;
  2363. newent.isADestructable = true;
  2364. newent.entity = destructables[ i ];
  2365. newent.damageCenter = entpos;
  2366. ents[ ents.size ] = newent;
  2367. }
  2368. }
  2369.  
  2370. //sentries
  2371. sentries = getentarray( "misc_turret", "classname" );
  2372. foreach ( sentry in sentries )
  2373. {
  2374. entpos = sentry.origin + (0,0,32);
  2375. distSq = distanceSquared( pos, entpos );
  2376. if ( distSq < radiusSq && ( !doLOS || weaponDamageTracePassed( pos, entpos, startRadius, sentry ) ) )
  2377. {
  2378. switch( sentry.model )
  2379. {
  2380. case "sentry_minigun_weak":
  2381. case "mp_sam_turret":
  2382. case "mp_remote_turret":
  2383. case "vehicle_ugv_talon_gun_mp":
  2384. ents[ ents.size ] = get_damageable_sentry(sentry, entpos);
  2385. break;
  2386. }
  2387. }
  2388. }
  2389.  
  2390. // mines ( the problem here seems to be the traceline from 1 ground position to another is easily blocked, the origin offset helps but may have it's own issues )
  2391. mines = getentarray( "script_model", "classname" );
  2392. foreach ( mine in mines )
  2393. {
  2394. if ( mine.model != "projectile_bouncing_betty_grenade" && mine.model != "ims_scorpion_body" )
  2395. continue;
  2396.  
  2397. entpos = mine.origin + (0,0,32);
  2398. distSq = distanceSquared( pos, entpos );
  2399. if ( distSq < radiusSq && ( !doLOS || weaponDamageTracePassed( pos, entpos, startRadius, mine ) ) )
  2400. ents[ ents.size ] = get_damageable_mine( mine, entpos );
  2401. }
  2402.  
  2403. return ents;
  2404. }
  2405.  
  2406.  
  2407. getEMPDamageEnts( pos, radius, doLOS, startRadius )
  2408. {
  2409. ents = [];
  2410.  
  2411. if ( !isDefined( doLOS ) )
  2412. doLOS = false;
  2413.  
  2414. if ( !isDefined( startRadius ) )
  2415. startRadius = 0;
  2416.  
  2417. grenades = getEntArray( "grenade", "classname" );
  2418. foreach ( grenade in grenades )
  2419. {
  2420. //if ( !isDefined( grenade.weaponName ) )
  2421. // continue;
  2422.  
  2423. entpos = grenade.origin;
  2424. dist = distance( pos, entpos );
  2425. if ( dist < radius && ( !doLOS || weaponDamageTracePassed( pos, entpos, startRadius, grenade ) ) )
  2426. ents[ ents.size ] = grenade;
  2427. }
  2428.  
  2429. turrets = getEntArray( "misc_turret", "classname" );
  2430. foreach ( turret in turrets )
  2431. {
  2432. //if ( !isDefined( turret.weaponName ) )
  2433. // continue;
  2434.  
  2435. entpos = turret.origin;
  2436. dist = distance( pos, entpos );
  2437. if ( dist < radius && ( !doLOS || weaponDamageTracePassed( pos, entpos, startRadius, turret ) ) )
  2438. ents[ ents.size ] = turret;
  2439. }
  2440.  
  2441. return ents;
  2442. }
  2443.  
  2444.  
  2445. weaponDamageTracePassed( from, to, startRadius, ent )
  2446. {
  2447. midpos = undefined;
  2448.  
  2449. diff = to - from;
  2450. if ( lengthsquared( diff ) < startRadius * startRadius )
  2451. return true;
  2452.  
  2453. dir = vectornormalize( diff );
  2454. midpos = from + ( dir[ 0 ] * startRadius, dir[ 1 ] * startRadius, dir[ 2 ] * startRadius );
  2455.  
  2456. trace = bullettrace( midpos, to, false, ent );
  2457.  
  2458. if ( getdvarint( "scr_damage_debug" ) != 0 || getdvarint( "scr_debugMines" ) != 0 )
  2459. {
  2460. thread debugprint( from, ".dmg" );
  2461. if ( isdefined( ent ) )
  2462. thread debugprint( to, "." + ent.classname );
  2463. else
  2464. thread debugprint( to, ".undefined" );
  2465. if ( trace[ "fraction" ] == 1 )
  2466. {
  2467. thread debugline( midpos, to, ( 1, 1, 1 ) );
  2468. }
  2469. else
  2470. {
  2471. thread debugline( midpos, trace[ "position" ], ( 1, .9, .8 ) );
  2472. thread debugline( trace[ "position" ], to, ( 1, .4, .3 ) );
  2473. }
  2474. }
  2475.  
  2476. return( trace[ "fraction" ] == 1 );
  2477. }
  2478.  
  2479. // eInflictor = the entity that causes the damage (e.g. a claymore)
  2480. // eAttacker = the player that is attacking
  2481. // iDamage = the amount of damage to do
  2482. // sMeansOfDeath = string specifying the method of death (e.g. "MOD_PROJECTILE_SPLASH")
  2483. // sWeapon = string specifying the weapon used (e.g. "claymore_mp")
  2484. // damagepos = the position damage is coming from
  2485. // damagedir = the direction damage is moving in
  2486. damageEnt( eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, damagepos, damagedir )
  2487. {
  2488. if ( self.isPlayer )
  2489. {
  2490. self.damageOrigin = damagepos;
  2491. self.entity thread [[ level.callbackPlayerDamage ]](
  2492. eInflictor,// eInflictor The entity that causes the damage.( e.g. a turret )
  2493. eAttacker,// eAttacker The entity that is attacking.
  2494. iDamage,// iDamage Integer specifying the amount of damage done
  2495. 0,// iDFlags Integer specifying flags that are to be applied to the damage
  2496. sMeansOfDeath,// sMeansOfDeath Integer specifying the method of death
  2497. sWeapon,// sWeapon The weapon number of the weapon used to inflict the damage
  2498. damagepos,// vPoint The point the damage is from?
  2499. damagedir,// vDir The direction of the damage
  2500. "none",// sHitLoc The location of the hit
  2501. 0// psOffsetTime The time offset for the damage
  2502. );
  2503. }
  2504. else
  2505. {
  2506. // destructable walls and such can only be damaged in certain ways.
  2507. if ( self.isADestructable && ( sWeapon == "artillery_mp" || sWeapon == "claymore_mp" || sWeapon == "stealth_bomb_mp" ) )
  2508. return;
  2509.  
  2510. self.entity notify( "damage", iDamage, eAttacker, ( 0, 0, 0 ), ( 0, 0, 0 ), "MOD_EXPLOSIVE", "", "", "", undefined, sWeapon );
  2511. }
  2512. }
  2513.  
  2514.  
  2515. debugline( a, b, color )
  2516. {
  2517. for ( i = 0; i < 30 * 20; i++ )
  2518. {
  2519. line( a, b, color );
  2520. wait .05;
  2521. }
  2522. }
  2523.  
  2524. debugcircle( center, radius, color, segments )
  2525. {
  2526. if ( !isDefined( segments ) )
  2527. segments = 16;
  2528.  
  2529. angleFrac = 360/segments;
  2530. circlepoints = [];
  2531.  
  2532. for( i = 0; i < segments; i++ )
  2533. {
  2534. angle = (angleFrac * i);
  2535. xAdd = cos(angle) * radius;
  2536. yAdd = sin(angle) * radius;
  2537. x = center[0] + xAdd;
  2538. y = center[1] + yAdd;
  2539. z = center[2];
  2540. circlepoints[circlepoints.size] = ( x, y, z );
  2541. }
  2542.  
  2543. for( i = 0; i < circlepoints.size; i++ )
  2544. {
  2545. start = circlepoints[i];
  2546. if (i + 1 >= circlepoints.size)
  2547. end = circlepoints[0];
  2548. else
  2549. end = circlepoints[i + 1];
  2550.  
  2551. thread debugline( start, end, color );
  2552. }
  2553. }
  2554.  
  2555. debugprint( pt, txt )
  2556. {
  2557. for ( i = 0; i < 30 * 20; i++ )
  2558. {
  2559. print3d( pt, txt );
  2560. wait .05;
  2561. }
  2562. }
  2563.  
  2564.  
  2565. onWeaponDamage( eInflictor, sWeapon, meansOfDeath, damage, eAttacker )
  2566. {
  2567. self endon( "death" );
  2568. self endon( "disconnect" );
  2569.  
  2570. switch( sWeapon )
  2571. {
  2572. case "concussion_grenade_mp":
  2573. // should match weapon settings in gdt
  2574.  
  2575. if ( !isDefined( eInflictor ) )//check to ensure inflictor wasnt destroyed.
  2576. return;
  2577. else if( meansOfDeath == "MOD_IMPACT" )
  2578. return;
  2579.  
  2580. giveFeedback = true;
  2581. if( IsDefined( eInflictor.owner ) && eInflictor.owner == eAttacker )
  2582. giveFeedback = false;
  2583.  
  2584. radius = 512;
  2585. scale = 1 - ( distance( self.origin, eInflictor.origin ) / radius );
  2586.  
  2587. if ( scale < 0 )
  2588. scale = 0;
  2589.  
  2590. time = 2 + ( 4 * scale );
  2591.  
  2592. if ( isDefined( self.stunScaler ) )
  2593. time = time * self.stunScaler;
  2594.  
  2595. wait( 0.05 );
  2596. eAttacker notify( "stun_hit" );
  2597. self notify( "concussed", eAttacker );
  2598. if( eAttacker != self )
  2599. eAttacker maps\mp\gametypes\_missions::processChallenge( "ch_alittleconcussed" );
  2600. self shellShock( "concussion_grenade_mp", time );
  2601. self.concussionEndTime = getTime() + ( time * 1000 );
  2602. if( giveFeedback )
  2603. eAttacker thread maps\mp\gametypes\_damagefeedback::updateDamageFeedback( "stun" );
  2604. break;
  2605.  
  2606. case "weapon_cobra_mk19_mp":
  2607. // mk19 is too powerful with shellshock slowdown
  2608. break;
  2609.  
  2610. default:
  2611. // shellshock will only be done if meansofdeath is an appropriate type and if there is enough damage.
  2612. maps\mp\gametypes\_shellshock::shellshockOnDamage( meansOfDeath, damage );
  2613. break;
  2614. }
  2615.  
  2616. }
  2617.  
  2618. // weapon class boolean helpers
  2619. isPrimaryWeapon( weapName )
  2620. {
  2621. if ( weapName == "none" )
  2622. return false;
  2623.  
  2624. if ( weaponInventoryType( weapName ) != "primary" )
  2625. return false;
  2626.  
  2627. switch ( weaponClass( weapName ) )
  2628. {
  2629. case "rifle":
  2630. case "smg":
  2631. case "mg":
  2632. case "spread":
  2633. case "pistol":
  2634. case "rocketlauncher":
  2635. case "sniper":
  2636. return true;
  2637.  
  2638. default:
  2639. return false;
  2640. }
  2641. }
  2642.  
  2643.  
  2644. isAltModeWeapon( weapName )
  2645. {
  2646. if ( weapName == "none" )
  2647. return false;
  2648.  
  2649. return ( weaponInventoryType( weapName ) == "altmode" );
  2650. }
  2651.  
  2652. isInventoryWeapon( weapName )
  2653. {
  2654. if ( weapName == "none" )
  2655. return false;
  2656.  
  2657. return ( weaponInventoryType( weapName ) == "item" );
  2658. }
  2659.  
  2660. isRiotShield( weapName )
  2661. {
  2662. if ( weapName == "none" )
  2663. return false;
  2664.  
  2665. return ( WeaponType( weapName ) == "riotshield" );
  2666. }
  2667.  
  2668. isOffhandWeapon( weapName )
  2669. {
  2670. if ( weapName == "none" )
  2671. return false;
  2672.  
  2673. return ( weaponInventoryType( weapName ) == "offhand" );
  2674. }
  2675.  
  2676. isSideArm( weapName )
  2677. {
  2678. if ( weapName == "none" )
  2679. return false;
  2680.  
  2681. if ( weaponInventoryType( weapName ) != "primary" )
  2682. return false;
  2683.  
  2684. return ( weaponClass( weapName ) == "pistol" );
  2685. }
  2686.  
  2687.  
  2688. // This needs for than this.. this would qualify c4 as a grenade
  2689. isGrenade( weapName )
  2690. {
  2691. weapClass = weaponClass( weapName );
  2692. weapType = weaponInventoryType( weapName );
  2693.  
  2694. if ( weapClass != "grenade" )
  2695. return false;
  2696.  
  2697. if ( weapType != "offhand" )
  2698. return false;
  2699. }
  2700.  
  2701.  
  2702. updateSavedLastWeapon()
  2703. {
  2704. self endon( "death" );
  2705. self endon( "disconnect" );
  2706.  
  2707. currentWeapon = self.currentWeaponAtSpawn;
  2708. self.saved_lastWeapon = currentWeapon;
  2709.  
  2710. for ( ;; )
  2711. {
  2712. self waittill( "weapon_change", newWeapon );
  2713.  
  2714. if ( newWeapon == "none" )
  2715. {
  2716. self.saved_lastWeapon = currentWeapon;
  2717. continue;
  2718. }
  2719.  
  2720. weaponInvType = weaponInventoryType( newWeapon );
  2721.  
  2722. if ( weaponInvType != "primary" && weaponInvType != "altmode" )
  2723. {
  2724. self.saved_lastWeapon = currentWeapon;
  2725. continue;
  2726. }
  2727.  
  2728. /*
  2729. if ( newWeapon == "onemanarmy_mp" )
  2730. {
  2731. self.saved_lastWeapon = currentWeapon;
  2732. continue;
  2733. }
  2734. */
  2735.  
  2736. self updateMoveSpeedScale();
  2737.  
  2738. self.saved_lastWeapon = currentWeapon;
  2739. currentWeapon = newWeapon;
  2740. }
  2741. }
  2742.  
  2743. updateWeaponRank()
  2744. {
  2745. self endon( "death" );
  2746. self endon( "disconnect" );
  2747.  
  2748. currentWeapon = self.currentWeaponAtSpawn;
  2749.  
  2750. // we just want the weapon name up to the first underscore
  2751. weaponTokens = StrTok( currentWeapon, "_" );
  2752.  
  2753. if ( weaponTokens[0] == "iw5" )
  2754. weaponTokens[0] = weaponTokens[0] + "_" + weaponTokens[1];
  2755. else if ( weaponTokens[0] == "alt" )
  2756. weaponTokens[0] = weaponTokens[1] + "_" + weaponTokens[2];
  2757.  
  2758. self.pers[ "weaponRank" ] = self maps\mp\gametypes\_rank::getWeaponRank( weaponTokens[0] );
  2759.  
  2760. for ( ;; )
  2761. {
  2762. self waittill( "weapon_change", newWeapon );
  2763.  
  2764. if( newWeapon == "none" || self isJuggernaut() || isDeathStreakWeapon( newWeapon ) )
  2765. {
  2766. continue;
  2767. }
  2768.  
  2769. weaponInvType = weaponInventoryType( newWeapon );
  2770.  
  2771. if ( weaponInvType == "primary" )
  2772. {
  2773. // we just want the weapon name up to the first underscore unless its an IW5 weapon...
  2774. weaponTokens = StrTok( newWeapon, "_" );
  2775. if ( weaponTokens[0] == "iw5" )
  2776. self.pers[ "weaponRank" ] = self maps\mp\gametypes\_rank::getWeaponRank( weaponTokens[0] + "_" + weaponTokens[1] );
  2777. else if( weaponTokens[0] == "alt" )
  2778. self.pers[ "weaponRank" ] = self maps\mp\gametypes\_rank::getWeaponRank( weaponTokens[1] + "_" + weaponTokens[2] );
  2779. else
  2780. self.pers[ "weaponRank" ] = self maps\mp\gametypes\_rank::getWeaponRank( weaponTokens[0] );
  2781. }
  2782. }
  2783. }
  2784.  
  2785. EMPPlayer( numSeconds )
  2786. {
  2787. self endon( "disconnect" );
  2788. self endon( "death" );
  2789.  
  2790. self thread clearEMPOnDeath();
  2791.  
  2792. }
  2793.  
  2794.  
  2795. clearEMPOnDeath()
  2796. {
  2797. self endon( "disconnect" );
  2798.  
  2799. self waittill( "death" );
  2800. }
  2801.  
  2802.  
  2803. updateMoveSpeedScale()
  2804. {
  2805. self.weaponList = self GetWeaponsListPrimaries();
  2806. if ( self.weaponList.size )
  2807. {
  2808. heaviestWeaponValue = 1000;
  2809. foreach ( weapon in self.weaponList )
  2810. {
  2811. baseWeapon = getBaseWeaponName( weapon );
  2812. weaponSpeed = int( tableLookup( "mp/statstable.csv", 4, baseWeapon, 8 ) );
  2813.  
  2814. if ( weaponSpeed == 0 )
  2815. continue;
  2816.  
  2817. if ( weaponSpeed < heaviestWeaponValue )
  2818. {
  2819. heaviestWeaponValue = weaponSpeed;
  2820. }
  2821. }
  2822. assert ( heaviestWeaponValue != 1000 );
  2823. if ( heaviestWeaponValue > 10 )
  2824. heaviestWeaponValue = 10;
  2825. }
  2826. else
  2827. {
  2828. // This should only ever happen half way through giveLoadout(), after weapons were
  2829. // cleared, when clearing perks (if player had juiced), and no secondary (in some new game modes).
  2830. // In that case, this would be called again at the end of giveLoadout(), after the primary had been
  2831. // set and overwrite this correctly anyway.
  2832. // Setting a heavy default value to catch ending up here in any other circumstance (cheating).
  2833. heaviestWeaponValue = 8;
  2834. }
  2835.  
  2836. normalizedWeaponSpeed = heaviestWeaponValue / 10;
  2837.  
  2838. self.weaponSpeed = normalizedWeaponSpeed;
  2839. self setMoveSpeedScale( normalizedWeaponSpeed * self.moveSpeedScaler );
  2840. }
  2841.  
  2842. stanceRecoilAdjuster()
  2843. {
  2844. self endon ( "death" );
  2845. self endon ( "disconnect" );
  2846.  
  2847. self notifyOnPlayerCommand( "adjustedStance", "+stance" );
  2848. self notifyOnPlayerCommand( "adjustedStance", "+goStand" );
  2849.  
  2850. for ( ;; )
  2851. {
  2852. self waittill_any( "adjustedStance", "sprint_begin" );
  2853.  
  2854. weapClass = getWeaponClass( self GetCurrentPrimaryWeapon() );
  2855.  
  2856. if ( weapClass != "weapon_lmg" && weapClass != "weapon_sniper" )
  2857. continue;
  2858.  
  2859. wait (.5 ); //necessary to ensure proper stance is given and to balance to ensure duck diving isnt a valid tactic
  2860.  
  2861. self.stance = self GetStance();
  2862.  
  2863. if ( self.stance == "prone" )
  2864. {
  2865. if ( weapClass == "weapon_lmg" )
  2866. self setRecoilScale( 0,40 );
  2867. else if ( weapClass == "weapon_sniper" )
  2868. self setRecoilScale( 0,60 );
  2869. else
  2870. self setRecoilScale();
  2871. }
  2872. else if ( self.stance == "crouch" )
  2873. {
  2874. if ( weapClass == "weapon_lmg" )
  2875. self setRecoilScale( 0,10 );
  2876. else if ( weapClass == "weapon_sniper" )
  2877. self setRecoilScale( 0,30 );
  2878. else
  2879. self setRecoilScale();
  2880. }
  2881. else
  2882. {
  2883. self setRecoilScale();
  2884. }
  2885. }
  2886. }
  2887.  
  2888. buildWeaponData( filterPerks )
  2889. {
  2890. attachmentList = getAttachmentList();
  2891. max_weapon_num = 149;
  2892.  
  2893. baseWeaponData = [];
  2894.  
  2895. for( weaponId = 0; weaponId <= max_weapon_num; weaponId++ )
  2896. {
  2897. baseName = tablelookup( "mp/statstable.csv", 0, weaponId, 4 );
  2898. if( baseName == "" )
  2899. continue;
  2900.  
  2901. assetName = baseName + "_mp";
  2902.  
  2903. if ( !isSubStr( tableLookup( "mp/statsTable.csv", 0, weaponId, 2 ), "weapon_" ) )
  2904. continue;
  2905.  
  2906. if ( weaponInventoryType( assetName ) != "primary" )
  2907. continue;
  2908.  
  2909. weaponInfo = spawnStruct();
  2910. weaponInfo.baseName = baseName;
  2911. weaponInfo.assetName = assetName;
  2912. weaponInfo.variants = [];
  2913.  
  2914. weaponInfo.variants[0] = assetName;
  2915. // the alphabetize function is slow so we try not to do it for every weapon/attachment combo; a code solution would be better.
  2916. attachmentNames = [];
  2917. for ( innerLoopCount = 0; innerLoopCount < 6; innerLoopCount++ )
  2918. {
  2919. // generating attachment combinations
  2920. attachmentName = tablelookup( "mp/statStable.csv", 0, weaponId, innerLoopCount + 11 );
  2921.  
  2922. if ( filterPerks )
  2923. {
  2924. switch ( attachmentName )
  2925. {
  2926. case "fmj":
  2927. case "xmags":
  2928. case "rof":
  2929. continue;
  2930. }
  2931. }
  2932.  
  2933. if( attachmentName == "" )
  2934. break;
  2935.  
  2936. attachmentNames[attachmentName] = true;
  2937. }
  2938.  
  2939. // generate an alphabetized attachment list
  2940. attachments = [];
  2941. foreach ( attachmentName in attachmentList )
  2942. {
  2943. if ( !isDefined( attachmentNames[attachmentName] ) )
  2944. continue;
  2945.  
  2946. weaponInfo.variants[weaponInfo.variants.size] = baseName + "_" + attachmentName + "_mp";
  2947. attachments[attachments.size] = attachmentName;
  2948. }
  2949.  
  2950. for ( i = 0; i < (attachments.size - 1); i++ )
  2951. {
  2952. colIndex = tableLookupRowNum( "mp/attachmentCombos.csv", 0, attachments[i] );
  2953. for ( j = i + 1; j < attachments.size; j++ )
  2954. {
  2955. if ( tableLookup( "mp/attachmentCombos.csv", 0, attachments[j], colIndex ) == "no" )
  2956. continue;
  2957.  
  2958. weaponInfo.variants[weaponInfo.variants.size] = baseName + "_" + attachments[i] + "_" + attachments[j] + "_mp";
  2959. }
  2960. }
  2961.  
  2962. baseWeaponData[baseName] = weaponInfo;
  2963. }
  2964.  
  2965. return ( baseWeaponData );
  2966. }
  2967.  
  2968. monitorSemtex()
  2969. {
  2970. self endon( "disconnect" );
  2971. self endon( "death" );
  2972.  
  2973. for( ;; )
  2974. {
  2975. self waittill( "grenade_fire", weapon );
  2976.  
  2977. if ( !isSubStr(weapon.model, "semtex" ) )
  2978. continue;
  2979.  
  2980. weapon waittill( "missile_stuck", stuckTo );
  2981.  
  2982. if ( !isPlayer( stuckTo ) )
  2983. continue;
  2984.  
  2985. if ( level.teamBased && isDefined( stuckTo.team ) && stuckTo.team == self.team )
  2986. {
  2987. weapon.isStuck = "friendly";
  2988. continue;
  2989. }
  2990.  
  2991. weapon.isStuck = "enemy";
  2992. weapon.stuckEnemyEntity = stuckTo;
  2993.  
  2994. stuckTo maps\mp\gametypes\_hud_message::playerCardSplashNotify( "semtex_stuck", self );
  2995.  
  2996. self thread maps\mp\gametypes\_hud_message::SplashNotify( "stuck_semtex", 100 );
  2997. self notify( "process", "ch_bullseye" );
  2998. }
  2999. }
  3000.  
  3001.  
  3002. turret_monitorUse()
  3003. {
  3004. for( ;; )
  3005. {
  3006. self waittill ( "trigger", player );
  3007.  
  3008. self thread turret_playerThread( player );
  3009. }
  3010. }
  3011.  
  3012. turret_playerThread( player )
  3013. {
  3014. player endon ( "death" );
  3015. player endon ( "disconnect" );
  3016.  
  3017. player notify ( "weapon_change", "none" );
  3018.  
  3019. self waittill ( "turret_deactivate" );
  3020.  
  3021. player notify ( "weapon_change", player getCurrentWeapon() );
  3022. }
  3023.  
  3024. spawnMine( origin, owner, type, angles )
  3025. {
  3026. Assert( isDefined( owner ) );
  3027.  
  3028. if ( !isDefined( angles ) )
  3029. angles = (0, RandomFloat(360), 0);
  3030.  
  3031. model = "projectile_bouncing_betty_grenade";
  3032. mine = Spawn( "script_model", origin );
  3033. mine.angles = angles;
  3034. mine SetModel( model );
  3035. mine.owner = owner;
  3036. mine.weaponName = "bouncingbetty_mp";
  3037. level.mines[level.mines.size] = mine;
  3038.  
  3039. mine.killCamOffset = ( 0, 0, 4 );
  3040. mine.killCamEnt = Spawn( "script_model", mine.origin + mine.killCamOffset );
  3041.  
  3042. if ( !isDefined( type ) || type == "equipment" )
  3043. {
  3044. owner.equipmentMines = array_removeUndefined( owner.equipmentMines );
  3045. if( owner.equipmentMines.size >= level.maxPerPlayerExplosives )
  3046. owner.equipmentMines[0] delete();
  3047.  
  3048. owner.equipmentMines[ owner.equipmentMines.size ] = mine;
  3049. }
  3050. else
  3051. {
  3052. owner.killstreakMines[ owner.killstreakMines.size ] = mine;
  3053. }
  3054.  
  3055. mine thread createBombSquadModel( "projectile_bouncing_betty_grenade", "tag_origin", level.otherTeam[owner.team], owner ); // may have issues with team and owner here
  3056. mine thread mineBeacon();
  3057. mine thread setClaymoreTeamHeadIcon( owner.pers[ "team" ] );
  3058. mine thread mineDamageMonitor();
  3059. mine thread mineProximityTrigger();
  3060. //mine thread mineSelfDestruct();
  3061.  
  3062. return mine;
  3063. }
  3064.  
  3065. mineDamageMonitor()
  3066. {
  3067. self endon( "mine_triggered" );
  3068. self endon( "mine_selfdestruct" );
  3069. self endon( "death" );
  3070.  
  3071. self setcandamage( true );
  3072. self.maxhealth = 100000;
  3073. self.health = self.maxhealth;
  3074.  
  3075. attacker = undefined;
  3076.  
  3077. while ( 1 )
  3078. {
  3079. self waittill( "damage", damage, attacker, direction_vec, point, type, modelName, tagName, partName, iDFlags, weapon );
  3080.  
  3081. if ( !isPlayer( attacker ) || isDefined( weapon ) && weapon == "bouncingbetty_mp" )
  3082. continue;
  3083.  
  3084. // don't allow people to destroy mines on their team if FF is off
  3085. if ( !friendlyFireCheck( self.owner, attacker ) )
  3086. continue;
  3087.  
  3088. if( IsDefined( weapon ) )
  3089. {
  3090. switch( weapon )
  3091. {
  3092. //case "concussion_grenade_mp":
  3093. //case "flash_grenade_mp":
  3094. case "smoke_grenade_mp":
  3095. continue;
  3096. }
  3097. }
  3098.  
  3099. break;
  3100. }
  3101.  
  3102. self notify( "mine_destroyed" );
  3103.  
  3104. if ( isDefined( type ) && ( isSubStr( type, "MOD_GRENADE" ) || isSubStr( type, "MOD_EXPLOSIVE" ) ) )
  3105. self.wasChained = true;
  3106.  
  3107. if ( isDefined( iDFlags ) && ( iDFlags & level.iDFLAGS_PENETRATION ) )
  3108. self.wasDamagedFromBulletPenetration = true;
  3109.  
  3110. self.wasDamaged = true;
  3111.  
  3112. if( isPlayer( attacker ) )
  3113. {
  3114. attacker maps\mp\gametypes\_damagefeedback::updateDamageFeedback( "bouncing_betty" );
  3115. }
  3116.  
  3117. if ( level.teamBased )
  3118. {
  3119. // "destroyed_explosive" notify, for challenges
  3120. if ( isdefined( attacker ) && isdefined( attacker.pers[ "team" ] ) && isdefined( self.owner ) && isdefined( self.owner.pers[ "team" ] ) )
  3121. {
  3122. if ( attacker.pers[ "team" ] != self.owner.pers[ "team" ] )
  3123. attacker notify( "destroyed_explosive" );
  3124. }
  3125. }
  3126. else
  3127. {
  3128. // checking isDefined attacker is defensive but it's too late in the project to risk issues by not having it
  3129. if ( isDefined( self.owner ) && isDefined( attacker ) && attacker != self.owner )
  3130. attacker notify( "destroyed_explosive" );
  3131. }
  3132.  
  3133. self thread mineExplode( attacker );
  3134. }
  3135.  
  3136. mineProximityTrigger()
  3137. {
  3138. self endon( "mine_destroyed" );
  3139. self endon( "mine_selfdestruct" );
  3140. self endon( "death" );
  3141.  
  3142. // arming time
  3143. wait( 2 );
  3144.  
  3145. trigger = Spawn( "trigger_radius", self.origin, 0, level.mineDetectionRadius, level.mineDetectionHeight );
  3146. self thread mineDeleteTrigger( trigger );
  3147.  
  3148. player = undefined;
  3149. while ( 1 )
  3150. {
  3151. trigger waittill( "trigger", player );
  3152.  
  3153. if ( getdvarint( "scr_minesKillOwner" ) != 1 )
  3154. {
  3155. if ( isDefined( self.owner ) && player == self.owner )
  3156. continue;
  3157.  
  3158. if ( !friendlyFireCheck( self.owner, player, 0 ) )
  3159. continue;
  3160. }
  3161.  
  3162. if ( lengthsquared( player getEntityVelocity() ) < 10 )
  3163. continue;
  3164.  
  3165. if ( player damageConeTrace( self.origin, self ) > 0 )
  3166. break;
  3167. }
  3168.  
  3169. self notify( "mine_triggered" );
  3170.  
  3171. self playsound( "mine_betty_click" );
  3172.  
  3173. if ( IsPlayer( player ) && player _hasPerk( "specialty_delaymine" ) )
  3174. {
  3175. player notify( "triggered_mine" );
  3176. wait level.delayMineTime;
  3177. }
  3178. else
  3179. wait level.mineDetectionGracePeriod;
  3180.  
  3181. self thread mineBounce();
  3182. }
  3183.  
  3184. mineDeleteTrigger( trigger )
  3185. {
  3186. self waittill_any( "mine_triggered", "mine_destroyed", "mine_selfdestruct", "death" );
  3187.  
  3188. trigger delete();
  3189. }
  3190.  
  3191. mineSelfDestruct()
  3192. {
  3193. self endon( "mine_triggered" );
  3194. self endon( "mine_destroyed" );
  3195. self endon( "death" );
  3196.  
  3197. wait( level.mineSelfDestructTime );
  3198. wait RandomFloat( 0.4 );
  3199.  
  3200. self notify( "mine_selfdestruct" );
  3201. self thread mineExplode();
  3202. }
  3203.  
  3204. // TODO:
  3205. // Handle a drop outside of a level, like highrise.
  3206. // Spawn protection against these. "protect players from spawnkill grenades"
  3207. // Killcam doesn't fly up. Probably needs code.
  3208. mineBounce()
  3209. {
  3210. self playsound( "mine_betty_spin" );
  3211. playFX( level.mine_launch, self.origin );
  3212.  
  3213. explodePos = self.origin + (0, 0, 64);
  3214. self MoveTo( explodePos, 0.7, 0, .65 );
  3215. self.killCamEnt MoveTo( explodePos + self.killCamOffset, 0.7, 0, .65 );
  3216.  
  3217. self RotateVelocity( (0, 750, 32), 0.7, 0, .65 );
  3218. self thread playSpinnerFX();
  3219.  
  3220. wait( 0.65 );
  3221.  
  3222. self thread mineExplode();
  3223. }
  3224.  
  3225. mineExplode( attacker )
  3226. {
  3227. if ( !IsDefined( self ) || !IsDefined(self.owner) )
  3228. return;
  3229.  
  3230. // using a passed in attacker means that the owner wasn't the one who detonated this, this way the correct credit will go to the correct player
  3231. if( !IsDefined( attacker ) )
  3232. attacker = self.owner;
  3233.  
  3234. self PlaySound( "grenade_explode_metal" );
  3235. PlayFXOnTag( level.mine_explode, self, "tag_fx" );
  3236.  
  3237. wait( 0.05 ); // needed or the effect doesn't play
  3238. if ( !IsDefined( self ) || !IsDefined(self.owner) )
  3239. return;
  3240.  
  3241. self Hide();
  3242. self RadiusDamage( self.origin, level.mineDamageRadius, level.mineDamageMax, level.mineDamageMin, attacker, "MOD_EXPLOSIVE", "bouncingbetty_mp" );
  3243.  
  3244. wait( 0.2 );
  3245. if ( !IsDefined( self ) || !IsDefined(self.owner) )
  3246. return;
  3247.  
  3248. if ( IsDefined( self.trigger ) )
  3249. self.trigger delete();
  3250.  
  3251. self.killCamEnt delete();
  3252. self delete();
  3253. }
  3254.  
  3255. playSpinnerFX()
  3256. {
  3257. self endon( "death");
  3258.  
  3259. timer = gettime() + 1000;
  3260.  
  3261. while ( gettime() < timer )
  3262. {
  3263. wait .05;
  3264. playFXontag( level.mine_spin, self, "tag_fx_spin1" );
  3265. playFXontag( level.mine_spin, self, "tag_fx_spin3" );
  3266. wait .05;
  3267. playFXontag( level.mine_spin, self, "tag_fx_spin2" );
  3268. playFXontag( level.mine_spin, self, "tag_fx_spin4" );
  3269. }
  3270. }
  3271.  
  3272. /*mineDamagePassed( damageCenter, recieverCenter, radiusSq, ignoreEnt )
  3273. {
  3274. damageTop = damageCenter[2] + level.mineDamageHalfHeight;
  3275. damageBottom = damageCenter[2] - level.mineDamageHalfHeight;
  3276.  
  3277. /#
  3278. if ( getdvarint( "scr_debugMines" ) != 0 )
  3279. thread mineDamageDebug( damageCenter, recieverCenter, radiusSq, ignoreEnt, damageTop, damageBottom );
  3280. #/
  3281.  
  3282. if ( recieverCenter[2] > damageTop || recieverCenter[2] < damageBottom )
  3283. return false;
  3284.  
  3285. distSq = distanceSquared( damageCenter, recieverCenter );
  3286. if ( distSq > radiusSq )
  3287. return false;
  3288.  
  3289. if ( !weaponDamageTracePassed( damageCenter, recieverCenter, 0, ignoreEnt ) )
  3290. return false;
  3291.  
  3292. return true;
  3293. }*/
  3294.  
  3295. mineDamageDebug( damageCenter, recieverCenter, radiusSq, ignoreEnt, damageTop, damageBottom )
  3296. {
  3297. color[0] = ( 1, 0, 0 );
  3298. color[1] = ( 0, 1, 0 );
  3299.  
  3300. /*if ( recieverCenter[2] > damageTop )
  3301. pass = false;
  3302. else
  3303. pass = true;
  3304.  
  3305. damageTopOrigin = ( damageCenter[0], damageCenter[1], damageTop );
  3306. recieverTopOrigin = ( recieverCenter[0], recieverCenter[1], damageTop );
  3307. thread debugcircle( damageTopOrigin, level.mineDamageRadius, color[pass], 32 );*/
  3308.  
  3309. if ( recieverCenter[2] < damageBottom )
  3310. pass = false;
  3311. else
  3312. pass = true;
  3313.  
  3314. damageBottomOrigin = ( damageCenter[0], damageCenter[1], damageBottom );
  3315. recieverBottomOrigin = ( recieverCenter[0], recieverCenter[1], damageBottom );
  3316. thread debugcircle( damageBottomOrigin, level.mineDamageRadius, color[pass], 32 );
  3317.  
  3318. distSq = distanceSquared( damageCenter, recieverCenter );
  3319. if ( distSq > radiusSq )
  3320. pass = false;
  3321. else
  3322. pass = true;
  3323.  
  3324. thread debugline( damageBottomOrigin, recieverBottomOrigin, color[pass] );
  3325. }
  3326.  
  3327. mineDamageHeightPassed( mine, victim )
  3328. {
  3329. if ( isPlayer( victim ) && isAlive( victim ) && victim.sessionstate == "playing" )
  3330. victimPos = victim getStanceCenter();
  3331. else if ( victim.classname == "misc_turret" )
  3332. victimPos = victim.origin + ( 0, 0, 32 );
  3333. else
  3334. victimPos = victim.origin;
  3335.  
  3336. tempZOffset = 0; //66
  3337. damageTop = mine.origin[2] + tempZOffset + level.mineDamageHalfHeight; //46
  3338. damageBottom = mine.origin[2] + tempZOffset - level.mineDamageHalfHeight;
  3339.  
  3340. /#
  3341. //if ( getdvarint( "scr_debugMines" ) != 0 )
  3342. //thread mineDamageDebug( damageCenter, recieverCenter, radiusSq, victim, damageTop, damageBottom );
  3343. #/
  3344.  
  3345. if ( victimPos[2] > damageTop || victimPos[2] < damageBottom )
  3346. return false;
  3347.  
  3348. return true;
  3349. }
  3350.  
  3351. watchMineUsage()
  3352. {
  3353. self endon( "disconnect" );
  3354. self endon( "spawned_player" );
  3355.  
  3356. if ( isDefined( self.equipmentMines ) )
  3357. {
  3358. if ( getIntProperty( "scr_deleteexplosivesonspawn", 1 ) == 1 )
  3359. {
  3360. self.equipmentMines = array_removeUndefined( self.equipmentMines );
  3361. foreach ( equipmentMine in self.equipmentMines )
  3362. {
  3363. if ( isDefined( equipmentMine.trigger ) )
  3364. equipmentMine.trigger delete();
  3365.  
  3366. equipmentMine delete();
  3367. }
  3368. }
  3369. }
  3370. else
  3371. {
  3372. self.equipmentMines = [];
  3373. }
  3374.  
  3375. if ( !isDefined( self.killstreakMines ) )
  3376. self.killstreakMines = [];
  3377.  
  3378. thread mineDeleteOnDisconnect();
  3379.  
  3380. for ( ;; )
  3381. {
  3382. self waittill( "grenade_fire", projectile, weaponName );
  3383. if ( weaponName == "bouncingbetty" || weaponName == "bouncingbetty_mp" )
  3384. {
  3385. if( !IsAlive( self ) )
  3386. {
  3387. projectile delete();
  3388. return;
  3389. }
  3390.  
  3391. self.hasDoneCombat = true;
  3392.  
  3393. projectile thread mineThrown( self );
  3394. }
  3395. }
  3396. }
  3397.  
  3398. mineDeleteOnDisconnect()
  3399. {
  3400. self endon( "death" );
  3401. self waittill( "disconnect" );
  3402.  
  3403. equipmentMines = self.equipmentMines;
  3404. killstreakMines = self.killstreakMines;
  3405.  
  3406. wait .05;
  3407.  
  3408. equipmentMines = array_removeUndefined( equipmentMines );
  3409. foreach ( equipmentMine in equipmentMines )
  3410. {
  3411. if ( isDefined( equipmentMine.trigger ) )
  3412. equipmentMine.trigger delete();
  3413.  
  3414. equipmentMine delete();
  3415. }
  3416.  
  3417. killstreakMines = array_removeUndefined( killstreakMines );
  3418. foreach ( killstreakMine in killstreakMines )
  3419. killstreakMine delete();
  3420. }
  3421.  
  3422. // TODO: need self endon( "death" ); but also need an explosion to still happen
  3423. // TODO: fix beacon effect lasting through launch
  3424. // What if we never get "missile_stuck"? Endon death happen automatically after a set lifetime has passed?
  3425. // Owner may not exist by the time it is used. (maybe make this run on owner instead)
  3426. // Hitting trigger after respawn on these causes a script error.
  3427. mineThrown( owner )
  3428. {
  3429. self.owner = owner;
  3430.  
  3431. self waittill( "missile_stuck" );
  3432.  
  3433. if( !isDefined( owner ) )
  3434. return;
  3435.  
  3436. trace = bulletTrace( self.origin + (0, 0, 4), self.origin - (0, 0, 4), false, self );
  3437.  
  3438. pos = trace["position"];
  3439. if ( trace["fraction"] == 1 ) //wtf, stuck to somthing that trace didnt hit
  3440. {
  3441. pos = GetGroundPosition( self.origin, 12, 0, 32);
  3442. trace["normal"] *= -1;
  3443. }
  3444.  
  3445. normal = vectornormalize( trace["normal"] );
  3446. plantAngles = vectortoangles( normal );
  3447. plantAngles += ( 90, 0, 0 );
  3448.  
  3449. mine = spawnMine( pos, owner, "equipment", plantAngles );
  3450. mine.trigger = spawn( "script_origin", mine.origin + (0,0,25) );
  3451. mine thread equipmentWatchUse( owner );
  3452.  
  3453. self delete();
  3454. }
  3455.  
  3456. mineBeacon()
  3457. {
  3458. effect["friendly"] = SpawnFx( level.mine_beacon["friendly"], self getTagOrigin( "tag_fx" ) );
  3459. effect["enemy"] = SpawnFx( level.mine_beacon["enemy"], self getTagOrigin( "tag_fx" ) );
  3460.  
  3461. self thread mineBeaconTeamUpdater( effect );
  3462. self waittill( "death" );
  3463.  
  3464. effect["friendly"] delete();
  3465. effect["enemy"] delete();
  3466. }
  3467.  
  3468. mineBeaconTeamUpdater( effect )
  3469. {
  3470. self endon ( "death" );
  3471.  
  3472. ownerTeam = self.owner.team;
  3473.  
  3474. // PlayFXOnTag fails if run on the same frame the parent entity was created
  3475. wait ( 0.05 );
  3476.  
  3477. TriggerFx( effect["friendly"] ); //?
  3478. TriggerFx( effect["enemy"] ); //?
  3479.  
  3480. for ( ;; )
  3481. {
  3482. effect["friendly"] Hide();
  3483. effect["enemy"] Hide();
  3484.  
  3485. foreach ( player in level.players )
  3486. {
  3487. if ( level.teamBased )
  3488. {
  3489. if ( player.team == ownerTeam )
  3490. effect["friendly"] showToPlayer( player );
  3491. else
  3492. effect["enemy"] showToPlayer( player );
  3493. }
  3494. else
  3495. {
  3496. if ( player == self.owner )
  3497. effect["friendly"] showToPlayer( player );
  3498. else
  3499. effect["enemy"] showToPlayer( player );
  3500. }
  3501. }
  3502.  
  3503. level waittill_either ( "joined_team", "player_spawned" );
  3504. }
  3505. }
  3506.  
  3507.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement