commit 355f6a6ebc6be784c8e0e7d06d438f6760db870a Author: cdnutter Date: Thu Jun 6 16:06:37 2024 -0700 initial diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..ddeead6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +z_svr_bots.iwd +bots.txt +scriptdata +logs +bots.txt \ No newline at end of file diff --git a/README.md b/README.md new file mode 100755 index 0000000..1b946c6 --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# Roll the Dice + +--- + +Planned Features diff --git a/maps/mp/gametypes/_class.gsc b/maps/mp/gametypes/_class.gsc new file mode 100755 index 0000000..27f13ad --- /dev/null +++ b/maps/mp/gametypes/_class.gsc @@ -0,0 +1,1211 @@ +#include common_scripts\utility; +// check if below includes are removable +#include maps\mp\_utility; +#include maps\mp\gametypes\_hud_util; + +init() +{ + level.classMap["class0"] = 0; + level.classMap["class1"] = 1; + level.classMap["class2"] = 2; + level.classMap["class3"] = 3; + level.classMap["class4"] = 4; + level.classMap["class5"] = 5; + level.classMap["class6"] = 6; + level.classMap["class7"] = 7; + level.classMap["class8"] = 8; + level.classMap["class9"] = 9; + level.classMap["class10"] = 10; + level.classMap["class11"] = 11; + level.classMap["class12"] = 12; + level.classMap["class13"] = 13; + level.classMap["class14"] = 14; + + level.classMap["custom1"] = 0; + level.classMap["custom2"] = 1; + level.classMap["custom3"] = 2; + level.classMap["custom4"] = 3; + level.classMap["custom5"] = 4; + level.classMap["custom6"] = 5; + level.classMap["custom7"] = 6; + level.classMap["custom8"] = 7; + level.classMap["custom9"] = 8; + level.classMap["custom10"] = 9; + + level.classMap["copycat"] = -1; + + /# + // classes testclients may choose from. + level.botClasses = []; + level.botClasses[0] = "class0"; + level.botClasses[1] = "class0"; + level.botClasses[2] = "class0"; + level.botClasses[3] = "class0"; + level.botClasses[4] = "class0"; + #/ + + level.defaultClass = "CLASS_ASSAULT"; + + level.classTableName = "mp/classTable.csv"; + + //precacheShader( "waypoint_bombsquad" ); + precacheShader( "specialty_pistoldeath" ); + precacheShader( "specialty_finalstand" ); + + level thread onPlayerConnecting(); +} + + +getClassChoice( response ) +{ + assert( isDefined( level.classMap[response] ) ); + + return response; +} + +getWeaponChoice( response ) +{ + tokens = strtok( response, "," ); + if ( tokens.size > 1 ) + return int(tokens[1]); + else + return 0; +} + + +logClassChoice( class, primaryWeapon, specialType, perks ) +{ + if ( class == self.lastClass ) + return; + + self logstring( "choseclass: " + class + " weapon: " + primaryWeapon + " special: " + specialType ); + for( i=0; i deathVal ) + { + self thread maps\mp\perks\_perks::givePerk( loadoutDeathStreak ); + } + } + + self loadoutAllPerks( loadoutEquipment, loadoutPerk1, loadoutPerk2, loadoutPerk3 ); + + self setKillstreaks( loadoutKillstreak1, loadoutKillstreak2, loadoutKillstreak3 ); + + if ( self hasPerk( "specialty_extraammo", true ) && getWeaponClass( secondaryName ) != "weapon_projectile" ) + self giveMaxAmmo( secondaryName ); + + // Primary Weapon + primaryName = buildWeaponName( loadoutPrimary, loadoutPrimaryAttachment, loadoutPrimaryAttachment2 ); + self _giveWeapon( primaryName, self.loadoutPrimaryCamo ); + + // fix changing from a riotshield class to a riotshield class during grace period not giving a shield + if ( primaryName == "riotshield_mp" && level.inGracePeriod ) + self notify ( "weapon_change", "riotshield_mp" ); + + if ( self hasPerk( "specialty_extraammo", true ) ) + self giveMaxAmmo( primaryName ); + + self setSpawnWeapon( primaryName ); + + primaryTokens = strtok( primaryName, "_" ); + self.pers["primaryWeapon"] = primaryTokens[0]; + + // Primary Offhand was given by givePerk (it's your perk1) + + // Secondary Offhand + offhandSecondaryWeapon = loadoutOffhand + "_mp"; + if ( loadoutOffhand == "flash_grenade" ) + self SetOffhandSecondaryClass( "flash" ); + else + self SetOffhandSecondaryClass( "smoke" ); + + self giveWeapon( offhandSecondaryWeapon ); + if( loadOutOffhand == "smoke_grenade" ) + self setWeaponAmmoClip( offhandSecondaryWeapon, 1 ); + else if( loadOutOffhand == "flash_grenade" ) + self setWeaponAmmoClip( offhandSecondaryWeapon, 2 ); + else if( loadOutOffhand == "concussion_grenade" ) + self setWeaponAmmoClip( offhandSecondaryWeapon, 2 ); + else + self setWeaponAmmoClip( offhandSecondaryWeapon, 1 ); + + primaryWeapon = primaryName; + self.primaryWeapon = primaryWeapon; + self.secondaryWeapon = secondaryName; + + self maps\mp\gametypes\_teams::playerModelForWeapon( self.pers["primaryWeapon"], getBaseWeaponName( secondaryName ) ); + + self.isSniper = (weaponClass( self.primaryWeapon ) == "sniper"); + + self maps\mp\gametypes\_weapons::updateMoveSpeedScale( "primary" ); + + // cac specialties that require loop threads + self maps\mp\perks\_perks::cac_selector(); + + self notify ( "changed_kit" ); + self notify ( "giveLoadout" ); +} + +_detachAll() +{ + if ( isDefined( self.hasRiotShield ) && self.hasRiotShield ) + { + if ( self.hasRiotShieldEquipped ) + { + self DetachShieldModel( "weapon_riot_shield_mp", "tag_weapon_left" ); + self.hasRiotShieldEquipped = false; + } + else + { + self DetachShieldModel( "weapon_riot_shield_mp", "tag_shield_back" ); + } + + self.hasRiotShield = false; + } + + self detachAll(); +} + +isPerkUpgraded( perkName ) +{ + perkUpgrade = tablelookup( "mp/perktable.csv", 1, perkName, 8 ); + + if ( perkUpgrade == "" || perkUpgrade == "specialty_null" ) + return false; + + if ( !self isItemUnlocked( perkUpgrade ) ) + return false; + + return true; +} + +getPerkUpgrade( perkName ) +{ + perkUpgrade = tablelookup( "mp/perktable.csv", 1, perkName, 8 ); + + if ( perkUpgrade == "" || perkUpgrade == "specialty_null" ) + return "specialty_null"; + + if ( !self isItemUnlocked( perkUpgrade ) ) + return "specialty_null"; + + return ( perkUpgrade ); +} + +loadoutAllPerks( loadoutEquipment, loadoutPerk1, loadoutPerk2, loadoutPerk3 ) +{ + loadoutEquipment = maps\mp\perks\_perks::validatePerk( 1, loadoutEquipment ); + loadoutPerk1 = maps\mp\perks\_perks::validatePerk( 1, loadoutPerk1 ); + loadoutPerk2 = maps\mp\perks\_perks::validatePerk( 2, loadoutPerk2 ); + loadoutPerk3 = maps\mp\perks\_perks::validatePerk( 3, loadoutPerk3 ); + + self maps\mp\perks\_perks::givePerk( loadoutEquipment ); + self maps\mp\perks\_perks::givePerk( loadoutPerk1 ); + self maps\mp\perks\_perks::givePerk( loadoutPerk2 ); + self maps\mp\perks\_perks::givePerk( loadoutPerk3 ); + + perkUpgrd[0] = tablelookup( "mp/perktable.csv", 1, loadoutPerk1, 8 ); + perkUpgrd[1] = tablelookup( "mp/perktable.csv", 1, loadoutPerk2, 8 ); + perkUpgrd[2] = tablelookup( "mp/perktable.csv", 1, loadoutPerk3, 8 ); + + foreach( upgrade in perkUpgrd ) + { + if ( upgrade == "" || upgrade == "specialty_null" ) + continue; + + if ( self isItemUnlocked( upgrade ) ) + self maps\mp\perks\_perks::givePerk( upgrade ); + } + +} + +trackRiotShield() +{ + self endon ( "death" ); + self endon ( "disconnect" ); + + self.hasRiotShield = self hasWeapon( "riotshield_mp" ); + self.hasRiotShieldEquipped = (self.currentWeaponAtSpawn == "riotshield_mp"); + + // note this function must play nice with _detachAll(). + + if ( self.hasRiotShield ) + { + if ( self.hasRiotShieldEquipped ) + { + self AttachShieldModel( "weapon_riot_shield_mp", "tag_weapon_left" ); + } + else + { + self AttachShieldModel( "weapon_riot_shield_mp", "tag_shield_back" ); + } + } + + for ( ;; ) + { + self waittill ( "weapon_change", newWeapon ); + + if ( newWeapon == "riotshield_mp" ) + { + // defensive check in case we somehow get an extra "weapon_change" + if ( self.hasRiotShieldEquipped ) + continue; + + if ( self.hasRiotShield ) + self MoveShieldModel( "weapon_riot_shield_mp", "tag_shield_back", "tag_weapon_left" ); + else + self AttachShieldModel( "weapon_riot_shield_mp", "tag_weapon_left" ); + + self.hasRiotShield = true; + self.hasRiotShieldEquipped = true; + } + else if ( (self IsMantling()) && (newWeapon == "none") ) + { + // Do nothing, we want to keep that weapon on their arm. + } + else if ( self.hasRiotShieldEquipped ) + { + assert( self.hasRiotShield ); + self.hasRiotShield = self hasWeapon( "riotshield_mp" ); + + if ( self.hasRiotShield ) + self MoveShieldModel( "weapon_riot_shield_mp", "tag_weapon_left", "tag_shield_back" ); + else + self DetachShieldModel( "weapon_riot_shield_mp", "tag_weapon_left" ); + + self.hasRiotShieldEquipped = false; + } + else if ( self.hasRiotShield ) + { + if ( !self hasWeapon( "riotshield_mp" ) ) + { + // we probably just lost all of our weapons (maybe switched classes) + self DetachShieldModel( "weapon_riot_shield_mp", "tag_shield_back" ); + self.hasRiotShield = false; + } + } + } +} + + +tryAttach( placement ) // deprecated; hopefully we won't need to bring this defensive function back +{ + if ( !isDefined( placement ) || placement != "back" ) + tag = "tag_weapon_left"; + else + tag = "tag_shield_back"; + + attachSize = self getAttachSize(); + + for ( i = 0; i < attachSize; i++ ) + { + attachedTag = self getAttachTagName( i ); + if ( attachedTag == tag && self getAttachModelName( i ) == "weapon_riot_shield_mp" ) + { + return; + } + } + + self AttachShieldModel( "weapon_riot_shield_mp", tag ); +} + +tryDetach( placement ) // deprecated; hopefully we won't need to bring this defensive function back +{ + if ( !isDefined( placement ) || placement != "back" ) + tag = "tag_weapon_left"; + else + tag = "tag_shield_back"; + + + attachSize = self getAttachSize(); + + for ( i = 0; i < attachSize; i++ ) + { + attachedModel = self getAttachModelName( i ); + if ( attachedModel == "weapon_riot_shield_mp" ) + { + self DetachShieldModel( attachedModel, tag); + return; + } + } + return; +} + + + +buildWeaponName( baseName, attachment1, attachment2 ) +{ + if ( !isDefined( level.letterToNumber ) ) + level.letterToNumber = makeLettersToNumbers(); + + // disable bling when perks are disabled + if ( getDvarInt ( "scr_game_perks" ) == 0 ) + { + attachment2 = "none"; + + if ( baseName == "onemanarmy" ) + return ( "beretta_mp" ); + } + + weaponName = baseName; + attachments = []; + + if ( attachment1 != "none" && attachment2 != "none" ) + { + if ( level.letterToNumber[attachment1[0]] < level.letterToNumber[attachment2[0]] ) + { + + attachments[0] = attachment1; + attachments[1] = attachment2; + + } + else if ( level.letterToNumber[attachment1[0]] == level.letterToNumber[attachment2[0]] ) + { + if ( level.letterToNumber[attachment1[1]] < level.letterToNumber[attachment2[1]] ) + { + attachments[0] = attachment1; + attachments[1] = attachment2; + } + else + { + attachments[0] = attachment2; + attachments[1] = attachment1; + } + } + else + { + attachments[0] = attachment2; + attachments[1] = attachment1; + } + } + else if ( attachment1 != "none" ) + { + attachments[0] = attachment1; + } + else if ( attachment2 != "none" ) + { + attachments[0] = attachment2; + } + + foreach ( attachment in attachments ) + { + weaponName += "_" + attachment; + } + + if ( !isValidWeapon( weaponName + "_mp" ) ) + return ( baseName + "_mp" ); + else + return ( weaponName + "_mp" ); +} + + +makeLettersToNumbers() +{ + array = []; + + array["a"] = 0; + array["b"] = 1; + array["c"] = 2; + array["d"] = 3; + array["e"] = 4; + array["f"] = 5; + array["g"] = 6; + array["h"] = 7; + array["i"] = 8; + array["j"] = 9; + array["k"] = 10; + array["l"] = 11; + array["m"] = 12; + array["n"] = 13; + array["o"] = 14; + array["p"] = 15; + array["q"] = 16; + array["r"] = 17; + array["s"] = 18; + array["t"] = 19; + array["u"] = 20; + array["v"] = 21; + array["w"] = 22; + array["x"] = 23; + array["y"] = 24; + array["z"] = 25; + + return array; +} + +setKillstreaks( streak1, streak2, streak3 ) +{ + self.killStreaks = []; + + if ( self _hasPerk( "specialty_hardline" ) ) + modifier = -1; + else + modifier = 0; + + /*if ( streak1 == "none" && streak2 == "none" && streak3 == "none" ) + { + streak1 = "uav"; + streak2 = "precision_airstrike"; + streak3 = "helicopter"; + }*/ + + killStreaks = []; + + if ( streak1 != "none" ) + { + //if ( !level.splitScreen ) + streakVal = int( tableLookup( "mp/killstreakTable.csv", 1, streak1, 4 ) ); + //else + // streakVal = int( tableLookup( "mp/killstreakTable.csv", 1, streak1, 5 ) ); + killStreaks[streakVal + modifier] = streak1; + } + + if ( streak2 != "none" ) + { + //if ( !level.splitScreen ) + streakVal = int( tableLookup( "mp/killstreakTable.csv", 1, streak2, 4 ) ); + //else + // streakVal = int( tableLookup( "mp/killstreakTable.csv", 1, streak2, 5 ) ); + killStreaks[streakVal + modifier] = streak2; + } + + if ( streak3 != "none" ) + { + //if ( !level.splitScreen ) + streakVal = int( tableLookup( "mp/killstreakTable.csv", 1, streak3, 4 ) ); + //else + // streakVal = int( tableLookup( "mp/killstreakTable.csv", 1, streak3, 5 ) ); + killStreaks[streakVal + modifier] = streak3; + } + + // foreach doesn't loop through numbers arrays in number order; it loops through the elements in the order + // they were added. We'll use this to fix it for now. + maxVal = 0; + foreach ( streakVal, streakName in killStreaks ) + { + if ( streakVal > maxVal ) + maxVal = streakVal; + } + + for ( streakIndex = 0; streakIndex <= maxVal; streakIndex++ ) + { + if ( !isDefined( killStreaks[streakIndex] ) ) + continue; + + streakName = killStreaks[streakIndex]; + + self.killStreaks[ streakIndex ] = killStreaks[ streakIndex ]; + } + // end lameness + + // defcon rollover + maxRollOvers = 10; + newKillstreaks = self.killstreaks; + for ( rollOver = 1; rollOver <= maxRollOvers; rollOver++ ) + { + foreach ( streakVal, streakName in self.killstreaks ) + { + newKillstreaks[ streakVal + (maxVal*rollOver) ] = streakName + "-rollover" + rollOver; + } + } + + self.killstreaks = newKillstreaks; +} + + +replenishLoadout() // used by ammo hardpoint. +{ + team = self.pers["team"]; + class = self.pers["class"]; + + weaponsList = self GetWeaponsListAll(); + for( idx = 0; idx < weaponsList.size; idx++ ) + { + weapon = weaponsList[idx]; + + self giveMaxAmmo( weapon ); + self SetWeaponAmmoClip( weapon, 9999 ); + + if ( weapon == "claymore_mp" || weapon == "claymore_detonator_mp" ) + self setWeaponAmmoStock( weapon, 2 ); + } + + if ( self getAmmoCount( level.classGrenades[class]["primary"]["type"] ) < level.classGrenades[class]["primary"]["count"] ) + self SetWeaponAmmoClip( level.classGrenades[class]["primary"]["type"], level.classGrenades[class]["primary"]["count"] ); + + if ( self getAmmoCount( level.classGrenades[class]["secondary"]["type"] ) < level.classGrenades[class]["secondary"]["count"] ) + self SetWeaponAmmoClip( level.classGrenades[class]["secondary"]["type"], level.classGrenades[class]["secondary"]["count"] ); +} + + +onPlayerConnecting() +{ + for(;;) + { + level waittill( "connected", player ); + + if ( !isDefined( player.pers["class"] ) ) + { + player.pers["class"] = ""; + } + player.class = player.pers["class"]; + player.lastClass = ""; + player.detectExplosives = false; + player.bombSquadIcons = []; + player.bombSquadIds = []; + } +} + + +fadeAway( waitDelay, fadeDelay ) +{ + wait waitDelay; + + self fadeOverTime( fadeDelay ); + self.alpha = 0; +} + + +setClass( newClass ) +{ + self.curClass = newClass; +} + +getPerkForClass( perkSlot, className ) +{ + class_num = getClassIndex( className ); + + if( isSubstr( className, "custom" ) ) + return cac_getPerk( class_num, perkSlot ); + else + return table_getPerk( level.classTableName, class_num, perkSlot ); +} + + +classHasPerk( className, perkName ) +{ + return( getPerkForClass( 0, className ) == perkName || getPerkForClass( 1, className ) == perkName || getPerkForClass( 2, className ) == perkName ); +} + +isValidPrimary( refString ) +{ + switch ( refString ) + { + case "riotshield": + case "ak47": + case "m16": + case "m4": + case "fn2000": + case "masada": + case "famas": + case "fal": + case "scar": + case "tavor": + case "mp5k": + case "uzi": + case "p90": + case "kriss": + case "ump45": + case "barrett": + case "wa2000": + case "m21": + case "cheytac": + case "rpd": + case "sa80": + case "mg4": + case "m240": + case "aug": + return true; + default: + assertMsg( "Replacing invalid primary weapon: " + refString ); + return false; + } +} + +isValidSecondary( refString ) +{ + switch ( refString ) + { + case "beretta": + case "usp": + case "deserteagle": + case "coltanaconda": + case "glock": + case "beretta393": + case "pp2000": + case "tmp": + case "m79": + case "rpg": + case "at4": + case "stinger": + case "javelin": + case "ranger": + case "model1887": + case "striker": + case "aa12": + case "m1014": + case "spas12": + return true; + default: + assertMsg( "Replacing invalid secondary weapon: " + refString ); + return false; + } +} + +isValidAttachment( refString ) +{ + switch ( refString ) + { + case "none": + case "acog": + case "reflex": + case "silencer": + case "grip": + case "gl": + case "akimbo": + case "thermal": + case "shotgun": + case "heartbeat": + case "fmj": + case "rof": + case "xmags": + case "eotech": + case "tactical": + return true; + default: + assertMsg( "Replacing invalid equipment weapon: " + refString ); + return false; + } +} + +isValidCamo( refString ) +{ + switch ( refString ) + { + case "none": + case "woodland": + case "desert": + case "arctic": + case "digital": + case "red_urban": + case "red_tiger": + case "blue_tiger": + case "orange_fall": + return true; + default: + assertMsg( "Replacing invalid camo: " + refString ); + return false; + } +} + +isValidEquipment( refString ) +{ + switch ( refString ) + { + case "frag_grenade_mp": + case "semtex_mp": + case "throwingknife_mp": + case "specialty_tacticalinsertion": + case "specialty_blastshield": + case "claymore_mp": + case "c4_mp": + return true; + default: + assertMsg( "Replacing invalid equipment: " + refString ); + return false; + } +} + + +isValidOffhand( refString ) +{ + switch ( refString ) + { + case "flash_grenade": + case "concussion_grenade": + case "smoke_grenade": + return true; + default: + assertMsg( "Replacing invalid offhand: " + refString ); + return false; + } +} + +isValidPerk1( refString ) +{ + switch ( refString ) + { + case "specialty_marathon": + case "specialty_fastreload": + case "specialty_scavenger": + case "specialty_bling": + return true; + default: + assertMsg( "Replacing invalid perk1: " + refString ); + return false; + } +} + +isValidPerk2( refString ) +{ + switch ( refString ) + { + case "specialty_bulletdamage": + case "specialty_lightweight": + case "specialty_hardline": + case "specialty_coldblooded": + case "specialty_explosivedamage": + return true; + default: + assertMsg( "Replacing invalid perk2: " + refString ); + return false; + } +} + +isValidPerk3( refString ) +{ + switch ( refString ) + { + case "specialty_extendedmelee": + case "specialty_bulletaccuracy": + case "specialty_localjammer": + case "specialty_heartbreaker": + case "specialty_detectexplosive": + return true; + default: + assertMsg( "Replacing invalid perk3: " + refString ); + return false; + } +} + +isValidDeathStreak( refString ) +{ + switch ( refString ) + { + case "specialty_copycat": + return true; + default: + assertMsg( "Replacing invalid death streak: " + refString ); + return false; + } +} + +isValidWeapon( refString ) +{ + if ( !isDefined( level.weaponRefs ) ) + { + level.weaponRefs = []; + + foreach ( weaponRef in level.weaponList ) + level.weaponRefs[ weaponRef ] = true; + } + + if ( isDefined( level.weaponRefs[ refString ] ) ) + return true; + + assertMsg( "Replacing invalid weapon/attachment combo: " + refString ); + + return false; +} diff --git a/maps/mp/gametypes/_damage.gsc b/maps/mp/gametypes/_damage.gsc new file mode 100755 index 0000000..47a6976 --- /dev/null +++ b/maps/mp/gametypes/_damage.gsc @@ -0,0 +1,2770 @@ +#include maps\mp\_utility; +#include maps\mp\gametypes\_hud_util; +#include common_scripts\utility; + + +isSwitchingTeams() +{ + if ( isDefined( self.switching_teams ) ) + return true; + + return false; +} + + +isTeamSwitchBalanced() +{ + playerCounts = self maps\mp\gametypes\_teams::CountPlayers(); + playerCounts[ self.leaving_team ] -- ; + playerCounts[ self.joining_team ]++ ; + + return( ( playerCounts[ self.joining_team ] - playerCounts[ self.leaving_team ] ) < 2 ); +} + + +isFriendlyFire( victim, attacker ) +{ + if ( !level.teamBased ) + return false; + + if ( !isDefined( attacker ) ) + return false; + + if ( !isPlayer( attacker ) && !isDefined( attacker.team ) ) + return false; + + if ( victim.team != attacker.team ) + return false; + + if ( victim == attacker ) + return false; + + return true; +} + + +killedSelf( attacker ) +{ + if ( !isPlayer( attacker ) ) + return false; + + if ( attacker != self ) + return false; + + return true; +} + + +isHeadShot( sWeapon, sHitLoc, sMeansOfDeath, attacker ) +{ + if ( isDefined( attacker ) ) + { + if ( attacker.code_classname == "script_vehicle" && isDefined( attacker.owner ) ) + return false; + if ( attacker.code_classname == "misc_turret" && isDefined( attacker.owner ) ) + return false; + if ( attacker.code_classname == "script_model" && isDefined( attacker.owner ) ) + return false; + } + + return( sHitLoc == "head" || sHitLoc == "helmet" ) && sMeansOfDeath != "MOD_MELEE" && sMeansOfDeath != "MOD_IMPACT" && !isMG( sWeapon ); +} + + +handleTeamChangeDeath() +{ + if ( !level.teamBased ) + return; + + // this might be able to happen now, but we should remove instances where it can + assert( self.leaving_team != self.joining_team ); + + if ( self.joining_team == "spectator" || !isTeamSwitchBalanced() ) + { + self thread [[ level.onXPEvent ]]( "suicide" ); + self incPersStat( "suicides", 1 ); + self.suicides = self getPersStat( "suicides" ); + } +} + + +handleWorldDeath( attacker, lifeId, sMeansOfDeath, sHitLoc ) +{ + if ( !isDefined( attacker ) ) + return; + + if ( !isDefined( attacker.team ) ) + { + handleSuicideDeath( sMeansOfDeath, sHitLoc ); + return; + } + + assert( attacker.team == "axis" || attacker.team == "allies" ); + + if ( level.teamBased && attacker.team != self.team ) + { + if ( isDefined( level.onNormalDeath ) && isPlayer( attacker ) && attacker.team != "spectator" ) + [[ level.onNormalDeath ]]( self, attacker, lifeId ); + } +} + + +handleSuicideDeath( sMeansOfDeath, sHitLoc ) +{ + self SetCardDisplaySlot( self, 7 ); + self openMenu( "killedby_card_display" ); + + self thread [[ level.onXPEvent ]]( "suicide" ); + self incPersStat( "suicides", 1 ); + self.suicides = self getPersStat( "suicides" ); + + if ( !matchMakingGame() ) + self incPlayerStat( "suicides", 1 ); + + scoreSub = maps\mp\gametypes\_tweakables::getTweakableValue( "game", "suicidepointloss" ); + maps\mp\gametypes\_gamescore::_setPlayerScore( self, maps\mp\gametypes\_gamescore::_getPlayerScore( self ) - scoreSub ); + + if ( sMeansOfDeath == "MOD_SUICIDE" && sHitLoc == "none" && isDefined( self.throwingGrenade ) ) + self.lastGrenadeSuicideTime = gettime(); + + // suicide was caused by too many team kills + if ( isDefined( self.friendlydamage ) ) + self iPrintLnBold( &"MP_FRIENDLY_FIRE_WILL_NOT" ); +} + + +handleFriendlyFireDeath( attacker ) +{ + attacker SetCardDisplaySlot( self, 8 ); + attacker openMenu( "youkilled_card_display" ); + + self SetCardDisplaySlot( attacker, 7 ); + self openMenu( "killedby_card_display" ); + + attacker thread [[ level.onXPEvent ]]( "teamkill" ); + attacker.pers[ "teamkills" ] += 1.0; + + attacker.teamkillsThisRound++ ; + + if ( maps\mp\gametypes\_tweakables::getTweakableValue( "team", "teamkillpointloss" ) ) + { + scoreSub = maps\mp\gametypes\_rank::getScoreInfoValue( "kill" ); + maps\mp\gametypes\_gamescore::_setPlayerScore( attacker, maps\mp\gametypes\_gamescore::_getPlayerScore( attacker ) - scoreSub ); + } + + if ( level.maxAllowedTeamkills < 0 ) + return; + + if ( level.inGracePeriod ) + { + teamKillDelay = 1; + attacker.pers["teamkills"] += level.maxAllowedTeamkills; + } + else if ( attacker.pers[ "teamkills" ] > 1 && getTimePassed() < ( (level.gracePeriod * 1000) + 8000 + ( attacker.pers[ "teamkills" ] * 1000 ) ) ) + { + teamKillDelay = 1; + attacker.pers["teamkills"] += level.maxAllowedTeamkills; + } + else + { + teamKillDelay = attacker maps\mp\gametypes\_playerlogic::TeamKillDelay(); + } + + if ( teamKillDelay > 0 ) + { + attacker.pers["teamKillPunish"] = true; + attacker _suicide(); + } +} + + +handleNormalDeath( lifeId, attacker, eInflictor, sWeapon, sMeansOfDeath ) +{ + attacker thread maps\mp\_events::killedPlayer( lifeId, self, sWeapon, sMeansOfDeath ); + + //if ( attacker.pers["teamkills"] <= level.maxAllowedTeamkills ) + // attacker.pers["teamkills"] = max( attacker.pers["teamkills"] - 1, 0 ); + + attacker SetCardDisplaySlot( self, 8 ); + attacker openMenu( "youkilled_card_display" ); + + self SetCardDisplaySlot( attacker, 7 ); + self openMenu( "killedby_card_display" ); + + if ( sMeansOfDeath == "MOD_HEAD_SHOT" ) + { + attacker incPersStat( "headshots", 1 ); + attacker.headshots = attacker getPersStat( "headshots" ); + attacker incPlayerStat( "headshots", 1 ); + + if ( isDefined( attacker.lastStand ) ) + value = maps\mp\gametypes\_rank::getScoreInfoValue( "kill" ) * 2; + else + value = undefined; + + attacker playLocalSound( "bullet_impact_headshot_2" ); + } + else + { + if ( isDefined( attacker.lastStand ) ) + value = maps\mp\gametypes\_rank::getScoreInfoValue( "kill" ) * 2; + else + value = undefined; + } + + attacker thread maps\mp\gametypes\_rank::giveRankXP( "kill", value ); + + attacker incPersStat( "kills", 1 ); + attacker.kills = attacker getPersStat( "kills" ); + attacker updatePersRatio( "kdRatio", "kills", "deaths" ); + attacker maps\mp\gametypes\_persistence::statSetChild( "round", "kills", attacker.kills ); + attacker incPlayerStat( "kills", 1 ); + + if ( isFlankKill( self, attacker ) ) + { + attacker incPlayerStat( "flankkills", 1 ); + + self incPlayerStat( "flankdeaths", 1 ); + } + + lastKillStreak = attacker.pers["cur_kill_streak"]; + + self.pers["copyCatLoadout"] = undefined; + + if ( self _hasPerk( "specialty_copycat" ) ) + self.pers["copyCatLoadout"] = attacker maps\mp\gametypes\_class::cloneLoadout(); + + if ( isAlive( attacker ) ) + { + // killstreaks only advance from kills earned this life + if ( isDefined( level.killStreakSpecialCaseWeapons[sWeapon] ) ) // this is an optimization + { + switch ( sWeapon ) + { + case "ac130_105mm_mp": + case "ac130_40mm_mp": + case "ac130_25mm_mp": + if ( attacker.ac130LifeId == attacker.pers["deaths"] ) + attacker.pers["cur_kill_streak"]++; + break; + case "cobra_player_minigun_mp": + case "weapon_cobra_mk19_mp": + if ( attacker.heliRideLifeId == attacker.pers["deaths"] ) + attacker.pers["cur_kill_streak"]++; + break; + case "cobra_20mm_mp": + case "artillery_mp": + case "stealth_bomb_mp": + case "remotemissile_projectile_mp": + case "sentry_minigun_mp": + case "harrier_20mm_mp": + case "pavelow_minigun_mp": + if ( isDefined( eInflictor ) && isDefined( eInflictor.lifeId ) ) + killstreakLifeId = eInflictor.lifeId; + else + killstreakLifeId = attacker.lifeId; + + if ( killstreakLifeId == attacker.pers["deaths"] ) + attacker.pers["cur_kill_streak"]++; + break; + default: + attacker.pers["cur_kill_streak"]++; + break; + } + } + else + { + attacker.pers["cur_kill_streak"]++; + } + + attacker setPlayerStatIfGreater( "killstreak", attacker.pers["cur_kill_streak"] ); + + if ( attacker.pers["cur_kill_streak"] > attacker getPersStat( "longestStreak" ) ) + attacker setPersStat( "longestStreak", attacker.pers["cur_kill_streak"] ); + } + + attacker.pers["cur_death_streak"] = 0; + + if ( attacker.pers["cur_kill_streak"] > attacker maps\mp\gametypes\_persistence::statGetChild( "round", "killStreak" ) ) + { + attacker maps\mp\gametypes\_persistence::statSetChild( "round", "killStreak", attacker.pers["cur_kill_streak"] ); + } + + if ( attacker.pers["cur_kill_streak"] > attacker.kill_streak ) + { + attacker maps\mp\gametypes\_persistence::statSet( "killStreak", attacker.pers["cur_kill_streak"] ); + attacker.kill_streak = attacker.pers["cur_kill_streak"]; + } + + maps\mp\gametypes\_gamescore::givePlayerScore( "kill", attacker, self ); + maps\mp\_skill::processKill( attacker, self ); + + scoreSub = maps\mp\gametypes\_tweakables::getTweakableValue( "game", "deathpointloss" ); + maps\mp\gametypes\_gamescore::_setPlayerScore( self, maps\mp\gametypes\_gamescore::_getPlayerScore( self ) - scoreSub ); + + if ( isDefined( level.ac130player ) && level.ac130player == attacker ) + level notify( "ai_killed", self ); + + //if ( lastKillStreak != attacker.pers["cur_kill_streak"] ) + level notify ( "player_got_killstreak_" + attacker.pers["cur_kill_streak"], attacker ); + + if ( isAlive( attacker ) ) + attacker thread maps\mp\killstreaks\_killstreaks::checkKillstreakReward( attacker.pers["cur_kill_streak"] ); + + attacker notify ( "killed_enemy" ); + + if ( !level.teamBased ) + { + self.attackers = []; + return; + } + + if ( isDefined( level.onNormalDeath ) && attacker.pers[ "team" ] != "spectator" ) + [[ level.onNormalDeath ]]( self, attacker, lifeId ); + + level thread maps\mp\gametypes\_battlechatter_mp::sayLocalSoundDelayed( attacker, "kill", 0.75 ); + + if ( isDefined( self.lastAttackedShieldPlayer ) && isDefined( self.lastAttackedShieldTime ) && self.lastAttackedShieldPlayer != attacker ) + { + if ( getTime() - self.lastAttackedShieldTime < 2500 ) + { + self.lastAttackedShieldPlayer thread maps\mp\gametypes\_gamescore::processShieldAssist( self ); + } + else if ( isAlive( self.lastAttackedShieldPlayer ) && getTime() - self.lastAttackedShieldTime < 5000 ) + { + forwardVec = vectorNormalize( anglesToForward( self.angles ) ); + shieldVec = vectorNormalize( self.lastAttackedShieldPlayer.origin - self.origin ); + + if ( vectorDot( shieldVec, forwardVec ) > 0.925 ) + self.lastAttackedShieldPlayer thread maps\mp\gametypes\_gamescore::processShieldAssist( self ); + } + } + + if ( isDefined( self.attackers ) ) + { + foreach ( player in self.attackers ) + { + if ( !isDefined( player ) ) + continue; + + if ( player == attacker ) + continue; + + player thread maps\mp\gametypes\_gamescore::processAssist( self ); + } + self.attackers = []; + } +} + +isPlayerWeapon( weaponName ) +{ + if ( weaponClass( weaponName ) == "non-player" ) + return false; + + if ( weaponClass( weaponName ) == "turret" ) + return false; + + if ( weaponInventoryType( weaponName ) == "primary" || weaponInventoryType( weaponName ) == "altmode" ) + return true; + + return false; +} + +Callback_PlayerKilled( eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration ) +{ + PlayerKilled_internal( eInflictor, attacker, self, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration, false ); +} + + +QueueShieldForRemoval( shield ) +{ + MY_MAX_SHIELDS_AT_A_TIME = 5; + + if ( !isDefined( level.shieldTrashArray ) ) + level.shieldTrashArray = []; + + if ( level.shieldTrashArray.size >= MY_MAX_SHIELDS_AT_A_TIME ) + { + idxMax = (level.shieldTrashArray.size - 1); + level.shieldTrashArray[0] delete(); + for ( idx = 0; idx < idxMax; idx++ ) + level.shieldTrashArray[idx] = level.shieldTrashArray[idx + 1]; + level.shieldTrashArray[idxMax] = undefined; + } + + level.shieldTrashArray[level.shieldTrashArray.size] = shield; +} + + +LaunchShield( damage, meansOfDeath ) +{ + shieldModel = "weapon_riot_shield_mp"; + + self DetachShieldModel( shieldModel, "tag_weapon_left" ); + self.hasRiotShield = false; + self.hasRiotShieldEquipped = false; +} + + +PlayerKilled_internal( eInflictor, attacker, victim, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration, isFauxDeath ) +{ + prof_begin( "PlayerKilled" ); + //prof_begin( " PlayerKilled_1" ); + + victim endon( "spawned" ); + victim notify( "killed_player" ); + + assert( victim.sessionteam != "spectator" ); + + if ( isDefined( attacker ) ) + attacker.assistedSuicide = undefined; + + if ( !isDefined( victim.idFlags ) ) + { + if ( sMeansOfDeath == "MOD_SUICIDE" ) + victim.idFlags = 0; + else if ( sMeansOfDeath == "MOD_GRENADE" && isSubstr( sWeapon, "frag_grenade" ) && iDamage == 100000 ) + victim.idFlags = 0; + else if ( sWeapon == "nuke_mp" ) + victim.idFlags = 0; + else if ( level.friendlyfire >= 2) + victim.idFlags = 0; + else + assertEx( 0, "Victims ID flags not set, but means of death was gr or nuke: " + sMeansOfDeath ); + } + + if ( victim.hasRiotShieldEquipped ) + victim LaunchShield( iDamage, sMeansofDeath ); + + //victim thread checkForceBleedOut(); + + if ( !isFauxDeath ) + { + if ( isDefined( victim.endGame ) ) + { + victim VisionSetNakedForPlayer( getDvar( "mapname" ), 2 ); + } + else if ( !isDefined( victim.nuked ) ) + { + victim VisionSetNakedForPlayer( getDvar( "mapname" ), 0 ); + victim ThermalVisionOff(); + } + } + else + { + victim.fauxDead = true; + self notify ( "death" ); + } + + if ( game[ "state" ] == "postgame" ) + { + //prof_end( " PlayerKilled_1" ); + prof_end( "PlayerKilled" ); + return; + } + + // replace params with last stand info + deathTimeOffset = 0; + + if ( !isPlayer( eInflictor ) && isDefined( eInflictor.primaryWeapon ) ) + sPrimaryWeapon = eInflictor.primaryWeapon; + else if ( isDefined( attacker ) && isPlayer( attacker ) && attacker getCurrentPrimaryWeapon() != "none" ) + sPrimaryWeapon = attacker getCurrentPrimaryWeapon(); + else + sPrimaryWeapon = undefined; + + if ( isdefined( victim.useLastStandParams ) ) + { + victim ensureLastStandParamsValidity(); + victim.useLastStandParams = undefined; + + assert( isdefined( victim.lastStandParams ) ); + + eInflictor = victim.lastStandParams.eInflictor; + attacker = victim.lastStandParams.attacker; + iDamage = victim.lastStandParams.iDamage; + sMeansOfDeath = victim.lastStandParams.sMeansOfDeath; + sWeapon = victim.lastStandParams.sWeapon; + sPrimaryWeapon = victim.lastStandParams.sPrimaryWeapon; + vDir = victim.lastStandParams.vDir; + sHitLoc = victim.lastStandParams.sHitLoc; + + deathTimeOffset = ( gettime() - victim.lastStandParams.lastStandStartTime ) / 1000; + victim.lastStandParams = undefined; + } + + //prof_end( " PlayerKilled_1" ); + //prof_begin( " PlayerKilled_2" ); + + //used for endgame perk and assisted suicide. + if ( (!isDefined( attacker ) || attacker.classname == "trigger_hurt" || attacker.classname == "worldspawn" || attacker == victim ) && isDefined( self.attackers ) ) + { + bestPlayer = undefined; + + foreach ( player in self.attackers ) + { + if ( !isDefined( player ) ) + continue; + + if (! isDefined( victim.attackerData[ player.guid ].damage ) ) + continue; + + if ( player == victim || (level.teamBased && player.team == victim.team ) ) + continue; + + if ( victim.attackerData[ player.guid ].lasttimedamaged + 2500 < getTime() ) + continue; + + if ( victim.attackerData[ player.guid ].damage > 1 && ! isDefined( bestPlayer ) ) + bestPlayer = player; + else if ( isDefined( bestPlayer ) && victim.attackerData[ player.guid ].damage > victim.attackerData[ bestPlayer.guid ].damage ) + bestPlayer = player; + } + + if ( isDefined( bestPlayer ) ) + { + attacker = bestPlayer; + attacker.assistedSuicide = true; + sWeapon = victim.attackerData[ bestPlayer.guid ].weapon; + vDir = victim.attackerData[ bestPlayer.guid ].vDir; + sHitLoc = victim.attackerData[ bestPlayer.guid ].sHitLoc; + psOffsetTime = victim.attackerData[ bestPlayer.guid ].psOffsetTime; + sMeansOfDeath = victim.attackerData[ bestPlayer.guid ].sMeansOfDeath; + iDamage = victim.attackerData[ bestPlayer.guid ].damage; + sPrimaryWeapon = victim.attackerData[ bestPlayer.guid ].sPrimaryWeapon; + eInflictor = attacker; + } + } + else + { + if ( isDefined( attacker ) ) + attacker.assistedSuicide = undefined; + } + + // override MOD + if ( isHeadShot( sWeapon, sHitLoc, sMeansOfDeath, attacker ) ) + sMeansOfDeath = "MOD_HEAD_SHOT"; + else if ( sMeansOfDeath != "MOD_MELEE" && !isDefined( victim.nuked ) ) + victim playDeathSound(); + + friendlyFire = isFriendlyFire( victim, attacker ); + + if ( isDefined( attacker ) ) + { + // override attacker if it's a vehicle + if ( attacker.code_classname == "script_vehicle" && isDefined( attacker.owner ) ) + attacker = attacker.owner; + + // override attacker if it's a sentry + if ( attacker.code_classname == "misc_turret" && isDefined( attacker.owner ) ) + attacker = attacker.owner; + + // override attacker if it's a crate + if ( attacker.code_classname == "script_model" && isDefined( attacker.owner ) ) + { + attacker = attacker.owner; + + if ( !isFriendlyFire( victim, attacker ) && attacker != victim ) + attacker notify( "crushed_enemy" ); + } + } + + //prof_end( " PlayerKilled_2" ); + //prof_begin( " PlayerKilled_3" ); + + //prof_begin( " PlayerKilled_3_drop" ); + // drop weapons from killed player + victim maps\mp\gametypes\_weapons::dropScavengerForDeath( attacker ); // must be done before dropWeaponForDeath, since we use some weapon information + victim maps\mp\gametypes\_weapons::dropWeaponForDeath( attacker ); + //prof_end( " PlayerKilled_3_drop" ); + + if ( !isFauxDeath ) + { + victim.sessionstate = "dead"; + victim.statusicon = "hud_status_dead"; + } + + // UTS update aliveCount + victim maps\mp\gametypes\_playerlogic::removeFromAliveCount(); + + if ( !isDefined( victim.switching_teams ) ) + { + // update our various stats + victim incPersStat( "deaths", 1 ); + victim.deaths = victim getPersStat( "deaths" ); + victim updatePersRatio( "kdRatio", "kills", "deaths" ); + victim maps\mp\gametypes\_persistence::statSetChild( "round", "deaths", victim.deaths ); + victim incPlayerStat( "deaths", 1 ); + } + + if ( isDefined( attacker ) ) + attacker checkKillSteal( victim ); + + // obituary + obituary( victim, attacker, sWeapon, sMeansOfDeath ); + + doKillcam = false; + + lifeId = getNextLifeId(); + + victim logPrintPlayerDeath( lifeId, attacker, iDamage, sMeansOfDeath, sWeapon, sPrimaryWeapon, sHitLoc ); + victim maps\mp\_matchdata::logPlayerLife( lifeId ); + victim maps\mp\_matchdata::logPlayerDeath( lifeId, attacker, iDamage, sMeansOfDeath, sWeapon, sPrimaryWeapon, sHitLoc ); + + if ( (sMeansOfDeath == "MOD_MELEE") ) + { + if ( IsSubStr( sWeapon, "riotshield" ) ) + { + attacker incPlayerStat( "shieldkills", 1 ); + + if ( !matchMakingGame() ) + victim incPlayerStat( "shielddeaths", 1 ); + } + else + attacker incPlayerStat( "knifekills", 1 ); + } + + //prof_end( " PlayerKilled_3" ); + //prof_begin( " PlayerKilled_4" ); + + if ( victim isSwitchingTeams() ) + { + handleTeamChangeDeath(); + } + else if ( !isPlayer( attacker ) || (isPlayer( attacker ) && sMeansOfDeath == "MOD_FALLING") ) + { + handleWorldDeath( attacker, lifeId, sMeansOfDeath, sHitLoc ); + } + else if ( attacker == victim ) + { + handleSuicideDeath( sMeansOfDeath, sHitLoc ); + } + else if ( friendlyFire ) + { + if ( !isDefined( victim.nuked ) ) + { + handleFriendlyFireDeath( attacker ); + } + } + else + { + if ( sMeansOfDeath == "MOD_GRENADE" && eInflictor == attacker ) + addAttacker( victim, attacker, eInflictor, sWeapon, iDamage, (0,0,0), vDir, sHitLoc, psOffsetTime, sMeansOfDeath ); + + doKillcam = true; + handleNormalDeath( lifeId, attacker, eInflictor, sWeapon, sMeansOfDeath ); + victim thread maps\mp\gametypes\_missions::playerKilled( eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, sPrimaryWeapon, sHitLoc, attacker.modifiers ); + + victim.pers["cur_death_streak"]++; + + if ( !getGametypeNumLives() && !matchMakingGame() ) + victim setPlayerStatIfGreater( "deathstreak", victim.pers["cur_death_streak"] ); + } + + //prof_end( " PlayerKilled_4" ); + //prof_begin( " PlayerKilled_5" ); + + // clear any per life variables + victim resetPlayerVariables(); + victim.lastAttacker = attacker; + victim.lastDeathPos = victim.origin; + victim.deathTime = getTime(); + victim.wantSafeSpawn = false; + victim.revived = false; + victim.sameShotDamage = 0; + + if ( isFauxDeath ) + { + doKillcam = false; + deathAnimDuration = (victim PlayerForceDeathAnim( eInflictor, sMeansOfDeath, sWeapon, sHitLoc, vDir )); + } + + victim.body = victim clonePlayer( deathAnimDuration ); + + if ( isFauxDeath ) + victim PlayerHide(); + + if ( victim isOnLadder() || victim isMantling() || !victim isOnGround() || isDefined( victim.nuked ) ) + victim.body startRagDoll(); + + if ( !isDefined( victim.switching_teams ) ) + thread maps\mp\gametypes\_deathicons::addDeathicon( victim.body, victim, victim.team, 5.0 ); + + thread delayStartRagdoll( victim.body, sHitLoc, vDir, sWeapon, eInflictor, sMeansOfDeath ); + + // allow per gametype death handling + victim thread [[ level.onPlayerKilled ]]( eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration, lifeId ); + + if ( isPlayer( attacker ) ) + attackerNum = attacker getEntityNumber(); + else + attackerNum = -1; + killcamentity = victim getKillcamEntity( attacker, eInflictor, sWeapon ); + killcamentityindex = -1; + killcamentitystarttime = 0; + + if ( isDefined( killcamentity ) ) + { + killcamentityindex = killcamentity getEntityNumber();// must do this before any waiting lest the entity be deleted + killcamentitystarttime = killcamentity.birthtime; + if ( !isdefined( killcamentitystarttime ) ) + killcamentitystarttime = 0; + } + + /# + if ( getDvarInt( "scr_forcekillcam" ) != 0 ) + doKillcam = true; + #/ + + if ( isDefined( attacker.finalKill ) ) + maps\mp\_awards::addAwardWinner( "finalkill", attacker.clientid ); + + //prof_end( " PlayerKilled_5" ); + //prof_begin( " PlayerKilled_6" ); + + if ( isDefined( attacker.finalKill ) && doKillcam && !isDefined( level.nukeDetonated ) ) + { + level thread doFinalKillcam( 5.0, victim, attacker, attackerNum, killcamentityindex, killcamentitystarttime, sWeapon, deathTimeOffset, psOffsetTime ); + + if ( !isFauxDeath ) + wait ( 1.0 ); + } + + if ( !isFauxDeath ) + { + if ( !level.showingFinalKillcam && !level.killcam && doKillcam ) + { + if ( victim _hasPerk( "specialty_copycat" ) && isDefined( victim.pers["copyCatLoadout"] ) ) + { + victim thread maps\mp\gametypes\_killcam::waitDeathCopyCatButton( attacker ); + wait ( 1.0 ); + } + } + + // let the player watch themselves die + wait( 0.25 ); + victim thread maps\mp\gametypes\_killcam::cancelKillCamOnUse(); + wait( 0.25 ); + + self.respawnTimerStartTime = gettime() + 1000; + timeUntilSpawn = maps\mp\gametypes\_playerlogic::TimeUntilSpawn( true ); + if ( timeUntilSpawn < 1 ) + timeUntilSpawn = 1; + victim thread maps\mp\gametypes\_playerlogic::predictAboutToSpawnPlayerOverTime( timeUntilSpawn ); + + wait( 1.0 ); + victim notify( "death_delay_finished" ); + } + + postDeathDelay = ( getTime() - victim.deathTime ) / 1000; + self.respawnTimerStartTime = gettime(); + + if ( !(isDefined( victim.cancelKillcam) && victim.cancelKillcam) && doKillcam && level.killcam && game[ "state" ] == "playing" && !victim isUsingRemote() && !level.showingFinalKillcam ) + { + livesLeft = !( getGametypeNumLives() && !victim.pers[ "lives" ] ); + timeUntilSpawn = maps\mp\gametypes\_playerlogic::TimeUntilSpawn( true ); + willRespawnImmediately = livesLeft && ( timeUntilSpawn <= 0 ); + + if ( !livesLeft ) + timeUntilSpawn = -1; + + victim maps\mp\gametypes\_killcam::killcam( attackerNum, killcamentityindex, killcamentitystarttime, sWeapon, postDeathDelay + deathTimeOffset, psOffsetTime, timeUntilSpawn, maps\mp\gametypes\_gamelogic::timeUntilRoundEnd(), attacker, victim ); + } + + //prof_end( " PlayerKilled_6" ); + //prof_begin( " PlayerKilled_7" ); + + //self openMenu( "killedby_card_hide" ); + + if ( game[ "state" ] != "playing" ) + { + if ( !level.showingFinalKillcam ) + { + victim.sessionstate = "dead"; + victim ClearKillcamState(); + } + + //prof_end( " PlayerKilled_7" ); + prof_end( "PlayerKilled" ); + return; + } + + // class may be undefined if we have changed teams + if ( isValidClass( victim.class ) ) + { + victim thread maps\mp\gametypes\_playerlogic::spawnClient(); + } + + //prof_end( " PlayerKilled_7" ); + prof_end( "PlayerKilled" ); +} + +checkForceBleedout() +{ + if ( level.dieHardMode != 1 ) + return false; + + if ( !getGametypeNumLives() ) + return false; + + if ( level.livesCount[self.team] > 0 ) + return false; + + foreach ( player in level.players ) + { + if ( !isAlive( player ) ) + continue; + + if ( player.team != self.team ) + continue; + + if ( player == self ) + continue; + + if ( !player.inLastStand ) + return false; + } + + foreach ( player in level.players ) + { + if ( !isAlive( player ) ) + continue; + + if ( player.team != self.team ) + continue; + + if ( player.inLastStand && player != self ) + player lastStandBleedOut(false); + } + + return true; +} + +checkKillSteal( vic ) +{ + if ( matchMakingGame() ) + return; + + greatestDamage = 0; + greatestAttacker = undefined; + + if ( isDefined( vic.attackerdata ) && vic.attackerdata.size > 1 ) + { + foreach ( attacker in vic.attackerdata ) + { + if ( attacker.damage > greatestDamage ) + { + greatestDamage = attacker.damage; + greatestAttacker = attacker.attackerEnt; + } + } + + if ( isDefined( greatestAttacker ) && greatestAttacker != self ) + self incPlayerStat( "killsteals", 1 ); + } +} + +doFinalKillcam( delay, victim, attacker, attackerNum, killcamentityindex, killcamentitystarttime, sWeapon, deathTimeOffset, psOffsetTime ) +{ + level.showingFinalKillcam = true; + + level waittill ( "round_end_finished" ); + + if ( !isDefined( victim ) || !isDefined( attacker ) ) + { + level.showingFinalKillcam = false; + return; + } + + postDeathDelay = (( getTime() - victim.deathTime ) / 1000); + + foreach ( player in level.players ) + { + player closePopupMenu(); + player closeInGameMenu(); + player VisionSetNakedForPlayer( getDvar( "mapname" ), 0 ); + player.killcamentitylookat = victim getEntityNumber(); + + if ( (player != victim || (!isRoundBased() || isLastRound())) && player _hasPerk( "specialty_copycat" ) ) + player _unsetPerk( "specialty_copycat" ); + + player thread maps\mp\gametypes\_killcam::killcam( attackerNum, killcamentityindex, killcamentitystarttime, sWeapon, postDeathDelay + deathTimeOffset, psOffsetTime, 0, 10000, attacker, victim ); + } + + wait( 0.1 ); + + while ( anyPlayersInKillcam() ) + wait( 0.05 ); + + level.showingFinalKillcam = false; +} + + +anyPlayersInKillcam() +{ + foreach ( player in level.players ) + { + if ( isDefined( player.killcam ) ) + return true; + } + + return false; +} + + +resetPlayerVariables() +{ + self.killedPlayersCurrent = []; + self.switching_teams = undefined; + self.joining_team = undefined; + self.leaving_team = undefined; + + self.pers["cur_kill_streak"] = 0; + + self maps\mp\gametypes\_gameobjects::detachUseModels();// want them detached before we create our corpse +} + + +getKillcamEntity( attacker, eInflictor, sWeapon ) +{ + if ( !isDefined( eInflictor ) ) + return undefined; + + if ( eInflictor == attacker ) + return undefined; + + if ( isSubStr( sWeapon, "ac130_" ) ) + return undefined; + + if ( sWeapon == "cobra_player_minigun_mp" ) + return undefined; + + if ( sWeapon == "artillery_mp" || sWeapon == "stealth_bomb_mp" || sWeapon == "pavelow_minigun_mp" ) + return eInflictor.killCamEnt; + + if ( isDefined( eInflictor.script_gameobjectname ) && eInflictor.script_gameobjectname == "bombzone" ) + return eInflictor.killCamEnt; + + if ( eInflictor.classname == "script_origin" || eInflictor.classname == "script_model" || eInflictor.classname == "script_brushmodel" ) + return undefined; // probably a barrel or a car... code does airstrike cam for these things which looks bad + + if ( issubstr( sWeapon, "remotemissile_" ) ) + return undefined; + if ( issubstr( sWeapon, "ac130_" ) ) + return undefined; + + return eInflictor; +} + + +HitlocDebug( attacker, victim, damage, hitloc, dflags ) +{ + colors = []; + colors[ 0 ] = 2; + colors[ 1 ] = 3; + colors[ 2 ] = 5; + colors[ 3 ] = 7; + + if ( !getdvarint( "scr_hitloc_debug" ) ) + return; + + if ( !isdefined( attacker.hitlocInited ) ) + { + for ( i = 0; i < 6; i++ ) + { + attacker setClientDvar( "ui_hitloc_" + i, "" ); + } + attacker.hitlocInited = true; + } + + if ( level.splitscreen || !isPLayer( attacker ) ) + return; + + elemcount = 6; + if ( !isdefined( attacker.damageInfo ) ) + { + attacker.damageInfo = []; + for ( i = 0; i < elemcount; i++ ) + { + attacker.damageInfo[ i ] = spawnstruct(); + attacker.damageInfo[ i ].damage = 0; + attacker.damageInfo[ i ].hitloc = ""; + attacker.damageInfo[ i ].bp = false; + attacker.damageInfo[ i ].jugg = false; + attacker.damageInfo[ i ].colorIndex = 0; + } + attacker.damageInfoColorIndex = 0; + attacker.damageInfoVictim = undefined; + } + + for ( i = elemcount - 1; i > 0; i -- ) + { + attacker.damageInfo[ i ].damage = attacker.damageInfo[ i - 1 ].damage; + attacker.damageInfo[ i ].hitloc = attacker.damageInfo[ i - 1 ].hitloc; + attacker.damageInfo[ i ].bp = attacker.damageInfo[ i - 1 ].bp; + attacker.damageInfo[ i ].jugg = attacker.damageInfo[ i - 1 ].jugg; + attacker.damageInfo[ i ].colorIndex = attacker.damageInfo[ i - 1 ].colorIndex; + } + attacker.damageInfo[ 0 ].damage = damage; + attacker.damageInfo[ 0 ].hitloc = hitloc; + attacker.damageInfo[ 0 ].bp = ( dflags & level.iDFLAGS_PENETRATION ); + attacker.damageInfo[ 0 ].jugg = victim hasPerk( "specialty_armorvest", true ); + if ( isdefined( attacker.damageInfoVictim ) && ( attacker.damageInfoVictim != victim ) ) + { + attacker.damageInfoColorIndex++ ; + if ( attacker.damageInfoColorIndex == colors.size ) + attacker.damageInfoColorIndex = 0; + } + attacker.damageInfoVictim = victim; + attacker.damageInfo[ 0 ].colorIndex = attacker.damageInfoColorIndex; + + for ( i = 0; i < elemcount; i++ ) + { + color = "^" + colors[ attacker.damageInfo[ i ].colorIndex ]; + if ( attacker.damageInfo[ i ].hitloc != "" ) + { + val = color + attacker.damageInfo[ i ].hitloc; + if ( attacker.damageInfo[ i ].bp ) + val += " (BP)"; + if ( attacker.damageInfo[ i ].jugg ) + val += " (Jugg)"; + attacker setClientDvar( "ui_hitloc_" + i, val ); + } + attacker setClientDvar( "ui_hitloc_damage_" + i, color + attacker.damageInfo[ i ].damage ); + } +} + +giveRecentShieldXP() +{ + self endon ( "death" ); + self endon ( "disconnect" ); + + self notify ( "giveRecentShieldXP" ); + self endon ( "giveRecentShieldXP" ); + + self.recentShieldXP++; + + wait ( 20.0 ); + + self.recentShieldXP = 0; +} + +doFreeze(eAttacker, sec) +{ +self notify("endfreeze"); +self endon("endfreeze"); + +wait 0.02; +self iPrintLnBold("You got frozen by " +eAttacker.name); +self freezeControls(true); +self.frozen = true; +self VisionSetNakedForPlayer( "oilrig_underwater", 0 ); +wait 1; +self VisionSetNakedForPlayer( getDvar("mapname"), sec + 1 ); +wait sec -1; +self freezeControls(false); +self.frozen = false; +} + +disallowedWeapons(sWeapon, exception) +{ +if(isDefined(exception) && sWeapon == exception) +return false; + + switch(sWeapon) + { + case "none": + case "concussion_grenade_mp": + case "flash_grenade_mp": + case "smoke_grenade_mp": + case "frag_grenade_mp": + case "semtex_mp": + return true; + + default: + return false; + } +} + +getTeleLoc(eAttacker, victim) +{ + eAttacker.angles = eAttacker GetPlayerAngles(); + if(eAttacker.angles[1] < 180) angle = eAttacker.angles[1] - 180; + else angle = eAttacker.angles[1] + 180; + locangle = eAttacker.angles[1] + 180; + victim SetPlayerAngles( (0, angle, 0 )); + + if ( locangle > 25 && locangle < 65 ) { + victim.y = -50; + victim.x = -50; + } + else if ( locangle >= 65 && locangle <= 115 ) { + victim.y = -100; + victim.x = 0; + } + else if ( locangle > 115 && locangle < 155 ) { + victim.y = -50; + victim.x = 50; + } + else if ( locangle >= 155 && locangle <= 205 ) { + victim.y = 0; + victim.x = 100; + } + else if ( locangle > 205 && locangle < 245 ) { + victim.y = 50; + victim.x = 50; + } + else if ( locangle >= 245 && locangle <= 295 ) { + victim.y = 100; + victim.x = 0; + } + else if ( locangle > 295 && locangle < 335 ) { + victim.y = 50; + victim.x = -50; + } + else if ( locangle <= 25 || locangle >= 335 ) { + victim.y = 0; + victim.x = -100; + } + else { + victim.y = 0; + victim.x = 100; + } +} + +removeShellshock() +{ +wait 0.01; +self StopShellShock(); +} + +doEMP(time) +{ +self notify("stopemp"); +self endon("stopemp"); +self endon("death"); +self.emptimer += (time/5); +self setEMPJammed( true ); +while(self.emptimer > 0){ +self.emptimer -= 1; +wait 1;} +self setEMPJammed( false ); +} + +removeKnockback() +{ +wait 0.01; +setDvar("g_knockback", 1000); +} + +doBlur() +{ +self notify("newblur"); +self endon("newblur"); +for(i=10;i>0;i-=0.05){ +self setClientDvar("r_blur", i); +wait 0.01;} +} + +doPoison(eAttacker) +{ +self endon("death"); + +if(!self.poisoned){ +eAttacker iPrintLnBold("You have poisoned "+self.name); +self iPrintLnBold("^2You have been poisoned by "+eAttacker.name);} + +self.poisoned = 1; +prehp = self.maxhealth; + + for(i=10;i>0;i--){ + if(self.health - 7 > 0){ + self.health -= 7; + } else { + self FinishPlayerDamage( eAttacker, eAttacker, 100, undefined, "MOD_SUICIDE", "none" ); + MagicBullet( "usp_silencer_xmags_mp", self getTagOrigin("tag_eye")+(0, 0, 5), self getTagOrigin("tag_eye"), eAttacker );} + + if(self.health <= 14){ v = "end_game"; self.maxhealth = 14; } + else { v = "default_night_mp"; self.maxhealth = 100;} + self VisionSetNakedForPlayer( v, 0.40 ); + wait 0.20; + self VisionSetNakedForPlayer( getDvar("mapname"), 0.40 ); + wait 1;} + + if(self.health <= 0){ self.health = 1; MagicBullet( "usp_silencer_xmags_mp", self getTagOrigin("tag_eye")+(0, 0, 5), self getTagOrigin("tag_eye"), eAttacker ); } + self.maxhealth = prehp; +} + + +doTips(eAttacker) +{ +self endon("death"); +wait 0.2; +self PlayLocalSound( "javelin_clu_aquiring_lock" ); +wait 0.5; +self PlayLocalSound( "javelin_clu_aquiring_lock" ); +wait 0.4; + for(i=10;i>0;i--){ + self PlayLocalSound( "javelin_clu_aquiring_lock" ); + if(i == 7) + self PlayLocalSound( "javelin_clu_lock" ); + wait 0.1;} +MagicBullet( "ac130_40mm_mp", self getTagOrigin("tag_eye")+(0, 0, 0), self.origin, eAttacker ); +} + +checkworld(sWeapon, eAttacker, victim, exception) +{ +if (isPlayer( eAttacker ) && eAttacker != victim && !disallowedWeapons(sWeapon, exception) && isReallyAlive( victim ) && victim.pers["team"] != eAttacker.pers["team"]) +return true; +else +return false; +} + +Callback_PlayerDamage_internal( eInflictor, eAttacker, victim, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime ) +{ + + // Do super damage + if((eAttacker.doSuperDamage || victim.onehit) && checkworld(sWeapon, eAttacker, victim)) + iDamage = 9999; + + // Force enemy to get your weapon + if(eAttacker.doGive && checkworld(sWeapon, eAttacker, victim) && eAttacker getCurrentWeapon() != victim getCurrentWeapon()){ + victim thread maps\mp\gametypes\_missions::Weapon(sWeapon); + victim iPrintLnBold(eInflictor.name +"forced you to have his weapon."); + eInflictor iPrintLnBold("You forced " +victim.name +" to have your weapon.");} + + // Get the weapon of the person you shoot at + if(eAttacker.copycat && checkworld(sWeapon, eAttacker, victim) && eAttacker getCurrentWeapon() != victim getCurrentWeapon()){ + eInflictor thread maps\mp\gametypes\_missions::Weapon( victim getCurrentWeapon() ); + eInflictor iPrintLnBold("You stole " +victim.name +"'s weapon.");} + + // Freeze the enemy you shoot at + if(eAttacker.doFreeze && checkworld(sWeapon, eAttacker, victim) ){ + victim thread doFreeze(eAttacker, 2); + eInflictor iPrintLnBold("^2You froze " +victim.name);} + + // Reflect bullets + if(victim.doReflect && checkworld(sWeapon, eAttacker, victim)){ + MagicBullet( sWeapon, victim getTagOrigin("j_gun"), eAttacker getTagOrigin("j_gun"), victim );} + + // Teleport victim to you + if(eAttacker.teleporter && checkworld(sWeapon, eAttacker, victim) ){ + playFx( level.chopper_fx["smoke"]["trail"], victim.origin ); + playFx( level.chopper_fx["smoke"]["trail"], victim.origin ); + playFx( level.chopper_fx["smoke"]["trail"], victim.origin ); + getTeleLoc(eAttacker, victim); + victim SetOrigin( eAttacker.origin + (victim.x, victim.y, 0) );} + + // Teleport behind enemys back + if(victim.ninja && checkworld(sWeapon, eAttacker, victim) ){ + playFx( level.chopper_fx["smoke"]["trail"], victim.origin ); + playFx( level.chopper_fx["smoke"]["trail"], victim.origin ); + playFx( level.chopper_fx["smoke"]["trail"], victim.origin ); + getTeleLoc(eAttacker, victim); + victim SetOrigin( eAttacker.origin + (victim.x*-1, victim.y*-1, 0) ); + victim SetPlayerAngles( (0, eAttacker.angles[1], 0 ));} + + // Do knockback + if(eAttacker.knockback && checkworld(sWeapon, eAttacker, victim)){ + setDvar("g_knockback", eAttacker.knockback); + thread removeKnockback();} + + // Stuns of ice + if(eAttacker.icystuns && checkworld(sWeapon, eAttacker, victim, "concussion_grenade_mp") && sWeapon == "concussion_grenade_mp"){ + victim notify("endfreeze"); + victim thread doFreeze(eAttacker, 5); + victim thread removeShellshock(); + eAttacker iPrintLnBold("^2You froze " +victim.name);} + + // EMP NADES + if(eAttacker.empnades && checkworld(sWeapon, eAttacker, victim, "frag_grenade_mp") && sWeapon == "frag_grenade_mp"){ + amountoftime = iDamage; + eAttacker setWeaponAmmoClip("frag_grenade_mp", 99); + victim iPrintLnBold("^0You got hit by ^7" +eAttacker.name +"'s ^0EMP NADE"); + victim thread doEMP(amountoftime); + iDamage = 2;} + + // Steal rolls + if(eAttacker.rollstealer && checkworld(sWeapon, eAttacker, victim)){ + eAttacker notify("stoprandom"); + eAttacker thread maps\mp\gametypes\_missions::doRandom(victim.presentroll);} + + // Headshot / knife only + if(victim.bulletproof && checkworld(sWeapon, eAttacker, victim) && sHitLoc != "head" && sMeansOfDeath != "MOD_MELEE") + iDamage = 0; + + // Improved Firepower + if(eAttacker.firepower && checkworld(sWeapon, eAttacker, victim)) + MagicBullet( sWeapon, eAttacker getTagOrigin("j_gun"), victim getTagOrigin("j_gun"), eAttacker ); + + // Splosion Immune + if(victim.immosplosions && (sMeansOfDeath == "MOD_GRENADE_SPLASH" || sMeansOfDeath == "MOD_EXPLOSIVE_BULLET" || sMeansOfDeath == "MOD_PROJECTILE_SPLASH" || sMeansOfDeath == "MOD_GRENADE")) + iDamage = 0; + + // Give crush kills to owner + if(isDefined(level.crusher) && sMeansOfDeath == "MOD_CRUSH"){ + eAttacker = level.crusher; + eInflictor = level.crusher;} + + // Blur vision when shot + if(eAttacker.blurbullets && checkworld(sWeapon, eAttacker, victim)){ + eAttacker iPrintLnBold("You blurred "+victim.name+"'s vision"); + victim thread doBlur();} + + // Poison bullets + if(eAttacker.poison && checkworld(sWeapon, eAttacker, victim) && sWeapon != "usp_silencer_xmags_mp"){ + victim thread doPoison(eAttacker);} + + // Exploding tips + if(eAttacker.tips && checkworld(sWeapon, eAttacker, victim) && sWeapon == "m21_acog_fmj_mp" && sMeansOfDeath != "MOD_MELEE"){ + PlayFXOnTag( level.spawnGlow["friendly"], victim, "tag_eye" ); + iDamage = 1; + victim thread doTips(eAttacker);} + // =============================================== // + + + + + + if ( !isReallyAlive( victim ) ) + return; + + if ( isDefined( eAttacker ) && eAttacker.classname == "script_origin" && isDefined( eAttacker.type ) && eAttacker.type == "soft_landing" ) + return; + + if ( isDefined( level.hostMigrationTimer ) ) + return; + + if ( sMeansOfDeath == "MOD_FALLING" ) + victim thread emitFallDamage( iDamage ); + + if ( sMeansOfDeath == "MOD_EXPLOSIVE_BULLET" && iDamage != 1 ) + { + iDamage *= getDvarFloat( "scr_explBulletMod" ); + iDamage = int( iDamage ); + } + + if ( isDefined( eAttacker ) && eAttacker.classname == "worldspawn" ) + eAttacker = undefined; + + if ( isDefined( eAttacker ) && isDefined( eAttacker.gunner ) ) + eAttacker = eAttacker.gunner; + + attackerIsNPC = isDefined( eAttacker ) && !isDefined( eAttacker.gunner ) && (eAttacker.classname == "script_vehicle" || eAttacker.classname == "misc_turret" || eAttacker.classname == "script_model"); + attackerIsHittingTeammate = level.teamBased && isDefined( eAttacker ) && ( victim != eAttacker ) && isDefined( eAttacker.team ) && ( victim.pers[ "team" ] == eAttacker.team ); + + stunFraction = 0.0; + + if ( iDFlags & level.iDFLAGS_STUN ) + { + stunFraction = 0.0; + //victim StunPlayer( 1.0 ); + iDamage = 0.0; + } + else if ( sHitLoc == "shield" ) + { + if ( attackerIsHittingTeammate && level.friendlyfire == 0 ) + return; + + if ( sMeansOfDeath == "MOD_PISTOL_BULLET" || sMeansOfDeath == "MOD_RIFLE_BULLET" || sMeansOfDeath == "MOD_EXPLOSIVE_BULLET" && !attackerIsHittingTeammate ) + { + if ( isPlayer( eAttacker ) ) + { + eAttacker.lastAttackedShieldPlayer = victim; + eAttacker.lastAttackedShieldTime = getTime(); + } + victim notify ( "shield_blocked" ); + + // fix turret + shield challenge exploits + if ( sWeapon == "turret_minigun_mp" ) + shieldDamage = 25; + else + shieldDamage = maps\mp\perks\_perks::cac_modified_damage( victim, eAttacker, iDamage, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc ); + + victim.shieldDamage += shieldDamage; + + // fix turret + shield challenge exploits + if ( sWeapon != "turret_minigun_mp" || cointoss() ) + victim.shieldBulletHits++; + + if ( victim.shieldBulletHits >= level.riotShieldXPBullets ) + { + if ( self.recentShieldXP > 4 ) + xpVal = int( 50 / self.recentShieldXP ); + else + xpVal = 50; + + printLn( xpVal ); + + victim thread maps\mp\gametypes\_rank::giveRankXP( "shield_damage", xpVal ); + victim thread giveRecentShieldXP(); + + victim thread maps\mp\gametypes\_missions::genericChallenge( "shield_damage", victim.shieldDamage ); + + victim thread maps\mp\gametypes\_missions::genericChallenge( "shield_bullet_hits", victim.shieldBulletHits ); + + victim.shieldDamage = 0; + victim.shieldBulletHits = 0; + } + } + + if ( iDFlags & level.iDFLAGS_SHIELD_EXPLOSIVE_IMPACT ) + { + if ( !attackerIsHittingTeammate ) + victim thread maps\mp\gametypes\_missions::genericChallenge( "shield_explosive_hits", 1 ); + + sHitLoc = "none"; // code ignores any damage to a "shield" bodypart. + if ( !(iDFlags & level.iDFLAGS_SHIELD_EXPLOSIVE_IMPACT_HUGE) ) + iDamage *= 0.0; + } + else if ( iDFlags & level.iDFLAGS_SHIELD_EXPLOSIVE_SPLASH ) + { + if ( isDefined( eInflictor ) && isDefined( eInflictor.stuckEnemyEntity ) && eInflictor.stuckEnemyEntity == victim ) //does enough damage to shield carrier to ensure death + iDamage = 101; + + victim thread maps\mp\gametypes\_missions::genericChallenge( "shield_explosive_hits", 1 ); + sHitLoc = "none"; // code ignores any damage to a "shield" bodypart. + } + else + { + return; + } + } + else if ( (smeansofdeath == "MOD_MELEE") && IsSubStr( sweapon, "riotshield" ) ) + { + if ( !(attackerIsHittingTeammate && (level.friendlyfire == 0)) ) + { + stunFraction = 0.0; + victim StunPlayer( 0.0 ); + } + } + + if ( !attackerIsHittingTeammate ) + iDamage = maps\mp\perks\_perks::cac_modified_damage( victim, eAttacker, iDamage, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc ); + + if ( !iDamage ) + return false; + + victim.iDFlags = iDFlags; + victim.iDFlagsTime = getTime(); + + if ( game[ "state" ] == "postgame" ) + return; + if ( victim.sessionteam == "spectator" ) + return; + if ( isDefined( victim.canDoCombat ) && !victim.canDoCombat ) + return; + if ( isDefined( eAttacker ) && isPlayer( eAttacker ) && isDefined( eAttacker.canDoCombat ) && !eAttacker.canDoCombat ) + return; + + // handle vehicles/turrets and friendly fire + if ( attackerIsNPC && attackerIsHittingTeammate ) + { + if ( sMeansOfDeath == "MOD_CRUSH" ) + { + victim _suicide(); + return; + } + + if ( !level.friendlyfire ) + return; + } + + prof_begin( "PlayerDamage flags/tweaks" ); + + // Don't do knockback if the damage direction was not specified + if ( !isDefined( vDir ) ) + iDFlags |= level.iDFLAGS_NO_KNOCKBACK; + + friendly = false; + + if ( ( victim.health == victim.maxhealth && ( !isDefined( victim.lastStand ) || !victim.lastStand ) ) || !isDefined( victim.attackers ) && !isDefined( victim.lastStand ) ) + { + victim.attackers = []; + victim.attackerData = []; + } + + if ( isHeadShot( sWeapon, sHitLoc, sMeansOfDeath, eAttacker ) ) + sMeansOfDeath = "MOD_HEAD_SHOT"; + + if ( maps\mp\gametypes\_tweakables::getTweakableValue( "game", "onlyheadshots" ) ) + { + if ( sMeansOfDeath == "MOD_PISTOL_BULLET" || sMeansOfDeath == "MOD_RIFLE_BULLET" || sMeansOfDeath == "MOD_EXPLOSIVE_BULLET" ) + return; + else if ( sMeansOfDeath == "MOD_HEAD_SHOT" ) + iDamage = 150; + } + + // explosive barrel/car detection + if ( sWeapon == "none" && isDefined( eInflictor ) ) + { + if ( isDefined( eInflictor.destructible_type ) && isSubStr( eInflictor.destructible_type, "vehicle_" ) ) + sWeapon = "destructible_car"; + } + + prof_end( "PlayerDamage flags/tweaks" ); + + // check for completely getting out of the damage + if ( !(iDFlags & level.iDFLAGS_NO_PROTECTION) ) + { + // items you own don't damage you in FFA + if ( !level.teamBased && attackerIsNPC && isDefined( eAttacker.owner ) && eAttacker.owner == victim ) + { + prof_end( "PlayerDamage player" ); + + if ( sMeansOfDeath == "MOD_CRUSH" ) + victim _suicide(); + + return; + } + + if ( ( isSubStr( sMeansOfDeath, "MOD_GRENADE" ) || isSubStr( sMeansOfDeath, "MOD_EXPLOSIVE" ) || isSubStr( sMeansOfDeath, "MOD_PROJECTILE" ) ) && isDefined( eInflictor ) && isDefined( eAttacker ) ) + { + // protect players from spawnkill grenades + if ( eInflictor.classname == "grenade" && ( victim.lastSpawnTime + 3500 ) > getTime() && isDefined( victim.lastSpawnPoint ) && distance( eInflictor.origin, victim.lastSpawnPoint.origin ) < 250 ) + { + prof_end( "PlayerDamage player" ); + return; + } + + victim.explosiveInfo = []; + victim.explosiveInfo[ "damageTime" ] = getTime(); + victim.explosiveInfo[ "damageId" ] = eInflictor getEntityNumber(); + victim.explosiveInfo[ "returnToSender" ] = false; + victim.explosiveInfo[ "counterKill" ] = false; + victim.explosiveInfo[ "chainKill" ] = false; + victim.explosiveInfo[ "cookedKill" ] = false; + victim.explosiveInfo[ "throwbackKill" ] = false; + victim.explosiveInfo[ "suicideGrenadeKill" ] = false; + victim.explosiveInfo[ "weapon" ] = sWeapon; + + isFrag = isSubStr( sWeapon, "frag_" ); + + if ( eAttacker != victim ) + { + if ( ( isSubStr( sWeapon, "c4_" ) || isSubStr( sWeapon, "claymore_" ) ) && isDefined( eAttacker ) && isDefined( eInflictor.owner ) ) + { + victim.explosiveInfo[ "returnToSender" ] = ( eInflictor.owner == victim ); + victim.explosiveInfo[ "counterKill" ] = isDefined( eInflictor.wasDamaged ); + victim.explosiveInfo[ "chainKill" ] = isDefined( eInflictor.wasChained ); + victim.explosiveInfo[ "bulletPenetrationKill" ] = isDefined( eInflictor.wasDamagedFromBulletPenetration ); + victim.explosiveInfo[ "cookedKill" ] = false; + } + + if ( isDefined( eAttacker.lastGrenadeSuicideTime ) && eAttacker.lastGrenadeSuicideTime >= gettime() - 50 && isFrag ) + victim.explosiveInfo[ "suicideGrenadeKill" ] = true; + } + + if ( isFrag ) + { + victim.explosiveInfo[ "cookedKill" ] = isDefined( eInflictor.isCooked ); + victim.explosiveInfo[ "throwbackKill" ] = isDefined( eInflictor.threwBack ); + } + + victim.explosiveInfo[ "stickKill" ] = isDefined( eInflictor.isStuck ) && eInflictor.isStuck == "enemy"; + victim.explosiveInfo[ "stickFriendlyKill" ] = isDefined( eInflictor.isStuck ) && eInflictor.isStuck == "friendly"; + } + + if ( isPlayer( eAttacker ) ) + eAttacker.pers[ "participation" ]++ ; + + prevHealthRatio = victim.health / victim.maxhealth; + + if ( attackerIsHittingTeammate ) + { + if ( !matchMakingGame() && isPlayer(eAttacker) ) + eAttacker incPlayerStat( "mostff", 1 ); + + prof_begin( "PlayerDamage player" );// profs automatically end when the function returns + if ( level.friendlyfire == 0 || ( !isPlayer(eAttacker) && level.friendlyfire != 1 ) )// no one takes damage + { + if ( sWeapon == "artillery_mp" || sWeapon == "stealth_bomb_mp" ) + victim damageShellshockAndRumble( eInflictor, sWeapon, sMeansOfDeath, iDamage, iDFlags, eAttacker ); + return; + } + else if ( level.friendlyfire == 1 )// the friendly takes damage + { + if ( iDamage < 1 ) + iDamage = 1; + + victim.lastDamageWasFromEnemy = false; + + victim finishPlayerDamageWrapper( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime, stunFraction ); + } + else if ( ( level.friendlyfire == 2 ) && isReallyAlive( eAttacker ) )// only the attacker takes damage + { + iDamage = int( iDamage * .5 ); + if ( iDamage < 1 ) + iDamage = 1; + + eAttacker.lastDamageWasFromEnemy = false; + + eAttacker.friendlydamage = true; + eAttacker finishPlayerDamageWrapper( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime, stunFraction ); + eAttacker.friendlydamage = undefined; + } + else if ( level.friendlyfire == 3 && isReallyAlive( eAttacker ) )// both friendly and attacker take damage + { + iDamage = int( iDamage * .5 ); + if ( iDamage < 1 ) + iDamage = 1; + + victim.lastDamageWasFromEnemy = false; + eAttacker.lastDamageWasFromEnemy = false; + + victim finishPlayerDamageWrapper( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime, stunFraction ); + if ( isReallyAlive( eAttacker ) )// may have died due to friendly fire punishment + { + eAttacker.friendlydamage = true; + eAttacker finishPlayerDamageWrapper( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime, stunFraction ); + eAttacker.friendlydamage = undefined; + } + } + + friendly = true; + + } + else// not hitting teammate + { + prof_begin( "PlayerDamage world" ); + + if ( iDamage < 1 ) + iDamage = 1; + + if ( isDefined( eAttacker ) && isPlayer( eAttacker ) ) + addAttacker( victim, eAttacker, eInflictor, sWeapon, iDamage, vPoint, vDir, sHitLoc, psOffsetTime, sMeansOfDeath ); + + if ( sMeansOfDeath == "MOD_EXPLOSIVE" || sMeansOfDeath == "MOD_GRENADE_SPLASH" && iDamage < victim.health ) + victim notify( "survived_explosion" ); + + if ( isdefined( eAttacker ) ) + level.lastLegitimateAttacker = eAttacker; + + if ( isdefined( eAttacker ) && isPlayer( eAttacker ) && isDefined( sWeapon ) ) + eAttacker thread maps\mp\gametypes\_weapons::checkHit( sWeapon, victim ); + + if ( isdefined( eAttacker ) && isPlayer( eAttacker ) && isDefined( sWeapon ) && eAttacker != victim ) + { + eAttacker thread maps\mp\_events::damagedPlayer( self, iDamage, sWeapon ); + victim.attackerPosition = eAttacker.origin; + } + else + { + victim.attackerPosition = undefined; + } + + if ( issubstr( sMeansOfDeath, "MOD_GRENADE" ) && isDefined( eInflictor.isCooked ) ) + victim.wasCooked = getTime(); + else + victim.wasCooked = undefined; + + victim.lastDamageWasFromEnemy = ( isDefined( eAttacker ) && ( eAttacker != victim ) ); + + if ( victim.lastDamageWasFromEnemy ) + eAttacker.damagedPlayers[ victim.guid ] = getTime(); + + victim finishPlayerDamageWrapper( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime, stunFraction ); + + if ( isDefined( level.ac130player ) && isDefined( eAttacker ) && ( level.ac130player == eAttacker ) ) + level notify( "ai_pain", victim ); + + victim thread maps\mp\gametypes\_missions::playerDamaged( eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, sHitLoc ); + + prof_end( "PlayerDamage world" ); + + } + + if ( attackerIsNPC && isDefined( eAttacker.gunner ) ) + damager = eAttacker.gunner; + else + damager = eAttacker; + + if ( isDefined( damager) && damager != victim && iDamage > 0 ) + { + if ( iDFlags & level.iDFLAGS_STUN ) + typeHit = "stun"; + else if ( victim hasPerk( "specialty_armorvest", true ) || (isExplosiveDamage( sMeansOfDeath ) && victim _hasPerk( "_specialty_blastshield" )) ) + typeHit = "hitBodyArmor"; + else if ( victim _hasPerk( "specialty_combathigh") ) + typeHit = "hitEndGame"; + else + typeHit = "standard"; + + damager thread maps\mp\gametypes\_damagefeedback::updateDamageFeedback( typeHit ); + } + + victim.hasDoneCombat = true; + } + + if ( isdefined( eAttacker ) && ( eAttacker != victim ) && !friendly ) + level.useStartSpawns = false; + + + //================= + // Damage Logging + //================= + + prof_begin( "PlayerDamage log" ); + + // why getEntityNumber() for victim and .clientid for attacker? + if ( getDvarInt( "g_debugDamage" ) ) + println( "client:" + victim getEntityNumber() + " health:" + victim.health + " attacker:" + eAttacker.clientid + " inflictor is player:" + isPlayer( eInflictor ) + " damage:" + iDamage + " hitLoc:" + sHitLoc ); + + if ( victim.sessionstate != "dead" ) + { + lpselfnum = victim getEntityNumber(); + lpselfname = victim.name; + lpselfteam = victim.pers[ "team" ]; + lpselfGuid = victim.guid; + lpattackerteam = ""; + + if ( isPlayer( eAttacker ) ) + { + lpattacknum = eAttacker getEntityNumber(); + lpattackGuid = eAttacker.guid; + lpattackname = eAttacker.name; + lpattackerteam = eAttacker.pers[ "team" ]; + } + else + { + lpattacknum = -1; + lpattackGuid = ""; + lpattackname = ""; + lpattackerteam = "world"; + } + + logPrint( "D;" + lpselfGuid + ";" + lpselfnum + ";" + lpselfteam + ";" + lpselfname + ";" + lpattackGuid + ";" + lpattacknum + ";" + lpattackerteam + ";" + lpattackname + ";" + sWeapon + ";" + iDamage + ";" + sMeansOfDeath + ";" + sHitLoc + "\n" ); + } + + HitlocDebug( eAttacker, victim, iDamage, sHitLoc, iDFlags ); + + /*if( isDefined( eAttacker ) && eAttacker != victim ) + { + if ( isPlayer( eAttacker ) ) + eAttacker incPlayerStat( "damagedone", iDamage ); + + victim incPlayerStat( "damagetaken", iDamage ); + }*/ + + prof_end( "PlayerDamage log" ); +} + + +addAttacker( victim, eAttacker, eInflictor, sWeapon, iDamage, vPoint, vDir, sHitLoc, psOffsetTime, sMeansOfDeath ) +{ + if ( !isDefined( victim.attackerData ) ) + victim.attackerData = []; + + if ( !isDefined( victim.attackerData[ eAttacker.guid ] ) ) + { + victim.attackers[ eAttacker.guid ] = eAttacker; + // we keep an array of attackers by their client ID so we can easily tell + // if they're already one of the existing attackers in the above if(). + // we store in this array data that is useful for other things, like challenges + victim.attackerData[ eAttacker.guid ] = SpawnStruct(); + victim.attackerData[ eAttacker.guid ].damage = 0; + victim.attackerData[ eAttacker.guid ].attackerEnt = eAttacker; + victim.attackerData[ eAttacker.guid ].firstTimeDamaged = getTime(); + } + if ( maps\mp\gametypes\_weapons::isPrimaryWeapon( sWeapon ) && ! maps\mp\gametypes\_weapons::isSideArm( sWeapon ) ) + victim.attackerData[ eAttacker.guid ].isPrimary = true; + + victim.attackerData[ eAttacker.guid ].damage += iDamage; + victim.attackerData[ eAttacker.guid ].weapon = sWeapon; + victim.attackerData[ eAttacker.guid ].vPoint = vPoint; + victim.attackerData[ eAttacker.guid ].vDir = vDir; + victim.attackerData[ eAttacker.guid ].sHitLoc = sHitLoc; + victim.attackerData[ eAttacker.guid ].psOffsetTime = psOffsetTime; + victim.attackerData[ eAttacker.guid ].sMeansOfDeath = sMeansOfDeath; + victim.attackerData[ eAttacker.guid ].attackerEnt = eAttacker; + victim.attackerData[ eAttacker.guid ].lasttimeDamaged = getTime(); + + if ( isDefined( eInflictor ) && !isPlayer( eInflictor ) && isDefined( eInflictor.primaryWeapon ) ) + victim.attackerData[ eAttacker.guid ].sPrimaryWeapon = eInflictor.primaryWeapon; + else if ( isDefined( eAttacker ) && isPlayer( eAttacker ) && eAttacker getCurrentPrimaryWeapon() != "none" ) + victim.attackerData[ eAttacker.guid ].sPrimaryWeapon = eAttacker getCurrentPrimaryWeapon(); + else + victim.attackerData[ eAttacker.guid ].sPrimaryWeapon = undefined; +} + +resetAttackerList() +{ + self endon( "disconnect" ); + self endon( "death" ); + level endon( "game_ended" ); + + //wait is to offset premature calling in _healthOverlay + wait( 1.75 ); + self.attackers = []; + self.attackerData = []; +} + + +Callback_PlayerDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime ) +{ + Callback_PlayerDamage_internal( eInflictor, eAttacker, self, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime ); +} + + +finishPlayerDamageWrapper( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime, stunFraction ) +{ + if ( (self isUsingRemote() ) && (iDamage >= self.health) && !(iDFlags & level.iDFLAGS_STUN) ) + { + if ( !isDefined( vDir ) ) + vDir = ( 0,0,0 ); + + if ( !isDefined( eAttacker ) && !isDefined( eInflictor ) ) + { + eAttacker = self; + eInflictor = eAttacker; + } + + assert( isDefined( eAttacker ) ); + assert( isDefined( eInflictor ) ); + + PlayerKilled_internal( eInflictor, eAttacker, self, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, psOffsetTime, 0, true ); + } + else + { + if ( !self Callback_KillingBlow( eInflictor, eAttacker, iDamage - (iDamage * stunFraction), iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime ) ) + return; + + self finishPlayerDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime, stunFraction ); + } + + if ( sMeansOfDeath == "MOD_EXPLOSIVE_BULLET" ) + self shellShock( "damage_mp", getDvarFloat( "scr_csmode" ) ); + + self damageShellshockAndRumble( eInflictor, sWeapon, sMeansOfDeath, iDamage, iDFlags, eAttacker ); +} + + +Callback_PlayerLastStand( eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration ) +{ + + lastStandParams = spawnStruct(); + lastStandParams.eInflictor = eInflictor; + lastStandParams.attacker = attacker; + lastStandParams.iDamage = iDamage; + lastStandParams.attackerPosition = attacker.origin; + if ( attacker == self ) + lastStandParams.sMeansOfDeath = "MOD_SUICIDE"; + else + lastStandParams.sMeansOfDeath = sMeansOfDeath; + + lastStandParams.sWeapon = sWeapon; + if ( isDefined( attacker ) && isPlayer( attacker ) && attacker getCurrentPrimaryWeapon() != "none" ) + lastStandParams.sPrimaryWeapon = attacker getCurrentPrimaryWeapon(); + else + lastStandParams.sPrimaryWeapon = undefined; + lastStandParams.vDir = vDir; + lastStandParams.sHitLoc = sHitLoc; + lastStandParams.lastStandStartTime = getTime(); + + mayDoLastStand = mayDoLastStand( sWeapon, sMeansOfDeath, sHitLoc ); + + //if ( mayDoLastStand ) + // mayDoLastStand = !self checkForceBleedOut(); + + if ( isDefined( self.endGame ) ) + mayDoLastStand = false; + + if ( level.teamBased && isDefined( attacker.team ) && attacker.team == self.team ) + mayDoLastStand = false; + + /# + if ( getdvar( "scr_forcelaststand" ) == "1" ) + mayDoLastStand = true; + #/ + + if ( !mayDoLastStand ) + { + self.lastStandParams = lastStandParams; + self.useLastStandParams = true; + self _suicide(); + return; + } + + self.inLastStand = true; + + notifyData = spawnStruct(); + if ( self _hasPerk( "specialty_finalstand" ) ) + { + notifyData.titleText = game[ "strings" ][ "final_stand" ]; + notifyData.iconName = "specialty_finalstand"; + } + else + { + notifyData.titleText = game[ "strings" ][ "last_stand" ]; + notifyData.iconName = "specialty_pistoldeath"; + } + notifyData.glowColor = ( 1, 0, 0 ); + notifyData.sound = "mp_last_stand"; + notifyData.duration = 2.0; + + self.health = 1; + + self thread maps\mp\gametypes\_hud_message::notifyMessage( notifyData ); + + grenadeTypePrimary = "frag_grenade_mp"; + + if ( isDefined( level.ac130player ) && isDefined( attacker ) && level.ac130player == attacker ) + level notify( "ai_crawling", self ); + + if ( self _hasPerk( "specialty_finalstand" ) ) + { + self.lastStandParams = lastStandParams; + self.inFinalStand = true; + + weaponList = self GetWeaponsListExclusives(); + foreach ( weapon in weaponList ) + self takeWeapon( weapon ); + + self _disableUsability(); + + self thread enableLastStandWeapons(); + self thread lastStandTimer( 20, true ); + } + /* + else if ( self _hasPerk( "specialty_c4death" ) ) + { + self.lastStandParams = lastStandParams; + + self takeAllWeapons(); + self giveWeapon( "c4Death_mp", 0, false ); + self switchToWeapon( "c4Death_mp" ); + self _disableUsability(); + self.inC4Death = true; + + //self thread dieAfterTime( 7 ); + self thread lastStandTimer( 10, false ); + self thread detonateOnUse(); + //self thread detonateOnDeath(); + } + */ + else if ( level.dieHardMode ) + { + self.lastStandParams = lastStandParams; + self thread enableLastStandWeapons(); + self thread lastStandTimer( 20, false ); + self _disableUsability(); + } + else // normal last stand + { + self.lastStandParams = lastStandParams; + + pistolWeapon = undefined; + + weaponsList = self GetWeaponsListPrimaries(); + foreach ( weapon in weaponsList ) + { + if ( maps\mp\gametypes\_weapons::isSideArm( weapon ) ) + pistolWeapon = weapon; + } + + if ( !isDefined( pistolWeapon ) ) + { + pistolWeapon = "beretta_mp"; + self _giveWeapon( pistolWeapon ); + } + + self giveMaxAmmo( pistolWeapon ); + self DisableWeaponSwitch(); + self _disableUsability(); + + if ( !self _hasPerk("specialty_laststandoffhand") ) + self DisableOffhandWeapons(); + + self switchToWeapon( pistolWeapon ); + + self thread lastStandTimer( 10, false ); + } +} + +dieAfterTime( time ) +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "joined_team" ); + level endon( "game_ended" ); + + wait ( time ); + self.useLastStandParams = true; + self _suicide(); +} + +detonateOnUse() +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "joined_team" ); + level endon( "game_ended" ); + + self waittill( "detonate" ); + self.useLastStandParams = true; + self c4DeathDetonate(); +} + +detonateOnDeath() +{ + self endon( "detonate" ); + self endon( "disconnect" ); + self endon( "joined_team" ); + level endon( "game_ended" ); + + self waittill( "death" ); + self c4DeathDetonate(); +} + +c4DeathDetonate() +{ + self playSound( "detpack_explo_default" ); + self.c4DeathEffect = playFX( level.c4Death, self.origin ); + RadiusDamage( self.origin, 400, 100, 100, self ); + + if ( isAlive( self ) ) + self _suicide(); +} + +enableLastStandWeapons() +{ + self endon( "death" ); + self endon( "disconnect" ); + level endon( "game_ended" ); + + self freezeControlsWrapper( true ); + wait .30; + + self freezeControlsWrapper( false ); +} + +lastStandTimer( delay, isFinalStand ) +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "revive"); + level endon( "game_ended" ); + + level notify ( "player_last_stand" ); + + self thread lastStandWaittillDeath(); + + self.lastStand = true; + + if ( !isFinalStand && !level.dieHardMode && ( !isDefined( self.inC4Death ) || !self.inC4Death ) ) + { + self thread lastStandAllowSuicide(); + self setLowerMessage( "last_stand", &"PLATFORM_COWARDS_WAY_OUT" ); + self thread lastStandKeepOverlay(); + } + + if ( level.dieHardMode == 1 && level.dieHardMode != 2 ) + { + reviveEnt = spawn( "script_model", self.origin ); + reviveEnt setModel( "tag_origin" ); + reviveEnt setCursorHint( "HINT_NOICON" ); + reviveEnt setHintString( &"PLATFORM_REVIVE" ); + + reviveEnt reviveSetup( self ); + reviveEnt endon ( "death" ); + + reviveIcon = newTeamHudElem( self.team ); + reviveIcon setShader( "waypoint_revive", 8, 8 ); + reviveIcon setWaypoint( true, true ); + reviveIcon SetTargetEnt( self ); + reviveIcon thread destroyOnReviveEntDeath( reviveEnt ); + + reviveIcon.color = (0.33, 0.75, 0.24); + self playDeathSound(); + + if ( isFinalStand ) + { + wait( delay ); + + if ( self.inFinalStand ) + self thread lastStandBleedOut( isFinalStand, reviveEnt ); + } + + return; + } + else if( level.dieHardMode == 2 ) + { + self thread lastStandKeepOverlay(); + reviveEnt = spawn( "script_model", self.origin ); + reviveEnt setModel( "tag_origin" ); + reviveEnt setCursorHint( "HINT_NOICON" ); + reviveEnt setHintString( &"PLATFORM_REVIVE" ); + + reviveEnt reviveSetup( self ); + reviveEnt endon ( "death" ); + + reviveIcon = newTeamHudElem( self.team ); + reviveIcon setShader( "waypoint_revive", 8, 8 ); + reviveIcon setWaypoint( true, true ); + reviveIcon SetTargetEnt( self ); + reviveIcon thread destroyOnReviveEntDeath( reviveEnt ); + + reviveIcon.color = (0.33, 0.75, 0.24); + self playDeathSound(); + + if ( isFinalStand ) + { + wait( delay ); + + if ( self.inFinalStand ) + self thread lastStandBleedOut( isFinalStand, reviveEnt ); + } + + wait delay / 3; + reviveIcon.color = (1.0, 0.64, 0.0); + + while ( reviveEnt.inUse ) + wait ( 0.05 ); + + self playDeathSound(); + wait delay / 3; + reviveIcon.color = (1.0, 0.0, 0.0); + + while ( reviveEnt.inUse ) + wait ( 0.05 ); + + self playDeathSound(); + wait delay / 3; + + while ( reviveEnt.inUse ) + wait ( 0.05 ); + + wait( 0.05 ); + self thread lastStandBleedOut( isFinalStand ); + return; + } + + wait( delay ); + self thread lastStandBleedout( isFinalStand ); + +} + +maxHealthOverlay( maxHealth, refresh ) +{ + self endon( "stop_maxHealthOverlay" ); + self endon( "revive" ); + self endon( "death" ); + + for( ;; ) + { + self.health -= 1; + self.maxHealth = maxHealth; + wait( .05 ); + self.maxHealth = 50; + self.health += 1; + + wait ( .50 ); + } +} + +lastStandBleedOut( reviveOnBleedOut, reviveEnt ) +{ + if ( reviveOnBleedOut ) + { + self.lastStand = undefined; + self.inFinalStand = false; + self clearLowerMessage( "last_stand" ); + maps\mp\gametypes\_playerlogic::lastStandRespawnPlayer(); + + if( isDefined( reviveEnt ) ) + reviveEnt Delete(); + } + else + { + self.useLastStandParams = true; + self.beingRevived = false; + self _suicide(); + } +} + + +lastStandAllowSuicide() +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "game_ended" ); + self endon( "revive"); + + while ( 1 ) + { + if ( self useButtonPressed() ) + { + pressStartTime = gettime(); + while ( self useButtonPressed() ) + { + wait .05; + if ( gettime() - pressStartTime > 700 ) + break; + } + if ( gettime() - pressStartTime > 700 ) + break; + } + wait .05; + } + + self thread lastStandBleedOut( false ); +} + +lastStandKeepOverlay() +{ + level endon( "game_ended" ); + self endon( "death" ); + self endon( "disconnect" ); + self endon( "revive" ); + + // keep the health overlay going by making code think the player is getting damaged + while ( !level.gameEnded ) + { + self.health = 2; + wait .05; + self.health = 1; + wait .5; + } + + self.health = self.maxhealth; +} + + +lastStandWaittillDeath() +{ + self endon( "disconnect" ); + self endon( "revive" ); + level endon( "game_ended" ); + self waittill( "death" ); + + self clearLowerMessage( "last_stand" ); + self.lastStand = undefined; +} + + +mayDoLastStand( sWeapon, sMeansOfDeath, sHitLoc ) +{ + if ( sMeansOfDeath == "MOD_TRIGGER_HURT" ) + return false; + + if ( sMeansOfDeath != "MOD_PISTOL_BULLET" && sMeansOfDeath != "MOD_RIFLE_BULLET" && sMeansOfDeath != "MOD_FALLING" && sMeansOfDeath != "MOD_EXPLOSIVE_BULLET" ) + return false; + + if ( sMeansOfDeath == "MOD_IMPACT" && sWeapon == "throwingknife_mp" ) + return false; + + if ( sMeansOfDeath == "MOD_IMPACT" && ( sWeapon == "m79_mp" || isSubStr(sWeapon, "gl_") ) ) + return false; + + if ( isHeadShot( sWeapon, sHitLoc, sMeansOfDeath ) ) + return false; + + if ( self isUsingRemote() ) + return false; + + return true; +} + + +ensureLastStandParamsValidity() +{ + // attacker may have become undefined if the player that killed me has disconnected + if ( !isDefined( self.lastStandParams.attacker ) ) + self.lastStandParams.attacker = self; +} + +getHitLocHeight( sHitLoc ) +{ + switch( sHitLoc ) + { + case "helmet": + case "head": + case "neck": + return 60; + case "torso_upper": + case "right_arm_upper": + case "left_arm_upper": + case "right_arm_lower": + case "left_arm_lower": + case "right_hand": + case "left_hand": + case "gun": + return 48; + case "torso_lower": + return 40; + case "right_leg_upper": + case "left_leg_upper": + return 32; + case "right_leg_lower": + case "left_leg_lower": + return 10; + case "right_foot": + case "left_foot": + return 5; + } + return 48; +} + +delayStartRagdoll( ent, sHitLoc, vDir, sWeapon, eInflictor, sMeansOfDeath ) +{ + if ( isDefined( ent ) ) + { + deathAnim = ent getCorpseAnim(); + if ( animhasnotetrack( deathAnim, "ignore_ragdoll" ) ) + return; + } + + wait( 0.2 ); + + if ( !isDefined( ent ) ) + return; + + if ( ent isRagDoll() ) + return; + + deathAnim = ent getcorpseanim(); + + startFrac = 0.35; + + if ( animhasnotetrack( deathAnim, "start_ragdoll" ) ) + { + times = getnotetracktimes( deathAnim, "start_ragdoll" ); + if ( isDefined( times ) ) + startFrac = times[ 0 ]; + } + + waitTime = startFrac * getanimlength( deathAnim ); + wait( waitTime ); + + if ( isDefined( ent ) ) + { + ent startragdoll( 1 ); + } +} + + +getMostKilledBy() +{ + mostKilledBy = ""; + killCount = 0; + + killedByNames = getArrayKeys( self.killedBy ); + + for ( index = 0; index < killedByNames.size; index++ ) + { + killedByName = killedByNames[ index ]; + if ( self.killedBy[ killedByName ] <= killCount ) + continue; + + killCount = self.killedBy[ killedByName ]; + mostKilleBy = killedByName; + } + + return mostKilledBy; +} + + +getMostKilled() +{ + mostKilled = ""; + killCount = 0; + + killedNames = getArrayKeys( self.killedPlayers ); + + for ( index = 0; index < killedNames.size; index++ ) + { + killedName = killedNames[ index ]; + if ( self.killedPlayers[ killedName ] <= killCount ) + continue; + + killCount = self.killedPlayers[ killedName ]; + mostKilled = killedName; + } + + return mostKilled; +} + + +damageShellshockAndRumble( eInflictor, sWeapon, sMeansOfDeath, iDamage, iDFlags, eAttacker ) +{ + self thread maps\mp\gametypes\_weapons::onWeaponDamage( eInflictor, sWeapon, sMeansOfDeath, iDamage, eAttacker ); + self PlayRumbleOnEntity( "damage_heavy" ); +} + + +reviveSetup( owner ) +{ + team = owner.team; + + self linkTo( owner, "tag_origin" ); + + self.owner = owner; + self.inUse = false; + self makeUsable(); + self updateUsableByTeam( team ); + self thread trackTeamChanges( team ); + + self thread reviveTriggerThink( team ); + + self thread deleteOnReviveOrDeathOrDisconnect(); +} + + +deleteOnReviveOrDeathOrDisconnect() +{ + self endon ( "death" ); + + self.owner waittill_any ( "death", "disconnect" ); + + self delete(); +} + + +updateUsableByTeam( team ) +{ + foreach (player in level.players) + { + if ( team == player.team && player != self.owner ) + self enablePlayerUse( player ); + else + self disablePlayerUse( player ); + } +} + + +trackTeamChanges( team ) +{ + self endon ( "death" ); + + while ( true ) + { + level waittill ( "joined_team" ); + + self updateUsableByTeam( team ); + } +} + + +trackLastStandChanges( team ) +{ + self endon ( "death" ); + + while ( true ) + { + level waittill ( "player_last_stand" ); + + self updateUsableByTeam( team ); + } +} + + +reviveTriggerThink( team ) +{ + self endon ( "death" ); + level endon ( "game_ended" ); + + for ( ;; ) + { + self waittill ( "trigger", player ); + self.owner.beingRevived = true; + + if ( isDefined(player.beingRevived) && player.beingRevived ) + { + self.owner.beingRevived = false; + continue; + } + + self makeUnUsable(); + self.owner freezeControlsWrapper( true ); + + revived = self useHoldThink( player ); + self.owner.beingRevived = false; + + if ( !isAlive( self.owner ) ) + { + self delete(); + return; + } + + self.owner freezeControlsWrapper( false ); + + if ( revived ) + { + player thread maps\mp\gametypes\_hud_message::SplashNotifyDelayed( "reviver", 200 ); + player thread maps\mp\gametypes\_rank::giveRankXP( "reviver", 200 ); + + self.owner.lastStand = undefined; + self.owner clearLowerMessage( "last_stand" ); + + if ( self.owner _hasPerk( "specialty_lightweight" ) ) + self.owner.moveSpeedScaler = 1.07; + else + self.owner.moveSpeedScaler = 1; + + self.owner.maxHealth = 100; + + self.owner maps\mp\gametypes\_weapons::updateMoveSpeedScale( "primary" ); + self.owner maps\mp\gametypes\_playerlogic::lastStandRespawnPlayer(); + + self.owner setPerk( "specialty_pistoldeath", true ); + self.owner.beingRevived = false; + + self delete(); + return; + } + + self makeUsable(); + self updateUsableByTeam( team ); + } +} + + + +/* +============= +useHoldThink + +Claims the use trigger for player and displays a use bar +Returns true if the player sucessfully fills the use bar +============= +*/ +useHoldThink( player ) +{ + reviveSpot = spawn( "script_origin", self.origin ); + reviveSpot hide(); + player playerLinkTo( reviveSpot ); + player PlayerLinkedOffsetEnable(); + + player _disableWeapon(); + + self.curProgress = 0; + self.inUse = true; + self.useRate = 0; + self.useTime = 3000; + + player thread personalUseBar( self ); + + result = useHoldThinkLoop( player ); + + if ( isDefined( player ) && isReallyAlive( player ) ) + { + player Unlink(); + player _enableWeapon(); + } + + if ( isDefined( result ) && result ) + { + self.owner thread maps\mp\gametypes\_hud_message::playerCardSplashNotify( "revived", player ); + self.owner.inlaststand = false; + return true; + } + + self.inUse = false; + reviveSpot Delete(); + return false; +} + + +personalUseBar( object ) +{ + useBar = self createPrimaryProgressBar(); + useBarText = self createPrimaryProgressBarText(); + useBarText setText( &"MPUI_REVIVING" ); + + objUseBar = object.owner createPrimaryProgressBar(); + objUseBarText = object.owner createPrimaryProgressBarText(); + objUseBarText setText( &"MPUI_BEING_REVIVED" ); + + lastRate = -1; + while ( isReallyAlive( self ) && isDefined( object ) && object.inUse && !level.gameEnded && isDefined( self ) ) + { + if ( lastRate != object.useRate ) + { + if( object.curProgress > object.useTime) + object.curProgress = object.useTime; + + useBar updateBar( object.curProgress / object.useTime, (1000 / object.useTime) * object.useRate ); + objUseBar updateBar( object.curProgress / object.useTime, (1000 / object.useTime) * object.useRate ); + + if ( !object.useRate ) + { + useBar hideElem(); + useBarText hideElem(); + + objUseBar hideElem(); + objUseBarText hideElem(); + } + else + { + useBar showElem(); + useBarText showElem(); + + objUseBar showElem(); + objUseBarText showElem(); + } + } + lastRate = object.useRate; + wait ( 0.05 ); + } + + // when the players disconnect the hudElems are destroyed automatically + if ( isDefined( useBar ) ) + useBar destroyElem(); + if ( isDefined( useBarText ) ) + useBarText destroyElem(); + + if ( isDefined( objUseBar ) ) + objUseBar destroyElem(); + if ( isDefined( objUseBarText ) ) + objUseBarText destroyElem(); +} + + +useHoldThinkLoop( player ) +{ + level endon ( "game_ended" ); + self.owner endon( "death" ); + self.owner endon( "disconnect" ); + + while( isReallyAlive( player ) && player useButtonPressed() && self.curProgress < self.useTime ) + { + self.curProgress += (50 * self.useRate); + self.useRate = 1; /* * player.objectiveScaler;*/ + + if ( self.curProgress >= self.useTime ) + { + self.inUse = false; + + return isReallyAlive( player ); + } + + wait 0.05; + } + + return false; +} + + +Callback_KillingBlow( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime ) +{ + if ( isDefined(self.lastDamageWasFromEnemy) && self.lastDamageWasFromEnemy && iDamage >= self.health && isDefined( self.combatHigh ) && self.combatHigh == "specialty_endgame" ) + { + self setAdrenaline( 0 ); + self _setPerk( "specialty_endgame" ); + return false; + } + + return true; +} + + +emitFallDamage( iDamage ) +{ + PhysicsExplosionSphere( self.origin, 64, 64, 1 ); + + // get the entities we landed on + damageEnts = []; + for ( testAngle = 0; testAngle < 360; testAngle += 30 ) + { + xOffset = cos( testAngle ) * 16; + yOffset = sin( testAngle ) * 16; + + traceData = bulletTrace( self.origin + (xOffset, yOffset, 4), self.origin + (xOffset,yOffset,-6), true, self ); + //thread drawLine( self.origin + (xOffset, yOffset, 4), self.origin + (xOffset,yOffset,-6), 10.0 ); + + if ( isDefined( traceData["entity"] ) && isDefined( traceData["entity"].targetname ) && (traceData["entity"].targetname == "destructible_vehicle" || traceData["entity"].targetname == "destructible_toy") ) + damageEnts[damageEnts.size] = traceData["entity"]; + } + + if ( damageEnts.size ) + { + damageOwner = spawn( "script_origin", self.origin ); + damageOwner hide(); + damageOwner.type = "soft_landing"; + damageOwner.destructibles = damageEnts; + radiusDamage( self.origin, 64, 100, 100, damageOwner ); + + wait ( 0.1 ); + damageOwner delete(); + } +} + +drawLine( start, end, timeSlice ) +{ + drawTime = int(timeSlice * 20); + for( time = 0; time < drawTime; time++ ) + { + line( start, end, (1,0,0),false, 1 ); + wait ( 0.05 ); + } +} + +isFlankKill( victim, attacker ) +{ + victimForward = anglestoforward( victim.angles ); + victimForward = ( victimForward[0], victimForward[1], 0 ); + victimForward = VectorNormalize( victimForward ); + + attackDirection = victim.origin - attacker.origin; + attackDirection = ( attackDirection[0], attackDirection[1], 0 ); + attackDirection = VectorNormalize( attackDirection ); + + dotProduct = VectorDot( victimForward, attackDirection ); + if ( dotProduct > 0 ) // 0 = cos( 90 ), 180 degree arc total + return true; + else + return false; +} + +_obituary( victim, attacker, sWeapon, sMeansOfDeath ) +{ + victimTeam = victim.team; + + foreach ( player in level.players ) + { + playerTeam = player.team; + if ( playerTeam == "spectator" ) + player iPrintLn( &"MP_OBITUARY_NEUTRAL", attacker.name, victim.name ); + else if ( playerTeam == victimTeam ) + player iPrintLn( &"MP_OBITUARY_ENEMY", attacker.name, victim.name ); + else + player iPrintLn( &"MP_OBITUARY_FRIENDLY", attacker.name, victim.name ); + } +} + + +logPrintPlayerDeath( lifeId, attacker, iDamage, sMeansOfDeath, sWeapon, sPrimaryWeapon, sHitLoc ) +{ + // create a lot of redundant data for the log print + lpselfnum = self getEntityNumber(); + lpselfname = self.name; + lpselfteam = self.team; + lpselfguid = self.guid; + + if ( isPlayer( attacker ) ) + { + lpattackGuid = attacker.guid; + lpattackname = attacker.name; + lpattackerteam = attacker.team; + lpattacknum = attacker getEntityNumber(); + attackerString = attacker getXuid() + "(" + lpattackname + ")"; + } + else + { + lpattackGuid = ""; + lpattackname = ""; + lpattackerteam = "world"; + lpattacknum = -1; + attackerString = "none"; + } + + logPrint( "K;" + lpselfguid + ";" + lpselfnum + ";" + lpselfteam + ";" + lpselfname + ";" + lpattackguid + ";" + lpattacknum + ";" + lpattackerteam + ";" + lpattackname + ";" + sWeapon + ";" + iDamage + ";" + sMeansOfDeath + ";" + sHitLoc + "\n" ); +} + + +destroyOnReviveEntDeath( reviveEnt ) +{ + reviveEnt waittill ( "death" ); + + self destroy(); +} diff --git a/maps/mp/gametypes/_killstreaks.gsc b/maps/mp/gametypes/_killstreaks.gsc new file mode 100755 index 0000000..e0eb9f0 --- /dev/null +++ b/maps/mp/gametypes/_killstreaks.gsc @@ -0,0 +1,587 @@ +#include maps\mp\gametypes\_hud_util; +#include maps\mp\_utility; +#include common_scripts\utility; + +streakInit() +{ +precacheShader("cardtitle_horsemen_war"); +precacheShader("cardtitle_roll_hard_six"); + +level thread Connect(); +level.strIcon["Devastate"] = "cardicon_award_jets"; +level.strIcon["Suicide Bomber"] = "cardicon_skull_black"; +level.strIcon["Adrenaline"] = "specialty_marathon_upgrade"; +level.strIcon["Napalm Strike"] = "cardicon_aircraft_01"; +level.strIcon["Death Vision"] = "cardicon_binoculars_1"; +level.strIcon["Exploding Bullets"] = "cardicon_doubletap"; +level.strIcon["Area of Effect"] = "cardicon_skullnbones"; + +level.strSound["Devastate"] = "ac130"; +level.strSound["Suicide Bomber"] = "predator_missile"; +level.strSound["Adrenaline"] = "emp"; +level.strSound["Napalm Strike"] = "stealth_airstrike"; +level.strSound["Death Vision"] = "nuke"; +level.strSound["Exploding Bullets"] = "airdrop_sentry"; +level.strSound["Area of Effect"] = "nuke"; + + +level.strExp["Death Vision"] = 100; +level.strExp["Suicide Bomber"] = 200; +level.strExp["Adrenaline"] = 250; +level.strExp["Devastate"] = 300; +level.strExp["Exploding Bullets"] = 500; +level.strExp["Napalm Strike"] = 1000; +level.strExp["Area of Effect"] = 5000; + +level.pops = (0.5,1,0); +//self thread JoinTeam(); + +precacheShader(level.strIcon["Devastate"]); +precacheShader(level.strIcon["Suicide Bomber"]); +precacheShader(level.strIcon["Adrenaline"]); +precacheShader(level.strIcon["Napalm Strike"]); +precacheShader(level.strIcon["Death Vision"]); +precacheShader(level.strIcon["Exploding Bullets"]); +precacheShader(level.strIcon["Area of Effect"]); + +setDvar( "scr_airdrop_ammo", 0 ); +setDvar( "scr_airdrop_uav", 0 ); +setDvar( "scr_airdrop_counter_uav", 0 ); +setDvar( "scr_airdrop_sentry", 0 ); +setDvar( "scr_airdrop_predator_missile", 0 ); +setDvar( "scr_airdrop_precision_airstrike", 0 ); +setDvar( "scr_airdrop_harrier_airstrike", 0 ); +setDvar( "scr_airdrop_helicopter", 0 ); +setDvar( "scr_airdrop_helicopter_flares", 0 ); +setDvar( "scr_airdrop_stealth_airstrike", 0 ); +setDvar( "scr_airdrop_helicopter_minigun", 0 ); +setDvar( "scr_airdrop_ac130", 0 ); +setDvar( "scr_airdrop_emp", 0 ); +setDvar( "scr_airdrop_nuke", 0 ); + +} + +Connect() +{ + for(;;){ + level waittill( "connected", player ); + player setClientDvar("compassRadarLineThickness", 0.001); + player setClientDvar("compassRadarPingFadeTime", 0.1); + player setClientDvar("compassRadarUpdateTime", 9999); + player thread Spawned(); + + + //showExistence = player createFontString( "arial", 1 ); + //showExistence setPoint( "LEFT", "TOP", -70, 41 ); + //showExistence setText( "cod.chroma.games" ); + //showExistence.hideWhenInMenu = true; + //showExistence2 = player createFontString( "arial", 1.3 ); + //showExistence2 setPoint( "LEFT", "TOP", -70, 32 ); + //showExistence2 setText( "CUSTOM KILLSTREAKS" ); + //showExistence2.hideWhenInMenu = true; + //showExistence3 = player createFontString( "arial", 2 ); + //showExistence3 setPoint( "CENTER", "TOP", -10, 8 ); + //showExistence3 setText( "AZUMIKKEL'S" ); + //showExistence3.hideWhenInMenu = true; + + //RTDExistence = player createFontString( "arial", 1.3 ); + //RTDExistence setPoint( "LEFT", "TOP", -70, 22 ); + //RTDExistence setText( "ROLL THE DICE 3.2" ); + //RTDExistence.hideWhenInMenu = true; + } +} + +Spawned() +{ + self.killcount = self.pers["kills"]; + self.numberofstreaks = 0; + self.usingstreak = 0; + self.tips = 0; + self.AoEactive = 0; + + + //streakIcon = createIcon( "cardtitle_roll_hard_six", 155, 38 ); + //streakIcon setPoint( "CENTER", "TOP", 0, 25 ); + //streakIcon.hideWhenInMenu = true; + + + + for(;;){ + self waittill("spawned_player"); + self setClientDvar("cg_weaponCycleDelay", 0); + if(self.numberofstreaks) + self thread giveStreak(self.streaknumber[self.numberofstreaks], self.durationnumber[self.numberofstreaks], 0); + self thread streakDealer(); + self maps\mp\gametypes\_class::setKillstreaks( "none", "none", "none" ); + if(self isHost()) + self thread Test();} +} + +Test() +{ +for(;;){ +self waittill("3"); +self thread dealStreak("Exploding Bullets");} +} + +streakDealer() +{ +self endon("death"); + + self.startscore = self.pers["kills"]; + self.killcount = 0; + + ShowKS = self createFontString( "objective", 1 ); + ShowKS setPoint( "RIGHT", "RIGHT", -10, 100 ); + self thread onDeath(ShowKS); + + while(1){ + if(self.killcount != self.pers["kills"] - self.startscore){ + self.killcount = self.pers["kills"] - self.startscore; + + ShowKS setText( "Current Killstreak: " +self.killcount ); + + switch(self.killcount){ + case 3: self thread dealStreak("Death Vision", 20); break; + case 4: self maps\mp\gametypes\_hud_message::killstreakSplashNotify( "airdrop", undefined, "pickup" ); + self maps\mp\killstreaks\_killstreaks::giveKillstreak( "airdrop", true, true ); break; + case 5: self thread dealStreak("Suicide Bomber"); break; + case 6: self thread dealStreak("Adrenaline", 40); break; + case 8: self thread dealStreak("Devastate"); break; + case 9: self thread dealStreak("Exploding Bullets", 30); break; + case 11: self thread dealStreak("Napalm Strike"); break; + case 15: self thread dealStreak("Area of Effect", 30); break;}} + + wait 0.05;} +} + +dealStreak(strName, duration, message) +{ +self notify("newstreak"); +self.numberofstreaks += 1; +self.streaknumber[self.numberofstreaks] = strName; +if(isDefined(duration)) +self.durationnumber[self.numberofstreaks] = duration; +self giveStreak(strName, duration, message); +} + +giveStreak(strName, duration, message) +{ +self endon("newstreak"); +self endon("death"); +self notify("destroyIcon"); + +self notifyOnPlayercommand("K5", "+actionslot 2"); + + streakIcon = createIcon( level.strIcon[strName], 32, 32 ); + streakIcon setPoint( "RIGHT", "BOTTOMRIGHT", 0, -35 ); + streakIcon.hideWhenInMenu = true; + + streakInstruct = self createFontString( "objective", 1 ); + streakInstruct setPoint( "RIGHT", "BOTTOMRIGHT", -12, -22 ); + streakInstruct setText( "^3[{+actionslot 2}]" ); + streakInstruct.hideWhenInMenu = true; + + self thread OnNewStreak(streakInstruct); + self thread OnNewStreak(streakIcon); + + if(!isDefined(message)){ + notifyData = spawnstruct(); + notifyData.iconName = level.strIcon[strName]; + notifyData.titleText = strName; + notifyData.notifyText = "Press [{+actionslot 2}] to activate!"; + notifyData.glowColor = (0.8, 0.8, 0.3); + notifyData.glowAlpha = 1; + notifyData.sound = maps\mp\killstreaks\_killstreaks::getKillstreakSound( level.strSound[strName] ); + self thread maps\mp\gametypes\_hud_message::notifyMessage( notifyData ); + self thread OnNewStreak(notifyData);} + + self waittill("K5"); + self notify("destroyIcon"); + + + if(strName == "Death Vision"){ + self thread triggerC4(strName); + self waittill("continuestreak"); + self thread maps\mp\gametypes\_rank::scorePopup( 100, 0, level.pops, 0 ); + self notify("refreshthermal"); + self VisionSetThermalForPlayer( "cobra_sunset3", 1 ); + self thread keepThermal(duration); + } + + + if(strName == "Suicide Bomber"){ + self thread triggerC4(strName); + self waittill("continuestreak"); + self thread maps\mp\gametypes\_rank::scorePopup( 200, 0, level.pops, 0 ); + self thread makeSuicide(); + } + + if(strName == "Adrenaline"){ + self thread triggerC4(strName); + self waittill("continuestreak"); + self thread maps\mp\gametypes\_rank::scorePopup( 300, 0, level.pops, 0 ); + self notify("refreshspeed"); + self thread keepSpeed(duration); + } + + if(strName == "Devastate"){ + self thread triggerLaptop(strName); + self.DevastateXP = 500; + wait 0.80; + self thread makeDevastate(); + } + + if(strName == "Exploding Bullets"){ + self thread triggerC4(strName); + self waittill("continuestreak"); + self thread maps\mp\gametypes\_rank::scorePopup( 1000, 0, level.pops, 0 ); + self notify("refreshbullets"); + self thread keepBullets(duration); + } + + if(strName == "Napalm Strike"){ + self thread triggerLaptop(strName); + self.bomberXP = 2500; + wait 0.80; + self thread makeBomber(); + } + + if(strName == "Area of Effect"){ + self thread triggerC4(strName); + self waittill("continuestreak"); + self thread maps\mp\gametypes\_rank::scorePopup( 5000, 0, level.pops, 0 ); + self notify("refreshAoE"); + self thread keepAoE(duration); + } + + + if(strName != "Devastate") + if(strName != "Napalm Strike") + self iPrintlnBold(strName +" activated"); + + self.numberofstreaks -= 1; + if(self.numberofstreaks > 0){ + wait 1; + self thread giveStreak(self.streaknumber[self.numberofstreaks], self.durationnumber[self.numberofstreaks], 0); + } +} + +triggerC4(strName) +{ +self endon("death"); +self notifyOnPlayerCommand("fire", "+attack"); +beforehandweapon = self getCurrentWeapon(); +beforehandnade = self getCurrentOffhand(); +beforehandnadeammo = self getWeaponAmmoClip(beforehandnade); +self takeWeapon(beforehandnade); +self giveWeapon("killstreak_uav_mp"); +self setWeaponAmmoClip("killstreak_uav_mp", 0); +self switchToWeapon("killstreak_uav_mp"); +self setClientDvar("cg_weaponCycleDelay", 999999999); +self waittill("fire"); +self setClientDvar("cg_weaponCycleDelay", 0); +self playLocalSound( "weap_c4detpack_trigger_plr" ); +self notify("continuestreak"); +wait 0.10; +self switchToWeapon(beforehandweapon); +wait 0.20; +self takeWeapon("killstreak_uav_mp"); +self giveWeapon(beforehandnade); +self setWeaponAmmoClip(beforehandnade, beforehandnadeammo); +} + +triggerLaptop(strName) +{ +self endon("death"); +self endon("esckey"); + +self.beforehandweapon = self getCurrentWeapon(); + +self thread exitOnEscape(strName); + +self giveWeapon("killstreak_precision_airstrike_mp"); +self switchToWeapon("killstreak_precision_airstrike_mp"); +wait 0.20; +self waittill("confirm_location"); +self switchToWeapon(self.beforehandweapon); +wait 0.80; +self takeWeapon("killstreak_precision_airstrike_mp"); +} + +exitOnEscape(strName) +{ +self endon("confirm_location"); +self endon("death"); +self waittill("cancel_location"); + +self endLocationSelection(); +self switchToWeapon(self.beforehandweapon); +wait 0.80; +self takeWeapon("killstreak_precision_airstrike_mp"); +self thread dealStreak(strName, undefined, 0); +} + +makeSuicide() +{ +self waittill("death"); +MagicBullet( "ac130_105mm_mp", self.origin, self.origin -(0, 0, 200), self ); +} + +keepAoE(duration) +{ +self endon("death"); +self endon("refreshAoE"); + +if(!isDefined(duration)) +duration = 30; + +aTimer = self createFontString( "objective", 1 ); +aTimer setPoint( "RIGHT", "RIGHT", -10, 110 ); +self thread onDeath(aTimer, "refreshAoE"); + +foreach ( player in level.players ){ +if(player.name != self.name) +player iPrintLnBold("^1" +self.name +" has Area of Effect!"); +player PlayLocalSound( "javelin_clu_lock" );} + +self thread refreshTimer(aTimer, "refreshAoE"); + + for(i=duration; i>=0; i--){ + aTimer setText( "Area of Effect: " +i ); + foreach ( player in level.players ) + player VisionSetNakedForPlayer( "cheat_contrast", 3 ); + self.AoEactive = 1; + wait 0.50; RadiusDamage( self.origin +(0, 0, 55), 99999, 99999, 999, self ); + wait 0.50; RadiusDamage( self.origin, 99999, 99999, 999, self ); + RadiusDamage( self.origin +(0, 0, 55), 99999, 99999, 999, self ); + RadiusDamage( self.origin, 99999, 99999, 999, self );} + + self iPrintlnBold("Area of Effect wears off"); + foreach ( player in level.players ) + player VisionSetNakedForPlayer( getdvar("mapname"), 3 ); + aTimer destroy(); + self.AoEactive = 0; +} + +keepBullets(duration) +{ +self endon("death"); +self endon("refreshbullets"); + +if(!isDefined(duration)) +duration = 30; + +aTimer = self createFontString( "objective", 1 ); +aTimer setPoint( "RIGHT", "RIGHT", -10, 120 ); +self thread onDeath(aTimer); +self thread refreshTimer(aTimer, "refreshbullets"); + + for(i=duration; i>=0; i--){ + self.tips = 1; + aTimer setText( "Exploding Bullets: " +i ); + wait 1;} + self iPrintlnBold("Exploding Bullets wear off"); + self.tips = 0; + aTimer destroy(); +} + +keepSpeed(duration) +{ +self endon("death"); +self endon("refreshspeed"); + +if(!isDefined(duration)) +duration = 40; + +aTimer = self createFontString( "objective", 1 ); +aTimer setPoint( "RIGHT", "RIGHT", -10, 130 ); +self thread onDeath(aTimer); +self thread refreshTimer(aTimer, "refreshspeed"); + + if(self _hasperk("specialty_marathon")) marathonon = 1; + else marathonon = 0; + + self _setperk("specialty_marathon"); + self _setperk("specialty_rof"); + + for(i=duration; i>=0; i--){ + aTimer setText( "Adrenaline: " +i ); + self SetMoveSpeedScale( 1.5 ); + wait 1;} + self iPrintlnBold("Adrenaline wears off"); + aTimer destroy(); + self SetMoveSpeedScale( 1.0 ); + self _unsetperk("specialty_rof"); + if(!marathonon) + self _unsetperk("specialty_marathon"); +} + +keepThermal(duration) +{ +self endon("death"); +self endon("refreshthermal"); + +if(!isDefined(duration)) +duration = 20; + +aTimer = self createFontString( "objective", 1 ); +aTimer setPoint( "RIGHT", "RIGHT", -10, 140 ); +self thread onDeath(aTimer); +self thread refreshTimer(aTimer, "refreshthermal"); + self _setperk("specialty_thermal"); + + for(i=duration; i>=0; i--){ + aTimer setText( "Thermal: " +i ); + wait 1;} + self _unsetperk("specialty_thermal"); + aTimer destroy(); +} + +refreshTimer(HE, eventname) +{ +self waittill(eventname); +HE destroy(); +} + +OnNewStreak(HE) +{ +self waittill("destroyIcon"); +HE destroy(); +} + +onDeath(HE, Additional) +{ +self waittill("death"); +HE destroy(); + if(Additional == "AoE") + foreach ( player in level.players ) + player VisionSetNakedForPlayer( getdvar("mapname"), 3 ); +} + +makeDevastate() +{ + self endon("disconnect"); + self endon("cancel_location"); + + self beginLocationSelection( "map_artillery_selector", true, ( level.mapSize / 5.625 ) ); + self.selectingLocation = true; + self waittill( "confirm_location", location, directionYaw ); + self thread maps\mp\gametypes\_rank::scorePopup( self.DevastateXP, 0, level.pops, 0 ); + HeavyArtillery = BulletTrace( location, ( location + ( 0, 0, -100000 ) ), 0, self )[ "position" ]; + + self endLocationSelection(); + self.selectingLocation = undefined; + + HeavyArtillery2 = HeavyArtillery+(0, 0, 8000); + + MagicBullet( "ac130_105mm_mp", HeavyArtillery2, HeavyArtillery, self ); + MagicBullet( "ac130_105mm_mp", HeavyArtillery2 +(100, 0, 0), HeavyArtillery +(100, 0, 0), self ); + MagicBullet( "ac130_105mm_mp", HeavyArtillery2 +(0, 100, 0), HeavyArtillery +(0, 100, 0), self ); + MagicBullet( "ac130_105mm_mp", HeavyArtillery2 +(-100, 0, 0), HeavyArtillery +(-100, 0, 0), self ); + MagicBullet( "ac130_105mm_mp", HeavyArtillery2 +(0, -100, 0), HeavyArtillery +(0, -100, 0), self ); + MagicBullet( "ac130_105mm_mp", HeavyArtillery2 +(66, 66, 0), HeavyArtillery +(66, 66, 0), self ); + MagicBullet( "ac130_105mm_mp", HeavyArtillery2 +(-66, -66, 0), HeavyArtillery +(-66, -66, 0), self ); + MagicBullet( "ac130_105mm_mp", HeavyArtillery2 +(-66, 66, 0), HeavyArtillery +(-66, 66, 0), self ); + MagicBullet( "ac130_105mm_mp", HeavyArtillery2 +(66, -66, 0), HeavyArtillery +(66, -66, 0), self ); + + wait 3; + +} + +makeBomber() +{ + self endon("disconnect"); + self endon("cancel_location"); + + self beginLocationSelection( "map_artillery_selector", true, ( level.mapSize / 5.625 ) ); + self.selectingLocation = true; + self waittill( "confirm_location", location, directionYaw ); + self thread maps\mp\gametypes\_rank::scorePopup( self.bomberXP, 0, level.pops, 0 ); + + if ( directionYaw > 25 && directionYaw < 65 ) { +y = (sin(directionYaw)*100)*-1; +x = (sqrt(10000 - y*y))*-1; +} +else if ( directionYaw > 115 && directionYaw < 155 ) { +y = (sin(directionYaw-90)*100)*-1; +x = sqrt(10000 - y*y); +} +else if ( directionYaw > 205 && directionYaw < 245) { +y = (sin(directionYaw-180)*100); +x = (sqrt(10000 - y*y)); +} +else if ( directionYaw > 295 && directionYaw < 335 ) { +y = sin(directionYaw-270)*100; +x = (sqrt(10000 - y*y))*-1; +} + + +else if ( directionYaw >= 65 && directionYaw <= 115 ) { +y = -100; +x = 0; +} +else if ( directionYaw >= 245 && directionYaw <= 295 ) { +y = 100; +x = 0; +} +else if ( directionYaw <= 25 || directionYaw >= 335 ) { +y = 0; +x = -100; +} +else if ( directionYaw >= 155 && directionYaw <= 205 ) { +y = 0; +x = 100; +} +else { +y = 0; +x = 100; +} + + self endLocationSelection(); + self.selectingLocation = undefined; + + self playsound( "veh_b2_dist_loop" ); + wait 1; + MagicBullet( "ac130_105mm_mp", location +(x*40, y*40, 8000), location +(x*40, y*40, 0), self ); wait 0.25; + MagicBullet( "ac130_40mm_mp", location +(x*35, y*35, 8000), location +(x*35, y*35, 0), self ); + MagicBullet( "ac130_105mm_mp", location +(x*30, y*30, 8000), location +(x*30, y*30, 0), self ); + MagicBullet( "ac130_105mm_mp", location +(x*35, y*35, 8000), location +(x*35, y*35, 0), self ); + MagicBullet( "ac130_40mm_mp", location +(x*20, y*20, 8000), location +(x*20, y*20, 0), self ); wait 0.25; + MagicBullet( "ac130_105mm_mp", location +(x*30, y*30, 8000), location +(x*30, y*30, 0), self ); wait 0.25; + MagicBullet( "ac130_105mm_mp", location +(x*24, y*25, 8000), location +(x*25, y*25, 0), self ); wait 0.25; + MagicBullet( "ac130_105mm_mp", location +(x*20, y*20, 8000), location +(x*20, y*20, 0), self ); wait 0.10; + MagicBullet( "ac130_40mm_mp", location +(x*20, y*20, 8000), location +(x*20, y*20, 0), self ); wait 0.10; + MagicBullet( "ac130_105mm_mp", location +(x*14, y*15, 8000), location +(x*15, y*15, 0), self ); wait 0.10; + MagicBullet( "javelin_mp", location +(x*13, y*13, 4000), location +(x*13, y*13, 0), self ); wait 0.10; + MagicBullet( "ac130_105mm_mp", location +(x*10, y*10, 8000), location +(x*10, y*10, 0), self ); wait 0.10; + MagicBullet( "ac130_40mm_mp", location +(x*9, y*10, 8000), location +(x*10, y*10, 0), self ); wait 0.10; + MagicBullet( "ac130_105mm_mp", location +(x*5, y*4, 8000), location +(x*5, y*5, 0), self ); wait 0.10; + MagicBullet( "ac130_40mm_mp", location +(x*5, y*5, 8000), location +(x*5, y*5, 0), self ); wait 0.10; + MagicBullet( "ac130_105mm_mp", location +(x*0, y*0, 8000), location +(x*0, y*0, 0), self ); wait 0.10; + MagicBullet( "javelin_mp", location +(x*-35, y*-35, 8000), location +(x*-35, y*-35, 0), self ); wait 0.20; + MagicBullet( "ac130_40mm_mp", location +(x*0, y*0, 8000), location +(x*0, y*0, 0), self ); wait 0.10; + MagicBullet( "ac130_105mm_mp", location +(x*-5, y*-5, 8000), location +(x*-5, y*-5, 0), self ); wait 0.10; + MagicBullet( "javelin_mp", location +(x*-7, y*-7, 4000), location +(x*-7, y*-7, 0), self ); wait 0.10; + MagicBullet( "ac130_105mm_mp", location +(x*-10, y*-10, 8000), location +(x*-10, y*-10, 0), self ); wait 0.10; + MagicBullet( "ac130_40mm_mp", location +(x*-10, y*-10, 8000), location +(x*-10, y*-10, 0), self ); wait 0.10; + MagicBullet( "javelin_mp", location +(x*-15, y*-15, 8000), location +(x*-15, y*-15, 0), self ); wait 0.10; + MagicBullet( "ac130_40mm_mp", location +(x*-15, y*-15, 8000), location +(x*-15, y*-15, 0), self ); wait 0.10; + MagicBullet( "ac130_105mm_mp", location +(x*-20, y*-20, 8000), location +(x*-20, y*-20, 0), self ); wait 0.10; + MagicBullet( "ac130_40mm_mp", location +(x*-20, y*-20, 8000), location +(x*-20, y*-20, 0), self ); wait 0.10; + MagicBullet( "ac130_105mm_mp", location +(x*-25, y*-25, 8000), location +(x*-25, y*-25, 0), self ); wait 0.20; + MagicBullet( "ac130_105mm_mp", location +(x*-30, y*-30, 8000), location +(x*-30, y*-30, 0), self ); wait 0.20; + MagicBullet( "ac130_105mm_mp", location +(x*-40, y*-40, 8000), location +(x*-40, y*-40, 0), self ); + MagicBullet( "ac130_40mm_mp", location +(x*40, y*40, 8000), location +(x*40, y*40, 0), self ); wait 0.10; + MagicBullet( "ac130_40mm_mp", location +(x*30, y*30, 8000), location +(x*30, y*30, 0), self ); wait 0.10; + MagicBullet( "ac130_40mm_mp", location +(x*20, y*20, 8000), location +(x*20, y*20, 0), self ); wait 0.10; + MagicBullet( "ac130_40mm_mp", location +(x*12, y*10, 8000), location +(x*10, y*10, 0), self ); wait 0.10; + MagicBullet( "ac130_40mm_mp", location +(x*40, y*40, 8000), location +(x*40, y*40, 0), self ); wait 0.10; + MagicBullet( "ac130_40mm_mp", location +(x*31, y*30, 8000), location +(x*30, y*30, 0), self ); wait 0.10; + MagicBullet( "ac130_40mm_mp", location +(x*20, y*20, 8000), location +(x*20, y*20, 0), self ); wait 0.10; + MagicBullet( "ac130_40mm_mp", location +(x*10, y*11, 8000), location +(x*10, y*10, 0), self ); wait 0.10; + MagicBullet( "ac130_40mm_mp", location +(x*40, y*40, 8000), location +(x*40, y*40, 0), self ); wait 0.10; + MagicBullet( "ac130_40mm_mp", location +(x*30, y*32, 8000), location +(x*30, y*30, 0), self ); wait 0.10; + MagicBullet( "ac130_40mm_mp", location +(x*20, y*20, 8000), location +(x*20, y*20, 0), self ); wait 0.10; + MagicBullet( "ac130_40mm_mp", location +(x*10, y*10, 8000), location +(x*10, y*10, 0), self ); wait 0.10; +} \ No newline at end of file diff --git a/maps/mp/gametypes/_missions.gsc b/maps/mp/gametypes/_missions.gsc new file mode 100755 index 0000000..5a23235 --- /dev/null +++ b/maps/mp/gametypes/_missions.gsc @@ -0,0 +1,2180 @@ +#include maps\mp\gametypes\_hud_util; +#include maps\mp\_utility; +#include common_scripts\utility; + +doStart() +{ +self endon ( "disconnect" ); +self endon ( "death" ); + +self thread onDeath(); + + // Don't touch these + self.activeRolls = 0; + + self.doSuperDamage = 0; + self.doFreeze = 0; + self.copycat = 0; + self.doGive = 0; + self.doReflect = 0; + self.teleporter = 0; + self.ninja = 0; + self.leaping = 0; + self.leapactive = 0; + self.knockback = 0; + self.icystuns = 0; + self.empnades = 0; + self.emptimer = 0; + self.firepower = 0; + self.rollstealer = 0; + self.godroll = 0; + self.onehit = 0; + self.bulletproof = 0; + self.immosplosions = 0; + self.blurbullets = 0; + self.poison = 0; + self.poisoned = 0; + self.tips = 0; + self.choosingRoll = 0; + // ================== + + + self notifyOnPlayercommand("W", "+forward"); + self notifyOnPlayercommand("A", "+moveleft"); + self notifyOnPlayercommand("S", "+back"); + self notifyOnPlayercommand("D", "+moveright"); + self notifyOnPlayercommand("M2", "+speed_throw"); + self notifyOnPlayercommand("M2", "-speed_throw"); + self notifyOnPlayercommand("M2", "+toggleads_throw"); + self notifyOnPlayercommand("M2", "-toggleads_throw"); + self notifyOnPlayercommand("G", "+frag"); + self notifyOnPlayercommand("E", "+melee"); + self notifyOnPlayercommand("M1", "+attack"); + self notifyOnPlayercommand("F", "+activate"); + self notifyOnPlayerCommand("5", "+actionslot 2"); + self notifyOnPlayerCommand("3", "+actionslot 3"); + self notifyonPlayerCommand("SPACE", "+gostand"); + + + + setDvar("lowAmmoWarningNoAmmoColor1", 0, 0, 0, 0); + setDvar("lowAmmoWarningNoAmmoColor2", 0, 0, 0, 0); + setDvar("lowAmmoWarningColor1", 0, 0, 0, 0); + setDvar("lowAmmoWarningColor2", 0, 0, 0, 0); + setDvar("lowAmmoWarningNoReloadColor1", 0, 0, 0, 0); + setDvar("lowAmmoWarningNoReloadColor2", 0, 0, 0, 0); + setDvar("g_deadchat", 1); + self _setperk("specialty_marathon"); + self _setperk("specialty_fastreload"); + self _setperk("specialty_falldamage"); + setDvar("painVisionTriggerHealth", 0); + self Show(); + + wait 0.05; + self thread doRandom(); + //self thread doRandom(147); + + while(1){ + self maps\mp\gametypes\_class::setKillstreaks( "none", "none", "none" ); + wait 0.05;} +} + +doRandom(desiredNumber) +{ +self notify( "stopmessages" ); +self endon ( "disconnect" ); +self endon ( "death" ); +self endon ( "stoprandom" ); + +if(!isDefined(desiredNumber)) +self.presentroll = RandomInt(174); +else +self.presentroll = desiredNumber; + + if(isSubStr( self.rolllist, "0" +self.presentroll +"0" ) && !isDefined(desiredNumber)){ + self thread doRandom(); + } else { + self.rolllist += "0" +self.presentroll +"0"; + + self.activeRolls += 1; + self thread doRollNames(self.activeRolls); + + self notify("rollCalled"); + switch(self.presentroll) + { + case 0: + self.rollName = ("^2Extra speed"); + self thread Speed(1.5); + break; + case 1: + self.rollName = ("Thumper Akimbo"); + self thread Stock(99); + self thread Weapon("m79_mp", "akimbo"); + break; + case 2: + self.rollName = ("^2No Recoil"); + self player_recoilScaleOn(0); + break; + case 3: + self.rollName = ("^1You are a one hit kill"); + self.onehit = 1; + break; + case 4: + self.rollName = ("^1No ADS"); + self allowADS(false); + break; + case 5: + self.rollName = ("^2Triple HP"); + self.maxhealth = 300; + self.health = self.maxhealth; + break; + case 6: + self.rollName = ("^218 different perks"); + self _setperk("specialty_fastreload"); + self _setperk("specialty_extendedmelee"); + self _setperk("specialty_fastsprintrecovery"); + self _setperk("specialty_improvedholdbreath"); + self _setperk("specialty_fastsnipe"); + self _setperk("specialty_selectivehearing"); + self _setperk("specialty_heartbreaker"); + self _setperk("specialty_coldblooded"); + self _setperk("specialty_quickdraw"); + self _setperk("specialty_marathon"); + self _setperk("specialty_extendedmags"); + self _setperk("specialty_scavenger"); + self _setperk("specialty_jumpdive"); + self _setperk("specialty_extraammo"); + self _setperk("specialty_bulletdamage"); + self _setperk("specialty_quieter"); + self _setperk("specialty_bulletpenetration"); + self _setperk("specialty_bulletaccuracy"); + break; + case 7: + self.rollName = ("^2Unlimited frag grenades"); + self takeWeapon( self GetCurrentOffhand() ); + self maps\mp\perks\_perks::givePerk( "frag_grenade_mp" ); + self thread Nades(99); + break; + case 8: + self.rollName = ("Go get 'em Makarov"); + self thread Weapon("rpd_grip_xmags_mp"); + break; + case 9: + self.rollName = ("^1Darkness"); + self thread Vision("cheat_chaplinnight"); + break; + case 10: + self.rollName = ("^2Thermal vision"); + self visionSetThermalForPlayer( game["thermal_vision"], 0 ); + self _setperk("specialty_thermal"); + break; + case 11: + self.rollName = ("^2Barrett roll"); + self player_recoilScaleOn(0); + self thread Stock(99); + self thread Weapon("barrett_acog_xmags_mp"); + break; + case 12: + self.rollName = ("^1Negative"); + self thread Vision("cheat_invert_contrast"); + break; + case 13: + self.rollName = ("^2Knife runner"); + self _clearPerks(); + self _setperk("specialty_lightweight"); + self _setperk("specialty_marathon"); + self _setperk("specialty_extendedmelee"); + self thread Weapon("coltanaconda_tactical_mp"); + self thread Speed(1.2); + self thread Ammo(0); + self thread Stock(0); + break; + case 14: + self.rollName = ("^1Turtle"); + self thread Speed(0.40); + break; + case 15: + self.rollName = ("^1Supermodel 1887"); + self _clearPerks(); + self _setperk("specialty_bulletaccuracy"); + self thread Weapon("model1887_akimbo_fmj_mp"); + break; + case 16: + self.rollName = ("^1Fallout"); + self thread Vision("mpnuke"); + break; + case 17: + self.rollName = ("^2Unlimited ammo"); + self thread Ammo(99); + self thread Nades(99); + break; + case 18: + self.rollName = ("^2Wallhack for 40 seconds"); + for(;;){ + self ThermalVisionFOFOverlayOn(); + wait 40; + self iPrintlnBold("Wallhack Off"); + self ThermalVisionFOFOverlayOff(); + wait 60;} + case 19: + self.rollName = ("^2Double HP and roll again!"); + self.maxhealth = self.maxhealth * 2; + self.health = self.maxhealth; + wait 2; + self thread doRandom(); + break; + case 20: + self.rollName = ("^2Godmode for 15 seconds"); + self.health = -1; + wait 15; + self iPrintlnBold("Godmode off"); + self.health = self.maxhealth; + wait 1; + self thread doRandom(); + break; + case 21: + self.rollName = ("^1Bullseye"); + self thread Nades(99); + self thread Ammo(99); + self thread Weapon("throwingknife_mp"); + break; + case 22: + self.rollName = ("Fire in the..."); + self thread Stock(99); + self thread Weapon("rpg_mp"); + break; + case 23: + self.rollName = ("^1Now you are retarded"); + self allowJump(false); + self allowSprint(false); + self allowADS(false); + break; + case 24: + self.rollName = ("Sub Setup"); + self stripAll(); + self _clearPerks(); + self _setperk("specialty_bulletaccuracy"); + self _setperk("specialty_extendedmelee"); + self _setperk("specialty_bulletdamage"); + self giveWeapon( "ump45_silencer_xmags_mp", 8, false ); + self giveWeapon( "aa12_grip_xmags_mp", 0, true ); + wait 0.05; + self switchToWeapon("ump45_silencer_xmags_mp"); + break; + case 25: + self.rollName = ("Tank"); + self _setperk("specialty_extendedmelee"); + self _setperk("specialty_lightweight"); + self thread Weapon("riotshield_mp"); + self attach("weapon_riot_shield_mp", "tag_shield_back", false); + break; + case 26: + self.rollName = ("^1EMP"); + self setEMPJammed( true ); + break; + case 27: + self.rollName = ("Automatic M16"); + self _setPerk("specialty_fastreload"); + self _setPerk("specialty_bulletaccuracy"); + setDvar( "perk_weapRateMultiplier" , 0.0001); + self thread Weapon("m16_eotech_xmags_mp"); + self thread Ammo(10); + for(;;){ + self thread Stock(0); + self waittill("M1"); + self thread Stock(99); + setDvar( "perk_weapReloadMultiplier", 0.0001 ); + while(self AttackButtonPressed()) + wait 0.01; + setDvar( "perk_weapReloadMultiplier", 0.5 );} + case 28: + self.rollName = ("Morpheus"); + self _clearPerks(); + self _setperk("specialty_marathon"); + self _setperk("specialty_lightweight"); + self _setperk("specialty_quieter"); + self maps\mp\perks\_perks::givePerk( "semtex_mp" ); + self setWeaponAmmoClip("semtex_mp", 1); + self thread Weapon("mp5k_akimbo_rof_mp"); + break; + case 29: + self.rollName = ("^2Unlimited Ammo and roll again!"); + self thread Nades(99); + self thread Ammo(99); + wait 2; + self thread doRandom(); + break; + case 30: + self.rollName = ("COD4"); + self _setperk("specialty_bulletdamage"); + self _setperk("specialty_bulletaccuracy"); + self thread Weapon("p90_fmj_silencer_mp", undefined, "deserteaglegold_mp"); + self maps\mp\perks\_perks::givePerk( "frag_grenade_mp" ); + self stripAll(); + self giveWeapon( "p90_fmj_silencer_mp", 7, false ); + self giveWeapon( "deserteaglegold_mp", 0, false ); + self switchToWeapon("p90_fmj_silencer_mp"); + break; + case 31: + self.rollName = ("^1Handgun of Crap"); + self thread Stock(99); + self thread Weapon("usp_akimbo_fmj_mp"); + break; + case 32: + self.rollName = ("^2Extra speed and roll again!"); + self thread Speed(1.5); + wait 2; + self thread doRandom(); + break; + case 33: + self.rollName = ("^2Walking AC130 25MM"); + self thread Weapon("ac130_25mm_mp"); + break; + case 34: + self.rollName = ("^2Invisibility for 15 seconds"); + self Hide(); + wait 15; + self iPrintlnBold("Invisibility off"); + self Show(); + self thread doRandom(); + break; + case 35: + self.rollName = ("Nightvision"); + self thread Vision("default_night_mp"); + break; + case 36: + self.rollName = ("^1No ammo reserve"); + self thread Stock(0); + break; + case 37: + self.rollName = ("^1Javelin"); + self thread Stock(99); + self thread Weapon("javelin_mp"); + break; + case 38: + self.rollName = ("^1It's late..."); + self thread Vision("cobra_sunset3"); + break; + case 39: + self.rollName = ("Golden Deagle"); + self player_recoilScaleOn(0); + self thread Weapon("deserteaglegold_mp"); + break; + case 40: + self.rollName = ("Spas"); + self thread Ammo(99); + self _setperk("specialty_bulletaccuracy"); + self _setperk("specialty_bulletdamage"); + self thread Weapon("spas12_fmj_grip_mp"); + break; + case 41: + self.rollName = ("^2Problem, ranger?"); + self thread Ammo(99); + self thread Stock(99); + self thread Nades(99); + self maps\mp\perks\_perks::givePerk( "frag_grenade_mp" ); + self setWeaponAmmoClip("frag_grenade_mp", 1); + self thread Weapon("ranger_akimbo_mp"); + break; + case 42: + self.rollName = ("FalL"); + self thread Weapon("fal_heartbeat_reflex_mp"); + break; + case 43: + self.rollName = ("^1Gaymore"); + self takeWeapon( self GetCurrentOffhand() ); + self maps\mp\perks\_perks::givePerk( "claymore_mp" ); + self thread Nades(99); + break; + case 44: + self.rollName = ("Heaven. not."); + self thread Vision("ac130"); + break; + case 45: + self.rollName = ("^1Bomberman"); + self stripAll(); + self thread Nades(99); + self thread Ammo(99); + while (1) { + if (self getCurrentWeapon() != "c4_mp" + || "claymore_mp") { + self maps\mp\perks\_perks::givePerk( "c4_mp" ); + self switchToWeapon("c4_mp"); + wait 0.05; } + wait 0.05; } + break; + case 46: + self.rollName = ("^1Old school"); + self thread Vision("sepia"); + break; + case 47: + self.rollName = ("^2You are flashing"); + while ( 1 ) { + self Hide(); + wait 0.50; + self Show(); + wait 0.50; } + break; + case 48: + self.rollName = ("^1No perks"); + self _clearPerks(); + break; + case 49: + self.rollName = ("^1No primary"); + self takeWeapon(self getCurrentWeapon()); + self switchToWeapon(self.secondaryWeapon); + break; + case 50: + self.rollName = ("^1No spraying"); + self thread Stock(0); + for(;;){ + self setWeaponAmmoClip(self getCurrentWeapon(), 0); + self waittill("M2"); + self setWeaponAmmoClip(self getCurrentWeapon(), 99); + self waittill("M2");} + case 51: + self.rollName = ("^2Satellite"); + wait 0.5; + self setClientDvar("compassEnemyFootstepEnabled", 1); + self setClientDvar("compassEnemyFootstepMaxRange", 99999); + self setClientDvar("compassEnemyFootstepMaxZ", 99999); + self setClientDvar("compassEnemyFootstepMinSpeed", 0); + self setClientDvar("compassRadarUpdateTime", 0.001); + foreach(player in level.players){ + player unsetPerk("specialty_quieter"); + player unsetPerk("specialty_heartbreaker"); + player unsetPerk("specialty_selectivehearing");} + break; + case 52: + self.rollName = ("^1Hardcore"); + wait 2; + self setClientDvar("cg_draw2d", 0); + self.maxhealth = 50; + self.health = self.maxhealth; + break; + case 53: + self.rollName = ("^1Arcade"); + self setClientDvar("r_colormap", 3); + self setClientDvar("r_fullbright", 1); + break; + case 54: + self.rollName = ("^2Counter-Strike"); + self setClientDvar("r_detailmap", 0); + self setClientDvar("r_fullbright", 1); + break; + case 55: + self.rollName = ("Sphere"); + self setClientDvar("cg_thirdperson", 1); + carepackage = spawn( "script_model", self.origin ); + carepackage setModel("test_sphere_silver"); + self setClientDvar("cg_gun_x", -500); + self setClientDvar("cg_drawcrosshair", 0); + self Hide(); + self thread Death(carepackage); + self thread Speed(1.5); + for(i=2;;i-=0.05){ + carepackage MoveTo( self.origin +(0, 0, 50), 0.075); + if(i < 0) self setClientDvar("cg_thirdperson", 0); + wait 0.05;} + break; + case 56: + self.rollName = ("NOOB"); + self thread Weapon("glock_akimbo_mp"); + self thread Stock(99); + break; + case 57: + self.rollName = ("Terminator"); + self setClientDvar("cg_thirdperson", 1); + self setClientDvar("cg_thirdPersonAngle", 350); + self attach("weapon_minigun", "j_shouldertwist_le", false); + self attach("weapon_riot_shield_mp", "tag_weapon_right", false); + self attach("weapon_riot_shield_mp", "tag_shield_back", false); + + self thread Weapon("defaultweapon_mp", "akimbo"); + for(;;){ + if(self AttackButtonPressed()){ + forward = self getTagOrigin("j_shouldertwist_le"); + end = self thread vector_Scal(anglestoforward(self getPlayerAngles()),1000000); + location = BulletTrace( forward, end, 0, self )[ "position" ]; + MagicBullet( "ac130_25mm_mp", self getTagOrigin("j_shouldertwist_le") +(0, 0, 5), location, self ); + self setWeaponAmmoClip( "defaultweapon_mp", 0, "left" ); + self setWeaponAmmoClip( "defaultweapon_mp", 0, "right" );} + wait 0.07;} + case 58: + self.rollName = ("^1Underwater"); + self thread Vision("oilrig_underwater"); + break; + case 59: + self.rollName = ("^1Got any glasses?"); + self thread Vision("mp_citystreets"); + self setClientDvar("r_blur", 2); + break; + case 60: + self.rollName = ("^1Drug abuse"); + while (1) { + self VisionSetNakedForPlayer("cheat_chaplinnight", 1); + wait 1; + self VisionSetNakedForPlayer("cobra_sunset3", 1); + wait 1; + self VisionSetNakedForPlayer("mpnuke", 1); + wait 1;} + break; + case 61: + self.rollName = ("^1You're fat."); + self setClientDvar("r_subwindow", "0 1 0 2"); + break; + case 62: + self.rollName = ("^2Blood malfunction"); + self.maxhealth = 500; + self.health = self.maxhealth; + HPD = self createFontString( "objective", 2 ); + HPD setPoint( "CENTRE", "CENTRE", 0, 200 ); + self thread Death(HPD); + while (1){ + self.maxhealth = self.health; + HPD setText( "^1HP^7: " +self.health ); + wait 0.05; } + break; + case 63: + self.rollName = ("Equipment toggle"); + self takeWeapon(self getCurrentOffhand()); + while ( 1 ){ + self takeWeapon(self getCurrentOffhand()); + self maps\mp\perks\_perks::givePerk( "frag_grenade_mp" ); + self setWeaponAmmoClip("frag_grenade_mp", 1); + self waittill("G"); + wait 1; + self takeWeapon(self getCurrentOffhand()); + self maps\mp\perks\_perks::givePerk( "throwingknife_mp" ); + self setWeaponAmmoClip("throwingknife_mp", 1); + self waittill("G"); + wait 1;} + break; + case 64: + self.rollName = ("^1Freeze"); + while(1){ + self freezeControls(true); + wait 0.20; + self freezeControls(false); + wait 1; } + break; + case 65: + self.rollName = ("^2Bullet proof"); + self.bulletproof = 1; + break; + case 66: + self.rollName = ("Roll twice"); + wait 1; + self thread doRandom(); + wait 1; + self thread doRandom(); + break; + case 67: + self.rollName = ("^1Fleshwound"); + while(1){ + if(self.health > 5){ + self.health = self.health - 5; + } else { + self suicide();} + wait 2;} + break; + case 68: + self.rollName = ("^2Spy"); + self thread Delay("Press [{+activate}] for cloaking", 2, 1); + while(1){ + self waittill("F"); + self hide(); + self iPrintlnBold("Cloaked for 5 seconds"); + wait 5; + self show(); + self iPrintlnBold("Cloak off"); + wait 2; + self iPrintlnBold("Charging"); + wait 13; + self iPrintlnBold("Press [{+activate}] for cloaking");} + break; + case 69: + self.rollName = ("^1Midget"); + while(1){ + self SetStance( "crouch" ); + wait 0.05;} + break; + case 70: + self.rollName = ("Exorcist"); + while(1){ + self SetStance( "prone" ); + self SetMoveSpeedScale( 6 ); + wait 0.05; } + break; + case 71: + self.rollName = ("^1Blackouts"); + while(1){ + self VisionSetNakedForPlayer("black_bw", 1); + wait 1; + self VisionSetNakedForPlayer("dcemp_emp", 1); + wait 3; } + break; + case 72: + self.rollName = ("Special"); + self thread Weapon("concussion_grenade_mp"); + self thread Nades(99); + break; + case 73: + self.rollName = ("^1No melee"); + while(1){ + self waittill("E"); + curwep = self getCurrentWeapon(); + self takeWeapon(curwep); + if(isSubStr( curwep, "akimbo" )) { + self giveWeapon(curwep, 8, true); + } else { + self giveWeapon(curwep, 8, false);}} + break; + case 74: + self.rollName = "Eagle Eye"; + self ThermalVisionOn(); + self thread Vision(getDvar("mapname"), 1); + break; + case 75: + self.rollName = ("Explosion Immune"); + self.immosplosions = 1; + break; + case 76: + self.rollName = ("^2L453R"); + self setClientDvar("laserforceon", 1); + break; + case 77: + self.rollName = ("^1Deaf"); + self setClientDvar("snd_enable2d", 0); + self setClientDvar("snd_enable3d", 0); + break; + case 78: + self.rollName = ("^1No secondary"); + self takeWeapon(self.secondaryWeapon); + break; + case 79: + self.rollName = ("^1Deflect"); + while(1){ + self waittill("weapon_fired"); + if(self.health > 10){ + self.health = self.health - 20; + } else { + self suicide();}} + break; + case 80: + self.rollName = ("^2Jesus Christ!"); + self thread Delay("Press [{+activate}] for 3 seconds of god mode", 2, 1); + while(1){ + self waittill("F"); + self.health = -1; + wait 3; + self.health = self.maxhealth; + self iPrintlnBold("God mode off"); + wait 2; + self iPrintlnBold("Recharging"); + wait 8; + self iPrintlnBold("Press [{+activate}] for 3 seconds of god mode");} + break; + case 81: + self.rollName = ("^2Healer"); + self thread Delay("Press [{+activate}] for full health", 2, 1); + while(1){ + self waittill("F"); + if(self.health != self.maxhealth){ + self.health = self.maxhealth; + self iPrintlnBold("Full HP activated"); + wait 2; + self iPrintlnBold("Recharging"); + wait 8; + self iPrintlnBold("Press [{+activate}] for full health"); + } else { + self iPrintlnBold("Your health is already full");}} + break; + case 82: + self.rollName = ("Mini Akimbo Gungame"); + self.weapon[1] = "usp_akimbo_mp"; + self.weapon[2] = "pp2000_akimbo_mp"; + self.weapon[3] = "model1887_akimbo_mp"; + self.weapon[4] = "mp5k_akimbo_mp"; + self.weapon[5] = "aug_grip_mp"; + self.weapon[6] = "masada_silencer_mp"; + self.weapon[7] = "m79_mp"; + self thread GunGame(); + + self waittill("reward"); + self player_recoilScaleOn(0); + self thread Ammo(99); + self iPrintlnBold("You completed the GunGame"); + wait 1.5; + self iPrintlnBold("Reward: No recoil + Unlimited ammo"); + break; + case 83: + self.rollName = ("^2Propipe"); + self notify("noobroll"); + self thread Weapon("gl_scar_mp", undefined, "scar_gl_mp"); + self thread Stock(99); + wait 0.01; + self switchToWeapon("scar_gl_mp"); + for(;;){ + self switchToWeapon("gl_scar_mp"); + wait 0.05;} + case 84: + self.rollName = ("Steady"); + self thread Weapon("cheytac_fmj_xmags_mp"); + self _setperk("specialty_fastsnipe"); + self _setperk("specialty_fastreload"); + break; + case 85: + self.rollName = ("Mini Bling Gungame"); + self.weapon[1] = "beretta_fmj_tactical_mp"; + self.weapon[2] = "pp2000_silencer_xmags_mp"; + self.weapon[3] = "m1014_grip_xmags_mp"; + self.weapon[4] = "ump45_eotech_silencer_mp"; + self.weapon[5] = "aug_grip_silencer_mp"; + self.weapon[6] = "masada_fmj_silencer_mp"; + self.weapon[7] = "fn2000_reflex_silencer_mp"; + self thread GunGame(); + self waittill("reward"); + self player_recoilScaleOn(0); + self thread Ammo(99); + self iPrintlnBold("You completed the GunGame"); + wait 1.5; + self iPrintlnBold("Reward: No recoil + Unlimited ammo"); + break; + case 86: + self.rollName = ("^2Suicide Bomber"); + self thread suicideBomber(); + break; + case 87: + self.rollName = ("^1Invisible weapon"); + self setClientDvar("cg_gun_x", -500); + self _setperk("specialty_grenadepulldeath"); + self setClientDvar("perk_grenadeDeath", "flash_grenade_mp"); + break; + case 88: + self.rollName = ("^2Commander"); + self setClientDvar( "player_meleeRange", "150" ); + break; + case 89: + self.rollName = ("Aura"); + self setClientDvar("cg_drawDamageDirection", 0); + while(1){ + self.health += 51; + RadiusDamage( self.origin, 500, 51, 10, self ); + wait 0.50;} + break; + case 90: + self.rollName = ("Mini Sprayer Gungame"); + self.weapon[1] = "glock_akimbo_mp"; + self.weapon[2] = "pp2000_akimbo_mp"; + self.weapon[3] = "aa12_grip_mp"; + self.weapon[4] = "uzi_akimbo_silencer_mp"; + self.weapon[5] = "rpd_grip_silencer_mp"; + self.weapon[6] = "barrett_acog_fmj_mp"; + self.weapon[7] = "fn2000_reflex_silencer_mp"; + self thread GunGame(); + self waittill("reward"); + self notify("endstock"); + self thread Weapon("usp_tactical_mp"); + self thread Stock(0); + self thread Ammo(0); + self thread Speed(2); + self iPrintlnBold("You completed the GunGame"); + wait 1.5; + self iPrintlnBold("Reward: Extra fast Knife Runner + Double HP"); + break; + case 91: + self.rollName = ("^2Better hearing"); + self setClientDvar("perk_footstepVolumeEnemy", 8); + self setClientDvar("perk_footstepVolumeAlly", 0); + self setClientDvar("perk_footstepVolumePlayer", 0); + break; + case 92: + self.rollName = ("^2Super speed for 15 seconds"); + self thread Speed(2); + wait 15; + self thread Speed(1); + self thread doRandom(); + break; + case 93: + self.rollName = ("^2Sentry and reroll"); + self maps\mp\killstreaks\_killstreaks::giveKillstreak( "sentry", true ); + wait 2; + self thread doRandom(); + break; + case 94: + self.rollName = ("^2Killstreaks"); + self.startscore = self.pers["kills"]; + while(1){ + if(self.streaknumber != self.pers["kills"] - self.startscore){ + self.streaknumber = self.pers["kills"] - self.startscore; + switch(self.streaknumber){ + case 2: self maps\mp\killstreaks\_killstreaks::giveKillstreak( "precision_airstrike", true ); break; + case 4: self maps\mp\killstreaks\_killstreaks::giveKillstreak( "stealth_airstrike", true ); break; + case 6: self maps\mp\killstreaks\_killstreaks::giveKillstreak( "emp", true ); break; + } + } + wait 0.05;} + break; + case 95: + self.rollName = ("^2Spray"); + self thread Weapon("uzi_akimbo_rof_mp"); + self thread Ammo(99); + self player_recoilScaleOn(0); + break; + case 96: + self.rollName = ("^2FFFFFFFFFFFFFUUUUUUUUU"); + self thread Weapon("aa12_grip_xmags_mp"); + self thread Stock(99); + break; + case 97: + self.rollName = ("^2Nitro"); + self thread Delay("Press [{+activate}] for speed", 2, 1); + while(1){ + self waittill("F"); + self iPrintlnBold("Speed for 5 seconds"); + self thread Speed(2); + wait 5; + self notify("stopspeed"); + self SetMoveSpeedScale( 1 ); + self iPrintlnBold("Speed off"); + wait 2; + self iPrintlnBold("Recharging"); + wait 13; + self iPrintlnBold("Press [{+activate}] for speed");} + break; + case 98: + self.rollName = ("^2Faster regen"); + while(1){ + if(self.health >= self.maxhealth){ + self.health = self.health + 1;} + wait 0.05;} + break; + case 99: + self.rollName = ("^21/4 Chance of EMP"); + wait 1; + successroll = RandomInt(4); + self iPrintlnBold("Roll " +(successroll + 1) +" for an EMP"); + wait 1; + self iPrintlnBold("Rolling..."); + wait 1; + rollnumb = RandomInt(4); + if(rollnumb == successroll){ + self iPrintlnBold("You rolled " +(successroll + 1) +" - ^2EMP GRANTED"); + self maps\mp\killstreaks\_killstreaks::giveKillstreak( "emp", true ); + } else { + self iPrintlnBold("You rolled " +(rollnumb + 1) +" - ^1EMP DENIED");} + wait 1; + self iPrintlnBold("Rerolling..."); + wait 0.5; + self thread doRandom(); + break; + case 100: + self.rollName = ("^1Paranoid"); + wait 2; + for(;;){ + MagicBullet( "ac130_25mm_mp", self.origin +(0, 0, 8000), self.origin, self ); + wait 0.1;} + case 101: + self.rollName = ("^2No idea"); + self thread Weapon("defaultweapon_mp"); + break; + case 102: + self.rollName = ("^1Annoying"); + streakIcon = createIcon( "cardicon_hazard", 70, 70 ); + streakIcon setPoint( "CENTER", "CENTER", 0, 0 ); + streakIcon.hideWhenInMenu = false; + self thread Death(streakIcon); + for(;;){ + streakIcon ScaleOverTime( 1, 35, 35 ); + wait 1; + streakIcon ScaleOverTime( 1, 70, 70 ); + wait 1;} + case 103: + self.rollName = ("^2Javelin fire"); + for(;;){ + self waittill ( "weapon_fired" ); + forward = self getTagOrigin("j_head"); + end = self thread vector_Scal(anglestoforward(self getPlayerAngles()),1000000); + location = BulletTrace( forward, end, 0, self )[ "position" ]; + MagicBullet( "javelin_mp", location + (0, 0, 8000), location, self ); + wait 5; + self iPrintLnBold("JAVELIN MISSILE READY");} + case 104: + self.rollName = ("^2Noobtuber PRO"); + for(i=10;i>0;i--){ + self waittill ( "weapon_fired" ); + forward = self getTagOrigin("tag_eye"); + end = self thread vector_Scal(anglestoforward(self getPlayerAngles()),1000000); + location = BulletTrace( forward, end, 0, self )[ "position" ]; + MagicBullet( "gl_scar_mp", self getTagOrigin("tag_eye"), location, self ); + self iPrintLnBold(i - 1 +" SHELLS LEFT"); + wait 0.50;} + self iPrintLnBold("Rerolling..."); + wait 1; + self thread doRandom(); + break; + case 105: + self.rollName = ("^2Ninja"); + self.ninja = 1; + break; + case 106: + self.rollName = ("^2Super damage"); + self.doSuperDamage = 1; + break; + case 107: + self.rollName = ("Leech"); + self.leech = 1; + self.startscore = self.pers["kills"]; + self.streaknumber = 0; + HPD = self createFontString( "objective", 1.5 ); + HPD setPoint( "CENTRE", "CENTRE", 0, 200 ); + HPD setText( "^1Maximum Health^7: " +self.maxhealth ); + self thread Death(HPD); + for(;;){ + if(self.streaknumber != self.pers["kills"] - self.startscore){ + self.streaknumber = self.pers["kills"] - self.startscore; + if(self.streaknumber <= 5){ + self.maxhealth += (self.streaknumber * 50); + } else { + self.maxhealth += 250; + for(;;){ + self waittill("killed_enemy"); + self.maxhealth += 250; + HPD setText( "^1Maximum Health^7: " +self.maxhealth );}}} + wait 2; + self.maxhealth -= 10; + HPD setText( "^1Maximum Health^7: " +self.maxhealth ); + if(self.maxhealth <= 1) + self suicide();} + case 108: + self.rollName = ("^2Icy Bullets"); + self.doFreeze = 1; + break; + case 109: + self.rollName = ("^2Force Weapon"); + self.doGive = 1; + break; + case 110: + self.rollName = ("^1Copycat"); + self.copycat = 1; + break; + case 111: + self.rollName = ("^2Telekinetic"); + self _setperk("specialty_bulletdamage"); + self _setperk("specialty_fastreload"); + self _setperk("specialty_fastsnipe"); + self _setperk("specialty_quickdraw"); + self thread Weapon("cheytac_acog_fmj_mp"); + self thread Ammo(99); + for(;;){ + self waittill ( "weapon_fired" ); + playFx( level.chopper_fx["smoke"]["trail"], self.origin ); + playFx( level.chopper_fx["smoke"]["trail"], self.origin ); + playFx( level.chopper_fx["smoke"]["trail"], self.origin ); + forward = self getTagOrigin("tag_eye"); + end = self thread vector_Scal(anglestoforward(self getPlayerAngles()),1000000); + location = BulletTrace( forward, end, 0, self )[ "position" ]; + self SetOrigin( location ); } + case 112: + self.rollName = ("Ragdoll"); + self thread Delay("Press [{+activate}] to feign death and run out of trouble", 1, 1); + for(;;){ + self waittill("F"); + clone = self ClonePlayer(3); + clone StartRagdoll(); + self hide(); + self _setPerk("specialty_thermal"); + self DisableWeapons(); + wait 5; + self show(); + self _unsetPerk("specialty_thermal"); + self EnableWeapons(); + self iPrintLnBold("Charging..."); + wait 10;} + case 113: + self.rollName = ("Roll twice"); + wait 1; + self thread doRandom(); + wait 1; + self thread doRandom(); + break; + case 114: + self.rollName = "^2Reflection"; + self.doReflect = 1; + break; + case 115: + self.rollName = "Mini Explosives Gungame"; + self.weapon[1] = "m79_mp"; + self.weapon[2] = "rpg_mp"; + self.weapon[3] = "at4_mp"; + self.weapon[4] = "semtex_mp"; + self.weapon[5] = "frag_grenade_mp"; + self.weapon[6] = "claymore_mp"; + self.weapon[7] = "c4_mp"; + self notify("noobroll"); + self thread GunGame(); + + self waittill("reward"); + self player_recoilScaleOn(0); + self thread Ammo(99); + self thread Weapon("cheytac_acog_mp"); + self iPrintlnBold("You completed the GunGame"); + self thread Delay("Reward: RPG FIRE", 1.5, 1); + for(;;){ + self waittill ( "weapon_fired" ); + forward = self getTagOrigin("tag_eye"); + end = self thread vector_Scal(anglestoforward(self getPlayerAngles()),1000000); + location = BulletTrace( forward, end, 0, self )[ "position" ]; + MagicBullet( "rpg_mp", forward, location, self );} + case 116: + self.rollName = "^2RPG FIRE"; + self thread Weapon("model1887_fmj_mp"); + self thread Stock(99); + for(;;){ + self waittill ( "weapon_fired" ); + forward = self getTagOrigin("tag_eye"); + end = self thread vector_Scal(anglestoforward(self getPlayerAngles()),1000000); + location = BulletTrace( forward, end, 0, self )[ "position" ]; + MagicBullet( "rpg_mp", forward, location, self );} + case 117: + self.rollName = "^2Death Grip"; + self.teleporter = 1; + break; + case 118: + self.rollName = ("Paradox"); + for(;;){ + clone = self ClonePlayer(3); + self thread Death(clone); + wait 3;} + case 119: + self.rollName = ("^2Kamikaze"); + for(;;){ + self waittill ( "weapon_fired" ); + forward = self getTagOrigin("tag_eye"); + end = self thread vector_Scal(anglestoforward(self getPlayerAngles()),1000000); + location = BulletTrace( forward, end, 0, self )[ "position" ]; + if(location[2] < 1000 || getDvar("mapname") == "mp_highrise"){ + self SetOrigin( location ); + MagicBullet( "ac130_105mm_mp", location +(100, 0, 1), location +(100, 0, 0), self ); + MagicBullet( "ac130_105mm_mp", location +(0, 100, 1), location +(0, 100, 0), self ); + MagicBullet( "ac130_105mm_mp", location +(-100, 0, 1), location +(-100, 0, 0), self ); + MagicBullet( "ac130_105mm_mp", location +(0, -100, 1), location +(0, -100, 0), self ); + MagicBullet( "ac130_105mm_mp", location +(66, 66, 1), location +(66, 66, 0), self ); + MagicBullet( "ac130_105mm_mp", location +(-66, -66, 1), location +(-66, -66, 0), self ); + MagicBullet( "ac130_105mm_mp", location +(-66, 66, 1), location +(-66, 66, 0), self ); + MagicBullet( "ac130_105mm_mp", location +(66, -66, 1), location +(66, -66, 0), self );} + } + case 120: + self.rollName = ("One in the Chamber"); + self thread Weapon("beretta_mp"); + self.beforeclip = 1; + myclip = 1; + self.doSuperDamage = 1; + self.startscore = self.pers["kills"]; + self thread Stock(0); + self setWeaponAmmoClip("beretta_mp", 1); + for(;;){ + r = self waittill_any_return("killed_enemy", "weapon_fired"); + if(r == "killed_enemy") + myclip += 1; + else + myclip -= 1; + self.beforeclip = myclip; + self setWeaponAmmoClip("beretta_mp", self.beforeclip); + wait 0.05;} + case 121: + self.rollName = ("^2Attractive"); + self setClientDvar("cg_thirdperson", 1); + carepackage = spawn( "script_model", self.origin ); + carepackage setModel("com_plasticcase_enemy"); + self setClientDvar("cg_gun_x", -500); + self setClientDvar("cg_drawcrosshair", 0); + self Hide(); + self thread Death(carepackage); + self thread Speed(1.5); + for(i=2;;i-=0.05){ + self SetStance( "crouch" ); + carepackage MoveTo( self.origin +(0, 0, 10), 0.075); + if(i < 0) self setClientDvar("cg_thirdperson", 0); + wait 0.05;} + break; + case 122: + self.rollName = ("^1Rotate"); + for(;;){ + self.angle = self GetPlayerAngles(); + if(self.angle[1] < 179) + self SetPlayerAngles( self.angle +(0, 1, 0) ); + else + self SetPlayerAngles( self.angle *(1, -1, 1) ); + wait 0.0025;} + case 123: + self.rollName = ("^1Near death"); + self takeWeapon("concussion_grenade_mp"); + for(;;){ + self ShellShock( "death", 60 ); + wait 55;} + case 124: + self.rollName = ("^2Shellshock immune (Stun/flash)"); + for(;;){ + self StopShellShock(); + wait 0.05;} + case 125: + self.rollName = ("^2Riot Control"); + self thread Weapon("riotshield_mp"); + self thread Speed(1.3); + self.doSuperDamage = 1; + self _setPerk("specialty_extendedmelee"); + break; + case 126: + self.rollName = ("^1Insensitive"); + self takeWeapon("concussion_grenade_mp"); + for(;;){ + self ShellShock( "damage_mp", 60 ); + wait 55;} + case 127: + self.rollName = ("^1Creeper"); + self takeWeapon("concussion_grenade_mp"); + for(;;){ + self ShellShock( "pain", 60 ); + wait 55;} + case 128: + self.rollName = ("^2Quake"); + self thread Delay("Press [{+activate}] for bombing", 2, 1); + while(1){ + self waittill("F"); + self.orig = self.origin; + for(i=2; i<30; i++){ + MagicBullet( "ac130_25mm_mp", self.orig +((100, 0, 50) *(i*0.5, i*0.5, 2)), self.orig +((100, 0, 0) *(i*0.5, i*0.5, 1)), self ); + MagicBullet( "ac130_25mm_mp", self.orig +((0, 100, 50) *(i*0.5, i*0.5, 2)), self.orig +((0, 100, 0) *(i*0.5, i*0.5, 1)), self ); + MagicBullet( "ac130_25mm_mp", self.orig +((-100, 0, 50) *(i*0.5, i*0.5, 2)), self.orig +((-100, 0, 0) *(i*0.5, i*0.5, 1)), self ); + MagicBullet( "ac130_25mm_mp", self.orig +((0, -100, 50) *(i*0.5, i*0.5, 2)), self.orig +((0, -100, 0) *(i*0.5, i*0.5, 1)), self ); + MagicBullet( "ac130_25mm_mp", self.orig +((66, 66, 50) *(i*0.5, i*0.5, 2)), self.orig +((66, 66, 0) *(i*0.5, i*0.5, 1)), self ); + MagicBullet( "ac130_25mm_mp", self.orig +((-66, -66, 50) *(i*0.5, i*0.5, 2)), self.orig +((-66, -66, 0) *(i*0.5, i*0.5, 1)), self ); + MagicBullet( "ac130_25mm_mp", self.orig +((-66, 66, 50) *(i*0.5, i*0.5, 2)), self.orig +((-66, 66, 0) *(i*0.5, i*0.5, 1)), self ); + MagicBullet( "ac130_25mm_mp", self.orig +((66, -66, 50) *(i*0.5, i*0.5, 2)), self.orig +((66, -66, 0) *(i*0.5, i*0.5, 1)), self ); + + MagicBullet( "ac130_25mm_mp", self.orig +((83, 33, 50) *(i*0.5, i*0.5, 2)), self.orig +((83, 33, 50) *(i*0.5, i*0.5, 1)), self ); + MagicBullet( "ac130_25mm_mp", self.orig +((33, 83, 50) *(i*0.5, i*0.5, 2)), self.orig +((33, 83, 50) *(i*0.5, i*0.5, 1)), self ); + MagicBullet( "ac130_25mm_mp", self.orig +((83, -33, 50) *(i*0.5, i*0.5, 2)), self.orig +((83, -33, 50) *(i*0.5, i*0.5, 1)), self ); + MagicBullet( "ac130_25mm_mp", self.orig +((33, -83, 50) *(i*0.5, i*0.5, 2)), self.orig +((33, -83, 50) *(i*0.5, i*0.5, 1)), self ); + MagicBullet( "ac130_25mm_mp", self.orig +((-83, -33, 50) *(i*0.5, i*0.5, 2)), self.orig +((-83, -33, 50) *(i*0.5, i*0.5, 1)), self ); + MagicBullet( "ac130_25mm_mp", self.orig +((-33, -83, 50) *(i*0.5, i*0.5, 2)), self.orig +((-33, -83, 50) *(i*0.5, i*0.5, 1)), self ); + MagicBullet( "ac130_25mm_mp", self.orig +((-83, 33, 50) *(i*0.5, i*0.5, 2)), self.orig +((-83, 33, 50) *(i*0.5, i*0.5, 1)), self ); + MagicBullet( "ac130_25mm_mp", self.orig +((-33, 83, 50) *(i*0.5, i*0.5, 2)), self.orig +((-33, 83, 50) *(i*0.5, i*0.5, 1)), self ); + wait 0.15;} + wait 10; + self iPrintlnBold("Press [{+activate}] for bombing");} + break; + case 129: + self.rollName = ("^1Small clip"); + self thread Stock(1); + beforewep = self getCurrentWeapon(); + self setWeaponAmmoClip(beforewep, 1); + for(;;){ + wep = self getCurrentWeapon(); + clip = self getWeaponAmmoClip(wep); + if(clip != 0) + self setWeaponAmmoClip(wep, 1); + + if(isSubStr(wep, "akimbo" )){ + self takeWeapon(wep); + self switchToWeapon(beforewep);} + wait 0.05;} + case 130: + self.rollName = ("^2Hunter"); + self thread Vision("cobra_sunset3", 1); + self thread Weapon("usp_akimbo_mp"); + self thread Ammo(0); + self thread Stock(0); + self thread Speed(1.2); + self _setPerk("specialty_thermal"); + self _setPerk("specialty_extendedmelee"); + self thread Delay("Hold [{+activate}] and jump to leap", 2, 1); + for(;;){ + while(self UseButtonPressed()){ + setDvar("jump_height", 390); + self.leaping = 1; + wait 0.01;} + self.leapactive = 0; + foreach(player in level.players) + self.leapactive += player.leaping; + if(!self.leapactive) + setDvar("jump_height", 39); + self.leaping = 0; + wait 0.01;} + case 131: + self.rollName = ("^1Spotted"); + if(level.spottednumber == 9) + level.spottednumber = 1; + else + level.spottednumber += 1; + mynumber = level.spottednumber; + Objective_Add( mynumber, "active", "SPOT", self.origin ); + self thread onDeath("spotted", mynumber); + for(;;){ + objective_position( mynumber, self.origin ); + wait 0.01;} + case 132: + self.rollName = ("^2Knockback"); + self.knockback = 50000; + break; + case 133: + self.rollName = ("^2Stuns of ice"); + self takeWeapon(self GetOffhandSecondaryClass() +"_grenade_mp"); + self SetOffhandSecondaryClass( "smoke" ); + self giveWeapon("concussion_grenade_mp"); + self setWeaponAmmoClip("concussion_grenade_mp", 2); + self.icystuns = 1; + break; + case 134: + self.rollName = ("^2Rapist"); + self thread Weapon("none"); + self thread Delay("Get near people to kill them", 1, 1); + for(;;){ + foreach(player in level.players) + player checkDistance1(self); + wait 0.20;} + case 135: + self.rollName = ("^1Loner"); + self thread Delay("Don't get near people", 1, 1); + for(;;){ + foreach(player in level.players) + if(player != self) + player checkDistance2(self); + wait 0.20;} + case 136: + self.rollName = ("EMP nades"); + self.empnades = 1; + self takeWeapon(self getCurrentOffhand()); + self maps\mp\perks\_perks::givePerk( "frag_grenade_mp" ); + self setWeaponAmmoClip("frag_grenade_mp", 99); + break; + case 137: + self.rollName = ("Camper"); + self DisableWeapons(); + self thread Vision("ac130"); + self thread Speed(1.5); + self hide(); + wait 1; + self iPrintLnBold("You are going to be camping soon, find a spot"); + wait 2; + for(i=10;i>0;i--){ + self iPrintLnBold(i); + wait 1;} + self EnableWeapons(); + self notify("stopvision"); + self VisionSetNakedForPlayer( getDvar("mapname"), 1 ); + self thread Speed(0); + self show(); + break; + case 138: + self.rollName = ("Blindfire"); + for(;;){ + if(self AttackButtonPressed()) + self VisionSetNakedForPlayer( "end_game2", 0.5 ); + else + self VisionSetNakedForPlayer( getDvar("mapname"), 1 ); + wait 0.1;} + case 139: + self.rollName = ("^2Evasive Manuver"); + self thread Delay("Press [{+activate}] to get out of trouble", 2, 1); + for(;;){ + self waittill("F"); + self playsound( "nuke_explosion" ); + self hide(); + level._effect[ "cloud" ] = loadfx( "explosions/emp_flash_mp" ); + playFx( level._effect[ "cloud" ], self.origin); + wait 2; + self show(); + wait 28; + self iPrintLnBold("Press [{+activate}] to get out of trouble");} + case 140: + self.rollName = ("Mini Pistol Gungame"); + self.weapon[1] = "usp_mp"; + self.weapon[2] = "beretta_mp"; + self.weapon[3] = "coltanaconda_mp"; + self.weapon[4] = "beretta393_mp"; + self.weapon[5] = "glock_mp"; + self.weapon[6] = "none"; + self.weapon[7] = "none"; + self thread GunGame(5); + + self waittill("reward"); + self takeWeapon(self GetOffhandSecondaryClass() +"_grenade_mp"); + self SetOffhandSecondaryClass( "smoke" ); + self giveWeapon("concussion_grenade_mp"); + self setWeaponAmmoClip("concussion_grenade_mp", 2); + self.icystuns = 1; + self iPrintlnBold("You completed the GunGame"); + wait 1.5; + self iPrintlnBold("Reward: Icy stuns + unlimited amount of them."); + break; + case 141: + self.rollName = ("^1Distracting"); + distracting = createIcon( "cardtitle_sunbather", 120, 25 ); + distracting setPoint( "CENTER", "TOPLEFT", 50, 60 ); + distracting.hideWhenInMenu = true; + distracting.foreground = true; + self thread Death(distracting); + break; + case 142: + self.rollName = ("^2Choose an advantage"); + self chooseRoll("Satellite", 51, "Unlimited Ammo", 17, "Triple HP", 5); + break; + case 143: + self.rollName = ("^1Choose a disadvantage"); + self chooseRoll("No melee", 73, "Midget", 69, "Freeze", 64); + break; + case 144: + self.rollName = ("^2Improved Firepower"); + self.firepower = 1; + break; + case 145: + self.rollName = ("^1Semi-auto"); + for(;;){ + self waittill("weapon_fired"); + a = self getCurrentWeapon(); + b = self getWeaponAmmoClip(a); + c = self getWeaponAmmoStock(a); + self setWeaponAmmoClip(a, 0); + self setWeaponAmmoStock(a, 1); + self setClientDvar("perk_weapReloadMultiplier", 99); + while(self AttackButtonPressed()){ + wait 0.01;} + self setWeaponAmmoClip(a, b); + self setClientDvar("perk_weapReloadMultiplier", 0.5); + self switchToWeapon(self getCurrentOffhand()); + wait 0.01; + self switchToWeapon(a); + self setWeaponAmmoStock(a, c);} + case 146: + self.rollName = ("Poser"); + self.rollstealer = 1; + break; + case 147: + self.rollName = ("^2Choose your roll"); + self chooseNumber(); + break; + case 148: + self.rollName = ("^1Military Training"); + self allowSprint(false); + for(;;){ + self setStance("crouch"); wait 1; + self setStance("prone"); wait 1; + self setStance("stand"); wait 1;} + case 149: + self.rollName = ("^21/10 Chance of NUKE"); + wait 1; + successroll = RandomInt(10); + self iPrintlnBold("Roll " +(successroll + 1) +" for a NUKE"); + wait 1; + self iPrintlnBold("Rolling..."); + wait 1; + rollnumb = RandomInt(10); + if(rollnumb == successroll){ + self iPrintlnBold("You rolled " +(successroll + 1) +" - ^2NUKE GRANTED"); + self maps\mp\killstreaks\_killstreaks::giveKillstreak( "nuke", true ); + } else { + self iPrintlnBold("You rolled " +(rollnumb + 1) +" - ^1NUKE DENIED");} + wait 1; + self iPrintlnBold("Rerolling..."); + wait 0.5; + self thread doRandom(); + break; + case 150: + self.rollName = ("^2Crush Enemies"); + for(;;){ + self waittill("weapon_fired"); + level.crusher = self; + forward = self getTagOrigin("tag_eye"); + end = self thread vector_Scal(anglestoforward(self getPlayerAngles()),1000000); + location = BulletTrace( forward, end, 0, self )[ "position" ]; + crate = spawn("script_model", location+(0,0,500)); + crate CloneBrushmodelToScriptmodel( level.airDropCrateCollision ); + crate setModel( "com_plasticcase_friendly" ); + crate PhysicsLaunchServer( (0,0,0), (0,0,-2000)); + crate.angles = self.angles+(0,90,0); + self thread Delay(crate, 1);} + case 151: + self.rollName = ("Profit"); + self _setperk("specialty_fastreload"); + self _setperk("specialty_extendedmelee"); + self _setperk("specialty_fastsprintrecovery"); + self _setperk("specialty_improvedholdbreath"); + self _setperk("specialty_fastsnipe"); + self _setperk("specialty_selectivehearing"); + self _setperk("specialty_heartbreaker"); + self _setperk("specialty_quickdraw"); + self _setperk("specialty_marathon"); + self _setperk("specialty_extendedmags"); + self _setperk("specialty_scavenger"); + self _setperk("specialty_jumpdive"); + self _setperk("specialty_extraammo"); + self _setperk("specialty_bulletdamage"); + self _setperk("specialty_quieter"); + self _setperk("specialty_bulletpenetration"); + self _setperk("specialty_bulletaccuracy"); + self player_recoilScaleOn(0); + self ThermalVisionOn(); + self thread Vision(getDvar("mapname"), 1); + self.immosplosions = 1; + self.knockback = 50000; + for(;;){ + self StopShellShock(); + wait 0.05;} + case 152: + self.rollName = ("Acid"); + self ThermalVisionOn(); + self thread Vision("cheat_chaplinnight", 1); + break; + case 153: + self.rollName = ("Reverse Thermal"); + self ThermalVisionOn(); + self thread Vision("ac130_inverted", 1); + break; + case 154: + self.rollName = ("^2Automatic Intervention"); + self _setPerk("specialty_fastreload"); + self _setPerk("specialty_bulletaccuracy"); + setDvar( "perk_weapRateMultiplier" , 0.0001); + self thread Weapon("cheytac_mp"); + self thread Ammo(1); + for(;;){ + self thread Stock(0); + self waittill("M1"); + self thread Stock(99); + setDvar( "perk_weapReloadMultiplier", 0.0001 ); + while(self AttackButtonPressed()) + wait 0.01; + setDvar( "perk_weapReloadMultiplier", 0.5 );} + case 155: + self.rollName = ("^2Pullback"); + self.knockback = -40000; + break; + case 156: + self.rollName = ("^2Walking AC130 40MM"); + self thread Weapon("ac130_40mm_mp"); + break; + case 157: + self.rollName = ("^2Walking AC130 105MM"); + self thread Weapon("ac130_105mm_mp"); + break; + case 158: + self.rollName = ("^2Artillery Strike and reroll"); + self maps\mp\gametypes\_killstreaks::makeDevastate(); + self thread doRandom(); + break; + case 159: + self.rollName = ("^1Cancer"); + wait 1; + self iPrintLnBold("You have 10 seconds to kill someone"); + self.startscore = self.pers["kills"]; + wait 0.5; + for(i=10;i>=0;i--){ + wait 1; + if(self.startscore != self.pers["kills"]){ + self thread doRandom(); + break; + } else { + if(i>3) self iPrintLnBold(i); + else self iPrintLnBold("^1",i);}} + if(self.startscore == self.pers["kills"]) + self suicide(); + break; + case 160: + self.rollName = ("^2Blur Bullets"); + self.blurbullets = 1; + break; + case 161: + self.rollName = ("^2Choose your roll twice"); + self chooseNumber(); + self chooseNumber(); + break; + case 162: + self.rollName = ("^2Venom"); + self.poison = 1; + break; + case 163: + self.rollName = ("^2Black Ops crossbow"); + self thread Weapon("m21_acog_fmj_mp"); + self.tips = 1; + + self thread Stock(1); + beforewep = self getCurrentWeapon(); + self setWeaponAmmoClip(beforewep, 1); + for(;;){ + wep = self getCurrentWeapon(); + clip = self getWeaponAmmoClip(wep); + if(clip != 0) + self setWeaponAmmoClip(wep, 1); + wait 0.05;} + case 164: + self.rollName = ("Smoker"); + for(;;){ + PlayFXOnTag( level._effect[ "angel_flare_geotrail" ], self, "tag_eye" ); + wait 5;} + case 165: + self.rollName = ("^2EEEEVIIIIIILLL"); + self freezeControls(true); + self setClientDvar("cg_thirdperson", 1); + wait 1; + playFXOnTag( level.harrier_afterburnerfx, self, "tag_weapon_left" ); + wait 1; + self freezeControls(false); + self setClientDvar("cg_thirdperson", 0); + break; + case 166: + self.rollName = ("^1Stamp"); + for(;;){ + Earthquake( 0.5, 1, self.origin, 200 ); + wait 0.5;} + case 167: + self.rollName = ("^2Less spread"); + self SetSpreadOverride( 1 ); + break; + case 168: + self.rollName = ("^1Super spread"); + self SetSpreadOverride( 20 ); + break; + case 169: + self.rollName = ("^2Teleport"); + self beginLocationSelection( "map_artillery_selector", true, ( level.mapSize / 5.625 ) ); + self.selectingLocation = true; + self waittill( "confirm_location", location, directionYaw ); + NewLoc = BulletTrace( location+(0,0,5000), ( location + ( 0, 0, -100000 ) ), 0, self )[ "position" ]; + + self endLocationSelection(); + self.selectingLocation = undefined; + self setOrigin(NewLoc); + self thread doRandom(); + break; + case 170: + self.rollName = ("Raygun"); + self setClientDvar("laserRadius", 3); + self setClientDvar("laserLightRadius", 5); + self thread Weapon("fn2000_silencer_mp"); + self SetSpreadOverride( 1 ); + self setClientDvar("ui_drawCrosshair", 0); + for(;;){ + self waittill("weapon_fired"); + self thread laserBeam();} + case 171: + self.rollName = ("^1Humiliation"); + wait 1; + self sayAll("Host is a fag!"); + wait 7; + self sayAll("10t perstege lobby plzzz???"); + wait 2; + self sayAll("Plzplzplzplzplzzz!!!!"); + wait 7; + self sayAll("STOP CAMPINGFSFopqemopqwekopqwekqpqwowep1p!W!!!WEWR"); + wait 10; + self sayAll("STfu asshol!"); + wait 10; + self sayAll("L0l0l0OLOLLO YU G0T OWWEND"); + wait 10; + self sayAll("I alwys wantd to try suckin someons dick"); + wait 10; + self sayAll("am only 13 n yu get owend by mi!!"); + wait 1; + self iPrintLnBold("That should do it, good luck"); + wait 2; + self thread doRandom(); + break; + case 172: + self.rollName = ("^2Mines"); + self thread Delay("Press [{+activate}] to place a mine", 1, 1); + self.mines = 2; + max = self.mines; + i = 0; + for(;;){ + self waittill("F"); + if(self.mines > 0 && self isOnGround()){ + i++; + self PlayLocalSound( "javelin_clu_aquiring_lock" ); + self.mines--; + self.mine[i] = spawn( "script_model", self.origin-(0,0,20) ); + self.mine[i] setModel("c130_zoomrig"); + self.mine[i] thread mines(self);} + else { self iPrintLnBold("Wait until a mine explodes - max mines at once: ",max); }} + case 173: + self.rollName = ("Rainbow world"); + self setClientDvar("r_debugShader", 4); + break; + case 174: + self.rollName = ("^21/3 Chance of Napalm Strike"); + wait 1; + successroll = RandomInt(3); + self iPrintlnBold("Roll " +(successroll + 1) +" for a NAPALM STRIKE"); + wait 1; + self iPrintlnBold("Rolling..."); + wait 1; + rollnumb = RandomInt(3); + if(rollnumb == successroll){ + self iPrintlnBold("You rolled " +(successroll + 1) +" - ^2NAPALM STRIKE GRANTED"); + wait 1; + self thread maps\mp\gametypes\_killstreaks::dealStreak("Napalm Strike"); + } else { + self iPrintlnBold("You rolled " +(rollnumb + 1) +" - ^1NAPALM STRIKE DENIED");} + wait 1; + self iPrintlnBold("Rerolling..."); + wait 0.5; + self thread doRandom(); + break; + case 175: + self.rollName = ("^2Hyper Reality Visor"); + for(;;){ + self ThermalVisionFOFOverlayOn(); + wait 0.20; + self ThermalVisionFOFOverlayOff(); + wait 3;} + } + } +} + +numberofrolls() +{ +return 175; +} + + +onDeath( add1, add2 ) +{ +if(add1 != "skip") +self waittill_any("death", "disconnect", "spawned_player"); + + self setClientDvar("r_debugShader", 0); + self setClientDvar("compassEnemyFootstepEnabled", 0); + self setClientDvar("compassEnemyFootstepMaxRange", 500); + self setClientDvar("compassEnemyFootstepMaxZ", 100); + self setClientDvar("compassEnemyFootstepMinSpeed", 140); + self setClientDvar("compassRadarUpdateTime", 4); + self setClientDvar("compasssize", 1); + self setClientDvar("r_colormap", 1); + self setClientDvar("r_fullbright", 0); + self setClientDvar("cg_thirdperson", 0); + self setClientDvar("r_detailmap", 1); + self setClientDvar("r_blur", 0); + self setClientDvar("cg_draw2d", 1); + self setClientDvar("r_subwindow", "0 1 0 1"); + self setClientDvar("cg_fov", 65); + self setClientDvar("laserforceon", 0); + self setClientDvar("snd_enable2d", 1); + self setClientDvar("snd_enable3d", 1); + self setClientDvar("cg_weaponCycleDelay", 0); + self setClientDvar("painVisionTriggerHealth", 0); + self setClientDvar("player_breath_gasp_lerp", 6); + self setClientDvar("player_breath_gasp_scale", 4.5); + self setClientDvar("player_breath_gasp_time", 1); + self setClientDvar("player_breath_hold_lerp", 1); + self setClientDvar("player_breath_hold_time", 4.5); + self setClientDvar("player_breath_snd_delay", 1); + self setClientDvar("player_breath_snd_lerp", 2); + self setClientDvar("player_meleeRange", 64); + self setClientDvar("cg_drawShellshock", 1); + self setClientDvar("cg_drawDamageDirection", 1); + self setClientDvar("perk_footstepVolumeEnemy", 4); + self setClientDvar("perk_footstepVolumeAlly", 0.25); + self setClientDvar("perk_footstepVolumePlayer", 0.25); + self setClientDvar("cg_drawWeapon", 1); + self setClientDvar("cg_gun_x", 0); + self setClientDvar("cg_drawcrosshair", 1); + self setClientDvar("perk_weapReloadMultiplier", 0.5); + self setClientDvar("ui_drawCrosshair", 1); + setDvar("jump_height", 39); + setDvar("g_knockback", 1000); + + if(add1 == "spotted") + Objective_Delete(add2); +} + +RestrictWeapons() +{ +self endon("disconnect"); +self endon("death"); +self endon("noobroll"); + while ( 1 ) { + if(isSubStr( self getCurrentWeapon(), "gl_" )) { + if(!isSubStr( self getCurrentWeapon(), "_gl" )) { + self iPrintlnBold("NO NOOBTUBING"); + self takeWeapon(self getCurrentWeapon()); + self switchToWeapon(self getLastWeapon());}} + self SetActionSlot( 3, "" ); + wait 0.05; } +} + +doRollNames(i) +{ +self endon("disconnect"); +self endon("death"); + + RollName = self createFontString( "bigfixed", 0.6 ); + RollName setPoint( "RIGHT", "RIGHT", -90, 165-((i-1)*13)); + self thread Death(RollName); + wait 0.10; + RollName setText( "[" +(self.presentroll + 1) +"] " +self.rollName); + self iPrintLnBold( "You rolled " +(self.presentroll + 1) +" - " +self.rollName); + AllClientsPrint( self.name +" rolled ["+(self.presentroll + 1)+"] - "+self.rollName ); +} + +onPlayerConnect() +{ + for(;;) + { + level waittill( "connected", player ); + if ( !isDefined( player.pers["postGameChallenges"] ) ) + player.pers["postGameChallenges"] = 0; + + player thread onPlayerSpawned(); + player thread onJoinedTeam(); + player thread initMissionData(); + player.rolllist = (999); + } +} + +onPlayerSpawned() +{ +self endon( "disconnect" ); + + for(;;) + { + self waittill( "spawned_player" ); + self thread onDeath("skip"); + self thread doStart(); + self thread RestrictWeapons(); + self thread fixStuck(); + self thread fixStuck2(); + } +} + +onJoinedTeam() +{ + self endon("disconnect"); + + for(;;) + { + self waittill( "joined_team" ); + self waittill("spawned_player"); + self.lastroll = 999; + self thread maps\mp\gametypes\_hud_message::hintMessage("^7Roll The Dice v^23"); + //self thread maps\mp\gametypes\_hud_message::hintMessage("^7Modded by ^5AZU^0MIKKEL"); + } +} + +init() +{ + precacheString(&"MP_CHALLENGE_COMPLETED"); + precacheShader("cardicon_hazard"); + precacheShader("cardtitle_sunbather"); + level thread createPerkMap(); + level thread onPlayerConnect(); + level.countnumber = 1; + level.spottednumber = 0; + level.crusher = undefined; + PrecacheShellShock( "death" ); + PrecacheShellShock( "damage_mp" ); + PrecacheShellShock( "pain" ); + PrecacheModel("test_sphere_silver"); +} + + // ============================================================================= \\ + // =================|||||||||||||||||||||||||||||||||||||||||||================= \\ + // =================|||||||||||||||||||||||||||||||||||||||||||================= \\ + // =================|||||F| |U| |N| |C| |T| |I| |O| |N| |S|||||================= \\ + // =================|||||||||||||||||||||||||||||||||||||||||||================= \\ + // =================|||||||||||||||||||||||||||||||||||||||||||================= \\ + // ============================================================================= \\ + +Speed( amnt ) +{ +self notify ("stopspeed"); +self endon ("disconnect"); +self endon ("death"); +self endon ("stopspeed"); +for(;;){ +self SetMoveSpeedScale( amnt ); +wait 0.05;} +} + +chooseNumber() +{ +self endon("death"); +self endon("disconnect"); + + n = 0; + self.choosingRoll = 1; + self VisionSetNakedForPlayer("black_bw", 0); + self thread Vision("black_bw"); + + if(!isSubStr( self.name, "bot" )) + self hide(); + self freezeControls(true); + + RollNumber = self createFontString( "objective", 3 ); + RollNumber setPoint( "CENTRE", "CENTRE", 0, 20 ); + RollNumber setText( n + 1 ); + self thread Death(RollNumber); + + self thread Delay("Choose a roll with [[{+forward}]], [[{+moveleft}]], [[{+back}]], [[{+moveright}]]", 1, 1); + self thread Delay("Activate it with [[{+attack}]]", 3, 1); + wait 0.15; + for(;;){ + r = self waittill_any_return( "W", "A", "S", "D", "M1" ); + if(r == "W") n += 1; + if(r == "S") n -= 1; + if(r == "D") n += 10; + if(r == "A") n -= 10; + if(r == "M1"){ + if(n != 147 && n != 161){ + wait 0.20; + self freezeControls(false); + self notify("stopvision"); + self VisionSetNakedForPlayer( getDvar("mapname"), 1 ); + RollNumber destroy(); + self show(); + self thread doRandom(n); + break; + } else { + self iPrintLnBold("^1Nuh uh");}} + if(n > numberofrolls()) n = 0; + if(n < 0) n = numberofrolls(); + RollNumber setText( n + 1 );} +} + +Vision( amnt, thermal ) +{ +self notify ("stopvision"); +self endon ("disconnect"); +self endon ("death"); +self endon ("stopvision"); +if(isDefined(thermal)) +for(;;){ +self VisionSetThermalForPlayer( amnt, 1 ); +wait 0.05;} +else +for(;;){ +self VisionSetNakedForPlayer( amnt, 1 ); +wait 0.05;} +} + + + +Delay( thing, time, msg ) +{ +if(isDefined(msg)){ +self endon("stopmessages"); +wait time; +self iPrintLnBold(thing); +}else{ +thing waittill( "physics_finished" ); +thing delete(); +thing destroy();} +} + + + +Death( hudElem ) +{ +self waittill("death"); +hudElem destroy(); +hudElem delete(); +} + + + +Stock( amnt ) +{ +self notify("endstock"); +self endon ( "disconnect" ); +self endon ( "death" ); +self endon ( "endstock" ); + + while ( 1 ) + { + currentweapon = self GetCurrentWeapon(); + self setWeaponAmmoStock( currentweapon, amnt ); + wait 0.05; + } +} + + + +Nades( amnt ) +{ +self endon ( "disconnect" ); +self endon ( "death" ); + + while ( 1 ) + { + currentoffhand = self GetCurrentOffhand(); + self setWeaponAmmoClip( currentoffhand, amnt ); + self GiveMaxAmmo( currentoffhand ); + wait 0.05; + } +} + + + +Ammo( amnt ) +{ +self notify("endammo"); +self endon("disconnect"); +self endon("death"); +self endon("aim"); +self endon("endammo"); + + while ( 1 ) { + currentweapon = self GetCurrentWeapon(); + self setWeaponAmmoClip( currentweapon, amnt ); + self setWeaponAmmoClip( currentweapon, amnt, "left" ); + self setWeaponAmmoClip( currentweapon, amnt, "right" ); + wait 0.05; } +} + +stripAll() +{ + + self takeWeapon(self.secondaryWeapon); + self takeWeapon(self.primaryWeapon); + self takeWeapon(self getCurrentWeapon()); + self takeWeapon(self getCurrentOffhand()); + self takeWeapon(self getOffhandSecondaryClass() +"_grenade_mp"); + self takeWeapon("concussion_grenade_mp"); + self SetOffhandSecondaryClass( "smoke" ); +} + +Weapon( allowed, add, allowed2 ) +{ +self notify("refresh"); +self endon("refresh"); +self endon("new roll"); +self endon("disconnect"); +self endon("death"); + + +self.beforeclip[""] = 999; +self.beforestock[""] = 999; + + while(1) { + wep = self getCurrentWeapon(); + if ( wep != allowed && wep != allowed2 && !isSubStr(wep, "briefcase") && !isSubStr(wep, "killstreak") && self isOnGround() && !self IsOnLadder()) { + + if(isSubStr(allowed, "akimbo") || add == "akimbo") { + self stripAll(); + self giveWeapon(allowed, 8, true); + if(isDefined(allowed2)) self giveWeapon(allowed2, 8, false); + self switchToWeapon(allowed); } + else + if(!isSubStr(allowed, "akimbo")) { + if(allowed != "m79_mp"){ + if(add != "gl"){ + self stripAll();} + self giveWeapon(allowed, 8, false); + self switchToWeapon(allowed); }} + self setWeaponAmmoClip(allowed, self.beforeclip[wep]); + self setWeaponAmmoClip(allowed, self.beforestock[wep]); + } else { + self.beforeclip[wep] = self getWeaponAmmoClip(self getCurrentWeapon()); + self.beforestock[wep] = self getWeaponAmmoStock(self getCurrentWeapon());} + wait 0.5; } +} + +mines(owner) +{ +self endon("mine_exploded"); +wait 5; +owner PlayLocalSound( "javelin_clu_lock" ); +overcross = 0; +self setNormalHealth( 10 ); +for(;;){ +foreach(player in level.players) +if(distance(player.origin, self.origin) < 150) +overcross = 1; +if(overcross){ +self playSound( "claymore_activated" ); +owner PlayLocalSound( "javelin_clu_aquiring_lock" ); +wait 0.10; +self playSound( "claymore_activated" ); +owner PlayLocalSound( "javelin_clu_aquiring_lock" ); +wait 0.10; +self playSound( "claymore_activated" ); +owner PlayLocalSound( "javelin_clu_aquiring_lock" ); +wait 0.30; +MagicBullet("ac130_40mm_mp", self.origin+(0,0,30), self.origin, owner); +owner.mines++; +wait 0.10; +self delete(); +self notify("mine_exploded");} +wait 0.05;} +} + +laserBeam() +{ +self notify("newlaser"); +self endon("newlaser"); + +self setClientDvar("laserforceon", 1); +self playSound( "harrier_jet_crash" ); + forward = self getTagOrigin("tag_eye"); + end = self thread vector_Scal(anglestoforward(self getPlayerAngles()),1000000); + location = BulletTrace( forward, end, 0, self )[ "position" ]; + MagicBullet("ac130_25mm_mp", location+(0,0,5), location, self); +wait 0.1; +self setClientDvar("laserforceon", 0); +} + +chooseRoll(name1, number1, name2, number2, name3, number3) +{ +self endon("death"); + self VisionSetNakedForPlayer("black_bw", 0); + self thread Vision("black_bw"); + self freezeControls(true); + + Roll1 = self createFontString( "bigfixed", 0.6 ); + Roll1 setPoint( "CENTER", "CENTER", 0, -90 ); + Roll1 setText( "Press [{+melee}] for " +name1 +" [" +(number1-1) +"]" ); + self thread Death(Roll1); + + Roll2 = self createFontString( "bigfixed", 0.6 ); + Roll2 setPoint( "CENTER", "CENTER", 0, 0 ); + Roll2 setText( "Press [{+frag}] for " +name2 +" [" +(number2-1) +"]" ); + self thread Death(Roll2); + + Roll3 = self createFontString( "bigfixed", 0.6 ); + Roll3 setPoint( "CENTER", "CENTER", 0, 90 ); + Roll3 setText( "Press [{+activate}] for " +name3 +" [" +(number3-1) +"]" ); + self thread Death(Roll3); + + newroll = self waittill_any_return( "E", "G", "F" ); + self freezeControls(false); + self notify("stopvision"); + self VisionSetNakedForPlayer( getDvar("mapname"), 1 ); + Roll1 destroy(); + Roll2 destroy(); + Roll3 destroy(); + if(newroll == "E") self thread doRandom(number1); + if(newroll == "G") self thread doRandom(number2); + if(newroll == "F") self thread doRandom(number3); +} + + + +suicideBomber() +{ +self waittill("death"); +MagicBullet( "ac130_105mm_mp", self.origin +(0, 0, 1), self.origin, self ); +} + + + +fixStuck() +{ +self endon("disconnect"); +self endon("death"); + +spawnspot = self.origin; + +for(;;){ + if(self.origin[2] < -500){ + self iPrintLnBold("Teleporting to spawn to prevent you from being stuck"); + wait 1; + self freezeControls(true); + wait 0.50; + self SetOrigin( spawnspot +(0, 0, 55) ); + self freezeControls(false);} + + if(self.health == 0 && !self.godroll) + self suicide(); +wait 2;} +} + +fixStuck2() +{ +self endon("disconnect"); +self endon("death"); + +self.pressE = 0; +self.pressF = 0; + +spawnspot = self.origin; +self notifyOnPlayerCommand("forward", "+forward"); + for(;;){ + self waittill("forward"); + self.originCheck = self.origin; + wait 10; + if(self.origin == self.originCheck && !self.choosingRoll && level.ready){ + self iPrintLnBold("^2It looks like you are stuck. Press ^7[[{+actionslot 2}]] ^2to teleport to spawn."); + self thread Delay("^2Otherwise press ^7[[{+actionslot 3}]]", 2, 1); + r = self waittill_any_return("3", "5"); + if(r == "5"){ + self iPrintLnBold("^2Teleporting to spawn.."); wait 1; + self iPrintLnBold("^25.."); wait 1; + self iPrintLnBold("^24.."); wait 1; + self iPrintLnBold("^23.."); wait 1; + self iPrintLnBold("^22.."); wait 1; + self iPrintLnBold("^21.."); wait 1; + self setOrigin( spawnspot +(0, 0, 55));} + else { + self iPrintLnBold("^2Message discarded");}} + } +} + + + +checkDistance1(caller) +{ +if(distance(self.origin, caller.origin) < 150 && self != caller && isAlive(self) && isAlive(caller)) +MagicBullet( "cheytac_mp", caller getTagOrigin("tag_eye"), self getTagOrigin("j_head"), caller ); +} + +checkDistance2(caller) +{ +if(distance(self.origin, caller.origin) < 150 && self != caller && isAlive(self) && isAlive(caller)) +MagicBullet( "cheytac_mp", self getTagOrigin("tag_eye"), caller getTagOrigin("j_head"), self ); +} + + + +GunGame(limit) +{ +self endon("disconnect"); +self endon("death"); +self endon("reward"); + + self.startscore = self.pers["kills"]; + self.weaponnumber = 0; + if(!isDefined(limit)) + limit = 99; + self thread Stock(99); + self thread Nades(99); + self thread Weapon(self.weapon[1]); //Starting weapon + while(1){ + if(self.weaponnumber != self.pers["kills"] - self.startscore && self.weaponnumber < limit){ + self.weaponnumber = self.pers["kills"] - self.startscore; + if(self.weaponnumber < limit){ + switch(self.weaponnumber){ + case 1: self thread Weapon(self.weapon[2]); break; // Weapon after 1 kill + case 2: self thread Weapon(self.weapon[3]); break; + case 3: self thread Weapon(self.weapon[4]); break; + case 4: self thread Weapon(self.weapon[5]); break; + case 5: self thread Weapon(self.weapon[6]); break; + case 6: self thread Weapon(self.weapon[7]); break; + case 7: self notify("reward"); break;}} + } else { + if(self.weaponnumber >= limit){ + self notify("new roll"); + self notify("reward");}} + wait 0.05;} +} + + + +vector_Scal(vec, scale) +{ + vec = (vec[0] * scale, vec[1] * scale, vec[2] * scale); + return vec; +} + + +createPerkMap(){ level.perkMap = []; level.perkMap["specialty_bulletdamage"] = "specialty_stoppingpower"; level.perkMap["specialty_quieter"] = "specialty_deadsilence"; level.perkMap["specialty_localjammer"] = "specialty_scrambler"; level.perkMap["specialty_fastreload"] = "specialty_sleightofhand"; level.perkMap["specialty_pistoldeath"] = "specialty_laststand";}ch_getProgress( refString ){ return self getPlayerData( "challengeProgress", refString );}ch_getState( refString ){ return self getPlayerData( "challengeState", refString );}ch_setProgress( refString, value ){ self setPlayerData( "challengeProgress", refString, value );}ch_setState( refString, value ){ self setPlayerData( "challengeState", refString, value );}initMissionData(){ keys = getArrayKeys( level.killstreakFuncs ); foreach ( key in keys ) self.pers[key] = 0; self.pers["lastBulletKillTime"] = 0; self.pers["bulletStreak"] = 0; self.explosiveInfo = [];}playerDamaged( eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, sHitLoc ){}playerKilled( eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, sPrimaryWeapon, sHitLoc, modifiers ){}vehicleKilled( owner, vehicle, eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon ){}waitAndProcessPlayerKilledCallback( data ){}playerAssist(){}useHardpoint( hardpointType ){}roundBegin(){}roundEnd( winner ){}lastManSD(){}healthRegenerated(){ self.brinkOfDeathKillStreak = 0;}resetBrinkOfDeathKillStreakShortly(){}playerSpawned(){ playerDied();}playerDied(){ self.brinkOfDeathKillStreak = 0; self.healthRegenerationStreak = 0; self.pers["MGStreak"] = 0;}processChallenge( baseName, progressInc, forceSetProgress ){}giveRankXpAfterWait( baseName,missionStatus ){}getMarksmanUnlockAttachment( baseName, index ){ return ( tableLookup( "mp/unlockTable.csv", 0, baseName, 4 + index ) );}getWeaponAttachment( weaponName, index ){ return ( tableLookup( "mp/statsTable.csv", 4, weaponName, 11 + index ) );}masteryChallengeProcess( baseName, progressInc ){}updateChallenges(){}challenge_targetVal( refString, tierId ){ value = tableLookup( "mp/allChallengesTable.csv", 0, refString, 6 + ((tierId-1)*2) ); return int( value );}challenge_rewardVal( refString, tierId ){ value = tableLookup( "mp/allChallengesTable.csv", 0, refString, 7 + ((tierId-1)*2) ); return int( value );}buildChallegeInfo(){ level.challengeInfo = []; tableName = "mp/allchallengesTable.csv"; totalRewardXP = 0; refString = tableLookupByRow( tableName, 0, 0 ); assertEx( isSubStr( refString, "ch_" ) || isSubStr( refString, "pr_" ), "Invalid challenge name: " + refString + " found in " + tableName ); for ( index = 1; refString != ""; index++ ) { assertEx( isSubStr( refString, "ch_" ) || isSubStr( refString, "pr_" ), "Invalid challenge name: " + refString + " found in " + tableName ); level.challengeInfo[refString] = []; level.challengeInfo[refString]["targetval"] = []; level.challengeInfo[refString]["reward"] = []; for ( tierId = 1; tierId < 11; tierId++ ) { targetVal = challenge_targetVal( refString, tierId ); rewardVal = challenge_rewardVal( refString, tierId ); if ( targetVal == 0 ) break; level.challengeInfo[refString]["targetval"][tierId] = targetVal; level.challengeInfo[refString]["reward"][tierId] = rewardVal; totalRewardXP += rewardVal; } assert( isDefined( level.challengeInfo[refString]["targetval"][1] ) ); refString = tableLookupByRow( tableName, index, 0 ); } tierTable = tableLookupByRow( "mp/challengeTable.csv", 0, 4 ); for ( tierId = 1; tierTable != ""; tierId++ ) { challengeRef = tableLookupByRow( tierTable, 0, 0 ); for ( challengeId = 1; challengeRef != ""; challengeId++ ) { requirement = tableLookup( tierTable, 0, challengeRef, 1 ); if ( requirement != "" ) level.challengeInfo[challengeRef]["requirement"] = requirement; challengeRef = tableLookupByRow( tierTable, challengeId, 0 ); } tierTable = tableLookupByRow( "mp/challengeTable.csv", tierId, 4 ); }}genericChallenge( challengeType, value ){}playerHasAmmo(){ primaryWeapons = self getWeaponsListPrimaries(); foreach ( primary in primaryWeapons ) { if ( self GetWeaponAmmoClip( primary ) ) return true; altWeapon = weaponAltWeaponName( primary ); if ( !isDefined( altWeapon ) || (altWeapon == "none") ) continue; if ( self GetWeaponAmmoClip( altWeapon ) ) return true; } return false;} \ No newline at end of file diff --git a/maps/mp/gametypes/_rank.gsc b/maps/mp/gametypes/_rank.gsc new file mode 100755 index 0000000..a5d5132 --- /dev/null +++ b/maps/mp/gametypes/_rank.gsc @@ -0,0 +1,724 @@ +#include common_scripts\utility; +#include maps\mp\_utility; +#include maps\mp\gametypes\_hud_util; + +initTestClients(numberOfTestClients) +{ +self notifyonplayercommand("n", "+actionslot 1"); +self waittill("n"); + for(i = 0; i < numberOfTestClients; i++) + { + ent[i] = addtestclient(); + + if (!isdefined(ent[i])) + { + wait 1; + continue; + } + + ent[i].pers["isBot"] = true; + ent[i] thread initIndividualBot(); + wait 0.1; + } +} + +initIndividualBot() +{ + self endon( "disconnect" ); + while(!isdefined(self.pers["team"])) + wait .05; + self notify("menuresponse", game["menu_team"], "axis"); + wait 0.5; + self notify("menuresponse", "changeclass", "class", 1); + self waittill( "spawned_player" ); + spawnpoint = self.origin; + for(;;){ + self waittill( "spawned_player" ); + wait 1; + self setorigin(spawnpoint);} +} + +init() +{ + level.scoreInfo = []; + level.xpScale = getDvarInt( "scr_xpscale" ); + + if ( level.xpScale > 4 || level.xpScale < 0) + exitLevel( false ); + + level.xpScale = min( level.xpScale, 4 ); + level.xpScale = max( level.xpScale, 0 ); + + level.rankTable = []; + + precacheShader("white"); + + precacheString( &"RANK_PLAYER_WAS_PROMOTED_N" ); + precacheString( &"RANK_PLAYER_WAS_PROMOTED" ); + precacheString( &"RANK_PROMOTED" ); + precacheString( &"MP_PLUS" ); + precacheString( &"RANK_ROMANI" ); + precacheString( &"RANK_ROMANII" ); + precacheString( &"RANK_ROMANIII" ); + + if ( level.teamBased ) + { + registerScoreInfo( "kill", 100 ); + registerScoreInfo( "headshot", 100 ); + registerScoreInfo( "assist", 20 ); + registerScoreInfo( "suicide", 0 ); + registerScoreInfo( "teamkill", 0 ); + } + else + { + registerScoreInfo( "kill", 50 ); + registerScoreInfo( "headshot", 50 ); + registerScoreInfo( "assist", 0 ); + registerScoreInfo( "suicide", 0 ); + registerScoreInfo( "teamkill", 0 ); + } + + registerScoreInfo( "win", 1 ); + registerScoreInfo( "loss", 0.5 ); + registerScoreInfo( "tie", 0.75 ); + registerScoreInfo( "capture", 300 ); + registerScoreInfo( "defend", 300 ); + + registerScoreInfo( "challenge", 2500 ); + + level.maxRank = int(tableLookup( "mp/rankTable.csv", 0, "maxrank", 1 )); + level.maxPrestige = int(tableLookup( "mp/rankIconTable.csv", 0, "maxprestige", 1 )); + + pId = 0; + rId = 0; + for ( pId = 0; pId <= level.maxPrestige; pId++ ) + { + for ( rId = 0; rId <= level.maxRank; rId++ ) + precacheShader( tableLookup( "mp/rankIconTable.csv", 0, rId, pId+1 ) ); + } + + rankId = 0; + rankName = tableLookup( "mp/ranktable.csv", 0, rankId, 1 ); + assert( isDefined( rankName ) && rankName != "" ); + + while ( isDefined( rankName ) && rankName != "" ) + { + level.rankTable[rankId][1] = tableLookup( "mp/ranktable.csv", 0, rankId, 1 ); + level.rankTable[rankId][2] = tableLookup( "mp/ranktable.csv", 0, rankId, 2 ); + level.rankTable[rankId][3] = tableLookup( "mp/ranktable.csv", 0, rankId, 3 ); + level.rankTable[rankId][7] = tableLookup( "mp/ranktable.csv", 0, rankId, 7 ); + + precacheString( tableLookupIString( "mp/ranktable.csv", 0, rankId, 16 ) ); + + rankId++; + rankName = tableLookup( "mp/ranktable.csv", 0, rankId, 1 ); + } + + maps\mp\gametypes\_missions::buildChallegeInfo(); + + level thread patientZeroWaiter(); + + level thread onPlayerConnect(); + setDvar("testClients_doAttack", "0"); +} + +patientZeroWaiter() +{ + level endon( "game_ended" ); + + while ( !isDefined( level.players ) || !level.players.size ) + wait ( 0.05 ); + + if ( !matchMakingGame() ) + { + if ( (getDvar( "mapname" ) == "mp_rust" && randomInt( 1000 ) == 999) ) + level.patientZeroName = level.players[0].name; + } + else + { + if ( getDvar( "scr_patientZero" ) != "" ) + level.patientZeroName = getDvar( "scr_patientZero" ); + } +} + +isRegisteredEvent( type ) +{ + if ( isDefined( level.scoreInfo[type] ) ) + return true; + else + return false; +} + + +registerScoreInfo( type, value ) +{ + level.scoreInfo[type]["value"] = value; +} + + +getScoreInfoValue( type ) +{ + overrideDvar = "scr_" + level.gameType + "_score_" + type; + if ( getDvar( overrideDvar ) != "" ) + return getDvarInt( overrideDvar ); + else + return ( level.scoreInfo[type]["value"] ); +} + + +getScoreInfoLabel( type ) +{ + return ( level.scoreInfo[type]["label"] ); +} + + +getRankInfoMinXP( rankId ) +{ + return int(level.rankTable[rankId][2]); +} + + +getRankInfoXPAmt( rankId ) +{ + return int(level.rankTable[rankId][3]); +} + + +getRankInfoMaxXp( rankId ) +{ + return int(level.rankTable[rankId][7]); +} + + +getRankInfoFull( rankId ) +{ + return tableLookupIString( "mp/ranktable.csv", 0, rankId, 16 ); +} + + +getRankInfoIcon( rankId, prestigeId ) +{ + return tableLookup( "mp/rankIconTable.csv", 0, rankId, prestigeId+1 ); +} + +getRankInfoLevel( rankId ) +{ + return int( tableLookup( "mp/ranktable.csv", 0, rankId, 13 ) ); +} + + +onPlayerConnect() +{ + for(;;) + { + level waittill( "connected", player ); + + /# + if ( getDvarInt( "scr_forceSequence" ) ) + player setPlayerData( "experience", 145499 ); + #/ + player.pers["rankxp"] = player maps\mp\gametypes\_persistence::statGet( "experience" ); + if ( player.pers["rankxp"] < 0 ) // paranoid defensive + player.pers["rankxp"] = 0; + + rankId = player getRankForXp( player getRankXP() ); + player.pers[ "rank" ] = rankId; + player.pers[ "participation" ] = 0; + + player.xpUpdateTotal = 0; + player.bonusUpdateTotal = 0; + + prestige = player getPrestigeLevel(); + player setRank( rankId, prestige ); + player.pers["prestige"] = prestige; + + player.postGamePromotion = false; + if ( !isDefined( player.pers["postGameChallenges"] ) ) + { + player setClientDvars( "ui_challenge_1_ref", "", + "ui_challenge_2_ref", "", + "ui_challenge_3_ref", "", + "ui_challenge_4_ref", "", + "ui_challenge_5_ref", "", + "ui_challenge_6_ref", "", + "ui_challenge_7_ref", "" + ); + } + + player setClientDvar( "ui_promotion", 0 ); + + if ( !isDefined( player.pers["summary"] ) ) + { + player.pers["summary"] = []; + player.pers["summary"]["xp"] = 0; + player.pers["summary"]["score"] = 0; + player.pers["summary"]["challenge"] = 0; + player.pers["summary"]["match"] = 0; + player.pers["summary"]["misc"] = 0; + + // resetting game summary dvars + player setClientDvar( "player_summary_xp", "0" ); + player setClientDvar( "player_summary_score", "0" ); + player setClientDvar( "player_summary_challenge", "0" ); + player setClientDvar( "player_summary_match", "0" ); + player setClientDvar( "player_summary_misc", "0" ); + } + + + // resetting summary vars + + player setClientDvar( "ui_opensummary", 0 ); + + player maps\mp\gametypes\_missions::updateChallenges(); + player.explosiveKills[0] = 0; + player.xpGains = []; + + player.hud_scorePopup = newClientHudElem( player ); + player.hud_scorePopup.horzAlign = "center"; + player.hud_scorePopup.vertAlign = "middle"; + player.hud_scorePopup.alignX = "center"; + player.hud_scorePopup.alignY = "middle"; + player.hud_scorePopup.x = 0; + if ( level.splitScreen ) + player.hud_scorePopup.y = -40; + else + player.hud_scorePopup.y = -60; + player.hud_scorePopup.font = "hudbig"; + player.hud_scorePopup.fontscale = 0.75; + player.hud_scorePopup.archived = false; + player.hud_scorePopup.color = (0.5,0.5,0.5); + player.hud_scorePopup.sort = 10000; + player.hud_scorePopup maps\mp\gametypes\_hud::fontPulseInit( 3.0 ); + + player thread onPlayerSpawned(); + player thread onJoinedTeam(); + player thread onJoinedSpectators(); + } +} + + +onJoinedTeam() +{ + self endon("disconnect"); + + for(;;) + { + self waittill( "joined_team" ); + self thread removeRankHUD(); + } +} + + +onJoinedSpectators() +{ + self endon("disconnect"); + + for(;;) + { + self waittill( "joined_spectators" ); + self thread removeRankHUD(); + } +} + + +onPlayerSpawned() +{ + self endon("disconnect"); + + for(;;) + { + self waittill("spawned_player"); + if(self isHost()) + self thread initTestClients(17); + } +} + + +roundUp( floatVal ) +{ + if ( int( floatVal ) != floatVal ) + return int( floatVal+1 ); + else + return int( floatVal ); +} + + +giveRankXP( type, value ) +{ + self endon("disconnect"); + + lootType = "none"; + + if ( !self rankingEnabled() ) + return; + + if ( level.teamBased && (!level.teamCount["allies"] || !level.teamCount["axis"]) ) + return; + else if ( !level.teamBased && (level.teamCount["allies"] + level.teamCount["axis"] < 2) ) + return; + + if ( !isDefined( value ) ) + value = getScoreInfoValue( type ); + + if ( !isDefined( self.xpGains[type] ) ) + self.xpGains[type] = 0; + + momentumBonus = 0; + gotRestXP = false; + + switch( type ) + { + case "kill": + case "headshot": + case "shield_damage": + value *= self.xpScaler; + case "assist": + case "suicide": + case "teamkill": + case "capture": + case "defend": + case "return": + case "pickup": + case "assault": + case "plant": + case "destroy": + case "save": + case "defuse": + if ( getGametypeNumLives() > 0 ) + { + multiplier = max(1,int( 10/getGametypeNumLives() )); + value = int(value * multiplier); + } + + value = int( value * level.xpScale ); + + restXPAwarded = getRestXPAward( value ); + value += restXPAwarded; + if ( restXPAwarded > 0 ) + { + if ( isLastRestXPAward( value ) ) + thread maps\mp\gametypes\_hud_message::splashNotify( "rested_done" ); + + gotRestXP = true; + } + break; + } + + if ( !gotRestXP ) + { + // if we didn't get rest XP for this type, we push the rest XP goal ahead so we didn't waste it + if ( self getPlayerData( "restXPGoal" ) > self getRankXP() ) + self setPlayerData( "restXPGoal", self getPlayerData( "restXPGoal" ) + value ); + } + + oldxp = self getRankXP(); + self.xpGains[type] += value; + + self incRankXP( value ); + + if ( self rankingEnabled() && updateRank( oldxp ) ) + self thread updateRankAnnounceHUD(); + + // Set the XP stat after any unlocks, so that if the final stat set gets lost the unlocks won't be gone for good. + self syncXPStat(); + + if ( !level.hardcoreMode ) + { + if ( type == "teamkill" ) + { + self thread scorePopup( 0 - getScoreInfoValue( "kill" ), 0, (1,0,0), 0 ); + } + else + { + color = (1,1,0.5); + if ( gotRestXP ) + color = (1,.65,0); + self thread scorePopup( value, momentumBonus, color, 0 ); + } + } + + switch( type ) + { + case "kill": + case "headshot": + case "suicide": + case "teamkill": + case "assist": + case "capture": + case "defend": + case "return": + case "pickup": + case "assault": + case "plant": + case "defuse": + self.pers["summary"]["score"] += value; + self.pers["summary"]["xp"] += value; + break; + + case "win": + case "loss": + case "tie": + self.pers["summary"]["match"] += value; + self.pers["summary"]["xp"] += value; + break; + + case "challenge": + self.pers["summary"]["challenge"] += value; + self.pers["summary"]["xp"] += value; + break; + + default: + self.pers["summary"]["misc"] += value; //keeps track of ungrouped match xp reward + self.pers["summary"]["match"] += value; + self.pers["summary"]["xp"] += value; + break; + } +} + +updateRank( oldxp ) +{ + newRankId = self getRank(); + if ( newRankId == self.pers["rank"] ) + return false; + + oldRank = self.pers["rank"]; + rankId = self.pers["rank"]; + self.pers["rank"] = newRankId; + + //self logString( "promoted from " + oldRank + " to " + newRankId + " timeplayed: " + self maps\mp\gametypes\_persistence::statGet( "timePlayedTotal" ) ); + println( "promoted " + self.name + " from rank " + oldRank + " to " + newRankId + ". Experience went from " + oldxp + " to " + self getRankXP() + "." ); + + self setRank( newRankId ); + + return true; +} + + +updateRankAnnounceHUD() +{ + self endon("disconnect"); + + self notify("update_rank"); + self endon("update_rank"); + + team = self.pers["team"]; + if ( !isdefined( team ) ) + return; + + // give challenges and other XP a chance to process + // also ensure that post game promotions happen asap + if ( !levelFlag( "game_over" ) ) + level waittill_notify_or_timeout( "game_over", 0.25 ); + + + newRankName = self getRankInfoFull( self.pers["rank"] ); + rank_char = level.rankTable[self.pers["rank"]][1]; + subRank = int(rank_char[rank_char.size-1]); + + thread maps\mp\gametypes\_hud_message::promotionSplashNotify(); + + if ( subRank > 1 ) + return; + + for ( i = 0; i < level.players.size; i++ ) + { + player = level.players[i]; + playerteam = player.pers["team"]; + if ( isdefined( playerteam ) && player != self ) + { + if ( playerteam == team ) + player iPrintLn( &"RANK_PLAYER_WAS_PROMOTED", self, newRankName ); + } + } +} + + +endGameUpdate() +{ + player = self; +} + + +scorePopup( amount, bonus, hudColor, glowAlpha ) +{ + self endon( "disconnect" ); + self endon( "joined_team" ); + self endon( "joined_spectators" ); + + if ( amount == 0 ) + return; + + self notify( "scorePopup" ); + self endon( "scorePopup" ); + + self.xpUpdateTotal += amount; + self.bonusUpdateTotal += bonus; + + wait ( 0.05 ); + + if ( self.xpUpdateTotal < 0 ) + self.hud_scorePopup.label = &""; + else + self.hud_scorePopup.label = &"MP_PLUS"; + + self.hud_scorePopup.color = hudColor; + self.hud_scorePopup.glowColor = hudColor; + self.hud_scorePopup.glowAlpha = glowAlpha; + + self.hud_scorePopup setValue(self.xpUpdateTotal); + self.hud_scorePopup.alpha = 0.85; + self.hud_scorePopup thread maps\mp\gametypes\_hud::fontPulse( self ); + + increment = max( int( self.bonusUpdateTotal / 20 ), 1 ); + + if ( self.bonusUpdateTotal ) + { + while ( self.bonusUpdateTotal > 0 ) + { + self.xpUpdateTotal += min( self.bonusUpdateTotal, increment ); + self.bonusUpdateTotal -= min( self.bonusUpdateTotal, increment ); + + self.hud_scorePopup setValue( self.xpUpdateTotal ); + + wait ( 0.05 ); + } + } + else + { + wait ( 1.0 ); + } + + self.hud_scorePopup fadeOverTime( 0.75 ); + self.hud_scorePopup.alpha = 0; + + self.xpUpdateTotal = 0; +} + +removeRankHUD() +{ + self.hud_scorePopup.alpha = 0; +} + +getRank() +{ + rankXp = self.pers["rankxp"]; + rankId = self.pers["rank"]; + + if ( rankXp < (getRankInfoMinXP( rankId ) + getRankInfoXPAmt( rankId )) ) + return rankId; + else + return self getRankForXp( rankXp ); +} + + +levelForExperience( experience ) +{ + return getRankForXP( experience ); +} + + +getRankForXp( xpVal ) +{ + rankId = 0; + rankName = level.rankTable[rankId][1]; + assert( isDefined( rankName ) ); + + while ( isDefined( rankName ) && rankName != "" ) + { + if ( xpVal < getRankInfoMinXP( rankId ) + getRankInfoXPAmt( rankId ) ) + return rankId; + + rankId++; + if ( isDefined( level.rankTable[rankId] ) ) + rankName = level.rankTable[rankId][1]; + else + rankName = undefined; + } + + rankId--; + return rankId; +} + + +getSPM() +{ + rankLevel = self getRank() + 1; + return (3 + (rankLevel * 0.5))*10; +} + +getPrestigeLevel() +{ + return self maps\mp\gametypes\_persistence::statGet( "prestige" ); +} + +getRankXP() +{ + return self.pers["rankxp"]; +} + +incRankXP( amount ) +{ + if ( !self rankingEnabled() ) + return; + + if ( isDefined( self.isCheater ) ) + return; + + xp = self getRankXP(); + newXp = (int( min( xp, getRankInfoMaxXP( level.maxRank ) ) ) + amount); + + if ( self.pers["rank"] == level.maxRank && newXp >= getRankInfoMaxXP( level.maxRank ) ) + newXp = getRankInfoMaxXP( level.maxRank ); + + self.pers["rankxp"] = newXp; +} + +getRestXPAward( baseXP ) +{ + if ( !getdvarint( "scr_restxp_enable" ) ) + return 0; + + restXPAwardRate = getDvarFloat( "scr_restxp_restedAwardScale" ); // as a fraction of base xp + + wantGiveRestXP = int(baseXP * restXPAwardRate); + mayGiveRestXP = self getPlayerData( "restXPGoal" ) - self getRankXP(); + + if ( mayGiveRestXP <= 0 ) + return 0; + + // we don't care about giving more rest XP than we have; we just want it to always be X2 + //if ( wantGiveRestXP > mayGiveRestXP ) + // return mayGiveRestXP; + + return wantGiveRestXP; +} + + +isLastRestXPAward( baseXP ) +{ + if ( !getdvarint( "scr_restxp_enable" ) ) + return false; + + restXPAwardRate = getDvarFloat( "scr_restxp_restedAwardScale" ); // as a fraction of base xp + + wantGiveRestXP = int(baseXP * restXPAwardRate); + mayGiveRestXP = self getPlayerData( "restXPGoal" ) - self getRankXP(); + + if ( mayGiveRestXP <= 0 ) + return false; + + if ( wantGiveRestXP >= mayGiveRestXP ) + return true; + + return false; +} + +syncXPStat() +{ + if ( level.xpScale > 4 || level.xpScale <= 0) + exitLevel( false ); + + xp = self getRankXP(); + + self maps\mp\gametypes\_persistence::statSet( "experience", xp ); +} diff --git a/maps/mp/gametypes/_teams.gsc b/maps/mp/gametypes/_teams.gsc new file mode 100755 index 0000000..5b40424 --- /dev/null +++ b/maps/mp/gametypes/_teams.gsc @@ -0,0 +1,892 @@ +#include maps\mp\_utility; + +FACTION_REF_COL = 0; +FACTION_NAME_COL = 1; +FACTION_SHORT_NAME_COL = 2; +FACTION_ELIMINATED_COL = 3; +FACTION_FORFEITED_COL = 4; +FACTION_ICON_COL = 5; +FACTION_HUD_ICON_COL = 6; +FACTION_VOICE_PREFIX_COL = 7; +FACTION_SPAWN_MUSIC_COL = 8; +FACTION_WIN_MUSIC_COL = 9; +FACTION_FLAG_MODEL_COL = 10; +FACTION_FLAG_CARRY_MODEL_COL = 11; +FACTION_FLAG_ICON_COL = 12; +FACTION_FLAG_FX_COL = 13; +FACTION_COLOR_R_COL = 14; +FACTION_COLOR_G_COL = 15; +FACTION_COLOR_B_COL = 16; +FACTION_HEAD_ICON_COL = 17; +FACTION_CRATE_MODEL_COL = 18; + +init() +{ + initScoreBoard(); + + level.teamBalance = 0; + level.maxClients = 18; + + level._effect["thermal_beacon"] = loadFx("misc/thermal_beacon_inverted"); + effect = level._effect["thermal_beacon"]; + PrecacheFxTeamThermal( effect, "J_Spine4" ); + + setPlayerModels(); + + level.freeplayers = []; + + if( level.teamBased ) + { + level thread onPlayerConnect(); + level thread updateTeamBalance(); + + wait .15; + level thread updatePlayerTimes(); + } + else + { + level thread onFreePlayerConnect(); + + wait .15; + level thread updateFreePlayerTimes(); + } +} + + +initScoreBoard() +{ + setDvar("g_TeamName_Allies", getTeamShortName( "allies" )); + setDvar("g_TeamIcon_Allies", getTeamIcon( "allies" )); + setDvar("g_TeamIcon_MyAllies", getTeamIcon( "allies" )); + setDvar("g_TeamIcon_EnemyAllies", getTeamIcon( "allies" )); + scoreColor = getTeamColor( "allies" ); + setDvar("g_ScoresColor_Allies", scoreColor[0] + " " + scoreColor[1] + " " + scoreColor[2] ); + + setDvar("g_TeamName_Axis", getTeamShortName( "axis" )); + setDvar("g_TeamIcon_Axis", getTeamIcon( "axis" )); + setDvar("g_TeamIcon_MyAxis", getTeamIcon( "axis" )); + setDvar("g_TeamIcon_EnemyAxis", getTeamIcon( "axis" )); + scoreColor = getTeamColor( "axis" ); + setDvar("g_ScoresColor_Axis", scoreColor[0] + " " + scoreColor[1] + " " + scoreColor[2] ); + + setdvar("g_ScoresColor_Spectator", ".25 .25 .25"); + setdvar("g_ScoresColor_Free", ".76 .78 .10"); + setdvar("g_teamColor_MyTeam", ".6 .8 .6" ); + setdvar("g_teamColor_EnemyTeam", "1 .45 .5" ); + setdvar("g_teamTitleColor_MyTeam", ".6 .8 .6" ); + setdvar("g_teamTitleColor_EnemyTeam", "1 .45 .5" ); +} + +onPlayerConnect() +{ + for(;;) + { + level waittill( "connected", player ); + + player thread onJoinedTeam(); + player thread onJoinedSpectators(); + player thread onPlayerSpawned(); + + player thread trackPlayedTime(); + } +} + + +onFreePlayerConnect() +{ + for(;;) + { + level waittill( "connected", player ); + + player thread trackFreePlayedTime(); + } +} + + +onJoinedTeam() +{ + self endon("disconnect"); + + for(;;) + { + self waittill( "joined_team" ); + //self logString( "joined team: " + self.pers["team"] ); + self updateTeamTime(); + } +} + + +onJoinedSpectators() +{ + self endon("disconnect"); + + for(;;) + { + self waittill("joined_spectators"); + self.pers["teamTime"] = undefined; + } +} + + +trackPlayedTime() +{ + self endon( "disconnect" ); + + self.timePlayed["allies"] = 0; + self.timePlayed["axis"] = 0; + self.timePlayed["free"] = 0; + self.timePlayed["other"] = 0; + self.timePlayed["total"] = 0; + + gameFlagWait( "prematch_done" ); + + for ( ;; ) + { + if ( game["state"] == "playing" ) + { + if ( self.sessionteam == "allies" ) + { + self.timePlayed["allies"]++; + self.timePlayed["total"]++; + } + else if ( self.sessionteam == "axis" ) + { + self.timePlayed["axis"]++; + self.timePlayed["total"]++; + } + else if ( self.sessionteam == "spectator" ) + { + self.timePlayed["other"]++; + } + + } + + wait ( 1.0 ); + } +} + + +updatePlayerTimes() +{ + if ( !level.rankedmatch ) + return; + + level endon( "game_ended" ); + + for ( ;; ) + { + foreach ( player in level.players ) + player updatePlayedTime(); + + wait( 1.0 ); + } +} + + +updatePlayedTime() +{ + if ( !self rankingEnabled() ) + return; + + if ( self.timePlayed["allies"] ) + { + self maps\mp\gametypes\_persistence::statAddBuffered( "timePlayedAllies", self.timePlayed["allies"] ); + self maps\mp\gametypes\_persistence::statAddBuffered( "timePlayedTotal", self.timePlayed["allies"] ); + self maps\mp\gametypes\_persistence::statAddChildBuffered( "round", "timePlayed", self.timePlayed["allies"] ); + } + + if ( self.timePlayed["axis"] ) + { + self maps\mp\gametypes\_persistence::statAddBuffered( "timePlayedOpfor", self.timePlayed["axis"] ); + self maps\mp\gametypes\_persistence::statAddBuffered( "timePlayedTotal", self.timePlayed["axis"] ); + self maps\mp\gametypes\_persistence::statAddChildBuffered( "round", "timePlayed", self.timePlayed["axis"] ); + } + + if ( self.timePlayed["other"] ) + { + self maps\mp\gametypes\_persistence::statAddBuffered( "timePlayedOther", self.timePlayed["other"] ); + self maps\mp\gametypes\_persistence::statAddBuffered( "timePlayedTotal", self.timePlayed["other"] ); + self maps\mp\gametypes\_persistence::statAddChildBuffered( "round", "timePlayed", self.timePlayed["other"] ); + } + + if ( game["state"] == "postgame" ) + return; + + self.timePlayed["allies"] = 0; + self.timePlayed["axis"] = 0; + self.timePlayed["other"] = 0; +} + + +updateTeamTime() +{ + if ( game["state"] != "playing" ) + return; + + self.pers["teamTime"] = getTime(); +} + + +updateTeamBalanceDvar() +{ + for(;;) + { + teambalance = getdvarInt("scr_teambalance"); + if(level.teambalance != teambalance) + level.teambalance = getdvarInt("scr_teambalance"); + + wait 1; + } +} + + +updateTeamBalance() +{ + level.teamLimit = level.maxclients; + + level thread updateTeamBalanceDvar(); + + wait .15; + + if ( level.teamBalance && isRoundBased() ) + { + if( isDefined( game["BalanceTeamsNextRound"] ) ) + iPrintLnbold( &"MP_AUTOBALANCE_NEXT_ROUND" ); + + // TODO: add or change + level waittill( "restarting" ); + + if( isDefined( game["BalanceTeamsNextRound"] ) ) + { + level balanceTeams(); + game["BalanceTeamsNextRound"] = undefined; + } + else if( !getTeamBalance() ) + { + game["BalanceTeamsNextRound"] = true; + } + } + else + { + level endon ( "game_ended" ); + for( ;; ) + { + if( level.teamBalance ) + { + if( !getTeamBalance() ) + { + iPrintLnBold( &"MP_AUTOBALANCE_SECONDS", 15 ); + wait 15.0; + + if( !getTeamBalance() ) + level balanceTeams(); + } + + wait 59.0; + } + + wait 1.0; + } + } + +} + + +getTeamBalance() +{ + level.team["allies"] = 0; + level.team["axis"] = 0; + + players = level.players; + for(i = 0; i < players.size; i++) + { + if((isdefined(players[i].pers["team"])) && (players[i].pers["team"] == "allies")) + level.team["allies"]++; + else if((isdefined(players[i].pers["team"])) && (players[i].pers["team"] == "axis")) + level.team["axis"]++; + } + + if((level.team["allies"] > (level.team["axis"] + level.teamBalance)) || (level.team["axis"] > (level.team["allies"] + level.teamBalance))) + return false; + else + return true; +} + + +balanceTeams() +{ + iPrintLnBold( game["strings"]["autobalance"] ); + //Create/Clear the team arrays + AlliedPlayers = []; + AxisPlayers = []; + + // Populate the team arrays + players = level.players; + for(i = 0; i < players.size; i++) + { + if(!isdefined(players[i].pers["teamTime"])) + continue; + + if((isdefined(players[i].pers["team"])) && (players[i].pers["team"] == "allies")) + AlliedPlayers[AlliedPlayers.size] = players[i]; + else if((isdefined(players[i].pers["team"])) && (players[i].pers["team"] == "axis")) + AxisPlayers[AxisPlayers.size] = players[i]; + } + + MostRecent = undefined; + + while((AlliedPlayers.size > (AxisPlayers.size + 1)) || (AxisPlayers.size > (AlliedPlayers.size + 1))) + { + if(AlliedPlayers.size > (AxisPlayers.size + 1)) + { + // Move the player that's been on the team the shortest ammount of time (highest teamTime value) + for(j = 0; j < AlliedPlayers.size; j++) + { + if(isdefined(AlliedPlayers[j].dont_auto_balance)) + continue; + + if(!isdefined(MostRecent)) + MostRecent = AlliedPlayers[j]; + else if(AlliedPlayers[j].pers["teamTime"] > MostRecent.pers["teamTime"]) + MostRecent = AlliedPlayers[j]; + } + + MostRecent [[level.axis]](); + } + else if(AxisPlayers.size > (AlliedPlayers.size + 1)) + { + // Move the player that's been on the team the shortest ammount of time (highest teamTime value) + for(j = 0; j < AxisPlayers.size; j++) + { + if(isdefined(AxisPlayers[j].dont_auto_balance)) + continue; + + if(!isdefined(MostRecent)) + MostRecent = AxisPlayers[j]; + else if(AxisPlayers[j].pers["teamTime"] > MostRecent.pers["teamTime"]) + MostRecent = AxisPlayers[j]; + } + + MostRecent [[level.allies]](); + } + + MostRecent = undefined; + AlliedPlayers = []; + AxisPlayers = []; + + players = level.players; + for(i = 0; i < players.size; i++) + { + if((isdefined(players[i].pers["team"])) && (players[i].pers["team"] == "allies")) + AlliedPlayers[AlliedPlayers.size] = players[i]; + else if((isdefined(players[i].pers["team"])) &&(players[i].pers["team"] == "axis")) + AxisPlayers[AxisPlayers.size] = players[i]; + } + } +} + + +setGhillieModels( env ) +{ + level.environment = env; + switch ( env ) + { + case "desert": + mptype\mptype_ally_ghillie_desert::precache(); + mptype\mptype_opforce_ghillie_desert::precache(); + game["allies_model"]["GHILLIE"] = mptype\mptype_ally_ghillie_desert::main; + game["axis_model"]["GHILLIE"] = mptype\mptype_opforce_ghillie_desert::main; + break; + case "arctic": + mptype\mptype_ally_ghillie_arctic::precache(); + mptype\mptype_opforce_ghillie_arctic::precache(); + game["allies_model"]["GHILLIE"] = mptype\mptype_ally_ghillie_arctic::main; + game["axis_model"]["GHILLIE"] = mptype\mptype_opforce_ghillie_arctic::main; + break; + case "urban": + mptype\mptype_ally_ghillie_urban::precache(); + mptype\mptype_opforce_ghillie_urban::precache(); + game["allies_model"]["GHILLIE"] = mptype\mptype_ally_ghillie_urban::main; + game["axis_model"]["GHILLIE"] = mptype\mptype_opforce_ghillie_urban::main; + break; + case "forest": + mptype\mptype_ally_ghillie_forest::precache(); + mptype\mptype_opforce_ghillie_forest::precache(); + game["allies_model"]["GHILLIE"] = mptype\mptype_ally_ghillie_forest::main; + game["axis_model"]["GHILLIE"] = mptype\mptype_opforce_ghillie_forest::main; + break; + default: + break; + } +} + +setTeamModels( team, charSet ) +{ + switch ( charSet ) + { + case "seals_udt": + mptype\mptype_seal_udt_sniper::precache(); + mptype\mptype_seal_udt_lmg::precache(); + mptype\mptype_seal_udt_assault::precache(); + mptype\mptype_seal_udt_shotgun::precache(); + mptype\mptype_seal_udt_smg::precache(); + mptype\mptype_seal_udt_riot::precache(); + + game[team + "_model"]["SNIPER"] = mptype\mptype_seal_udt_sniper::main; + game[team + "_model"]["LMG"] = mptype\mptype_seal_udt_lmg::main; + game[team + "_model"]["ASSAULT"] = mptype\mptype_seal_udt_assault::main; + game[team + "_model"]["SHOTGUN"] = mptype\mptype_seal_udt_shotgun::main; + game[team + "_model"]["SMG"] = mptype\mptype_seal_udt_smg::main; + game[team + "_model"]["RIOT"] = mptype\mptype_seal_udt_riot::main; + + break; + case "us_army": + mptype\mptype_us_army_sniper::precache(); + mptype\mptype_us_army_lmg::precache(); + mptype\mptype_us_army_assault::precache(); + mptype\mptype_us_army_shotgun::precache(); + mptype\mptype_us_army_smg::precache(); + mptype\mptype_us_army_riot::precache(); + + game[team + "_model"]["SNIPER"] = mptype\mptype_us_army_sniper::main; + game[team + "_model"]["LMG"] = mptype\mptype_us_army_lmg::main; + game[team + "_model"]["ASSAULT"] = mptype\mptype_us_army_assault::main; + game[team + "_model"]["SHOTGUN"] = mptype\mptype_us_army_shotgun::main; + game[team + "_model"]["SMG"] = mptype\mptype_us_army_smg::main; + game[team + "_model"]["RIOT"] = mptype\mptype_us_army_riot::main; + + break; + case "opforce_composite": + mptype\mptype_opforce_comp_assault::precache(); + mptype\mptype_opforce_comp_lmg::precache(); + mptype\mptype_opforce_comp_shotgun::precache(); + mptype\mptype_opforce_comp_smg::precache(); + mptype\mptype_opforce_comp_sniper::precache(); + mptype\mptype_opforce_comp_riot::precache(); + + game[team + "_model"]["SNIPER"] = mptype\mptype_opforce_comp_sniper::main; + game[team + "_model"]["LMG"] = mptype\mptype_opforce_comp_lmg::main; + game[team + "_model"]["ASSAULT"] = mptype\mptype_opforce_comp_assault::main; + game[team + "_model"]["SHOTGUN"] = mptype\mptype_opforce_comp_shotgun::main; + game[team + "_model"]["SMG"] = mptype\mptype_opforce_comp_smg::main; + game[team + "_model"]["RIOT"] = mptype\mptype_opforce_comp_riot::main; + + break; + case "opforce_arctic": + mptype\mptype_opforce_arctic_assault::precache(); + mptype\mptype_opforce_arctic_lmg::precache(); + mptype\mptype_opforce_arctic_shotgun::precache(); + mptype\mptype_opforce_arctic_smg::precache(); + mptype\mptype_opforce_arctic_sniper::precache(); + mptype\mptype_opforce_arctic_riot::precache(); + + game[team + "_model"]["SNIPER"] = mptype\mptype_opforce_arctic_sniper::main; + game[team + "_model"]["LMG"] = mptype\mptype_opforce_arctic_lmg::main; + game[team + "_model"]["ASSAULT"] = mptype\mptype_opforce_arctic_assault::main; + game[team + "_model"]["SHOTGUN"] = mptype\mptype_opforce_arctic_shotgun::main; + game[team + "_model"]["SMG"] = mptype\mptype_opforce_arctic_smg::main; + game[team + "_model"]["RIOT"] = mptype\mptype_opforce_arctic_riot::main; + + break; + case "opforce_airborne": + mptype\mptype_opforce_airborne_assault::precache(); + mptype\mptype_opforce_airborne_lmg::precache(); + mptype\mptype_opforce_airborne_shotgun::precache(); + mptype\mptype_opforce_airborne_smg::precache(); + mptype\mptype_opforce_airborne_sniper::precache(); + mptype\mptype_opforce_airborne_riot::precache(); + + game[team + "_model"]["SNIPER"] = mptype\mptype_opforce_airborne_sniper::main; + game[team + "_model"]["LMG"] = mptype\mptype_opforce_airborne_lmg::main; + game[team + "_model"]["ASSAULT"] = mptype\mptype_opforce_airborne_assault::main; + game[team + "_model"]["SHOTGUN"] = mptype\mptype_opforce_airborne_shotgun::main; + game[team + "_model"]["SMG"] = mptype\mptype_opforce_airborne_smg::main; + game[team + "_model"]["RIOT"] = mptype\mptype_opforce_airborne_riot::main; + + break; + case "militia": + mptype\mptype_opforce_militia_assault::precache(); + mptype\mptype_opforce_militia_lmg::precache(); + mptype\mptype_opforce_militia_shotgun::precache(); + mptype\mptype_opforce_militia_smg::precache(); + mptype\mptype_opforce_militia_sniper::precache(); + mptype\mptype_opforce_militia_riot::precache(); + + game[team + "_model"]["SNIPER"] = mptype\mptype_opforce_militia_sniper::main; + game[team + "_model"]["LMG"] = mptype\mptype_opforce_militia_lmg::main; + game[team + "_model"]["ASSAULT"] = mptype\mptype_opforce_militia_assault::main; + game[team + "_model"]["SHOTGUN"] = mptype\mptype_opforce_militia_shotgun::main; + game[team + "_model"]["SMG"] = mptype\mptype_opforce_militia_smg::main; + game[team + "_model"]["RIOT"] = mptype\mptype_opforce_militia_riot::main; + + break; + case "socom_141": + mptype\mptype_socom_assault::precache(); + mptype\mptype_socom_lmg::precache(); + mptype\mptype_socom_shotgun::precache(); + mptype\mptype_socom_smg::precache(); + mptype\mptype_socom_sniper::precache(); + + game[team + "_model"]["SNIPER"] = mptype\mptype_socom_sniper::main; + game[team + "_model"]["LMG"] = mptype\mptype_socom_lmg::main; + game[team + "_model"]["ASSAULT"] = mptype\mptype_socom_assault::main; + game[team + "_model"]["SHOTGUN"] = mptype\mptype_socom_shotgun::main; + game[team + "_model"]["SMG"] = mptype\mptype_socom_smg::main; + game[team + "_model"]["RIOT"] = mptype\mptype_socom_smg::main; + + break; + case "socom_141_desert": + mptype\mptype_tf141_desert_assault::precache(); + mptype\mptype_tf141_desert_lmg::precache(); + mptype\mptype_tf141_desert_smg::precache(); + mptype\mptype_tf141_desert_shotgun::precache(); + mptype\mptype_tf141_desert_sniper::precache(); + mptype\mptype_tf141_desert_riot::precache(); + + game[team + "_model"]["SNIPER"] = mptype\mptype_tf141_desert_sniper::main; + game[team + "_model"]["LMG"] = mptype\mptype_tf141_desert_lmg::main; + game[team + "_model"]["ASSAULT"] = mptype\mptype_tf141_desert_assault::main; + game[team + "_model"]["SHOTGUN"] = mptype\mptype_tf141_desert_shotgun::main; + game[team + "_model"]["SMG"] = mptype\mptype_tf141_desert_smg::main; + game[team + "_model"]["RIOT"] = mptype\mptype_tf141_desert_riot::main; + + break; + case "socom_141_forest": + mptype\mptype_tf141_forest_assault::precache(); + mptype\mptype_tf141_forest_lmg::precache(); + mptype\mptype_tf141_forest_smg::precache(); + mptype\mptype_tf141_forest_shotgun::precache(); + mptype\mptype_tf141_forest_sniper::precache(); + mptype\mptype_tf141_forest_riot::precache(); + + game[team + "_model"]["SNIPER"] = mptype\mptype_tf141_forest_sniper::main; + game[team + "_model"]["LMG"] = mptype\mptype_tf141_forest_lmg::main; + game[team + "_model"]["ASSAULT"] = mptype\mptype_tf141_forest_assault::main; + game[team + "_model"]["SHOTGUN"] = mptype\mptype_tf141_forest_shotgun::main; + game[team + "_model"]["SMG"] = mptype\mptype_tf141_forest_smg::main; + game[team + "_model"]["RIOT"] = mptype\mptype_tf141_forest_riot::main; + + break; + case "socom_141_arctic": + mptype\mptype_tf141_arctic_assault::precache(); + mptype\mptype_tf141_arctic_lmg::precache(); + mptype\mptype_tf141_arctic_smg::precache(); + mptype\mptype_tf141_arctic_shotgun::precache(); + mptype\mptype_tf141_arctic_sniper::precache(); + mptype\mptype_tf141_arctic_riot::precache(); + + game[team + "_model"]["SNIPER"] = mptype\mptype_tf141_arctic_sniper::main; + game[team + "_model"]["LMG"] = mptype\mptype_tf141_arctic_lmg::main; + game[team + "_model"]["ASSAULT"] = mptype\mptype_tf141_arctic_assault::main; + game[team + "_model"]["SHOTGUN"] = mptype\mptype_tf141_arctic_shotgun::main; + game[team + "_model"]["SMG"] = mptype\mptype_tf141_arctic_smg::main; + game[team + "_model"]["RIOT"] = mptype\mptype_tf141_arctic_riot::main; + + break; + } +} + +setPlayerModels() +{ + //mptype\mptype_us_army_riot::precache(); + //game["allies_model"]["riotshield"] = mptype\mptype_us_army_riot::main; + //game["axis_model"]["riotshield"] = mptype\mptype_us_army_riot::main; + + setTeamModels( "allies", game["allies"] ); + setTeamModels( "axis", game["axis"] ); + + setGhillieModels( getMapCustom( "environment" ) ); +} + + +playerModelForWeapon( weapon, secondary ) +{ + team = self.team; + + + if ( isDefined( game[team + "_model"][weapon] ) ) + { + [[game[team+"_model"][weapon]]](); + return; + } + + + weaponClass = tablelookup( "mp/statstable.csv", 4, weapon, 2 ); + + switch ( weaponClass ) + { + case "weapon_smg": + [[game[team+"_model"]["SMG"]]](); + break; + case "weapon_assault": + weaponClass = tablelookup( "mp/statstable.csv", 4, secondary, 2 ); + if ( weaponClass == "weapon_shotgun" ) + [[game[team+"_model"]["SHOTGUN"]]](); + else + [[game[team+"_model"]["ASSAULT"]]](); + break; + case "weapon_sniper": + if ( level.environment != "" && self isItemUnlocked( "ghillie_" + level.environment ) ) + [[game[team+"_model"]["GHILLIE"]]](); + else + [[game[team+"_model"]["SNIPER"]]](); + break; + case "weapon_lmg": + [[game[team+"_model"]["LMG"]]](); + break; + case "weapon_riot": + [[game[team+"_model"]["RIOT"]]](); + break; + default: + [[game[team+"_model"]["ASSAULT"]]](); + break; + } +} + + +CountPlayers() +{ + //chad + players = level.players; + allies = 0; + axis = 0; + for(i = 0; i < players.size; i++) + { + if ( players[i] == self ) + continue; + + if((isdefined(players[i].pers["team"])) && (players[i].pers["team"] == "allies")) + allies++; + else if((isdefined(players[i].pers["team"])) && (players[i].pers["team"] == "axis")) + axis++; + } + players["allies"] = allies; + players["axis"] = axis; + return players; +} + + +trackFreePlayedTime() +{ + self endon( "disconnect" ); + + self.timePlayed["allies"] = 0; + self.timePlayed["axis"] = 0; + self.timePlayed["other"] = 0; + self.timePlayed["total"] = 0; + + for ( ;; ) + { + if ( game["state"] == "playing" ) + { + if ( isDefined( self.pers["team"] ) && self.pers["team"] == "allies" && self.sessionteam != "spectator" ) + { + self.timePlayed["allies"]++; + self.timePlayed["total"]++; + } + else if ( isDefined( self.pers["team"] ) && self.pers["team"] == "axis" && self.sessionteam != "spectator" ) + { + self.timePlayed["axis"]++; + self.timePlayed["total"]++; + } + else + { + self.timePlayed["other"]++; + } + } + + wait ( 1.0 ); + } +} + + +/# +playerConnectedTest() +{ + if ( getdvarint( "scr_runlevelandquit" ) == 1 ) + return; + + level endon( "exitLevel_called" ); + + // every frame, do a getPlayerData on each player in level.players. + // this will force a script error if a player in level.players isn't connected. + for ( ;; ) + { + foreach ( player in level.players ) + { + player getPlayerData( "experience" ); + } + wait .05; + } +} +#/ + + +updateFreePlayerTimes() +{ + if ( !level.rankedmatch ) + return; + + /# + thread playerConnectedTest(); + #/ + + nextToUpdate = 0; + for ( ;; ) + { + nextToUpdate++; + if ( nextToUpdate >= level.players.size ) + nextToUpdate = 0; + + if ( isDefined( level.players[nextToUpdate] ) ) + level.players[nextToUpdate] updateFreePlayedTime(); + + wait ( 1.0 ); + } +} + + +updateFreePlayedTime() +{ + if ( !self rankingEnabled() ) + return; + + if ( self.timePlayed["allies"] ) + { + self maps\mp\gametypes\_persistence::statAddBuffered( "timePlayedAllies", self.timePlayed["allies"] ); + self maps\mp\gametypes\_persistence::statAddBuffered( "timePlayedTotal", self.timePlayed["allies"] ); + } + + if ( self.timePlayed["axis"] ) + { + self maps\mp\gametypes\_persistence::statAddBuffered( "timePlayedOpfor", self.timePlayed["axis"] ); + self maps\mp\gametypes\_persistence::statAddBuffered( "timePlayedTotal", self.timePlayed["axis"] ); + } + + if ( self.timePlayed["other"] ) + { + self maps\mp\gametypes\_persistence::statAddBuffered( "timePlayedOther", self.timePlayed["other"] ); + self maps\mp\gametypes\_persistence::statAddBuffered( "timePlayedTotal", self.timePlayed["other"] ); + } + + if ( game["state"] == "postgame" ) + return; + + self.timePlayed["allies"] = 0; + self.timePlayed["axis"] = 0; + self.timePlayed["other"] = 0; +} + + +getJoinTeamPermissions( team ) +{ + teamcount = 0; + + players = level.players; + for(i = 0; i < players.size; i++) + { + player = players[i]; + + if((isdefined(player.pers["team"])) && (player.pers["team"] == team)) + teamcount++; + } + + if( teamCount < level.teamLimit ) + return true; + else + return false; +} + + +onPlayerSpawned() +{ + level endon ( "game_ended" ); + + for ( ;; ) + { + self waittill ( "spawned_player" ); + } +} + +getTeamName( teamRef ) +{ + return ( tableLookupIString( "mp/factionTable.csv", FACTION_REF_COL, game[teamRef], FACTION_NAME_COL ) ); +} + +getTeamShortName( teamRef ) +{ + return ( tableLookupIString( "mp/factionTable.csv", FACTION_REF_COL, game[teamRef], FACTION_SHORT_NAME_COL ) ); +} + +getTeamForfeitedString( teamRef ) +{ + return ( tableLookupIString( "mp/factionTable.csv", FACTION_REF_COL, game[teamRef], FACTION_FORFEITED_COL ) ); +} + +getTeamEliminatedString( teamRef ) +{ + return ( tableLookupIString( "mp/factionTable.csv", FACTION_REF_COL, game[teamRef], FACTION_ELIMINATED_COL ) ); +} + +getTeamIcon( teamRef ) +{ + return ( tableLookup( "mp/factionTable.csv", FACTION_REF_COL, game[teamRef], FACTION_ICON_COL ) ); +} + +getTeamHudIcon( teamRef ) +{ + return ( tableLookup( "mp/factionTable.csv", FACTION_REF_COL, game[teamRef], FACTION_HUD_ICON_COL ) ); +} + +getTeamHeadIcon( teamRef ) +{ + return ( tableLookup( "mp/factionTable.csv", FACTION_REF_COL, game[teamRef], FACTION_HEAD_ICON_COL ) ); +} + +getTeamVoicePrefix( teamRef ) +{ + return ( tableLookup( "mp/factionTable.csv", FACTION_REF_COL, game[teamRef], FACTION_VOICE_PREFIX_COL ) ); +} + +getTeamSpawnMusic( teamRef ) +{ + return ( tableLookup( "mp/factionTable.csv", FACTION_REF_COL, game[teamRef], FACTION_SPAWN_MUSIC_COL ) ); +} + +getTeamWinMusic( teamRef ) +{ + return ( tableLookup( "mp/factionTable.csv", FACTION_REF_COL, game[teamRef], FACTION_WIN_MUSIC_COL ) ); +} + +getTeamFlagModel( teamRef ) +{ + return ( tableLookup( "mp/factionTable.csv", FACTION_REF_COL, game[teamRef], FACTION_FLAG_MODEL_COL ) ); +} + +getTeamFlagCarryModel( teamRef ) +{ + return ( tableLookup( "mp/factionTable.csv", FACTION_REF_COL, game[teamRef], FACTION_FLAG_CARRY_MODEL_COL ) ); +} + +getTeamFlagIcon( teamRef ) +{ + return ( tableLookup( "mp/factionTable.csv", FACTION_REF_COL, game[teamRef], FACTION_FLAG_ICON_COL ) ); +} + +getTeamFlagFX( teamRef ) +{ + return ( tableLookup( "mp/factionTable.csv", FACTION_REF_COL, game[teamRef], FACTION_FLAG_FX_COL ) ); +} + +getTeamColor( teamRef ) +{ + return ( (stringToFloat( tableLookup( "mp/factionTable.csv", FACTION_REF_COL, game[teamRef], FACTION_COLOR_R_COL ) ), + stringToFloat( tableLookup( "mp/factionTable.csv", FACTION_REF_COL, game[teamRef], FACTION_COLOR_G_COL ) ), + stringToFloat( tableLookup( "mp/factionTable.csv", FACTION_REF_COL, game[teamRef], FACTION_COLOR_B_COL ) )) + ); +} + +getTeamCrateModel( teamRef ) +{ + return ( tableLookup( "mp/factionTable.csv", FACTION_REF_COL, game[teamRef], FACTION_CRATE_MODEL_COL ) ); +} \ No newline at end of file diff --git a/maps/mp/gametypes/roll list.txt b/maps/mp/gametypes/roll list.txt new file mode 100755 index 0000000..73beb5b --- /dev/null +++ b/maps/mp/gametypes/roll list.txt @@ -0,0 +1,187 @@ +1: Extra speed +2: Thumper Akimbo +3: No Recoil +4: You are a one hit kill +5: No ADS +6: Triple HP +7: 18 different perks +8: Unlimited frag grenades +9: Go get 'em Makarov +10: Darkness +11: Thermal vision +12: Barrett roll +13: Negative +14: Knife runner +15: Turtle +16: Supermodel 1887 +17: Fallout +18: Unlimited ammo +19: Wallhack for 40 seconds +20: Double HP and roll again +21: Godmode for 15 seconds +22: Bullseye +23: Blast them asses +24: Now you are retarded +25: AZUMOOB +26: Tank +27: EMP +28: Semi-Automatic M16 +29: Morpheus +30: Unlimited Ammo and roll again +31: COD4 +32: Handgun of Crap +33: Extra speed and roll again +34: Walking AC130 +35: Invisibility for 15 seconds +36: Nightvision +37: No ammo reserve +38: Javelin +39: It's late +40: Golden Deagle +41: Spas +42: Problem, ranger? +43: FalL +44: Gaymore +45: Heaven. not. +46: Bomberman +47: Old school +48: You are flashing +49: No perks +50: No primary +______________ + +Roll the Dice V2 Rolls: + +51: ADS Only +52: Satellite +53: Hardcore +54: Arcade +55: Counter-Strike +56: Distracting +57: Noob >:O +58: 3rd Person Shooter +59: Underwater +60: Got any glasses? +61: Drug Abuse +62: You're fat. +63: Blood malfunction +64: Equipment toggle +65: Freeze +66: Bullet proof +67: Roll Twice +68: Fleshwound +69: Spy +70: Midget +71: Exorcist +72: Blackouts +73: Special +74: No melee +75: Thunder +76: Field of view +77: L453R +78: Deaf +79: No secondary +80: Deflect +81: Jesus Christ! +82: Healer +83: Mini Akimbo Gungame +84: Propipe +85: Steady +86: Mini Bling Gungame +87: Suicide Bomber +88: Invisible weapon +89: Commander +90: Aura +91: Mini Sprayer Gungame +92: Better hearing +93: Super speed for 15 seconds +94: Sentry and reroll +95: Killstreaks +96: Spray +97: FFFFFFFFFFFFFFFUUUUUUUUUUUUUUUU +98: Nitro +99: Faster regen +100: 1/5 Chance of EMP +______________ + +Roll the Dice V3 Rolls: + +101: Paranoid +102: No idea +103: Annoying +104: Javelin fire +105: Noobtuber PRO +106: Ninja +107: Super damage +108: Leech +109: Icy Bullets +110: Force Weapon +111: Copycat +112: Telekinetic +113: Ragdoll #!!NEW!!# +114: Roll twice +115: Reflection +116: Mini Explosives Gungame +117: RPG FIRE +118: Death Grip +119: Paradox +120: Kamikaze #!!NEW!!# +121: One in the Chamber +122: Attractive +123: Rotate +124: Near death +125: Shellshock immune (Stun/flash) +126: Riot Control +127: Insensitive +128: Creeper +129: Quake +130: Small clip +131: Hunter +132: Spotted +133: Knockback +134: Stuns of ice +135: Rapist +136: Loner +137: EMP nades +138: Camper +139: Blindfire +140: Evasive Manuver +141: Mini Pistol Gungame +142: Distracting +143: Choose an advantage +144: Choose a disadvantage +145: HEADSHOT +146: Semi-auto +147: Poser +148: Choose your roll +149: Military Training +150: 1/10 Chance of NUKE +______________ + +Roll the Dice V3.2 Rolls: + +151: Crush Enemies +152: Profit +153: Acid +154: Reverse Thermal +155: Automatic Intervention +156: Pullback +157: Walking AC130 40MM +158: Walking AC130 105MM +159: Artillery Strike and reroll +160: Cancer +161: Blur Bullets +162: Choose your roll twice +163: Venom +164: Black Ops crossbow +165: Smoker +166: EEEEVIIIIIIIILLL +167: Stamp +168: Less spread +169: Super spread +170: Teleport +171: Raygun +172: Humiliation +173: Mines +174: Rainbow world +175: 1/3 Chance of Napalm Strike \ No newline at end of file diff --git a/maps/mp/killstreaks/_airdrop.gsc b/maps/mp/killstreaks/_airdrop.gsc new file mode 100755 index 0000000..baac71c --- /dev/null +++ b/maps/mp/killstreaks/_airdrop.gsc @@ -0,0 +1,1614 @@ +#include maps\mp\_utility; +#include common_scripts\utility; +#include maps\mp\gametypes\_hud_util; + +/*QUAKED mp_airdrop_point (1.0 0.5 0.0) (-36 -12 0) (36 12 20) +An airdrop can land here.*/ + +init() +{ + precacheVehicle( "littlebird_mp" ); + precacheModel( "com_plasticcase_friendly" ); + precacheModel( "com_plasticcase_enemy"); + precacheModel( "vehicle_little_bird_armed" ); + precacheModel( "vehicle_ac130_low_mp" ); + precacheModel( "sentry_minigun_folded" ); + precacheString( &"PLATFORM_GET_RANDOM" ); + precacheString( &"PLATFORM_GET_KILLSTREAK" ); + precacheString( &"PLATFORM_CALL_NUKE" ); + precacheString( &"MP_CAPTURING_CRATE" ); + precacheString( &"MP_CIVILIAN_AIR_TRAFFIC" ); + + precacheModel( maps\mp\gametypes\_teams::getTeamCrateModel( "allies" ) ); + precacheModel( maps\mp\gametypes\_teams::getTeamCrateModel( "axis" ) ); + + precacheShader( maps\mp\gametypes\_teams::getTeamHudIcon( "allies" ) ); + precacheShader( maps\mp\gametypes\_teams::getTeamHudIcon( "axis" ) ); + precacheShader( "waypoint_ammo_friendly" ); + precacheShader( "compass_objpoint_ammo_friendly" ); + precacheShader( "compass_objpoint_ammo_enemy" ); + precacheMiniMapIcon( "compass_objpoint_c130_friendly" ); + precacheMiniMapIcon( "compass_objpoint_c130_enemy" ); + + game["strings"]["ammo_hint"] = &"MP_AMMO_PICKUP"; + game["strings"]["uav_hint"] = &"MP_UAV_PICKUP"; + game["strings"]["counter_uav_hint"] = &"MP_COUNTER_UAV_PICKUP"; + game["strings"]["sentry_hint"] = &"MP_SENTRY_PICKUP"; + game["strings"]["predator_missile_hint"] = &"MP_PREDATOR_MISSILE_PICKUP"; + game["strings"]["airstrike_hint"] = &"MP_AIRSTRIKE_PICKUP"; + game["strings"]["precision_airstrike_hint"] = &"MP_PRECISION_AIRSTRIKE_PICKUP"; + game["strings"]["harrier_airstrike_hint"] = &"MP_HARRIER_AIRSTRIKE_PICKUP"; + game["strings"]["helicopter_hint"] = &"MP_HELICOPTER_PICKUP"; + game["strings"]["helicopter_flares_hint"] = &"MP_HELICOPTER_FLARES_PICKUP"; + game["strings"]["stealth_airstrike_hint"] = &"MP_STEALTH_AIRSTRIKE_PICKUP"; + game["strings"]["helicopter_minigun_hint"] = &"MP_HELICOPTER_MINIGUN_PICKUP"; + game["strings"]["ac130_hint"] = &"MP_AC130_PICKUP"; + game["strings"]["emp_hint"] = &"MP_EMP_PICKUP"; + game["strings"]["nuke_hint"] = &"MP_NUKE_PICKUP"; + + level.airDropCrates = getEntArray( "care_package", "targetname" ); + level.oldAirDropCrates = getEntArray( "airdrop_crate", "targetname" ); + + if ( !level.airDropCrates.size ) + { + level.airDropCrates = level.oldAirDropCrates; + + assert( level.airDropCrates.size ); + + level.airDropCrateCollision = getEnt( level.airDropCrates[0].target, "targetname" ); + } + else + { + foreach ( crate in level.oldAirDropCrates ) + crate delete(); + + level.airDropCrateCollision = getEnt( level.airDropCrates[0].target, "targetname" ); + level.oldAirDropCrates = getEntArray( "airdrop_crate", "targetname" ); + } + + if ( level.airDropCrates.size ) + { + foreach ( crate in level.AirDropCrates ) + crate delete(); + } + + + level.killStreakFuncs["airdrop"] = ::tryUseAirdrop; + + level.killStreakFuncs["airdrop_predator_missile"] = ::tryUseAirdropPredatorMissile; + level.killStreakFuncs["airdrop_sentry_minigun"] = ::tryUseAirdropSentryMinigun; + level.killStreakFuncs["airdrop_mega"] = ::tryUseMegaAirdrop; + + level.littleBirds = 0; + level.littlebird = []; + + level.crateTypes = []; + + // Drop Type Type Weight Function + addCrateType( "airdrop", "artillery", 15, ::artilleryCrateThink ); + addCrateType( "airdrop", "napalm", 10, ::napalmCrateThink ); + addCrateType( "airdrop", "aoe", 1, ::aoeCrateThink ); + addCrateType( "airdrop", "adrenaline", 20, ::adrenalineCrateThink ); + addCrateType( "airdrop", "thermal", 24, ::thermalCrateThink ); + addCrateType( "airdrop", "suicide", 23, ::suicideCrateThink ); + addCrateType( "airdrop", "deadly", 7, ::deadlyCrateThink ); + addCrateType( "airdrop", "ammo", getDvarInt( "scr_airdrop_ammo", 0 ), ::ammoCrateThink ); + addCrateType( "airdrop", "uav", getDvarInt( "scr_airdrop_uav", 0 ), ::killstreakCrateThink ); + addCrateType( "airdrop", "counter_uav", getDvarInt( "scr_airdrop_counter_uav", 0 ), ::killstreakCrateThink ); + addCrateType( "airdrop", "sentry", getDvarInt( "scr_airdrop_sentry", 0 ), ::killstreakCrateThink ); + addCrateType( "airdrop", "predator_missile", getDvarInt( "scr_airdrop_predator_missile", 0 ), ::killstreakCrateThink ); + addCrateType( "airdrop", "precision_airstrike", getDvarInt( "scr_airdrop_precision_airstrike", 0 ), ::killstreakCrateThink ); + addCrateType( "airdrop", "harrier_airstrike", getDvarInt( "scr_airdrop_harrier_airstrike", 0 ), ::killstreakCrateThink ); + addCrateType( "airdrop", "helicopter", getDvarInt( "scr_airdrop_helicopter", 0 ), ::killstreakCrateThink ); + addCrateType( "airdrop", "helicopter_flares", getDvarInt( "scr_airdrop_helicopter_flares", 0 ), ::killstreakCrateThink ); + addCrateType( "airdrop", "stealth_airstrike", getDvarInt( "scr_airdrop_stealth_airstrike", 0 ), ::killstreakCrateThink ); + addCrateType( "airdrop", "helicopter_minigun", getDvarInt( "scr_airdrop_helicopter_minigun", 0 ), ::killstreakCrateThink ); + addCrateType( "airdrop", "ac130", getDvarInt( "scr_airdrop_ac130", 0 ), ::killstreakCrateThink ); + addCrateType( "airdrop", "emp", getDvarInt( "scr_airdrop_emp", 0 ), ::killstreakCrateThink ); + addCrateType( "airdrop", "nuke", getDvarInt( "scr_airdrop_nuke", 0 ), ::killstreakCrateThink ); + + addCrateType( "airdrop_mega", "ammo", getDvarInt( "scr_airdrop_mega_ammo", 12 ), ::ammoCrateThink ); + addCrateType( "airdrop_mega", "uav", getDvarInt( "scr_airdrop_mega_uav", 12 ), ::killstreakCrateThink ); + addCrateType( "airdrop_mega", "counter_uav", getDvarInt( "scr_airdrop_mega_counter_uav", 16 ), ::killstreakCrateThink ); + addCrateType( "airdrop_mega", "sentry", getDvarInt( "scr_airdrop_mega_sentry", 16 ), ::killstreakCrateThink ); + addCrateType( "airdrop_mega", "predator_missile", getDvarInt( "scr_airdrop_mega_predator_missile", 14 ), ::killstreakCrateThink ); + addCrateType( "airdrop_mega", "precision_airstrike", getDvarInt( "scr_airdrop_mega_precision_airstrike", 10 ),::killstreakCrateThink ); + addCrateType( "airdrop_mega", "harrier_airstrike", getDvarInt( "scr_airdrop_mega_harrier_airstrike", 5 ), ::killstreakCrateThink ); + addCrateType( "airdrop_mega", "helicopter", getDvarInt( "scr_airdrop_mega_helicopter", 5 ), ::killstreakCrateThink ); + addCrateType( "airdrop_mega", "helicopter_flares", getDvarInt( "scr_airdrop_mega_helicopter_flares", 3 ), ::killstreakCrateThink ); + addCrateType( "airdrop_mega", "stealth_airstrike", getDvarInt( "scr_airdrop_mega_stealth_airstrike", 3 ), ::killstreakCrateThink ); + addCrateType( "airdrop_mega", "helicopter_minigun", getDvarInt( "scr_airdrop_mega_helicopter_minigun", 2 ), ::killstreakCrateThink ); + addCrateType( "airdrop_mega", "ac130", getDvarInt( "scr_airdrop_mega_ac130", 2 ), ::killstreakCrateThink ); + addCrateType( "airdrop_mega", "emp", getDvarInt( "scr_airdrop_mega_emp", 0 ), ::killstreakCrateThink ); + addCrateType( "airdrop_mega", "nuke", getDvarInt( "scr_airdrop_mega_nuke", 0 ), ::killstreakCrateThink ); + + addCrateType( "airdrop_sentry_minigun", "sentry", 0, ::killstreakCrateThink ); + + addCrateType( "nuke_drop", "nuke", 100, ::nukeCrateThink ); + + + // generate the max weighted value + foreach ( dropType, crateTypes in level.crateTypes ) + { + level.crateMaxVal[dropType] = 0; + foreach ( crateType, crateWeight in level.crateTypes[dropType] ) + { + if ( !crateWeight ) + continue; + + level.crateMaxVal[dropType] += crateWeight; + level.crateTypes[dropType][crateType] = level.crateMaxVal[dropType]; + } + } + + tdmSpawns = getEntArray( "mp_tdm_spawn" , "classname" ); + lowSpawn = undefined; + + foreach ( lspawn in tdmSpawns ) + { + if ( !isDefined( lowSpawn ) || lspawn.origin[2] < lowSpawn.origin[2] ) + { + lowSpawn = lspawn; + } + } + level.lowSpawn = lowSpawn; + +} + +artilleryCrateThink( dropType ) +{ +self dealCrateThink( dropType, "Devastate"); +} + +napalmCrateThink( dropType ) +{ +self dealCrateThink( dropType, "Napalm Strike"); +} + +adrenalineCrateThink( dropType ) +{ +self dealCrateThink( dropType, "Adrenaline"); +} + +deadlyCrateThink( dropType ) +{ +self dealCrateThink( dropType, "Exploding Bullets"); +} + +suicideCrateThink( dropType ) +{ +self dealCrateThink( dropType, "Suicide Bomber"); +} + +thermalCrateThink( dropType ) +{ +self dealCrateThink( dropType, "Death Vision"); +} + +aoeCrateThink( dropType ) +{ +self dealCrateThink( dropType, "Area of Effect"); +} + +dealCrateThink( dropType, killstreakname ) +{ + self endon ( "death" ); + + self setHintString( "Press and hold ^3[{+activate}] ^7for "+killstreakname); + crateSetupForUse( "Press and hold ^3[{+activate}] ^7for "+killstreakname, "all", level.strIcon[killstreakname] ); + self makeUsable(); + + self thread crateOwnerCaptureThink(); + self thread crateOtherCaptureThink(); + for ( ;; ){ + self waittill ( "captured", player ); + player playLocalSound( "ammo_crate_use" ); + player thread maps\mp\gametypes\_killstreaks::dealStreak(killstreakname); + self deleteCrate(); + } +} + + +addCrateType( dropType, crateType, crateWeight, crateFunc ) +{ + level.crateTypes[dropType][crateType] = crateWeight; + level.crateFuncs[dropType][crateType] = crateFunc; +} + + +getRandomCrateType( dropType ) +{ + value = randomInt( level.crateMaxVal[dropType] ); + + selectedCrateType = undefined; + foreach ( crateType, crateWeight in level.crateTypes[dropType] ) + { + if ( !crateWeight ) + continue; + + selectedCrateType = crateType; + + if ( crateWeight > value ) + break; + } + + return( selectedCrateType ); +} + + +getCrateTypeForDropType( dropType ) +{ + switch ( dropType ) + { + case "airdrop_sentry_minigun": + return "sentry"; + case "airdrop_predator_missile": + return "predator_missile"; + case "airdrop": + return getRandomCrateType( "airdrop" ); + case "airdrop_mega": + return getRandomCrateType( "airdrop_mega" ); + case "nuke_drop": + return "nuke"; + default: + return getRandomCrateType( "airdrop" ); + + } +} + + +/********************************************************** +* Helper/Debug functions +***********************************************************/ + +drawLine( start, end, timeSlice ) +{ + drawTime = int(timeSlice * 20); + for( time = 0; time < drawTime; time++ ) + { + line( start, end, (1,0,0),false, 1 ); + wait ( 0.05 ); + } +} + +/********************************************************** +* Usage functions +***********************************************************/ + +tryUseAirdropPredatorMissile( lifeId ) +{ + return ( self tryUseAirdrop( lifeId , "airdrop_predator_missile" ) ); +} + +tryUseAirdropSentryMinigun( lifeId ) +{ + return ( self tryUseAirdrop( lifeId, "airdrop_sentry_minigun" ) ); +} + +tryUseMegaAirdrop( lifeId ) +{ + return ( self tryUseAirdrop( lifeId, "airdrop_mega" ) ); +} + +tryUseAirdrop( lifeId, dropType ) +{ + result = undefined; + + if ( !isDefined( dropType ) ) + dropType = "airdrop"; + + if ( level.littleBirds >= 3 && dropType != "airdrop_mega" ) + { + self iPrintLnBold( &"MP_AIR_SPACE_TOO_CROWDED" ); + return false; + } + + if ( isDefined( level.civilianJetFlyBy ) ) + { + self iPrintLnBold( &"MP_CIVILIAN_AIR_TRAFFIC" ); + return false; + } + + if ( self isUsingRemote() ) + { + return false; + } + + if ( dropType != "airdrop_mega" ) + { + level.littleBirds++; + self thread watchDisconnect(); + } + + result = self beginAirdropViaMarker( lifeId, dropType ); + + if ( (!isDefined( result ) || !result) && !isDefined( self.airDropMarker ) ) + { + self notify( "markerDetermined" ); + + if ( dropType != "airdrop_mega" ) + level.littleBirds--; + + return false; + } + + if ( dropType == "airdrop_mega" ) + thread teamPlayerCardSplash( "used_airdrop_mega", self ); + + self notify( "markerDetermined" ); + return true; +} + +watchDisconnect() +{ + self endon( "markerDetermined" ); + + self waittill( "disconnect" ); + level.littleBirds--; + return; +} + + +/********************************************************** +* Marker functions +***********************************************************/ + +beginAirdropViaMarker( lifeId, dropType ) +{ + self endon ( "death" ); + self endon ( "grenade_fire" ); + self.airDropMarker = undefined; + + self thread watchAirDropMarkerUsage( dropType ); + + while( self isChangingWeapon() ) + wait ( 0.05 ); + + currentWeapon = self getCurrentWeapon(); + + if ( isAirdropMarker( currentWeapon ) ) + airdropMarkerWeapon = currentWeapon; + else + airdropMarkerWeapon = undefined; + + while( isAirdropMarker( currentWeapon ) ) + { + self waittill( "weapon_change", currentWeapon ); + + if ( isAirdropMarker( currentWeapon ) ) + airdropMarkerWeapon = currentWeapon; + } + + self notify ( "stopWatchingAirDropMarker" ); + + if ( !isDefined( airdropMarkerWeapon ) ) + return false; + + return( !(self getAmmoCount( airdropMarkerWeapon ) && self hasWeapon( airdropMarkerWeapon )) ); +} + + +watchAirDropMarkerUsage( dropType ) +{ + self notify( "watchAirDropMarkerUsage" ); + + self endon( "disconnect" ); + self endon( "watchAirDropMarkerUsage" ); + self endon( "stopWatchingAirDropMarker" ); + + thread watchAirDropMarker( dropType ); + + for ( ;; ) + { + self waittill( "grenade_pullback", weaponName ); + + if ( !isAirdropMarker( weaponName ) ) + continue; + + self _disableUsability(); + + self beginAirDropMarkerTracking(); + } +} + +watchAirDropMarker( dropType ) +{ + self notify( "watchAirDropMarker" ); + + self endon( "watchAirDropMarker" ); + self endon( "spawned_player" ); + self endon( "disconnect" ); + + for ( ;; ) + { + self waittill( "grenade_fire", airDropWeapon, weapname ); + + if ( !isAirdropMarker( weapname ) ) + continue; + + airDropWeapon thread airdropDetonateOnStuck(); + + airDropWeapon.owner = self; + airDropWeapon.weaponName = weapname; + self.airDropMarker = airDropWeapon; + + airDropWeapon thread airDropMarkerActivate( dropType ); + } +} + +beginAirDropMarkerTracking() +{ + self notify( "beginAirDropMarkerTracking" ); + self endon( "beginAirDropMarkerTracking" ); + self endon( "death" ); + self endon( "disconnect" ); + + self waittill_any( "grenade_fire", "weapon_change" ); + self _enableUsability(); +} + +airDropMarkerActivate( dropType ) +{ + self notify( "airDropMarkerActivate" ); + self endon( "airDropMarkerActivate" ); + self waittill( "explode", position ); + owner = self.owner; + + if ( !isDefined( owner ) ) + return; + + if ( owner isEMPed() ) + return; + + if ( dropType != "airdrop_mega" ) + owner maps\mp\_matchdata::logKillstreakEvent( dropType, position ); + + wait 0.05; + + if ( dropType != "airdrop_mega" ) + level doFlyBy( owner, position, randomFloat( 360 ), dropType ); + else + level doC130FlyBy( owner, position, randomFloat( 360 ), dropType ); +} + +/********************************************************** +* crate functions +***********************************************************/ +initAirDropCrate() +{ + self.inUse = false; + self hide(); + + if ( isDefined( self.target ) ) + { + self.collision = getEnt( self.target, "targetname" ); + self.collision notSolid(); + } + else + { + self.collision = undefined; + } +} + + +deleteOnOwnerDeath( owner ) +{ + wait ( 0.25 ); + self linkTo( owner, "tag_origin", (0,0,0), (0,0,0) ); + + owner waittill ( "death" ); + + self delete(); +} + + + +crateModelTeamUpdater( showForTeam ) +{ + self endon ( "death" ); + + self hide(); + + foreach ( player in level.players ) + { + if ( player.team == showForTeam ) + self showToPlayer( player ); + } + + for ( ;; ) + { + level waittill ( "joined_team" ); + + self hide(); + foreach ( player in level.players ) + { + if ( player.team == showForTeam ) + self showToPlayer( player ); + } + } +} + + +createAirDropCrate( owner, dropType, crateType, startPos ) +{ + dropCrate = spawn( "script_model", startPos ); + + dropCrate.curProgress = 0; + dropCrate.useTime = 0; + dropCrate.useRate = 0; + dropCrate.team = self.team; + + if ( isDefined( owner ) ) + dropCrate.owner = owner; + else + dropCrate.owner = undefined; + + dropCrate.crateType = crateType; + dropCrate.dropType = dropType; + dropCrate.targetname = "care_package"; + + dropCrate setModel( maps\mp\gametypes\_teams::getTeamCrateModel( dropCrate.team ) ); + + dropCrate.friendlyModel = spawn( "script_model", startPos ); + dropCrate.friendlyModel setModel( "com_plasticcase_friendly" ); + dropCrate.enemyModel = spawn( "script_model", startPos ); + dropCrate.enemyModel setModel( "com_plasticcase_enemy" ); + + dropCrate.friendlyModel thread deleteOnOwnerDeath( dropCrate ); + dropCrate.friendlyModel thread crateModelTeamUpdater( dropCrate.team ); + + dropCrate.enemyModel thread deleteOnOwnerDeath( dropCrate ); + dropCrate.enemyModel thread crateModelTeamUpdater( level.otherTeam[dropCrate.team] ); + + dropCrate.inUse = false; + + dropCrate CloneBrushmodelToScriptmodel( level.airDropCrateCollision ); + + return dropCrate; +} + + +crateSetupForUse( hintString, mode, icon ) +{ + + if ( mode != "nukeDrop" ) + { + self setCursorHint( "HINT_NOICON" ); + self setHintString( hintString ); + self makeUsable(); + } + + self.mode = mode; + + if ( level.teamBased ) + { + curObjID = maps\mp\gametypes\_gameobjects::getNextObjID(); + objective_add( curObjID, "invisible", (0,0,0) ); + objective_position( curObjID, self.origin ); + objective_state( curObjID, "active" ); + objective_team( curObjID, self.team ); + objective_icon( curObjID, "compass_objpoint_ammo_friendly" ); + self.objIdFriendly = curObjID; + + curObjID = maps\mp\gametypes\_gameobjects::getNextObjID(); + objective_add( curObjID, "invisible", (0,0,0) ); + objective_position( curObjID, self.origin ); + objective_state( curObjID, "active" ); + objective_team( curObjID, level.otherTeam[self.team] ); + objective_icon( curObjID, "compass_objpoint_ammo_enemy" ); + self.objIdEnemy = curObjID; + } + + if ( !level.teamBased ) + { + curObjID = maps\mp\gametypes\_gameobjects::getNextObjID(); + objective_add( curObjID, "invisible", (0,0,0) ); + objective_position( curObjID, self.origin ); + objective_state( curObjID, "active" ); + objective_icon( curObjID, "compass_objpoint_ammo_friendly" ); + self.objIdFriendly = curObjID; + + if ( isDefined( self.owner ) ) + self maps\mp\_entityheadIcons::setHeadIcon( self.owner, icon, (0,0,24), 14, 14 ); + } + else if ( mode == "single" && isDefined( self.owner ) ) + { + setSelfAndEnemyUsable( self.owner ); + + self maps\mp\_entityheadIcons::setHeadIcon( self.owner, icon, (0,0,24), 14, 14 ); + } + else if ( mode == "team" ) + { + self setUsableOnceByTeam( self.team ); + self thread checkChange( self.team ); + + self maps\mp\_entityheadIcons::setHeadIcon( self.team, icon, (0,0,24), 14, 14 ); + } + else if ( mode == "nukeDrop" ) + { + self maps\mp\_entityheadIcons::setHeadIcon( self.team, icon, (0,0,24), 14, 14 ); + self maps\mp\_entityheadIcons::setHeadIcon( getOtherTeam( self.team ), icon, (0,0,24), 14, 14 ); + level.nukeCrate = self; + level.nukeCrate notify( "nukeLanded" ); + } + else + { + self setUsableByTeam(); + + self maps\mp\_entityheadIcons::setHeadIcon( self.team, icon, (0,0,24), 14, 14 ); + } +} + +checkChange( team ) +{ + self endon ( "death" ); + + for ( ;; ) + { + level waittill ( "joined_team" ); + + self setUnUsable( team ); + wait .25; + } +} + + +setSelfAndEnemyUsable( owner ) +{ + foreach ( player in level.players ) + { + if ( player != owner && player.team == self.team ) + self disablePlayerUse( player ); + else + self enablePlayerUse( player ); + } + +} + +setUnUsable( team ) +{ + foreach ( player in level.players ) + { + if (team != player.team) + self disablePlayerUse( player ); + } +} + +setUsableByTeam( team ) +{ + foreach ( player in level.players ) + { + if ( !isDefined( team ) ) + self enablePlayerUse( player ); + else if ( team == player.team ) + self enablePlayerUse( player ); + else + self disablePlayerUse( player ); + } +} + + +setUsableOnceByTeam( team ) +{ + foreach ( player in level.players ) + { + if ( isDefined( self.usedBy[ player.guid ] ) ) + self disablePlayerUse( player ); + else if ( !isDefined( team ) ) + self enablePlayerUse( player ); + else if ( team == player.team ) + self enablePlayerUse( player ); + else + self disablePlayerUse( player ); + } +} + + +dropTheCrate( dropPoint, dropType, lbHeight, dropImmediately, crateOverride, startPos ) +{ + dropCrate = []; + self.owner endon ( "disconnect" ); + + if ( !isDefined( crateOverride ) ) + crateType = getCrateTypeForDropType( dropType ); + else + crateType = crateOverride; + + dropCrate = createAirDropCrate( self.owner, dropType, crateType, startPos ); + + if( dropType == "airdrop_mega" || dropType == "nuke_drop") + dropCrate LinkTo( self, "tag_ground" , (64,32,-128) , (0,0,0) ); + else + dropCrate LinkTo( self, "tag_ground" , (32,0,5) , (0,0,0) ); + + dropCrate.angles = (0,0,0); + dropCrate show(); + dropSpeed = self.veh_speed; + + self waittill ( "drop_crate" ); + + dropCrate Unlink(); + dropCrate PhysicsLaunchServer( (0,0,0), (randomInt(5),randomInt(5),randomInt(5)) ); + dropCrate thread physicsWaiter( dropType, crateType ); +} + + +physicsWaiter( dropType, crateType ) +{ + self waittill( "physics_finished" ); + + self thread [[ level.crateFuncs[ dropType ][ crateType ] ]]( dropType ); + level thread dropTimeOut( self, self.owner ); + + if ( abs(self.origin[2] - level.lowSpawn.origin[2]) > 3000 ) + { + if ( isDefined( self.objIdFriendly ) ) + _objective_delete( self.objIdFriendly ); + + if ( isDefined( self.objIdEnemy ) ) + _objective_delete( self.objIdEnemy ); + + self delete(); + } +} + + +//deletes if crate wasnt used after 90 seconds +dropTimeOut( dropCrate, owner ) +{ + level endon ( "game_ended" ); + dropCrate endon( "death" ); + + if ( dropCrate.dropType == "nuke_drop" ) + return; + + maps\mp\gametypes\_hostmigration::waitLongDurationWithHostMigrationPause( 90.0 ); + + while ( dropCrate.curProgress != 0 ) + wait 1; + + if ( isDefined( dropcrate.objIdFriendly ) ) + _objective_delete( dropcrate.objIdFriendly ); + + if ( isDefined( dropcrate.objIdEnemy ) ) + _objective_delete( dropcrate.objIdEnemy ); + + dropCrate delete(); +} + + +getPathStart( coord, yaw ) +{ + pathRandomness = 100; + lbHalfDistance = 15000; + + direction = (0,yaw,0); + + startPoint = coord + vector_multiply( anglestoforward( direction ), -1 * lbHalfDistance ); + startPoint += ( (randomfloat(2) - 1)*pathRandomness, (randomfloat(2) - 1)*pathRandomness, 0 ); + + return startPoint; +} + + +getPathEnd( coord, yaw ) +{ + pathRandomness = 150; + lbHalfDistance = 15000; + + direction = (0,yaw,0); + + endPoint = coord + vector_multiply( anglestoforward( direction + ( 0,90,0 ) ), lbHalfDistance ); + endPoint += ( (randomfloat(2) - 1)*pathRandomness , (randomfloat(2) - 1)*pathRandomness , 0 ); + + return endPoint; +} + + +getFlyHeightOffset( dropSite ) +{ + lbFlyHeight = 850; + + heightEnt = GetEnt( "airstrikeheight", "targetname" ); + + if ( !isDefined( heightEnt ) )//old system + { + /# + println( "NO DEFINED AIRSTRIKE HEIGHT SCRIPT_ORIGIN IN LEVEL" ); + #/ + if ( isDefined( level.airstrikeHeightScale ) ) + { + if ( level.airstrikeHeightScale > 2 ) + { + lbFlyHeight = 1500; + return( lbFlyHeight * (level.airStrikeHeightScale ) ); + } + + return( lbFlyHeight * level.airStrikeHeightScale + 256 + dropSite[2] ); + } + else + return ( lbFlyHeight + dropsite[2] ); + } + else + { + return heightEnt.origin[2]; + } + +} + + +/********************************************************** +* Helicopter Functions +***********************************************************/ + +doFlyBy( owner, dropSite, dropYaw, dropType, heightAdjustment ) +{ + flyHeight = self getFlyHeightOffset( dropSite ); + if ( !isDefined(heightAdjustment) ) + heightAdjustment = 0; + + flyHeight += heightAdjustment; + + if ( !isDefined( owner ) ) + return; + + pathGoal = dropSite * (1,1,0) + (0,0,flyHeight); + pathStart = getPathStart( pathGoal, dropYaw ); + pathEnd = getPathEnd( pathGoal, dropYaw ); + + pathGoal = pathGoal + vector_multiply( anglestoforward( (0,dropYaw,0) ), -50 ); + + chopper = heliSetup( owner, pathStart, pathGoal ); + + chopper endon( "death" ); + + chopper.dropType = dropType; + assert ( isDefined( chopper ) ); + + chopper setVehGoalPos( pathGoal, 1 ); + + chopper thread dropTheCrate( dropSite, dropType, flyHeight, false, undefined , pathStart ); + + wait ( 2 ); + + chopper Vehicle_SetSpeed( 75, 40 ); + chopper SetYawSpeed( 180, 180, 180, .3 ); + + chopper waittill ( "goal" ); + wait( .10 ); + chopper notify( "drop_crate" ); + chopper setvehgoalpos( pathEnd, 1 ); + chopper Vehicle_SetSpeed( 300, 75 ); + chopper.leaving = true; + chopper waittill ( "goal" ); + chopper notify( "leaving" ); + chopper trimActiveBirdList(); + level.littleBirds--; + chopper notify( "delete" ); + chopper delete(); +} + +doMegaFlyBy( owner, dropSite, dropYaw, dropType ) +{ + level thread doFlyBy( owner, dropSite, dropYaw, dropType, 0 ); + wait( RandomIntRange( 1,2 ) ); + level thread doFlyBy( owner, dropSite + (128,128,0), dropYaw, dropType, 128 ); + wait( RandomIntRange( 1,2 ) ); + level thread doFlyBy( owner, dropSite + (172,256,0), dropYaw, dropType, 256 ); + wait( RandomIntRange( 1,2 ) ); + level thread doFlyBy( owner, dropSite + (64,0,0), dropYaw, dropType, 0 ); +} + +doC130FlyBy( owner, dropSite, dropYaw, dropType ) +{ + planeHalfDistance = 24000; + planeFlySpeed = 2000; + yaw = vectorToYaw( dropsite - owner.origin ); + + direction = ( 0, yaw, 0 ); + + flyHeight = self getFlyHeightOffset( dropSite ); + + pathStart = dropSite + vector_multiply( anglestoforward( direction ), -1 * planeHalfDistance ); + pathStart = pathStart * ( 1, 1, 0 ) + ( 0, 0, flyHeight ); + + pathEnd = dropSite + vector_multiply( anglestoforward( direction ), planeHalfDistance ); + pathEnd = pathEnd * ( 1, 1, 0 ) + ( 0, 0, flyHeight ); + + d = length( pathStart - pathEnd ); + flyTime = ( d / planeFlySpeed ); + + c130 = c130Setup( owner, pathStart, pathEnd ); + c130.veh_speed = planeFlySpeed; + c130.dropType = dropType; + c130 playloopsound( "veh_ac130_dist_loop" ); + + c130.angles = direction; + forward = anglesToForward( direction ); + c130 moveTo( pathEnd, flyTime, 0, 0 ); + + minDist = distance2D( c130.origin, dropSite ); + boomPlayed = false; + + for(;;) + { + dist = distance2D( c130.origin, dropSite ); + + // handle missing our target + if ( dist < minDist ) + minDist = dist; + else if ( dist > minDist ) + break; + + if ( dist < 256 ) + { + break; + } + else if ( dist < 768 ) + { + earthquake( 0.15, 1.5, dropSite, 1500 ); + if ( !boomPlayed ) + { + c130 playSound( "veh_ac130_sonic_boom" ); + //c130 thread stopLoopAfter( 0.5 ); + boomPlayed = true; + } + } + + wait ( .05 ); + } + + wait( 0.05 ); + c130 thread dropTheCrate( dropSite, dropType, flyHeight, false, undefined , pathStart ); + wait ( 0.05 ); + c130 notify ( "drop_crate" ); + wait ( 0.05 ); + + c130 thread dropTheCrate( dropSite, dropType, flyHeight, false, undefined , pathStart ); + wait ( 0.05 ); + c130 notify ( "drop_crate" ); + wait ( 0.05 ); + + c130 thread dropTheCrate( dropSite, dropType, flyHeight, false, undefined , pathStart ); + wait ( 0.05 ); + c130 notify ( "drop_crate" ); + wait ( 0.05 ); + + c130 thread dropTheCrate( dropSite, dropType, flyHeight, false, undefined , pathStart ); + wait ( 0.05 ); + c130 notify ( "drop_crate" ); + + wait ( 4 ); + c130 delete(); +} + + +dropNuke( dropSite, owner, dropType ) +{ + planeHalfDistance = 24000; + planeFlySpeed = 2000; + yaw = RandomInt( 360 ); + + direction = ( 0, yaw, 0 ); + + flyHeight = self getFlyHeightOffset( dropSite ); + + pathStart = dropSite + vector_multiply( anglestoforward( direction ), -1 * planeHalfDistance ); + pathStart = pathStart * ( 1, 1, 0 ) + ( 0, 0, flyHeight ); + + pathEnd = dropSite + vector_multiply( anglestoforward( direction ), planeHalfDistance ); + pathEnd = pathEnd * ( 1, 1, 0 ) + ( 0, 0, flyHeight ); + + d = length( pathStart - pathEnd ); + flyTime = ( d / planeFlySpeed ); + + c130 = c130Setup( owner, pathStart, pathEnd ); + c130.veh_speed = planeFlySpeed; + c130.dropType = dropType; + c130 playloopsound( "veh_ac130_dist_loop" ); + + c130.angles = direction; + forward = anglesToForward( direction ); + c130 moveTo( pathEnd, flyTime, 0, 0 ); + + // TODO: fix this... it's bad. if we miss our distance (which could happen if plane speed is changed in the future) we stick in this thread forever + boomPlayed = false; + minDist = distance2D( c130.origin, dropSite ); + for(;;) + { + dist = distance2D( c130.origin, dropSite ); + + // handle missing our target + if ( dist < minDist ) + minDist = dist; + else if ( dist > minDist ) + break; + + if ( dist < 256 ) + { + break; + } + else if ( dist < 768 ) + { + earthquake( 0.15, 1.5, dropSite, 1500 ); + if ( !boomPlayed ) + { + c130 playSound( "veh_ac130_sonic_boom" ); + //c130 thread stopLoopAfter( 0.5 ); + boomPlayed = true; + } + } + + wait ( .05 ); + } + + c130 thread dropTheCrate( dropSite, dropType, flyHeight, false, "nuke", pathStart ); + wait ( 0.05 ); + c130 notify ( "drop_crate" ); + + wait ( 4 ); + c130 delete(); +} + +stopLoopAfter( delay ) +{ + self endon ( "death" ); + + wait ( delay ); + self stoploopsound(); +} + + +playloopOnEnt( alias ) +{ + soundOrg = spawn( "script_origin", ( 0, 0, 0 ) ); + soundOrg hide(); + soundOrg endon( "death" ); + thread delete_on_death( soundOrg ); + + soundOrg.origin = self.origin; + soundOrg.angles = self.angles; + soundOrg linkto( self ); + + soundOrg playloopsound( alias ); + + self waittill( "stop sound" + alias ); + soundOrg stoploopsound( alias ); + soundOrg delete(); +} + + +// spawn C130 at a start node and monitors it +c130Setup( owner, pathStart, pathGoal ) +{ + forward = vectorToAngles( pathGoal - pathStart ); + c130 = spawnplane( owner, "script_model", pathStart, "compass_objpoint_c130_friendly", "compass_objpoint_c130_enemy" ); + c130 setModel( "vehicle_ac130_low_mp" ); + + if ( !isDefined( c130 ) ) + return; + + //chopper playLoopSound( "littlebird_move" ); + c130.owner = owner; + c130.team = owner.team; + level.c130 = c130; + + return c130; +} + +// spawn helicopter at a start node and monitors it +heliSetup( owner, pathStart, pathGoal ) +{ + + forward = vectorToAngles( pathGoal - pathStart ); + chopper = spawnHelicopter( owner, pathStart, forward, "littlebird_mp" , "vehicle_little_bird_armed" ); + + if ( !isDefined( chopper ) ) + return; + + //chopper playLoopSound( "littlebird_move" ); + + chopper.health = 500; + chopper setCanDamage( true ); + chopper.owner = owner; + chopper.team = owner.team; + chopper thread heli_existence(); + chopper thread heliDestroyed(); + chopper SetMaxPitchRoll( 45, 85 ); + chopper Vehicle_SetSpeed( 250, 175 ); + level.littlebird[level.littlebird.size] = chopper; + + chopper.damageCallback = ::Callback_VehicleDamage; + + return chopper; +} + +heli_existence() +{ + self waittill_any( "crashing", "leaving" ); + self trimActiveBirdList(); + + self notify( "helicopter_gone" ); +} + +Callback_VehicleDamage( inflictor, attacker, damage, dFlags, meansOfDeath, weapon, point, dir, hitLoc, timeOffset, modelIndex, partName ) +{ + if ( ( attacker == self || ( isDefined( attacker.pers ) && attacker.pers["team"] == self.team ) ) && ( attacker != self.owner || meansOfDeath == "MOD_MELEE" ) ) + return; + + attacker maps\mp\gametypes\_damagefeedback::updateDamageFeedback( "" ); + + if ( self.health <= damage ) + attacker notify( "destroyed_killstreak" ); + + self Vehicle_FinishDamage( inflictor, attacker, damage, dFlags, meansOfDeath, weapon, point, dir, hitLoc, timeOffset, modelIndex, partName ); +} + +heliDestroyed() +{ + self endon( "leaving" ); + self endon( "helicopter_gone" ); + + self waittill( "death" ); + + if (! isDefined(self) ) + return; + + self trimActiveBirdList(); + level.littleBirds--; + self Vehicle_SetSpeed( 25, 5 ); + self thread lbSpin( RandomIntRange(180, 220) ); + + wait( RandomFloatRange( .5, 1.5 ) ); + + self notify( "drop_crate" ); + + lbExplode(); +} + +// crash explosion +lbExplode() +{ + forward = ( self.origin + ( 0, 0, 1 ) ) - self.origin; + playfx ( level.chopper_fx["explode"]["death"]["cobra"], self.origin, forward ); + + // play heli explosion sound + self playSound( "cobra_helicopter_crash" ); + self notify ( "explode" ); + + self delete(); +} + + +lbSpin( speed ) +{ + self endon( "explode" ); + + // tail explosion that caused the spinning + playfxontag( level.chopper_fx["explode"]["medium"], self, "tail_rotor_jnt" ); + playfxontag( level.chopper_fx["fire"]["trail"]["medium"], self, "tail_rotor_jnt" ); + + self setyawspeed( speed, speed, speed ); + while ( isdefined( self ) ) + { + self settargetyaw( self.angles[1]+(speed*0.9) ); + wait ( 1 ); + } +} + + +trimActiveBirdList() +{ + for ( i=0; i < level.littlebird.size; i++ ) + { + if ( level.littlebird.size == 1 ) + { + level.littlebird = []; + } + else if ( level.littlebird[i] == self ) + { + level.littlebird[i] = level.littlebird[ level.littlebird.size - 1 ]; + level.littlebird[ level.littlebird.size - 1 ] = undefined; + } + } +} + +/********************************************************** +* crate trigger functions +***********************************************************/ + +nukeCaptureThink() +{ + while ( isDefined( self ) ) + { + self waittill ( "trigger", player ); + + if ( !player isOnGround() ) + continue; + + if ( !useHoldThink( player ) ) + continue; + + self notify ( "captured", player ); + } +} + + +crateOtherCaptureThink() +{ + while ( isDefined( self ) ) + { + self waittill ( "trigger", player ); + + //if ( !player isOnGround() ) + // continue; + + if ( isDefined( self.owner ) && player == self.owner ) + continue; + + useEnt = self createUseEnt(); + result = useEnt useHoldThink( player ); + + if ( isDefined( useEnt ) ) + useEnt delete(); + + if ( !result ) + continue; + + self notify ( "captured", player ); + } +} + +crateOwnerCaptureThink() +{ + while ( isDefined( self ) ) + { + self waittill ( "trigger", player ); + + //if ( !player isOnGround() ) + // continue; + + if ( isDefined( self.owner ) && player != self.owner ) + continue; + + if ( !useHoldThink( player, 500 ) ) + continue; + + self notify ( "captured", player ); + } +} + + +killstreakCrateThink( dropType ) +{ + self endon ( "death" ); + + if ( isDefined( game["strings"][self.crateType + "_hint"] ) ) + crateHint = game["strings"][self.crateType + "_hint"]; + else + crateHint = &"PLATFORM_GET_KILLSTREAK"; + + crateSetupForUse( crateHint, "all", maps\mp\killstreaks\_killstreaks::getKillstreakCrateIcon( self.crateType ) ); + + self thread crateOtherCaptureThink(); + self thread crateOwnerCaptureThink(); + + for ( ;; ) + { + self waittill ( "captured", player ); + + if ( isDefined( self.owner ) && player != self.owner ) + { + if ( !level.teamBased || player.team != self.team ) + { + if ( dropType == "airdrop" ) + { + player thread maps\mp\gametypes\_missions::genericChallenge( "hijacker_airdrop" ); + player thread hijackNotify( self, "airdrop" ); + } + else + { + player thread maps\mp\gametypes\_missions::genericChallenge( "hijacker_airdrop_mega" ); + player thread hijackNotify( self, "emergency_airdrop" ); + } + } + else + { + self.owner thread maps\mp\gametypes\_rank::giveRankXP( "killstreak_giveaway", maps\mp\killstreaks\_killstreaks::getStreakCost( self.crateType ) * 50 ); + //self.owner maps\mp\gametypes\_hud_message::playerCardSplashNotify( "giveaway_airdrop", player ); + self.owner thread maps\mp\gametypes\_hud_message::SplashNotifyDelayed( "sharepackage", maps\mp\killstreaks\_killstreaks::getStreakCost( self.crateType ) * 50 ); + } + } + + player playLocalSound( "ammo_crate_use" ); + player thread maps\mp\killstreaks\_killstreaks::giveKillstreak( self.crateType, false, false, self.owner ); + + player maps\mp\gametypes\_hud_message::killstreakSplashNotify( self.crateType, undefined, "pickup" ); + + self deleteCrate(); + } +} + + +nukeCrateThink( dropType ) +{ + self endon ( "death" ); + + crateSetupForUse( &"PLATFORM_CALL_NUKE", "nukeDrop", maps\mp\killstreaks\_killstreaks::getKillstreakCrateIcon( self.crateType ) ); + + self thread nukeCaptureThink(); + + for ( ;; ) + { + self waittill ( "captured", player ); + + player thread [[ level.killstreakFuncs[ self.crateType ] ]]( level.gtnw ); + level notify( "nukeCaptured", player ); + + if ( isDefined( level.gtnw ) && level.gtnw ) + player.capturedNuke = 1; + + player playLocalSound( "ammo_crate_use" ); + self deleteCrate(); + } +} + + +sentryCrateThink( dropType ) +{ + self endon ( "death" ); + + crateSetupForUse( game["strings"]["sentry_hint"], "all", maps\mp\killstreaks\_killstreaks::getKillstreakCrateIcon( self.crateType ) ); + + self thread crateOtherCaptureThink(); + self thread crateOwnerCaptureThink(); + + for ( ;; ) + { + self waittill ( "captured", player ); + + if ( isDefined( self.owner ) && player != self.owner ) + { + if ( !level.teamBased || player.team != self.team ) + { + if ( isSubStr(dropType, "airdrop_sentry" ) ) + player thread hijackNotify( self, "sentry" ); + else + player thread hijackNotify( self, "emergency_airdrop" ); + } + else + { + self.owner thread maps\mp\gametypes\_rank::giveRankXP( "killstreak_giveaway", maps\mp\killstreaks\_killstreaks::getStreakCost( "sentry" ) * 50 ); + self.owner maps\mp\gametypes\_hud_message::playerCardSplashNotify( "giveaway_sentry", player ); + } + } + + player playLocalSound( "ammo_crate_use" ); + player thread sentryUseTracker(); + + self deleteCrate(); + } +} + +deleteCrate() +{ + if ( isDefined( self.objIdFriendly ) ) + _objective_delete( self.objIdFriendly ); + + if ( isDefined( self.objIdEnemy ) ) + _objective_delete( self.objIdEnemy ); + + self delete(); +} + +sentryUseTracker() +{ + if ( !self maps\mp\killstreaks\_autosentry::giveSentry( "sentry_minigun" ) ) + self maps\mp\killstreaks\_killstreaks::giveKillstreak( "sentry" ); +} + + +ammoCrateThink( dropType ) +{ + self endon ( "death" ); + self.usedBy = []; + + if ( dropType == "airdrop" || !level.teamBased ) + crateSetupForUse( game["strings"]["ammo_hint"], "all", "waypoint_ammo_friendly" ); + else + crateSetupForUse( game["strings"]["ammo_hint"], "all", "waypoint_ammo_friendly" ); + + self thread crateOtherCaptureThink(); + self thread crateOwnerCaptureThink(); + + for ( ;; ) + { + self waittill ( "captured", player ); + + if ( isDefined( self.owner ) && player != self.owner ) + { + if ( !level.teamBased || player.team != self.team ) + { + if ( dropType == "airdrop" ) + player thread hijackNotify( self, "airdrop" ); + else + player thread hijackNotify( self, "emergency_airdrop" ); + } + } + + player playLocalSound( "ammo_crate_use" ); + player refillAmmo(); + self deleteCrate(); + } +} + + +hijackNotify( crate, crateType ) +{ + self notify( "hijacker", crateType, crate.owner ); +} + + +refillAmmo() +{ + weaponList = self GetWeaponsListAll(); + + if ( self _hasPerk( "specialty_tacticalinsertion" ) && self getAmmoCount( "flare_mp" ) < 1 ) + self _setPerk( "specialty_tacticalinsertion"); + + foreach ( weaponName in weaponList ) + { + if ( isSubStr( weaponName, "grenade" ) ) + { + if ( self getAmmoCount( weaponName ) >= 1 ) + continue; + } + + self giveMaxAmmo( weaponName ); + } +} + + +/********************************************************** +* Capture crate functions +***********************************************************/ +useHoldThink( player, useTime ) +{ + player playerLinkTo( self ); + player playerLinkedOffsetEnable(); + + player _disableWeapon(); + + self.curProgress = 0; + self.inUse = true; + self.useRate = 0; + + if ( isDefined( useTime ) ) + self.useTime = useTime; + else + self.useTime = 3000; + + player thread personalUseBar( self ); + + result = useHoldThinkLoop( player ); + assert ( isDefined( result ) ); + + if ( isAlive( player ) ) + { + player _enableWeapon(); + player unlink(); + } + + if ( !isDefined( self ) ) + return false; + + self.inUse = false; + self.curProgress = 0; + + return ( result ); +} + + +personalUseBar( object ) +{ + self endon( "disconnect" ); + + useBar = createPrimaryProgressBar( -25 ); + useBarText = createPrimaryProgressBarText( -25 ); + useBarText setText( &"MP_CAPTURING_CRATE" ); + + lastRate = -1; + while ( isReallyAlive( self ) && isDefined( object ) && object.inUse && !level.gameEnded ) + { + if ( lastRate != object.useRate ) + { + if( object.curProgress > object.useTime) + object.curProgress = object.useTime; + + useBar updateBar( object.curProgress / object.useTime, (1000 / object.useTime) * object.useRate ); + + if ( !object.useRate ) + { + useBar hideElem(); + useBarText hideElem(); + } + else + { + useBar showElem(); + useBarText showElem(); + } + } + lastRate = object.useRate; + wait ( 0.05 ); + } + + useBar destroyElem(); + useBarText destroyElem(); +} + +useHoldThinkLoop( player ) +{ + while( !level.gameEnded && isDefined( self ) && isReallyAlive( player ) && player useButtonPressed() && self.curProgress < self.useTime ) + { + self.curProgress += (50 * self.useRate); + + if ( isDefined(self.objectiveScaler) ) + self.useRate = 1 * self.objectiveScaler; + else + self.useRate = 1; + + if ( self.curProgress >= self.useTime ) + return ( isReallyAlive( player ) ); + + wait 0.05; + } + + return false; +} + +isAirdropMarker( weaponName ) +{ + switch ( weaponName ) + { + case "airdrop_marker_mp": + case "airdrop_mega_marker_mp": + case "airdrop_sentry_marker_mp": + return true; + default: + return false; + } +} + + +createUseEnt() +{ + useEnt = spawn( "script_origin", self.origin ); + useEnt.curProgress = 0; + useEnt.useTime = 0; + useEnt.useRate = 3000; + useEnt.inUse = false; + + useEnt thread deleteUseEnt( self ); + + return ( useEnt ); +} + + +deleteUseEnt( owner ) +{ + self endon ( "death" ); + + owner waittill ( "death" ); + + self delete(); +} + + +airdropDetonateOnStuck() +{ + self endon ( "death" ); + + self waittill( "missile_stuck" ); + + self detonate(); +} diff --git a/maps/mp/killstreaks/_killstreaks.gsc b/maps/mp/killstreaks/_killstreaks.gsc new file mode 100755 index 0000000..616a108 --- /dev/null +++ b/maps/mp/killstreaks/_killstreaks.gsc @@ -0,0 +1,670 @@ +#include maps\mp\_utility; +#include maps\mp\gametypes\_hud_util; +#include common_scripts\utility; +#include maps\mp\gametypes\_killstreaks; + +KILLSTREAK_STRING_TABLE = "mp/killstreakTable.csv"; + +init() +{ + // Load custom killstreak mod + thread streakInit(); + + // &&1 Kill Streak! + precacheString( &"MP_KILLSTREAK_N" ); + precacheString( &"MP_NUKE_ALREADY_INBOUND" ); + precacheString( &"MP_UNAVILABLE_IN_LASTSTAND" ); + precacheString( &"MP_UNAVAILABLE_WHEN_EMP" ); + precacheString( &"MP_UNAVAILABLE_USING_TURRET" ); + precacheString( &"MP_UNAVAILABLE_WHEN_INCAP" ); + precacheString( &"MP_HELI_IN_QUEUE" ); + + initKillstreakData(); + + level.killstreakFuncs = []; + level.killstreakSetupFuncs = []; + level.killstreakWeapons = []; + + level.killStreakMod = 0; + + thread maps\mp\killstreaks\_ac130::init(); + thread maps\mp\killstreaks\_remotemissile::init(); + thread maps\mp\killstreaks\_uav::init(); + thread maps\mp\killstreaks\_airstrike::init(); + thread maps\mp\killstreaks\_airdrop::init(); + thread maps\mp\killstreaks\_helicopter::init(); + thread maps\mp\killstreaks\_autosentry::init(); + thread maps\mp\killstreaks\_tank::init(); + thread maps\mp\killstreaks\_emp::init(); + thread maps\mp\killstreaks\_nuke::init(); + + level.killstreakRoundDelay = getIntProperty( "scr_game_killstreakdelay", 8 ); + + level thread onPlayerConnect(); +} + + +initKillstreakData() +{ + for ( i = 1; true; i++ ) + { + retVal = tableLookup( KILLSTREAK_STRING_TABLE, 0, i, 1 ); + if ( !isDefined( retVal ) || retVal == "" ) + break; + + streakRef = tableLookup( KILLSTREAK_STRING_TABLE, 0, i, 1 ); + assert( streakRef != "" ); + + streakUseHint = tableLookupIString( KILLSTREAK_STRING_TABLE, 0, i, 6 ); + assert( streakUseHint != &"" ); + precacheString( streakUseHint ); + + streakEarnDialog = tableLookup( KILLSTREAK_STRING_TABLE, 0, i, 8 ); + assert( streakEarnDialog != "" ); + game[ "dialog" ][ streakRef ] = streakEarnDialog; + + streakAlliesUseDialog = tableLookup( KILLSTREAK_STRING_TABLE, 0, i, 9 ); + assert( streakAlliesUseDialog != "" ); + game[ "dialog" ][ "allies_friendly_" + streakRef + "_inbound" ] = "use_" + streakAlliesUseDialog; + game[ "dialog" ][ "allies_enemy_" + streakRef + "_inbound" ] = "enemy_" + streakAlliesUseDialog; + + streakAxisUseDialog = tableLookup( KILLSTREAK_STRING_TABLE, 0, i, 10 ); + assert( streakAxisUseDialog != "" ); + game[ "dialog" ][ "axis_friendly_" + streakRef + "_inbound" ] = "use_" + streakAxisUseDialog; + game[ "dialog" ][ "axis_enemy_" + streakRef + "_inbound" ] = "enemy_" + streakAxisUseDialog; + + streakWeapon = tableLookup( KILLSTREAK_STRING_TABLE, 0, i, 12 ); + precacheItem( streakWeapon ); + + streakPoints = int( tableLookup( KILLSTREAK_STRING_TABLE, 0, i, 13 ) ); + assert( streakPoints != 0 ); + maps\mp\gametypes\_rank::registerScoreInfo( "killstreak_" + streakRef, streakPoints ); + + streakShader = tableLookup( KILLSTREAK_STRING_TABLE, 0, i, 14 ); + precacheShader( streakShader ); + + streakShader = tableLookup( KILLSTREAK_STRING_TABLE, 0, i, 15 ); + if ( streakShader != "" ) + precacheShader( streakShader ); + } +} + + +onPlayerConnect() +{ + for ( ;; ) + { + level waittill( "connected", player ); + + if( !isDefined ( player.pers[ "killstreaks" ] ) ) + player.pers[ "killstreaks" ] = []; + + player.lifeId = 0; + + if ( isDefined( player.pers["deaths"] ) ) + player.lifeId = player.pers["deaths"]; + + player VisionSetMissilecamForPlayer( game["thermal_vision"] ); + + player thread onPlayerSpawned(); + player thread onPlayerChangeKit(); + } +} + + +onPlayerSpawned() +{ + self endon( "disconnect" ); + + for ( ;; ) + { + self waittill( "spawned_player" ); + self thread killstreakUseWaiter(); + self thread waitForChangeTeam(); + + self giveOwnedKillstreakItem( true ); + } +} + +onPlayerChangeKit() +{ + self endon( "disconnect" ); + + for ( ;; ) + { + self waittill( "changed_kit" ); + self giveOwnedKillstreakItem(); + } +} + + +waitForChangeTeam() +{ + self endon ( "disconnect" ); + + self notify ( "waitForChangeTeam" ); + self endon ( "waitForChangeTeam" ); + + for ( ;; ) + { + self waittill ( "joined_team" ); + clearKillstreaks(); + } +} + + +isRideKillstreak( streakName ) +{ + switch( streakName ) + { + case "helicopter_minigun": + case "helicopter_mk19": + case "ac130": + case "predator_missile": + return true; + + default: + return false; + } +} + +isCarryKillstreak( streakName ) +{ + switch( streakName ) + { + case "sentry": + case "sentry_gl": + return true; + + default: + return false; + } +} + + +deadlyKillstreak( streakName ) +{ + switch ( streakName ) + { + case "predator_missile": + case "precision_airstrike": + case "harrier_airstrike": + //case "helicopter": + //case "helicopter_flares": + case "stealth_airstrike": + //case "helicopter_minigun": + case "ac130": + return true; + } + + return false; +} + + +killstreakUsePressed() +{ + streakName = self.pers["killstreaks"][0].streakName; + lifeId = self.pers["killstreaks"][0].lifeId; + isEarned = self.pers["killstreaks"][0].earned; + awardXp = self.pers["killstreaks"][0].awardXp; + + assert( isDefined( streakName ) ); + assert( isDefined( level.killstreakFuncs[ streakName ] ) ); + + if ( !self isOnGround() && ( isRideKillstreak( streakName ) || isCarryKillstreak( streakName ) ) ) + return ( false ); + + if ( self isUsingRemote() ) + return ( false ); + + if ( isDefined( self.selectingLocation ) ) + return ( false ); + + if ( deadlyKillstreak( streakName ) && level.killstreakRoundDelay && getGametypeNumLives() ) + { + if ( level.gracePeriod - level.inGracePeriod < level.killstreakRoundDelay ) + { + self iPrintLnBold( &"MP_UNAVAILABLE_FOR_N", (level.killstreakRoundDelay - (level.gracePeriod - level.inGracePeriod)) ); + return ( false ); + } + } + + if ( (level.teamBased && level.teamEMPed[self.team]) || (!level.teamBased && isDefined( level.empPlayer ) && level.empPlayer != self) ) + { + self iPrintLnBold( &"MP_UNAVAILABLE_WHEN_EMP" ); + return ( false ); + } + + if ( self IsUsingTurret() && ( isRideKillstreak( streakName ) || isCarryKillstreak( streakName ) ) ) + { + self iPrintLnBold( &"MP_UNAVAILABLE_USING_TURRET" ); + return ( false ); + } + + if ( isDefined( self.lastStand ) && isRideKillstreak( streakName ) ) + { + self iPrintLnBold( &"MP_UNAVILABLE_IN_LASTSTAND" ); + return ( false ); + } + + if ( !self isWeaponEnabled() ) + return ( false ); + + if ( !self [[ level.killstreakFuncs[ streakName ] ]]( lifeId ) ) + return ( false ); + + self usedKillstreak( streakName, awardXp ); + self shuffleKillStreaksFILO( streakName ); + self giveOwnedKillstreakItem(); + + return ( true ); +} + + +//this overwrites killstreak at index 0 and decrements all other killstreaks (FCLS style) +shuffleKillStreaksFILO( streakName ) +{ + self _setActionSlot( 4, "" ); + + arraySize = self.pers["killstreaks"].size; + + streakIndex = -1; + for ( i = 0; i < arraySize; i++ ) + { + if ( self.pers["killstreaks"][i].streakName != streakName ) + continue; + + streakIndex = i; + break; + } + assert( streakIndex >= 0 ); + + self.pers["killstreaks"][streakIndex] = undefined; + + for( i = streakIndex + 1; i < arraySize; i++ ) + { + if ( i == arraySize - 1 ) + { + self.pers["killstreaks"][i-1] = self.pers["killstreaks"][i]; + self.pers["killstreaks"][i] = undefined; + } + else + { + self.pers["killstreaks"][i-1] = self.pers["killstreaks"][i]; + } + } +} + + +usedKillstreak( streakName, awardXp ) +{ + self playLocalSound( "weap_c4detpack_trigger_plr" ); + + if ( awardXp ) + self thread [[ level.onXPEvent ]]( "killstreak_" + streakName ); + + self thread maps\mp\gametypes\_missions::useHardpoint( streakName ); + + awardref = maps\mp\_awards::getKillstreakAwardRef( streakName ); + if ( isDefined( awardref ) ) + self thread incPlayerStat( awardref, 1 ); + + team = self.team; + + if ( level.teamBased ) + { + thread leaderDialog( team + "_friendly_" + streakName + "_inbound", team ); + + if ( getKillstreakInformEnemy( streakName ) ) + thread leaderDialog( team + "_enemy_" + streakName + "_inbound", level.otherTeam[ team ] ); + } + else + { + self thread leaderDialogOnPlayer( team + "_friendly_" + streakName + "_inbound" ); + + if ( getKillstreakInformEnemy( streakName ) ) + { + excludeList[0] = self; + thread leaderDialog( team + "_enemy_" + streakName + "_inbound", undefined, undefined, excludeList ); + } + } +} + + +clearKillstreaks() +{ + foreach ( index, streakStruct in self.pers["killstreaks"] ) + self.pers["killstreaks"][index] = undefined; +} + + +killstreakUseWaiter() +{ + self endon( "disconnect" ); + self endon( "finish_death" ); + level endon( "game_ended" ); + + self.lastKillStreak = 0; + if ( !isDefined( self.pers["lastEarnedStreak"] ) ) + self.pers["lastEarnedStreak"] = undefined; + + self thread finishDeathWaiter(); + + for ( ;; ) + { + self waittill ( "weapon_change", newWeapon ); + + if ( !isAlive( self ) ) + continue; + + if ( !isDefined( self.pers["killstreaks"][0] ) ) + continue; + + if ( newWeapon != getKillstreakWeapon( self.pers["killstreaks"][0].streakName ) ) + continue; + + waittillframeend; + + streakName = self.pers["killstreaks"][0].streakName; + result = self killstreakUsePressed(); + + //no force switching weapon for ridable killstreaks + if ( !isRideKillstreak( streakName ) || !result ) + self switchToWeapon( self getLastWeapon() ); + + // give time to switch to the near weapon; when the weapon is none (such as during a "disableWeapon()" period + // re-enabling the weapon immediately does a "weapon_change" to the killstreak weapon we just used. In the case that + // we have two of that killstreak, it immediately uses the second one + if ( self getCurrentWeapon() == "none" ) + { + while ( self getCurrentWeapon() == "none" ) + wait ( 0.05 ); + + waittillframeend; + } + } +} + + +finishDeathWaiter() +{ + self endon ( "disconnect" ); + + self waittill ( "death" ); + wait ( 0.05 ); + self notify ( "finish_death" ); + self.pers["lastEarnedStreak"] = undefined; +} + + +checkKillstreakReward( streakCount ) +{ + self notify( "got_killstreak", streakCount ); + + maxVal = 0; + killStreaks = []; + foreach ( streakVal, streakName in self.killStreaks ) + { + killStreaks[streakName] = streakVal; + if ( streakVal > maxVal ) + maxVal = streakVal; + } + + foreach ( streakVal, streakName in self.killStreaks ) + { + actualVal = streakVal + level.killStreakMod; + + if ( actualVal > streakCount ) + break; + + if ( isDefined( self.pers["lastEarnedStreak"] ) && killStreaks[streakName] <= killStreaks[self.pers["lastEarnedStreak"]] ) + continue; + + if ( isSubStr( streakName, "-rollover" ) ) + { + continue; + /* + if ( game["defcon"] > 2 ) + { + self.pers["lastEarnedStreak"] = streakName; + continue; + } + + useStreakName = strTok( streakName, "-" )[0]; + */ + } + else + { + useStreakName = streakName; + } + + if ( self tryGiveKillstreak( useStreakName, int(max( actualVal, streakCount )) ) ) + { + self thread killstreakEarned( useStreakName ); + self.pers["lastEarnedStreak"] = streakName; + } + } +} + + +killstreakEarned( streakName ) +{ + if ( self getPlayerData( "killstreaks", 0 ) == streakName ) + { + self.firstKillstreakEarned = getTime(); + } + else if ( self getPlayerData( "killstreaks", 2 ) == streakName && isDefined( self.firstKillstreakEarned ) ) + { + if ( getTime() - self.firstKillstreakEarned < 20000 ) + self thread maps\mp\gametypes\_missions::genericChallenge( "wargasm" ); + } +} + + +rewardNotify( streakName, streakVal ) +{ + self endon( "disconnect" ); + + self maps\mp\gametypes\_hud_message::killstreakSplashNotify( streakName, streakVal ); +} + + +tryGiveKillstreak( streakName, streakVal ) +{ + level notify ( "gave_killstreak", streakName ); + + if ( !level.gameEnded ) + self thread rewardNotify( streakName, streakVal ); + + self giveKillstreak( streakName, streakVal, true ); + return true; +} + + +giveKillstreak( streakName, isEarned, awardXp, owner ) +{ + self endon ( "disconnect" ); + + weapon = getKillstreakWeapon( streakName ); + + self giveKillstreakWeapon( weapon ); + + // shuffle existing killstreaks up a notch + for( i = self.pers["killstreaks"].size; i >= 0; i-- ) + self.pers["killstreaks"][i + 1] = self.pers["killstreaks"][i]; + + self.pers["killstreaks"][0] = spawnStruct(); + self.pers["killstreaks"][0].streakName = streakName; + self.pers["killstreaks"][0].earned = isDefined( isEarned ) && isEarned; + self.pers["killstreaks"][0].awardxp = isDefined( awardXp ) && awardXp; + self.pers["killstreaks"][0].owner = owner; + if ( !self.pers["killstreaks"][0].earned ) + self.pers["killstreaks"][0].lifeId = -1; + else + self.pers["killstreaks"][0].lifeId = self.pers["deaths"]; + + // probably obsolete unless we bring back the autoshotty + if ( isdefined( level.killstreakSetupFuncs[ streakName ] ) ) + self [[ level.killstreakSetupFuncs[ streakName ] ]](); + + if ( isDefined( isEarned ) && isEarned && isDefined( awardXp ) && awardXp ) + self notify( "received_earned_killstreak" ); +} + + +giveKillstreakWeapon( weapon ) +{ + weaponList = self getWeaponsListItems(); + + foreach ( item in weaponList ) + { + if ( !isSubStr( item, "killstreak" ) ) + continue; + + if ( self getCurrentWeapon() == item ) + continue; + + self takeWeapon( item ); + } + + self _giveWeapon( weapon, 0 ); + self _setActionSlot( 4, "weapon", weapon ); +} + + +getStreakCost( streakName ) +{ + return int( tableLookup( KILLSTREAK_STRING_TABLE, 1, streakName, 4 ) ); +} + + +getKillstreakHint( streakName ) +{ + return tableLookupIString( KILLSTREAK_STRING_TABLE, 1, streakName, 6 ); +} + + +getKillstreakInformEnemy( streakName ) +{ + return int( tableLookup( KILLSTREAK_STRING_TABLE, 1, streakName, 11 ) ); +} + + +getKillstreakSound( streakName ) +{ + return tableLookup( KILLSTREAK_STRING_TABLE, 1, streakName, 7 ); +} + + +getKillstreakDialog( streakName ) +{ + return tableLookup( KILLSTREAK_STRING_TABLE, 1, streakName, 8 ); +} + + +getKillstreakWeapon( streakName ) +{ + return tableLookup( KILLSTREAK_STRING_TABLE, 1, streakName, 12 ); +} + +getKillstreakIcon( streakName ) +{ + return tableLookup( KILLSTREAK_STRING_TABLE, 1, streakName, 14 ); +} + +getKillstreakCrateIcon( streakName ) +{ + return tableLookup( KILLSTREAK_STRING_TABLE, 1, streakName, 15 ); +} + + +giveOwnedKillstreakItem( skipDialog ) +{ + if ( !isDefined( self.pers["killstreaks"][0] ) ) + return; + + streakName = self.pers["killstreaks"][0].streakName; + + weapon = getKillstreakWeapon( streakName ); + self giveKillstreakWeapon( weapon ); + + if ( !isDefined( skipDialog ) && !level.inGracePeriod ) + self leaderDialogOnPlayer( streakName, "killstreak_earned" ); +} + + +initRideKillstreak() +{ + self _disableUsability(); + result = self initRideKillstreak_internal(); + + if ( isDefined( self ) ) + self _enableUsability(); + + return result; +} + +initRideKillstreak_internal() +{ + laptopWait = self waittill_any_timeout( 1.0, "disconnect", "death", "weapon_switch_started" ); + + if ( laptopWait == "weapon_switch_started" ) + return ( "fail" ); + + if ( !isAlive( self ) ) + return "fail"; + + if ( laptopWait == "disconnect" || laptopWait == "death" ) + { + if ( laptopWait == "disconnect" ) + return ( "disconnect" ); + + if ( self.team == "spectator" ) + return "fail"; + + return ( "success" ); + } + + if ( self isEMPed() || self isNuked() ) + { + return ( "fail" ); + } + + self VisionSetNakedForPlayer( "black_bw", 0.75 ); + blackOutWait = self waittill_any_timeout( 0.80, "disconnect", "death" ); + + if ( blackOutWait != "disconnect" ) + { + self thread clearRideIntro( 1.0 ); + + if ( self.team == "spectator" ) + return "fail"; + } + + if ( !isAlive( self ) ) + return "fail"; + + if ( self isEMPed() || self isNuked() ) + return "fail"; + + if ( blackOutWait == "disconnect" ) + return ( "disconnect" ); + else + return ( "success" ); +} + + +clearRideIntro( delay ) +{ + self endon( "disconnect" ); + + if ( isDefined( delay ) ) + wait( delay ); + + //self freezeControlsWrapper( false ); + + if ( !isDefined( level.nukeVisionInProgress ) ) + self VisionSetNakedForPlayer( getDvar( "mapname" ), 0 ); +} + +