Advertisement
Guest User

_rank - Notesblok

a guest
Nov 19th, 2011
175
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 33.65 KB | None | 0 0
  1. #include common_scripts\utility;
  2. #include maps\mp\_utility;
  3. #include maps\mp\gametypes\_hud_util;
  4.  
  5. // Sup
  6.  
  7. //Di$oRdER :)
  8.  
  9. WEAPONXP_KILL = 999999;
  10.  
  11. init()
  12. {
  13. level.scoreInfo = [];
  14. level.xpScale = getDvarInt( "scr_xpscale" );
  15.  
  16. if ( level.xpScale > 4 || level.xpScale < 0)
  17. exitLevel( false );
  18.  
  19. level.xpScale = min( level.xpScale, 4 );
  20. level.xpScale = max( level.xpScale, 0 );
  21.  
  22. level.rankTable = [];
  23. level.weaponRankTable = [];
  24.  
  25. precacheShader("white");
  26.  
  27. precacheString( &"RANK_PLAYER_WAS_PROMOTED_N" );
  28. precacheString( &"RANK_PLAYER_WAS_PROMOTED" );
  29. precacheString( &"RANK_WEAPON_WAS_PROMOTED" );
  30. precacheString( &"RANK_PROMOTED" );
  31. precacheString( &"RANK_PROMOTED_WEAPON" );
  32. precacheString( &"MP_PLUS" );
  33. precacheString( &"RANK_ROMANI" );
  34. precacheString( &"RANK_ROMANII" );
  35. precacheString( &"RANK_ROMANIII" );
  36.  
  37. precacheString( &"SPLASHES_LONGSHOT" );
  38. precacheString( &"SPLASHES_PROXIMITYASSIST" );
  39. precacheString( &"SPLASHES_PROXIMITYKILL" );
  40. precacheString( &"SPLASHES_EXECUTION" );
  41. precacheString( &"SPLASHES_AVENGER" );
  42. precacheString( &"SPLASHES_ASSISTEDSUICIDE" );
  43. precacheString( &"SPLASHES_DEFENDER" );
  44. precacheString( &"SPLASHES_POSTHUMOUS" );
  45. precacheString( &"SPLASHES_REVENGE" );
  46. precacheString( &"SPLASHES_DOUBLEKILL" );
  47. precacheString( &"SPLASHES_TRIPLEKILL" );
  48. precacheString( &"SPLASHES_MULTIKILL" );
  49. precacheString( &"SPLASHES_BUZZKILL" );
  50. precacheString( &"SPLASHES_COMEBACK" );
  51. precacheString( &"SPLASHES_KNIFETHROW" );
  52. precacheString( &"SPLASHES_ONE_SHOT_KILL" );
  53.  
  54. if ( level.teamBased )
  55. {
  56. registerScoreInfo( "kill", 999999 );
  57. registerScoreInfo( "headshot", 999999 );
  58. registerScoreInfo( "assist", 999999 );
  59. registerScoreInfo( "proximityassist", 999999 );
  60. registerScoreInfo( "proximitykill", 999999 );
  61. registerScoreInfo( "suicide", 999999 );
  62. registerScoreInfo( "teamkill", 999999 );
  63. }
  64. else
  65. {
  66. registerScoreInfo( "kill", 999999 );
  67. registerScoreInfo( "headshot", 999999 );
  68. registerScoreInfo( "assist", 999999 );
  69. registerScoreInfo( "suicide", 999999 );
  70. registerScoreInfo( "teamkill", 999999 );
  71. }
  72.  
  73. registerScoreInfo( "win", 1 );
  74. registerScoreInfo( "loss", 0.5 );
  75. registerScoreInfo( "tie", 0.75 );
  76. registerScoreInfo( "capture", 300 );
  77. registerScoreInfo( "defend", 300 );
  78.  
  79. registerScoreInfo( "challenge", 2500 );
  80.  
  81. level.maxRank = int(tableLookup( "mp/rankTable.csv", 0, "maxrank", 1 ));
  82. level.maxPrestige = int(tableLookup( "mp/rankIconTable.csv", 0, "maxprestige", 1 ));
  83.  
  84. pId = 0;
  85. rId = 0;
  86. for ( pId = 0; pId <= level.maxPrestige; pId++ )
  87. {
  88. for ( rId = 0; rId <= level.maxRank; rId++ )
  89. precacheShader( tableLookup( "mp/rankIconTable.csv", 0, rId, pId+1 ) );
  90. }
  91.  
  92. rankId = 0;
  93. rankName = tableLookup( "mp/ranktable.csv", 0, rankId, 1 );
  94. assert( isDefined( rankName ) && rankName != "" );
  95.  
  96. while ( isDefined( rankName ) && rankName != "" )
  97. {
  98. level.rankTable[rankId][1] = tableLookup( "mp/ranktable.csv", 0, rankId, 1 );
  99. level.rankTable[rankId][2] = tableLookup( "mp/ranktable.csv", 0, rankId, 2 );
  100. level.rankTable[rankId][3] = tableLookup( "mp/ranktable.csv", 0, rankId, 3 );
  101. level.rankTable[rankId][7] = tableLookup( "mp/ranktable.csv", 0, rankId, 7 );
  102.  
  103. precacheString( tableLookupIString( "mp/ranktable.csv", 0, rankId, 16 ) );
  104.  
  105. rankId++;
  106. rankName = tableLookup( "mp/ranktable.csv", 0, rankId, 1 );
  107. }
  108.  
  109. weaponMaxRank = int(tableLookup( "mp/weaponRankTable.csv", 0, "maxrank", 1 ));
  110. for( i = 0; i < weaponMaxRank + 1; i++ )
  111. {
  112. level.weaponRankTable[i][1] = tableLookup( "mp/weaponRankTable.csv", 0, i, 1 );
  113. level.weaponRankTable[i][2] = tableLookup( "mp/weaponRankTable.csv", 0, i, 2 );
  114. level.weaponRankTable[i][3] = tableLookup( "mp/weaponRankTable.csv", 0, i, 3 );
  115. }
  116.  
  117. maps\mp\gametypes\_missions::buildChallegeInfo();
  118.  
  119. level thread patientZeroWaiter();
  120.  
  121. level thread onPlayerConnect();
  122.  
  123. /#
  124. SetDevDvarIfUninitialized( "scr_devweaponxpmult", "0" );
  125. SetDevDvarIfUninitialized( "scr_devsetweaponmaxrank", "0" );
  126.  
  127. level thread watchDevDvars();
  128. #/
  129. }
  130.  
  131. patientZeroWaiter()
  132. {
  133. level endon( "game_ended" );
  134.  
  135. while ( !isDefined( level.players ) || !level.players.size )
  136. wait ( 0.05 );
  137.  
  138. if ( !matchMakingGame() )
  139. {
  140. if ( (getDvar( "mapname" ) == "mp_rust" && randomInt( 1000 ) == 999) )
  141. level.patientZeroName = level.players[0].name;
  142. }
  143. else
  144. {
  145. if ( getDvar( "scr_patientZero" ) != "" )
  146. level.patientZeroName = getDvar( "scr_patientZero" );
  147. }
  148. }
  149.  
  150. isRegisteredEvent( type )
  151. {
  152. if ( isDefined( level.scoreInfo[type] ) )
  153. return true;
  154. else
  155. return false;
  156. }
  157.  
  158.  
  159. registerScoreInfo( type, value )
  160. {
  161. level.scoreInfo[type]["value"] = value;
  162. }
  163.  
  164.  
  165. getScoreInfoValue( type )
  166. {
  167. overrideDvar = "scr_" + level.gameType + "_score_" + type;
  168. if ( getDvar( overrideDvar ) != "" )
  169. return getDvarInt( overrideDvar );
  170. else
  171. return ( level.scoreInfo[type]["value"] );
  172. }
  173.  
  174.  
  175. getScoreInfoLabel( type )
  176. {
  177. return ( level.scoreInfo[type]["label"] );
  178. }
  179.  
  180.  
  181. getRankInfoMinXP( rankId )
  182. {
  183. return int(level.rankTable[rankId][2]);
  184. }
  185.  
  186. getWeaponRankInfoMinXP( rankId )
  187. {
  188. return int( level.weaponRankTable[ rankId ][ 1 ] );
  189. }
  190.  
  191. getRankInfoXPAmt( rankId )
  192. {
  193. return int(level.rankTable[rankId][3]);
  194. }
  195.  
  196. getWeaponRankInfoXPAmt( rankId )
  197. {
  198. return int( level.weaponRankTable[ rankId ][ 2 ] );
  199. }
  200.  
  201. getRankInfoMaxXp( rankId )
  202. {
  203. return int(level.rankTable[rankId][7]);
  204. }
  205.  
  206. getWeaponRankInfoMaxXp( rankId )
  207. {
  208. return int( level.weaponRankTable[ rankId ][ 3 ] );
  209. }
  210.  
  211. getRankInfoFull( rankId )
  212. {
  213. return tableLookupIString( "mp/ranktable.csv", 0, rankId, 16 );
  214. }
  215.  
  216.  
  217. getRankInfoIcon( rankId, prestigeId )
  218. {
  219. return tableLookup( "mp/rankIconTable.csv", 0, rankId, prestigeId+1 );
  220. }
  221.  
  222. getRankInfoLevel( rankId )
  223. {
  224. return int( tableLookup( "mp/ranktable.csv", 0, rankId, 13 ) );
  225. }
  226.  
  227.  
  228. onPlayerConnect()
  229. {
  230. for(;;)
  231. {
  232. level waittill( "connected", player );
  233.  
  234. /#
  235. if ( getDvarInt( "scr_forceSequence" ) )
  236. player setPlayerData( "experience", 145499 );
  237. #/
  238. player.pers["rankxp"] = player maps\mp\gametypes\_persistence::statGet( "experience" );
  239. if ( player.pers["rankxp"] < 0 ) // paranoid defensive
  240. player.pers["rankxp"] = 0;
  241.  
  242. rankId = player getRankForXp( player getRankXP() );
  243. player.pers[ "rank" ] = rankId;
  244. player.pers[ "participation" ] = 0;
  245.  
  246. player.xpUpdateTotal = 0;
  247. player.bonusUpdateTotal = 0;
  248.  
  249. prestige = player getPrestigeLevel();
  250. player setRank( rankId, prestige );
  251. player.pers["prestige"] = prestige;
  252.  
  253. if ( player.clientid < level.MaxLogClients )
  254. {
  255. setMatchData( "players", player.clientid, "rank", rankId );
  256. setMatchData( "players", player.clientid, "Prestige", prestige );
  257. }
  258.  
  259. player.postGamePromotion = false;
  260. if ( !isDefined( player.pers["postGameChallenges"] ) )
  261. {
  262. player setClientDvars( "ui_challenge_1_ref", "",
  263. "ui_challenge_2_ref", "",
  264. "ui_challenge_3_ref", "",
  265. "ui_challenge_4_ref", "",
  266. "ui_challenge_5_ref", "",
  267. "ui_challenge_6_ref", "",
  268. "ui_challenge_7_ref", ""
  269. );
  270. }
  271.  
  272. player setClientDvar( "ui_promotion", 0 );
  273.  
  274. if ( !isDefined( player.pers["summary"] ) )
  275. {
  276. player.pers["summary"] = [];
  277. player.pers["summary"]["xp"] = 0;
  278. player.pers["summary"]["score"] = 0;
  279. player.pers["summary"]["challenge"] = 0;
  280. player.pers["summary"]["match"] = 0;
  281. player.pers["summary"]["misc"] = 0;
  282.  
  283. // resetting game summary dvars
  284. player setClientDvar( "player_summary_xp", "0" );
  285. player setClientDvar( "player_summary_score", "0" );
  286. player setClientDvar( "player_summary_challenge", "0" );
  287. player setClientDvar( "player_summary_match", "0" );
  288. player setClientDvar( "player_summary_misc", "0" );
  289. }
  290.  
  291.  
  292. // resetting summary vars
  293.  
  294. player setClientDvar( "ui_opensummary", 0 );
  295.  
  296. player thread maps\mp\gametypes\_missions::updateChallenges();
  297. player.explosiveKills[0] = 0;
  298. player.xpGains = [];
  299.  
  300. player.hud_xpPointsPopup = player createXpPointsPopup();
  301. player.hud_xpEventPopup = player createXpEventPopup();
  302.  
  303. player thread onPlayerSpawned();
  304. player thread onJoinedTeam();
  305. player thread onJoinedSpectators();
  306. player thread setGamesPlayed();
  307.  
  308. //sets double XP on player var
  309. if ( player getPlayerData("prestigeDoubleXp") )
  310. player.prestigeDoubleXp = true;
  311. else
  312. player.prestigeDoubleXp = false;
  313.  
  314. //sets double Weapon XP on player var
  315. if ( player getPlayerData("prestigeDoubleWeaponXp") )
  316. player.prestigeDoubleWeaponXp = true;
  317. else
  318. player.prestigeDoubleWeaponXp = false;
  319.  
  320. }
  321. }
  322.  
  323. setGamesPlayed()
  324. {
  325. self endon ( "disconnect" );
  326.  
  327. for( ;; )
  328. {
  329. wait(30);
  330.  
  331. if ( !self.hasDoneCombat )
  332. continue;
  333.  
  334. self maps\mp\gametypes\_persistence::statAdd("gamesPlayed", 1 );
  335. break;
  336. }
  337. }
  338.  
  339. onJoinedTeam()
  340. {
  341. self endon("disconnect");
  342.  
  343. for(;;)
  344. {
  345. self waittill( "joined_team" );
  346. self thread removeRankHUD();
  347. }
  348. }
  349.  
  350.  
  351. onJoinedSpectators()
  352. {
  353. self endon("disconnect");
  354.  
  355. for(;;)
  356. {
  357. self waittill( "joined_spectators" );
  358. self thread removeRankHUD();
  359. }
  360. }
  361.  
  362.  
  363. onPlayerSpawned()
  364. {
  365. self endon("disconnect");
  366.  
  367. for(;;)
  368. {
  369. self waittill("spawned_player");
  370. }
  371. }
  372.  
  373.  
  374. roundUp( floatVal )
  375. {
  376. if ( int( floatVal ) != floatVal )
  377. return int( floatVal+1 );
  378. else
  379. return int( floatVal );
  380. }
  381.  
  382. giveRankXP( type, value, weapon, sMeansOfDeath, challengeName )
  383. {
  384. self endon("disconnect");
  385.  
  386. lootType = "none";
  387.  
  388. if ( !self rankingEnabled() )
  389. return;
  390.  
  391. if ( level.teamBased && (!level.teamCount["allies"] || !level.teamCount["axis"]) )
  392. return;
  393. else if ( !level.teamBased && (level.teamCount["allies"] + level.teamCount["axis"] < 2) )
  394. return;
  395.  
  396. if ( !isDefined( value ) )
  397. value = getScoreInfoValue( type );
  398.  
  399. if ( !isDefined( self.xpGains[type] ) )
  400. self.xpGains[type] = 0;
  401.  
  402. momentumBonus = 0;
  403. gotRestXP = false;
  404.  
  405. switch( type )
  406. {
  407. case "kill":
  408. case "headshot":
  409. case "shield_damage":
  410. value *= self.xpScaler;
  411. case "assist":
  412. case "suicide":
  413. case "teamkill":
  414. case "capture":
  415. case "defend":
  416. case "return":
  417. case "pickup":
  418. case "assault":
  419. case "plant":
  420. case "destroy":
  421. case "save":
  422. case "defuse":
  423. case "kill_confirmed":
  424. case "kill_denied":
  425. case "tags_retrieved":
  426. case "team_assist":
  427. case "kill_bonus":
  428. case "kill_carrier":
  429. case "draft_rogue":
  430. case "survivor":
  431. case "final_rogue":
  432. case "gained_gun_rank":
  433. case "dropped_enemy_gun_rank":
  434. case "got_juggernaut":
  435. case "kill_as_juggernaut":
  436. case "kill_juggernaut":
  437. case "jugg_on_jugg":
  438. if ( getGametypeNumLives() > 0 )
  439. {
  440. multiplier = max(1,int( 10/getGametypeNumLives() ));
  441. value = int(value * multiplier);
  442. }
  443.  
  444. // do we have an entitlement or prestige-award to give us an additional xp multiplier
  445. entitlement_xp = 0;
  446. prestigeBonus_xp = 0;
  447.  
  448. if ( self.prestigeDoubleXp )
  449. {
  450. howMuchTimePlayed = self getPlayerData( "prestigeDoubleXpTimePlayed" );
  451. if ( howMuchTimePlayed >= self.bufferedStatsMax["prestigeDoubleXpMaxTimePlayed"] )
  452. {
  453. self setPlayerData( "prestigeDoubleXp", false );
  454. self setPlayerData( "prestigeDoubleXpTimePlayed", 0 );
  455. self setPlayerData( "prestigeDoubleXpMaxTimePlayed", 0 );
  456. self.prestigeDoubleXp = false;
  457. }
  458. else
  459. {
  460. prestigeBonus_xp = 2;
  461. }
  462. }
  463.  
  464. for ( i = 0; i < 3; i++ )
  465. {
  466. if ( self getPlayerData( "xpMultiplierTimePlayed", i) < self.bufferedChildStatsMax[ "xpMaxMultiplierTimePlayed" ][ i ] )
  467. {
  468. entitlement_xp += int( self getPlayerData( "xpMultiplier", i) );
  469. }
  470. }
  471.  
  472. if ( entitlement_xp > 0 ) //we do have an entitlement xp multiplier
  473. {
  474. //adding prestige bonus to entitlement bonus
  475. if ( prestigeBonus_xp > 0 )
  476. entitlement_xp += prestigeBonus_xp;
  477.  
  478. value = int( ( value * level.xpScale ) * entitlement_xp );
  479. }
  480. else if ( prestigeBonus_xp > 0 ) //no entitlement xp multiplier, just prestige bonus
  481. {
  482. value = int( value * level.xpScale * prestigeBonus_xp );
  483. }
  484. else //no entitlement xp multiplier, or prestige bonus
  485. {
  486. value = int( value * level.xpScale );
  487. }
  488.  
  489. restXPAwarded = getRestXPAward( value );
  490. value += restXPAwarded;
  491. if ( restXPAwarded > 0 )
  492. {
  493. if ( isLastRestXPAward( value ) )
  494. thread maps\mp\gametypes\_hud_message::splashNotify( "rested_done" );
  495.  
  496. gotRestXP = true;
  497. }
  498. break;
  499. case "challenge":
  500. entitlement_xp = 0;
  501. if ( self getPlayerData( "challengeXPMultiplierTimePlayed", 0 ) < self.bufferedChildStatsMax[ "challengeXPMaxMultiplierTimePlayed" ][ 0 ] )
  502. {
  503. entitlement_xp += int( self getPlayerData( "challengeXPMultiplier", 0 ) );
  504. if ( entitlement_xp > 0 )
  505. value = int( value * entitlement_xp );
  506. }
  507.  
  508. break;
  509. }
  510.  
  511. if ( !gotRestXP )
  512. {
  513. // if we didn't get rest XP for this type, we push the rest XP goal ahead so we didn't waste it
  514. if ( self getPlayerData( "restXPGoal" ) > self getRankXP() )
  515. self setPlayerData( "restXPGoal", self getPlayerData( "restXPGoal" ) + value );
  516. }
  517.  
  518. oldxp = self getRankXP();
  519. self.xpGains[type] += value;
  520.  
  521. self incRankXP( value );
  522.  
  523. if ( self rankingEnabled() && updateRank( oldxp ) )
  524. self thread updateRankAnnounceHUD();
  525.  
  526. // Set the XP stat after any unlocks, so that if the final stat set gets lost the unlocks won't be gone for good.
  527. self syncXPStat();
  528.  
  529. // if this is a weapon challenge then set the weapon
  530. weaponChallenge = maps\mp\gametypes\_missions::isWeaponChallenge( challengeName );
  531. if( weaponChallenge )
  532. weapon = self GetCurrentWeapon();
  533.  
  534. // riot shield gives xp for taking shield damage
  535. if( type == "shield_damage" )
  536. {
  537. weapon = self GetCurrentWeapon();
  538. sMeansOfDeath = "MOD_MELEE";
  539. }
  540.  
  541. //////////////////////////////////////////////////////////////
  542. // WEAPON SHIT
  543. // check for weapon xp gains, they need to have cac unlocked before we start weapon xp gains
  544. if( weaponShouldGetXP( weapon, sMeansOfDeath ) || weaponChallenge )
  545. {
  546. // we just want the weapon name up to the first underscore
  547. weaponTokens = StrTok( weapon, "_" );
  548. //curWeapon = self GetCurrentWeapon();
  549.  
  550. if ( weaponTokens[0] == "iw5" )
  551. weaponName = weaponTokens[0] + "_" + weaponTokens[1];
  552. else if ( weaponTokens[0] == "alt" )
  553. weaponName = weaponTokens[1] + "_" + weaponTokens[2];
  554. else
  555. weaponName = weaponTokens[0];
  556.  
  557. if( weaponTokens[0] == "gl" )
  558. weaponName = weaponTokens[1];
  559.  
  560. if( /*IsDefined( curWeapon ) && curWeapon == weapon &&*/ self IsItemUnlocked( weaponName ) )
  561. {
  562. // is the weapon their class loadout weapon or a weapon they picked up?
  563. if( self.primaryWeapon == weapon ||
  564. self.secondaryWeapon == weapon ||
  565. WeaponAltWeaponName( self.primaryWeapon ) == weapon ||
  566. ( IsDefined( self.tookWeaponFrom ) && IsDefined( self.tookWeaponFrom[ weapon ] ) ) )
  567. {
  568. oldWeaponXP = self getWeaponRankXP( weaponName );
  569.  
  570. // we want normalized weapon xp kill points regardless of game mode
  571. switch( type )
  572. {
  573. case "kill":
  574. modifiedValue = WEAPONXP_KILL;
  575. break;
  576. default:
  577. modifiedValue = value;
  578. break;
  579. }
  580. /#
  581. if( GetDvarInt( "scr_devweaponxpmult" ) > 0 )
  582. modifiedValue *= GetDvarInt( "scr_devweaponxpmult" );
  583. #/
  584. //IW5 Prestige bonus weapon XP
  585. if ( self.prestigeDoubleWeaponXp )
  586. {
  587. howMuchWeaponXPTimePlayed = self getPlayerData( "prestigeDoubleWeaponXpTimePlayed" );
  588. if ( howMuchWeaponXPTimePlayed >= self.bufferedStatsMax["prestigeDoubleWeaponXpMaxTimePlayed"] )
  589. {
  590. self setPlayerData( "prestigeDoubleWeaponXp", true );
  591. self setPlayerData( "prestigeDoubleWeaponXpTimePlayed", 0 );
  592. self setPlayerData( "prestigeDoubleWeaponXpMaxTimePlayed", 0 );
  593. self.prestigeDoubleWeaponXp = true;
  594. }
  595. else
  596. {
  597. modifiedValue *= 2;
  598. }
  599. }
  600.  
  601. if ( self getPlayerData( "weaponXPMultiplierTimePlayed", 999999 ) < self.bufferedChildStatsMax[ "weaponXPMaxMultiplierTimePlayed" ][ 0 ] )
  602. {
  603. weaponXPMult = int( self getPlayerData( "weaponXPMultiplier", 999999 ) );
  604. if ( weaponXPMult > 0 )
  605. modifiedValue *= weaponXPMult;
  606. }
  607.  
  608. newWeaponXP = oldWeaponXP + modifiedValue;
  609.  
  610. if( !isWeaponMaxRank( weaponName ) )
  611. {
  612. // make sure we don't give more than the max.
  613. weaponMaxRankXP = getWeaponMaxRankXP( weaponName );
  614. if( newWeaponXP > weaponMaxRankXP )
  615. {
  616. newWeaponXP = weaponMaxRankXP;
  617. modifiedValue = weaponMaxRankXP - oldWeaponXP;
  618. }
  619.  
  620. //for tracking weaponXP earned on a weapon per game
  621. if ( !isDefined( self.weaponsUsed ) )
  622. {
  623. self.weaponsUsed = [];
  624. self.weaponXpEarned = [];
  625. }
  626.  
  627. weaponFound = false;
  628. foundIndex = 999;
  629. for( i = 0; i < self.weaponsUsed.size; i++ )
  630. {
  631. if ( self.weaponsUsed[i] == weaponName )
  632. {
  633. weaponFound = true;
  634. foundIndex = i;
  635. }
  636. }
  637.  
  638. if ( weaponFound )
  639. {
  640. self.weaponXpEarned[foundIndex] += modifiedValue;
  641. }
  642. else
  643. {
  644. self.weaponsUsed[self.weaponsUsed.size] = weaponName;
  645. self.weaponXpEarned[self.weaponXpEarned.size] = modifiedValue;
  646. }
  647.  
  648. self SetPlayerData( "weaponXP", weaponName, newWeaponXP );
  649. self maps\mp\_matchdata::logWeaponStat( weaponName, "XP", modifiedValue );
  650. self incPlayerStat( "weaponxpearned", modifiedValue );
  651. if ( self rankingEnabled() && updateWeaponRank( newWeaponXP, weaponName ) )
  652. {
  653. self thread updateWeaponRankAnnounceHUD();
  654. }
  655. }
  656. }
  657. }
  658. }
  659. // END.
  660. //////////////////////////////////////////////////////////////
  661.  
  662. if ( !level.hardcoreMode )
  663. {
  664. if ( type == "teamkill" )
  665. {
  666. self thread xpPointsPopup( 0 - getScoreInfoValue( "kill" ), 0, (1,0,0), 0 );
  667. }
  668. else
  669. {
  670. color = (1,1,0.5);
  671. if ( gotRestXP )
  672. color = (1,.65,0);
  673. self thread xpPointsPopup( value, momentumBonus, color, 0 );
  674. if ( type == "assist" )
  675. {
  676. assist_string = &"MP_ASSIST";
  677. if( self _hasPerk( "specialty_assists" ) )
  678. {
  679. if( !( self.pers["assistsToKill"] % 2 ) )
  680. {
  681. assist_string = &"MP_ASSIST_TO_KILL";
  682. }
  683. }
  684. self thread maps\mp\gametypes\_rank::xpEventPopup( assist_string );
  685. }
  686. }
  687. }
  688.  
  689. switch( type )
  690. {
  691. case "kill":
  692. case "headshot":
  693. case "suicide":
  694. case "teamkill":
  695. case "assist":
  696. case "capture":
  697. case "defend":
  698. case "return":
  699. case "pickup":
  700. case "assault":
  701. case "plant":
  702. case "defuse":
  703. case "kill_confirmed":
  704. case "kill_denied":
  705. case "tags_retrieved":
  706. case "team_assist":
  707. case "kill_bonus":
  708. case "kill_carrier":
  709. case "draft_rogue":
  710. case "survivor":
  711. case "final_rogue":
  712. case "gained_gun_rank":
  713. case "dropped_enemy_gun_rank":
  714. case "got_juggernaut":
  715. case "kill_as_juggernaut":
  716. case "kill_juggernaut":
  717. case "jugg_on_jugg":
  718. self.pers["summary"]["score"] += value;
  719. self.pers["summary"]["xp"] += value;
  720. break;
  721.  
  722. case "win":
  723. case "loss":
  724. case "tie":
  725. self.pers["summary"]["match"] += value;
  726. self.pers["summary"]["xp"] += value;
  727. break;
  728.  
  729. case "challenge":
  730. self.pers["summary"]["challenge"] += value;
  731. self.pers["summary"]["xp"] += value;
  732. break;
  733.  
  734. default:
  735. self.pers["summary"]["misc"] += value; //keeps track of ungrouped match xp reward
  736. self.pers["summary"]["match"] += value;
  737. self.pers["summary"]["xp"] += value;
  738. break;
  739. }
  740. }
  741.  
  742. weaponShouldGetXP( weapon, meansOfDeath )
  743. {
  744. if( self IsItemUnlocked( "cac" ) &&
  745. !self isJuggernaut() &&
  746. IsDefined( weapon ) &&
  747. IsDefined( meansOfDeath ) &&
  748. !isKillstreakWeapon( weapon ) )
  749. {
  750. if( isBulletDamage( meansOfDeath ) )
  751. {
  752. return true;
  753. }
  754. if( IsExplosiveDamageMOD( meansOfDeath ) || meansOfDeath == "MOD_IMPACT" )
  755. {
  756. if( getWeaponClass( weapon ) == "weapon_projectile" || getWeaponClass( weapon ) == "weapon_assault" )
  757. return true;
  758. }
  759. if( meansOfDeath == "MOD_MELEE" )
  760. {
  761. if( getWeaponClass( weapon ) == "weapon_riot" )
  762. return true;
  763. }
  764. }
  765.  
  766. return false;
  767. }
  768.  
  769. updateRank( oldxp )
  770. {
  771. newRankId = self getRank();
  772. if ( newRankId == self.pers["rank"] )
  773. return false;
  774.  
  775. oldRank = self.pers["rank"];
  776. self.pers["rank"] = newRankId;
  777.  
  778. //self logString( "promoted from " + oldRank + " to " + newRankId + " timeplayed: " + self maps\mp\gametypes\_persistence::statGet( "timePlayedTotal" ) );
  779. println( "promoted " + self.name + " from rank " + oldRank + " to " + newRankId + ". Experience went from " + oldxp + " to " + self getRankXP() + "." );
  780.  
  781. self setRank( newRankId );
  782.  
  783. return true;
  784. }
  785.  
  786. updateWeaponRank( oldxp, weapon )
  787. {
  788. // NOTE: weapon is already coming in tokenized, so it should be the weapon without attachments and _mp
  789. newRankId = self getWeaponRank( weapon );
  790. if ( newRankId == self.pers[ "weaponRank" ] )
  791. return false;
  792.  
  793. oldRank = self.pers[ "weaponRank" ];
  794. self.pers[ "weaponRank" ] = newRankId;
  795. self SetPlayerData( "weaponRank", weapon, newRankId );
  796.  
  797. //self logString( "promoted from " + oldRank + " to " + newRankId + " timeplayed: " + self maps\mp\gametypes\_persistence::statGet( "timePlayedTotal" ) );
  798. println( "promoted " + self.name + "'s weapon from rank " + oldRank + " to " + newRankId + ". Experience went from " + oldxp + " to " + self getWeaponRankXP( weapon ) + "." );
  799.  
  800. // now that we've ranked up, process the mastery challenge
  801. self thread maps\mp\gametypes\_missions::masteryChallengeProcess( weapon );
  802.  
  803. return true;
  804. }
  805.  
  806. updateRankAnnounceHUD()
  807. {
  808. self endon("disconnect");
  809.  
  810. self notify("update_rank");
  811. self endon("update_rank");
  812.  
  813. team = self.pers["team"];
  814. if ( !isdefined( team ) )
  815. return;
  816.  
  817. // give challenges and other XP a chance to process
  818. // also ensure that post game promotions happen asap
  819. if ( !levelFlag( "game_over" ) )
  820. level waittill_notify_or_timeout( "game_over", 0.25 );
  821.  
  822.  
  823. newRankName = self getRankInfoFull( self.pers["rank"] );
  824. rank_char = level.rankTable[self.pers["rank"]][1];
  825. subRank = int(rank_char[rank_char.size-1]);
  826.  
  827. thread maps\mp\gametypes\_hud_message::promotionSplashNotify();
  828.  
  829. if ( subRank > 1 )
  830. return;
  831.  
  832. for ( i = 0; i < level.players.size; i++ )
  833. {
  834. player = level.players[i];
  835. playerteam = player.pers["team"];
  836. if ( isdefined( playerteam ) && player != self )
  837. {
  838. if ( playerteam == team )
  839. player iPrintLn( &"RANK_PLAYER_WAS_PROMOTED", self, newRankName );
  840. }
  841. }
  842. }
  843.  
  844. updateWeaponRankAnnounceHUD()
  845. {
  846. self endon("disconnect");
  847.  
  848. self notify("update_weapon_rank");
  849. self endon("update_weapon_rank");
  850.  
  851. team = self.pers["team"];
  852. if ( !isdefined( team ) )
  853. return;
  854.  
  855. // give challenges and other XP a chance to process
  856. // also ensure that post game promotions happen asap
  857. if ( !levelFlag( "game_over" ) )
  858. level waittill_notify_or_timeout( "game_over", 0.25 );
  859.  
  860. thread maps\mp\gametypes\_hud_message::weaponPromotionSplashNotify();
  861.  
  862. //for ( i = 0; i < level.players.size; i++ )
  863. //{
  864. // player = level.players[i];
  865. // playerteam = player.pers["team"];
  866. // if ( isdefined( playerteam ) && player != self )
  867. // {
  868. // if ( playerteam == team )
  869. // player iPrintLn( &"RANK_WEAPON_WAS_PROMOTED", self );
  870. // }
  871. //}
  872. }
  873.  
  874. endGameUpdate()
  875. {
  876. player = self;
  877. }
  878.  
  879. createXpPointsPopup()
  880. {
  881. hud_xpPointsPopup = newClientHudElem( self );
  882. hud_xpPointsPopup.horzAlign = "center";
  883. hud_xpPointsPopup.vertAlign = "middle";
  884. hud_xpPointsPopup.alignX = "center";
  885. hud_xpPointsPopup.alignY = "middle";
  886. hud_xpPointsPopup.x = 30;
  887. if ( level.splitScreen )
  888. hud_xpPointsPopup.y = -30;
  889. else
  890. hud_xpPointsPopup.y = -50;
  891. hud_xpPointsPopup.font = "hudbig";
  892. hud_xpPointsPopup.fontscale = 0.65;
  893. hud_xpPointsPopup.archived = false;
  894. hud_xpPointsPopup.color = (0.5,0.5,0.5);
  895. hud_xpPointsPopup.sort = 10000;
  896. hud_xpPointsPopup maps\mp\gametypes\_hud::fontPulseInit( 3.0 );
  897. return hud_xpPointsPopup;
  898. }
  899.  
  900. xpPointsPopup( amount, bonus, hudColor, glowAlpha )
  901. {
  902. self endon( "disconnect" );
  903. self endon( "joined_team" );
  904. self endon( "joined_spectators" );
  905.  
  906. if ( amount == 0 )
  907. return;
  908.  
  909. self notify( "xpPointsPopup" );
  910. self endon( "xpPointsPopup" );
  911.  
  912. self.xpUpdateTotal += amount;
  913. self.bonusUpdateTotal += bonus;
  914.  
  915. wait ( 0.05 );
  916.  
  917. if ( self.xpUpdateTotal < 0 )
  918. self.hud_xpPointsPopup.label = &"";
  919. else
  920. self.hud_xpPointsPopup.label = &"MP_PLUS";
  921.  
  922. self.hud_xpPointsPopup.color = hudColor;
  923. self.hud_xpPointsPopup.glowColor = hudColor;
  924. self.hud_xpPointsPopup.glowAlpha = glowAlpha;
  925.  
  926. self.hud_xpPointsPopup setValue(self.xpUpdateTotal);
  927. self.hud_xpPointsPopup.alpha = 0.85;
  928. self.hud_xpPointsPopup thread maps\mp\gametypes\_hud::fontPulse( self );
  929.  
  930. increment = max( int( self.bonusUpdateTotal / 20 ), 1 );
  931.  
  932. if ( self.bonusUpdateTotal )
  933. {
  934. while ( self.bonusUpdateTotal > 0 )
  935. {
  936. self.xpUpdateTotal += min( self.bonusUpdateTotal, increment );
  937. self.bonusUpdateTotal -= min( self.bonusUpdateTotal, increment );
  938.  
  939. self.hud_xpPointsPopup setValue( self.xpUpdateTotal );
  940.  
  941. wait ( 0.05 );
  942. }
  943. }
  944. else
  945. {
  946. wait ( 1.0 );
  947. }
  948.  
  949. self.hud_xpPointsPopup fadeOverTime( 0.75 );
  950. self.hud_xpPointsPopup.alpha = 0;
  951.  
  952. self.xpUpdateTotal = 0;
  953. }
  954.  
  955. createXpEventPopup()
  956. {
  957. hud_xpEventPopup = newClientHudElem( self );
  958. hud_xpEventPopup.children = [];
  959. hud_xpEventPopup.horzAlign = "center";
  960. hud_xpEventPopup.vertAlign = "middle";
  961. hud_xpEventPopup.alignX = "center";
  962. hud_xpEventPopup.alignY = "middle";
  963. hud_xpEventPopup.x = 55;
  964. if ( level.splitScreen )
  965. hud_xpEventPopup.y = -20;
  966. else
  967. hud_xpEventPopup.y = -35;
  968. hud_xpEventPopup.font = "hudbig";
  969. hud_xpEventPopup.fontscale = 0.65;
  970. hud_xpEventPopup.archived = false;
  971. hud_xpEventPopup.color = (0.5,0.5,0.5);
  972. hud_xpEventPopup.sort = 10000;
  973. hud_xpEventPopup.elemType = "msgText";
  974. hud_xpEventPopup maps\mp\gametypes\_hud::fontPulseInit( 3.0 );
  975. return hud_xpEventPopup;
  976. }
  977.  
  978. xpEventPopup( event, hudColor, glowAlpha )
  979. {
  980. self endon( "disconnect" );
  981. self endon( "joined_team" );
  982. self endon( "joined_spectators" );
  983.  
  984. self notify( "xpEventPopup" );
  985. self endon( "xpEventPopup" );
  986.  
  987. wait ( 0.05 );
  988.  
  989. /*if ( self.spUpdateTotal < 0 )
  990. self.hud_xpEventPopup.label = &"";
  991. else
  992. self.hud_xpEventPopup.label = &"MP_PLUS";*/
  993.  
  994. if ( !isDefined( hudColor ) )
  995. hudColor = (1,1,0.5);
  996. if ( !isDefined( glowAlpha ) )
  997. glowAlpha = 0;
  998.  
  999. self.hud_xpEventPopup.color = hudColor;
  1000. self.hud_xpEventPopup.glowColor = hudColor;
  1001. self.hud_xpEventPopup.glowAlpha = glowAlpha;
  1002.  
  1003. self.hud_xpEventPopup setText(event);
  1004. self.hud_xpEventPopup.alpha = 0.85;
  1005.  
  1006. wait ( 1.0 );
  1007.  
  1008. self.hud_xpEventPopup fadeOverTime( 0.75 );
  1009. self.hud_xpEventPopup.alpha = 0;
  1010. }
  1011.  
  1012. removeRankHUD()
  1013. {
  1014. self.hud_xpPointsPopup.alpha = 0;
  1015. }
  1016.  
  1017. getRank()
  1018. {
  1019. rankXp = self.pers["rankxp"];
  1020. rankId = self.pers["rank"];
  1021.  
  1022. if ( rankXp < (getRankInfoMinXP( rankId ) + getRankInfoXPAmt( rankId )) )
  1023. return rankId;
  1024. else
  1025. return self getRankForXp( rankXp );
  1026. }
  1027.  
  1028. getWeaponRank( weapon )
  1029. {
  1030. // NOTE: weapon is already coming in tokenized, so it should be the weapon without attachments and _mp
  1031. rankXp = self GetPlayerData( "weaponXP", weapon );
  1032. return self getWeaponRankForXp( rankXp, weapon );
  1033. }
  1034.  
  1035. levelForExperience( experience )
  1036. {
  1037. return getRankForXP( experience );
  1038. }
  1039.  
  1040. weaponLevelForExperience( experience )
  1041. {
  1042. return getWeaponRankForXP( experience );
  1043. }
  1044.  
  1045. getCurrentWeaponXP()
  1046. {
  1047. weapon = self GetCurrentWeapon();
  1048. if( IsDefined( weapon ) )
  1049. {
  1050. return self GetPlayerData( "weaponXP", weapon );
  1051. }
  1052.  
  1053. return 0;
  1054. }
  1055.  
  1056. getRankForXp( xpVal )
  1057. {
  1058. rankId = 0;
  1059. rankName = level.rankTable[rankId][1];
  1060. assert( isDefined( rankName ) );
  1061.  
  1062. while ( isDefined( rankName ) && rankName != "" )
  1063. {
  1064. if ( xpVal < getRankInfoMinXP( rankId ) + getRankInfoXPAmt( rankId ) )
  1065. return rankId;
  1066.  
  1067. rankId++;
  1068. if ( isDefined( level.rankTable[rankId] ) )
  1069. rankName = level.rankTable[rankId][1];
  1070. else
  1071. rankName = undefined;
  1072. }
  1073.  
  1074. rankId--;
  1075. return rankId;
  1076. }
  1077.  
  1078. getWeaponRankForXp( xpVal, weapon )
  1079. {
  1080. // NOTE: weapon is already coming in tokenized, so it should be the weapon without attachments and _mp
  1081. if( !IsDefined( xpVal ) )
  1082. xpVal = 0;
  1083.  
  1084. weaponClass = tablelookup( "mp/statstable.csv", 4, weapon, 2 );
  1085. weaponMaxRank = int( tableLookup( "mp/weaponRankTable.csv", 0, weaponClass, 1 ) );
  1086. for( rankId = 0; rankId < weaponMaxRank + 1; rankId++ )
  1087. {
  1088. if ( xpVal < getWeaponRankInfoMinXP( rankId ) + getWeaponRankInfoXPAmt( rankId ) )
  1089. return rankId;
  1090. }
  1091.  
  1092. return ( rankId - 1 );
  1093. }
  1094.  
  1095. getSPM()
  1096. {
  1097. rankLevel = self getRank() + 1;
  1098. return (3 + (rankLevel * 0.5))*10;
  1099. }
  1100.  
  1101. getPrestigeLevel()
  1102. {
  1103. return self maps\mp\gametypes\_persistence::statGet( "prestige" );
  1104. }
  1105.  
  1106. getRankXP()
  1107. {
  1108. return self.pers["rankxp"];
  1109. }
  1110.  
  1111. getWeaponRankXP( weapon )
  1112. {
  1113. return self GetPlayerData( "weaponXP", weapon );
  1114. }
  1115.  
  1116. getWeaponMaxRankXP( weapon )
  1117. {
  1118. // NOTE: weapon is already coming in tokenized, so it should be the weapon without attachments and _mp
  1119. weaponClass = tablelookup( "mp/statstable.csv", 4, weapon, 2 );
  1120. weaponMaxRank = int( tableLookup( "mp/weaponRankTable.csv", 0, weaponClass, 1 ) );
  1121. weaponMaxRankXP = getWeaponRankInfoMaxXp( weaponMaxRank );
  1122.  
  1123. return weaponMaxRankXP;
  1124. }
  1125.  
  1126. isWeaponMaxRank( weapon )
  1127. {
  1128. // NOTE: weapon is already coming in tokenized, so it should be the weapon without attachments and _mp
  1129. weaponRankXP = self GetPlayerData( "weaponXP", weapon );
  1130. weaponMaxRankXP = getWeaponMaxRankXP( weapon );
  1131.  
  1132. return ( weaponRankXP >= weaponMaxRankXP );
  1133. }
  1134.  
  1135. // TODO: waiting to see how we decide to do this
  1136. //checkWeaponUnlocks( weapon )
  1137. //{
  1138. // // see if the weapon has unlocked anything new
  1139. // // NOTE: weapon is already coming in tokenized, so it should be the weapon without attachments and _mp
  1140. // weaponClass = tablelookup( "mp/statstable.csv", 4, weapon, 2 );
  1141. //
  1142. // weaponAttachmentCol = tablelookup( "mp/statstable.csv", 0, weaponClass, 2 );
  1143. // weaponCamoCol = tablelookup( "mp/statstable.csv", 0, weaponClass, 3 );
  1144. // weaponBuffCol = tablelookup( "mp/statstable.csv", 0, weaponClass, 4 );
  1145. // weaponCustomCol = tablelookup( "mp/statstable.csv", 0, weaponClass, 5 );
  1146. //
  1147. // weaponRank = self getWeaponRank( weapon );
  1148. //
  1149. // attachment = tablelookup( "mp/statstable.csv", 0, weaponRank, weaponAttachmentCol );
  1150. // if( attachment != "" )
  1151. // {
  1152. // // unlocked a new attachment
  1153. // self SetPlayerData( "attachmentNew", weapon, attachment, true );
  1154. // }
  1155. //
  1156. // // TODO: when we get camos online
  1157. // //camo = tablelookup( "mp/statstable.csv", 0, weaponRank, weaponCamoCol );
  1158. // //if( camo != "" )
  1159. // //{
  1160. // // // unlocked a new camo
  1161. // // self SetPlayerData( "camoNew", weapon, camo, true );
  1162. // //}
  1163. //
  1164. // buff = tablelookup( "mp/statstable.csv", 0, weaponRank, weaponBuffCol );
  1165. // if( buff != "" )
  1166. // {
  1167. // // unlocked a new buff
  1168. // self SetPlayerData( "perkNew", weapon, buff, true );
  1169. // }
  1170. //
  1171. // // TODO: when we get customs online
  1172. // //custom = tablelookup( "mp/statstable.csv", 0, weaponRank, weaponCustomCol );
  1173. // //if( custom != "" )
  1174. // //{
  1175. // // // unlocked a new custom
  1176. // // self SetPlayerData( "customNew", weapon, custom, true );
  1177. // //}
  1178. //}
  1179.  
  1180. incRankXP( amount )
  1181. {
  1182. if ( !self rankingEnabled() )
  1183. return;
  1184.  
  1185. if ( isDefined( self.isCheater ) )
  1186. return;
  1187.  
  1188. xp = self getRankXP();
  1189. newXp = (int( min( xp, getRankInfoMaxXP( level.maxRank ) ) ) + amount);
  1190.  
  1191. if ( self.pers["rank"] == level.maxRank && newXp >= getRankInfoMaxXP( level.maxRank ) )
  1192. newXp = getRankInfoMaxXP( level.maxRank );
  1193.  
  1194. self.pers["rankxp"] = newXp;
  1195. }
  1196.  
  1197. getRestXPAward( baseXP )
  1198. {
  1199. if ( !getdvarint( "scr_restxp_enable" ) )
  1200. return 0;
  1201.  
  1202. restXPAwardRate = getDvarFloat( "scr_restxp_restedAwardScale" ); // as a fraction of base xp
  1203.  
  1204. wantGiveRestXP = int(baseXP * restXPAwardRate);
  1205. mayGiveRestXP = self getPlayerData( "restXPGoal" ) - self getRankXP();
  1206.  
  1207. if ( mayGiveRestXP <= 0 )
  1208. return 0;
  1209.  
  1210. // we don't care about giving more rest XP than we have; we just want it to always be X2
  1211. //if ( wantGiveRestXP > mayGiveRestXP )
  1212. // return mayGiveRestXP;
  1213.  
  1214. return wantGiveRestXP;
  1215. }
  1216.  
  1217.  
  1218. isLastRestXPAward( baseXP )
  1219. {
  1220. if ( !getdvarint( "scr_restxp_enable" ) )
  1221. return false;
  1222.  
  1223. restXPAwardRate = getDvarFloat( "scr_restxp_restedAwardScale" ); // as a fraction of base xp
  1224.  
  1225. wantGiveRestXP = int(baseXP * restXPAwardRate);
  1226. mayGiveRestXP = self getPlayerData( "restXPGoal" ) - self getRankXP();
  1227.  
  1228. if ( mayGiveRestXP <= 0 )
  1229. return false;
  1230.  
  1231. if ( wantGiveRestXP >= mayGiveRestXP )
  1232. return true;
  1233.  
  1234. return false;
  1235. }
  1236.  
  1237. syncXPStat()
  1238. {
  1239. if ( level.xpScale > 4 || level.xpScale <= 0)
  1240. exitLevel( false );
  1241.  
  1242. xp = self getRankXP();
  1243.  
  1244. /#
  1245. // Attempt to catch xp resgression
  1246. oldXp = self getPlayerData( "experience" );
  1247. assert( xp >= oldXp, "Attempted XP regression in syncXPStat - " + oldXp + " -> " + xp + " for player " + self.name );
  1248. #/
  1249.  
  1250. self maps\mp\gametypes\_persistence::statSet( "experience", xp );
  1251. }
  1252.  
  1253. /#
  1254. watchDevDvars()
  1255. {
  1256. level endon( "game_ended" );
  1257.  
  1258. while( true )
  1259. {
  1260. if( GetDvarInt( "scr_devsetweaponmaxrank" ) > 0 )
  1261. {
  1262. // grab all of the players and max their current weapon rank
  1263. foreach( player in level.players )
  1264. {
  1265. if( IsDefined( player.pers[ "isBot" ] ) && player.pers[ "isBot" ] )
  1266. continue;
  1267.  
  1268. weapon = player GetCurrentWeapon();
  1269.  
  1270. // we just want the weapon name up to the first underscore
  1271. weaponTokens = StrTok( weapon, "_" );
  1272.  
  1273. if ( weaponTokens[0] == "iw5" )
  1274. weaponName = weaponTokens[0] + "_" + weaponTokens[1];
  1275. else if ( weaponTokens[0] == "alt" )
  1276. weaponName = weaponTokens[1] + "_" + weaponTokens[2];
  1277. else
  1278. weaponName = weaponTokens[0];
  1279.  
  1280. if( weaponTokens[0] == "gl" )
  1281. weaponName = weaponTokens[1];
  1282.  
  1283. weaponMaxRankXP = getWeaponMaxRankXP( weaponName );
  1284. player SetPlayerData( "weaponXP", weaponName, weaponMaxRankXP );
  1285. player updateWeaponRank( weaponMaxRankXP, weaponName );
  1286. }
  1287. SetDevDvar( "scr_devsetweaponmaxrank", 0 );
  1288. }
  1289.  
  1290. wait( 0.05 );
  1291. }
  1292. }
  1293. #/
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement