This commit is contained in:
2024-12-11 11:28:08 +01:00
commit 12ac62a956
444 changed files with 303964 additions and 0 deletions

View File

@ -0,0 +1,536 @@
#include maps\mp\_utility;
#include maps\mp\gametypes\_hud_util;
RESPAWN_DELAY = 4000;
RESPAWN_MIN_DELAY = 2000;
BATTLEBUDDY_SPAWN_STATUS_OK = 0;
BATTLEBUDDY_SPAWN_STATUS_INCOMBAT = -1;
BATTLEBUDDY_SPAWN_STATUS_BLOCKED = -2;
BATTLEBUDDY_SPAWN_STATUS_ENEMY_LOS = -3;
BATTLEBUDDY_SPAWN_STATUS_BUDDY_DEAD = -4;
init()
{
if ( level.teamBased
&& !IsDefined( level.noBuddySpawns )
)
{
if ( !IsDefined( level.battleBuddyWaitList ) )
{
level.battleBuddyWaitList = [];
}
level thread onPlayerSpawned();
level thread onPlayerConnect();
}
}
onPlayerConnect()
{
for ( ;; )
{
level waittill( "connected", player );
//this could be more efficient... check for fireTeam
player thread onBattleBuddyMenuSelection();
player thread onDisconnect();
}
}
onPlayerSpawned()
{
level endon("game_ended");
for(;;)
{
level waittill( "player_spawned", player );
if ( !IsAI( player ) )
{
// If we're coming back from a battle buddy spawn
// try to match our stance with our buddy's
if ( IsDefined( player.isSpawningOnBattleBuddy ) )
{
player.isSpawningOnBattleBuddy = undefined;
if ( IsDefined( player.battleBuddy ) && IsAlive( player.battleBuddy ) )
{
if ( player.battleBuddy GetStance() != "stand" )
{
player SetStance( "crouch" );
}
}
}
if ( player wantsBattleBuddy() )
{
if ( !(player hasBattleBuddy()) )
{
player.firstSpawn = false;
player findBattleBuddy();
}
}
else
{
player leaveBattleBuddySystem();
}
}
}
}
// onBattleBuddyMenuSelection
// wait for BB toggle from the LUI and change stuff accordingly
onBattleBuddyMenuSelection() // self == player
{
self endon( "disconnect" );
level endon("game_ended");
while ( true )
{
self waittill( "luinotifyserver", channel, value );
if ( channel == "battlebuddy_update" )
{
newBBFlag = !(self wantsBattleBuddy() );
self SetCommonPlayerData( "enableBattleBuddy", newBBFlag );
if ( newBBFlag )
{
self findBattleBuddy();
}
else
{
self leaveBattleBuddySystem();
}
}
else if ( channel == "team_select"
&& self.hasSpawned
)
{
// we need to remove this player from whatever BB situation he's in now
// but if he wants a BB on his new team, we need to preserve that
// the respawn should handle the new pairing
bbFlag = self wantsBattleBuddy();
self leaveBattleBuddySystem();
self SetCommonPlayerData( "enableBattleBuddy", bbFlag );
}
}
}
onDisconnect() // self == player
{
self waittill ( "disconnect" );
self leaveBattleBuddySystemDisconnect();
}
waitForPlayerRespawnChoice() // self == dead player
{
self updateSessionState( "spectator" );
self.forceSpectatorClient = self.battleBuddy getEntityNumber();
self forceThirdPersonWhenFollowing();
self SetClientOmnvar( "cam_scene_name", "over_shoulder" );
self SetClientOmnvar( "cam_scene_lead", self.battleBuddy getEntityNumber() );
self waitForBuddySpawnTimer();
}
watchForRandomSpawnButton()
{
self endon( "disconnect" );
self endon( "abort_battlebuddy_spawn" );
self endon ( "teamSpawnPressed" );
level endon("game_ended");
self SetClientOmnvar( "ui_battlebuddy_showButtonPrompt", true );
self NotifyOnPlayerCommand( "respawn_random", "+usereload" );
self NotifyOnPlayerCommand( "respawn_random", "+activate" );
// give a little space for the mashers to see the menu
wait (0.5);
self waittill( "respawn_random" );
self SetClientOmnvar( "ui_battlebuddy_timer_ms", 0 );
self SetClientOmnvar( "ui_battlebuddy_showButtonPrompt", false );
self setupForRandomSpawn();
}
setupForRandomSpawn() // self == player
{
self clearBuddyMessage();
self.isSpawningOnBattleBuddy = undefined;
self notify( "randomSpawnPressed" );
self cleanupBuddySpawn();
}
/*
watchForBuddyDeath()
{
self endon( "disconnect" );
self endon( "abort_battlebuddy_spawn" );
self endon( "success_battlebuddy_spawn" );
while ( isReallyAlive( self.battleBuddy ) )
{
wait ( 0.5 );
}
self notify( "abort_battlebuddy_spawn" );
}
*/
waitForBuddySpawnTimer()
{
self endon( "randomSpawnPressed" );
level endon("game_ended");
self.isSpawningOnBattleBuddy = undefined;
self thread watchForRandomSpawnButton();
if ( IsDefined(self.battleBuddyRespawnTimeStamp) )
{
timeToWait = RESPAWN_DELAY - (GetTime() - self.battleBuddyRespawnTimeStamp);
if (timeToWait < RESPAWN_MIN_DELAY)
{
timeToWait = RESPAWN_MIN_DELAY;
}
}
else
{
timeToWait = RESPAWN_DELAY;
}
result = self checkBuddySpawn();
if ( result.status == BATTLEBUDDY_SPAWN_STATUS_OK )
{
self.battleBuddy SetClientOmnvar( "ui_battlebuddy_status", "incoming" );
}
else if ( result.status == BATTLEBUDDY_SPAWN_STATUS_INCOMBAT
|| result.status == BATTLEBUDDY_SPAWN_STATUS_ENEMY_LOS )
{
self.battleBuddy SetClientOmnvar( "ui_battlebuddy_status", "err_combat" );
}
else
{
self.battleBuddy SetClientOmnvar( "ui_battlebuddy_status", "err_pos" );
}
self updateTimer( timeToWait );
result = self checkBuddySpawn();
while ( result.status != BATTLEBUDDY_SPAWN_STATUS_OK )
{
if ( result.status == BATTLEBUDDY_SPAWN_STATUS_INCOMBAT
|| result.status == BATTLEBUDDY_SPAWN_STATUS_ENEMY_LOS )
{
self SetClientOmnvar( "ui_battlebuddy_status", "wait_combat" );
self.battleBuddy SetClientOmnvar( "ui_battlebuddy_status", "err_combat" );
}
else if ( result.status == BATTLEBUDDY_SPAWN_STATUS_BLOCKED )
{
self SetClientOmnvar( "ui_battlebuddy_status", "wait_pos" );
self.battleBuddy SetClientOmnvar( "ui_battlebuddy_status", "err_pos" );
}
else if ( result.status == BATTLEBUDDY_SPAWN_STATUS_BUDDY_DEAD )
{
self cleanupBuddySpawn();
return;
}
// not sure how expensive the safety checks are
// but 1s delays can be kind of unresponsive
wait ( 0.5 );
result = self checkBuddySpawn();
}
self.isSpawningOnBattleBuddy = true;
self thread displayBuddySpawnSuccessful();
self playLocalSound( "copycat_steal_class" );
self notify ( "teamSpawnPressed" );
}
clearBuddyMessage()
{
self SetClientOmnvar( "ui_battlebuddy_status", "none" );
self SetClientOmnvar( "ui_battlebuddy_showButtonPrompt", false );
if ( IsDefined( self.battleBuddy ) )
{
self.battleBuddy SetClientOmnvar( "ui_battlebuddy_status", "none" );
}
}
displayBuddyStatusMessage( messageID ) // self == player who sees message
{
self setLowerMessage( "waiting_info", messageID, undefined, undefined, undefined, undefined, undefined, undefined, true );
}
displayBuddySpawnSuccessful()
{
self clearBuddyMessage();
if ( IsDefined( self.battleBuddy ) )
{
self.battleBuddy SetClientOmnvar( "ui_battlebuddy_status", "on_you" );
wait (1.5);
self.battleBuddy SetClientOmnvar( "ui_battlebuddy_status", "none" );
}
}
checkBuddySpawn() // self == player
{
result = SpawnStruct();
if ( !IsDefined( self.battleBuddy ) || !IsAlive( self.battleBuddy ) )
{
result.status = BATTLEBUDDY_SPAWN_STATUS_BUDDY_DEAD;
return result;
}
if( maps\mp\gametypes\_spawnscoring::isPlayerInCombat( self.battleBuddy, true ) )
{
result.status = BATTLEBUDDY_SPAWN_STATUS_INCOMBAT;
}
else
{
spawnLocation = maps\mp\gametypes\_spawnscoring::findSpawnLocationNearPlayer( self.battleBuddy );
if( IsDefined(spawnLocation) )
{
trace = SpawnStruct();
trace.maxTraceCount = 18;
trace.currentTraceCount = 0;
if( !maps\mp\gametypes\_spawnscoring::isSafeToSpawnOn( self.battleBuddy, spawnLocation, trace) )
{
result.status = BATTLEBUDDY_SPAWN_STATUS_ENEMY_LOS;
}
else
{
// we have a valid location, let's go!
result.status = BATTLEBUDDY_SPAWN_STATUS_OK;
result.origin = spawnLocation;
dirToBuddy = self.battleBuddy.origin - spawnLocation;
result.angles = (0, self.battleBuddy.angles[1], 0);
}
}
else
{
result.status = BATTLEBUDDY_SPAWN_STATUS_BLOCKED;
}
}
return result;
}
cleanupBuddySpawn()
{
self thread maps\mp\gametypes\_spectating::setSpectatePermissions();
self.forceSpectatorClient = -1;
self updateSessionState( "dead" );
self disableForceThirdPersonWhenFollowing();
// this should get cleaned up in the respawn
// self.isSpawningOnBattleBuddy = undefined;
self SetClientOmnvar( "cam_scene_name", "unknown" );
self clearBuddyMessage();
self notify("abort_battlebuddy_spawn");
}
updateTimer( timeToWait )
{
self endon( "disconnect" );
self endon( "abort_battlebuddy_spawn" );
self endon ( "teamSpawnPressed" );
timeInSeconds = timeToWait * 0.001;
self SetClientOmnvar( "ui_battlebuddy_timer_ms", timeToWait + GetTime() );
wait ( timeInSeconds );
self SetClientOmnvar( "ui_battlebuddy_timer_ms", 0 );
}
/* --------------------------------------------------------------------------
* Manager functions
* Used to pair up players as they spawn
*/
wantsBattleBuddy() // self == player
{
return self GetCommonPlayerData( "enableBattleBuddy" );
}
hasBattleBuddy() // self == player
{
return IsDefined( self.battleBuddy );
}
needsBattleBuddy() // self == player
{
return (self wantsBattleBuddy()
&& ! self hasBattleBuddy() );
}
isValidBattleBuddy( otherPlayer ) // self == player
{
return ( self != otherPlayer
&& self.team == otherPlayer.team
&& otherPlayer needsBattleBuddy()
);
}
canBuddySpawn() // self == player
{
return ( self hasBattleBuddy() && isReallyAlive( self.battleBuddy ) );
}
pairBattleBuddy( otherPlayer ) // self == player
{
removeFromBattleBuddyWaitList( otherPlayer );
self.battleBuddy = otherPlayer;
otherPlayer.battleBuddy = self;
self SetClientOmnvar( "ui_battlebuddy_idx", otherPlayer GetEntityNumber() );
otherPlayer SetClientOmnvar( "ui_battlebuddy_idx", self GetEntityNumber() );
}
getWaitingBattleBuddy() // self == player
{
return ( level.battleBuddyWaitList[ self.team ] );
}
// there should only be one player on the wait list at any time
addToBattleBuddyWaitList( player )
{
if ( !IsDefined( level.battleBuddyWaitList[ player.team ] ) )
{
level.battleBuddyWaitList[ player.team ] = player;
}
else if ( level.battleBuddyWaitList[ player.team ] != player )
{
Print( "There is already a player: " + (level.battleBuddyWaitList[ player.team ] GetEntityNumber()) + " but trying to add: " + (player GetEntityNumber()));
}
}
removeFromBattleBuddyWaitList( player )
{
if ( IsDefined( player.team )
&& IsDefined( level.battleBuddyWaitList[ player.team ] )
&& player == level.battleBuddyWaitList[ player.team ] )
{
level.battleBuddyWaitList[ player.team ] = undefined;
}
}
findBattleBuddy() // self == player
{
// look for a buddy inside the private party
if ( level.onlineGame )
{
self.fireTeamMembers = self GetFireteamMembers();;
if ( self.fireTeamMembers.size >= 1 )
{
foreach ( otherPlayer in self.fireTeamMembers )
{
if ( self isValidBattleBuddy( otherPlayer ) )
{
self pairBattleBuddy( otherPlayer );
}
}
}
}
// we couldn't find a match among the fireteam members
// so find one from the overflow
if ( !(self hasBattleBuddy()) )
{
// guarantee that the player is on the same team and wants a BB
// need to make sure we update this list if the player switches teams or untoggles his BB status
otherPlayer = self getWaitingBattleBuddy();
if ( IsDefined( otherPlayer ) && self isValidBattleBuddy( otherPlayer ) )
{
self pairBattleBuddy( otherPlayer );
}
else
{
addToBattleBuddyWaitList( self );
self SetClientOmnvar( "ui_battlebuddy_idx", -1 );
}
}
}
clearBattleBuddy()
{
if ( !IsAlive( self ) )
{
self setupForRandomSpawn();
}
self SetClientOmnvar( "ui_battlebuddy_idx", -1 );
self.battleBuddy = undefined;
}
leaveBattleBuddySystem() // self == player
{
if ( self hasBattleBuddy() )
{
otherPlayer = self.battleBuddy;
self clearBattleBuddy();
self SetCommonPlayerData( "enableBattleBuddy", false );
otherPlayer clearBattleBuddy();
otherPlayer findBattleBuddy();
}
else
{
// must make sure that the teams are correct in the team_select case
removeFromBattleBuddyWaitList( self );
// !!! hack. Can't call SetClientDvar on removed entity
// according to UAV code, birth_time is one way to id removed entities
self SetClientOmnvar( "ui_battlebuddy_idx", -1 );
}
}
// we need a specialized function, unfortunately, because disconnected players don't have all the variables anymore
// and we can't cleanly distinguished a removed entity and a newly spawned player
// we *could* have a player wait on his buddy's disconnect, but it won't handle the case
leaveBattleBuddySystemDisconnect() // self == player
{
if ( self hasBattleBuddy() )
{
otherPlayer = self.battleBuddy;
otherPlayer clearBattleBuddy();
otherPlayer findBattleBuddy();
otherPlayer clearBuddyMessage();
}
else
{
// ensure that this guy is not being tracked any more
foreach ( teamName, waitingPlayer in level.battleBuddyWaitList )
{
if ( waitingPlayer == self)
{
level.battleBuddyWaitList[ teamName ] = undefined;
break;
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,217 @@
// Callback Setup
// This script provides the hooks from code into script for the gametype callback functions.
//=============================================================================
// Code Callback functions
/*================
Called by code after the level's main script function has run.
================*/
CodeCallback_StartGameType()
{
if( getDvar( "r_reflectionProbeGenerate" ) == "1" )
level waittill( "eternity" );
// If the gametype has not beed started, run the startup
if(!isDefined(level.gametypestarted) || !level.gametypestarted)
{
[[level.callbackStartGameType]]();
level.gametypestarted = true; // so we know that the gametype has been started up
}
}
/*================
Called when a player begins connecting to the server.
Called again for every map change or tournement restart.
Return undefined if the client should be allowed, otherwise return
a string with the reason for denial.
Otherwise, the client will be sent the current gamestate
and will eventually get to ClientBegin.
firstTime will be qtrue the very first time a client connects
to the server machine, but qfalse on map changes and tournement
restarts.
================*/
CodeCallback_PlayerConnect()
{
if( getDvar( "r_reflectionProbeGenerate" ) == "1" )
level waittill( "eternity" );
self endon("disconnect");
[[level.callbackPlayerConnect]]();
}
/*================
Called when a player drops from the server.
Will not be called between levels.
self is the player that is disconnecting.
================*/
CodeCallback_PlayerDisconnect(reason)
{
self notify("disconnect");
[[level.callbackPlayerDisconnect]](reason);
}
/*================
Called when a player has taken damage.
self is the player that took damage.
================*/
CodeCallback_PlayerDamage(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset)
{
self endon("disconnect");
sWeapon = maps\mp\_utility::weaponMap( sWeapon );
[[level.callbackPlayerDamage]](eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset);
}
/*================
Called when a player has been killed.
self is the player that was killed.
================*/
CodeCallback_PlayerKilled(eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, timeOffset, deathAnimDuration)
{
self endon("disconnect");
sWeapon = maps\mp\_utility::weaponMap( sWeapon );
[[level.callbackPlayerKilled]](eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, timeOffset, deathAnimDuration);
}
/*================
Called when a vehicle has taken damage.
self is the vehicle that took damage.
================*/
CodeCallback_VehicleDamage( inflictor, attacker, damage, dFlags, meansOfDeath, sWeapon, point, dir, hitLoc, timeOffset, modelIndex, partName )
{
sWeapon = maps\mp\_utility::weaponMap( sWeapon );
if ( isDefined( self.damageCallback ) )
self [[self.damageCallback]]( inflictor, attacker, damage, dFlags, meansOfDeath, sWeapon, point, dir, hitLoc, timeOffset, modelIndex, partName );
else
self Vehicle_FinishDamage( inflictor, attacker, damage, dFlags, meansOfDeath, sWeapon, point, dir, hitLoc, timeOffset, modelIndex, partName );
}
/*================
Called when code is forcibly ending the game.
e.g. we suck as host.
================*/
CodeCallback_CodeEndGame()
{
self endon("disconnect");
[[level.callbackCodeEndGame]]();
}
/*================
Called when a player has been killed, but has last stand perk.
self is the player that was killed.
================*/
CodeCallback_PlayerLastStand(eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, timeOffset, deathAnimDuration )
{
self endon("disconnect");
sWeapon = maps\mp\_utility::weaponMap( sWeapon );
[[level.callbackPlayerLastStand]](eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, timeOffset, deathAnimDuration );
}
/*================
Called when a player reconnects to the server
following a host migration.
================*/
CodeCallback_PlayerMigrated()
{
self endon("disconnect");
[[level.callbackPlayerMigrated]]();
}
/*================
Called once when a host migration has occured.
================*/
CodeCallback_HostMigration()
{
[[level.callbackHostMigration]]();
}
//=============================================================================
// Damage flags used in the playerDamage callback
SetupDamageFlags()
{
// code-defined:
level.iDFLAGS_RADIUS = 1; // damage was indirect
level.iDFLAGS_NO_ARMOR = 2; // armor does not protect from this damage
level.iDFLAGS_NO_KNOCKBACK = 4; // do not affect velocity, just view angles
level.iDFLAGS_PENETRATION = 8; // damage occurred after one or more penetrations
level.iDFLAGS_STUN = 16; // non-lethal
level.iDFLAGS_SHIELD_EXPLOSIVE_IMPACT = 32; // missile impacted on the front of the victim's shield
level.iDFLAGS_SHIELD_EXPLOSIVE_IMPACT_HUGE = 64; // ...and was from a projectile with "Big Explosion" checked on.
level.iDFLAGS_SHIELD_EXPLOSIVE_SPLASH = 128; // explosive splash, somewhat deflected by the victim's shield
// script-defined:
level.iDFLAGS_NO_TEAM_PROTECTION = 256;
level.iDFLAGS_NO_PROTECTION = 512;
level.iDFLAGS_PASSTHRU = 1024;
}
/*================
Setup any misc callbacks stuff like defines and default callbacks
================*/
SetupCallbacks()
{
SetDefaultCallbacks();
SetupDamageFlags();
}
/*================
Called from the gametype script to store off the default callback functions.
This allows the callbacks to be overridden by level script, but not lost.
================*/
SetDefaultCallbacks()
{
level.callbackStartGameType = maps\mp\gametypes\_gamelogic::Callback_StartGameType;
level.callbackPlayerConnect = maps\mp\gametypes\_playerlogic::Callback_PlayerConnect;
level.callbackPlayerDisconnect = maps\mp\gametypes\_playerlogic::Callback_PlayerDisconnect;
level.callbackPlayerDamage = maps\mp\gametypes\_damage::Callback_PlayerDamage;
level.callbackPlayerKilled = maps\mp\gametypes\_damage::Callback_PlayerKilled;
level.callbackCodeEndGame = maps\mp\gametypes\_gamelogic::Callback_CodeEndGame;
level.callbackPlayerLastStand = maps\mp\gametypes\_damage::Callback_PlayerLastStand;
level.callbackPlayerMigrated = maps\mp\gametypes\_playerlogic::Callback_PlayerMigrated;
level.callbackHostMigration = maps\mp\gametypes\_hostmigration::Callback_HostMigration;
}
/*================
Called when a gametype is not supported.
================*/
AbortLevel()
{
println("Aborting level - gametype is not supported");
level.callbackStartGameType = ::callbackVoid;
level.callbackPlayerConnect = ::callbackVoid;
level.callbackPlayerDisconnect = ::callbackVoid;
level.callbackPlayerDamage = ::callbackVoid;
level.callbackPlayerKilled = ::callbackVoid;
level.callbackCodeEndGame = ::callbackVoid;
level.callbackPlayerLastStand = ::callbackVoid;
level.callbackPlayerMigrated = ::callbackVoid;
level.callbackHostMigration = ::callbackVoid;
setdvar("g_gametype", "dm");
exitLevel(false);
}
/*================
================*/
callbackVoid()
{
}

2615
maps/mp/gametypes/_class.gsc Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1 @@
/* remove me */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,88 @@
init()
{
}
updateDamageFeedback( typeHit )
{
noSound = false;
if( isdefined( level.damageFeedbackNoSound ) && level.damageFeedbackNoSound )
noSound = true;
if( !IsPlayer( self ) )
return;
switch( typeHit )
{
case "thermobaric_debuff":
case "hitblastshield":
case "hitlightarmor":
case "hitjuggernaut":
case "hitmorehealth":
case "hitmotionsensor":
case "hitcritical":
case "hitalienarmor":
case "hitaliensoft":
case "hitkill":
case "hitkilljugg":
case "hitdeadeyekill":
case "hitkillblast":
case "thermodebuff_kill":
if ( !noSound )
self PlayLocalSound( "MP_hit_alert" );
self SetClientOmnvar( "damage_feedback", typeHit );
break;
case "none":
break;
case "meleestun":
if ( !Isdefined( self.meleestun ) )
{
if ( !noSound )
self PlayLocalSound( "crate_impact" );
self.meleestun = true;
}
self SetClientOmnvar( "damage_feedback", "hitcritical" );
wait 0.2;
self.meleestun = undefined;
break;
default:
if ( !noSound )
self PlayLocalSound( "MP_hit_alert" );
self SetClientOmnvar( "damage_feedback", "standard" );
break;
}
}
hudIconType( typeHit )
{
noSound = false;
if( isdefined( level.damageFeedbackNoSound ) && level.damageFeedbackNoSound )
noSound = true;
if( !IsPlayer( self ) )
return;
switch( typeHit )
{
case "scavenger":
case "throwingknife":
if ( !noSound )
self PlayLocalSound( "scavenger_pack_pickup" );
if( !level.hardcoreMode )
self SetClientOmnvar( "damage_feedback_other", typeHit );
break;
case "boxofguns":
if ( !noSound )
self PlayLocalSound( "mp_box_guns_ammo" );
if( !level.hardcoreMode )
self SetClientOmnvar( "damage_feedback_other", typeHit );
break;
case "oracle":
if ( !noSound )
self PlayLocalSound( "oracle_radar_pulse_plr" );
if( !level.hardcoreMode )
self SetClientOmnvar( "damage_feedback_other", typeHit );
break;
}
}

View File

@ -0,0 +1,81 @@
#include maps\mp\_utility;
init()
{
if (!level.teambased)
return;
precacheShader("headicon_dead");
level thread onPlayerConnect();
}
onPlayerConnect()
{
for(;;)
{
level waittill("connected", player);
player.selfDeathIcons = []; // icons that other people see which point to this player when he's dead
}
}
updateDeathIconsEnabled()
{
//if (!self.enableDeathIcons)
// self removeOtherDeathIcons();
}
addDeathIcon( entity, dyingplayer, team, timeout )
{
if ( !level.teambased )
return;
iconOrg = entity.origin;
dyingplayer endon("spawned_player");
dyingplayer endon("disconnect");
wait .05;
WaitTillSlowProcessAllowed();
assert(team == "allies" || team == "axis" || IsSubStr( team, "team_" ));
if ( getDvar( "ui_hud_showdeathicons" ) == "0" )
return;
if ( level.hardcoreMode )
return;
if ( isdefined( self.lastDeathIcon ) )
self.lastDeathIcon destroy();
newdeathicon = newTeamHudElem( team );
newdeathicon.x = iconOrg[0];
newdeathicon.y = iconOrg[1];
newdeathicon.z = iconOrg[2] + 54;
newdeathicon.alpha = .61;
newdeathicon.archived = false;
newdeathicon.showinkillcam = false;
if ( level.splitscreen )
newdeathicon setShader("headicon_dead", 14, 14);
else
newdeathicon setShader("headicon_dead", 7, 7);
newdeathicon setwaypoint( false );
self.lastDeathIcon = newdeathicon;
newdeathicon thread destroySlowly ( timeout );
}
destroySlowly( timeout )
{
self endon("death");
wait timeout;
self fadeOverTime(1.0);
self.alpha = 0;
wait 1.0;
self destroy();
}

3556
maps/mp/gametypes/_dev.gsc Normal file

File diff suppressed because it is too large Load Diff

872
maps/mp/gametypes/_door.gsc Normal file
View File

@ -0,0 +1,872 @@
#include maps\mp\_utility;
#include common_scripts\utility;
// DOOR STATS
DEFAULT_DOOR_MOVE_TIME_SEC = 3.0;
DEFAULT_DOOR_PAUSE_TIME_SEC = 1.0;
// WHEEL "DOOR" STATS
DEFAULT_WHEEL_DIAMETER = 30.0;
// DOOR STATES
STATE_DOOR_CLOSED = 0;
STATE_DOOR_CLOSING = 1;
STATE_DOOR_OPEN = 2;
STATE_DOOR_OPENING = 3;
STATE_DOOR_PAUSED = 4;
// ENT SPAWNFLAGS
SPAWNFLAG_DYNAMIC_PATH = 1;
SPAWNFLAG_AI_SIGHT_LINE = 2;
// DOOR SYSTEM DOCUMENTATION
//
// - door button trigger ent
// - The button trigger targetname is passed to the door system in door_system_init( buttonName )
// - Break this trigger into multiple pieces to support multiple doors.
// - target all pieces of the door from this trigger by giving them the corresponding targetname
// - set script_index to a time in MILLISECONDS on a button if you want to override the default move time for the corresponding doors
// - add the script_parameters open_interrupt=true KVP to the button trigger to allow the doors to be interrupted while opening as well as while closing
// - targeted script_origin
// - assumed to be the sound entity. If no sound entity is given one of the doors is used as the sound origin
// - targeted entity with classname that has substring "trigger"
// - this is assumed to be the blocking trigger for the door setup. When this trigger goes off the door will stop / change state
// - targeted script_models and script_brushmodels
// - targeted entity with script_noteworthy substring "light"
// - script_noteworthy "light_on" entities will be shown when the door is useable
// - script_noteworthy "light_off" entities will be shown when the door is unuseable
// - all other targetted script_model and script_brushmodel are assumed to be the door entities
// - door entities assume their starting position to be their closed state for lighting reasons
// - door entities should target a script_struct placed at the doors open position
// - door entites with script_noteworthy "counterclockwise_wheel" or "clockwise_wheel" will rotate as well as translate
//
// DOOR SYSTEM FUTURE FEATURE FUN
// - doors need to support entites being in the way
// - things like killstreaks, equipment, etc. Potentially this is the trigger setup?
// - have the button triggers target the button model(s)
// - this script_model or script_brushmodel has animations on it which can be played according to state
// - have door buttons have a default state according to gametypes
// - this way a door ent can start open in DOM or start close in S&R
// - game modes should also have a way to set the door state through a function call
// - this function call could call a change state on the door and pop the doors into position
// - have doors support movement through animation
// - script would need to make animations pause mid movement and ease in and out of that pause state
// - collision would have to be linked to the animations to keep players from running through the door
// - support multiple wheel sizes
/*
=============
///ScriptDocBegin
"Name: door_system_init( <triggerName> )"
"Summary: Initialize function for the door finite state machine. Takes a trigger to be used to activate the door. This trigger can be broken into multiple pieces to support multiple buttons. See above documentation for door setup directions."
"Module: Utility"
"MandatoryArg: <triggerName>: The targetname of the door triggers in the level. To support multiple buttons for one door simply create a trigger made of multiple pieces, one piece for each button."
"Example: level thread door_system_init( "zebraDoorButton" )"
"SPMP: multiplayer"
///ScriptDocEnd
=============
*/
door_system_init( triggerName )
{
buttons = GetEntArray( triggerName, "targetname" );
foreach ( button in buttons )
{
if ( IsDefined( button.script_parameters ) )
{
button button_parse_parameters( button.script_parameters );
}
button door_setup();
}
foreach ( button in buttons )
{
button thread door_think();
}
}
door_setup()
{
button = self;
// Setup door references
AssertEx( IsDefined( button.target ), "door_setup() found switch without at least one door target." );
button.doors = [];
if ( IsDefined( button.script_index ) )
{
button.doorMoveTime = max( 0.1, Float( button.script_index ) / 1000 );
}
targetEnts = GetEntArray( button.target, "targetname" );
foreach ( ent in targetEnts )
{
if ( IsSubStr( ent.classname, "trigger" ) )
{
if ( !IsDefined( button.trigBlock ) )
{
button.trigBlock = [];
}
if ( IsDefined( ent.script_parameters ) )
{
ent trigger_parse_parameters( ent.script_parameters );
}
if ( IsDefined( ent.script_linkTo ) )
{
linked_door = GetEnt( ent.script_linkTo, "script_linkname" );
ent EnableLinkTo();
ent LinkTo( linked_door );
}
button.trigBlock[ button.trigBlock.size ] = ent;
}
else if ( ent.classname == "script_brushmodel" || ent.classname == "script_model" )
{
if ( IsDefined( ent.script_noteworthy ) && IsSubStr( ent.script_noteworthy, "light" ) )
{
if ( IsSubStr( ent.script_noteworthy, "light_on" ) )
{
if ( !IsDefined( button.lights_on ) )
{
button.lights_on = [];
}
ent Hide();
button.lights_on[ button.lights_on.size ] = ent;
}
else if ( IsSubStr( ent.script_noteworthy, "light_off" ) )
{
if ( !IsDefined( button.lights_off ) )
{
button.lights_off = [];
}
ent Hide();
button.lights_off[ button.lights_off.size ] = ent;
}
else
{
AssertMsg( "Invalid light ent with script_noteworthy of: " + ent.script_noteworthy );
}
}
else if ( ent.spawnflags & SPAWNFLAG_AI_SIGHT_LINE )
{
if ( !IsDefined( button.ai_sight_brushes ) )
{
button.ai_sight_brushes = [];
}
ent NotSolid();
ent Hide();
ent SetAISightLineVisible( false );
button.ai_sight_brushes[ button.ai_sight_brushes.size ] = ent;
}
else
{
button.doors[ button.doors.size ] = ent;
}
}
else if ( ent.classname == "script_origin" )
{
button.entSound = ent;
}
}
if ( !IsDefined( button.entSound ) && button.doors.size )
{
button.entSound = SortByDistance( button.doors, button.origin )[ 0 ];
}
foreach ( door in button.doors )
{
AssertEx( IsDefined( door.target ), "door_setup() found door without a close position struct target." );
door.posClosed = door.origin;
door.posOpen = getstruct( door.target, "targetname" ).origin;
door.distMove = Distance( door.posOpen, door.posClosed );
door.origin = door.posOpen;
door.no_moving_unresolved_collisions = false;
if( IsDefined( door.script_parameters ) )
{
door door_parse_parameters( door.script_parameters );
}
}
}
door_think()
{
button = self;
button door_state_change( STATE_DOOR_OPEN, true );
while ( 1 )
{
button.stateDone = undefined;
button.stateInterrupted = undefined;
button waittill_any( "door_state_done", "door_state_interrupted" );
// Prefer state done over state interrupted
if ( IsDefined( button.stateDone ) && button.stateDone )
{
stateNext = button door_state_next( button.stateCurr );
button door_state_change( stateNext, false );
}
else if ( IsDefined( button.stateInterrupted ) && button.stateInterrupted )
{
button door_state_change( STATE_DOOR_PAUSED, false );
}
else
{
AssertMsg( "state finished without being flagged as done or interrupted." );
}
}
}
door_state_next( state )
{
button = self;
stateNext = undefined;
if ( state == STATE_DOOR_CLOSED )
{
stateNext = STATE_DOOR_OPENING;
}
else if ( state == STATE_DOOR_OPEN )
{
stateNext = STATE_DOOR_CLOSING;
}
else if ( state == STATE_DOOR_CLOSING )
{
stateNext = STATE_DOOR_CLOSED;
}
else if ( state == STATE_DOOR_OPENING )
{
stateNext = STATE_DOOR_OPEN;
}
else if ( state == STATE_DOOR_PAUSED )
{
AssertEx( IsDefined( button.statePrev ), "door_state_next() was passed STATE_DOOR_PAUSED without a previous state to go to." );
stateNext = button.statePrev;
}
else
{
AssertMsg( "Unhandled state value of: " + state );
}
return stateNext;
}
door_state_update( noSound )
{
button = self;
button endon( "door_state_interrupted" );
button.stateDone = undefined;
if ( button.stateCurr == STATE_DOOR_CLOSED || button.stateCurr == STATE_DOOR_OPEN )
{
if ( !noSound )
{
foreach ( door in button.doors )
{
if( IsDefined( door.stop_sound ) )
{
door StopLoopSound();
door PlaySoundOnMovingEnt( door.stop_sound );
}
}
}
if ( IsDefined( button.lights_on ) )
{
foreach ( light in button.lights_on )
{
light Show();
}
}
foreach ( door in button.doors )
{
if ( button.stateCurr == STATE_DOOR_CLOSED )
{
if ( IsDefined( button.ai_sight_brushes ) )
{
foreach ( ai_sight_brush in button.ai_sight_brushes )
{
ai_sight_brush Show();
ai_sight_brush SetAISightLineVisible( true );
}
}
if ( door.spawnflags & SPAWNFLAG_DYNAMIC_PATH )
{
door DisconnectPaths();
}
}
else // button.stateCurr == STATE_DOOR_OPEN
{
if ( IsDefined( button.ai_sight_brushes ) )
{
foreach ( ai_sight_brush in button.ai_sight_brushes )
{
ai_sight_brush Hide();
ai_sight_brush SetAISightLineVisible( false );
}
}
if ( door.spawnflags & SPAWNFLAG_DYNAMIC_PATH )
{
if( IsDefined( door.script_noteworthy ) && ( door.script_noteworthy == "always_disconnect" ) )
{
door DisconnectPaths();
}
else
{
door ConnectPaths();
}
}
}
if ( IsDefined( door.script_noteworthy ) )
{
if ( ( door.script_noteworthy == "clockwise_wheel" ) || ( door.script_noteworthy == "counterclockwise_wheel" ) )
{
door RotateVelocity( ( 0, 0, 0 ), 0.1 );
}
}
if(door.no_moving_unresolved_collisions)
{
door.unresolved_collision_func = undefined;
}
}
//"Press and hold [{+activate}] to open door"
//"Press and hold [{+activate}] to close door"
hintString = ter_op( button.stateCurr == STATE_DOOR_CLOSED, &"MP_DOOR_USE_OPEN", &"MP_DOOR_USE_CLOSE" );
button SetHintString( hintString );
button MakeUsable();
button waittill( "trigger" );
if( IsDefined( button.button_sound ) )
{
button PlaySound( button.button_sound );
}
}
else if ( button.stateCurr == STATE_DOOR_CLOSING || button.stateCurr == STATE_DOOR_OPENING )
{
if ( IsDefined( button.lights_off ) )
{
foreach ( light in button.lights_off )
{
light Show();
}
}
button MakeUnusable();
if ( button.stateCurr == STATE_DOOR_CLOSING )
{
button thread door_state_on_interrupt();
foreach ( door in button.doors )
{
if ( IsDefined( door.script_noteworthy ) )
{
timeMove = ter_op( IsDefined( button.doorMoveTime ), button.doorMoveTime, DEFAULT_DOOR_MOVE_TIME_SEC );
posGoal = ter_op( button.stateCurr == STATE_DOOR_CLOSING, door.posClosed, door.posOpen );
distRemaining = Distance( door.origin, posGoal );
time = max( 0.1, distRemaining / door.distMove * timeMove );
timeEase = max( time * 0.25, 0.05 );
angularDistance = 360 * distRemaining / ( 3.14 * DEFAULT_WHEEL_DIAMETER );
if ( door.script_noteworthy == "clockwise_wheel" )
{
door RotateVelocity( ( 0, 0, -1 * angularDistance / time ), time, timeEase, timeEase );
}
else if ( door.script_noteworthy == "counterclockwise_wheel" )
{
door RotateVelocity( ( 0, 0, angularDistance / time ), time, timeEase, timeEase );
}
}
}
}
else if ( button.stateCurr == STATE_DOOR_OPENING )
{
if ( IsDefined( button.open_interrupt ) && ( button.open_interrupt ) )
{
button thread door_state_on_interrupt();
}
foreach ( door in button.doors )
{
if ( IsDefined( door.script_noteworthy ) )
{
timeMove = ter_op( IsDefined( button.doorMoveTime ), button.doorMoveTime, DEFAULT_DOOR_MOVE_TIME_SEC );
posGoal = ter_op( button.stateCurr == STATE_DOOR_CLOSING, door.posClosed, door.posOpen );
distRemaining = Distance( door.origin, posGoal );
time = max( 0.1, distRemaining / door.distMove * timeMove );
timeEase = max( time * 0.25, 0.05 );
angularDistance = 360 * distRemaining / ( 3.14 * DEFAULT_WHEEL_DIAMETER );
if ( door.script_noteworthy == "clockwise_wheel" )
{
door RotateVelocity( ( 0, 0, angularDistance / time ), time, timeEase, timeEase );
}
else if ( door.script_noteworthy == "counterclockwise_wheel" )
{
door RotateVelocity( ( 0, 0, -1 * angularDistance / time ), time, timeEase, timeEase );
}
}
}
}
// Give the interrupt thread time to stop the door before a move starts
wait 0.1;
button childthread door_state_update_sound( "garage_door_start", "garage_door_loop" );
timeMove = ter_op( IsDefined( button.doorMoveTime ), button.doorMoveTime, DEFAULT_DOOR_MOVE_TIME_SEC );
timeMax = undefined;
foreach ( door in button.doors )
{
posGoal = ter_op( button.stateCurr == STATE_DOOR_CLOSING, door.posClosed, door.posOpen );
if ( door.origin != posGoal )
{
time = max( 0.1, Distance( door.origin, posGoal ) / door.distMove * timeMove );
timeEase = max( time * 0.25, 0.05 );
door MoveTo( posGoal, time, timeEase, timeEase );
door maps\mp\_movers::notify_moving_platform_invalid();
if(door.no_moving_unresolved_collisions)
{
door.unresolved_collision_func = maps\mp\_movers::unresolved_collision_void;
}
if ( !IsDefined( timeMax ) || time > timeMax )
{
timeMax = time;
}
}
}
if ( IsDefined( timeMax ) )
{
wait timeMax;
}
}
else if ( button.stateCurr == STATE_DOOR_PAUSED )
{
foreach ( door in button.doors )
{
door MoveTo( door.origin, 0.05, 0.0, 0.0 );
door maps\mp\_movers::notify_moving_platform_invalid();
if(door.no_moving_unresolved_collisions)
{
door.unresolved_collision_func = undefined;
}
if ( IsDefined( door.script_noteworthy ) )
{
if ( ( door.script_noteworthy == "clockwise_wheel" ) || ( door.script_noteworthy == "counterclockwise_wheel" ) )
{
door RotateVelocity( ( 0, 0, 0 ), 0.05 );
}
}
}
AssertEx( IsDefined( button.statePrev ) && ( button.statePrev == STATE_DOOR_CLOSING || button.statePrev == STATE_DOOR_OPENING ), "door_state_init() called with pause state without a valid previous state." );
// Make sure the light's off state remains on during pause
if ( IsDefined( button.lights_off ) )
{
foreach ( light in button.lights_off )
{
light Show();
}
}
button.entSound StopLoopSound();
// playSoundAtPos( button.entSound.origin, "garage_door_interupt" );
foreach( door in button.doors )
{
if( IsDefined( door.interrupt_sound ) )
{
door PlaySound( door.interrupt_sound );
}
}
wait DEFAULT_DOOR_PAUSE_TIME_SEC;
}
else
{
AssertMsg( "Unhandled state value of: " + button.stateCurr );
}
button.stateDone = true;
foreach ( door in button.doors )
{
door.stateDone = true; // for sub-members like the hopper wheels in mp_frag
}
button notify( "door_state_done" );
}
door_state_update_sound( default_soundStart, default_soundLoop )
{
button = self;
use_default_start_sound = true;
use_default_loop_sound = true;
sound_length = 0;
if( ( button.stateCurr == STATE_DOOR_OPENING ) || ( button.stateCurr == STATE_DOOR_CLOSING ) )
{
foreach( door in button.doors )
{
if( IsDefined( door.start_sound ) )
{
door PlaySoundOnMovingEnt( door.start_sound );
sound_length = LookupSoundLength( door.start_sound ) / 1000;
use_default_start_sound = false;
}
}
if( use_default_start_sound )
{
sound_length = LookupSoundLength( default_soundStart ) / 1000;
playSoundAtPos( button.entSound.origin, default_soundStart );
}
}
wait( sound_length * 0.3 ); // fraction of the sound so it blends better with the looping sound
if( ( button.stateCurr == STATE_DOOR_OPENING ) || ( button.stateCurr == STATE_DOOR_CLOSING ) )
{
foreach( door in button.doors )
{
if( IsDefined( door.loop_sound ) )
{
if( door.loop_sound != "none" )
{
door PlayLoopSound( door.loop_sound );
}
use_default_loop_sound = false;
}
}
if( use_default_loop_sound )
{
button.entSound PlayLoopSound( default_soundLoop );
}
}
}
door_state_change( state, noSound )
{
button = self;
if ( IsDefined( button.stateCurr ) )
{
door_state_exit( button.stateCurr );
button.statePrev = button.stateCurr;
}
button.stateCurr = state;
button thread door_state_update( noSound );
}
door_state_exit( state )
{
button = self;
if ( state == STATE_DOOR_CLOSED || state == STATE_DOOR_OPEN )
{
if ( IsDefined( button.lights_on ) )
{
foreach ( light in button.lights_on )
{
light Hide();
}
}
}
else if ( state == STATE_DOOR_CLOSING || state == STATE_DOOR_OPENING )
{
if ( IsDefined( button.lights_off ) )
{
foreach ( light in button.lights_off )
{
light Hide();
}
}
button.entSound StopLoopSound();
foreach( door in button.doors )
{
if( IsDefined( door.loop_sound ) )
{
door StopLoopSound();
}
}
}
else if ( state == STATE_DOOR_PAUSED )
{
}
else
{
AssertMsg( "Unhandled state value of: " + state );
}
}
door_state_on_interrupt()
{
button = self;
button endon( "door_state_done" );
filtered_triggers = [];
foreach ( trigger in button.trigBlock )
{
if ( button.stateCurr == STATE_DOOR_CLOSING )
{
if ( IsDefined( trigger.not_closing ) && ( trigger.not_closing == true ) )
{
continue;
}
}
else if ( button.stateCurr == STATE_DOOR_OPENING )
{
if ( IsDefined( trigger.not_opening ) && ( trigger.not_opening == true ) )
{
continue;
}
}
filtered_triggers[ filtered_triggers.size ] = trigger;
}
if ( filtered_triggers.size > 0 )
{
interrupter = button waittill_any_triggered_return_triggerer( filtered_triggers );
if ( !IsDefined( interrupter.fauxDead ) || ( interrupter.fauxDead == false ) )
{
button.stateInterrupted = true;
button notify( "door_state_interrupted" );
}
}
}
waittill_any_triggered_return_triggerer( triggers )
{
button = self;
foreach ( trigger in triggers )
{
button thread return_triggerer( trigger );
}
button waittill( "interrupted" );
return button.interrupter;
}
return_triggerer( trigger )
{
button = self;
button endon( "door_state_done" );
button endon( "interrupted" );
while ( 1 )
{
trigger waittill( "trigger", ent );
// This prone_only business is to account for the fact that the player's prone bounding box, which the trigger uses, actually only encompasses approximately his head to his waist. This can result in a prone player's
// legs getting caught in the door (note: he should still be able to get out of the stuck spot by changing stance to crouch or stand). To alleviate that we add a second trigger (the prone_only trigger) which is much
// wider (32 units on either side of the door), resulting int he doors staying open for the prone player. We also check the player's facing so that the doors don't stop for a prone player whose legs are NOT between the doors, to prevent sliver shooting.
if ( IsDefined( trigger.prone_only ) && ( trigger.prone_only == true ) )
{
if ( IsPlayer( ent ) )
{
stance = ent GetStance();
if ( stance != "prone" )
{
continue;
}
else
{
norm_facing_vec = VectorNormalize( AnglesToForward( ent.angles ) );
norm_vec_to_trig = VectorNormalize( trigger.origin - ent.origin );
dot = VectorDot( norm_facing_vec, norm_vec_to_trig );
if ( dot > 0 )
{
continue;
}
}
}
}
break;
}
button.interrupter = ent;
button notify( "interrupted" );
}
button_parse_parameters( parameters )
{
button = self;
button.button_sound = undefined;
if ( !IsDefined( parameters ) )
parameters = "";
params = StrTok( parameters, ";" );
foreach ( param in params )
{
toks = StrTok( param, "=" );
if ( toks.size!= 2 )
continue;
if ( toks[ 1 ] == "undefined" || toks[ 1 ] == "default" )
{
button.params[ toks[ 0 ]] = undefined;
continue;
}
switch( toks[ 0 ] )
{
case "open_interrupt":
button.open_interrupt = string_to_bool( toks[ 1 ] );
break;
case "button_sound":
button.button_sound = toks[1];
break;
default:
break;
}
}
}
door_parse_parameters( parameters )
{
door = self;
door.start_sound = undefined;
door.stop_sound = undefined;
door.loop_sound = undefined;
door.interrupt_sound = undefined;
if ( !IsDefined( parameters ) )
parameters = "";
params = StrTok( parameters, ";" );
foreach ( param in params )
{
toks = StrTok( param, "=" );
if ( toks.size!= 2 )
continue;
if ( toks[ 1 ] == "undefined" || toks[ 1 ] == "default" )
{
door.params[ toks[ 0 ]] = undefined;
continue;
}
switch( toks[ 0 ] )
{
case "stop_sound":
door.stop_sound = toks[1];
break;
case "interrupt_sound":
door.interrupt_sound = toks[1];
break;
case "loop_sound":
door.loop_sound = toks[1];
break;
case "open_interrupt":
door.open_interrupt = string_to_bool( toks[ 1 ] );
break;
case "start_sound":
door.start_sound = toks[1];
break;
case "unresolved_collision_nodes":
door.unresolved_collision_nodes = GetNodeArray(toks[ 1 ], "targetname");
break;
case "no_moving_unresolved_collisions":
door.no_moving_unresolved_collisions = string_to_bool(toks[1]);
break;
default:
break;
}
}
}
trigger_parse_parameters( parameters )
{
trigger = self;
if ( !IsDefined( parameters ) )
parameters = "";
params = StrTok( parameters, ";" );
foreach ( param in params )
{
toks = StrTok( param, "=" );
if ( toks.size!= 2 )
continue;
if ( toks[ 1 ] == "undefined" || toks[ 1 ] == "default" )
{
trigger.params[ toks[ 0 ]] = undefined;
continue;
}
switch( toks[ 0 ] )
{
case "not_opening":
trigger.not_opening = string_to_bool( toks[ 1 ] );
break;
case "not_closing":
trigger.not_closing = string_to_bool( toks[ 1 ] );
break;
case "prone_only":
trigger.prone_only = string_to_bool( toks[ 1 ] );
break;
default:
break;
}
}
}
string_to_bool( the_string )
{
retVal = undefined;
switch( the_string )
{
case "1":
case "true":
retVal = true;
break;
case "0":
case "false":
retVal = false;
break;
default:
AssertMsg( "Invalid string to bool convert attempted." );
break;
}
return retVal;
}

View File

@ -0,0 +1,120 @@
init()
{
// Draws a team icon over teammates
level.drawfriend = 0;
game["headicon_allies"] = maps\mp\gametypes\_teams::getTeamHeadIcon( "allies" );
game["headicon_axis"] = maps\mp\gametypes\_teams::getTeamHeadIcon( "axis" );
precacheHeadIcon( game["headicon_allies"] );
precacheHeadIcon( game["headicon_axis"] );
precacheShader( "waypoint_revive" );
level thread onPlayerConnect();
for(;;)
{
updateFriendIconSettings();
wait 5;
}
}
onPlayerConnect()
{
for(;;)
{
level waittill("connected", player);
player thread onPlayerSpawned();
player thread onPlayerKilled();
}
}
onPlayerSpawned()
{
self endon("disconnect");
for(;;)
{
self waittill("spawned_player");
self thread showFriendIcon();
}
}
onPlayerKilled()
{
self endon("disconnect");
for(;;)
{
self waittill("killed_player");
self.headicon = "";
}
}
showFriendIcon()
{
if(level.drawfriend)
{
if(self.pers["team"] == "allies")
{
self.headicon = game["headicon_allies"];
self.headiconteam = "allies";
}
else
{
self.headicon = game["headicon_axis"];
self.headiconteam = "axis";
}
}
}
updateFriendIconSettings()
{
drawfriend = maps\mp\_utility::getIntProperty("scr_drawfriend", level.drawfriend);
if(level.drawfriend != drawfriend)
{
level.drawfriend = drawfriend;
updateFriendIcons();
}
}
updateFriendIcons()
{
// for all living players, show the appropriate headicon
players = level.players;
for(i = 0; i < players.size; i++)
{
player = players[i];
if(isDefined(player.pers["team"]) && player.pers["team"] != "spectator" && player.sessionstate == "playing")
{
if(level.drawfriend)
{
if(player.pers["team"] == "allies")
{
player.headicon = game["headicon_allies"];
player.headiconteam = "allies";
}
else
{
player.headicon = game["headicon_axis"];
player.headiconteam = "axis";
}
}
else
{
players = level.players;
for(i = 0; i < players.size; i++)
{
player = players[i];
if(isDefined(player.pers["team"]) && player.pers["team"] != "spectator" && player.sessionstate == "playing")
player.headicon = "";
}
}
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,616 @@
#include maps\mp\_utility;
#include maps\mp\gametypes\_hud_util;
#include common_scripts\utility;
getHighestScoringPlayer()
{
updatePlacement();
if ( !level.placement["all"].size )
return ( undefined );
else
return ( level.placement["all"][0] );
}
getLosingPlayers()
{
updatePlacement();
players = level.placement["all"];
losingPlayers = [];
foreach ( player in players )
{
if ( player == level.placement["all"][0] )
continue;
losingPlayers[losingPlayers.size] = player;
}
return losingPlayers;
}
givePlayerScore( event, player, victim, overrideCheckPlayerScoreLimitSoon, overridePointsPopup, bScaleDown )
{
if ( is_aliens() )
return;
else
givePlayerScore_regularMP( event, player, victim, overrideCheckPlayerScoreLimitSoon, overridePointsPopup, bScaleDown );
}
givePlayerScore_regularMP( event, player, victim, overrideCheckPlayerScoreLimitSoon, overridePointsPopup, bScaleDown )
{
// If this is a squadmate, give credit to the agent's owner player
if ( IsDefined(player.owner) && !IsBot( player ) )
{
player = player.owner;
}
if ( !IsBot( player ) )
{
//If a player is commanding a bot, give the credit to the bot, not the player
if ( IsDefined( player.commanding_bot ) )
{
player = player.commanding_bot;
}
}
if ( !IsPlayer(player) )
return;
if ( !isDefined( overrideCheckPlayerScoreLimitSoon ) )
overrideCheckPlayerScoreLimitSoon = false;
if ( !isDefined( overridePointsPopup ) )
overridePointsPopup = false;
// score has a max value of 65000
if ( !isDefined( bScaleDown ) )
bScaleDown = false;
prevScore = player.pers["score"];
onPlayerScore( event, player, victim, bScaleDown );
score_change = (player.pers["score"] - prevScore);
if ( score_change == 0 )
return;
// score was scaled down, multiply back to the real value
if( bScaleDown )
score_change = int(score_change * 10);
// Store the event value to use for dm and sotf_ffa
// This is used to get the correct value of each kill event
// so we display them correct for the xpPointsPopup in offline matches, and leaderboards
eventValue = maps\mp\gametypes\_rank::getScoreInfoValue( event );
if ( !player rankingEnabled() && !level.hardcoreMode && !overridePointsPopup )
{
// Get the correct value of the "kill" event to be shown in the XP Point Popups
if ( gameModeUsesDeathmatchScoring( level.gameType ) )
player thread maps\mp\gametypes\_rank::xpPointsPopup( eventValue );
else
player thread maps\mp\gametypes\_rank::xpPointsPopup( score_change );
}
// Store the correct lifetime score
if ( gameModeUsesDeathmatchScoring( level.gameType ) )
player maps\mp\gametypes\_persistence::statAdd( "score", eventValue );
else if ( !IsSquadsMode() )
player maps\mp\gametypes\_persistence::statAdd( "score", score_change );
//maxing player score to 65000 to protect from scoreboard overflow(max unsigned short?)
if ( player.pers["score"] >= 65000 )
player.pers["score"] = 65000;
player.score = player.pers["score"];
scoreChildStat = player.score;
// score was scaled down, multiply back to the real value
if( bScaleDown )
scoreChildStat = int(scoreChildStat * 10);
// Store the correct per game score
if ( gameModeUsesDeathmatchScoring( level.gameType ) )
player maps\mp\gametypes\_persistence::statSetChild( "round", "score", scoreChildStat * eventValue );
else
player maps\mp\gametypes\_persistence::statSetChild( "round", "score", scoreChildStat );
if ( !level.teambased )
thread sendUpdatedDMScores();
// player score and team score aren't always the same values towards winning the match
// checkScoreLimit() checks team score correctly, checkPlayerScoreLimitSoon() uses player score
if ( !overrideCheckPlayerScoreLimitSoon )
player maps\mp\gametypes\_gamelogic::checkPlayerScoreLimitSoon();
scoreEndedMatch = player maps\mp\gametypes\_gamelogic::checkScoreLimit();
}
onPlayerScore( event, player, victim, bScaleDown )
{
score = undefined;
if ( IsDefined( level.onPlayerScore ) )
{
score = [[level.onPlayerScore]](event, player, victim);
}
if ( !IsDefined( score ) )
{
score = maps\mp\gametypes\_rank::getScoreInfoValue( event );
}
score = score * level.objectivePointsMod;
// player.score has a max value of 65000
// scale down by 10 to allow larger numbers
if( bScaleDown )
score = int( score / 10 );
assert( isDefined( score ) );
player.pers["score"] += score;
}
// Seems to only be used for reducing a player's score due to suicide
_setPlayerScore( player, score )
{
if ( score == player.pers["score"] )
return;
if ( score < 0 )
return;
player.pers["score"] = score;
player.score = player.pers["score"];
player thread maps\mp\gametypes\_gamelogic::checkScoreLimit();
}
_getPlayerScore( player )
{
if( !IsDefined( player ) )
player = self;
return player.pers["score"];
}
giveTeamScoreForObjective( team, score )
{
score *= level.objectivePointsMod;
// NOTE: don't set level.wasWinning here because it'll give a false positive if they are tied and the lead changes below
// this caused a bug where the lead_taken and lead_lost vo was reversed, it was happening because the first time the lead changed
// they were tied before the score changed, then the next time it came in here it set level.wasWinning to the team that was already winning
// this then caused the lead_lost vo to play for the team who is winning
_setTeamScore( team, _getTeamScore( team ) + score );
level notify( "update_team_score", team, _getTeamScore( team ) );
isWinning = getWinningTeam();
if ( !level.splitScreen && isWinning != "none" && isWinning != level.wasWinning && getTime() - level.lastStatusTime > 5000 && getScoreLimit() != 1 )
{
level.lastStatusTime = getTime();
leaderDialog( "lead_taken", isWinning, "status" );
if ( level.wasWinning != "none")
leaderDialog( "lead_lost", level.wasWinning, "status" );
}
if( isWinning != "none" )
{
level.wasWinning = isWinning;
teamScore = _getTeamScore( isWinning );
scoreLimit = getWatchedDvar( "scorelimit" );
// this is to handle join in progress potential div by 0
if ( teamScore == 0 || scoreLimit == 0 )
return;
scorePercentage = ( teamScore/ scoreLimit ) * 100;
if( scorePercentage > level.scorePercentageCutOff )
SetNoJIPScore( true );
}
}
getWinningTeam()
{
assert( level.teamBased == true );
teams_list = level.teamNameList;
if( !IsDefined( level.wasWinning ) )
level.wasWinning = "none";
winning_team = "none";
winning_score = 0;
if( level.wasWinning != "none" )
{
winning_team = level.wasWinning;
winning_score = game[ "teamScores" ][ level.wasWinning ];
}
num_teams_tied_for_winning = 1;
foreach( teamName in teams_list )
{
if( teamName == level.wasWinning )
continue;
if( game[ "teamScores" ][ teamName ] > winning_score )
{
// new winning team found
winning_team = teamName;
winning_score = game[ "teamScores" ][ teamName ];
num_teams_tied_for_winning = 1;
}
else if( game[ "teamScores" ][ teamName ] == winning_score )
{
num_teams_tied_for_winning = num_teams_tied_for_winning + 1;
winning_team = "none";
}
}
return( winning_team );
}
_setTeamScore( team, teamScore )
{
if ( teamScore == game["teamScores"][team] )
return;
game["teamScores"][team] = teamScore;
updateTeamScore( team );
if ( game["status"] == "overtime" && !isDefined( level.overtimeScoreWinOverride ) || ( isDefined( level.overtimeScoreWinOverride ) && !level.overtimeScoreWinOverride ) )
thread maps\mp\gametypes\_gamelogic::onScoreLimit();
else
{
thread maps\mp\gametypes\_gamelogic::checkTeamScoreLimitSoon( team );
thread maps\mp\gametypes\_gamelogic::checkScoreLimit();
}
}
updateTeamScore( team )
{
assert( level.teamBased );
teamScore = 0;
// Blitz was added in this check, because it is technically a round based game, even though we don't keep track of the score based on rounds won.
if ( !isRoundBased() || !isObjectiveBased() || level.gameType == "blitz")
teamScore = _getTeamScore( team );
else
teamScore = game["roundsWon"][team];
setTeamScore( team, teamScore );
//thread sendUpdatedTeamScores();
}
_getTeamScore( team )
{
return game["teamScores"][team];
}
sendUpdatedTeamScores()
{
level notify("updating_scores");
level endon("updating_scores");
wait .05;
WaitTillSlowProcessAllowed();
foreach ( player in level.players )
player updateScores();
}
sendUpdatedDMScores()
{
level notify("updating_dm_scores");
level endon("updating_dm_scores");
wait .05;
WaitTillSlowProcessAllowed();
for ( i = 0; i < level.players.size; i++ )
{
level.players[i] updateDMScores();
level.players[i].updatedDMScores = true;
}
}
removeDisconnectedPlayerFromPlacement()
{
offset = 0;
numPlayers = level.placement["all"].size;
found = false;
for ( i = 0; i < numPlayers; i++ )
{
if ( level.placement["all"][i] == self )
found = true;
if ( found )
level.placement["all"][i] = level.placement["all"][ i + 1 ];
}
if ( !found )
return;
level.placement["all"][ numPlayers - 1 ] = undefined;
assert( level.placement["all"].size == numPlayers - 1 );
if( level.multiTeamBased )
{
MTDM_updateTeamPlacement();
}
if ( level.teamBased )
{
updateTeamPlacement();
return;
}
numPlayers = level.placement["all"].size;
for ( i = 0; i < numPlayers; i++ )
{
player = level.placement["all"][i];
player notify( "update_outcome" );
}
}
updatePlacement()
{
prof_begin("updatePlacement");
placementAll = [];
foreach ( player in level.players )
{
if ( isDefined( player.connectedPostGame ))
continue;
if( player.pers["team"] == "spectator" || player.pers["team"] == "none" )
continue;
placementAll[placementAll.size] = player;
}
for ( i = 1; i < placementAll.size; i++ )
{
player = placementAll[i];
playerScore = player.score;
// for ( j = i - 1; j >= 0 && (player.score > placementAll[j].score || (player.score == placementAll[j].score && player.deaths < placementAll[j].deaths)); j-- )
for ( j = i - 1; j >= 0 && getBetterPlayer( player, placementAll[j] ) == player; j-- )
placementAll[j + 1] = placementAll[j];
placementAll[j + 1] = player;
}
level.placement["all"] = placementAll;
if( level.multiTeamBased )
{
MTDM_updateTeamPlacement();
}
else if ( level.teamBased )
{
updateTeamPlacement();
}
prof_end("updatePlacement");
}
getBetterPlayer( playerA, playerB )
{
if ( playerA.score > playerB.score )
return playerA;
if ( playerB.score > playerA.score )
return playerB;
if ( playerA.deaths < playerB.deaths )
return playerA;
if ( playerB.deaths < playerA.deaths )
return playerB;
// TODO: more metrics for getting the better player
if ( cointoss() )
return playerA;
else
return playerB;
}
updateTeamPlacement()
{
placement["allies"] = [];
placement["axis"] = [];
placement["spectator"] = [];
assert( level.teamBased );
placementAll = level.placement["all"];
placementAllSize = placementAll.size;
for ( i = 0; i < placementAllSize; i++ )
{
player = placementAll[i];
team = player.pers["team"];
placement[team][ placement[team].size ] = player;
}
level.placement["allies"] = placement["allies"];
level.placement["axis"] = placement["axis"];
}
//NOTE: should conisder consolidating this with updateTeamPlacement... ( this was easiest 1st pass implementation )
MTDM_updateTeamPlacement()
{
placement["spectator"] = [];
foreach( teamname in level.teamNameList )
{
placement[teamname] = [];
}
assert( level.multiTeamBased );
placementAll = level.placement["all"];
placementAllSize = placementAll.size;
for ( i = 0; i < placementAllSize; i++ )
{
player = placementAll[i];
team = player.pers["team"];
placement[team][ placement[team].size ] = player;
}
foreach( teamname in level.teamNameList )
{
level.placement[teamname] = placement[teamname];
}
}
initialDMScoreUpdate()
{
// the first time we call updateDMScores on a player, we have to send them the whole scoreboard.
// by calling updateDMScores on each player one at a time,
// we can avoid having to send the entire scoreboard to every single player
// the first time someone kills someone else.
wait .2;
numSent = 0;
while(1)
{
didAny = false;
players = level.players;
for ( i = 0; i < players.size; i++ )
{
player = players[i];
if ( !isdefined( player ) )
continue;
if ( isdefined( player.updatedDMScores ) )
continue;
player.updatedDMScores = true;
player updateDMScores();
didAny = true;
wait .5;
}
if ( !didAny )
wait 3; // let more players connect
}
}
processAssist( killedplayer )
{
if ( IsDefined( level.assists_disabled ) )
return;
if ( is_aliens() )
return;
else
processAssist_regularMP( killedplayer );
}
processAssist_regularMP( killedplayer )
{
self endon("disconnect");
killedplayer endon("disconnect");
wait .05; // don't ever run on the same frame as the playerkilled callback.
WaitTillSlowProcessAllowed();
self_pers_team = self.pers["team"];
if ( self_pers_team != "axis" && self_pers_team != "allies" )
return;
if ( self_pers_team == killedplayer.pers["team"] )
return;
assistCreditTo = self;
if ( IsDefined( self.commanding_bot ) )
{
assistCreditTo = self.commanding_bot;
}
assistCreditTo thread [[level.onXPEvent]]( "assist" );
assistCreditTo incPersStat( "assists", 1 );
assistCreditTo.assists = assistCreditTo getPersStat( "assists" );
assistCreditTo incPlayerStat( "assists", 1 );
assistCreditTo maps\mp\gametypes\_persistence::statSetChild( "round", "assists", assistCreditTo.assists );
givePlayerScore( "assist", self, killedplayer );
self maps\mp\killstreaks\_killstreaks::giveAdrenaline( "assist" );
self thread maps\mp\gametypes\_missions::playerAssist( killedplayer );
}
processShieldAssist( killedPlayer )
{
if ( IsDefined( level.assists_disabled ) )
return;
if ( is_aliens() )
return;
else
processShieldAssist_regularMP( killedPlayer );
}
processShieldAssist_regularMP( killedPlayer )
{
self endon( "disconnect" );
killedPlayer endon( "disconnect" );
wait .05; // don't ever run on the same frame as the playerkilled callback.
WaitTillSlowProcessAllowed();
if ( self.pers["team"] != "axis" && self.pers["team"] != "allies" )
return;
if ( self.pers["team"] == killedplayer.pers["team"] )
return;
self thread [[level.onXPEvent]]( "assist" );
self thread [[level.onXPEvent]]( "assist" );
self incPersStat( "assists", 1 );
self.assists = self getPersStat( "assists" );
self incPlayerStat( "assists", 1 );
self maps\mp\gametypes\_persistence::statSetChild( "round", "assists", self.assists );
givePlayerScore( "assist", self, killedplayer );
self thread maps\mp\gametypes\_hud_message::SplashNotifyDelayed( "shield_assist" );
self thread maps\mp\gametypes\_missions::playerAssist( killedPlayer );
}
gameModeUsesDeathmatchScoring( mode )
{
return ( mode== "dm"
|| mode == "sotf_ffa"
// || mode == "gun"
);
}

View File

@ -0,0 +1,4 @@
/*QUAKED mp_global_intermission (1.0 0.0 1.0) (-16 -16 -16) (16 16 16)
Intermission is randomly viewed from one of these positions.
Spectators spawn randomly at one of these positions.
*/

View File

@ -0,0 +1,293 @@
#include maps\mp\_utility;
#include maps\mp\gametypes\_hud_util;
#include common_scripts\utility;
init()
{
level.splitscreen = isSplitScreen();
set_console_status();
level.onlineGame = getDvarInt( "onlinegame" );
level.rankedMatch = ( ( level.onlineGame && !getDvarInt( "xblive_privatematch" ) ) || GetDvarInt( "force_ranking" ) ); // System link games are no longer ranked games
/#
if ( getdvarint( "scr_forcerankedmatch" ) == 1 )
{
level.onlineGame = true;
level.rankedMatch = true;
}
#/
level.script = toLower( getDvar( "mapname" ) );
level.gametype = toLower( getDvar( "g_gametype" ) );
//default team list, use this for team algos, overwrite it for Multiteam games
level.teamNameList = ["axis", "allies"];
level.otherTeam["allies"] = "axis";
level.otherTeam["axis"] = "allies";
level.multiTeamBased = false;
level.teamBased = false;
level.objectiveBased = false;
level.endGameOnTimeLimit = true;
level.showingFinalKillcam = false;
level.tiSpawnDelay = getDvarInt( "scr_tispawndelay" );
// hack to allow maps with no scripts to run correctly
if ( !isDefined( level.tweakablesInitialized ) )
maps\mp\gametypes\_tweakables::init();
level.halftimeType = "halftime";
level.lastStatusTime = 0;
level.wasWinning = "none";
level.lastSlowProcessFrame = 0;
level.placement["allies"] = [];
level.placement["axis"] = [];
level.placement["all"] = [];
level.postRoundTime = 5.0;
level.playersLookingForSafeSpawn = [];
registerDvars();
if( matchMakingGame() )
{
mapLeaderboard = " LB_MAP_" + getdvar( "ui_mapname" );
gamemodeLeaderboard = "";
baseLeaderboards = "";
if( IsSquadsMode() )
{
if( getDvarInt( "squad_match" ) )
{
gamemodeLeaderboard = " LB_GM_SQUAD_ASSAULT";
level thread endMatchOnHostDisconnect();
}
else if( level.gametype == "horde" )
{
gamemodeLeaderboard = " LB_GM_HORDE";
}
}
else
{
baseLeaderboards = "LB_GB_TOTALXP_AT LB_GB_TOTALXP_LT LB_GB_WINS_AT LB_GB_WINS_LT LB_GB_KILLS_AT LB_GB_KILLS_LT LB_GB_ACCURACY_AT LB_ACCOLADES";
gamemodeLeaderboard = " LB_GM_" + level.gametype;
if( getDvarInt( "g_hardcore" ) )
gamemodeLeaderboard += "_HC";
}
precacheLeaderboards( baseLeaderboards + gamemodeLeaderboard + mapLeaderboard );
}
level.teamCount["allies"] = 0;
level.teamCount["axis"] = 0;
level.teamCount["spectator"] = 0;
level.aliveCount["allies"] = 0;
level.aliveCount["axis"] = 0;
level.aliveCount["spectator"] = 0;
level.livesCount["allies"] = 0;
level.livesCount["axis"] = 0;
level.oneLeftTime = [];
level.hasSpawned["allies"] = 0;
level.hasSpawned["axis"] = 0;
/#
if ( getdvarint( "scr_runlevelandquit" ) == 1 )
{
thread runLevelAndQuit();
}
#/
max_possible_teams = 9;
init_multiTeamData( max_possible_teams );
}
endMatchOnHostDisconnect()
{
level endon ( "game_ended" );
for( ;; )
{
level waittill( "connected", player );
if( player isHost() )
{
host = player;
break;
}
}
host waittill( "disconnect" );
thread maps\mp\gametypes\_gamelogic::endGame( "draw", game[ "end_reason" ][ "host_ended_game" ] );
}
init_multiTeamData( max_num_teams )
{
for( i = 0; i < max_num_teams; i++ )
{
team_name = "team_" + i;
level.placement[team_name] = [];
level.teamCount[team_name] = 0;
level.aliveCount[team_name] = 0;
level.livesCount[team_name] = 0;
level.hasSpawned[team_name] = 0;
}
}
/#
runLevelAndQuit()
{
wait 1;
while ( level.players.size < 1 )
{
wait 0.5;
}
wait 0.5;
level notify( "game_ended" );
exitLevel();
}
#/
registerDvars()
{
SetOmnvar( "ui_bomb_timer", 0 );
if( getDvar( "r_reflectionProbeGenerate" ) != "1" )
{
SetOmnvar( "ui_nuke_end_milliseconds", 0 );
}
SetDvar( "ui_danger_team", "" );
SetDvar( "ui_inhostmigration", 0 );
SetDvar( "ui_override_halftime", 0 );
SetDvar( "camera_thirdPerson", getDvarInt( "scr_thirdPerson" ) );
}
SetupCallbacks()
{
level.onXPEvent = ::onXPEvent;
level.getSpawnPoint = ::blank;
level.onSpawnPlayer = ::blank;
level.onRespawnDelay = ::blank;
level.onTimeLimit = maps\mp\gametypes\_gamelogic::default_onTimeLimit;
level.onHalfTime = maps\mp\gametypes\_gamelogic::default_onHalfTime;
level.onDeadEvent = maps\mp\gametypes\_gamelogic::default_onDeadEvent;
level.onOneLeftEvent = maps\mp\gametypes\_gamelogic::default_onOneLeftEvent;
level.onPrecacheGametype = ::blank;
level.onStartGameType = ::blank;
level.onPlayerKilled = ::blank;
level.killStreakInit = maps\mp\killstreaks\_killstreaks_init::init;
level.matchEventsInit = maps\mp\_matchevents::init;
level.intelInit = maps\mp\gametypes\_intel::init;
/#
level.devInit = maps\mp\gametypes\_dev::init;
#/
//level.autoassign = maps\mp\gametypes\_menus::menuAutoAssign;
//level.spectator = maps\mp\gametypes\_menus::menuSpectator;
//level.class = maps\mp\gametypes\_menus::menuClass;
//level.onTeamSelection = maps\mp\gametypes\_menus::onMenuTeamSelect;
}
blank( arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10 )
{
}
/#
xpRateThread()
{
self endon ( "death" );
self endon ( "disconnect" );
level endon ( "game_ended" );
gameFlagWait( "prematch_done" );
for ( ;; )
{
wait ( 5.0 );
if ( level.players[0].pers["team"] == "allies" || level.players[0].pers["team"] == "axis" )
self maps\mp\gametypes\_rank::giveRankXP( "kill", int(min( getDvarInt( "scr_xprate" ), 50 )) );
}
}
#/
testMenu()
{
self endon ( "death" );
self endon ( "disconnect" );
for ( ;; )
{
wait ( 10.0 );
notifyData = spawnStruct();
notifyData.titleText = &"MP_CHALLENGE_COMPLETED";
notifyData.notifyText = "wheee";
notifyData.sound = "mp_challenge_complete";
self thread maps\mp\gametypes\_hud_message::notifyMessage( notifyData );
}
}
testShock()
{
self endon ( "death" );
self endon ( "disconnect" );
for ( ;; )
{
wait ( 3.0 );
numShots = randomInt( 6 );
for ( i = 0; i < numShots; i++ )
{
iPrintLnBold( numShots );
self shellShock( "frag_grenade_mp", 0.2 );
wait ( 0.1 );
}
}
}
onXPEvent( event )
{
//self thread maps\mp\_loot::giveMoney( event, 10 );
self thread maps\mp\gametypes\_rank::giveRankXP( event );
}
debugLine( start, end )
{
for ( i = 0; i < 50; i++ )
{
line( start, end );
wait .05;
}
}

View File

View File

@ -0,0 +1,289 @@
#include maps\mp\_utility;
init()
{
level.healthOverlayCutoff = 0.55;
regenTime = 5;
regenTime = maps\mp\gametypes\_tweakables::getTweakableValue( "player", "healthregentime" );
level.playerHealth_RegularRegenDelay = regenTime;
level.healthRegenDisabled = (level.playerHealth_RegularRegenDelay <= 0);
level thread onPlayerConnect();
}
onPlayerConnect()
{
for(;;)
{
level waittill("connected", player);
player thread onPlayerSpawned();
}
}
onPlayerSpawned()
{
self endon("disconnect");
for(;;)
{
self waittill("spawned_player");
self thread playerHealthRegen();
self VisionSetThermalForPlayer( game[ "thermal_vision" ] );
/#
//self thread showTempDamage();
#/
}
}
/#
//showTempDamage()
//{
// self endon ( "death" );
// self endon ( "disconnect" );
// setDevDvar( "scr_damage_wait", 0 );
// setDevDvar( "scr_damage_fadein", 0.25 );
// setDevDvar( "scr_damage_fadeout", 0.5 );
// setDevDvar( "scr_damage_holdtime", 0.5 );
// setDevDvar( "scr_damage_numfades", 5 );
//
// for ( ;; )
// {
// while ( getDvarFloat( "scr_damage_wait" ) <= 0 )
// wait ( 1.0 );
//
// wait ( getDvarFloat( "scr_damage_wait" ) );
//
// for ( i = 0; i < getDvarInt( "scr_damage_numfades" ); i++ )
// {
// self VisionSetNakedForPlayer( "near_death_mp", getDvarFloat( "scr_damage_fadein" ) * (getDvarInt( "scr_damage_numfades" ) - i) );
// wait ( getDvarFloat( "scr_damage_fadein" ) + getDvarFloat( "scr_damage_holdtime" ) );
// self VisionSetNakedForPlayer( "near_death_mp", getDvarFloat( "scr_damage_fadeout" ) * getDvarInt( "scr_damage_numfades" ) );
// wait ( getDvarFloat( "scr_damage_fadeout" ) );
// }
//
// }
//}
#/
playerHealthRegen()
{
self endon ( "death" );
self endon ( "disconnect" );
self endon ( "joined_team" );
self endon ( "joined_spectators" );
self endon ( "faux_spawn" );
level endon ( "game_ended" );
if ( self.health <= 0 )
{
assert( !isalive( self ) );
return;
}
veryHurt = false;
hurtTime = 0;
thread playerPainBreathingSound( self.maxhealth * 0.55 );
for (;;)
{
self waittill( "damage" );
if ( self.health <= 0 ) // player dead
return;
// jugg's don't regen health
if( self isJuggernaut() )
continue;
hurtTime = getTime();
healthRatio = self.health / self.maxHealth;
self.regenSpeed = 1;
if( self _hasPerk( "specialty_regenfaster" ) )
self.regenSpeed *= level.regenFasterMod;
else if( self _hasPerk( "specialty_bloodrush" ) )
self.regenSpeed *= self.bloodrushRegenSpeedMod;
if ( healthRatio <= level.healthOverlayCutoff ) //this is used for a challenge
{
self.atBrinkOfDeath = true;
}
self thread healthRegeneration( hurtTime, healthRatio );
self thread breathingManager( hurtTime, healthRatio );
}
}
breathingManager( hurtTime, healthRatio )
{
self notify( "breathingManager" );
self endon ( "breathingManager" );
self endon ( "death" );
self endon ( "disconnect" );
self endon ( "joined_team" );
self endon ( "joined_spectators" );
level endon ( "game_ended" );
if( self isUsingRemote() )
return;
if( !IsPlayer(self) )
return;
self.breathingStopTime = hurtTime + ( 6000 * self.regenSpeed );
wait ( 6 * self.regenSpeed );
if ( !level.gameEnded )
{
if ( self hasFemaleCustomizationModel() )
{
self playLocalSound("Fem_breathing_better");
}
else
{
self playLocalSound("breathing_better");
}
}
}
healthRegeneration( hurtTime, healthRatio )
{
self notify( "healthRegeneration" );
self endon ( "healthRegeneration" );
self endon ( "death" );
self endon ( "disconnect" );
self endon ( "joined_team" );
self endon ( "joined_spectators" );
level endon ( "game_ended" );
healthRegenDisabled = level.healthRegenDisabled || ( IsDefined(self.healthRegenDisabled) && self.healthRegenDisabled );
if ( healthRegenDisabled )
return;
// Watch when bloodrush is activated and then manually override the regen speed
// This is only needed if the player is damaged before bloodrush is activated
self childthread maps\mp\perks\_perkfunctions::regenSpeedWatcher();
wait ( ( level.playerHealth_RegularRegenDelay ) * self.regenSpeed ); //reduce this for perk
if ( healthRatio < .55 )
{
wasVeryHurt = true;
}
else
{
wasVeryHurt = false;
}
while( true )
{
if( !IsDefined( self.regenSpeed ) || self.regenSpeed == 1 ) // standard speed 5 seconds 100 frames
{
wait( 0.05 );
if( self.health < self.maxHealth )
{
self.health += 1;
healthRatio = self.health / self.maxHealth;
}
else
break;
}
else // faster regen
{
wait( 0.05 );
if( self.health < self.maxHealth )
{
if( self _hasPerk( "specialty_regenfaster" ) )
self.health += level.regenFasterHealthMod;
else if( self _hasPerk( "specialty_bloodrush" ) )
self.health += self.bloodrushRegenHealthMod;
}
else
break;
}
if( self.health > self.maxHealth )
self.health = self.maxHealth;
}
self notify( "healed" );
//fully regenerated
self maps\mp\gametypes\_damage::resetAttackerList();
if ( wasVeryHurt )
self maps\mp\gametypes\_missions::healthRegenerated();
}
wait_for_not_using_remote()
{
// this fixes a bug where you can be very damaged and showing the red visionset, then enter a killstreak using a remote
// once you come out, the red visionset was staying on because we never told it to reset while you were in the killstreak
self notify( "waiting_to_stop_remote" );
self endon( "waiting_to_stop_remote" );
self endon( "death" );
level endon( "game_ended" );
self waittill( "stopped_using_remote" );
self restoreBaseVisionSet( 0 );
}
playerPainBreathingSound( healthcap )
{
level endon ( "game_ended" );
self endon ( "death" );
self endon ( "disconnect" );
self endon ( "joined_team" );
self endon ( "joined_spectators" );
if( !IsPlayer(self) )
return;
wait ( 2 );
for (;;)
{
wait ( 0.2 );
if ( self.health <= 0 )
return;
// Player still has a lot of health so no breathing sound
if ( self.health >= healthcap )
continue;
healthRegenDisabled = level.healthRegenDisabled || ( IsDefined(self.healthRegenDisabled) && self.healthRegenDisabled );
// Juggernauts may breathe forever
if ( healthRegenDisabled && IsDefined( self.breathingStopTime ) && gettime() > self.breathingStopTime )
continue;
if( self isUsingRemote() )
continue;
if ( self hasFemaleCustomizationModel() )
self playLocalSound( "Fem_breathing_hurt" );
else
self playLocalSound( "breathing_hurt" );
wait ( .784 );
wait ( 0.1 + randomfloat (0.8) );
}
}

View File

@ -0,0 +1,836 @@
#include common_scripts\utility;
#include maps\mp\_utility;
#include maps\mp\gametypes\_hud_util;
#include maps\mp\killstreaks\_airdrop;
#include maps\mp\gametypes\horde;
#include maps\mp\gametypes\_horde_util;
CONST_AIR_DROP_USE_TIME = 1000;
CONST_LOOT_DROP_USE_TIME = 2000;
KILLSTREAK_SLOT_1 = 1;
KILLSTREAK_SLOT_3 = 3;
CONST_STAGE_0_OUTLINE = 2;
CONST_STAGE_0_COLOR = (0.431, 0.745, 0.235);
CONST_STAGE_1_OUTLINE = 5;
CONST_STAGE_1_COLOR = (0.804, 0.804, 0.035);
createHordeCrates( friendly_crate_model, enemy_crate_model )
{
level.getRandomCrateTypeForGameMode = ::getRandomCrateTypeHorde;
// ammo icon
level.hordeIcon["ammo"] = "specialty_ammo_crate";
// weapon icons
level.hordeIcon["iw6_mts255_mp_barrelrange03_reflexshotgun"] = "hud_icon_mts255";
level.hordeIcon["iw6_fp6_mp_barrelrange03_reflexshotgun"] = "hud_icon_fp6";
level.hordeIcon["iw6_vepr_mp_grip"] = "hud_icon_vepr";
level.hordeIcon["iw6_microtar_mp_eotechsmg"] = "hud_icon_microtar";
level.hordeIcon["iw6_ak12_mp_flashsuppress_grip"] = "hud_icon_ak12";
level.hordeIcon["iw6_arx160_mp_flashsuppress_hybrid"] = "hud_icon_arx160";
level.hordeIcon["iw6_m27_mp_flashsuppress_hybrid"] = "hud_icon_m27";
level.hordeIcon["iw6_kac_mp_flashsuppress"] = "hud_icon_kac";
level.hordeIcon["iw6_usr_mp_usrvzscope_xmags"] = "hud_icon_usr";
level.hordeIcon["iw6_magnumhorde_mp_fmj"] = "hud_icon_magnum";
level.hordeIcon["throwingknife_mp"] = "throw_knife_sm";
// perk icons
level.hordeIcon["specialty_lightweight"] = "icon_perks_agility"; // incresed movement speed
level.hordeIcon["specialty_fastreload"] = "icon_perks_sleight_of_hand"; // fast reload
level.hordeIcon["specialty_quickdraw"] = "icon_perks_quickdraw"; // faster aiming
level.hordeIcon["specialty_marathon"] = "icon_perks_marathon"; // unlimited sprint
level.hordeIcon["specialty_quickswap"] = "icon_perks_reflex"; // swap weapons faster
level.hordeIcon["specialty_bulletaccuracy"] = "icon_perks_steady_aim"; // increase hip fire accuracy
level.hordeIcon["specialty_fastsprintrecovery"] = "icon_perks_ready_up"; // weapon is ready faster after sprinting
level.hordeIcon["_specialty_blastshield"] = "icon_perks_blast_shield"; // resistance to explosives
level.hordeIcon["specialty_stalker"] = "icon_perks_stalker"; // move faster while aiming
level.hordeIcon["specialty_sharp_focus"] = "icon_perks_focus"; // reduce flinch when hit
level.hordeIcon["specialty_regenfaster"] = "icon_perks_icu"; // faster health regeneration
level.hordeIcon["specialty_sprintreload"] = "icon_perks_on_the_go"; // reload while sprinting
level.hordeIcon["specialty_triggerhappy"] = "icon_perks_triggerhappy"; // auto-reload after kill
// Drop Type Type Weight Function Friendly Model Enemy Model Hint String
addCrateType( "a", "iw6_mts255_mp_barrelrange03_reflexshotgun", 12, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_MTS" );
addCrateType( "a", "iw6_fp6_mp_barrelrange03_reflexshotgun", 12, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_FP6" );
addCrateType( "a", "iw6_vepr_mp_grip", 12, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_VEPR" );
addCrateType( "a", "iw6_microtar_mp_eotechsmg", 12, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_MICRO" );
addCrateType( "a", "iw6_ak12_mp_flashsuppress_grip", 0, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_AK" );
addCrateType( "a", "iw6_arx160_mp_flashsuppress_hybrid", 0, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_ARX" );
addCrateType( "a", "iw6_m27_mp_flashsuppress_hybrid", 0, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_M27" );
addCrateType( "a", "iw6_kac_mp_flashsuppress", 0, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_KAC" );
addCrateType( "a", "iw6_usr_mp_usrvzscope_xmags", 12, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_USR" );
addCrateType( "a", "iw6_magnumhorde_mp_fmj", 0, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_WEST" );
addCrateType( "a", "throwingknife_mp", 3, ::hordeCrateLethalThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_KNIFE" );
addCrateType( "a", "specialty_lightweight", 0, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_LIGHT" );
addCrateType( "a", "specialty_fastreload", 0, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_FAST" );
addCrateType( "a", "specialty_quickdraw", 10, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_QIUCK" );
addCrateType( "a", "specialty_marathon", 0, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_MARA" );
addCrateType( "a", "specialty_quickswap", 10, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_SWAP" );
addCrateType( "a", "specialty_bulletaccuracy", 0, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_AIM" );
addCrateType( "a", "specialty_fastsprintrecovery", 7, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_READY" );
addCrateType( "a", "_specialty_blastshield", 0, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_BLAST" );
addCrateType( "a", "specialty_stalker", 10, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_STALK" );
addCrateType( "a", "specialty_sharp_focus", 0, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_FOCUS" );
addCrateType( "a", "specialty_regenfaster", 0, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_HEALTH" );
addCrateType( "a", "specialty_sprintreload", 0, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_GO" );
addCrateType( "a", "specialty_triggerhappy", 0, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_TRIGGER" );
addCrateType( "a", "ammo", 0, ::hordeCrateAmmoThink, friendly_crate_model, enemy_crate_model, &"HORDE_AMMO" );
addCrateType( "b", "iw6_mts255_mp_barrelrange03_reflexshotgun", 5, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_MTS" );
addCrateType( "b", "iw6_fp6_mp_barrelrange03_reflexshotgun", 5, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_FP6" );
addCrateType( "b", "iw6_vepr_mp_grip", 10, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_VEPR" );
addCrateType( "b", "iw6_microtar_mp_eotechsmg", 10, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_MICRO" );
addCrateType( "b", "iw6_ak12_mp_flashsuppress_grip", 10, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_AK" );
addCrateType( "b", "iw6_arx160_mp_flashsuppress_hybrid", 10, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_ARX" );
addCrateType( "b", "iw6_m27_mp_flashsuppress_hybrid", 0, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_M27" );
addCrateType( "b", "iw6_kac_mp_flashsuppress", 0, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_KAC" );
addCrateType( "b", "iw6_usr_mp_usrvzscope_xmags", 10, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_USR" );
addCrateType( "b", "iw6_magnumhorde_mp_fmj", 0, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_WEST" );
addCrateType( "b", "throwingknife_mp", 3, ::hordeCrateLethalThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_KNIFE" );
addCrateType( "b", "specialty_lightweight", 10, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_LIGHT" );
addCrateType( "b", "specialty_fastreload", 0, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_FAST" );
addCrateType( "b", "specialty_quickdraw", 0, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_QIUCK" );
addCrateType( "b", "specialty_marathon", 10, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_MARA" );
addCrateType( "b", "specialty_quickswap", 0, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_SWAP" );
addCrateType( "b", "specialty_bulletaccuracy", 0, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_AIM" );
addCrateType( "b", "specialty_fastsprintrecovery", 0, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_READY" );
addCrateType( "b", "_specialty_blastshield", 0, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_BLAST" );
addCrateType( "b", "specialty_stalker", 0, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_STALK" );
addCrateType( "b", "specialty_sharp_focus", 7, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_FOCUS" );
addCrateType( "b", "specialty_regenfaster", 0, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_HEALTH" );
addCrateType( "b", "specialty_sprintreload", 10, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_GO" );
addCrateType( "b", "specialty_triggerhappy", 0, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_TRIGGER" );
addCrateType( "b", "ammo", 0, ::hordeCrateAmmoThink, friendly_crate_model, enemy_crate_model, &"HORDE_AMMO" );
addCrateType( "c", "iw6_mts255_mp_barrelrange03_reflexshotgun", 5, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_MTS" );
addCrateType( "c", "iw6_fp6_mp_barrelrange03_reflexshotgun", 5, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_FP6" );
addCrateType( "c", "iw6_vepr_mp_grip", 5, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_VEPR" );
addCrateType( "c", "iw6_microtar_mp_eotechsmg", 5, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_MICRO" );
addCrateType( "c", "iw6_ak12_mp_flashsuppress_grip", 12, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_AK" );
addCrateType( "c", "iw6_arx160_mp_flashsuppress_hybrid", 12, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_ARX" );
addCrateType( "c", "iw6_m27_mp_flashsuppress_hybrid", 0, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_M27" );
addCrateType( "c", "iw6_kac_mp_flashsuppress", 0, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_KAC" );
addCrateType( "c", "iw6_usr_mp_usrvzscope_xmags", 6, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_USR" );
addCrateType( "c", "iw6_magnumhorde_mp_fmj", 0, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_WEST" );
addCrateType( "c", "throwingknife_mp", 2, ::hordeCrateLethalThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_KNIFE" );
addCrateType( "c", "specialty_lightweight", 0, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_LIGHT" );
addCrateType( "c", "specialty_fastreload", 12, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_FAST" );
addCrateType( "c", "specialty_quickdraw", 0, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_QIUCK" );
addCrateType( "c", "specialty_marathon", 0, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_MARA" );
addCrateType( "c", "specialty_quickswap", 0, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_SWAP" );
addCrateType( "c", "specialty_bulletaccuracy", 12, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_AIM" );
addCrateType( "c", "specialty_fastsprintrecovery", 0, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_READY" );
addCrateType( "c", "_specialty_blastshield", 12, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_BLAST" );
addCrateType( "c", "specialty_stalker", 0, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_STALK" );
addCrateType( "c", "specialty_sharp_focus", 0, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_FOCUS" );
addCrateType( "c", "specialty_regenfaster", 12, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_HEALTH" );
addCrateType( "c", "specialty_sprintreload", 0, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_GO" );
addCrateType( "c", "specialty_triggerhappy", 0, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_TRIGGER" );
addCrateType( "c", "ammo", 0, ::hordeCrateAmmoThink, friendly_crate_model, enemy_crate_model, &"HORDE_AMMO" );
addCrateType( "d", "iw6_mts255_mp_barrelrange03_reflexshotgun", 5, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_MTS" );
addCrateType( "d", "iw6_fp6_mp_barrelrange03_reflexshotgun", 5, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_FP6" );
addCrateType( "d", "iw6_vepr_mp_grip", 5, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_VEPR" );
addCrateType( "d", "iw6_microtar_mp_eotechsmg", 5, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_MICRO" );
addCrateType( "d", "iw6_ak12_mp_flashsuppress_grip", 5, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_AK" );
addCrateType( "d", "iw6_arx160_mp_flashsuppress_hybrid", 5, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_ARX" );
addCrateType( "d", "iw6_m27_mp_flashsuppress_hybrid", 10, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_M27" );
addCrateType( "d", "iw6_kac_mp_flashsuppress", 10, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_KAC" );
addCrateType( "d", "iw6_usr_mp_usrvzscope_xmags", 5, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_USR" );
addCrateType( "d", "iw6_magnumhorde_mp_fmj", 0, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_WEST" );
addCrateType( "d", "throwingknife_mp", 2, ::hordeCrateLethalThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_KNIFE" );
addCrateType( "d", "specialty_lightweight", 3, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_LIGHT" );
addCrateType( "d", "specialty_fastreload", 4, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_FAST" );
addCrateType( "d", "specialty_quickdraw", 3, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_QIUCK" );
addCrateType( "d", "specialty_marathon", 4, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_MARA" );
addCrateType( "d", "specialty_quickswap", 3, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_SWAP" );
addCrateType( "d", "specialty_bulletaccuracy", 4, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_AIM" );
addCrateType( "d", "specialty_fastsprintrecovery", 3, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_READY" );
addCrateType( "d", "_specialty_blastshield", 4, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_BLAST" );
addCrateType( "d", "specialty_stalker", 3, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_STALK" );
addCrateType( "d", "specialty_sharp_focus", 4, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_FOCUS" );
addCrateType( "d", "specialty_regenfaster", 4, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_HEALTH" );
addCrateType( "d", "specialty_sprintreload", 4, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_GO" );
addCrateType( "d", "specialty_triggerhappy", 0, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_TRIGGER" );
addCrateType( "d", "ammo", 0, ::hordeCrateAmmoThink, friendly_crate_model, enemy_crate_model, &"HORDE_AMMO" );
addCrateType( "e", "iw6_mts255_mp_barrelrange03_reflexshotgun", 4, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_MTS" );
addCrateType( "e", "iw6_fp6_mp_barrelrange03_reflexshotgun", 4, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_FP6" );
addCrateType( "e", "iw6_vepr_mp_grip", 4, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_VEPR" );
addCrateType( "e", "iw6_microtar_mp_eotechsmg", 4, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_MICRO" );
addCrateType( "e", "iw6_ak12_mp_flashsuppress_grip", 4, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_AK" );
addCrateType( "e", "iw6_arx160_mp_flashsuppress_hybrid", 4, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_ARX" );
addCrateType( "e", "iw6_m27_mp_flashsuppress_hybrid", 9, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_M27" );
addCrateType( "e", "iw6_kac_mp_flashsuppress", 9, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_KAC" );
addCrateType( "e", "iw6_usr_mp_usrvzscope_xmags", 5, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_USR" );
addCrateType( "e", "iw6_magnumhorde_mp_fmj", 3, ::hordeCrateWeaponThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_WEST" );
addCrateType( "e", "throwingknife_mp", 2, ::hordeCrateLethalThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_KNIFE" );
addCrateType( "e", "specialty_lightweight", 4, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_LIGHT" );
addCrateType( "e", "specialty_fastreload", 4, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_FAST" );
addCrateType( "e", "specialty_quickdraw", 4, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_QIUCK" );
addCrateType( "e", "specialty_marathon", 4, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_MARA" );
addCrateType( "e", "specialty_quickswap", 4, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_SWAP" );
addCrateType( "e", "specialty_bulletaccuracy", 4, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_AIM" );
addCrateType( "e", "specialty_fastsprintrecovery", 4, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_READY" );
addCrateType( "e", "_specialty_blastshield", 4, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_BLAST" );
addCrateType( "e", "specialty_stalker", 4, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_STALK" );
addCrateType( "e", "specialty_sharp_focus", 4, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_FOCUS" );
addCrateType( "e", "specialty_regenfaster", 4, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_HEALTH" );
addCrateType( "e", "specialty_sprintreload", 4, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_GO" );
addCrateType( "e", "specialty_triggerhappy", 3, ::hordeCratePerkThink, friendly_crate_model, enemy_crate_model, &"HORDE_DOUBLE_TAP_TRIGGER" );
addCrateType( "e", "ammo", 0, ::hordeCrateAmmoThink, friendly_crate_model, enemy_crate_model, &"HORDE_AMMO" );
setupLootCrates( friendly_crate_model, enemy_crate_model );
}
setupLootCrates( friendly_crate_model, enemy_crate_model )
{
// Drop Type Type Weight Function Friendly Model Enemy Model Hint String
addCrateType( "loot", "ims", 15, ::killstreakCrateThinkHorde, friendly_crate_model, enemy_crate_model, &"KILLSTREAKS_HINTS_IMS_PICKUP" );
addCrateType( "loot", "helicopter", 15, ::killstreakCrateThinkHorde, friendly_crate_model, enemy_crate_model, &"KILLSTREAKS_HINTS_HELICOPTER_PICKUP" );
addCrateType( "loot", "drone_hive", 15, ::killstreakCrateThinkHorde, friendly_crate_model, enemy_crate_model, &"KILLSTREAKS_HINTS_DRONE_HIVE_PICKUP" );
addCrateType( "loot", "sentry", 15, ::killstreakCrateThinkHorde, friendly_crate_model, enemy_crate_model, &"KILLSTREAKS_HINTS_SENTRY_PICKUP" );
addCrateType( "loot", "heli_sniper", 15, ::killstreakCrateThinkHorde, friendly_crate_model, enemy_crate_model, &"KILLSTREAKS_HINTS_HELI_SNIPER_PICKUP" );
addCrateType( "loot", "ball_drone_backup", 15, ::killstreakCrateThinkHorde, friendly_crate_model, enemy_crate_model, &"KILLSTREAKS_HINTS_BALL_DRONE_BACKUP_PICKUP" );
}
hordeCrateWeaponThink( dropType )
{
self endon ( "death" );
self endon ( "doubleTap" );
self endon( "restarting_physics" );
if( !IsDefined(self.doubleTapCount) )
self.doubleTapCount = 0;
crateHint = game["strings"][self.crateType + "_hint"];
self thread doubleTapThink();
self crateSetupForUse( crateHint, level.hordeIcon[self.crateType] );
self thread crateAllCaptureThinkHorde( CONST_AIR_DROP_USE_TIME );
setCrateLooksBasedOnTap( self );
level thread removeOnNextAirDrop( self );
while( true )
{
self waittill ( "captured", player );
tryGiveHordeWeapon( player, self.crateType );
self deleteCrate();
}
}
tryGiveHordeWeapon( player, weaponName )
{
player playLocalSound( "ammo_crate_use" );
weaponList = [];
weaponListTemp = player GetWeaponsListPrimaries();
baseWeaponName = GetWeaponBaseName( weaponName );
foreach( weaponHeld in weaponListTemp )
{
if( weaponHeld == level.intelMiniGun )
continue;
weaponList[weaponList.size] = weaponHeld;
}
if( weaponList.size > 1 )
{
removeWeapon = true;
foreach( weaponInList in weaponList )
{
if( weaponName == weaponInList )
removeWeapon = false;
}
if( removeWeapon )
{
replaceWeapon = player GetCurrentPrimaryWeapon();
if( replaceWeapon == "none" )
replaceWeapon = player getLastWeapon();
if( !player HasWeapon( replaceWeapon ) || (replaceWeapon == level.intelMiniGun) )
replaceWeapon = player maps\mp\killstreaks\_killstreaks::getFirstPrimaryWeapon();
player TakeWeapon( replaceWeapon );
}
else
{
player GiveMaxAmmo( weaponName );
// give weapon level
barSize = player.weaponState[ baseWeaponName ]["barSize"];
player.weaponState[ baseWeaponName ]["vaule"] = barSize;
player notify( "weaponPointsEarned" );
}
}
createHordeWeaponState( player, baseWeaponName, true );
player _giveWeapon( weaponName );
player SwitchToWeaponImmediate( weaponName );
}
hordeCratePerkThink( dropType )
{
self endon ( "death" );
self endon ( "doubleTap" );
self endon( "restarting_physics" );
if( !IsDefined(self.doubleTapCount) )
self.doubleTapCount = 0;
crateHint = game["strings"][self.crateType + "_hint"];
self thread doubleTapThink();
self crateSetupForUse( crateHint, level.hordeIcon[self.crateType] );
self thread crateAllCaptureThinkHorde( CONST_AIR_DROP_USE_TIME );
setCrateLooksBasedOnTap( self );
level thread removeOnNextAirDrop( self );
while( true )
{
self waittill ( "captured", player );
player playLocalSound( "ammo_crate_use" );
if( !player _hasPerk(self.crateType) )
{
perk = self.crateType;
player givePerk( perk, false );
// create HUD icon
perkTableIndex = TableLookup( "mp/hordeIcons.csv", 1, perk, 0 );
player SetClientOmnvar( "ui_horde_update_perk", int(perkTableIndex) );
// record current perk list
numPerks = player.horde_perks.size;
player.horde_perks[numPerks]["name"] = perk;
player.horde_perks[numPerks]["index"] = int(perkTableIndex);
}
self deleteCrate();
}
}
hordeCrateLethalThink( dropType )
{
self endon ( "death" );
self endon ( "doubleTap" );
self endon( "restarting_physics" );
if( !IsDefined(self.doubleTapCount) )
self.doubleTapCount = 0;
crateHint = game["strings"][self.crateType + "_hint"];
self thread doubleTapThink();
self crateSetupForUse( crateHint, level.hordeIcon[self.crateType] );
self thread crateAllCaptureThinkHorde( CONST_AIR_DROP_USE_TIME );
setCrateLooksBasedOnTap( self );
level thread removeOnNextAirDrop( self );
while( true )
{
self waittill ( "captured", player );
player playLocalSound( "ammo_crate_use" );
if( !player HasWeapon(self.crateType) )
{
currentOffHand = player GetCurrentOffhand();
player TakeWeapon( currentOffHand );
player givePerkEquipment( self.crateType, true );
}
else
{
player GiveMaxAmmo( self.crateType );
}
self deleteCrate();
}
}
hordeCrateAmmoThink( dropType )
{
self endon ( "death" );
self endon( "restarting_physics" );
crateHint = game["strings"][self.crateType + "_hint"];
crateSetupForUse( crateHint, level.hordeIcon[self.crateType] );
self thread crateAllCaptureThinkHorde( CONST_LOOT_DROP_USE_TIME );
self.friendlyModel HudOutlineEnable( CONST_STAGE_1_OUTLINE, false );
self.outlineColor = CONST_STAGE_1_OUTLINE;
level thread removeOnNextAirDrop( self );
while( true )
{
self waittill ( "captured", player );
player playLocalSound( "ammo_crate_use" );
level thread refillAmmoHorde( player );
self deleteCrate();
}
}
killstreakCrateThinkHorde( dropType )
{
self endon ( "death" );
self endon( "restarting_physics" );
crateHint = game["strings"][self.crateType + "_hint"];
crateSetupForUse( crateHint, getKillstreakOverheadIcon( self.crateType ) );
self thread crateAllCaptureThinkHorde( CONST_LOOT_DROP_USE_TIME );
setCrateLook( self, 3, (0.157, 0.784, 0.784) );
while( true )
{
self waittill ( "captured", player );
if( !IsPlayer(player) )
continue;
slotNumber = getSlotNumber( player );
if( !IsDefined(slotNumber) )
continue;
player playLocalSound( "ammo_crate_use" );
player thread maps\mp\killstreaks\_killstreaks::giveKillstreak( self.crateType, false, false, self.owner, slotNumber );
self deleteCrate();
}
}
getSlotNumber( player )
{
slotNumber = undefined;
for( i = KILLSTREAK_SLOT_1; i < KILLSTREAK_SLOT_3 + 1; i++ )
{
self_pers_killstreak_i = player.pers["killstreaks"][i];
if( !IsDefined( self_pers_killstreak_i ) || !IsDefined( self_pers_killstreak_i.streakName ) || self_pers_killstreak_i.available == false )
{
slotNumber = i;
break;
}
}
return slotNumber;
}
crateAllCaptureThinkHorde( useTime )
{
// this function should not end on death because useHoldThink needs to clean itself up
self endon ( "doubleTap" );
self endon( "restarting_physics" );
if( !IsDefined(useTime) )
useTime = 500;
while ( IsDefined( self ) )
{
self MakeUsable();
self waittill ( "trigger", player );
if( handleAgentUse(player) )
continue;
if( handleKillStreakLimit(player) )
continue;
if ( !self validateOpenConditions(player) )
continue;
self MakeUnusable();
player.isCapturingCrate = true;
if ( !useHoldThink( player, useTime ) )
{
player.isCapturingCrate = false;
continue;
}
player.isCapturingCrate = false;
awardHordeCrateUsed( player );
self notify ( "captured", player );
}
}
handleKillStreakLimit( player )
{
if( (self.dropType == "loot") && !IsDefined( getSlotNumber(player) ) )
{
player SetClientOmnvar( "ui_killstreak_limit", 1 );
return true;
}
return false;
}
handleAgentUse( player )
{
if( !IsPlayer(player) )
{
if( IsDefined(player.disablePlayerUseEnt) )
player.disablePlayerUseEnt EnablePlayerUse( player );
player.disablePlayerUseEnt = self;
self DisablePlayerUse( player );
return true;
}
return false;
}
monitorDoubleTap( player )
{
player endon( "disconnect" );
buttonTime = 0;
while( true )
{
if( player UseButtonPressed() )
{
buttonTime = 0;
while ( player UseButtonPressed() )
{
buttonTime += 0.05;
wait( 0.05 );
}
if ( buttonTime >= 0.5 )
continue;
buttonTime = 0;
while ( !player UseButtonPressed() && buttonTime < 0.5 )
{
buttonTime += 0.05;
wait( 0.05 );
}
if ( buttonTime >= 0.5 )
continue;
level notify( "doubleTap", player );
}
wait( 0.05 );
}
}
doubleTapThink()
{
self endon( "death" );
self endon( "capture" );
self endon( "restarting_physics" );
maxDistanceSq = 128 * 128;
// small delay before allowing a double tap twice in a row
if( self.doubleTapCount > 0 )
wait( 1.0 );
while( true )
{
level waittill( "doubleTap", player );
if( isPlayerInLastStand(player) )
continue;
if( !isReallyAlive(player) )
continue;
if( IsDefined(self.inUse) && self.inUse )
continue;
if( Distance2DSquared(player.origin, self.origin ) < maxDistanceSq )
{
self notify( "doubleTap" );
self newRandomCrate();
break;
}
}
}
newRandomCrate()
{
self.doubleTapCount++;
playSoundAtPos( self.origin, "mp_killconfirm_tags_drop" );
if(self.doubleTapCount > 1 )
{
crateType = "ammo";
}
else
{
originalWeight = level.crateTypes[ self.dropType ][ self.crateType ].raw_weight;
changeCrateWeight( self.dropType, self.crateType, 0 );
crateType = getRandomCrateTypeHorde( self.dropType );
changeCrateWeight( self.dropType, self.crateType, originalWeight );
}
self.crateType = crateType;
// setup new crate
self thread [[ level.crateTypes[ self.dropType ][ self.crateType ].func ]]( self.dropType );
}
runLootDrop()
{
dropType = "loot";
dropNum = 8;
crateOffest = RandomInt( level.crateTypes["loot"].size );
createSpawnHeight = (0,0,75);
/#
if( IsDefined(level.spawnMaxCrates) )
dropNum = level.hordeDropLocations.size;
#/
if( !level.carePackages.size )
sortDropLocations();
for( i = 0; i < dropNum; i++ )
{
dropLocation = level.hordeDropLocations[ level.dropLocationIndex ];
groundLocation = getFinalDropLocation( dropLocation.traceLocation );
// player was blocking the spawn location
if( !IsDefined(groundLocation) )
{
level.dropLocationIndex = getNextDropLocationIndex( level.dropLocationIndex );
continue;
}
startPos = groundLocation;
crateType = getCrateTypeForLootDrop( crateOffest + i );
dropCrate = level.players[0] createAirDropCrate( level.players[0], dropType, crateType, startPos + createSpawnHeight, startPos, 3 );
dropCrate.angles = (0,0,0);
dropCrate.droppingToGround = true;
dropCrate.friendlyModel hide();
wait(0.05);
dropCrate thread waitForDropCrateMsg( dropCrate, (RandomInt(25),RandomInt(25),RandomInt(25)), dropType, crateType, 800, true);
//level thread lootCrateEffect( dropCrate );
level thread removeAtRoundEnd( dropCrate );
level.dropLocationIndex = getNextDropLocationIndex( level.dropLocationIndex );
wait(0.05);
PlayFX( level._effect["crate_teleport"], dropCrate.origin, ( 0, 0, 1 ) );
PlaySoundAtPos( dropCrate.origin, "crate_teleport_safeguard" );
dropCrate.friendlyModel show();
}
}
lootCrateEffect( crate )
{
crate waittill( "physics_finished" );
dropEffect = SpawnFx( level._effect[ "loot_crtae" ], crate.origin - (0,0,16) );
TriggerFX( dropEffect );
crate waittill_any_timeout_no_endon_death( level.specialRoundTime, "death" );
dropEffect Delete();
}
getFinalDropLocation( groundLocation )
{
if( !isPlayerNearLocation(groundLocation) )
return groundLocation;
pathNodeArray = GetNodesInRadiusSorted( groundLocation, 256, 64, 128, "Path" );
foreach( pathNode in pathNodeArray )
{
if( !isPlayerNearLocation(pathNode.origin) )
return pathNode.origin;
}
return undefined;
}
isPlayerNearLocation( groundLocation )
{
pickNewLocation = false;
foreach( player in level.participants )
{
distSquared = Distance2DSquared( player.origin, groundLocation );
if( distSquared < (64 * 64) )
{
pickNewLocation = true;
break;
}
}
return pickNewLocation;
}
getCrateTypeForLootDrop( index )
{
while( index >= level.crateTypes["loot"].size )
{
index = index - level.crateTypes["loot"].size;
}
lootKeys = GetArrayKeys( level.crateTypes["loot"] );
type = level.crateTypes["loot"][ lootKeys[index] ].type;
return type;
}
removeOnNextAirDrop( dropCrate )
{
dropCrate endon( "death" );
dropCrate endon( "doubleTap" );
dropCrate endon( "restarting_physics" );
level waittill( "airSupport" );
while( IsDefined(dropCrate.inUse) && dropCrate.inUse )
{
waitframe();
}
dropCrate deleteCrate();
}
removeAtRoundEnd( dropCrate )
{
dropCrate endon( "death" );
level waittill( "round_ended" );
while( IsDefined(dropCrate.inUse) && dropCrate.inUse )
{
waitframe();
}
dropCrate deleteCrate();
}
getRandomCrateTypeHorde( dropType )
{
numPowerWeapons = getNumPowerWeapons();
value = RandomInt( level.crateMaxVal[ dropType ] );
selectedCrateType = undefined;
foreach( crateType in level.crateTypes[ dropType ] )
{
type = crateType.type;
if( !level.crateTypes[ dropType ][ type ].weight )
continue;
if( !canPickCrate( type, numPowerWeapons) )
continue;
selectedCrateType = type;
if( level.crateTypes[ dropType ][ type ].weight > value )
{
break;
}
}
return( selectedCrateType );
}
CONST_POWER_GUN = "iw6_magnumhorde_mp_fmj";
CONST_POWER_PERK = "specialty_triggerhappy";
CONST_POWER_LIMIT = 2;
getNumPowerWeapons()
{
numPowerWeapons = 0;
foreach( player in level.players )
{
if( !isOnHumanTeam(player) )
continue;
if( player HasWeapon( CONST_POWER_GUN ) )
numPowerWeapons++;
if( player _hasPerk( CONST_POWER_PERK ) )
numPowerWeapons++;
}
carePackages = getEntArray( "care_package", "targetname" );
foreach( crate in carePackages )
{
if( crate.crateType == CONST_POWER_GUN )
numPowerWeapons++;
if( crate.crateType == CONST_POWER_PERK )
numPowerWeapons++;
}
return numPowerWeapons;
}
isPowerWeapon( crateType )
{
return ( (crateType == CONST_POWER_GUN) || (crateType == CONST_POWER_PERK) );
}
canPickCrate( crateType, numPowerWeapons )
{
if( isPowerWeapon(crateType) && (numPowerWeapons >= CONST_POWER_LIMIT) )
return false;
return true;
}
setCrateLook( crate, outlineNum, HUDColor )
{
crate.friendlyModel HudOutlineEnable( outlineNum, false );
crate.outlineColor = outlineNum;
foreach( icon in crate.entityHeadIcons )
icon.color = HUDColor;
}
setCrateLooksBasedOnTap( crate )
{
if( crate.doubleTapCount == 0 )
{
setCrateLook( crate, CONST_STAGE_0_OUTLINE, CONST_STAGE_0_COLOR );
}
else
{
setCrateLook( crate, CONST_STAGE_1_OUTLINE, CONST_STAGE_1_COLOR );
}
}

View File

@ -0,0 +1,472 @@
#include common_scripts\utility;
#include maps\mp\_utility;
#include maps\mp\gametypes\_hud_util;
#include maps\mp\gametypes\_horde_util;
CONST_LAST_STAND_TIME = 25;
CONST_LAST_STAND_COLOR = (0.804, 0.804, 0.035);
CONST_REVIVE_ENT_VERTICAL_OFFSET = ( 0, 0, 20 );
/#
CONST_FORCE_LAST_STAND = false;
#/
Callback_PlayerLastStandHorde( eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration )
{
self registerLastStandParameter( eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc );
if( gameShouldEnd( self ) )
{
self.useLastStandParams = true;
self _suicide();
hordeEndGame();
return;
}
if( !mayDoLastStandHorde( self ) )
{
self.useLastStandParams = true;
self _suicide();
return;
}
self.inLastStand = true;
self.lastStand = true;
self.ignoreme = true;
self.health = 1;
self HudOutlineEnable( 1, false );
self _disableUsability();
self thread lastStandReviveHorde();
}
gameShouldEnd( player )
{
/#
if( CONST_FORCE_LAST_STAND )
return false;
#/
isAnyPlayerStillActive = false;
foreach( activePlayer in level.participants )
{
if( (player == activePlayer) && !hasAgentSquadMember(player) )
continue;
if( !isOnHumanTeam(activePlayer) )
continue;
if( isPlayerInLastStand(activePlayer) && !hasAgentSquadMember(activePlayer))
continue;
if( !IsDefined(activePlayer.sessionstate) || (activePlayer.sessionstate != "playing") )
continue;
isAnyPlayerStillActive = true;
break;
}
return !isAnyPlayerStillActive;
}
hordeEndGame()
{
level.finalKillCam_winner = level.enemyTeam;
level thread maps\mp\gametypes\_gamelogic::endGame( level.enemyTeam , game[ "end_reason" ][ level.playerTeam+"_eliminated" ] );
}
mayDoLastStandHorde( player )
{
/#
if( CONST_FORCE_LAST_STAND )
return true;
#/
if( player touchingBadTrigger() )
return false;
return true;
}
registerLastStandParameter( eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc )
{
lastStandParams = spawnStruct();
lastStandParams.eInflictor = eInflictor;
lastStandParams.attacker = attacker;
lastStandParams.iDamage = iDamage;
lastStandParams.attackerPosition = attacker.origin;
lastStandParams.sMeansOfDeath = sMeansOfDeath;
lastStandParams.sWeapon = sWeapon;
lastStandParams.vDir = vDir;
lastStandParams.sHitLoc = sHitLoc;
lastStandParams.lastStandStartTime = getTime();
if( IsDefined( attacker ) && IsPlayer( attacker ) && (attacker getCurrentPrimaryWeapon() != "none") )
lastStandParams.sPrimaryWeapon = attacker getCurrentPrimaryWeapon();
else
lastStandParams.sPrimaryWeapon = undefined;
self.lastStandParams = lastStandParams;
}
lastStandReviveHorde()
{
self endon( "death" );
self endon( "disconnect" );
self endon( "revive");
level endon( "game_ended" );
level notify ( "player_last_stand" );
self notify( "force_cancel_placement" );
level thread playSoundToAllPlayers( "mp_safe_team_last_stand" );
level thread leaderDialog( "ally_down", level.playerTeam, "status" );
level thread perkPenalty( self );
self thread lastStandWaittillDeathHorde();
self thread lastStandAmmoWacher();
self thread lastStandKeepOverlayHorde();
// create revive ent
reviveEnt = spawn( "script_model", self.origin );
reviveEnt setModel( "tag_origin" );
reviveEnt setCursorHint( "HINT_NOICON" );
reviveEnt setHintString( &"PLATFORM_REVIVE" );
reviveEnt makeUsable();
reviveEnt.inUse = false;
reviveEnt.curProgress = 0;
reviveEnt.useTime = level.lastStandUseTime;
reviveEnt.useRate = 1;
reviveEnt.id = "last_stand";
reviveEnt.targetname = "revive_trigger";
reviveEnt.owner = self;
reviveEnt linkTo( self, "tag_origin", CONST_REVIVE_ENT_VERTICAL_OFFSET, (0,0,0) );
reviveEnt thread maps\mp\gametypes\_damage::deleteOnReviveOrDeathOrDisconnect();
// create revive HUD icon
reviveIcon = newTeamHudElem( self.team );
reviveIcon setShader( "waypoint_revive", 8, 8 );
reviveIcon setWaypoint( true, true );
reviveIcon SetTargetEnt( self );
reviveIcon.color = (0.33, 0.75, 0.24);
reviveIcon thread maps\mp\gametypes\_damage::destroyOnReviveEntDeath( reviveEnt );
self thread lastStandUpdateReviveIconColorHorde( reviveEnt, reviveIcon, CONST_LAST_STAND_TIME );
// create the bleed out timer
self thread lastStandTimerHorde( CONST_LAST_STAND_TIME, reviveEnt );
// wait to be revived
reviveEnt thread reviveTriggerThinkHorde();
reviveEnt thread lastStandWaittillLifeRecived();
reviveEnt endon ( "death" );
wait( CONST_LAST_STAND_TIME );
while( IsDefined(reviveEnt.inUse) && reviveEnt.inUse )
{
waitframe();
}
level thread leaderDialog( "ally_dead", level.playerTeam, "status" );
self HudOutlineDisable();
self _suicide();
}
reviveTriggerThinkHorde()
{
self endon ( "death" );
level endon ( "game_ended" );
while( true )
{
self makeUsable();
self waittill ( "trigger", player );
self makeUnUsable();
self.curProgress = 0;
self.inUse = true;
self.owner.beingRevived = true;
player freezecontrols( true );
player _disableWeapon();
player.isReviving = true;
result = maps\mp\gametypes\_damage::useHoldThinkLoop( player );
self.inUse = false;
if( IsDefined( self.owner ) ) // self.owner could be undefined if the player being revived disconnects during the revive
{
self.owner.beingRevived = false;
}
if( IsDefined( player ) && isReallyAlive( player ) )
{
player freezecontrols( false );
player _enableWeapon();
player.isReviving = false;
if( IsDefined( result ) && result ) // result will be undefined if the player being revived disconnected
{
player thread maps\mp\gametypes\_hud_message::SplashNotifyDelayed( "horde_reviver" );
player thread maps\mp\perks\_perkfunctions::setLightArmor( 850 );
if( IsPlayer(player) )
{
awardHordeRevive( player );
}
else if( IsDefined(player.owner) && IsPlayer(player.owner) && (player.owner != self.owner) )
{
// increment a player's revive stat when his agent revives another player
awardHordeRevive( player.owner );
}
}
if( !IsDefined( result ) )
{
player maps\mp\gametypes\_gameobjects::updateUIProgress( self, false ); // clear the "reviving" bar because that player disconnected
}
}
if( IsDefined( result ) && result )
{
self.owner notify ( "revive_trigger", player );
break;
}
}
}
lastStandWaittillLifeRecived()
{
self endon( "death" );
self endon( "game_ended" );
player = self.owner;
player waittill( "revive_trigger", reviver );
if ( IsDefined( reviver ) && IsPlayer( reviver ) && reviver != player )
player thread maps\mp\gametypes\_hud_message::playerCardSplashNotify( "revived", reviver );
player lastStandRespawnPlayerHorde( self );
}
lastStandRespawnPlayerHorde( reviveEnt )
{
self notify ( "revive" );
self.lastStand = undefined;
self.inLastStand = false;
self.headicon = "";
self.health = self.maxHealth;
self.moveSpeedScaler = 1;
self.ignoreme = false;
self.beingRevived = false;
if( self _hasPerk( "specialty_lightweight" ) )
{
self.moveSpeedScaler = lightWeightScalar();
}
self HudOutlineDisable();
self LastStandRevive();
self setStance( "crouch" );
self _enableUsability();
self maps\mp\gametypes\_weapons::updateMoveSpeedScale();
self clearLowerMessage( "last_stand" );
self givePerk( "specialty_pistoldeath", false );
if( !CanSpawn(self.origin) )
{
maps\mp\_movers::unresolved_collision_nearest_node( self, false );
}
reviveEnt delete();
}
lastStandWaittillDeathHorde()
{
self endon( "disconnect" );
self endon( "revive" );
level endon( "game_ended" );
self waittill( "death" );
self.lastStand = undefined;
self.inLastStand = false;
self.ignoreme = false;
}
lastStandKeepOverlayHorde()
{
self endon( "death" );
self endon( "disconnect" );
self endon( "revive" );
level endon( "game_ended" );
// keep the health overlay going by making code think the player is getting damaged
while( true )
{
self.health = 2;
waitframe();
self.health = 1;
waitframe();
}
}
lastStandUpdateReviveIconColorHorde( reviveEnt, reviveIcon, bleedOutTime )
{
self endon( "death" );
self endon( "disconnect" );
self endon( "revive" );
level endon( "game_ended" );
reviveEnt endon( "death" );
self playDeathSound();
wait bleedOutTime / 3;
reviveIcon.color = (1.0, 0.64, 0.0);
while ( reviveEnt.inUse )
wait ( 0.05 );
self playDeathSound();
wait bleedOutTime / 3;
reviveIcon.color = (1.0, 0.0, 0.0);
while ( reviveEnt.inUse )
wait ( 0.05 );
self playDeathSound();
}
lastStandTimerHorde( bleedOutTime, reviveEnt )
{
self endon( "disconnect" );
timer_offset = 90;
if ( !issplitscreen() )
timer_offset = 135;
timer = self maps\mp\gametypes\_hud_util::createTimer( "hudsmall", 1.0 );
timer maps\mp\gametypes\_hud_util::setPoint( "CENTER", undefined, 0, timer_offset );
timer.label = &"MP_HORDE_BLEED_OUT";
timer.color = CONST_LAST_STAND_COLOR;
timer.archived = false;
timer.showInKillcam = false;
timer setTimer( bleedOutTime - 1 );
reviveEnt waittill ( "death" );
if( !IsDefined(timer) )
return;
timer notify( "destroying" );
timer destroyElem();
}
lastStandAmmoWacher()
{
self endon( "death" );
self endon( "disconnect" );
self endon( "revive" );
level endon( "game_ended" );
while( true )
{
wait( 1.5 );
currentWeapon = self GetCurrentPrimaryWeapon();
if( !maps\mp\gametypes\_weapons::isPrimaryWeapon( currentWeapon ) )
continue;
ammoStock = self GetWeaponAmmoStock( currentWeapon );
clipSize = WeaponClipSize( currentWeapon );
if( ammoStock < clipSize )
self setWeaponAmmoStock( currentWeapon, clipSize );
}
}
perkPenalty( player )
{
player endon( "disconnect" );
level endon( "game_ended" );
if( !IsPlayer(player) )
return;
while( isPlayerInLastStand(player) && (player.horde_perks.size > 0) )
{
// Grab the perk name and index
perkName = player.horde_perks[player.horde_perks.size - 1]["name"];
perkTableIndex = player.horde_perks[player.horde_perks.size - 1]["index"];
player thread flashPerk( perkTableIndex );
result = player waittill_any_return_no_endon_death( "remove_perk", "death", "revive" );
if( result == "death" )
return;
if( result == "revive" )
{
if ( IsDefined( player.flashingPerkIndex ) )
{
// See if we are already flashing the perk before we tell it to stop
if( player.flashingPerkIndex == perkTableIndex )
{
// Sending the index tells LUI to stop flashing the perk, if it was previously flashing
player SetClientOmnvar( "ui_horde_update_perk", perkTableIndex );
player.flashingPerkIndex = undefined;
}
}
return;
}
if( result == "remove_perk" )
{
// Sending back a negative index tells LUI to remove the existing perk
player SetClientOmnvar( "ui_horde_update_perk", perkTableIndex * -1 );
player _unsetPerk( perkName );
// Make sure we remove it from the array
player.horde_perks = array_remove_perk( player.horde_perks, perkName );
}
}
}
array_remove_perk ( perkArray, perkName )
{
newPerkArray = [];
foreach( subArray in perkArray )
{
if ( subArray["name"] != perkName )
newPerkArray[ newPerkArray.size ] = subArray;
}
return newPerkArray;
}
flashPerk( perkTableIndex )
{
self endon ("death");
self endon ("revive");
wait(0.5);
// Sending the index tells LUI to start flashing, if it was previously created
self SetClientOmnvar( "ui_horde_update_perk", perkTableIndex );
self.flashingPerkIndex = perkTableIndex;
wait(8);
self notify( "remove_perk" );
}

View File

@ -0,0 +1,240 @@
#include common_scripts\utility;
#include maps\mp\_utility;
#include maps\mp\gametypes\_hud_util;
isPlayerInLastStand( player )
{
return ( IsDefined(player.lastStand) && player.lastStand );
}
isOnHumanTeam( player )
{
return ( player.team == level.playerTeam );
}
getNumPlayers()
{
numPlayers = 0;
if( !IsDefined(level.players) )
return 0;
foreach( player in level.players )
{
if( isOnHumanTeam(player) )
numPlayers++;
}
return numPlayers;
}
isSpecialRound( roundNumber )
{
if( !IsDefined(roundNumber) )
roundNumber = level.currentRoundNumber;
if( !level.enableSpecialRound )
return false;
if( (roundNumber % 5) == 1 )
return true;
return false;
}
isDogRound()
{
return (level.chanceToSpawnDog > 0);
}
showTeamSplashHorde( splash )
{
foreach( teamMate in level.players )
{
if ( isOnHumanTeam(teamMate) && isReallyAlive(teamMate) )
teamMate thread maps\mp\gametypes\_hud_message::SplashNotify( splash );
}
}
hasAgentSquadMember( player )
{
hasAgentSquadMember = false;
if( IsAgent(player) )
return hasAgentSquadMember;
foreach( killstreak in player.pers["killstreaks"] )
{
if( IsDefined(killstreak) && IsDefined(killstreak.streakName) && killstreak.available && (killstreak.streakName == "agent") )
{
hasAgentSquadMember = true;
break;
}
}
return hasAgentSquadMember;
}
getPlayerWeaponHorde( player )
{
weaponName = player GetCurrentPrimaryWeapon();
if( IsDefined(player.changingWeapon) )
weaponName = player.changingWeapon;
if( !maps\mp\gametypes\_weapons::isPrimaryWeapon(weaponName) )
weaponName = player getLastWeapon();
if( !player HasWeapon( weaponName ) )
weaponName = player maps\mp\killstreaks\_killstreaks::getFirstPrimaryWeapon();
return weaponName;
}
playSoundToAllPlayers( soundName )
{
level endon( "game_ended" );
foreach( player in level.players )
{
if( !isReallyAlive(player) )
continue;
if( !isOnHumanTeam(player) )
continue;
player PlaySoundToPlayer( soundName, player );
}
}
refillAmmoHorde( player )
{
weaponList = player GetWeaponsListAll();
foreach( weaponName in weaponList )
{
player giveMaxAmmo( weaponName );
if( weaponName == level.intelMiniGun )
{
clipSize = WeaponClipSize( level.intelMiniGun );
player SetWeaponAmmoClip( level.intelMiniGun, clipSize );
}
}
}
/#
hordeShowDropLocations()
{
SetDevDvarIfUninitialized( "scr_hordeGiveIntelReward", "0" );
SetDevDvarIfUninitialized( "scr_hordeGiveWeaponLevel", "0" );
while( true )
{
if( GetDvarInt( "scr_hordeShowDropLocations" ) > 0)
{
foreach( dropLocation in level.hordeDropLocations )
drawDropLocation( dropLocation );
}
if( GetDvarInt( "scr_hordeGiveIntelReward" ) > 0 )
{
SetDevDvar( "scr_hordeGiveIntelReward", 0 );
level thread maps\mp\gametypes\_intelchallenges::intelTeamReward( level.playerTeam );
}
if( GetDvarInt( "scr_hordeGiveWeaponLevel" ) > 0 )
{
SetDevDvar( "scr_hordeGiveWeaponLevel", 0 );
foreach( player in level.players )
{
weaponName = getPlayerWeaponHorde( player );
baseWeaponName = GetWeaponBaseName( weaponName );
if( maps\mp\gametypes\horde::hasWeaponState(player, baseWeaponName) )
{
barSize = player.weaponState[ baseWeaponName ]["barSize"];
player.weaponState[ baseWeaponName ]["vaule"] = barSize;
player notify( "weaponPointsEarned" );
}
}
}
wait(0.05);
}
}
drawDropLocation( dropLocation )
{
color = (0.804, 0.804, 0.035);
center = dropLocation.origin - (0,0,12);
forward = (32, 0, 0);
right = (0, 16, 0);
height = (0, 0, 32);
a = center + forward - right;
b = center + forward + right;
c = center - forward + right;
d = center - forward - right;
line(a, b, color, 0);
line(b, c, color, 0);
line(c, d, color, 0);
line(d, a, color, 0);
line(a, a + height, color, 0);
line(b, b + height, color, 0);
line(c, c + height, color, 0);
line(d, d + height, color, 0);
a = a + height;
b = b + height;
c = c + height;
d = d + height;
line(a, b, color, 0);
line(b, c, color, 0);
line(c, d, color, 0);
line(d, a, color, 0);
print3d(center + height, "Air Drop", color, 1, 1);
}
#/
awardHordeKill( player )
{
player maps\mp\gametypes\_persistence::statSetChild( "round", "squardKills", player.killz + 1 ); // update stats before capping the value
player.killz = int( min( player.killz + 1, 999 ) ); // "Kills" values are capped in code/hud at 999, so cap here to keep parity.
player.kills = player.killz;
player setPersStat( "hordeKills", player.killz );
}
awardHordeRevive( player )
{
player maps\mp\gametypes\_persistence::statSetChild( "round", "squardRevives", player.numRevives + 1 ); // update stats before capping the value
player.numRevives = int( min( player.numRevives + 1, 999 ) ); // "assists" values are capped in code/hud at 999, so cap here to keep parity.
player.assists = player.numRevives;
player setPersStat( "hordeRevives", player.numRevives );
}
awardHordeCrateUsed( player )
{
player maps\mp\gametypes\_persistence::statSetChild( "round", "squardCrates", player.numCrtaesCaptured + 1 ); // update stats before capping the value
player.numCrtaesCaptured = int( min( player.numCrtaesCaptured + 1, 999 ) ); // "extrascore0" values are capped in code at 1023 and 999 in hud, so cap here to keep parity.
player setExtraScore0( player.numCrtaesCaptured );
player setPersStat( "hordeCrates", player.numCrtaesCaptured );
}
awardHordeRoundNumber( player, value )
{
player maps\mp\gametypes\_persistence::statSetChild( "round", "sguardWave", value );
player setPersStat( "hordeRound", value );
}
awardHordWeaponLevel( player, value )
{
player maps\mp\gametypes\_persistence::statSetChild( "round", "sguardWeaponLevel", value );
player setPersStat( "hordeWeapon", value );
}

View File

@ -0,0 +1,260 @@
#include maps\mp\_utility;
#include common_scripts\utility;
Callback_HostMigration()
{
if ( is_aliens() )
{
SetNoJIPTime( true );
}
level.hostMigrationReturnedPlayerCount = 0;
if ( level.gameEnded )
{
println( "Migration starting at time " + gettime() + ", but game has ended, so no countdown." );
return;
}
println( "Migration starting at time " + gettime() );
foreach ( character in level.characters )
character.hostMigrationControlsFrozen = false;
level.hostMigrationTimer = true;
setDvar( "ui_inhostmigration", 1 );
level notify( "host_migration_begin" );
maps\mp\gametypes\_gamelogic::UpdateTimerPausedness();
foreach ( character in level.characters )
{
character thread hostMigrationTimerThink();
if ( IsPlayer( character ) )
{
// reset client dvars
character SetClientOmnvar( "ui_session_state", character.sessionstate );
}
}
// reset game state
SetDvar( "ui_game_state", game[ "state" ] );
level endon( "host_migration_begin" );
hostMigrationWait();
level.hostMigrationTimer = undefined;
setDvar( "ui_inhostmigration", 0 );
println( "Migration finished at time " + gettime() );
level notify( "host_migration_end" );
maps\mp\gametypes\_gamelogic::UpdateTimerPausedness();
level thread maps\mp\gametypes\_gamelogic::updateGameEvents();
if( ( GetDvar( "squad_use_hosts_squad" ) == "1" ) )
{
level thread maps\mp\gametypes\_menus::update_wargame_after_migration();
}
}
hostMigrationWait()
{
level endon( "game_ended" );
// start with a 20 second wait.
// once we get enough players, or the first 15 seconds pass, switch to a 5 second timer.
level.inGracePeriod = 25;
thread maps\mp\gametypes\_gamelogic::matchStartTimer( "waiting_for_players", 20.0 );
hostMigrationWaitForPlayers();
level.inGracePeriod = 10;
thread maps\mp\gametypes\_gamelogic::matchStartTimer( "match_resuming_in", 5.0 );
wait 5;
level.inGracePeriod = false;
}
hostMigrationWaitForPlayers()
{
level endon( "hostmigration_enoughplayers" );
wait 15;
}
hostMigrationName( ent )
{
if ( !IsDefined( ent ) )
return "<removed_ent>";
entNum = -1;
entName = "?";
if ( IsDefined( ent.entity_number ) )
entNum = ent.entity_number;
if ( isPlayer( ent ) && IsDefined( ent.name ) )
entName = ent.name;
if ( isPlayer( ent ) )
return "player <" + entName + ">";
if ( IsAgent( ent ) && IsGameParticipant( ent ) )
return "participant agent <" + entNum + ">";
if ( IsAgent( ent ) )
return "non-participant agent <" + entNum + ">";
return "unknown entity <" + entNum + ">";
}
hostMigrationTimerThink_Internal()
{
level endon( "host_migration_begin" );
level endon( "host_migration_end" );
assertex( IsDefined( self.hostMigrationControlsFrozen ), "Not properly tracking controller frozen for " + hostMigrationName( self ) );
while ( !isReallyAlive( self ) )
{
self waittill( "spawned" );
}
println( "Migration freezing controls for " + hostMigrationName( self ) + " with hostMigrationControlsFrozen = " + self.hostMigrationControlsFrozen );
self.hostMigrationControlsFrozen = true;
self freezeControlsWrapper( true );
level waittill( "host_migration_end" );
}
hostMigrationTimerThink()
{
self endon( "disconnect" );
assertex( IsDefined( self.hostMigrationControlsFrozen ), "Not properly tracking controller frozen for " + hostMigrationName( self ) );
if ( IsPlayer( self ) )
self setClientDvar( "cg_scoreboardPingGraph", "0" );
hostMigrationTimerThink_Internal();
assertex( IsDefined( self.hostMigrationControlsFrozen ), "Attempted to unfreeze controls for " + hostMigrationName( self ) );
println( "Migration attempting to unfreeze controls for " + hostMigrationName( self ) + " with hostMigrationControlsFrozen = " + self.hostMigrationControlsFrozen );
if ( self.hostMigrationControlsFrozen )
{
// make sure we aren't in prematch still before we unfreeze controls because prematch wants them frozen and will unfreeze when done
if( gameFlag( "prematch_done" ) )
self freezeControlsWrapper( false );
self.hostMigrationControlsFrozen = undefined;
}
if ( IsPlayer( self ) )
self setClientDvar( "cg_scoreboardPingGraph", "1" );
}
waitTillHostMigrationDone()
{
if ( !isDefined( level.hostMigrationTimer ) )
return 0;
starttime = gettime();
level waittill( "host_migration_end" );
return gettime() - starttime;
}
waitTillHostMigrationStarts( duration )
{
if ( isDefined( level.hostMigrationTimer ) )
return;
level endon( "host_migration_begin" );
wait duration;
}
waitLongDurationWithHostMigrationPause( duration )
{
if ( duration == 0 )
return;
assert( duration > 0 );
starttime = gettime();
endtime = gettime() + duration * 1000;
while ( gettime() < endtime )
{
waitTillHostMigrationStarts( (endtime - gettime()) / 1000 );
if ( isDefined( level.hostMigrationTimer ) )
{
timePassed = waitTillHostMigrationDone();
endtime += timePassed;
}
}
waitTillHostMigrationDone();
return gettime() - starttime;
}
waittill_notify_or_timeout_hostmigration_pause( msg, duration )
{
self endon( msg );
if ( duration == 0 )
return;
assert( duration > 0 );
starttime = gettime();
endtime = gettime() + duration * 1000;
while ( gettime() < endtime )
{
waitTillHostMigrationStarts( (endtime - gettime()) / 1000 );
if ( isDefined( level.hostMigrationTimer ) )
{
timePassed = waitTillHostMigrationDone();
endtime += timePassed;
}
}
waitTillHostMigrationDone();
return gettime() - starttime;
}
waitLongDurationWithGameEndTimeUpdate( duration )
{
if ( duration == 0 )
return;
assert( duration > 0 );
starttime = gettime();
endtime = gettime() + duration * 1000;
while ( gettime() < endtime )
{
waitTillHostMigrationStarts( (endtime - gettime()) / 1000 );
while ( isDefined( level.hostMigrationTimer ) )
{
endTime += 1000;
setGameEndTime( int( endTime ) );
wait 1;
}
}
while ( isDefined( level.hostMigrationTimer ) )
{
endTime += 1000;
setGameEndTime( int( endTime ) );
wait 1;
}
return gettime() - starttime;
}

149
maps/mp/gametypes/_hud.gsc Normal file
View File

@ -0,0 +1,149 @@
/*
// Edge relative placement values for rect->h_align and rect->v_align
#define HORIZONTAL_ALIGN_SUBLEFT 0 // left edge of a 4:3 screen (safe area not included)
#define HORIZONTAL_ALIGN_LEFT 1 // left viewable (safe area) edge
#define HORIZONTAL_ALIGN_CENTER 2 // center of the screen (reticle)
#define HORIZONTAL_ALIGN_RIGHT 3 // right viewable (safe area) edge
#define HORIZONTAL_ALIGN_FULLSCREEN 4 // disregards safe area
#define HORIZONTAL_ALIGN_NOSCALE 5 // uses exact parameters - neither adjusts for safe area nor scales for screen size
#define HORIZONTAL_ALIGN_TO640 6 // scales a real-screen resolution x down into the 0 - 640 range
#define HORIZONTAL_ALIGN_CENTER_SAFEAREA 7 // center of the safearea
#define HORIZONTAL_ALIGN_MAX HORIZONTAL_ALIGN_CENTER_SAFEAREA
#define HORIZONTAL_ALIGN_DEFAULT HORIZONTAL_ALIGN_SUBLEFT
#define VERTICAL_ALIGN_SUBTOP 0 // top edge of the 4:3 screen (safe area not included)
#define VERTICAL_ALIGN_TOP 1 // top viewable (safe area) edge
#define VERTICAL_ALIGN_CENTER 2 // center of the screen (reticle)
#define VERTICAL_ALIGN_BOTTOM 3 // bottom viewable (safe area) edge
#define VERTICAL_ALIGN_FULLSCREEN 4 // disregards safe area
#define VERTICAL_ALIGN_NOSCALE 5 // uses exact parameters - neither adjusts for safe area nor scales for screen size
#define VERTICAL_ALIGN_TO480 6 // scales a real-screen resolution y down into the 0 - 480 range
#define VERTICAL_ALIGN_CENTER_SAFEAREA 7 // center of the save area
#define VERTICAL_ALIGN_MAX VERTICAL_ALIGN_CENTER_SAFEAREA
#define VERTICAL_ALIGN_DEFAULT VERTICAL_ALIGN_SUBTOP
static const char *g_he_font[] =
{
"default", // HE_FONT_DEFAULT
"bigfixed", // HE_FONT_BIGFIXED
"smallfixed", // HE_FONT_SMALLFIXED
"objective", // HE_FONT_OBJECTIVE
};
// These values correspond to the defines in q_shared.h
static const char *g_he_alignx[] =
{
"left", // HE_ALIGN_LEFT
"center", // HE_ALIGN_CENTER
"right", // HE_ALIGN_RIGHT
};
static const char *g_he_aligny[] =
{
"top", // HE_ALIGN_TOP
"middle", // HE_ALIGN_MIDDLE
"bottom", // HE_ALIGN_BOTTOM
};
// These values correspond to the defines in menudefinition.h
static const char *g_he_horzalign[] =
{
"subleft", // HORIZONTAL_ALIGN_SUBLEFT
"left", // HORIZONTAL_ALIGN_LEFT
"center", // HORIZONTAL_ALIGN_CENTER
"right", // HORIZONTAL_ALIGN_RIGHT
"fullscreen", // HORIZONTAL_ALIGN_FULLSCREEN
"noscale", // HORIZONTAL_ALIGN_NOSCALE
"alignto640", // HORIZONTAL_ALIGN_TO640
"center_safearea", // HORIZONTAL_ALIGN_CENTER_SAFEAREA
};
cassert( ARRAY_COUNT( g_he_horzalign ) == HORIZONTAL_ALIGN_MAX + 1 );
static const char *g_he_vertalign[] =
{
"subtop", // VERTICAL_ALIGN_SUBTOP
"top", // VERTICAL_ALIGN_TOP
"middle", // VERTICAL_ALIGN_CENTER
"bottom", // VERTICAL_ALIGN_BOTTOM
"fullscreen", // VERTICAL_ALIGN_FULLSCREEN
"noscale", // VERTICAL_ALIGN_NOSCALE
"alignto480", // VERTICAL_ALIGN_TO480
"center_safearea", // VERTICAL_ALIGN_CENTER_SAFEAREA
};
cassert( ARRAY_COUNT( g_he_vertalign ) == VERTICAL_ALIGN_MAX + 1 );
*/
init()
{
level.uiParent = spawnstruct();
level.uiParent.horzAlign = "left";
level.uiParent.vertAlign = "top";
level.uiParent.alignX = "left";
level.uiParent.alignY = "top";
level.uiParent.x = 0;
level.uiParent.y = 0;
level.uiParent.width = 0;
level.uiParent.height = 0;
level.uiParent.children = [];
level.fontHeight = 12;
level.hud["allies"] = spawnstruct();
level.hud["axis"] = spawnstruct();
// we can, of course, separate out the following constants for splitscreen.
// primary progress bars are for things like capturing flags or planting bombs - big, important things that happen as you play a gametype
level.primaryProgressBarY = -61; // from center
level.primaryProgressBarX = 0;
level.primaryProgressBarHeight = 9; //28; // this is the height and width of the whole progress bar, including the outline. the part that actually moves is 2 pixels smaller.
level.primaryProgressBarWidth = 120;
level.primaryProgressBarTextY = -75;
level.primaryProgressBarTextX = 0;
level.primaryProgressBarFontSize = 1.2; // 1.4 before font change from "objective"
level.teamProgressBarY = 32; // 205;
level.teamProgressBarHeight = 14;
level.teamProgressBarWidth = 192;
level.teamProgressBarTextY = 8; // 155;
level.teamProgressBarFontSize = 1.65;
level.lowerTextYAlign = "BOTTOM";
level.lowerTextY = -140;
level.lowerTextFontSize = 1.6;
}
fontPulseInit( maxFontScale )
{
self.baseFontScale = self.fontScale;
if ( isDefined( maxFontScale ) )
self.maxFontScale = min( maxFontScale, 6.3 );
else
self.maxFontScale = min( self.fontScale * 2, 6.3 );
self.inFrames = 2;
self.outFrames = 4;
}
fontPulse(player)
{
self notify ( "fontPulse" );
self endon ( "fontPulse" );
self endon( "death" );
player endon("disconnect");
player endon("joined_team");
player endon("joined_spectators");
self ChangeFontScaleOverTime( self.inFrames * 0.05 );
self.fontScale = self.maxFontScale;
wait self.inFrames * 0.05;
self ChangeFontScaleOverTime( self.outFrames * 0.05 );
self.fontScale = self.baseFontScale;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,942 @@
#include maps\mp\_utility;
setParent( element )
{
if ( isDefined( self.parent ) && self.parent == element )
return;
if ( isDefined( self.parent ) )
self.parent removeChild( self );
self.parent = element;
self.parent addChild( self );
if ( isDefined( self.point ) )
self setPoint( self.point, self.relativePoint, self.xOffset, self.yOffset );
else
self setPoint( "TOPLEFT" );
}
getParent()
{
return self.parent;
}
removeDestroyedChildren()
{
// No need to check this more than once per frame
if ( IsDefined( self.childCheckTime ) && self.childCheckTime == GetTime() )
return;
self.childCheckTime = GetTime();
newChildren = [];
foreach( i, child in self.children )
{
if ( !IsDefined( child ) )
continue;
child.index = newChildren.size;
newChildren[ newChildren.size ] = child;
}
self.children = newChildren;
}
addChild( element )
{
element.index = self.children.size;
self.children[self.children.size] = element;
// Nothing cleans up destroyed children in the array, so without this it will eventually pop
self removeDestroyedChildren();
}
removeChild( element )
{
element.parent = undefined;
if ( self.children[self.children.size-1] != element )
{
self.children[element.index] = self.children[self.children.size-1];
self.children[element.index].index = element.index;
}
self.children[self.children.size-1] = undefined;
element.index = undefined;
}
setPoint( point, relativePoint, xOffset, yOffset, moveTime )
{
if ( !isDefined( moveTime ) )
moveTime = 0;
element = self getParent();
if ( moveTime )
self moveOverTime( moveTime );
if ( !isDefined( xOffset ) )
xOffset = 0;
self.xOffset = xOffset;
if ( !isDefined( yOffset ) )
yOffset = 0;
self.yOffset = yOffset;
self.point = point;
self.alignX = "center";
self.alignY = "middle";
if ( isSubStr( point, "TOP" ) )
self.alignY = "top";
if ( isSubStr( point, "BOTTOM" ) )
self.alignY = "bottom";
if ( isSubStr( point, "LEFT" ) )
self.alignX = "left";
if ( isSubStr( point, "RIGHT" ) )
self.alignX = "right";
if ( !isDefined( relativePoint ) )
relativePoint = point;
self.relativePoint = relativePoint;
relativeX = "center_adjustable";
relativeY = "middle";
if ( isSubStr( relativePoint, "TOP" ) )
relativeY = "top_adjustable";
if ( isSubStr( relativePoint, "BOTTOM" ) )
relativeY = "bottom_adjustable";
if ( isSubStr( relativePoint, "LEFT" ) )
relativeX = "left_adjustable";
if ( isSubStr( relativePoint, "RIGHT" ) )
relativeX = "right_adjustable";
if ( element == level.uiParent )
{
self.horzAlign = relativeX;
self.vertAlign = relativeY;
}
else
{
self.horzAlign = element.horzAlign;
self.vertAlign = element.vertAlign;
}
if ( strip_suffix( relativeX, "_adjustable" ) == element.alignX )
{
offsetX = 0;
xFactor = 0;
}
else if ( relativeX == "center" || element.alignX == "center" )
{
offsetX = int(element.width / 2);
if ( relativeX == "left_adjustable" || element.alignX == "right" )
xFactor = -1;
else
xFactor = 1;
}
else
{
offsetX = element.width;
if ( relativeX == "left_adjustable" )
xFactor = -1;
else
xFactor = 1;
}
self.x = element.x + (offsetX * xFactor);
if ( strip_suffix( relativeY, "_adjustable" ) == element.alignY )
{
offsetY = 0;
yFactor = 0;
}
else if ( relativeY == "middle" || element.alignY == "middle" )
{
offsetY = int(element.height / 2);
if ( relativeY == "top_adjustable" || element.alignY == "bottom" )
yFactor = -1;
else
yFactor = 1;
}
else
{
offsetY = element.height;
if ( relativeY == "top_adjustable" )
yFactor = -1;
else
yFactor = 1;
}
self.y = element.y + (offsetY * yFactor);
self.x += self.xOffset;
self.y += self.yOffset;
switch ( self.elemType )
{
case "bar":
setPointBar( point, relativePoint, xOffset, yOffset );
break;
}
self updateChildren();
}
setPointBar( point, relativePoint, xOffset, yOffset )
{
self.bar.horzAlign = self.horzAlign;
self.bar.vertAlign = self.vertAlign;
self.bar.alignX = "left";
self.bar.alignY = self.alignY;
self.bar.y = self.y;
if ( self.alignX == "left" )
self.bar.x = self.x;
else if ( self.alignX == "right" )
self.bar.x = self.x - self.width;
else
self.bar.x = self.x - int(self.width / 2);
if ( self.alignY == "top" )
self.bar.y = self.y;
else if ( self.alignY == "bottom" )
self.bar.y = self.y;
self updateBar( self.bar.frac );
}
updateBar( barFrac, rateOfChange )
{
if ( self.elemType == "bar" )
updateBarScale( barFrac, rateOfChange );
}
updateBarScale( barFrac, rateOfChange ) // rateOfChange is optional and is in "(entire bar lengths) per second"
{
barWidth = int(self.width * barFrac + 0.5); // (+ 0.5 rounds)
if ( !barWidth )
barWidth = 1;
self.bar.frac = barFrac;
self.bar setShader( self.bar.shader, barWidth, self.height );
assertEx( barWidth <= self.width, "barWidth <= self.width: " + barWidth + " <= " + self.width + " - barFrac was " + barFrac );
//if barWidth is bigger than self.width then we are drawing more than 100%
if ( isDefined( rateOfChange ) && barWidth < self.width )
{
if ( rateOfChange > 0 )
{
//printLn( "scaling from: " + barWidth + " to " + self.width + " at " + ((1 - barFrac) / rateOfChange) );
assertex( ((1 - barFrac) / rateOfChange) > 0, "barFrac: " + barFrac + "rateOfChange: " + rateOfChange );
self.bar scaleOverTime( (1 - barFrac) / rateOfChange, self.width, self.height );
}
else if ( rateOfChange < 0 )
{
//printLn( "scaling from: " + barWidth + " to " + 0 + " at " + (barFrac / (-1 * rateOfChange)) );
assertex( (barFrac / (-1 * rateOfChange)) > 0, "barFrac: " + barFrac + "rateOfChange: " + rateOfChange );
self.bar scaleOverTime( barFrac / (-1 * rateOfChange), 1, self.height );
}
}
self.bar.rateOfChange = rateOfChange;
self.bar.lastUpdateTime = getTime();
}
createFontString( font, fontScale )
{
fontElem = newClientHudElem( self );
fontElem.elemType = "font";
fontElem.font = font;
fontElem.fontscale = fontScale;
fontElem.baseFontScale = fontScale;
fontElem.x = 0;
fontElem.y = 0;
fontElem.width = 0;
fontElem.height = int(level.fontHeight * fontScale);
fontElem.xOffset = 0;
fontElem.yOffset = 0;
fontElem.children = [];
fontElem setParent( level.uiParent );
fontElem.hidden = false;
return fontElem;
}
createServerFontString( font, fontScale, team )
{
if ( isDefined( team ) )
fontElem = newTeamHudElem( team );
else
fontElem = newHudElem();
fontElem.elemType = "font";
fontElem.font = font;
fontElem.fontscale = fontScale;
fontElem.baseFontScale = fontScale;
fontElem.x = 0;
fontElem.y = 0;
fontElem.width = 0;
fontElem.height = int(level.fontHeight * fontScale);
fontElem.xOffset = 0;
fontElem.yOffset = 0;
fontElem.children = [];
fontElem setParent( level.uiParent );
fontElem.hidden = false;
return fontElem;
}
createServerTimer( font, fontScale, team )
{
if ( isDefined( team ) )
timerElem = newTeamHudElem( team );
else
timerElem = newHudElem();
timerElem.elemType = "timer";
timerElem.font = font;
timerElem.fontScale = fontScale;
timerElem.baseFontScale = fontScale;
timerElem.x = 0;
timerElem.y = 0;
timerElem.width = 0;
timerElem.height = int(level.fontHeight * fontScale);
timerElem.xOffset = 0;
timerElem.yOffset = 0;
timerElem.children = [];
timerElem setParent( level.uiParent );
timerElem.hidden = false;
return timerElem;
}
createTimer( font, fontScale )
{
timerElem = newClientHudElem( self );
timerElem.elemType = "timer";
timerElem.font = font;
timerElem.fontScale = fontScale;
timerElem.baseFontScale = fontScale;
timerElem.x = 0;
timerElem.y = 0;
timerElem.width = 0;
timerElem.height = int(level.fontHeight * fontScale);
timerElem.xOffset = 0;
timerElem.yOffset = 0;
timerElem.children = [];
timerElem setParent( level.uiParent );
timerElem.hidden = false;
return timerElem;
}
createIcon( shader, width, height )
{
iconElem = newClientHudElem( self );
iconElem.elemType = "icon";
iconElem.x = 0;
iconElem.y = 0;
iconElem.width = width;
iconElem.height = height;
iconElem.baseWidth = iconElem.width;
iconElem.baseHeight = iconElem.height;
iconElem.xOffset = 0;
iconElem.yOffset = 0;
iconElem.children = [];
iconElem setParent( level.uiParent );
iconElem.hidden = false;
if ( isDefined( shader ) )
{
iconElem setShader( shader, width, height );
iconElem.shader = shader;
}
return iconElem;
}
createServerIcon( shader, width, height, team )
{
if ( isDefined( team ) )
iconElem = newTeamHudElem( team );
else
iconElem = newHudElem();
iconElem.elemType = "icon";
iconElem.x = 0;
iconElem.y = 0;
iconElem.width = width;
iconElem.height = height;
iconElem.baseWidth = iconElem.width;
iconElem.baseHeight = iconElem.height;
iconElem.xOffset = 0;
iconElem.yOffset = 0;
iconElem.children = [];
iconElem setParent( level.uiParent );
iconElem.hidden = false;
if ( isDefined( shader ) )
{
iconElem setShader( shader, width, height );
iconElem.shader = shader;
}
return iconElem;
}
createServerBar( color, width, height, flashFrac, team, selected )
{
if ( isDefined( team ) )
barElem = newTeamHudElem( team );
else
barElem = newHudElem();
barElem.x = 0;
barElem.y = 0;
barElem.frac = 0;
barElem.color = color;
barElem.sort = -2;
barElem.shader = "progress_bar_fill";
barElem setShader( "progress_bar_fill", width, height );
barElem.hidden = false;
if ( isDefined( flashFrac ) )
{
barElem.flashFrac = flashFrac;
// barElem thread flashThread();
}
if ( isDefined( team ) )
barElemBG = newTeamHudElem( team );
else
barElemBG = newHudElem();
barElemBG.elemType = "bar";
barElemBG.x = 0;
barElemBG.y = 0;
barElemBG.width = width;
barElemBG.height = height;
barElemBG.xOffset = 0;
barElemBG.yOffset = 0;
barElemBG.bar = barElem;
barElemBG.children = [];
barElemBG.sort = -3;
barElemBG.color = (0,0,0);
barElemBG.alpha = 0.5;
barElemBG setParent( level.uiParent );
barElemBG setShader( "progress_bar_bg", width, height );
barElemBG.hidden = false;
return barElemBG;
}
createBar( color, width, height, flashFrac )
{
barElem = newClientHudElem( self );
barElem.x = 0 ;
barElem.y = 0;
barElem.frac = 0;
barElem.color = color;
barElem.sort = -2;
barElem.shader = "progress_bar_fill";
barElem setShader( "progress_bar_fill", width, height );
barElem.hidden = false;
if ( isDefined( flashFrac ) )
{
barElem.flashFrac = flashFrac;
// barElem thread flashThread();
}
barElemBG = newClientHudElem( self );
barElemBG.elemType = "bar";
barElemBG.width = width;
barElemBG.height = height;
barElemBG.xOffset = 0;
barElemBG.yOffset = 0;
barElemBG.bar = barElem;
barElemBG.children = [];
barElemBG.sort = -3;
barElemBG.color = (0,0,0);
barElemBG.alpha = 0.5;
barElemBG setParent( level.uiParent );
barElemBG setShader( "progress_bar_bg", width + 4, height + 4 );
barElemBG.hidden = false;
return barElemBG;
}
getCurrentFraction()
{
frac = self.bar.frac;
if (isdefined(self.bar.rateOfChange))
{
frac += (getTime() - self.bar.lastUpdateTime) * self.bar.rateOfChange;
if (frac > 1) frac = 1;
if (frac < 0) frac = 0;
}
return frac;
}
createPrimaryProgressBar( xOffset, yOffset )
{
if( IsAgent(self) )
return undefined;
if ( !isDefined( xOffset ) )
xOffset = 0;
if ( !isDefined( yOffset ) )
yOffset = -25; // purposely defaulting to -25
if( self isSplitscreenPlayer() )
yOffset += 20;
bar = createBar( (1, 1, 1), level.primaryProgressBarWidth, level.primaryProgressBarHeight );
bar setPoint("CENTER", undefined, level.primaryProgressBarX + xOffset, level.primaryProgressBarY + yOffset );
return bar;
}
createPrimaryProgressBarText( xOffset, yOffset,fontsize, usefont )
{
if( IsAgent(self) )
return undefined;
if ( !isDefined( xOffset ) )
xOffset = 0;
if ( !isDefined( yOffset ) )
yOffset = -25; // purposely defaulting to -25
if( self isSplitscreenPlayer() )
yOffset += 20;
font_size = level.primaryProgressBarFontSize;
font = "default";
if ( isDefined ( fontsize ) )
font_size = fontsize;
if ( isDefined ( usefont ) )
font = usefont;
text = createFontString( font, font_size );
text setPoint("CENTER", undefined, level.primaryProgressBarTextX + xOffset, level.primaryProgressBarTextY + yOffset );
text.sort = -1;
return text;
}
createTeamProgressBar( team )
{
bar = createServerBar( (1,0,0), level.teamProgressBarWidth, level.teamProgressBarHeight, undefined, team );
bar setPoint("TOP", undefined, 0, level.teamProgressBarY);
return bar;
}
createTeamProgressBarText( team )
{
text = createServerFontString( "default", level.teamProgressBarFontSize, team );
text setPoint("TOP", undefined, 0, level.teamProgressBarTextY);
return text;
}
setFlashFrac( flashFrac )
{
self.bar.flashFrac = flashFrac;
}
hideElem()
{
if ( self.hidden )
return;
self.hidden = true;
if ( self.alpha != 0 )
self.alpha = 0;
if ( self.elemType == "bar" || self.elemType == "bar_shader" )
{
self.bar.hidden = true;
if ( self.bar.alpha != 0 )
self.bar.alpha = 0;
}
}
showElem()
{
if ( !self.hidden )
return;
self.hidden = false;
if ( self.elemType == "bar" || self.elemType == "bar_shader" )
{
if ( self.alpha != .5 )
self.alpha = .5;
self.bar.hidden = false;
if ( self.bar.alpha != 1 )
self.bar.alpha = 1;
}
else
{
if ( self.alpha != 1 )
self.alpha = 1;
}
}
flashThread()
{
self endon ( "death" );
if ( !self.hidden )
self.alpha = 1;
while(1)
{
if ( self.frac >= self.flashFrac )
{
if ( !self.hidden )
{
self fadeOverTime(0.3);
self.alpha = .2;
wait(0.35);
self fadeOverTime(0.3);
self.alpha = 1;
}
wait(0.7);
}
else
{
if ( !self.hidden && self.alpha != 1 )
self.alpha = 1;
wait ( 0.05 );
}
}
}
destroyElem()
{
tempChildren = [];
for ( index = 0; index < self.children.size; index++ )
{
if ( isDefined( self.children[index] ) )
tempChildren[tempChildren.size] = self.children[index];
}
for ( index = 0; index < tempChildren.size; index++ )
tempChildren[index] setParent( self getParent() );
if ( self.elemType == "bar" || self.elemType == "bar_shader" )
{
self.bar destroy();
}
self destroy();
}
setIconShader( shader )
{
self setShader( shader, self.width, self.height );
self.shader = shader;
}
getIconShader( shader )
{
return self.shader;
}
setIconSize( width, height )
{
assert( isDefined( self.shader ) );
self setShader( self.shader, width, height );
}
setWidth( width )
{
self.width = width;
}
setHeight( height )
{
self.height = height;
}
setSize( width, height )
{
self.width = width;
self.height = height;
}
updateChildren()
{
for ( index = 0; index < self.children.size; index++ )
{
child = self.children[index];
child setPoint( child.point, child.relativePoint, child.xOffset, child.yOffset );
}
}
transitionReset()
{
self.x = self.xOffset;
self.y = self.yOffset;
if ( self.elemType == "font" )
{
self.fontScale = self.baseFontScale;
self.label = &"";
}
else if ( self.elemType == "icon" )
{
//self scaleOverTime( 0.001, self.width, self.height );
self setShader( self.shader, self.width, self.height );
}
self.alpha = 0;
}
transitionZoomIn( duration )
{
switch ( self.elemType )
{
case "font":
case "timer":
self.fontScale = 6.3;
self changeFontScaleOverTime( duration );
self.fontScale = self.baseFontScale;
break;
case "icon":
self setShader( self.shader, self.width * 6, self.height * 6 );
self scaleOverTime( duration, self.width, self.height );
break;
}
}
transitionPulseFXIn( inTime, duration )
{
transTime = int(inTime)*1000;
showTime = int(duration)*1000;
switch ( self.elemType )
{
case "font":
case "timer":
self setPulseFX( transTime+250, showTime+transTime, transTime+250 );
break;
default:
break;
}
}
transitionSlideIn( duration, direction )
{
if ( !isDefined( direction ) )
direction = "left";
switch ( direction )
{
case "left":
self.x += 1000;
break;
case "right":
self.x -= 1000;
break;
case "up":
self.y -= 1000;
break;
case "down":
self.y += 1000;
break;
}
self moveOverTime( duration );
self.x = self.xOffset;
self.y = self.yOffset;
}
transitionSlideOut( duration, direction )
{
if ( !isDefined( direction ) )
direction = "left";
gotoX = self.xOffset;
gotoY = self.yOffset;
switch ( direction )
{
case "left":
gotoX += 1000;
break;
case "right":
gotoX -= 1000;
break;
case "up":
gotoY -= 1000;
break;
case "down":
gotoY += 1000;
break;
}
self.alpha = 1;
self moveOverTime( duration );
self.x = gotoX;
self.y = gotoY;
}
transitionZoomOut( duration )
{
switch ( self.elemType )
{
case "font":
case "timer":
self changeFontScaleOverTime( duration );
self.fontScale = 6.3;
case "icon":
self scaleOverTime( duration, self.width * 6, self.height * 6 );
break;
}
}
transitionFadeIn( duration )
{
self fadeOverTime( duration );
if ( isDefined( self.maxAlpha ) )
self.alpha = self.maxAlpha;
else
self.alpha = 1;
}
transitionFadeOut( duration )
{
self fadeOverTime( 0.15 );
self.alpha = 0;
}
getWeeklyRef( chRef )
{
for ( chIndex = 0; chIndex < 3; chIndex++ )
{
weeklyId = self GetRankedPlayerData( "weeklyChallengeId", chIndex );
weeklyRef = tableLookupByRow( "mp/weeklyChallengesTable.csv", weeklyId, 0 );
if ( weeklyRef == chRef )
return "ch_weekly_" + chIndex;
}
return "";
}
getDailyRef( chRef )
{
for ( chIndex = 0; chIndex < 3; chIndex++ )
{
dailyId = self GetRankedPlayerData( "dailyChallengeId", chIndex );
dailyRef = tableLookupByRow( "mp/dailyChallengesTable.csv", dailyId, 0 );
if ( dailyRef == chRef )
return "ch_daily_" + chIndex;
}
return "";
}
ch_getProgress( refString )
{
if ( level.challengeInfo[refString]["type"] == 0 )
return self GetRankedPlayerData( "challengeProgress", refString );
else if ( level.challengeInfo[refString]["type"] == 1 )
return self GetRankedPlayerData( "challengeProgress", getDailyRef( refString ) );
else if ( level.challengeInfo[refString]["type"] == 2 )
return self GetRankedPlayerData( "challengeProgress", getWeeklyRef( refString ) );
}
ch_getState( refString )
{
if ( level.challengeInfo[refString]["type"] == 0 )
return self GetRankedPlayerData( "challengeState", refString );
else if ( level.challengeInfo[refString]["type"] == 1 )
return self GetRankedPlayerData( "challengeState", getDailyRef( refString ) );
else if ( level.challengeInfo[refString]["type"] == 2 )
return self GetRankedPlayerData( "challengeState", getWeeklyRef( refString ) );
}
ch_setProgress( refString, value )
{
if ( level.challengeInfo[refString]["type"] == 0 )
return self setRankedPlayerData( "challengeProgress", refString, value );
else if ( level.challengeInfo[refString]["type"] == 1 )
return self setRankedPlayerData( "challengeProgress", getDailyRef( refString ), value );
else if ( level.challengeInfo[refString]["type"] == 2 )
return self setRankedPlayerData( "challengeProgress", getWeeklyRef( refString ), value );
}
ch_setState( refString, value )
{
if ( level.challengeInfo[refString]["type"] == 0 )
return self setRankedPlayerData( "challengeState", refString, value );
else if ( level.challengeInfo[refString]["type"] == 1 )
return self setRankedPlayerData( "challengeState", getDailyRef( refString ), value );
else if ( level.challengeInfo[refString]["type"] == 2 )
return self setRankedPlayerData( "challengeState", getWeeklyRef( refString ), value );
}
ch_getTarget( refString, state )
{
if ( level.challengeInfo[refString]["type"] == 0 )
return int( tableLookup( "mp/allChallengesTable.csv", 0, refString, 9 + ((state-1)*2) ) );
else if ( level.challengeInfo[refString]["type"] == 1 )
return int( tableLookup( "mp/dailyChallengesTable.csv", 0, refString, 9 + ((state-1)*2) ) );
else if ( level.challengeInfo[refString]["type"] == 2 )
return int( tableLookup( "mp/weeklyChallengesTable.csv", 0, refString, 9 + ((state-1)*2) ) );
}
ch_isActiveChallenge( refString )
{
numActiveChallenges = 5;
if ( level.challengeInfo[refString]["type"] == 0 )
{
for( i = 0; i < numActiveChallenges; i++ )
{
activeCh = self GetRankedPlayerData( "activeChallenges", i );
if ( activeCh == refString )
return true;
}
}
else if ( level.challengeInfo[refString]["type"] == 1 )
return true;
else if ( level.challengeInfo[refString]["type"] == 2 )
return true;
return false;
}

View File

@ -0,0 +1,678 @@
#include common_scripts\utility;
#include maps\mp\_utility;
#include maps\mp\gametypes\_hud_util;
INTEL_MODEL_NAME = "com_metal_briefcase_intel";
INTEL_ANIM_NAME = "mp_briefcase_spin";
init()
{
level thread populateIntelChallenges();
level.intelActive = false;
if( !IsDefined(level.supportIntel) || level.supportIntel )
level thread onPlayerConnect();
if( IsDefined(level.enableTeamIntel) && IsDefined(level.enableTeamIntel) )
level thread runTeamIntel();
/#
SetDevDvarIfUninitialized( "scr_devIntelChallengeName", "temp" );
SetDevDvarIfUninitialized( "scr_devIntelChallengeNum", -1 );
#/
}
populateIntelChallenges()
{
level endon ( "game_ended" );
wait(0.05);
level.intelChallengeArray = [];
checkAvailability = ( level.gameType == "sd" || level.gameType == "sr" );
rowIndex = 0;
while( true )
{
challengeName = TableLookupByRow( "mp/intelChallenges.csv", rowIndex, 0 );
challengeReward = int( TableLookupByRow( "mp/intelChallenges.csv", rowIndex, 2 ) );
challengeTarget = int( TableLookupByRow( "mp/intelChallenges.csv", rowIndex, 3 ) );
available = int( TableLookupByRow( "mp/intelChallenges.csv", rowIndex, 4 ) ) == 1;
teamChallenge = int( TableLookupByRow( "mp/intelChallenges.csv", rowIndex, 5 ) ) == 1;
juggChallenge = int( TableLookupByRow( "mp/intelChallenges.csv", rowIndex, 6 ) ) == 1;
rowIndex++;
if( challengeName == "" )
break;
if( checkAvailability && !available )
continue;
level.intelChallengeArray[ challengeName ] = SpawnStruct();
level.intelChallengeArray[ challengeName ].challengeName = challengeName;
level.intelChallengeArray[ challengeName ].challengeReward = challengeReward;
level.intelChallengeArray[ challengeName ].challengeTarget = challengeTarget;
level.intelChallengeArray[ challengeName ].teamChallenge = teamChallenge;
level.intelChallengeArray[ challengeName ].juggChallenge = juggChallenge;
}
}
runTeamIntel()
{
level endon ( "game_ended" );
level.numMeleeKillsIntel = 0;
level.numHeadShotsIntel = 0;
level.numKillStreakKillsIntel = 0;
level.numEquipmentKillsIntel = 0;
while( true )
{
level waittill( "giveTeamIntel", team );
validChallengesArray = [];
foreach( challenge in level.intelChallengeArray )
{
if( !challenge.teamChallenge )
continue;
validChallengesArray[ validChallengesArray.size ] = challenge;
}
randChallenge = validChallengesArray[ RandomInt( validChallengesArray.size ) ];
challengeNameIndex = randChallenge.challengeName;
/#
devChallengeNum = GetDvarInt( "scr_devIntelChallengeNum" );
if( devChallengeNum != -1 )
{
randChallenge = validChallengesArray[ devChallengeNum ];
challengeNameIndex = randChallenge.challengeName;
}
#/
level maps\mp\gametypes\_intelchallenges::giveTeamChallenge( challengeNameIndex, team );
}
}
onPlayerConnect()
{
for(;;)
{
level waittill( "connected", player );
player thread intelDeathWatcher();
}
}
intelDeathWatcher( player ) // self == player
{
level endon ( "game_ended" );
self endon( "disconnect" );
for ( ;; )
{
self waittill( "death", attacker );
if ( IsDefined( self.hasIntel ) && self.hasIntel )
{
if ( ( IsDefined( self.OnHeliSniper ) && self.OnHeliSniper ) || self.sessionstate == "spectator" )
{
self.hasIntel = false;
level thread randAssignIntel();
}
else
{
self onDropIntel();
}
}
else if ( !level.intelActive )
{
if ( level.teamBased && IsDefined( attacker ) && IsDefined( attacker.team ) && attacker.team == self.team )
continue;
level.intelActive = true;
self onDropIntel( true );
}
}
}
CONST_INTEL_TRIG_RADIUS = 96;
CONST_INTEL_TRIG_RADIUS_EXIT = 192;
CONST_INTEL_TRIG_HEIGHT = 60;
onDropIntel( first_drop ) // self == player
{
self.hasIntel = false;
if ( !IsDefined( first_drop ) )
first_drop = false;
pos = self.origin;
// in the case the player kills themselves and the remote killstreak simultaneously store a new death position
// self.deathPosition gets cleared in playerlogic before this if check
if( IsDefined( self.intelDeathPosition ) )
{
pos = self.intelDeathPosition;
self.intelDeathPosition = undefined;
}
new_origin = GetGroundPosition( pos, 42, 1000, 72 );
pos_model = pos + ( 0, 0, 32 );
if( first_drop )
{
intelCase = Spawn( "script_model", pos_model );
intelCase.angles = (0,0,0);
intelCase SetModel( INTEL_MODEL_NAME );
intelTrigger = Spawn( "trigger_radius", pos, 0, CONST_INTEL_TRIG_RADIUS, CONST_INTEL_TRIG_HEIGHT );
intelTrigger.id = "intel";
intelEnt = [];
intelEnt["visuals"] = intelCase;
intelEnt["trigger"] = intelTrigger;
intelEnt["owner"] = "none";
intelEnt["isActive"] = true;
intelEnt["firstTriggerPlayer"] = undefined;
intelEnt["useRate"] = 1;
intelEnt["useTime"] = 0.5;
intelEnt["useProgress"] = 0;
intelEnt["dropped_time"] = GetTime();
level.intelEnt = intelEnt;
level.intelEnt["trigger"] EnableLinkTo();
}
// not the first drop
else
{
if( IsDefined( level.intelEnt["visuals"] GetLinkedParent() ) )
{
level.intelEnt["visuals"] Unlink();
level.intelEnt["trigger"] Unlink();
}
// Hide intel while moving to fix issue where intel
// would slide from the previous position to the new
// position.
level.intelEnt["visuals"] Hide();
level.intelEnt["visuals"].origin = pos_model;
level.intelEnt["trigger"].origin = new_origin;
}
// rand assign if touching bad trigger
if( level.intelEnt["visuals"] touchingBadTrigger() )
{
level.intelEnt["isActive"] = false;
level.intelEnt["visuals"] Hide();
level thread randAssignIntel();
return;
}
level.intelEnt["owner"] = "none";
level.intelEnt["isActive"] = true;
level.intelEnt["dropped_time"] = GetTime();
level.intelEnt["visuals"] ScriptModelPlayAnim( INTEL_ANIM_NAME );
// start trigger watcher
self thread intelTriggerWatcher();
// start emergency respawn timer if players cant pick it up
level.intelEnt thread intelEmergencyRespawnTimer();
}
intelDeathOverride( data )
{
level.intelEnt["isActive"] = false;
level.intelEnt["visuals"] Hide();
level thread randAssignIntel();
}
intelTriggerWatcher() // self == player
{
level notify ( "intelTriggerWatcher" );
level endon ( "intelTriggerWatcher" );
level endon( "game_ended" );
level.intelEnt["visuals"] endon( "pickedUp" );
intelTrigger = level.intelEnt["trigger"];
// Handle moving platform.
data = SpawnStruct();
data.linkparent = self GetMovingPlatformParent();
data.endonString = "intelTriggerWatcher";
data.deathOverrideCallback = ::intelDeathOverride;
level.intelEnt["visuals"] thread maps\mp\_movers::handle_moving_platforms( data );
level.intelEnt["trigger"] LinkTo( level.intelEnt["visuals"] );
wait 0.05;
// Now that a frame has passed show the intel. Fix for
// intel sliding across the level
level.intelEnt["visuals"] Show();
for( ;; )
{
intelTrigger waittill( "trigger", player );
if ( !IsPlayer(player) )
continue;
if ( isAI( player ) )
continue;
if ( !isAlive( player ) || ( isDefined( player.fauxDead ) && player.fauxDead ) )
{
//there is a time when you kill your self with remote that this will pass
// FIX for 56302 - commenting out the wait, players cannot pick up a briefcase if the owner is in a remote killstreak
//wait( .25 );
continue;
}
if ( level.intelEnt["isActive"] )
{
if ( isDefined( player.hasIntel ) && player.hasIntel )
continue;
//blocking call
result = intelTrigger proximityThink( player );
if( result )
player onPickupIntel();
}
}
}
intelEmergencyRespawnTimer() // self == intel
{
level.intelEnt["visuals"] endon( "pickedUp" );
for( ;; )
{
if( GetTime() > ( level.intelEnt["dropped_time"] + 60000 ) )
break;
wait 1;
}
//not picked up for 2 minutes
//random place intel on player
level.intelEnt["isActive"] = false;
level.intelEnt["visuals"] Hide();
level thread randAssignIntel();
}
onPickupIntel() // self == player
{
self.hasIntel = true;
level.intelEnt["isActive"] = false;
level.intelEnt["visuals"] Hide();
level.intelEnt["owner"] = self;
validChallengesArray = [];
//adding xp for picking up intel
self thread maps\mp\gametypes\_rank::giveRankXP( "challenge", 100 );
if ( self isJuggernaut() )
{
foreach ( challenge in level.intelChallengeArray )
{
challengeName = challenge.challengeName;
if ( !challenge.juggChallenge )
{
continue;
}
if ( ( IsDefined( self.isJuggernautManiac ) && self.isJuggernautManiac == true ) )
{
if ( !IsSubStr( challengeName, "maniac" ) )
{
continue;
}
}
else if ( ( IsDefined( self.isJuggernautRecon ) && self.isJuggernautRecon == true ) )
{
if ( !IsSubStr( challengeName, "recon" ) )
{
continue;
}
}
else
{
if ( !IsSubStr( challengeName, "assault" ) )
{
continue;
}
}
validChallengesArray[ validChallengesArray.size ] = challenge;
}
}
else
{
otherTeam = getOtherTeam( self.team );
numEnemies = level.teamcount[otherTeam];
otherTeamAliveCount = level.aliveCount[ otherteam ]; // how many enemy lives remain
isInfiniteLives = undefined;
isInfiniteLives = GetDvarInt( "scr_player_lives" ) == 0;
weapons = self GetWeaponsListPrimaries();
foreach ( challenge in level.intelChallengeArray )
{
challengeName = challenge.challengeName;
killsToComplete = challenge.challengeTarget;
if ( !isInfiniteLives ) // for Elimination modes
{
if ( challengeName == "ch_intel_tbag" || killsToComplete > otherTeamAliveCount ) // can't complete this if only one enemy life left
{
continue;
}
}
if ( challengeName == "ch_intel_secondarykills" && intelCanComplete_secondaryKills( self, weapons ) == false )
{
continue;
}
if ( challengeName == "ch_intel_explosivekill" && intelCanComplete_explosiveKill( self, weapons ) == false )
{
continue;
}
if ( challenge.teamChallenge )
{
continue;
}
if ( challenge.juggChallenge )
{
continue;
}
validChallengesArray[ validChallengesArray.size ] = challenge;
}
}
randChallenge = validChallengesArray[ RandomInt( validChallengesArray.size ) ];
challengeNameIndex = randChallenge.challengeName;
/#
devChallengeName = GetDvar( "scr_devIntelChallengeName" );
if( devChallengeName != "temp" )
challengeNameIndex = devChallengeName;
#/
if ( self isJuggernaut() )
{
self maps\mp\gametypes\_intelchallenges::giveJuggernautChallenge( challengeNameIndex );
}
else
{
self maps\mp\gametypes\_intelchallenges::giveChallenge( challengeNameIndex );
self thread watchForJuggernaut();
}
self thread watchForPlayerDisconnect();
//self thread watchForJoinedSpectator();
self thread watchForRemoteKillstreak();
level.intelEnt["visuals"] notify("pickedUp");
}
intelCanComplete_secondaryKills( player, weapons )
{
result = false;
foreach ( weapon in weapons )
{
if ( isCACSecondaryWeapon( weapon ) )
{
if ( player GetAmmoCount( weapon ) > 0 )
{
result = true;
break;
}
}
}
return result;
}
intelCanComplete_explosiveKill( player, weapons )
{
result = false;
// Does the user have an explosive lethal with ammo
if ( self.loadoutPerkEquipment != "specialty_null" && !IsSubStr( self.loadoutPerkEquipment, "throwingknife" ) )
{
offhandAmmoCount = player GetAmmoCount( self.loadoutPerkEquipment );
if ( offhandAmmoCount > 0 )
{
result = true;
}
}
if ( result == false )
{
// Does the user have a secondary launcher with ammo or underbarrel with ammo
foreach ( weapon in weapons )
{
weapClass = WeaponClass( weapon );
if ( ( weapClass == "rocketlauncher" || weapClass == "grenade" ) && player GetAmmoCount( weapon ) > 0 )
{
result = true;
break;
}
else
{
altWeapon = WeaponAltWeaponName( weapon );
if ( IsDefined( altWeapon ) && WeaponClass( altWeapon ) == "grenade" && player GetAmmoCount( altWeapon ) > 0 )
{
result = true;
break;
}
}
}
}
return result;
}
watchForJuggernaut() // self == player
{
// if Player equips Juggernaut while holding Intel
self endon( "death" );
self endon( "intel_cleanup" );
while ( 1 )
{
level waittill( "juggernaut_equipped" );
// In case multiple players become the jugg on the same
// frame wait for all of them to go through
waittillframeend;
if ( self isJuggernaut() )
{
self thread updateJuggIntel();
}
}
}
updateJuggIntel()
{
self notify( "intel_cleanup" );
// remove active Intel HUD info and replace with Jugg
self SetClientOmnvar( "ui_intel_active_index", -1 );
self onPickupIntel();
}
watchForPlayerDisconnect() // self == player
{
self endon( "death" );
self endon( "intel_cleanup" );
self waittill( "disconnect" );
level thread randAssignIntel();
}
watchForRemoteKillstreak() // self == player
{
self endon( "death" );
self endon( "intel_cleanup" );
self endon( "stopped_using_remote" );
self waittill( "using_remote" );
self.intelDeathPosition = self.origin;
self thread updateIntelDeathPosition();
}
updateIntelDeathPosition()
{
self endon( "death" );
self endon( "intel_cleanup" );
self waittill( "stopped_using_remote" );
self.intelDeathPosition = undefined;
self thread WatchForRemoteKillstreak();
}
randAssignIntel() // self == level
{
level notify( "randAssignIntel" );
level endon( "randAssignIntel" );
level endon( "game_ended" );
for ( ;; )
{
wait ( 1 );
selectedPlayer = getRandomPlayingPlayer();
if(! isDefined( selectedPlayer ) )
continue;
selectedPlayer.hasIntel = true;
level.intelEnt["owner"] = selectedPlayer;
selectedPlayer thread watchForPlayerDisconnect();
break;
}
}
awardPlayerChallengeComplete( index )
{
self endon( "disconnect" );
self replenishAmmo();
self.hasIntel = false;
challenge = level.intelChallengeArray[index];
reference = challenge.challengeName;
rewardXP = Int( challenge.challengeReward );
self SetClientOmnvar( "ui_intel_active_index", -1 );
//Give Killstreak Reward
self thread maps\mp\killstreaks\_killstreaks::giveKillstreak( "airdrop_assault", false, false, self );
self thread maps\mp\gametypes\_hud_message::SplashNotifyDelayed( reference, rewardXP );
self thread maps\mp\gametypes\_rank::giveRankXP( "intel", rewardXP );
level thread randAssignIntel();
self thread [[ level.leaderDialogOnPlayer_func ]]( "achieve_carepackage", undefined, undefined, self.origin );
self maps\mp\gametypes\_missions::processChallenge( "ch_intelligence" );
self notify( "intel_cleanup" );
}
replenishAmmo()
{
weaponList = self GetWeaponsListAll();
foreach ( weaponName in weaponList )
{
if ( isKillstreakWeapon( weaponName ) )
{
continue;
}
else if ( WeaponInventoryType( weaponName ) == "offhand" )
{
// GiveMaxAmmo() fails to refill frags to 2, so use SetWeaponAmmoClip() for all offhands -DM
if ( ( weaponName == self.loadoutPerkEquipment && self _hasPerk( "specialty_extra_deadly" ) )
|| ( weaponName == self.loadoutPerkOffhand && self _hasPerk( "specialty_extra_equipment" ) ) )
{
self SetWeaponAmmoClip( weaponName, 2 );
}
else
{
self SetWeaponAmmoClip( weaponName, 1 );
}
}
else
{
self GiveMaxAmmo( weaponName );
}
}
}
/***************************************
* USE BAR
*
*
***************************************/
proximityThink( player ) // self == intel trigger
{
if ( !isDefined( self ) )
return false;
self.inUse = true;
result = self proximityThinkLoop( player );
assert ( isDefined( result ) );
if ( !isDefined( self ) )
return false;
level.intelEnt["useProgress"] = 0;
return ( result );
}
proximityThinkLoop( player ) // self == intel trigger
{
self.useRate = level.intelEnt["useRate"];
self.useTime = level.intelEnt["useTime"];
self.curProgress = 0;
while ( !level.gameEnded && IsDefined( self ) && isReallyAlive( player ) )
{
if ( Distance2DSquared( self.origin, player.origin ) > CONST_INTEL_TRIG_RADIUS_EXIT * CONST_INTEL_TRIG_RADIUS_EXIT )
break;
level.intelEnt["useProgress"] += 0.05 * self.useRate;
self.curProgress = level.intelEnt["useProgress"];
player maps\mp\gametypes\_gameobjects::updateUIProgress( self, true );
if ( level.intelEnt["useProgress"] >= self.useTime )
{
player maps\mp\gametypes\_gameobjects::updateUIProgress( self, false );
return ( isReallyAlive( player ) );
}
wait 0.05;
}
player maps\mp\gametypes\_gameobjects::updateUIProgress( self, false );
return false;
}

View File

@ -0,0 +1,955 @@
#include common_scripts\utility;
#include maps\mp\_utility;
#include maps\mp\gametypes\_hud_util;
INTEL_MINIGUN_REWARD_DURATION = 60;
INTEL_MINIGUN_REWARD_EXPIRE_FLASH_DURATION = 8;
giveChallenge( challengeIndex )
{
self thread deathWatcher();
// Have to grab rowNum because challengeIndex is an index into the array and not the table
omnvar_index = TableLookupRowNum( "mp/intelChallenges.csv", 0, challengeIndex );
self SetClientOmnvar( "ui_intel_active_index", omnvar_index );
switch( challengeIndex )
{
case "ch_intel_headshots":
self thread intelHeadshotChallenge(challengeIndex);
break;
case "ch_intel_kills":
self thread intelKillsChallenge(challengeIndex);
break;
case "ch_intel_knifekill":
self thread intelKnifeKillChallenge(challengeIndex);
break;
case "ch_intel_explosivekill":
self thread intelBombKillChallenge(challengeIndex);
break;
case "ch_intel_crouchkills":
self thread intelCrouchKillsChallenge(challengeIndex);
break;
case "ch_intel_pronekills":
self thread intelProneKillsChallenge(challengeIndex);
break;
case "ch_intel_backshots":
self thread intelBackKillsChallenge(challengeIndex);
break;
case "ch_intel_jumpshot":
self thread intelJumpShotKillsChallenge(challengeIndex);
break;
case "ch_intel_secondarykills":
self thread intelSecondaryKillsChallenge(challengeIndex);
break;
case "ch_intel_foundshot":
self thread intelFoundshotKillsChallenge(challengeIndex);
break;
case "ch_intel_tbag":
self thread intelTbagChallenge(challengeIndex);
break;
default:
AssertMsg( challengeIndex + " not found" );
}
}
giveTeamChallenge( challengeIndex, team )
{
switch( challengeIndex )
{
case "ch_team_intel_melee":
level thread intelTeamMelee( challengeIndex, team );
break;
case "ch_team_intel_headshot":
level thread intelTeamHeadShot( challengeIndex, team );
break;
case "ch_team_intel_killstreak":
level thread intelTeamKillStreak( challengeIndex, team );
break;
case "ch_team_intel_equipment":
level thread intelTeamEquipment( challengeIndex, team );
break;
default:
AssertMsg( challengeIndex + " not found" );
}
}
intelTeamMelee( challengeReference, team )
{
level endon ( "game_ended" );
level endon( "giveTeamIntel" );
level endon( "teamIntelFail" );
level.numMeleeKillsIntel = 0;
numKillsTarget = level.intelChallengeArray[challengeReference].challengeTarget;
omnvar_index = TableLookupRowNum( "mp/intelChallenges.csv", 0, challengeReference );
level thread teamIntelStartHUD( challengeReference, team, omnvar_index, numKillsTarget );
while( level.numMeleeKillsIntel < numKillsTarget )
{
level waittill( "enemy_death" );
setTeamIntelProgress( numKillsTarget - level.numMeleeKillsIntel );
}
teamIntelEndHUD( challengeReference, team );
level thread intelTeamReward( team );
}
setTeamIntelProgress( progress )
{
// make sure the progress doesn't go negative
level.updateIntelProgress = Int( Max( progress, 0 ) );
updateTeamIntelProgress( level.updateIntelProgress );
}
updateTeamIntelProgress( progress )
{
level.currentTeamIntelProgress = progress;
foreach( player in level.players )
{
player playerUpdateTeamIntelProgress();
}
}
//self == player
playerUpdateTeamIntelProgress()
{
self SetClientOmnvar( "ui_intel_progress_current", level.currentTeamIntelProgress );
}
playerUpdateIntelProgress( updateIntelProgress ) //self == player
{
self SetClientOmnvar( "ui_intel_progress_current", updateIntelProgress );
}
intelTeamHeadShot( challengeReference, team )
{
level endon ( "game_ended" );
level endon( "giveTeamIntel" );
level endon( "teamIntelFail" );
level.numHeadShotsIntel = 0;
numKillsTarget = level.intelChallengeArray[challengeReference].challengeTarget;
omnvar_index = TableLookupRowNum( "mp/intelChallenges.csv", 0, challengeReference );
level thread teamIntelStartHUD( challengeReference, team, omnvar_index, numKillsTarget );
while( level.numHeadShotsIntel < numKillsTarget )
{
level waittill( "enemy_death" );
setTeamIntelProgress( numKillsTarget - level.numHeadShotsIntel );
}
teamIntelEndHUD( challengeReference, team );
level thread intelTeamReward( team );
}
intelTeamKillStreak( challengeReference, team )
{
level endon ( "game_ended" );
level endon( "giveTeamIntel" );
level endon( "teamIntelFail" );
level.numKillStreakKillsIntel = 0;
numKillsTarget = level.intelChallengeArray[challengeReference].challengeTarget;
omnvar_index = TableLookupRowNum( "mp/intelChallenges.csv", 0, challengeReference );
level thread teamIntelStartHUD( challengeReference, team, omnvar_index, numKillsTarget );
while( level.numKillStreakKillsIntel < numKillsTarget )
{
level waittill( "enemy_death" );
setTeamIntelProgress( numKillsTarget - level.numKillStreakKillsIntel );
}
teamIntelEndHUD( challengeReference, team );
level thread intelTeamReward( team );
}
intelTeamEquipment( challengeReference, team )
{
level endon ( "game_ended" );
level endon( "giveTeamIntel" );
level endon( "teamIntelFail" );
level.numEquipmentKillsIntel = 0;
numKillsTarget = level.intelChallengeArray[challengeReference].challengeTarget;
omnvar_index = TableLookupRowNum( "mp/intelChallenges.csv", 0, challengeReference );
level thread teamIntelStartHUD( challengeReference, team, omnvar_index, numKillsTarget );
while( level.numEquipmentKillsIntel < numKillsTarget )
{
level waittill( "enemy_death" );
setTeamIntelProgress( numKillsTarget - level.numEquipmentKillsIntel );
}
teamIntelEndHUD( challengeReference, team );
level thread intelTeamReward( team );
}
teamIntelStartHUD( challengeReference, team, omnvar_index, intelTarget )
{
level endon( "game_ended" );
level endon( "giveTeamIntel" );
level endon( "teamIntelFail" );
level endon( "teamIntelComplete" );
level.isTeamIntelComplete = false;
level.currentTeamIntelName = challengeReference;
level.currentTeamIntelProgress = intelTarget;
foreach( player in level.players )
{
player playerTeamIntelStartHUD( challengeReference, team, omnvar_index, intelTarget );
}
while(1)
{
level waittill( "player_spawned", player );
player playerTeamIntelStartHUD( challengeReference, team, omnvar_index, intelTarget );
}
}
//Self == player
playerTeamIntelStartHUD( challengeReference, team, omnvar_index, intelTarget )
{
if( self.team != team )
return;
self SetClientOmnvar( "ui_intel_active_index", omnvar_index );
self playerUpdateTeamIntelProgress();
if( isReallyAlive(self) )
self thread maps\mp\gametypes\_hud_message::SplashNotify( challengeReference + "_received" );
}
teamIntelEndHUD( challengeReference, team )
{
level notify("teamIntelComplete");
foreach( player in level.players )
{
if( player.team != team )
continue;
player SetClientOmnvar( "ui_intel_active_index", -1 );
player SetClientOmnvar( "ui_intel_progress_current", -1 );
if( isReallyAlive(player) )
player thread maps\mp\gametypes\_hud_message::SplashNotify( challengeReference );
}
}
intelTeamReward( team )
{
level endon ( "game_ended" );
level notify( "intelTeamReward" );
foreach( player in level.players )
{
if( player.team != team )
continue;
if( !isReallyAlive(player) )
continue;
player thread intelTeamRewardPlayer();
}
level.isTeamIntelComplete = true;
}
intelTeamRewardPlayerWaitTillComplete( rewardTime )
{
level endon( "intelTeamReward" ); //incase intelTeamReward() somehow gets called while intelTeamRewardPlayer() is waiting.
while ( rewardTime )
{
wait ( 1.0 );
maps\mp\gametypes\_hostmigration::waitTillHostMigrationDone();
// Make sure the player isn't carrying anything, or securing a crate
if ( ( !IsDefined( self.isCarrying ) || self.isCarrying == 0 ) && !IsDefined( self.ui_securing ) )
rewardTime = max( 0, rewardTime - 1.0 );
if ( rewardTime == INTEL_MINIGUN_REWARD_EXPIRE_FLASH_DURATION )
self childthread flashIntelIcon( );
}
}
intelTeamRewardPlayer()
{
level endon ( "game_ended" );
player = self;
player givePerk( "specialty_explosivebullets", false );
// show HUD icon
player SetClientOmnvar( "ui_horde_update_explosive", 1);
player _giveWeapon( level.intelMiniGun );
player GiveStartAmmo( level.intelMiniGun );
if( (player isWeaponEnabled()) && (player isUsabilityEnabled()) && !(player isUsingRemote()) && !(player maps\mp\killstreaks\_killstreaks::isUsingHeliSniper()) )
player SwitchToWeaponImmediate( level.intelMiniGun );
player intelTeamRewardPlayerWaitTillComplete( INTEL_MINIGUN_REWARD_DURATION );
player _unsetPerk( "specialty_explosivebullets" );
// hide HUD icon
player SetClientOmnvar( "ui_horde_update_explosive", 0);
cuurentWeaponName = player GetCurrentPrimaryWeapon();
player TakeWeapon( level.intelMiniGun );
if( cuurentWeaponName == level.intelMiniGun )
{
nextWeaponName = player maps\mp\killstreaks\_killstreaks::getFirstPrimaryWeapon();
player SwitchToWeaponImmediate( nextWeaponName );
}
}
flashIntelIcon( )
{
self endon( "death" );
self endon( "disconnect" );
// Start flashing HUD icon
// Tells LUI to start flashing item only if it has been shown
self SetClientOmnvar( "ui_horde_update_explosive", 1);
wait(8);
self SetClientOmnvar( "ui_horde_update_explosive", 0);
}
intelSplash()
{
}
deathWatcher()
{
self endon( "disconnect" );
//level endon( "game_ended" );
self endon( "intel_cleanup" );
self waittill( "death" );
self SetClientOmnvar( "ui_intel_active_index", -1 );
self thread maps\mp\gametypes\_hud_message::SplashNotifyDelayed( "ch_intel_failed" );
}
//Challenges
intelHeadshotChallenge( challengeReference )
{
self endon("disconnect");
self endon("death");
self endon( "intel_cleanup" );
numHeadshots = 0;
headshotTarget = level.intelChallengeArray[challengeReference].challengeTarget;
self thread maps\mp\gametypes\_hud_message::SplashNotifyDelayed( challengeReference + "_received", headshotTarget );
self playerUpdateIntelProgress( headshotTarget );
while( numHeadshots < headshotTarget )
{
self waittill( "got_a_kill", victim, weapon, meansOfDeath );
if( isKillstreakWeapon( weapon ) )
continue;
if ( meansOfDeath == "MOD_HEAD_SHOT" )
{
numHeadshots++;
updateIntelProgress = headshotTarget - numHeadshots;
playerUpdateIntelProgress( updateIntelProgress );
}
}
self maps\mp\gametypes\_intel::awardPlayerChallengeComplete( challengeReference );
}
intelKillsChallenge( challengeReference )
{
self endon("disconnect");
self endon("death");
self endon( "intel_cleanup" );
numKills = 0;
numKillsTarget = level.intelChallengeArray[challengeReference].challengeTarget;
self thread maps\mp\gametypes\_hud_message::SplashNotifyDelayed( challengeReference + "_received", numKillsTarget );
self playerUpdateIntelProgress( numKillsTarget );
while( numKills < numKillsTarget )
{
self waittill( "got_a_kill", victim, weapon );
if( isKillstreakWeapon( weapon ) )
{
continue;
}
numKills++;
updateIntelProgress = numKillsTarget - numKills;
playerUpdateIntelProgress( updateIntelProgress );
}
self maps\mp\gametypes\_intel::awardPlayerChallengeComplete( challengeReference );
}
intelCrouchKillsChallenge( challengeReference )
{
self endon("disconnect");
self endon("death");
self endon( "intel_cleanup" );
numKills = 0;
numKillsTarget = level.intelChallengeArray[challengeReference].challengeTarget;
self playerUpdateIntelProgress( numKillsTarget );
self thread maps\mp\gametypes\_hud_message::SplashNotifyDelayed( challengeReference + "_received", numKillsTarget );
while( numKills < numKillsTarget )
{
self waittill( "got_a_kill", victim, weapon );
if ( self getStance() == "crouch" )
{
if ( isKillstreakWeapon( weapon ) )
{
continue;
}
numKills++;
updateIntelProgress = numKillsTarget - numKills;
playerUpdateIntelProgress( updateIntelProgress );
}
}
self maps\mp\gametypes\_intel::awardPlayerChallengeComplete( challengeReference );
}
intelFoundshotKillsChallenge( challengeReference )
{
self endon("disconnect");
self endon("death");
self endon( "intel_cleanup" );
numKills = 0;
numKillsTarget = level.intelChallengeArray[challengeReference].challengeTarget;
self thread maps\mp\gametypes\_hud_message::SplashNotifyDelayed( challengeReference + "_received", numKillsTarget );
self playerUpdateIntelProgress( numKillsTarget );
while( numKills < numKillsTarget )
{
self waittill( "got_a_kill", victim, weapon, meansOfDeath );
// allow picked up riotshield and combat knife
if ( meansOfDeath == "MOD_MELEE"
&& !maps\mp\gametypes\_weapons::isKnifeOnly( weapon )
&& !maps\mp\gametypes\_weapons::isRiotShield( weapon )
)
continue;
if (maps\mp\gametypes\_weapons::isOffhandWeapon( weapon )
|| isKillstreakWeapon( weapon )
|| isEnvironmentWeapon( weapon )
)
continue;
weapon = weaponMap( weapon );
// we do this check to allow the player to use weapons picked up before the challenge started
if ( weapon != self.pers[ "primaryWeapon" ]
&& weapon != self.pers[ "secondaryWeapon" ] )
{
numKills++;
updateIntelProgress = numKillsTarget - numKills;
playerUpdateIntelProgress( updateIntelProgress );
}
}
self maps\mp\gametypes\_intel::awardPlayerChallengeComplete( challengeReference );
}
intelSecondaryKillsChallenge( challengeReference )
{
self endon("disconnect");
self endon("death");
self endon( "intel_cleanup" );
numKills = 0;
numKillsTarget = level.intelChallengeArray[challengeReference].challengeTarget;
self thread maps\mp\gametypes\_hud_message::SplashNotifyDelayed( challengeReference + "_received", numKillsTarget );
self playerUpdateIntelProgress( numKillsTarget );
while( numKills < numKillsTarget )
{
self waittill( "got_a_kill", victim, weapon, meansOfDeath );
// Mk32 spawns a projectile that needs to be mapped back to it
weapon = weaponMap( weapon );
if ( isCACSecondaryWeapon( weapon ) )
{
if ( meansOfDeath == "MOD_MELEE" && !IsSubStr( weapon, "tactical" ) )
continue;
numKills++;
updateIntelProgress = numKillsTarget - numKills;
playerUpdateIntelProgress( updateIntelProgress );
}
}
self maps\mp\gametypes\_intel::awardPlayerChallengeComplete( challengeReference );
}
intelBackKillsChallenge( challengeReference )
{
self endon("disconnect");
self endon("death");
self endon( "intel_cleanup" );
numKills = 0;
numKillsTarget = level.intelChallengeArray[challengeReference].challengeTarget;
self thread maps\mp\gametypes\_hud_message::SplashNotifyDelayed( challengeReference + "_received", numKillsTarget );
self playerUpdateIntelProgress( numKillsTarget );
while( numKills < numKillsTarget )
{
self waittill( "got_a_kill", victim, weapon, meansOfDeath );
if( isKillstreakWeapon( weapon ) )
continue;
vAngles = victim.anglesOnDeath[1];
pAngles = self.anglesOnKill[1];
angleDiff = AngleClamp180( vAngles - pAngles );
if ( abs(angleDiff) < 65 )
{
numKills++;
updateIntelProgress = numKillsTarget - numKills;
playerUpdateIntelProgress( updateIntelProgress );
}
}
self maps\mp\gametypes\_intel::awardPlayerChallengeComplete( challengeReference );
}
intelJumpShotKillsChallenge( challengeReference )
{
self endon("disconnect");
self endon("death");
self endon( "intel_cleanup" );
numKills = 0;
numKillsTarget = Int( level.intelChallengeArray[challengeReference].challengeTarget );
self thread maps\mp\gametypes\_hud_message::SplashNotifyDelayed( challengeReference + "_received", numKillsTarget );
self playerUpdateIntelProgress( numKillsTarget );
while( numKills < numKillsTarget )
{
self waittill( "got_a_kill", victim, weapon, meansOfDeath );
if( isKillstreakWeapon( weapon ) )
continue;
if ( !self isOnGround() )
{
numKills++;
updateIntelProgress = numKillsTarget - numKills;
playerUpdateIntelProgress( updateIntelProgress );
}
}
self maps\mp\gametypes\_intel::awardPlayerChallengeComplete( challengeReference );
}
intelKnifeKillChallenge( challengeReference )
{
self endon("disconnect");
self endon("death");
self endon( "intel_cleanup" );
numKills = 0;
numKillsTarget = level.intelChallengeArray[challengeReference].challengeTarget;
self thread maps\mp\gametypes\_hud_message::SplashNotifyDelayed( challengeReference + "_received", numKillsTarget );
self playerUpdateIntelProgress( numKillsTarget );
while( numKills < numKillsTarget )
{
self waittill( "got_a_kill", victim, weapon, meansOfDeath );
if ( meansOfDeath == "MOD_MELEE" )
{
numKills++;
updateIntelProgress = numKillsTarget - numKills;
playerUpdateIntelProgress( updateIntelProgress );
}
}
self maps\mp\gametypes\_intel::awardPlayerChallengeComplete( challengeReference );
}
intelBombKillChallenge( challengeReference )
{
self endon("disconnect");
self endon("death");
self endon( "intel_cleanup" );
numKills = 0;
numKillsTarget = level.intelChallengeArray[challengeReference].challengeTarget;
self thread maps\mp\gametypes\_hud_message::SplashNotifyDelayed( challengeReference + "_received", numKillsTarget );
self playerUpdateIntelProgress( numKillsTarget );
while( numKills < numKillsTarget )
{
self waittill( "got_a_kill", victim, weapon, meansOfDeath );
if( isKillstreakWeapon( weapon ) )
continue;
if ( weapon == "throwingknife_mp" )
continue;
if ( IsExplosiveDamageMOD( MeansOfDeath ) || meansOfDeath == "MOD_IMPACT" )
{
numKills++;
updateIntelProgress = numKillsTarget - numKills;
playerUpdateIntelProgress( updateIntelProgress );
}
}
self maps\mp\gametypes\_intel::awardPlayerChallengeComplete( challengeReference );
}
intelProneKillsChallenge( challengeReference )
{
self endon("disconnect");
self endon("death");
self endon( "intel_cleanup" );
numKills = 0;
numKillsTarget = Int( level.intelChallengeArray[challengeReference].challengeTarget );
self thread maps\mp\gametypes\_hud_message::SplashNotifyDelayed( challengeReference + "_received", numKillsTarget );
self playerUpdateIntelProgress( numKillsTarget );
while( numKills < numKillsTarget )
{
self waittill( "got_a_kill", victim, weapon, meansOfDeath );
if( isKillstreakWeapon( weapon ) )
continue;
if ( self getStance() == "prone" )
{
numKills++;
updateIntelProgress = numKillsTarget - numKills;
playerUpdateIntelProgress( updateIntelProgress );
}
}
self maps\mp\gametypes\_intel::awardPlayerChallengeComplete( challengeReference );
}
intelTbagChallenge( challengeReference )
{
self endon("disconnect");
self endon("death");
self endon( "intel_cleanup" );
numKillsTarget = level.intelChallengeArray[challengeReference].challengeTarget;
self thread maps\mp\gametypes\_hud_message::SplashNotifyDelayed( challengeReference + "_received" );
for ( ;; )
{
self waittill( "got_a_kill", victim, weapon, meansOfDeath );
if( isKillstreakWeapon( weapon ) )
continue;
self thread watchForTbag( victim.origin, challengeReference );
}
}
watchForTbag( position, challengeReference )
{
self notify( "watchForTbag" );
self endon( "watchForTbag" );
self endon( "death" );
self endon( "disconnect" );
self endon( "intel_cleanup" );
numTbag = 0;
self notifyOnPlayerCommand( "Tbag_adjustedStance", "+stance" );
self notifyOnPlayerCommand( "Tbag_adjustedStance", "+goStand" );
if( !level.console && !isAI(self) )
{
self notifyOnPlayerCommand( "Tbag_adjustedStance", "+togglecrouch" );
self notifyOnPlayerCommand( "Tbag_adjustedStance", "+movedown" );
}
while( true )
{
// make sure they start in a standing position
while( self GetStance() != "stand" )
wait( 0.05 );
self waittill( "Tbag_adjustedStance" );
while( self GetStance() != "crouch" )
wait( 0.05 );
if( Distance2D( self.origin, position ) < 128 )
{
self waittill( "Tbag_adjustedStance" );
while( self GetStance() != "stand" )
wait( 0.05 );
if( Distance2D( self.origin, position ) < 128 )
numTbag++;
}
if( numTbag )
{
self thread maps\mp\gametypes\_intel::awardPlayerChallengeComplete( challengeReference );
return;
}
}
}
giveJuggernautChallenge( challengeIndex )
{
self thread deathWatcher();
// Have to grab rowNum because challengeIndex is an index into the array and not the table
omnvar_index = TableLookupRowNum( "mp/intelChallenges.csv", 0, challengeIndex );
self SetClientOmnvar( "ui_intel_active_index", omnvar_index );
switch( challengeIndex )
{
case "ch_intel_jugg_maniac_knife":
self thread intelJuggManiacKnifeChallenge( challengeIndex );
break;
case "ch_intel_jugg_maniac_throwingknife":
self thread intelJuggManiacThrowingKnifeChallenge( challengeIndex );
break;
case "ch_intel_jugg_maniac_backknife":
self thread intelJuggManiacBackKnifeChallenge( challengeIndex );
break;
case "ch_intel_jugg_assault_kills":
self thread intelJuggAssaultKillsChallenge( challengeIndex );
break;
case "ch_intel_jugg_recon_shieldkills":
self thread intelJuggReconShieldKillsChallenge( challengeIndex );
break;
case "ch_intel_jugg_recon_pistolkills":
self thread intelJuggReconPistolKillsChallenge( challengeIndex );
break;
default:
AssertMsg( challengeIndex + " not found" );
}
}
intelJuggAssaultKillsChallenge( challengeReference )
{
self endon("disconnect");
self endon("death");
self endon( "intel_cleanup" );
numKills = 0;
numKillsTarget = Int( level.intelChallengeArray[challengeReference].challengeTarget );
self thread maps\mp\gametypes\_hud_message::SplashNotifyDelayed( challengeReference + "_received", numKillsTarget );
self playerUpdateIntelProgress( numKillsTarget );
while( numKills < numKillsTarget )
{
self waittill( "got_a_kill", victim, weapon, meansOfDeath );
if( isJuggernautWeapon( weapon ) )
{
numKills++;
updateIntelProgress = numKillsTarget - numKills;
playerUpdateIntelProgress( updateIntelProgress );
}
}
self maps\mp\gametypes\_intel::awardPlayerChallengeComplete( challengeReference );
}
intelJuggManiacKnifeChallenge( challengeReference )
{
self endon("disconnect");
self endon("death");
self endon( "intel_cleanup" );
numKills = 0;
numKillsTarget = Int( level.intelChallengeArray[challengeReference].challengeTarget );
self thread maps\mp\gametypes\_hud_message::SplashNotifyDelayed( challengeReference + "_received", numKillsTarget );
self playerUpdateIntelProgress( numKillsTarget );
while( numKills < numKillsTarget )
{
self waittill( "got_a_kill", victim, weapon, meansOfDeath );
if( weapon == "iw6_knifeonlyjugg_mp" )
{
numKills++;
updateIntelProgress = numKillsTarget - numKills;
playerUpdateIntelProgress( updateIntelProgress );
}
}
self maps\mp\gametypes\_intel::awardPlayerChallengeComplete( challengeReference );
}
intelJuggManiacThrowingKnifeChallenge( challengeReference )
{
self endon("disconnect");
self endon("death");
self endon( "intel_cleanup" );
numKills = 0;
numKillsTarget = Int( level.intelChallengeArray[challengeReference].challengeTarget );
self thread maps\mp\gametypes\_hud_message::SplashNotifyDelayed( challengeReference + "_received", numKillsTarget );
self playerUpdateIntelProgress( numKillsTarget );
while( numKills < numKillsTarget )
{
self waittill( "got_a_kill", victim, weapon, meansOfDeath );
if( weapon == "throwingknifejugg_mp" )
{
numKills++;
updateIntelProgress = numKillsTarget - numKills;
playerUpdateIntelProgress( updateIntelProgress );
}
}
self maps\mp\gametypes\_intel::awardPlayerChallengeComplete( challengeReference );
}
intelJuggManiacBackKnifeChallenge( challengeReference )
{
self endon("disconnect");
self endon("death");
self endon( "intel_cleanup" );
numKills = 0;
numKillsTarget = level.intelChallengeArray[challengeReference].challengeTarget;
self thread maps\mp\gametypes\_hud_message::SplashNotifyDelayed( challengeReference + "_received", numKillsTarget );
self playerUpdateIntelProgress( numKillsTarget );
while( numKills < numKillsTarget )
{
self waittill( "got_a_kill", victim, weapon, meansOfDeath );
if( isJuggernautWeapon( weapon ) )
{
vAngles = victim.anglesOnDeath[1];
pAngles = self.anglesOnKill[1];
angleDiff = AngleClamp180( vAngles - pAngles );
if ( abs(angleDiff) < 90 )
{
numKills++;
updateIntelProgress = numKillsTarget - numKills;
playerUpdateIntelProgress( updateIntelProgress );
}
}
}
self maps\mp\gametypes\_intel::awardPlayerChallengeComplete( challengeReference );
}
intelJuggReconShieldKillsChallenge( challengeReference )
{
self endon("disconnect");
self endon("death");
self endon( "intel_cleanup" );
numKills = 0;
numKillsTarget = Int( level.intelChallengeArray[challengeReference].challengeTarget );
self thread maps\mp\gametypes\_hud_message::SplashNotifyDelayed( challengeReference + "_received", numKillsTarget );
self playerUpdateIntelProgress( numKillsTarget );
while( numKills < numKillsTarget )
{
self waittill( "got_a_kill", victim, weapon, meansOfDeath );
if( weapon == "iw6_riotshieldjugg_mp" )
{
numKills++;
updateIntelProgress = numKillsTarget - numKills;
playerUpdateIntelProgress( updateIntelProgress );
}
}
self maps\mp\gametypes\_intel::awardPlayerChallengeComplete( challengeReference );
}
intelJuggReconPistolKillsChallenge( challengeReference )
{
self endon("disconnect");
self endon("death");
self endon( "intel_cleanup" );
numKills = 0;
numKillsTarget = Int( level.intelChallengeArray[challengeReference].challengeTarget );
self thread maps\mp\gametypes\_hud_message::SplashNotifyDelayed( challengeReference + "_received", numKillsTarget );
self playerUpdateIntelProgress( numKillsTarget );
while( numKills < numKillsTarget )
{
self waittill( "got_a_kill", victim, weapon, meansOfDeath );
if( weapon == "iw6_magnumjugg_mp" && meansOfDeath != "MOD_MELEE" )
{
numKills++;
updateIntelProgress = numKillsTarget - numKills;
playerUpdateIntelProgress( updateIntelProgress );
}
}
self maps\mp\gametypes\_intel::awardPlayerChallengeComplete( challengeReference );
}

View File

@ -0,0 +1,702 @@
#include common_scripts\utility;
#include maps\mp\_utility;
#include maps\mp\gametypes\_hud_util;
CINEMATIC_CAMERA_NUM_ATTACKER_FINAL_KILLCAM = 5;
init()
{
level.killcam = maps\mp\gametypes\_tweakables::getTweakableValue( "game", "allowkillcam" );
}
setCinematicCameraStyle( cameraStyle, leadingActorId, supportingActorId )
{
// make sure this "cam_scene_name" has a corresponding file in "game/share/raw/mp/cinematic_camera/*.txt" and is added to common_mp.csv & ncsLuiStrings.txt
self SetClientOmnvar( "cam_scene_name", cameraStyle );
self SetClientOmnvar( "cam_scene_lead", leadingActorId );
self SetClientOmnvar( "cam_scene_support", supportingActorId );
}
// self == client to show killcam
// in normal killcam, this is the eVictim
// in final killcam, this is your player and not necessarily the eVictim
setKillCameraStyle( eInflictor, inflictorAgentInfo, attackerNum, eVictim, killcamentityindex, killcamInfo )
{
killcamInfo.cameraStyle = "unknown";
if ( IsDefined( inflictorAgentInfo ) && IsDefined( inflictorAgentInfo.agent_type ) )
{
if ( inflictorAgentInfo.agent_type == "dog" || inflictorAgentInfo.agent_type == "wolf" )
{
self setCinematicCameraStyle( "killcam_dog", eInflictor GetEntityNumber(), eVictim GetEntityNumber() );
killcamInfo.cameraStyle = "killcam_dog";
}
else if ( inflictorAgentInfo.agent_type == "beastmen" )
{
self setCinematicCameraStyle( "killcam_agent_firstperson", eInflictor GetEntityNumber(), eVictim GetEntityNumber() );
killcamInfo.cameraStyle = "killcam_agent_firstperson";
}
else
{
self setCinematicCameraStyle( "killcam_agent", eInflictor GetEntityNumber(), eVictim GetEntityNumber() );
killcamInfo.cameraStyle = "killcam_agent";
}
return true;
}
else if ( killcamentityindex > 0 )
{
// use killcam entity camera rather than a "cinematic camera"
self setCinematicCameraStyle( "unknown", -1, -1 );
return false;
}
else
{
// we decided to not do the cinematic killcam on the normal in-match killcam
self setCinematicCameraStyle( "unknown", -1, -1 );
return false;
}
return false;
}
trimKillCamTime( eInflictor, inflictorAgentInfo, attacker, victim, killcamentityindex, camtime, postdelay, predelay, maxtime )
{
killcamlength = camtime + postdelay;
//
// don't let the killcam last past the end of the round.
//
if ( isdefined(maxtime) && killcamlength > maxtime )
{
// first trim postdelay down to a minimum of 1 second.
// if that doesn't make it short enough, trim camtime down to a minimum of 1 second.
// if that's still not short enough, cancel the killcam.
if ( maxtime < 2 )
return;
if (maxtime - camtime >= 1) {
// reduce postdelay so killcam ends at end of match
postdelay = maxtime - camtime;
}
else {
// distribute remaining time over postdelay and camtime
postdelay = 1;
camtime = maxtime - 1;
}
// recalc killcamlength
killcamlength = camtime + postdelay;
}
killcamoffset = camtime + predelay;
//
// don't show killcam before attacker/inflictor spawns
//
if ( IsDefined( inflictorAgentInfo ) && IsDefined( inflictorAgentInfo.lastSpawnTime ) )
{
lastAttackerSpawnTime = inflictorAgentInfo.lastSpawnTime;
}
else
{
lastAttackerSpawnTime = attacker.lastSpawnTime;
if ( IsDefined( attacker.deathTime ) )
{
// don't let the killcam last past the attacker death so that victim can see where attacker respawns in killcam
if ( gettime() - attacker.deathTime < (postdelay * 1000.0) )
{
postdelay = 1.0; // time from death until respawn (or killcam)
postdelay -= 0.05; // shorten by 1 server frame so that you don't see attacker spawn for 1 frame
// recalc killcamlength
killcamlength = camtime + postdelay;
}
}
}
aliveTime = ( getTime() - lastAttackerSpawnTime ) / 1000.0;
if ( (killcamoffset > aliveTime) && (aliveTime > predelay) )
{
trimmedCamtime = aliveTime - predelay;
if ( camtime > trimmedCamtime )
{
camtime = trimmedCamtime;
// recalc killcamlength & killcamoffset
killcamlength = camtime + postdelay;
killcamoffset = camtime + predelay;
}
}
result = spawnStruct();
result.camtime = camtime;
result.postdelay = postdelay;
result.killcamlength = killcamlength;
result.killcamoffset = killcamoffset;
return result;
}
preKillcamNotify( eInflictor, attacker )
{
if( IsDefined(attacker) && !IsAgent(attacker) )
{
self LoadCustomizationPlayerView( attacker );
}
// TODO: Could store the attacker spawn time here, before too much time passes?
}
killcam(
eInflictor, // entity of the inflictor, can be the attacker
inflictorAgentInfo, // if inflictor is agent, contains struct with cached agent_type, lastSpawnTime. undefined if not agent. needed because if agent inflictor dies before victim's killcam starts, eInflictor's script variables were cleared.
attackerNum, // entity number of the attacker
killcamentityindex, // entity number of the entity to view (grenade, airstrike, etc)
killcamentitystarttime, // time at which the killcamentity came into being
sWeapon, // killing weapon
predelay, // time between player death and beginning of killcam
offsetTime, // something to do with how far back in time the killer was seeing the world when he made the kill; latency related, sorta
timeUntilRespawn, // will the player be allowed to respawn after the killcam?
maxtime, // time remaining until map ends; the killcam will never last longer than this. undefined = no limit
attacker, // entity object of attacker
victim, // entity object of the victim
sMeansOfDeath // the means of death
)
{
// monitors killcam and hides HUD elements during killcam session
//if ( !level.splitscreen )
// self thread killcam_HUD_off();
self endon( "disconnect" );
self endon( "spawned" );
level endon( "game_ended" );
if ( attackerNum < 0 || !IsDefined( attacker ) )
return;
//this is to track and amortize number of killcams per frame
level.numPlayersWaitingToEnterKillcam++;
if ( level.numPlayersWaitingToEnterKillcam > 1 )
{
/#
println( "more than one client entering killcam this frame: " + level.numPlayersWaitingToEnterKillcam );
#/
wait 0.05 * ( level.numPlayersWaitingToEnterKillcam - 1 );
}
wait 0.05; // Allow all players entering killcam to increment 'level.numPlayersWaitingToEnterKillcam'
level.numPlayersWaitingToEnterKillcam--;
// length from killcam start to killcam end
if (getdvar("scr_killcam_time") == "")
{
if ( sWeapon == "artillery_mp" || sWeapon == "stealth_bomb_mp" || sWeapon == "warhawk_mortar_mp" )
camtime = (gettime() - killcamentitystarttime) / 1000 - predelay - .1;
else if( sWeapon == "remote_mortar_missile_mp" )
camtime = 6.5;
else if ( level.showingFinalKillcam )
camtime = 4.0;
else if ( sWeapon == "apache_minigun_mp" )
camtime = 3.0;
else if ( sWeapon == "javelin_mp" )
camtime = 8;
else if ( issubstr( sWeapon, "remotemissile_" ) )
camtime = 5;
else if ( IsDefined( eInflictor.sentrytype ) && eInflictor.sentrytype == "multiturret" ) // shortening killcam time on mp_shipment mutliturrets. Gives time for camera to set up
camtime = 2.0;
else if ( IsDefined( eInflictor.carestrike ) )
camtime = 2.0;
else if ( !timeUntilRespawn || timeUntilRespawn > 5.0 ) // if we're not going to respawn, we can take more time to watch what happened
camtime = 5.0;
else if ( sWeapon == "frag_grenade_mp" || sWeapon == "frag_grenade_short_mp" || sWeapon == "semtex_mp" || sWeapon == "semtexproj_mp" || sWeapon == "thermobaric_grenade_mp" || sWeapon == "mortar_shell__mp" )
camtime = 4.25; // show long enough to see grenade thrown
else
camtime = 2.5;
}
else
camtime = getdvarfloat("scr_killcam_time");
if ( IsDefined( maxtime ) )
{
if ( camtime > maxtime )
camtime = maxtime;
if ( camtime < 0.05 )
camtime = 0.05;
}
// time after player death that killcam continues for
if (getdvar("scr_killcam_posttime") == "")
postdelay = 2;
else {
postdelay = getdvarfloat("scr_killcam_posttime");
if (postdelay < 0.05)
postdelay = 0.05;
}
/* timeline:
| camtime | postdelay |
| | predelay |
^ killcam start ^ player death ^ killcam end
^ player starts watching killcam
*/
if ( attackerNum < 0 || !IsDefined( attacker ) )
return; // Need to check this again in case the attacker disconnected during the wait
killcamTimes = trimKillCamTime( eInflictor, inflictorAgentInfo, attacker, victim, killcamentityindex, camtime, postdelay, predelay, maxtime );
if ( !IsDefined( killcamTimes ) )
return;
assert( IsDefined( killcamTimes.camtime ) );
assert( IsDefined( killcamTimes.postdelay ) );
assert( IsDefined( killcamTimes.killcamlength ) );
assert( IsDefined( killcamTimes.killcamoffset ) );
// LUA: we need to reset this dvar so the killcam will reset if we come in here for the final killcam while you're watching a killcam
self SetClientOmnvar( "ui_killcam_end_milliseconds", 0 );
// END LUA
// LUA: we need to show attacker info in the lua killcam
assert( IsGameParticipant( attacker ) );
if( IsPlayer( attacker ) )
{
self SetClientOmnvar( "ui_killcam_killedby_id", attacker GetEntityNumber() );
self SetClientOmnvar( "ui_killcam_victim_id", victim GetEntityNumber() );
self LoadCustomizationPlayerView( attacker );
}
if ( isKillstreakWeapon( sWeapon ) )
{
{
if ( sMeansOfDeath == "MOD_MELEE" && maps\mp\killstreaks\_killstreaks::isAirdropMarker( sWeapon ) )
{
weaponRowIdx = TableLookupRowNum( "mp/statsTable.csv", 4, "iw6_knifeonly" );
self SetClientOmnvar( "ui_killcam_killedby_weapon", weaponRowIdx );
self SetClientOmnvar( "ui_killcam_killedby_killstreak", -1 );
}
else
{
killstreakRowIdx = getKillstreakRowNum( level.killstreakWeildWeapons[ sWeapon ] );
self SetClientOmnvar( "ui_killcam_killedby_killstreak", killstreakRowIdx );
self SetClientOmnvar( "ui_killcam_killedby_weapon", -1 );
self SetClientOmnvar( "ui_killcam_killedby_attachment1", -1 );
self SetClientOmnvar( "ui_killcam_killedby_attachment2", -1 );
self SetClientOmnvar( "ui_killcam_killedby_attachment3", -1 );
self SetClientOmnvar( "ui_killcam_killedby_attachment4", -1 );
}
}
}
else
{
attachments = [];
weaponName = GetWeaponBaseName( sWeapon );
if( IsDefined( weaponName ) )
{
// set to knife only weapon to get knife image for lua
if( sMeansOfDeath == "MOD_MELEE" && ( !maps\mp\gametypes\_weapons::isRiotShield( sWeapon ) ) )
{
weaponName = "iw6_knifeonly";
}
else
{
weaponName = weaponMap( weaponName );
weaponName = strip_suffix( weaponName, "_mp" );
}
weaponRowIdx = TableLookupRowNum( "mp/statsTable.csv", 4, weaponName );
self SetClientOmnvar( "ui_killcam_killedby_weapon", weaponRowIdx );
self SetClientOmnvar( "ui_killcam_killedby_killstreak", -1 );
if( weaponName != "iw6_knifeonly" )
attachments = GetWeaponAttachments( sWeapon );
}
else
{
self SetClientOmnvar( "ui_killcam_killedby_weapon", -1 );
self SetClientOmnvar( "ui_killcam_killedby_killstreak", -1 );
}
for( i = 0; i < 4; i++ )
{
if( IsDefined( attachments[ i ] ) )
{
attachmentRowIdx = TableLookupRowNum( "mp/attachmentTable.csv", 4, attachmentMap_toBase( attachments[ i ] ) );
self SetClientOmnvar( "ui_killcam_killedby_attachment" + ( i + 1 ), attachmentRowIdx );
}
else
{
self SetClientOmnvar( "ui_killcam_killedby_attachment" + ( i + 1 ), -1 );
}
}
// abilities, bit masking for lua
bit_mask = [ 0, 0 ];
pers_loadout_perks = attacker.pers[ "loadoutPerks" ];
for( i = 0; i < pers_loadout_perks.size; i++ )
{
idx = int( TableLookup( "mp/killCamAbilitiesBitMaskTable.csv", 1, pers_loadout_perks[i], 0 ) );
if( idx == 0 )
continue;
bitmaskIdx = int( ( idx - 1 ) / 24 );
bit = 1 << ( ( idx - 1 ) % 24 );
bit_mask[bitmaskIdx] |= bit;
}
self SetClientOmnvar( "ui_killcam_killedby_abilities1", bit_mask[0] );
self SetClientOmnvar( "ui_killcam_killedby_abilities2", bit_mask[1] );
}
forceRespawn = GetDvarInt( "scr_player_forcerespawn" );
if ( timeUntilRespawn && !level.gameEnded || ( isDefined( self ) && isDefined(self.battleBuddy) && !level.gameEnded )
|| forceRespawn == false && !level.gameEnded )
{
//setLowerMessage( "kc_info", &"PLATFORM_PRESS_TO_SKIP", undefined, undefined, undefined, undefined, undefined, undefined, true );
self SetClientOmnvar( "ui_killcam_text", "skip" );
}
else if ( !level.gameEnded )
{
//setLowerMessage( "kc_info", &"PLATFORM_PRESS_TO_RESPAWN", undefined, undefined, undefined, undefined, undefined, undefined, true );
self SetClientOmnvar( "ui_killcam_text", "respawn" );
}
else
{
self SetClientOmnvar( "ui_killcam_text", "none" );
}
// END LUA
startTime = getTime();
self notify ( "begin_killcam", startTime );
if ( !isAgent(attacker) && isDefined( attacker ) ) // attacker may have disconnected
attacker visionsyncwithplayer( victim );
self updateSessionState( "spectator", "hud_status_dead" );
self.spectatekillcam = true;
if( IsAgent( attacker ) || IsAgent( eInflictor ) )
{
attackerNum = victim GetEntityNumber();
// fix issue with victim disappearing for 1 snapshot when killcam is played via victim
// subtract half a server frame time (50 / 2) that will be added in code when psoffsettime is set
offsetTime -= 25;
}
self.forcespectatorclient = attackerNum;
self.killcamentity = -1;
usingCinematicKillCam = self setKillCameraStyle( eInflictor, inflictorAgentInfo, attackerNum, victim, killcamentityindex, killcamTimes );
if ( !usingCinematicKillCam )
self thread setKillCamEntity( killcamentityindex, killcamTimes.killcamoffset, killcamentitystarttime );
self.archivetime = killcamTimes.killcamoffset;
self.killcamlength = killcamTimes.killcamlength;
self.psoffsettime = offsetTime;
// ignore spectate permissions
self allowSpectateTeam("allies", true);
self allowSpectateTeam("axis", true);
self allowSpectateTeam("freelook", true);
self allowSpectateTeam("none", true);
if( level.multiTeamBased )
{
foreach( teamname in level.teamNameList )
{
self allowSpectateTeam( teamname, true );
}
}
self thread endedKillcamCleanup();
// wait till the next server frame to allow code a chance to update archivetime if it needs trimming
wait 0.05;
if( !isDefined( self ) )
return;
assertex( self.archivetime <= killcamTimes.killcamoffset + 0.0001, "archivetime: " + self.archivetime + ", killcamTimes.killcamoffset: " + killcamTimes.killcamoffset );
if ( self.archivetime < killcamTimes.killcamoffset )
{
truncation_amount = killcamTimes.killcamoffset - self.archivetime;
if ( game["truncated_killcams"] < 32 )
{
println( "Truncated killcam is being recorded. Count = " + game["truncated_killcams"] );
setMatchData( "killcam", game["truncated_killcams"], truncation_amount );
game["truncated_killcams"]++;
}
println( "WARNING: Code trimmed killcam time by " + truncation_amount + " seconds because it doesn't have enough game time recorded!" );
}
killcamTimes.camtime = self.archivetime - .05 - predelay;
killcamTimes.killcamlength = killcamTimes.camtime + killcamTimes.postdelay;
self.killcamlength = killcamTimes.killcamlength;
if ( killcamTimes.camtime <= 0 ) // if we're not looking back in time far enough to even see the death, cancel
{
println( "Cancelling killcam because we don't even have enough recorded to show the death." );
self updateSessionState( "dead" );
self ClearKillcamState();
self notify ( "killcam_ended" );
return;
}
showFinalKillcamFX = level.showingFinalKillcam;
// LUA: we need to show timer info in the lua killcam, this will tell the killcam to display and eveything else to hide
self SetClientOmnvar( "ui_killcam_end_milliseconds", int( killcamTimes.killcamlength * 1000 ) + GetTime() );
if ( showFinalKillcamFX )
self SetClientOmnvar( "ui_killcam_victim_or_attacker", 1 );
// END LUA
/#
if ( getDvarInt( "scr_devfinalkillcam" ) != 0 )
showFinalKillcamFX = !IsBot( victim ) && !IsAgent( victim );
#/
if ( showFinalKillcamFX )
self thread doFinalKillCamFX( killcamTimes, self.killcamentity, attacker, victim, sMeansOfDeath );
self.killcam = true;
if ( isDefined( self.battleBuddy ) && !level.gameEnded )
{
self.battleBuddyRespawnTimeStamp = GetTime();
}
self thread spawnedKillcamCleanup();
if ( !level.showingFinalKillcam )
self thread waitSkipKillcamButton( timeUntilRespawn );
else
self notify ( "showing_final_killcam" );
self thread endKillcamIfNothingToShow();
self waittillKillcamOver();
if ( level.showingFinalKillcam )
{
self thread maps\mp\gametypes\_playerlogic::spawnEndOfGame();
return;
}
self thread calculateKillCamTime( startTime );
self thread killcamCleanup( true );
}
doFinalKillCamFX( killcamInfo, killcamentityindex, eAttacker, eVictim, sMeansOfDeath )
{
self endon("killcam_ended");
if ( isDefined( level.doingFinalKillcamFx ) )
return;
level.doingFinalKillcamFx = true;
camTime = killcamInfo.camTime;
accumTime = 0;
victimNum = eVictim GetEntityNumber();
// attacker cam
// we do killcamInfo here because it could be a dog or agent
if( !IsDefined( killcamInfo.attackerNum ) )
killcamInfo.attackerNum = eAttacker GetEntityNumber();
// this is the final slowmo when the victim dies
intoSlowMoTime = camTime;
if ( intoSlowMoTime > 1.0 )
{
intoSlowMoTime = 1.0;
accumTime += 1.0;
wait( camTime - accumTime );
}
SetSlowMotion( 1.0, 0.25, intoSlowMoTime ); // start timescale, end timescale, lerp duration
wait( intoSlowMoTime + .5 );
// finally show the attacker in 3rd person
SetSlowMotion( 0.25, 1, 1 );
level.doingFinalKillcamFx = undefined;
}
calculateKillCamTime( startTime )
{
watchedTime = int(getTime() - startTime);
self incPlayerStat( "killcamtimewatched", watchedTime );
}
waittillKillcamOver()
{
self endon("abort_killcam");
wait(self.killcamlength - 0.05);
}
setKillCamEntity( killcamentityindex, killcamoffset, starttime )
{
self endon("disconnect");
self endon("killcam_ended");
killcamtime = (gettime() - killcamoffset * 1000);
if ( starttime > killcamtime )
{
wait .05;
// code may have trimmed archivetime after the first frame if we couldn't go back in time as far as requested.
killcamoffset = self.archivetime;
killcamtime = (gettime() - killcamoffset * 1000);
if ( starttime > killcamtime )
wait (starttime - killcamtime) / 1000;
}
self.killcamentity = killcamentityindex;
}
waitSkipKillcamButton( timeUntilRespawn )
{
self endon("disconnect");
self endon("killcam_ended");
if ( !IsAI( self ) )
{
self NotifyOnPlayerCommand( "kc_respawn", "+usereload" );
self NotifyOnPlayerCommand( "kc_respawn", "+activate" );
self waittill("kc_respawn");
self.cancelKillcam = true;
if ( !matchMakingGame() )
self incPlayerStat( "killcamskipped", 1 );
if ( timeUntilRespawn <= 0 )
clearLowerMessage( "kc_info" );
self notify("abort_killcam");
}
}
endKillcamIfNothingToShow()
{
self endon("disconnect");
self endon("killcam_ended");
while(1)
{
// code may trim our archivetime to zero if there is nothing "recorded" to show.
// this can happen when the person we're watching in our killcam goes into killcam himself.
// in this case, end the killcam.
if ( self.archivetime <= 0 )
break;
wait .05;
}
self notify("abort_killcam");
}
spawnedKillcamCleanup()
{
self endon("disconnect");
self endon("killcam_ended");
self waittill("spawned");
self thread killcamCleanup( false );
}
endedKillcamCleanup()
{
self endon("disconnect");
self endon("killcam_ended");
level waittill("game_ended");
self thread killcamCleanup( true );
}
killcamCleanup( clearState )
{
// LUA: we need to reset this dvar so the killcam will reset
self SetClientOmnvar( "ui_killcam_end_milliseconds", 0 );
// END LUA
self.killcam = undefined;
showingFinalKillcam = level.showingFinalKillcam;
/#
if ( getDvarInt( "scr_devfinalkillcam" ) != 0 )
{
showingFinalKillcam = true;
SetSlowMotion( 1.0, 1.0, 0.0 );
level.doingFinalKillcamFx = undefined;
}
#/
if( !showingFinalKillcam )
self setCinematicCameraStyle( "unknown", -1, -1 );
if ( !level.gameEnded )
self clearLowerMessage( "kc_info" );
self thread maps\mp\gametypes\_spectating::setSpectatePermissions();
self notify("killcam_ended"); // do this last, in case this function was called from a thread ending on it
if ( !clearState )
return;
self updateSessionState( "dead" );
self ClearKillcamState();
}
// 2013-06-26 wallace
// waitSkipKillcamButton does the same thing, no reason to do both
/*
cancelKillCamOnUse()
{
self.cancelKillcam = false;
self thread cancelKillCamOnUse_specificButton( "+usereload", ::cancelKillCamCallback );
//self thread cancelKillCamOnUse_specificButton( "+frag", ::cancelKillCamSafeSpawnCallback );
}
cancelKillCamCallback()
{
self.cancelKillcam = true;
}
cancelKillCamSafeSpawnCallback()
{
self.cancelKillcam = true;
self.wantSafeSpawn = true;
}
cancelKillCamOnUse_specificButton( inputFlag, finishedFunc )
{
self endon ( "death_delay_finished" );
self endon ( "disconnect" );
level endon ( "game_ended" );
while ( true )
{
self waittill( inputFlag );
self [[finishedFunc]]();
return;
}
}
*/

1108
maps/mp/gametypes/_menus.gsc Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,671 @@
#include common_scripts\utility;
#include maps\mp\_utility;
#include maps\mp\gametypes\_hud_util;
init()
{
//using allies defaults for all this stuff for now.
game["music"]["spawn_allies"] = "mus_us_spawn";
game["music"]["defeat_allies"] = "mus_us_defeat";
game["music"]["victory_allies"] = "mus_us_victory";
game["music"]["winning_allies"] = "mus_us_winning";
game["music"]["losing_allies"] = "mus_us_losing";
game["voice"]["allies"] = maps\mp\gametypes\_teams::getTeamVoicePrefix( "allies" ) + "1mc_";
game["music"]["allies_used_nuke"] = "mus_us_nuke_fired";
game["music"]["allies_hit_by_nuke"] = "mus_us_nuke_hit";
game["music"]["draw_allies"] = "mus_us_draw";
game["music"]["spawn_axis"] = "mus_fd_spawn";
game["music"]["defeat_axis"] = "mus_fd_defeat";
game["music"]["victory_axis"] = "mus_fd_victory";
game["music"]["winning_axis"] = "mus_fd_winning";
game["music"]["losing_axis"] = "mus_fd_losing";
game["voice"]["axis"] = maps\mp\gametypes\_teams::getTeamVoicePrefix( "axis" ) + "1mc_";
game["music"]["axis_used_nuke"] = "mus_fd_nuke_fired";
game["music"]["axis_hit_by_nuke"] = "mus_fd_nuke_hit";
game["music"]["draw_axis"] = "mus_fd_draw";
game["music"]["losing_time"] = "mp_time_running_out_losing";
game["music"]["allies_suspense"] = [];
game["music"]["allies_suspense"][game["music"]["allies_suspense"].size] = "mus_us_suspense_01";
game["music"]["allies_suspense"][game["music"]["allies_suspense"].size] = "mus_us_suspense_02";
game["music"]["allies_suspense"][game["music"]["allies_suspense"].size] = "mus_us_suspense_03";
game["music"]["allies_suspense"][game["music"]["allies_suspense"].size] = "mus_us_suspense_04";
game["music"]["allies_suspense"][game["music"]["allies_suspense"].size] = "mus_us_suspense_05";
game["music"]["allies_suspense"][game["music"]["allies_suspense"].size] = "mus_us_suspense_06";
game["music"]["axis_suspense"] = [];
game["music"]["axis_suspense"][game["music"]["axis_suspense"].size] = "mus_fd_suspense_01";
game["music"]["axis_suspense"][game["music"]["axis_suspense"].size] = "mus_fd_suspense_02";
game["music"]["axis_suspense"][game["music"]["axis_suspense"].size] = "mus_fd_suspense_03";
game["music"]["axis_suspense"][game["music"]["axis_suspense"].size] = "mus_fd_suspense_04";
game["music"]["axis_suspense"][game["music"]["axis_suspense"].size] = "mus_fd_suspense_05";
game["music"]["axis_suspense"][game["music"]["axis_suspense"].size] = "mus_fd_suspense_06";
game["dialog"]["mission_success"] = "mission_success";
game["dialog"]["mission_failure"] = "mission_fail";
game["dialog"]["mission_draw"] = "draw";
game["dialog"]["round_success"] = "encourage_win";
game["dialog"]["round_failure"] = "encourage_lost";
game["dialog"]["round_draw"] = "draw";
// status
game["dialog"]["timesup"] = "timesup";
game["dialog"]["winning_time"] = "winning";
game["dialog"]["losing_time"] = "losing";
game["dialog"]["winning_score"] = "winning_fight";
game["dialog"]["losing_score"] = "losing_fight";
game["dialog"]["lead_lost"] = "lead_lost";
game["dialog"]["lead_tied"] = "tied";
game["dialog"]["lead_taken"] = "lead_taken";
game["dialog"]["last_alive"] = "lastalive";
game["dialog"]["boost"] = "boost";
if ( !isDefined( game["dialog"]["offense_obj"] ) )
game["dialog"]["offense_obj"] = "boost";
if ( !isDefined( game["dialog"]["defense_obj"] ) )
game["dialog"]["defense_obj"] = "boost";
game["dialog"]["hardcore"] = "hardcore";
game["dialog"]["highspeed"] = "highspeed";
game["dialog"]["tactical"] = "tactical";
game["dialog"]["challenge"] = "challengecomplete";
game["dialog"]["promotion"] = "promotion";
game["dialog"]["bomb_taken"] = "acheive_bomb";
game["dialog"]["bomb_lost"] = "bomb_taken";
game["dialog"]["bomb_defused"] = "bomb_defused"; // 2013-08-01 wallace this is not used anymore, bc we have team specific options
game["dialog"]["bomb_defused_axis"] = "bomb_defused_axis";
game["dialog"]["bomb_defused_allies"] = "bomb_defused_allies";
game["dialog"]["bomb_planted"] = "bomb_planted";
game["dialog"]["obj_taken"] = "securedobj";
game["dialog"]["obj_lost"] = "lostobj";
game["dialog"]["obj_defend"] = "obj_defend";
game["dialog"]["obj_destroy"] = "obj_destroy";
game["dialog"]["obj_capture"] = "capture_obj";
game["dialog"]["objs_capture"] = "capture_objs";
game["dialog"]["hq_located"] = "hq_located";
game["dialog"]["hq_enemy_captured"] = "hq_captured";
game["dialog"]["hq_enemy_destroyed"] = "hq_destroyed";
game["dialog"]["hq_secured"] = "hq_secured";
game["dialog"]["hq_offline"] = "hq_offline";
game["dialog"]["hq_online"] = "hq_online";
game["dialog"]["move_to_new"] = "new_positions";
game["dialog"]["push_forward"] = "pushforward";
game["dialog"]["attack"] = "attack";
game["dialog"]["defend"] = "defend";
game["dialog"]["offense"] = "offense";
game["dialog"]["defense"] = "defense";
game["dialog"]["halftime"] = "halftime";
game["dialog"]["overtime"] = "overtime";
game["dialog"]["side_switch"] = "switching";
game["dialog"]["flag_taken"] = "ourflag";
game["dialog"]["flag_dropped"] = "ourflag_drop";
game["dialog"]["flag_returned"] = "ourflag_return";
game["dialog"]["flag_captured"] = "ourflag_capt";
game["dialog"]["flag_getback"] = "getback_ourflag";
game["dialog"]["enemy_flag_bringhome"] = "enemyflag_tobase";
game["dialog"]["enemy_flag_taken"] = "enemyflag";
game["dialog"]["enemy_flag_dropped"] = "enemyflag_drop";
game["dialog"]["enemy_flag_returned"] = "enemyflag_return";
game["dialog"]["enemy_flag_captured"] = "enemyflag_capt";
game["dialog"]["got_flag"] = "achieve_flag";
game["dialog"]["dropped_flag"] = "lost_flag";
game["dialog"]["enemy_got_flag"] = "enemy_has_flag";
game["dialog"]["enemy_dropped_flag"] = "enemy_dropped_flag";
game["dialog"]["capturing_a"] = "capturing_a";
game["dialog"]["capturing_b"] = "capturing_b";
game["dialog"]["capturing_c"] = "capturing_c";
game["dialog"]["captured_a"] = "capture_a";
game["dialog"]["captured_b"] = "capture_c";
game["dialog"]["captured_c"] = "capture_b";
game["dialog"]["securing_a"] = "securing_a";
game["dialog"]["securing_b"] = "securing_b";
game["dialog"]["securing_c"] = "securing_c";
game["dialog"]["secured_a"] = "secure_a";
game["dialog"]["secured_b"] = "secure_b";
game["dialog"]["secured_c"] = "secure_c";
game["dialog"]["losing_a"] = "losing_a";
game["dialog"]["losing_b"] = "losing_b";
game["dialog"]["losing_c"] = "losing_c";
game["dialog"]["lost_a"] = "lost_a";
game["dialog"]["lost_b"] = "lost_b";
game["dialog"]["lost_c"] = "lost_c";
game["dialog"]["enemy_taking_a"] = "enemy_take_a";
game["dialog"]["enemy_taking_b"] = "enemy_take_b";
game["dialog"]["enemy_taking_c"] = "enemy_take_c";
game["dialog"]["enemy_has_a"] = "enemy_has_a";
game["dialog"]["enemy_has_b"] = "enemy_has_b";
game["dialog"]["enemy_has_c"] = "enemy_has_c";
game["dialog"]["lost_all"] = "take_positions";
game["dialog"]["secure_all"] = "positions_lock";
game["dialog"]["losing_target"] = "enemy_capture";
game["dialog"]["lost_target"] = "lost_target";
game["dialog"]["taking_target"] = "capturing_target";
game["dialog"]["took_target"] = "achieve_target";
game["dialog"]["defcon_raised"] = "defcon_raised";
game["dialog"]["defcon_lowered"] = "defcon_lowered";
game["dialog"]["one_minute_left"] = "one_minute";
game["dialog"]["thirty_seconds_left"] = "thirty_seconds";
game["music"]["nuke_music"] = "nuke_music";
game["dialog"]["sentry_destroyed"] = "sentry_destroyed";
game["dialog"]["sentry_gone"] = "sentry_gone";
game["dialog"]["ti_destroyed"] = "ti_blocked";
game["dialog"]["ti_gone"] = "ti_cancelled";
game["dialog"]["ims_destroyed"] = "ims_destroyed";
game["dialog"]["satcom_destroyed"] = "satcom_destroyed";
game["dialog"]["ballistic_vest_destroyed"] = "ballistic_vest_destroyed";
game["dialog"]["ammocrate_destroyed"] = "ammocrate_destroyed";
game["dialog"]["ammocrate_gone"] = "ammocrate_gone";
game["dialog"]["achieve_carepackage"] = "achieve_carepackage";
game["dialog"]["gryphon_destroyed"] = "gryphon_destroyed";
game["dialog"]["gryphon_gone"] = "gryphon_gone";
game["dialog"]["vulture_destroyed"] = "vulture_destroyed";
game["dialog"]["vulture_gone"] = "vulture_gone";
game["dialog"]["nowl_destroyed"] = "nowl_destroyed";
game["dialog"]["nowl_gone"] = "nowl_gone";
game["dialog"]["oracle_gone"] = "oracle_gone";
game["dialog"]["dog_gone"] = "dog_gone";
game["dialog"]["dog_killed"] = "dog_killed";
game["dialog"]["squad_gone"] = "squad_gone";
game["dialog"]["squad_killed"] = "squad_killed";
game["dialog"]["odin_gone"] = "odin_gone";
game["dialog"]["odin_carepackage"] = "odin_carepackage";
game["dialog"]["odin_marking"] = "odin_marking";
game["dialog"]["odin_marked"] = "odin_marked";
game["dialog"]["odin_m_marked"] = "odin_m_marked";
game["dialog"]["odin_smoke"] = "odin_smoke";
game["dialog"]["odin_moving"] = "odin_moving";
game["dialog"]["loki_gone"] = "loki_gone";
game["dialog"]["odin_target_killed"] = "odin_target_killed";
game["dialog"]["odin_targets_killed"] = "odin_targets_killed";
game["dialog"]["claymore_destroyed"] = "null";
game["dialog"]["mine_destroyed"] = "null";
level thread onPlayerConnect();
level thread onLastAlive();
level thread musicController();
level thread onGameEnded();
level thread onRoundSwitch();
}
onPlayerConnect()
{
for(;;)
{
level waittill ( "connected", player );
player thread onPlayerSpawned();
player thread finalKillcamMusic();
player thread watchHostMigration();
}
}
onPlayerSpawned() // self == player
{
self endon ( "disconnect" );
if ( !isAI( self ) )
{
self waittill( "spawned_player" );
self thread doIntro();
}
}
doIntro() // self == player
{
level endon( "host_migration_begin" );
if ( !level.splitscreen || level.splitscreen && !isDefined( level.playedStartingMusic ) )
{
//only play one spawn music
if( !self isSplitscreenPlayer() || self isSplitscreenPlayerPrimary() )
self playLocalSound( game["music"]["spawn_" + self.team] );
if ( level.splitscreen )
level.playedStartingMusic = true;
}
if ( isDefined( game["dialog"]["gametype"] ) && (!level.splitscreen || self == level.players[0]) )
{
if ( isDefined( game["dialog"]["allies_gametype"] ) && self.team == "allies" )
self leaderDialogOnPlayer( "allies_gametype" );
else if ( isDefined( game["dialog"]["axis_gametype"] ) && self.team == "axis" )
self leaderDialogOnPlayer( "axis_gametype" );
else if ( !self isSplitscreenPlayer() || self isSplitscreenPlayerPrimary() )
self leaderDialogOnPlayer( "gametype" );
}
gameFlagWait( "prematch_done" );
//player could disco during this wait
if ( !isDefined( self ) )
return;
if ( self.team == game["attackers"] )
{
if( !self isSplitscreenPlayer() || self isSplitscreenPlayerPrimary() )
self leaderDialogOnPlayer( "offense_obj", "introboost" );
}
else
{
if( !self isSplitscreenPlayer() || self isSplitscreenPlayerPrimary() )
self leaderDialogOnPlayer( "defense_obj", "introboost" );
}
}
watchHostMigration() // self == player
{
self endon( "disconnect" );
level endon( "grace_period_ending" );
while( true )
{
level waittill( "host_migration_begin" );
was_in_grace_period = level.inGracePeriod;
level waittill( "host_migration_end" );
if( was_in_grace_period )
self thread doIntro();
}
}
onLastAlive()
{
level endon ( "game_ended" );
level waittill ( "last_alive", player );
if ( !isAlive( player ) )
return;
player leaderDialogOnPlayer( "last_alive" );
}
onRoundSwitch()
{
level waittill ( "round_switch", switchType );
switch( switchType )
{
case "halftime":
foreach ( player in level.players )
{
if( player isSplitscreenPlayer() && !player isSplitscreenPlayerPrimary() )
continue;
player leaderDialogOnPlayer( "halftime" );
}
break;
case "overtime":
foreach ( player in level.players )
{
if( player isSplitscreenPlayer() && !player isSplitscreenPlayerPrimary() )
continue;
player leaderDialogOnPlayer( "overtime" );
}
break;
default:
foreach ( player in level.players )
{
if( player isSplitscreenPlayer() && !player isSplitscreenPlayerPrimary() )
continue;
player leaderDialogOnPlayer( "side_switch" );
}
break;
}
}
onGameEnded()
{
level thread roundWinnerDialog();
level thread gameWinnerDialog();
level waittill ( "game_win", winner );
if ( level.teamBased )
{
if ( level.splitscreen )
{
if ( winner == "allies" )
playSoundOnPlayers( game["music"]["victory_allies"], "allies" );
else if ( winner == "axis" )
playSoundOnPlayers( game["music"]["victory_axis"], "axis" );
else
playSoundOnPlayers( game["music"]["nuke_music"] );
}
else
{
if ( winner == "allies" )
{
playSoundOnPlayers( game["music"]["victory_allies"], "allies" );
playSoundOnPlayers( game["music"]["defeat_axis"], "axis" );
}
else if ( winner == "axis" )
{
playSoundOnPlayers( game["music"]["victory_axis"], "axis" );
playSoundOnPlayers( game["music"]["defeat_allies"], "allies" );
}
else
{
playSoundOnPlayers( game["music"]["draw_axis"], "axis" );
playSoundOnPlayers( game["music"]["draw_allies"], "allies" );
}
}
}
else
{
foreach ( player in level.players )
{
if( player isSplitscreenPlayer() && !player isSplitscreenPlayerPrimary() )
continue;
if ( player.pers["team"] != "allies" && player.pers["team"] != "axis" )
player playLocalSound( game["music"]["nuke_music"] );
else if ( isDefined( winner ) && isPlayer( winner ) && player == winner )
player playLocalSound( game["music"]["victory_" + player.pers["team"] ] );
else if ( !level.splitScreen )
player playLocalSound( game["music"]["defeat_" + player.pers["team"] ] );
}
}
}
roundWinnerDialog()
{
level waittill ( "round_win", winner );
delay = level.roundEndDelay / 4;
if ( delay > 0 )
wait ( delay );
if ( !isDefined( winner ) || isPlayer( winner ) /*|| isDefined( level.nukeDetonated )*/ )
return;
if ( winner == "allies" )
{
leaderDialog( "round_success", "allies" );
leaderDialog( "round_failure", "axis" );
}
else if ( winner == "axis" )
{
leaderDialog( "round_success", "axis" );
leaderDialog( "round_failure", "allies" );
}
}
gameWinnerDialog()
{
level waittill ( "game_win", winner );
delay = level.postRoundTime / 2;
if ( delay > 0 )
wait ( delay );
if ( !isDefined( winner ) || isPlayer( winner ) /*|| isDefined( level.nukeDetonated )*/ )
return;
if ( winner == "allies" )
{
leaderDialog( "mission_success", "allies" );
leaderDialog( "mission_failure", "axis" );
}
else if ( winner == "axis" )
{
leaderDialog( "mission_success", "axis" );
leaderDialog( "mission_failure", "allies" );
}
else
{
leaderDialog( "mission_draw" );
}
}
musicController()
{
level endon ( "game_ended" );
level.musicEnabled = 1;
thread suspenseMusic();
level waittill ( "match_ending_soon", reason );
assert( isDefined( reason ) );
// Also checking for isModdedRoundGame(), since blitz is based on teamscores as well
if ( getWatchedDvar( "roundlimit" ) == 1 || game["roundsPlayed"] == (getWatchedDvar( "roundlimit" ) - 1) || isModdedRoundGame() )
{
if ( !level.splitScreen )
{
if ( reason == "time" )
{
if ( level.teamBased )
{
if ( game["teamScores"]["allies"] > game["teamScores"]["axis"] )
{
if ( isMusicEnabled() )
{
playSoundOnPlayers( game["music"]["winning_allies"], "allies" );
playSoundOnPlayers( game["music"]["losing_axis"], "axis" );
}
leaderDialog( "winning_time", "allies" );
leaderDialog( "losing_time", "axis" );
}
else if ( game["teamScores"]["axis"] > game["teamScores"]["allies"] )
{
if ( !level.hardcoreMode )
{
playSoundOnPlayers( game["music"]["winning_axis"], "axis" );
playSoundOnPlayers( game["music"]["losing_allies"], "allies" );
}
leaderDialog( "winning_time", "axis" );
leaderDialog( "losing_time", "allies" );
}
}
else
{
if ( isMusicEnabled() )
playSoundOnPlayers( game["music"]["losing_time"] );
leaderDialog( "timesup" );
}
}
else if ( reason == "score" )
{
if ( level.teamBased )
{
if ( game["teamScores"]["allies"] > game["teamScores"]["axis"] )
{
if ( isMusicEnabled() )
{
playSoundOnPlayers( game["music"]["winning_allies"], "allies" );
playSoundOnPlayers( game["music"]["losing_axis"], "axis" );
}
leaderDialog( "winning_score", "allies" );
leaderDialog( "losing_score", "axis" );
}
else if ( game["teamScores"]["axis"] > game["teamScores"]["allies"] )
{
if ( isMusicEnabled() )
{
playSoundOnPlayers( game["music"]["winning_axis"], "axis" );
playSoundOnPlayers( game["music"]["losing_allies"], "allies" );
}
leaderDialog( "winning_score", "axis" );
leaderDialog( "losing_score", "allies" );
}
}
else
{
winningPlayer = maps\mp\gametypes\_gamescore::getHighestScoringPlayer();
losingPlayers = maps\mp\gametypes\_gamescore::getLosingPlayers();
excludeList[0] = winningPlayer;
if ( isMusicEnabled() )
{
winningPlayer playLocalSound( game["music"]["winning_" + winningPlayer.pers["team"] ] );
foreach ( otherPlayer in level.players )
{
if ( otherPlayer == winningPlayer )
continue;
otherPlayer playLocalSound( game["music"]["losing_" + otherPlayer.pers["team"] ] );
}
}
winningPlayer leaderDialogOnPlayer( "winning_score" );
leaderDialogOnPlayers( "losing_score", losingPlayers );
}
}
level waittill ( "match_ending_very_soon" );
leaderDialog( "timesup" );
}
}
else
{
if ( !level.hardcoreMode )
playSoundOnPlayers( game["music"]["losing_allies"] );
leaderDialog( "timesup" );
}
}
suspenseMusic( skipInitialDelay )
{
if ( !isMusicEnabled() )
return;
level endon ( "game_ended" );
level endon ( "match_ending_soon" );
level endon ( "stop_suspense_music" );
if ( IsDefined( level.noSuspenseMusic ) && level.noSuspenseMusic )
return;
allies_numTracks = game["music"]["allies_suspense"].size;
axis_numTracks = game["music"]["axis_suspense"].size;
level.curSuspsenseTrack = [];
if ( IsDefined( skipInitialDelay ) && skipInitialDelay )
wait ( 120 );
for ( ;; )
{
wait ( randomFloatRange( 60, 120 ) );
level.curSuspsenseTrack[ "allies" ] = RandomInt(allies_numTracks);
playSoundOnPlayers( game["music"]["allies_suspense"][level.curSuspsenseTrack[ "allies" ]], "allies" );
level.curSuspsenseTrack[ "axis" ] = RandomInt(axis_numTracks);
playSoundOnPlayers( game["music"]["axis_suspense"][level.curSuspsenseTrack[ "axis" ]], "axis" );
}
}
stopSuspenseMusic()
{
// block suspense music from playing
level notify ( "stop_suspense_music" );
// stop current suspense music, if it's playing.
if ( IsDefined( level.curSuspsenseTrack ) && level.curSuspsenseTrack.size == 2 )
{
foreach ( player in level.players )
{
team = player.team;
// this is ugly; must save the sound ID in order to stop it;
player StopLocalSound( game["music"][team + "_suspense"][level.curSuspsenseTrack[ team ]] );
}
}
}
finalKillcamMusic()
{
self waittill ( "showing_final_killcam" );
}
// general interface for music
enableMusic()
{
if ( level.musicEnabled == 0 )
{
thread suspenseMusic();
}
level.musicEnabled++;
}
// TODO: This only blocks future music from playing; it does not stop any currently playing tracks
disableMusic()
{
if ( level.musicEnabled > 0 )
{
level.musicEnabled--;
if ( level.musicEnabled == 0 )
{
stopSuspenseMusic();
}
}
else
{
AssertMsg( "Trying to disable music when already disabled!" );
}
}
isMusicEnabled()
{
return ( !level.hardcoreMode && level.musicEnabled > 0 );
}

View File

@ -0,0 +1,160 @@
#include maps\mp\_utility;
#include maps\mp\gametypes\_hud_util;
init()
{
precacheShader("objpoint_default");
level.objPointNames = [];
level.objPoints = [];
if ( level.splitscreen )
level.objPointSize = 15;
else
level.objPointSize = 8;
level.objpoint_alpha_default = 0.75;
level.objPointScale = 1.0;
}
createTeamObjpoint( name, origin, team, shader, alpha, scale )
{
assert( team == "axis" || team == "allies" || team == "all" || IsSubStr( team, "team_" ));
objPoint = getObjPointByName( name );
if ( isDefined( objPoint ) )
deleteObjPoint( objPoint );
if ( !isDefined( shader ) )
shader = "objpoint_default";
if ( !isDefined( scale ) )
scale = 1.0;
if ( team != "all" )
objPoint = newTeamHudElem( team );
else
objPoint = newHudElem();
objPoint.name = name;
objPoint.x = origin[0];
objPoint.y = origin[1];
objPoint.z = origin[2];
objPoint.team = team;
objPoint.isFlashing = false;
objPoint.isShown = true;
objPoint setShader( shader, level.objPointSize, level.objPointSize );
objPoint setWaypoint( true, false );
if ( isDefined( alpha ) )
objPoint.alpha = alpha;
else
objPoint.alpha = level.objpoint_alpha_default;
objPoint.baseAlpha = objPoint.alpha;
objPoint.index = level.objPointNames.size;
level.objPoints[name] = objPoint;
level.objPointNames[level.objPointNames.size] = name;
return objPoint;
}
deleteObjPoint( oldObjPoint )
{
assert( level.objPoints.size == level.objPointNames.size );
if ( level.objPoints.size == 1 )
{
assert( level.objPointNames[0] == oldObjPoint.name );
assert( isDefined( level.objPoints[oldObjPoint.name] ) );
level.objPoints = [];
level.objPointNames = [];
oldObjPoint destroy();
return;
}
newIndex = oldObjPoint.index;
oldIndex = (level.objPointNames.size - 1);
objPoint = getObjPointByIndex( oldIndex );
level.objPointNames[newIndex] = objPoint.name;
objPoint.index = newIndex;
level.objPointNames[oldIndex] = undefined;
level.objPoints[oldObjPoint.name] = undefined;
oldObjPoint destroy();
}
updateOrigin( origin )
{
if ( self.x != origin[0] )
self.x = origin[0];
if ( self.y != origin[1] )
self.y = origin[1];
if ( self.z != origin[2] )
self.z = origin[2];
}
setOriginByName( name, origin )
{
objPoint = getObjPointByName( name );
objPoint updateOrigin( origin );
}
getObjPointByName( name )
{
if ( isDefined( level.objPoints[name] ) )
return level.objPoints[name];
else
return undefined;
}
getObjPointByIndex( index )
{
if ( isDefined( level.objPointNames[index] ) )
return level.objPoints[level.objPointNames[index]];
else
return undefined;
}
startFlashing()
{
self endon("stop_flashing_thread");
if ( self.isFlashing )
return;
self.isFlashing = true;
while ( self.isFlashing )
{
self fadeOverTime( 0.75 );
self.alpha = 0.35 * self.baseAlpha;
wait ( 0.75 );
self fadeOverTime( 0.75 );
self.alpha = self.baseAlpha;
wait ( 0.75 );
}
self.alpha = self.baseAlpha;
}
stopFlashing()
{
if ( !self.isFlashing )
return;
self.isFlashing = false;
}

View File

@ -0,0 +1,399 @@
#include common_scripts\utility;
#include maps\mp\_utility;
#include maps\mp\gametypes\_hud_util;
// -.-.-.-.-.-.-.-.-.-. //
// Outline Init
// -.-.-.-.-.-.-.-.-.-. //
init()
{
level.outlineIDs = 0;
level.outlineEnts = [];
level thread outlineCatchPlayerDisconnect();
level thread outlineOnPlayerJoinedTeam();
}
// -.-.-.-.-.-.-.-.-.-. //
// Outline Private Logic
// -.-.-.-.-.-.-.-.-.-. //
// teamVisibleTo is optional and should only be added if the type is "TEAM"
// - this parameter is needed because an empty playersVisibleTo array could be passed to this
// function if no team members exist at the time of the call. In that case the team
// could not be grabbed from a playersVisibleTo entry
outlineEnableInternal( entToOutline, colorIndex, playersVisibleTo, depthEnable, priorityNum, type, teamVisibleTo )
{
AssertEx( type != "TEAM" || IsDefined( teamVisibleTo ), "outlineEnableInternal() passed type \"TEAM\" without teamVisibleTo being defined." );
if ( !IsDefined( entToOutline.outlines ) )
{
entToOutline.outlines = [];
}
oInfo = SpawnStruct();
oInfo.priority = priorityNum;
oInfo.colorIndex = colorIndex;
oInfo.playersVisibleTo = playersVisibleTo;
oInfo.depthEnable = depthEnable;
oInfo.type = type;
if ( type == "TEAM" )
{
oInfo.team = teamVisibleTo;
}
ID = outlineGenerateUniqueID();
entToOutline.outlines[ ID ] = oInfo;
outlineAddToGlobalList( entToOutline );
playersToSeeOutline = [];
foreach ( player in oInfo.playersVisibleTo )
{
oInfoHighest = outlineGetHighestInfoForPlayer( entToOutline, player );
// If the new outline priority is the same as the highest priority
// apply the new outline because it is the most recent
if ( !IsDefined( oInfoHighest ) || oInfoHighest == oInfo || oInfoHighest.priority == oInfo.priority )
{
playersToSeeOutline[ playersToSeeOutline.size ] = player;
}
}
if ( playersToSeeOutline.size > 0 )
{
entToOutline HudOutlineEnableForClients( playersToSeeOutline, oInfo.colorIndex, oInfo.depthEnable );
}
return ID;
}
outlineDisableInternal( ID, entOutlined )
{
if ( !IsDefined( entOutlined.outlines ) )
{
outlineRemoveFromGlobalList( entOutlined );
return;
}
else if ( !IsDefined( entOutlined.outlines[ ID ] ) )
{
return;
}
oInfoToDisable = entOutlined.outlines[ ID ];
// Remove outline info from array, preserve array keys (IDs)
outlinesUpdated = [];
foreach ( key, oInfo in entOutlined.outlines )
{
if ( oInfo != oInfoToDisable )
{
outlinesUpdated[ key ] = oInfo;
}
}
if ( outlinesUpdated.size == 0 )
{
outlineRemoveFromGlobalList( entOutlined );
}
// Make sure the entOutlined is not removed
if ( IsDefined( entOutlined ) )
{
entOutlined.outlines = outlinesUpdated;
foreach ( player in oInfoToDisable.playersVisibleTo )
{
// Make sure the player isn't removed
if ( !IsDefined( player ) )
continue;
oInfoHighest = outlineGetHighestInfoForPlayer( entOutlined, player );
if ( IsDefined( oInfoHighest ) )
{
// Outlined entities can have multiple outlines of the same
// priority so unless an outline is found with a higher priority
// a new outline call should be made to make sure an outline exists
// for this player. Otherwise assume the highest outline is already
// applied.
if ( oInfoHighest.priority <= oInfoToDisable.priority )
{
entOutlined HudOutlineEnableForClient( player, oInfoHighest.colorIndex, oInfoHighest.depthEnable );
}
}
else
{
entOutlined HudOutlineDisableForClient( player );
}
}
}
}
outlineCatchPlayerDisconnect()
{
while ( true )
{
// Assumes two players cannot connect on the same frame
level waittill( "connected", player );
level thread outlineOnPlayerDisconnect( player );
}
}
outlineOnPlayerDisconnect( player )
{
level endon( "game_ended" );
player waittill( "disconnect" );
// Intentionally call these even if the player is removed
// at this point so arrays can be scrubbed
outlineRemovePlayerFromVisibleToArrays( player );
outlineDisableInternalAll( player );
}
outlineOnPlayerJoinedTeam()
{
while ( true )
{
// Assumes two players cannot join a team on the same frame
level waittill( "joined_team", player );
if ( !IsDefined( player.team ) || player.team == "spectator" )
continue;
// After joined_team is notified the player could still be picking
// a class while seeing in 3rd person. Wait until spawn to actually
// adjust team outlines
thread outlineOnPlayerJoinedTeam_onFirstSpawn( player );
}
}
outlineOnPlayerJoinedTeam_onFirstSpawn( player )
{
// Players can change teams and then change team again
// without entering the game. End this thread if another
// change team notify happens before spawned_player
player notify( "outlineOnPlayerJoinedTeam_onFirstSpawn" );
player endon( "outlineOnPlayerJoinedTeam_onFirstSpawn" );
player endon( "disconnect" );
player waittill( "spawned_player" );
outlineRemovePlayerFromVisibleToArrays( player );
outlineDisableInternalAll( player );
outlineAddPlayerToExistingTeamOutlines( player );
}
outlineRemovePlayerFromVisibleToArrays( player )
{
level.outlineEnts = array_removeUndefined( level.outlineEnts );
foreach ( entOutlined in level.outlineEnts )
{
outlinedForPlayer = false;
foreach ( oInfo in entOutlined.outlines )
{
// Scrub outline array in case of undefined player references
oInfo.playersVisibleTo = array_removeUndefined( oInfo.playersVisibleTo );
if ( IsDefined( player ) && array_contains( oInfo.playersVisibleTo, player ) )
{
oInfo.playersVisibleTo = array_remove( oInfo.playersVisibleTo, player );
outlinedForPlayer = true;
}
}
if ( outlinedForPlayer && IsDefined( entOutlined ) && IsDefined( player ) )
{
entOutlined HudOutlineDisableForClient( player );
}
}
}
outlineAddPlayerToExistingTeamOutlines( player )
{
// Traverse outlined entities and add the player to any existing team outline calls
foreach ( entOutlined in level.outlineEnts )
{
// Outlined ents may be removed entities
if ( !IsDefined( entOutlined ) )
continue;
oInfoHighest = undefined;
foreach ( oInfo in entOutlined.outlines )
{
if ( ( oInfo.Type == "ALL" ) || ( oInfo.type == "TEAM" && oInfo.team == player.team ) )
{
if ( !array_contains( oInfo.playersVisibleTo, player ) )
{
oInfo.playersVisibleTo[ oInfo.playersVisibleTo.size ] = player;
}
else
{
AssertMsg( "Found a team outline call on a player's new team that already had a reference to him. This should never happen. Are we letting a player change teams to his own team?" );
}
if ( !IsDefined( oInfoHighest ) || oInfo.priority > oInfoHighest.priority )
{
oInfoHighest = oInfo;
}
}
}
if ( IsDefined( oInfoHighest ) )
{
entOutlined HudOutlineEnableForClient( player, oInfoHighest.colorIndex, oInfoHighest.depthEnable );
}
}
}
outlineDisableInternalAll( entOutlined )
{
if ( !IsDefined( entOutlined ) || !IsDefined( entOutlined.outlines ) || entOutlined.outlines.size == 0 )
return;
foreach ( ID, _ in entOutlined.outlines )
{
outlineDisableInternal( ID, entOutlined );
}
}
outlineAddToGlobalList( entOutlined )
{
if ( !array_contains( level.outlineEnts, entOutlined ) )
{
level.outlineEnts[ level.outlineEnts.size ] = entOutlined;
}
}
outlineRemoveFromGlobalList( entOutlined )
{
level.outlineEnts = array_remove( level.outlineEnts, entOutlined );
}
outlineGetHighestPriorityID( entOutlined )
{
result = -1;
if ( !IsDefined( entOutlined.outlines ) || entOutlined.size == 0 )
return result;
oInfoHighest = undefined;
foreach ( ID, oInfo in entOutlined.outlines )
{
if ( !IsDefined( oInfoHighest ) || oInfo.priority > oInfoHighest.priority )
{
oInfoHighest = oInfo;
result = ID;
}
}
return result;
}
outlineGetHighestInfoForPlayer( entOutlined, player )
{
oInfoHighest = undefined;
if ( IsDefined( entOutlined.outlines ) && entOutlined.outlines.size )
{
foreach ( ID, oInfo in entOutlined.outlines )
{
if ( array_contains( oInfo.playersVisibleTo, player ) && ( !IsDefined( oInfoHighest ) || oInfo.priority > oInfoHighest.priority ) )
{
oInfoHighest = oInfo;
}
}
}
return oInfoHighest;
}
outlineGenerateUniqueID()
{
AssertEx( IsDefined( level.outlineIDs ), "Outline enable called on entity before _outline::init() function has been called." );
level.outlineIDs++;
return level.outlineIDs;
}
outlinePriorityGroupMap( priorityGroup )
{
priorityGroup = ToLower( priorityGroup );
priority = undefined;
switch ( priorityGroup )
{
case "level_script":
priority = 0;
break;
case "equipment":
priority = 1;
break;
case "perk":
priority = 2;
break;
case "killstreak": // Killstreaks that are shared.
priority = 3;
break;
case "killstreak_personal": // Killstreaks like Odin or the Predator that should always trump things like the skylark which is a shared outline
priority = 4;
break;
default:
AssertMsg( "Invalid priority group passed to outlinePriorityGroupMap(): " + priorityGroup );
priority = 0;
break;
}
return priority;
}
outlineColorIndexMap( colorName )
{
colorName = ToLower( colorName );
idx = undefined;
switch ( colorName )
{
case "white":
idx = 0;
break;
case "red":
idx = 1;
break;
case "green":
idx = 2;
break;
case "cyan":
idx = 3;
break;
case "orange":
idx = 4;
break;
case "yellow":
idx = 5;
break;
case "blue":
idx = 6;
break;
default:
AssertMsg( "Invalid color name passed to outlineColorIndexMap(): " + colorName );
idx = 0;
break;
}
return idx;
}

View File

@ -0,0 +1,719 @@
#include maps\mp\_utility;
MAX_KD_HISTORY = 5;
init()
{
maps\mp\gametypes\_class::init();
if ( !is_aliens() )
{
level.persistentDataInfo = [];
maps\mp\gametypes\_missions::init();
maps\mp\gametypes\_rank::init();
level thread updateBufferedStats();
level thread uploadGlobalStatCounters();
level thread writeKDHistoryStats();
}
maps\mp\gametypes\_playercards::init();
}
initBufferedStats()
{
println( "Init Buffered Stats for " + self.name );
self.bufferedStats = [];
self.squadMemberBufferedStats = [];
if ( self rankingEnabled() )
{
self.bufferedStats[ "totalShots" ] = self getRankedPlayerData( "totalShots" );
self.bufferedStats[ "accuracy" ] = self getRankedPlayerData( "accuracy" );
self.bufferedStats[ "misses" ] = self getRankedPlayerData( "misses" );
self.bufferedStats[ "hits" ] = self getRankedPlayerData( "hits" );
self.bufferedStats[ "timePlayedAllies" ] = self getRankedPlayerData( "timePlayedAllies" );
self.bufferedStats[ "timePlayedOpfor" ] = self getRankedPlayerData( "timePlayedOpfor" );
self.bufferedStats[ "timePlayedOther" ] = self getRankedPlayerData( "timePlayedOther" );
self.bufferedStats[ "timePlayedTotal" ] = self getRankedPlayerData( "timePlayedTotal" );
activeMember = self GetRankedPlayerData( "activeSquadMember" );
self.squadMemberBufferedStats[ "experienceToPrestige" ] = self getRankedPlayerData( "squadMembers", activeMember, "experienceToPrestige" );
println( "timePlayedAllies " + self.bufferedStats[ "timePlayedAllies" ] );
println( "timePlayedOpfor " + self.bufferedStats[ "timePlayedOpfor" ] );
println( "timePlayedOther " + self.bufferedStats[ "timePlayedOther" ] );
println( "timePlayedTotal " + self.bufferedStats[ "timePlayedTotal" ] );
}
self.bufferedChildStats = [];
self.bufferedChildStats[ "round" ] = [];
self.bufferedChildStats[ "round" ][ "timePlayed" ] = self getCommonPlayerData( "round", "timePlayed" );
if ( self rankingEnabled() )
{
self.bufferedChildStats[ "xpMultiplierTimePlayed" ] = [];
self.bufferedChildStats[ "xpMultiplierTimePlayed" ][ 0 ] = self getRankedPlayerData( "xpMultiplierTimePlayed", 0 );
self.bufferedChildStats[ "xpMultiplierTimePlayed" ][ 1 ] = self getRankedPlayerData( "xpMultiplierTimePlayed", 1 );
self.bufferedChildStats[ "xpMultiplierTimePlayed" ][ 2 ] = self getRankedPlayerData( "xpMultiplierTimePlayed", 2 );
self.bufferedChildStatsMax[ "xpMaxMultiplierTimePlayed" ] = [];
self.bufferedChildStatsMax[ "xpMaxMultiplierTimePlayed" ][ 0 ] = self getRankedPlayerData( "xpMaxMultiplierTimePlayed", 0 );
self.bufferedChildStatsMax[ "xpMaxMultiplierTimePlayed" ][ 1 ] = self getRankedPlayerData( "xpMaxMultiplierTimePlayed", 1 );
self.bufferedChildStatsMax[ "xpMaxMultiplierTimePlayed" ][ 2 ] = self getRankedPlayerData( "xpMaxMultiplierTimePlayed", 2 );
self.bufferedChildStats[ "challengeXPMultiplierTimePlayed" ] = [];
self.bufferedChildStats[ "challengeXPMultiplierTimePlayed" ][ 0 ] = self getRankedPlayerData( "challengeXPMultiplierTimePlayed", 0 );
self.bufferedChildStatsMax[ "challengeXPMaxMultiplierTimePlayed" ] = [];
self.bufferedChildStatsMax[ "challengeXPMaxMultiplierTimePlayed" ][ 0 ] = self getRankedPlayerData( "challengeXPMaxMultiplierTimePlayed", 0 );
self.bufferedChildStats[ "weaponXPMultiplierTimePlayed" ] = [];
self.bufferedChildStats[ "weaponXPMultiplierTimePlayed" ][ 0 ] = self getRankedPlayerData( "weaponXPMultiplierTimePlayed", 0 );
self.bufferedChildStatsMax[ "weaponXPMaxMultiplierTimePlayed" ] = [];
self.bufferedChildStatsMax[ "weaponXPMaxMultiplierTimePlayed" ][ 0 ] = self getRankedPlayerData( "weaponXPMaxMultiplierTimePlayed", 0 );
if ( IsSquadsMode() )
{
self.bufferedStats["prestigeDoubleXp"] = self getRankedPlayerData( "prestigeDoubleXp" );
self.bufferedStats["prestigeDoubleXpTimePlayed"] = self getRankedPlayerData( "prestigeDoubleXpTimePlayed" );
self.bufferedStatsMax["prestigeDoubleXpMaxTimePlayed"] = self getRankedPlayerData( "prestigeDoubleXpMaxTimePlayed" );
}
//IW5 prestige reward double Weapon XP
self.bufferedStats["prestigeDoubleWeaponXp"] = self getRankedPlayerData( "prestigeDoubleWeaponXp" );
self.bufferedStats["prestigeDoubleWeaponXpTimePlayed"] = self getRankedPlayerData( "prestigeDoubleWeaponXpTimePlayed" );
self.bufferedStatsMax["prestigeDoubleWeaponXpMaxTimePlayed"] = self getRankedPlayerData( "prestigeDoubleWeaponXpMaxTimePlayed" );
}
}
// ==========================================
// Script persistent data functions
// These are made for convenience, so persistent data can be tracked by strings.
// They make use of code functions which are prototyped below.
/*
=============
statGet
Returns the value of the named stat
=============
*/
statGet( dataName )
{
assert( !isDefined( self.bufferedStats[ dataName ] ) ); // should use statGetBuffered consistently with statSetBuffered
return self getRankedPlayerData( dataName );
}
/*
=============
statSet
Sets the value of the named stat
=============
*/
statSet( dataName, value )
{
if ( !self rankingEnabled() )
return;
assert( !isDefined( self.bufferedStats[ dataName ] ) ); // should use statGetBuffered consistently with statSetBuffered
self setRankedPlayerData( dataName, value );
}
/*
=============
statAdd
Adds the passed value to the value of the named stat
=============
*/
statAdd( dataName, value, optionalArrayInd )
{
if ( !self rankingEnabled() )
return;
assert( !isDefined( self.bufferedStats[ dataName ] ) ); // should use statGetBuffered consistently with statSetBuffered
if ( isDefined( optionalArrayInd ) )
{
curValue = self getRankedPlayerData( dataName, optionalArrayInd );
self setRankedPlayerData( dataName, optionalArrayInd, value + curValue );
}
else
{
curValue = self getRankedPlayerData( dataName );
self setRankedPlayerData( dataName, value + curValue );
}
}
statGetChild( parent, child )
{
if ( parent == "round" )
return self getCommonPlayerData( parent, child );
else
return self getRankedPlayerData( parent, child );
}
statSetChild( parent, child, value )
{
if ( IsAgent(self) )
return;
if ( !self rankingEnabled() )
return;
if ( parent == "round" )
self setCommonPlayerData( parent, child, value );
else
self setRankedPlayerData( parent, child, value );
}
statAddChild( parent, child, value )
{
if ( !self rankingEnabled() )
return;
assert( isDefined( self.bufferedChildStats[ parent ][ child ] ) );
curValue = self getRankedPlayerData( parent, child );
self setRankedPlayerData( parent, child, curValue + value );
}
statGetChildBuffered( parent, child )
{
if ( !self rankingEnabled() )
return 0;
assert( isDefined( self.bufferedChildStats[ parent ][ child ] ) );
return self.bufferedChildStats[ parent ][ child ];
}
statSetChildBuffered( parent, child, value )
{
if ( !self rankingEnabled() )
return;
assert( isDefined( self.bufferedChildStats[ parent ][ child ] ) );
self.bufferedChildStats[ parent ][ child ] = value;
}
statAddChildBuffered( parent, child, value )
{
if ( !self rankingEnabled() )
return;
assert( isDefined( self.bufferedChildStats[ parent ][ child ] ) );
curValue = statGetChildBuffered( parent, child );
statSetChildBuffered( parent, child, curValue + value );
}
statAddBufferedWithMax( stat, value, max )
{
if ( !self rankingEnabled() )
return;
assert( isDefined( self.bufferedStats[ stat ] ) );
newValue = statGetBuffered( stat ) + value;
if ( newValue > max )
newValue = max;
if ( newValue < statGetBuffered( stat ) ) // has wrapped so keep at the max
newValue = max;
statSetBuffered( stat, newValue );
}
statAddChildBufferedWithMax( parent, child, value, max )
{
if ( !self rankingEnabled() )
return;
assert( isDefined( self.bufferedChildStats[ parent ][ child ] ) );
newValue = statGetChildBuffered( parent, child ) + value;
if ( newValue > max )
newValue = max;
if ( newValue < statGetChildBuffered( parent, child ) ) // has wrapped so keep at the max
newValue = max;
statSetChildBuffered( parent, child, newValue );
}
/*
=============
statGetBuffered
Returns the value of the named stat
=============
*/
statGetBuffered( dataName )
{
if ( !self rankingEnabled() )
return 0;
assert( isDefined( self.bufferedStats[ dataName ] ) );
return self.bufferedStats[ dataName ];
}
/*
=============
statGetSquadBuffered
Returns the value of the named squad stat
=============
*/
statGetSquadBuffered( dataName )
{
if ( !self rankingEnabled() )
return 0;
assert( isDefined( self.SquadMemberBufferedStats[ dataName ] ) );
return self.SquadMemberBufferedStats[ dataName ];
}
/*
=============
statSet
Sets the value of the named stat
=============
*/
statSetBuffered( dataName, value )
{
if ( !self rankingEnabled() )
return;
assert( isDefined( self.bufferedStats[ dataName ] ) );
self.bufferedStats[ dataName ] = value;
}
/*
=============
statSetSquad
Sets the value of the named stat
=============
*/
statSetSquadBuffered( dataName, value )
{
if ( !self rankingEnabled() )
return;
assert( isDefined( self.SquadMemberBufferedStats[ dataName ] ) );
self.SquadMemberBufferedStats[ dataName ] = value;
}
/*
=============
statAdd
Adds the passed value to the value of the named stat
=============
*/
statAddBuffered( dataName, value )
{
if ( !self rankingEnabled() )
return;
assert( isDefined( self.bufferedStats[ dataName ] ) );
assert( value >= 0 );
curValue = statGetBuffered( dataName );
statSetBuffered( dataName, curValue + value );
}
/*
=============
statAddSquadBuffered
Adds the passed value to the value of the named stat
=============
*/
statAddSquadBuffered( dataName, value )
{
if ( !self rankingEnabled() )
return;
assert( isDefined( self.SquadMemberBufferedStats[ dataName ] ) );
assert( value >= 0 );
curValue = statGetSquadBuffered( dataName );
statSetSquadBuffered( dataName, curValue + value );
}
updateBufferedStats()
{
// give the first player time to connect
wait ( 0.15 );
nextToUpdate = 0;
while ( !level.gameEnded )
{
maps\mp\gametypes\_hostmigration::waitTillHostMigrationDone();
nextToUpdate++;
if ( nextToUpdate >= level.players.size )
nextToUpdate = 0;
if ( isDefined( level.players[nextToUpdate] ) )
{
level.players[nextToUpdate] writeBufferedStats();
level.players[nextToUpdate] updateWeaponBufferedStats();
}
wait ( 2.0 );
}
foreach ( player in level.players )
{
player writeBufferedStats();
player updateWeaponBufferedStats();
}
}
writeBufferedStats()
{
rankingEnabled = self rankingEnabled();
if ( rankingEnabled )
{
foreach ( statName, statVal in self.bufferedStats )
{
self setRankedPlayerData( statName, statVal );
}
//AI doesnt have valid data for active squad member
if ( !isAI(self) )
{
foreach ( statName, statVal in self.squadMemberBufferedStats )
{
self SetRankedPlayerData( "squadMembers", self.pers[ "activeSquadMember" ], statName, statVal );
}
}
}
foreach ( statName, statVal in self.bufferedChildStats )
{
foreach ( childStatName, childStatVal in statVal )
{
if ( statName == "round" )
self setCommonPlayerData( statName, childStatName, childStatVal );
else if ( rankingEnabled )
self setRankedPlayerData( statName, childStatName, childStatVal );
}
}
}
writeKDHistoryStats()
{
if( !matchMakingGame() )
return;
if ( IsSquadsMode() )
return;
level waittill( "game_ended" );
wait 0.1; // wait because endGame_RegularMP is waiting and we need the round limit to be correct...
if ( wasLastRound() || (!isRoundBased() && hitTimeLimit()) )
{
foreach ( player in level.players )
{
player incrementRankedReservedHistory( player.kills, player.deaths );
}
}
}
incrementRankedReservedHistory( kills, deaths )
{
if ( !self rankingEnabled() )
return;
// shift everything up.
for ( i = 0; i < MAX_KD_HISTORY - 1; i++ )
{
prev = self getRankedPlayerDataReservedInt( "kdHistoryK" + (i + 1) );
self setRankedPlayerDataReservedInt( "kdHistoryK" + i, prev );
prev = self getRankedPlayerDataReservedInt( "kdHistoryD" + (i + 1) );
self setRankedPlayerDataReservedInt( "kdHistoryD" + i, prev );
}
self setRankedPlayerDataReservedInt( "kdHistoryK" + (MAX_KD_HISTORY-1), int(clamp(kills, 0, 255)) );
self setRankedPlayerDataReservedInt( "kdHistoryD" + (MAX_KD_HISTORY-1), int(clamp(deaths, 0, 255)) );
}
incrementWeaponStat( weaponName, stat, incValue )
{
// HACK for gold pdw / knife. This should use weaponMap() but in this
// case the weapon is the script base name not the code base
// name. Next project no script base names! - JC
if ( weaponName == "iw6_pdwauto" )
weaponName = "iw6_pdw";
else if ( weaponName == "iw6_knifeonlyfast" )
weaponName = "iw6_knifeonly";
if( isKillstreakWeapon( weaponName ) )
return;
if( IsDefined( level.disableWeaponStats ) )
return;
if ( self rankingEnabled() )
{
oldval = self getRankedPlayerData( "weaponStats", weaponName, stat );
self setRankedPlayerData( "weaponStats", weaponName, stat, oldval+incValue );
}
}
incrementAttachmentStat( attachmentName, stat, incValue )
{
if( IsDefined( level.disableWeaponStats ) )
return;
if ( self rankingEnabled() )
{
oldval = self getRankedPlayerData( "attachmentsStats", attachmentName, stat );
self setRankedPlayerData( "attachmentsStats", attachmentName, stat, oldval+incValue );
}
}
updateWeaponBufferedStats()
{
if ( !IsDefined( self.trackingWeaponName ) )
return;
if ( self.trackingWeaponName == "" || self.trackingWeaponName == "none" )
return;
if ( isKillstreakWeapon( self.trackingWeaponName ) || isEnvironmentWeapon( self.trackingWeaponName ) )
return;
weapName = self.trackingWeaponName;
weapStat = undefined;
strStart = GetSubStr( weapName, 0, 4 );
if ( strStart == "alt_" )
{
attachments = getWeaponAttachmentsBaseNames( weapName );
foreach ( attachName in attachments )
{
if ( attachName == "shotgun" || attachName == "gl" )
{
weapStat = attachName;
break;
}
}
// No longer have underbarrel hybrids, kept for iw5 weapons
if ( !IsDefined( weapStat ) )
{
tokens = StrTok( weapName, "_" );
weapStat = tokens[ 1 ] + "_" + tokens[ 2 ];
}
}
else if ( strStart == "iw5_" || strStart == "iw6_" )
{
tokens = StrTok( weapName, "_" );
weapStat = tokens[ 0 ] + "_" + tokens[ 1 ];
}
AssertEx( IsDefined( weapStat ), "updateWeaponBufferedStats() failed to get weapon name for stats." );
// log underbarrel stats
if( weapStat == "gl" || weapStat == "shotgun" )
{
self persLog_attachmentStats( weapStat );
self persClear_stats();
return;
}
if ( !isCACPrimaryWeapon( weapStat ) && !isCACSecondaryWeapon( weapStat ) )
return;
persLog_weaponStats( weapStat );
attachments = GetWeaponAttachments( weapName );
foreach ( attachName in attachments )
{
attachBase = attachmentMap_toBase( attachName );
switch ( attachBase )
{
case "scope": // Do not log stats on default scopes
case "gl": // GL stats already logged above when in alt mode
case "shotgun": // Shotgun stats already logged above when in alt mode
continue;
}
persLog_attachmentStats( attachBase );
}
self persClear_stats();
}
persClear_stats()
{
self.trackingWeaponName = "none";
self.trackingWeaponShots = 0;
self.trackingWeaponKills = 0;
self.trackingWeaponHits = 0;
self.trackingWeaponHeadShots = 0;
self.trackingWeaponDeaths = 0;
}
persLog_weaponStats( weaponName )
{
if( self.trackingWeaponShots > 0 )
{
self incrementWeaponStat( weaponName, "shots", self.trackingWeaponShots );
self maps\mp\_matchdata::logWeaponStat( weaponName, "shots", self.trackingWeaponShots);
}
if( self.trackingWeaponKills > 0 )
{
self incrementWeaponStat( weaponName, "kills", self.trackingWeaponKills );
self maps\mp\_matchdata::logWeaponStat( weaponName, "kills", self.trackingWeaponKills);
}
if( self.trackingWeaponHits > 0 )
{
self incrementWeaponStat( weaponName, "hits", self.trackingWeaponHits );
self maps\mp\_matchdata::logWeaponStat( weaponName, "hits", self.trackingWeaponHits);
}
if( self.trackingWeaponHeadShots > 0 )
{
self incrementWeaponStat( weaponName, "headShots", self.trackingWeaponHeadShots );
self maps\mp\_matchdata::logWeaponStat( weaponName, "headShots", self.trackingWeaponHeadShots);
}
if( self.trackingWeaponDeaths > 0 )
{
self incrementWeaponStat( weaponName, "deaths", self.trackingWeaponDeaths );
self maps\mp\_matchdata::logWeaponStat( weaponName, "deaths", self.trackingWeaponDeaths);
}
}
persLog_attachmentStats( attachName )
{
if( self.trackingWeaponShots > 0 && attachName != "tactical" )
{
self incrementAttachmentStat( attachName, "shots", self.trackingWeaponShots );
self maps\mp\_matchdata::logAttachmentStat( attachName, "shots", self.trackingWeaponShots);
}
if( self.trackingWeaponKills > 0 && attachName != "tactical" )
{
self incrementAttachmentStat( attachName, "kills", self.trackingWeaponKills );
self maps\mp\_matchdata::logAttachmentStat( attachName, "kills", self.trackingWeaponKills);
}
if( self.trackingWeaponHits > 0 && attachName != "tactical" )
{
self incrementAttachmentStat( attachName, "hits", self.trackingWeaponHits );
self maps\mp\_matchdata::logAttachmentStat( attachName, "hits", self.trackingWeaponHits);
}
if( self.trackingWeaponHeadShots > 0 && attachName != "tactical" )
{
self incrementAttachmentStat( attachName, "headShots", self.trackingWeaponHeadShots );
self maps\mp\_matchdata::logAttachmentStat( attachName, "headShots", self.trackingWeaponHeadShots);
}
if( self.trackingWeaponDeaths > 0 )
{
self incrementAttachmentStat( attachName, "deaths", self.trackingWeaponDeaths );
self maps\mp\_matchdata::logAttachmentStat( attachName, "deaths", self.trackingWeaponDeaths);
}
}
uploadGlobalStatCounters()
{
level waittill( "game_ended" );
if( !matchMakingGame() )
return;
totalKills = 0;
totalDeaths = 0;
totalAssists = 0;
totalHeadshots = 0;
totalSuicides = 0;
totalTimePlayed = 0;
foreach ( player in level.players )
{
totalTimePlayed += player.timePlayed["total"];
}
incrementCounter( "global_minutes", int( totalTimePlayed / 60 ) );
if ( isRoundBased() && !wasLastRound() )
return;
wait( 0.05 );
foreach ( player in level.players )
{
totalKills += player.kills;
totalDeaths += player.deaths;
totalAssists += player.assists;
totalHeadshots += player.headshots;
totalSuicides += player.suicides;
}
incrementCounter( "global_headshots", totalHeadshots );
incrementCounter( "global_suicides", totalSuicides );
incrementCounter( "global_games", 1 );
if( !IsDefined(level.assists_disabled) )
incrementCounter( "global_assists", totalAssists );
if( !IsDefined(level.isHorde) )
incrementCounter( "global_kills", totalKills );
if( !IsDefined(level.isHorde) )
incrementCounter( "global_deaths", totalDeaths );
}

View File

@ -0,0 +1,28 @@
#include common_scripts\utility;
#include maps\mp\_utility;
init()
{
level thread onPlayerConnect();
}
onPlayerConnect()
{
for(;;)
{
level waittill( "connected", player );
//@NOTE: Should we make sure they're really unlocked before setting them? Catch cheaters...
// e.g. isItemUnlocked( iconHandle )
if ( !IsAI( player ) )
{
player.playerCardPatch = player GetCaCPlayerData( "patch" );
player.playerCardPatchBacking = player GetCaCPlayerData( "patchbacking" );
player.playerCardBackground = player GetCaCPlayerData( "background" );
}
}
}

File diff suppressed because it is too large Load Diff

1527
maps/mp/gametypes/_rank.gsc Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,109 @@
init()
{
level.hostname = getdvar("sv_hostname");
if(level.hostname == "")
level.hostname = "CoDHost";
setdvar("sv_hostname", level.hostname);
level.allowvote = getdvarint("g_allowvote", 1);
SetDvar("g_allowvote", level.allowvote);
SetDvar("ui_allowvote", level.allowvote);
setFriendlyFire( maps\mp\gametypes\_tweakables::getTweakableValue( "team", "fftype" ) );
constrainGameType(getdvar("g_gametype"));
for(;;)
{
updateServerSettings();
wait 5;
}
}
updateServerSettings()
{
sv_hostname = getdvar("sv_hostname");
if(level.hostname != sv_hostname)
{
level.hostname = sv_hostname;
}
g_allowvote = getdvarint("g_allowvote", 1);
if(level.allowvote != g_allowvote)
{
level.allowvote = g_allowvote;
setdvar("ui_allowvote", level.allowvote);
}
scr_friendlyfire = maps\mp\gametypes\_tweakables::getTweakableValue( "team", "fftype" );
if(level.friendlyfire != scr_friendlyfire)
{
setFriendlyFire( scr_friendlyfire );
}
}
constrainGameType(gametype)
{
entities = getentarray();
for(i = 0; i < entities.size; i++)
{
entity = entities[i];
if(gametype == "dm")
{
if(isdefined(entity.script_gametype_dm) && entity.script_gametype_dm != "1")
{
//iprintln("DELETED(GameType): ", entity.classname);
entity delete();
}
}
else if(gametype == "tdm")
{
if(isdefined(entity.script_gametype_tdm) && entity.script_gametype_tdm != "1")
{
//iprintln("DELETED(GameType): ", entity.classname);
entity delete();
}
}
else if(gametype == "ctf")
{
if(isdefined(entity.script_gametype_ctf) && entity.script_gametype_ctf != "1")
{
//iprintln("DELETED(GameType): ", entity.classname);
entity delete();
}
}
else if(gametype == "hq")
{
if(isdefined(entity.script_gametype_hq) && entity.script_gametype_hq != "1")
{
//iprintln("DELETED(GameType): ", entity.classname);
entity delete();
}
}
else if(gametype == "sd")
{
if(isdefined(entity.script_gametype_sd) && entity.script_gametype_sd != "1")
{
//iprintln("DELETED(GameType): ", entity.classname);
entity delete();
}
}
else if(gametype == "koth")
{
if(isdefined(entity.script_gametype_koth) && entity.script_gametype_koth != "1")
{
//iprintln("DELETED(GameType): ", entity.classname);
entity delete();
}
}
}
}
setFriendlyFire( enabled )
{
level.friendlyfire = enabled;
setdvar("ui_friendlyfire", enabled );
setdvar("cg_drawFriendlyHUDGrenades", enabled );
}

View File

@ -0,0 +1,293 @@
#include maps\mp\_utility;
#include common_scripts\utility;
init()
{
level._effect[ "slide_dust" ] = LoadFX( "vfx/gameplay/screen_effects/vfx_scrnfx_tocam_slidedust_m" );
level._effect[ "hit_left" ] = LoadFX( "vfx/gameplay/screen_effects/vfx_blood_hit_left" );
level._effect[ "hit_right" ] = LoadFX( "vfx/gameplay/screen_effects/vfx_blood_hit_right" );
level._effect[ "melee_spray" ] = LoadFX( "vfx/gameplay/screen_effects/vfx_melee_blood_spray" );
}
shellshockOnDamage( cause, damage )
{
if ( self maps\mp\_flashgrenades::isFlashbanged() )
return; // don't interrupt flashbang shellshock
if ( cause == "MOD_EXPLOSIVE" ||
cause == "MOD_GRENADE" ||
cause == "MOD_GRENADE_SPLASH" ||
cause == "MOD_PROJECTILE" ||
cause == "MOD_PROJECTILE_SPLASH" )
{
if ( damage > 10 )
{
if ( isDefined(self.shellShockReduction) && self.shellShockReduction )
self shellshock( "frag_grenade_mp", self.shellShockReduction );
else
self shellshock("frag_grenade_mp", 0.5);
}
}
}
endOnDeath()
{
self waittill( "death" );
waittillframeend;
self notify ( "end_explode" );
}
grenade_earthQuake()
{
self notify( "grenade_earthQuake" );
self endon( "grenade_earthQuake" );
self thread endOnDeath();
self endon( "end_explode" );
self waittill( "explode", position );
PlayRumbleOnPosition( "grenade_rumble", position );
Earthquake( 0.5, 0.75, position, 800 );
foreach ( player in level.players )
{
if ( player isUsingRemote() )
continue;
if ( DistanceSquared( position, player.origin ) > 600*600 )
continue;
if ( player DamageConeTrace( position ) )
player thread dirtEffect( position );
// do some hud shake
player SetClientOmnvar( "ui_hud_shake", true );
}
}
dirtEffect( position )
{
self notify( "dirtEffect" );
self endon( "dirtEffect" );
self endon ( "disconnect" );
if( !isReallyAlive( self ) )
return;
forwardVec = VectorNormalize( AnglesToForward( self.angles ) );
rightVec = VectorNormalize( AnglesToRight( self.angles ) );
grenadeVec = VectorNormalize( position - self.origin );
fDot = VectorDot( grenadeVec, forwardVec );
rDot = VectorDot( grenadeVec, rightVec );
/#
if( GetDvarInt( "g_debugDamage" ) )
{
PrintLn( fDot );
PrintLn( rDot );
}
#/
string_array = [ "death", "damage" ];
// center
if( fDot > 0 && fDot > 0.5 && self GetCurrentWeapon() != "iw6_riotshield_mp" )
{
// NOTE: I think we are doing this through fx now, if not then we need to play fx here
self waittill_any_in_array_or_timeout( string_array, 2.0 );
}
else if( abs( fDot ) < 0.866 )
{
// right
if( rDot > 0 )
{
// NOTE: I think we are doing this through fx now, if not then we need to play fx here
self waittill_any_in_array_or_timeout( string_array, 2.0 );
}
// left
else
{
// NOTE: I think we are doing this through fx now, if not then we need to play fx here
self waittill_any_in_array_or_timeout( string_array, 2.0 );
}
}
}
bloodEffect( position )
{
self endon ( "disconnect" );
if( !isReallyAlive( self ) )
return;
forwardVec = VectorNormalize( AnglesToForward( self.angles ) );
rightVec = VectorNormalize( AnglesToRight( self.angles ) );
damageVec = VectorNormalize( position - self.origin );
fDot = VectorDot( damageVec, forwardVec );
rDot = VectorDot( damageVec, rightVec );
/#
if( GetDvarInt( "g_debugDamage" ) )
{
PrintLn( fDot );
PrintLn( rDot );
}
#/
// center
if( fDot > 0 && fDot > 0.5 )
{
// purposely empty for now because we only want left and right splatter
}
else if( abs( fDot ) < 0.866 )
{
// left by default
fx = level._effect[ "hit_left" ];
// right
if( rDot > 0 )
fx = level._effect[ "hit_right" ];
string_array = [ "death", "damage" ];
self thread play_fx_with_entity( fx, string_array, 7.0 );
}
}
bloodMeleeEffect() // self == player
{
self endon ( "disconnect" );
// HACK: waiting for the knife to come out before showing the blood, this needs to come from somewhere to match perfectly
wait( 0.5 );
string_array = [ "death" ];
self thread play_fx_with_entity( level._effect[ "melee_spray" ], string_array, 1.5 );
}
play_fx_with_entity( fx, string_array, timeout ) // self == player
{
self endon ( "disconnect" );
blood_effect_ent = SpawnFXForClient( fx, self GetEye(), self );
TriggerFX( blood_effect_ent );
blood_effect_ent SetFXKillDefOnDelete();
self waittill_any_in_array_or_timeout( string_array, timeout );
blood_effect_ent delete();
}
c4_earthQuake()
{
self thread endOnDeath();
self endon( "end_explode" );
self waittill( "explode", position );
PlayRumbleOnPosition( "grenade_rumble", position );
Earthquake( 0.4, 0.75, position, 512 );
foreach( player in level.players )
{
if( player isUsingRemote() )
continue;
if( distance( position, player.origin ) > 512 )
continue;
if( player DamageConeTrace( position ) )
player thread dirtEffect( position );
// do some hud shake
player SetClientOmnvar( "ui_hud_shake", true );
}
}
barrel_earthQuake()
{
position = self.origin;
PlayRumbleOnPosition( "grenade_rumble", position );
Earthquake( 0.4, 0.5, position, 512 );
foreach( player in level.players )
{
if( player isUsingRemote() )
continue;
if( distance( position, player.origin ) > 512 )
continue;
if( player DamageConeTrace( position ) )
player thread dirtEffect( position );
// do some hud shake
player SetClientOmnvar( "ui_hud_shake", true );
}
}
artillery_earthQuake()
{
position = self.origin;
PlayRumbleOnPosition( "artillery_rumble", self.origin );
Earthquake( 0.7, 0.5, self.origin, 800 );
foreach( player in level.players )
{
if( player isUsingRemote() )
continue;
if( distance( position, player.origin ) > 600 )
continue;
if( player DamageConeTrace( position ) )
player thread dirtEffect( position );
// do some hud shake
player SetClientOmnvar( "ui_hud_shake", true );
}
}
stealthAirstrike_earthQuake( position )
{
PlayRumbleOnPosition( "grenade_rumble", position );
Earthquake( 1.0, 0.6, position, 2000 );
foreach( player in level.players )
{
if( player isUsingRemote() )
continue;
if( distance( position, player.origin ) > 1000 )
continue;
if( player DamageConeTrace( position ) )
player thread dirtEffect( position );
// do some hud shake
player SetClientOmnvar( "ui_hud_shake", true );
}
}
airstrike_earthQuake( position )
{
PlayRumbleOnPosition( "artillery_rumble", position );
Earthquake( 0.7, 0.75, position, 1000 );
foreach( player in level.players )
{
if( player isUsingRemote() )
continue;
if( distance( position, player.origin ) > 900 )
continue;
if( player DamageConeTrace( position ) )
player thread dirtEffect( position );
// do some hud shake
player SetClientOmnvar( "ui_hud_shake", true );
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,342 @@
#include maps\mp\_utility;
init()
{
level.spectateOverride["allies"] = spawnstruct();
level.spectateOverride["axis"] = spawnstruct();
level thread onPlayerConnect();
level thread getLevelMLGCams();
}
createMLGCamObject( icon )
{
precacheshader( icon );
camera = spawn( "script_model", (0,0,0) );
camera setModel( "tag_origin" );
camera.angles = (0,0,0);
curObjID = maps\mp\gametypes\_gameobjects::getNextObjID();
objective_add( curObjID, "active", (0,0,0) );
objective_icon( curObjID, icon );
objective_playermask_hidefromall( curObjID );
Objective_OnEntityWithRotation( curObjID, camera );
camera.objID = curObjID;
return camera;
}
setMLGCamVisibility( visible )
{
for ( i = 0; i < level.CameraMapObjs.size; i++ )
{
if ( visible )
{
objective_playermask_showto( level.CameraMapObjs[i].objId, self GetEntityNumber() );
}
else
{
objective_playermask_hidefrom( level.CameraMapObjs[i].objId, self GetEntityNumber() );
}
}
}
getLevelMLGCams()
{
mapname = ToLower( getDvar( "mapname" ) );
camera1RawPos = TableLookup( "mp/CameraPositions.csv", 0, mapname, 1 );
camera1RawAng = TableLookup( "mp/CameraPositions.csv", 0, mapname, 2 );
level.CameraMapObjs = [];
level.CameraMapObjs[0] = createMLGCamObject( "compass_mlg_cam1" );
level.CameraMapObjs[1] = createMLGCamObject( "compass_mlg_cam2" );
level.CameraMapObjs[2] = createMLGCamObject( "compass_mlg_cam3" );
level.CameraMapObjs[3] = createMLGCamObject( "compass_mlg_cam4" );
if ( camera1RawPos == "" )
return;
camera2RawPos = TableLookup( "mp/CameraPositions.csv", 0, mapname, 3 );
camera2RawAng = TableLookup( "mp/CameraPositions.csv", 0, mapname, 4 );
camera3RawPos = TableLookup( "mp/CameraPositions.csv", 0, mapname, 5 );
camera3RawAng = TableLookup( "mp/CameraPositions.csv", 0, mapname, 6 );
camera4RawPos = TableLookup( "mp/CameraPositions.csv", 0, mapname, 7 );
camera4RawAng = TableLookup( "mp/CameraPositions.csv", 0, mapname, 8 );
level.Camera1Pos = getCameraVecOrAng( camera1RawPos );
level.Camera1Ang = getCameraVecOrAng( camera1RawAng );
level.Camera2Pos = getCameraVecOrAng( camera2RawPos );
level.Camera2Ang = getCameraVecOrAng( camera2RawAng );
level.Camera3Pos = getCameraVecOrAng( camera3RawPos );
level.Camera3Ang = getCameraVecOrAng( camera3RawAng );
level.Camera4Pos = getCameraVecOrAng( camera4RawPos );
level.Camera4Ang = getCameraVecOrAng( camera4RawAng );
if ( mapname == "mp_strikezone" )
{
camera5RawPos = TableLookup( "mp/CameraPositions.csv", 0, mapname+"_b", 1 );
camera5RawAng = TableLookup( "mp/CameraPositions.csv", 0, mapname+"_b", 2 );
camera6RawPos = TableLookup( "mp/CameraPositions.csv", 0, mapname+"_b", 3 );
camera6RawAng = TableLookup( "mp/CameraPositions.csv", 0, mapname+"_b", 4 );
camera7RawPos = TableLookup( "mp/CameraPositions.csv", 0, mapname+"_b", 5 );
camera7RawAng = TableLookup( "mp/CameraPositions.csv", 0, mapname+"_b", 6 );
camera8RawPos = TableLookup( "mp/CameraPositions.csv", 0, mapname+"_b", 7 );
camera8RawAng = TableLookup( "mp/CameraPositions.csv", 0, mapname+"_b", 8 );
level.Camera5Pos = getCameraVecOrAng( camera5RawPos );
level.Camera5Ang = getCameraVecOrAng( camera5RawAng );
level.Camera6Pos = getCameraVecOrAng( camera6RawPos );
level.Camera6Ang = getCameraVecOrAng( camera6RawAng );
level.Camera7Pos = getCameraVecOrAng( camera7RawPos );
level.Camera7Ang = getCameraVecOrAng( camera7RawAng );
level.Camera8Pos = getCameraVecOrAng( camera8RawPos );
level.Camera8Ang = getCameraVecOrAng( camera8RawAng );
}
}
getCameraVecOrAng( elementString )
{
cameraAElements = StrTok( elementString, " " );
CameraAVectorOrAng = ( Int( cameraAElements[0] ), Int( cameraAElements[1] ), Int( cameraAElements[2] ) );
return CameraAVectorOrAng;
}
onPlayerConnect()
{
for(;;)
{
level waittill( "connected", player );
player thread onJoinedTeam();
player thread onJoinedSpectators();
player thread onSpectatingClient();
player thread onFreecam();
}
}
onJoinedTeam()
{
self endon("disconnect");
for(;;)
{
self waittill( "joined_team" );
self setSpectatePermissions();
self setMLGCamVisibility( false );
}
}
onJoinedSpectators()
{
self endon("disconnect");
for(;;)
{
self waittill( "joined_spectators" );
self setSpectatePermissions();
if ( self IsMLGSpectator() || ( isDefined( self.pers["mlgSpectator"] ) && self.pers["mlgSpectator"] ) )
{
self SetMLGSpectator( 1 );
self SetClientOmnvar( "ui_use_mlg_hud", true );
self setMLGCamVisibility( true );
}
}
}
onSpectatingClient()
{
self endon("disconnect");
for( ;; )
{
self waittill( "spectating_cycle" );
// show the card for the player we're viewing. Could be undefined if the cyling failed
spectatedPlayer = self GetSpectatingPlayer();
if ( isDefined( spectatedPlayer ) )
{
// we used to set the card slot for the player here, leaving this in case we want to do something here
}
}
}
onFreecam()
{
self endon("disconnect");
for( ;; )
{
self waittill ( "luinotifyserver", channel, view );
if ( channel == "mlg_view_change" )
{
self maps\mp\gametypes\_playerlogic::resetUIDvarsOnSpectate();
}
}
}
updateSpectateSettings()
{
level endon ( "game_ended" );
for ( index = 0; index < level.players.size; index++ )
level.players[index] setSpectatePermissions();
}
setSpectatePermissions()
{
team = self.sessionteam;
if ( level.gameEnded && gettime() - level.gameEndTime >= 2000 )
{
if( level.multiTeamBased )
{
for( i = 0; i < level.teamNameList.size; i++ )
{
self allowSpectateTeam( level.teamNameList[i], false );
}
}
else
{
self allowSpectateTeam( "allies", false );
self allowSpectateTeam( "axis", false );
}
self allowSpectateTeam( "freelook", false );
self allowSpectateTeam( "none", true );
return;
}
spectateType = maps\mp\gametypes\_tweakables::getTweakableValue( "game", "spectatetype" );
if ( self IsMLGSpectator() )
{
spectateType = 2;
}
if ( bot_is_fireteam_mode() )
{
//ONLY spectate your bots, regardless of mode - NOTE: all fireteam modes are team modes
spectateType = 1;
}
switch( spectateType )
{
case 0: // disabled
if( level.multiTeamBased )
{
for( i = 0; i < level.teamNameList.size; i++ )
{
self allowSpectateTeam( level.teamNameList[i], false );
}
}
else
{
self allowSpectateTeam( "allies", false );
self allowSpectateTeam( "axis", false );
}
self allowSpectateTeam( "freelook", false );
self allowSpectateTeam( "none", false );
break;
case 1: // team/player only
if ( !level.teamBased )
{
self allowSpectateTeam( "allies", true );
self allowSpectateTeam( "axis", true );
self allowSpectateTeam( "none", true );
self allowSpectateTeam( "freelook", false );
}
else if ( isDefined( team ) && (team == "allies" || team == "axis") && !level.multiTeamBased )
{
self allowSpectateTeam( team, true );
self allowSpectateTeam( getOtherTeam( team ), false );
self allowSpectateTeam( "freelook", false );
self allowSpectateTeam( "none", false );
}
else if ( isDefined( team ) && IsSubStr( team, "team_" ) && level.multiTeamBased )
{
for( i = 0; i < level.teamNameList.size; i++ )
{
if( team == level.teamNameList[i] )
{
self allowSpectateTeam( level.teamNameList[i], true );
}
else
{
self allowSpectateTeam( level.teamNameList[i], false );
}
}
self allowSpectateTeam( "freelook", false );
self allowSpectateTeam( "none", false );
}
else
{
if( level.multiTeamBased )
{
for( i = 0; i < level.teamNameList.size; i++ )
{
self allowSpectateTeam( level.teamNameList[i], false );
}
}
else
{
self allowSpectateTeam( "allies", false );
self allowSpectateTeam( "axis", false );
}
self allowSpectateTeam( "freelook", false );
self allowSpectateTeam( "none", false );
}
break;
case 2: // free
if( level.multiTeamBased )
{
for( i = 0; i < level.teamNameList.size; i++ )
{
self allowSpectateTeam( level.teamNameList[i], true );
}
}
else
{
self allowSpectateTeam( "allies", true );
self allowSpectateTeam( "axis", true );
}
self allowSpectateTeam( "freelook", true );
self allowSpectateTeam( "none", true );
break;
}
if ( isDefined( team ) && (team == "axis" || team == "allies") )
{
if ( isdefined(level.spectateOverride[team].allowFreeSpectate) )
self allowSpectateTeam( "freelook", true );
if (isdefined(level.spectateOverride[team].allowEnemySpectate))
self allowSpectateTeam( getOtherTeam( team ), true );
}
}

View File

@ -0,0 +1,968 @@
#include maps\mp\_utility;
#include common_scripts\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;
FACTION_DEPLOY_MODEL_COL = 19;
MT_REF_COL = 0;
MT_NAME_COL = 1;
MT_ICON_COL = 2;
MT_HEAD_ICON_COL = 3;
init()
{
initScoreBoard();
level.teamBalance = getDvarInt("scr_teambalance");
level.maxClients = getDvarInt( "sv_maxclients" );
setPlayerModels();
level.freeplayers = [];
if( level.teamBased )
{
level thread onPlayerConnect();
level thread updateTeamBalance();
wait .15;
if ( !is_aliens() )
level thread updatePlayerTimes();
}
else
{
level thread onFreePlayerConnect();
wait .15;
level thread updateFreePlayerTimes();
}
}
initScoreBoard()
{
//NOTE: multi team teams do not need to set these dvars, the team names used on the scoreboard are taken from MTTable.csv
//currently there are no team icons used for the MT scoreboard, and enemy teams will use g_teamTitleColor_EnemyTeam when needed.
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_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 ( ;; )
{
maps\mp\gametypes\_hostmigration::waitTillHostMigrationDone();
foreach ( player in level.players )
player updatePlayedTime();
wait( 1.0 );
}
}
updatePlayedTime()
{
// bots dont need this logic running and its one of the lowest hanging script performance costs
if ( IsAI( self ) )
return;
if ( !self rankingEnabled() )
return;
if ( self.timePlayed["allies"] )
{
if ( !IsSquadsMode() )
{
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"] );
self maps\mp\gametypes\_persistence::statAddChildBufferedWithMax( "xpMultiplierTimePlayed", 0, self.timePlayed["allies"], self.bufferedChildStatsMax[ "xpMaxMultiplierTimePlayed" ][ 0 ] );
self maps\mp\gametypes\_persistence::statAddChildBufferedWithMax( "xpMultiplierTimePlayed", 1, self.timePlayed["allies"], self.bufferedChildStatsMax[ "xpMaxMultiplierTimePlayed" ][ 1 ] );
self maps\mp\gametypes\_persistence::statAddChildBufferedWithMax( "xpMultiplierTimePlayed", 2, self.timePlayed["allies"], self.bufferedChildStatsMax[ "xpMaxMultiplierTimePlayed" ][ 2 ] );
self maps\mp\gametypes\_persistence::statAddChildBufferedWithMax( "challengeXPMultiplierTimePlayed", 0, self.timePlayed["allies"], self.bufferedChildStatsMax[ "challengeXPMaxMultiplierTimePlayed" ][ 0 ] );
self maps\mp\gametypes\_persistence::statAddChildBufferedWithMax( "weaponXPMultiplierTimePlayed", 0, self.timePlayed["allies"], self.bufferedChildStatsMax[ "weaponXPMaxMultiplierTimePlayed" ][ 0 ] );
if ( IsSquadsMode() )
{
self maps\mp\gametypes\_persistence::statAddBufferedWithMax( "prestigeDoubleXpTimePlayed", self.timePlayed["allies"], self.bufferedStatsMax["prestigeDoubleXpMaxTimePlayed"] );
self maps\mp\gametypes\_persistence::statAddBufferedWithMax( "prestigeDoubleWeaponXpTimePlayed", self.timePlayed["allies"], self.bufferedStatsMax["prestigeDoubleWeaponXpMaxTimePlayed"] );
}
}
if ( self.timePlayed["axis"] )
{
if ( !IsSquadsMode() )
{
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"] );
self maps\mp\gametypes\_persistence::statAddChildBufferedWithMax( "xpMultiplierTimePlayed", 0, self.timePlayed["axis"], self.bufferedChildStatsMax[ "xpMaxMultiplierTimePlayed" ][ 0 ] );
self maps\mp\gametypes\_persistence::statAddChildBufferedWithMax( "xpMultiplierTimePlayed", 1, self.timePlayed["axis"], self.bufferedChildStatsMax[ "xpMaxMultiplierTimePlayed" ][ 1 ] );
self maps\mp\gametypes\_persistence::statAddChildBufferedWithMax( "xpMultiplierTimePlayed", 2, self.timePlayed["axis"], self.bufferedChildStatsMax[ "xpMaxMultiplierTimePlayed" ][ 2 ] );
self maps\mp\gametypes\_persistence::statAddChildBufferedWithMax( "challengeXPMultiplierTimePlayed", 0, self.timePlayed["axis"], self.bufferedChildStatsMax[ "challengeXPMaxMultiplierTimePlayed" ][ 0 ] );
self maps\mp\gametypes\_persistence::statAddChildBufferedWithMax( "weaponXPMultiplierTimePlayed", 0, self.timePlayed["axis"], self.bufferedChildStatsMax[ "weaponXPMaxMultiplierTimePlayed" ][ 0 ] );
if ( IsSquadsMode() )
{
self maps\mp\gametypes\_persistence::statAddBufferedWithMax( "prestigeDoubleXpTimePlayed", self.timePlayed["axis"], self.bufferedStatsMax[ "prestigeDoubleXpMaxTimePlayed" ] );
self maps\mp\gametypes\_persistence::statAddBufferedWithMax( "prestigeDoubleWeaponXpTimePlayed", self.timePlayed["axis"], self.bufferedStatsMax["prestigeDoubleWeaponXpMaxTimePlayed"] );
}
}
if ( self.timePlayed["other"] )
{
if ( !IsSquadsMode() )
{
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"] );
self maps\mp\gametypes\_persistence::statAddChildBufferedWithMax( "xpMultiplierTimePlayed", 0, self.timePlayed["other"], self.bufferedChildStatsMax[ "xpMaxMultiplierTimePlayed" ][ 0 ] );
self maps\mp\gametypes\_persistence::statAddChildBufferedWithMax( "xpMultiplierTimePlayed", 1, self.timePlayed["other"], self.bufferedChildStatsMax[ "xpMaxMultiplierTimePlayed" ][ 1 ] );
self maps\mp\gametypes\_persistence::statAddChildBufferedWithMax( "xpMultiplierTimePlayed", 2, self.timePlayed["other"], self.bufferedChildStatsMax[ "xpMaxMultiplierTimePlayed" ][ 2 ] );
self maps\mp\gametypes\_persistence::statAddChildBufferedWithMax( "challengeXPMultiplierTimePlayed", 0, self.timePlayed["other"], self.bufferedChildStatsMax[ "challengeXPMaxMultiplierTimePlayed" ][ 0 ] );
self maps\mp\gametypes\_persistence::statAddChildBufferedWithMax( "weaponXPMultiplierTimePlayed", 0, self.timePlayed["other"], self.bufferedChildStatsMax[ "weaponXPMaxMultiplierTimePlayed" ][ 0 ] );
if ( IsSquadsMode() )
{
self maps\mp\gametypes\_persistence::statAddBufferedWithMax( "prestigeDoubleXpTimePlayed", self.timePlayed["other"], self.bufferedStatsMax[ "prestigeDoubleXpMaxTimePlayed" ] );
self maps\mp\gametypes\_persistence::statAddBufferedWithMax( "prestigeDoubleWeaponXpTimePlayed", self.timePlayed["other"], self.bufferedStatsMax["prestigeDoubleWeaponXpMaxTimePlayed"] );
}
}
if ( self.pers["rank"] != level.maxRank )
{
if ( self.timePlayed["allies"] )
self maps\mp\gametypes\_persistence::statAddSquadBuffered( "experienceToPrestige", self.timePlayed["allies"] );
else if ( self.timePlayed["axis"] )
self maps\mp\gametypes\_persistence::statAddSquadBuffered( "experienceToPrestige", self.timePlayed["axis"] );
else if ( self.timePlayed["other"] )
self maps\mp\gametypes\_persistence::statAddSquadBuffered( "experienceToPrestige", 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 / 2;
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.onTeamSelection]]("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.onTeamSelection]]("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];
}
}
}
setPlayerModels()
{
// new way
setDefaultCharacterData();
// for juggernauts
game[ "allies_model" ][ "JUGGERNAUT" ] = maps\mp\killstreaks\_juggernaut::setJugg;
game[ "axis_model" ][ "JUGGERNAUT" ] = maps\mp\killstreaks\_juggernaut::setJugg;
game[ "allies_model" ][ "JUGGERNAUT_MANIAC" ] = maps\mp\killstreaks\_juggernaut::setJuggManiac;
game[ "axis_model" ][ "JUGGERNAUT_MANIAC" ] = maps\mp\killstreaks\_juggernaut::setJuggManiac;
}
playerModelForWeapon( weapon, secondary )
{
// Not necessary. May need to revisit for ghillie with the new system
}
CountPlayers()
{
player_counts = [];
for( i = 0; i < level.teamNameList.size; i++ )
{
player_counts[level.teamNameList[i]] = 0;
}
for( i = 0; i < level.players.size; i++ )
{
if( level.players[i] == self )
continue;
if( level.players[i].pers["team"] == "spectator" )
continue;
if( isdefined( level.players[i].pers["team"] ))
{
assert( isdefined( player_counts[level.players[i].pers["team"]] ));
player_counts[level.players[i].pers["team"]]++;
}
}
return player_counts;
}
setDefaultCharacterData()
{
// Models used here must be always loaded and not streamed / transients.
// You can use them for the customization system so long as that rule is maintained.
if ( !IsDefined( level.defaultHeadModels ) )
{
level.defaultHeadModels = [];
level.defaultHeadModels[ "allies" ] = "head_mp_head_a";
level.defaultHeadModels[ "axis" ] = "head_mp_head_a";
}
if ( !IsDefined( level.defaultBodyModels ) )
{
level.defaultBodyModels = [];
level.defaultBodyModels[ "allies" ] = "mp_body_us_rangers_assault_a_urban";
level.defaultBodyModels[ "axis" ] = "mp_body_us_rangers_assault_a_woodland";
}
if ( !IsDefined( level.defaultViewArmModels ) )
{
level.defaultViewArmModels = [];
level.defaultViewArmModels[ "allies" ] = "viewhands_us_rangers_urban";
level.defaultViewArmModels[ "axis" ] = "viewhands_us_rangers_woodland";
}
if ( !IsDefined( level.defaultVoices ) )
{
level.defaultVoices = [];
level.defaultVoices[ "allies" ] = "delta";
level.defaultVoices[ "axis" ] = "delta";
}
}
setCharacterModels( bodyModelName, headModelName, viewModelName )
{
self SetModel( bodyModelName );
self SetViewModel( viewModelName );
self Attach( headModelName, "", true );
self.headModel = headModelName;
}
setModelFromCustomization()
{
assert( IsDefined( self ) );
assert( IsPlayer( self ) );
bodyModelName = self GetCustomizationBody();
headModelName = self GetCustomizationHead();
viewModelName = self GetCustomizationViewmodel();
setCharacterModels( bodyModelName, headModelName, viewModelName );
}
setDefaultModel()
{
assert( IsDefined( self ) );
bodyModelName = level.defaultBodyModels[self.team];
headModelName = level.defaultHeadModels[self.team];
viewModelName = level.defaultViewArmModels[self.team];
setCharacterModels( bodyModelName, headModelName, viewModelName );
}
getPlayerModelIndex()
{
if ( level.rankedMatch )
return self GetRankedPlayerData( "squadMembers", self.pers["activeSquadMember"], "body" );
else
return self GetPrivatePlayerData( "privateMatchSquadMembers", self.pers["activeSquadMember"], "body" );
}
getPlayerFoleyType( bodyIndex )
{
return TableLookup( "mp/cac/bodies.csv", 0, bodyIndex, 5 );
}
getPlayerModelName( bodyIndex )
{
return TableLookup( "mp/cac/bodies.csv", 0, bodyIndex, 1 );
}
setupPlayerModel()
{
if ( IsPlayer( self ) )
self setModelFromCustomization();
else
self setDefaultModel();
if ( !isAI( self ) )
{
bodyIndex = self getPlayerModelIndex();
self.bodyIndex = bodyIndex;
modelFoleyType = self getPlayerFoleyType( bodyIndex );
// cloth
self SetClothType( modelFoleyType );
}
else
{
self SetClothType( "vestLight" );
}
// voice -- TODO
self.voice = level.defaultVoices[ self.team ];
//Force override with default for MLG
if( isAnyMLGMatch() && !isAI( self ) )
{
bodyModelName = getPlayerModelName( self getPlayerModelIndex() );
if( IsSubStr( bodyModelName, "fullbody_sniper" ) )
{
self thread forceDefaultModel();
}
}
// Override certain things when we're a juggernaut
if( self isJuggernaut() )
{
if( IsDefined( self.isJuggernautManiac ) && self.isJuggernautManiac )
thread [[game[self.team + "_model"]["JUGGERNAUT_MANIAC"]]]();
else if( IsDefined( self.isJuggernautLevelCustom ) && self.isJuggernautLevelCustom )
thread [[game[self.team + "_model"]["JUGGERNAUT_CUSTOM"]]]();
else
thread [[game[self.team + "_model"]["JUGGERNAUT"]]]();
}
}
forceDefaultModel()
{
if( IsDefined( self.headModel ) )
{
self Detach( self.headModel, "" );
self.headModel = undefined;
}
if( self.team == "axis" )
{
self SetModel( "mp_body_juggernaut_light_black" );
self SetViewModel( "viewhands_juggernaut_ally" );
}
else
{
self SetModel( "mp_body_infected_a" );
self SetViewmodel( "viewhands_gs_hostage" );
}
if( IsDefined( self.headModel ) )
{
self Detach( self.headModel, "" );
self.headModel = undefined;
}
self Attach( "head_mp_infected", "", true );
self.headModel = "head_mp_infected";
self SetClothType("cloth");
}
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 GetRankedPlayerData( "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;
// bots dont need this logic running and its one of the lowest hanging script performance costs
if ( IsAI( self ) )
return;
if ( self.timePlayed["allies"] )
{
if ( !IsSquadsMode() )
{
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"] );
self maps\mp\gametypes\_persistence::statAddChildBufferedWithMax( "xpMultiplierTimePlayed", 0, self.timePlayed["allies"], self.bufferedChildStatsMax[ "xpMaxMultiplierTimePlayed" ][ 0 ] );
self maps\mp\gametypes\_persistence::statAddChildBufferedWithMax( "xpMultiplierTimePlayed", 1, self.timePlayed["allies"], self.bufferedChildStatsMax[ "xpMaxMultiplierTimePlayed" ][ 1 ] );
self maps\mp\gametypes\_persistence::statAddChildBufferedWithMax( "xpMultiplierTimePlayed", 2, self.timePlayed["allies"], self.bufferedChildStatsMax[ "xpMaxMultiplierTimePlayed" ][ 2 ] );
if ( IsSquadsMode() )
{
self maps\mp\gametypes\_persistence::statAddBufferedWithMax( "prestigeDoubleXpTimePlayed", self.timePlayed["allies"], self.bufferedStatsMax["prestigeDoubleXpMaxTimePlayed"] );
self maps\mp\gametypes\_persistence::statAddBufferedWithMax( "prestigeDoubleWeaponXpTimePlayed", self.timePlayed["allies"], self.bufferedStatsMax["prestigeDoubleWeaponXpMaxTimePlayed"] );
}
}
if ( self.timePlayed["axis"] )
{
if ( !IsSquadsMode() )
{
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"] );
self maps\mp\gametypes\_persistence::statAddChildBufferedWithMax( "xpMultiplierTimePlayed", 0, self.timePlayed["axis"], self.bufferedChildStatsMax[ "xpMaxMultiplierTimePlayed" ][ 0 ] );
self maps\mp\gametypes\_persistence::statAddChildBufferedWithMax( "xpMultiplierTimePlayed", 1, self.timePlayed["axis"], self.bufferedChildStatsMax[ "xpMaxMultiplierTimePlayed" ][ 1 ] );
self maps\mp\gametypes\_persistence::statAddChildBufferedWithMax( "xpMultiplierTimePlayed", 2, self.timePlayed["axis"], self.bufferedChildStatsMax[ "xpMaxMultiplierTimePlayed" ][ 2 ] );
if ( IsSquadsMode() )
{
self maps\mp\gametypes\_persistence::statAddBufferedWithMax( "prestigeDoubleXpTimePlayed", self.timePlayed["axis"], self.bufferedStatsMax["prestigeDoubleXpMaxTimePlayed"] );
self maps\mp\gametypes\_persistence::statAddBufferedWithMax( "prestigeDoubleWeaponXpTimePlayed", self.timePlayed["axis"], self.bufferedStatsMax["prestigeDoubleWeaponXpMaxTimePlayed"] );
}
}
if ( self.timePlayed["other"] )
{
if ( !IsSquadsMode() )
{
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"] );
self maps\mp\gametypes\_persistence::statAddChildBufferedWithMax( "xpMultiplierTimePlayed", 0, self.timePlayed["other"], self.bufferedChildStatsMax[ "xpMaxMultiplierTimePlayed" ][ 0 ] );
self maps\mp\gametypes\_persistence::statAddChildBufferedWithMax( "xpMultiplierTimePlayed", 1, self.timePlayed["other"], self.bufferedChildStatsMax[ "xpMaxMultiplierTimePlayed" ][ 1 ] );
self maps\mp\gametypes\_persistence::statAddChildBufferedWithMax( "xpMultiplierTimePlayed", 2, self.timePlayed["other"], self.bufferedChildStatsMax[ "xpMaxMultiplierTimePlayed" ][ 2 ] );
if ( IsSquadsMode() )
{
self maps\mp\gametypes\_persistence::statAddBufferedWithMax( "prestigeDoubleXpTimePlayed", self.timePlayed["other"], self.bufferedStatsMax["prestigeDoubleXpMaxTimePlayed"] );
self maps\mp\gametypes\_persistence::statAddBufferedWithMax( "prestigeDoubleWeaponXpTimePlayed", self.timePlayed["other"], self.bufferedStatsMax["prestigeDoubleWeaponXpMaxTimePlayed"] );
}
}
if ( game["state"] == "postgame" )
return;
self.timePlayed["allies"] = 0;
self.timePlayed["axis"] = 0;
self.timePlayed["other"] = 0;
}
getJoinTeamPermissions( team )
{
if ( is_aliens() )
return true;
teamcount = 0;
botcount = 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( IsBot( player ) )
botcount++;
}
}
if( teamCount < level.teamLimit )
return true;
else if ( botcount > 0 ) // If team is full but has bots, still allow human player on
return true;
else if ( !matchMakingGame() ) // For non match making games we don't care how many people can join a team
return true;
else if ( level.gameType == "infect" ) // Since we are forcing everyone to start off as survivors, make sure they can bypass the team limit
return true;
else
return false;
}
onPlayerSpawned()
{
level endon ( "game_ended" );
for ( ;; )
{
self waittill ( "spawned_player" );
}
}
MT_getTeamName( teamRef )
{
return ( tableLookupIString( "mp/MTTable.csv", MT_REF_COL, teamRef, MT_NAME_COL ));
}
MT_getTeamIcon( teamRef )
{
return ( tableLookup( "mp/MTTable.csv", MT_REF_COL, teamRef, MT_ICON_COL ));
}
MT_getTeamHeadIcon( teamRef )
{
return ( tableLookup( "mp/MTTable.csv", MT_REF_COL, teamRef, MT_HEAD_ICON_COL ));
}
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 ) );
}
getTeamDeployModel( teamRef )
{
return ( tableLookup( "mp/factionTable.csv", FACTION_REF_COL, game[teamRef], FACTION_DEPLOY_MODEL_COL ) );
}

View File

@ -0,0 +1,540 @@
#include common_scripts\utility;
#include maps\mp\_utility;
#include maps\mp\gametypes\_weapons;
PROTECTION_DIST_SQ = 256 * 256;
PREDATOR_PROTECTION_DIST_SQ = 384 * 384;
SWITCHBLADE_PROTECTION_DIST_SQ = 1024 * 1024;
HIND_PROTECTION_DIST_SQ = 384 * 384;
trophyUsed( grenade ) // self == player
{
self endon( "spawned_player" );
self endon( "disconnect" );
if( !IsAlive( self ) )
{
grenade delete();
return;
}
if( self IsOnLadder()
|| !self IsOnGround() )
{
// 2013-08-01 wallace: as always, the grenade itself knows whether it is "alientrophy_mp" or "trophy_mp"
self restockTrophy( grenade.weapon_name );
grenade delete();
return;
}
if ( isDefined( self.OnHeliSniper ) && self.OnHeliSniper )
{
grenade delete();
self.heliSniper thread trophyActive( self );
return;
}
// need to see if this is being placed far away from the player and not let it do that
// this will fix a legacy bug where you can stand on a ledge and plant a claymore down on the ground far below you
grenade Hide();
// grenade waittill( "missile_stuck", stuckTo );
placement = self CanPlayerPlaceSentry( true, 12 );
if ( placement[ "result" ]
&& is_normal_upright( AnglesToUp( placement[ "angles" ] ) )
)
{
grenade.origin = placement[ "origin" ];
grenade.angles = placement[ "angles" ];
}
else
{
// 2013-08-22 wallace: set the trophy to the player's position to address all sorts of weird placement issues (falling through cracks, clipping through walls at weird angles)
// this will cause the playe to clip through the trophy, though.
grenade.origin = self.origin;
grenade.angles = self.angles;
}
grenade Show();
// these sounds used to be in the gdt grenade fire, but we want to be able to play the scavenger sound if there was a bad placement
self PlayLocalSound( "trophy_turret_plant_plr" );
self PlaySoundToTeam( "trophy_turret_plant_npc", "allies", self );
self PlaySoundToTeam( "trophy_turret_plant_npc", "axis", self );
// need to spawn in a model and delete the "grenade" so we can damage it properly
trophy = Spawn( "script_model", grenade.origin );
assert( IsDefined( trophy ) );
//trophy maketrophysystem( self );
trophy SetModel( "mp_trophy_system_iw6" );
trophy thread createBombSquadModel( "mp_trophy_system_iw6_bombsquad", "tag_origin", self );
trophy.angles = grenade.angles;
trophy.team = self.team;
trophy.owner = self;
trophy.isTallForWaterChecks = true; // make sure that this is not destroyed by the water script in mp_flooded
if ( isDefined ( self.trophyRemainingAmmo ) && self.trophyRemainingAmmo > 0 )
trophy.ammo = self.trophyRemainingAmmo;
else if (is_aliens() )
trophy.ammo = 5;
else
trophy.ammo = 2;
// calculate an origin that is both closer to the center of the trophy system model and higher off the ground to improve the player use trace over uneven/angled script_brushmodels
offset_magnitude = 16;
offset_vector = AnglesToUp( trophy.angles );
offset_vector = offset_magnitude * offset_vector;
offset_origin = trophy.origin + offset_vector;
trophy.trigger = spawn( "script_origin", offset_origin );
//trophy.trigger EnableLinkTo();
trophy.trigger LinkTo( trophy );
trophy thread trophyDamage( self );
trophy thread trophyWaitForDetonation();
trophy thread trophyActive( self );
trophy thread trophyDisconnectWaiter( self );
trophy thread trophyPlayerSpawnWaiter( self );
trophy thread trophyUseListener( self );
trophy SetOtherEnt( self );
trophy maps\mp\gametypes\_weapons::makeExplosiveTargetableByAI( true );
trophy maps\mp\gametypes\_weapons::explosiveHandleMovers( placement[ "entity" ], true );
if ( level.teamBased )
trophy maps\mp\_entityheadicons::setTeamHeadIcon( self.team, (0,0,65) );
else
trophy maps\mp\_entityheadicons::setPlayerHeadIcon( self, (0,0,65) );
self onTacticalEquipmentPlanted( trophy );
trophy thread playAnimations();
if( IsDefined( grenade ) )
{
waitframe();
grenade Delete();
}
if( is_aliens() )
self TakeWeapon( "alientrophy_mp" );
}
//waittillStopMoving( timeout )
//{
// self endon( "death" );
//
// prevOrigin = undefined;
// while( true )
// {
// if( !IsDefined( prevOrigin ) )
// prevOrigin = self.origin;
// else if( prevOrigin == self.origin )
// break;
// else
// prevOrigin = self.origin;
//
// wait(0.05);
//
// timeout -= 0.05;
// if( timeout <= 0 )
// return false;
// }
//
// return true;
//}
trophyUseListener( owner ) // self == trophy
{
self endon ( "death" );
level endon ( "game_ended" );
owner endon ( "disconnect" );
owner endon ( "death" );
self.trigger setCursorHint( "HINT_NOICON" );
self.trigger setHintString( &"MP_PICKUP_TROPHY" );
self.trigger setSelfUsable( owner );
self.trigger thread notUsableForJoiningPlayers( owner );
for ( ;; )
{
self.trigger waittill ( "trigger", owner );
self StopLoopSound();
if ( is_aliens() )
{
offhandweapons = owner GetWeaponsListOffhands();
cannot_pick_up = undefined;
foreach ( offhandweapon in offhandweapons )
{
if ( offhandweapon == "alienflare_mp" || offhandweapon == "alientrophy_mp" || offhandweapon == "alienthrowingknife_mp" || ( isDefined( level.trophy_use_pickupfunc ) && [[level.trophy_use_pickupfunc]]( offhandweapon) ) )
{
ammo_count = owner GetAmmoCount( offhandweapon );
if ( ammo_count > 0 )
{
owner setLowerMessage( "slots_full", &"ALIEN_COLLECTIBLES_TACTICAL_FULL", 3 );
cannot_pick_up = true;
break;
}
}
}
if ( !IsDefined( cannot_pick_up ) )
{
owner setOffhandSecondaryClass( "flash" ); //ALIENS USES THIS CLASS FOR THE TROPHY SYSTEM
owner playLocalSound( "scavenger_pack_pickup" );
owner.trophyRemainingAmmo = self.ammo;
owner TakeWeapon ( "alientrophy_mp" );
owner _giveweapon ( "alientrophy_mp" );
self ScriptModelClearAnim();
self deleteExplosive();
self notify( "death" );
}
}
else // give item to user if not juggernaut (switched class) but in aliens we want juggs to be able to move the trophy
{
if( !owner isJuggernaut() )
{
owner restockTrophy( "trophy_mp" );
owner.trophyRemainingAmmo = self.ammo;
self ScriptModelClearAnim();
self deleteExplosive();
self notify( "death" );
}
}
}
}
trophyPlayerSpawnWaiter( owner )
{
self endon ( "disconnect" );
self endon ( "death" );
owner waittill( "spawned" );
self notify ( "detonateExplosive" );
}
trophyDisconnectWaiter( owner )
{
self endon ( "death" );
owner waittill( "disconnect" );
self notify ( "detonateExplosive" );
}
trophyActive( owner )
{
owner endon( "disconnect" );
self endon ( "death" );
// 2013-08-22 wallace: camera_jnt is at the position of the camera sensor in the IW6 model
// we use this is our ref point b/c self.origin might sometimes be underground, which would cause the BulletTracePassed call to fail
if ( is_aliens() && self.model == "mp_weapon_alien_crate" ) //aliens engineer class slow field bubble also works as a trophy
position = self.origin;
else
position = self GetTagOrigin( "camera_jnt" );
if ( IsDefined ( self.cameraOffset ) )
self.cameraOffsetVector = (0, 0, self.cameraOffset);
else
self.cameraOffsetVector = position - self.origin; // add this in case the trophy is on a moving platform
normalProtectionDistanceSquared = 256 * 256;
specialProtectionDistanceSquared = 384 * 384;
self.killCamEnt = Spawn( "script_model", position + ( 0, 0, 5 ) );
self.killCamEnt LinkTo( self );
if ( !IsDefined( level.grenades ) )
level.grenades = [];
if ( !IsDefined( level.missiles ) )
level.missiles = [];
for( ;; )
{
if ( IsDefined( self.disabled )
|| ( level.grenades.size < 1 && level.missiles.size < 1 )
)
{
wait( .05 );
continue;
}
sentryTargets = array_combine ( level.grenades, level.missiles );
foreach ( grenade in sentryTargets )
{
if ( !isDefined(grenade) )
continue;
if ( grenade == self )
continue;
if ( IsDefined( grenade.exploding ) )
{
AssertEx( grenade.exploding == true, "grenade.exploding should always be set to true" );
continue;
}
if ( isDefined( grenade.weapon_name ) )
{
switch( grenade.weapon_name )
{
case "trophy_mp":
case "claymore_mp":
case "throwingknife_mp":
case "throwingknifejugg_mp":
case "airdrop_marker_mp":
case "deployable_vest_marker_mp":
case "deployable_weapon_crate_marker_mp":
case "odin_projectile_marking_mp":
case "odin_projectile_smoke_mp":
case "odin_projectile_airdrop_mp":
case "odin_projectile_large_rod_mp":
case "odin_projectile_small_rod_mp":
continue;
}
}
if ( !isDefined( grenade.owner ) )
grenade.owner = GetMissileOwner( grenade );
//assertEx( isDefined( grenade.owner ), "grenade has no owner" );
//grenades owner may have disconnected by now if they do we should just assume enemy and detonate it.
if ( IsDefined( grenade.owner ) && !(owner isEnemy( grenade.owner ) ) )
continue;
// If this is a night owl, we need to make sure we update the position, otherwise it will no longer block grenades when it moves to a new location
if ( isDefined( self.cameraOffsetVector ) )
position = self.origin + self.cameraOffsetVector;
grenadeDistanceSquared = DistanceSquared( grenade.origin, position );
protectionDistanceSquared = trophy_getProtectionDistance( grenade );
if ( grenadeDistanceSquared < protectionDistanceSquared )
{
// can't use BulletTracePassed any more b/c traces collide with C4 for some reason?
// we are checking the trace fraction to make sure it is getting to the target entity (ala nothing in the way), then we want to make sure the target entity is the grenade
traceResult = BulletTrace( position, grenade.origin, false, self );
if ( traceResult[ "fraction" ] == 1 || ( IsDefined( traceResult[ "entity" ] ) && traceResult[ "entity" ] == grenade ) )
{
playFX( level.sentry_fire, position, ( grenade.origin - position ), AnglesToUp( self.angles ) );
self playSound( "trophy_detect_projectile" );
// do a little extra if this was a predator missile or reaper missile
if( trophy_grenadeIsKillstreakMissile( grenade ) )
{
if( IsDefined( grenade.type ) && grenade.type == "remote" )
{
// show that you destroyed a killstreak and give the streak point
level thread maps\mp\gametypes\_missions::killstreakKilled( grenade.owner, owner, undefined, owner, undefined, "MOD_EXPLOSIVE", "trophy_mp" );
level thread teamPlayerCardSplash( "callout_destroyed_predator_missile", owner );
owner thread maps\mp\gametypes\_rank::giveRankXP( "kill", 100, "trophy_mp", "MOD_EXPLOSIVE" );
owner notify( "destroyed_killstreak", "trophy_mp" );
}
// play fx and a sound
if( IsDefined( level.chopper_fx["explode"]["medium"] ) )
PlayFX( level.chopper_fx["explode"]["medium"], grenade.origin );
if( IsDefined( level.barrelExpSound ) )
grenade PlaySound( level.barrelExpSound );
}
owner thread projectileExplode( grenade, self );
owner maps\mp\gametypes\_missions::processChallenge( "ch_noboomforyou" );
if( !is_aliens() )
{
//for weapons stats tracking
owner thread maps\mp\gametypes\_gamelogic::threadedSetWeaponStatByName( "trophy_mp", 1, "hits" );
}
self.ammo--;
if ( self.ammo <= 0 )
{
// if we are out of ammo then we don't need to track the remaining ammo
// there was a bug here where every trophy set down after this would only have 1 ammo
owner.trophyRemainingAmmo = undefined;
self notify ( "detonateExplosive" );
}
}
}
}
wait( .05 );
}
}
trophy_grenadeIsKillstreakMissile( grenade )
{
return ( ( IsDefined( grenade.classname ) && grenade.classname == "rocket" ) &&
( IsDefined( grenade.type ) && ( grenade.type == "remote" || grenade.type == "remote_mortar" ) ) );
}
trophy_getProtectionDistance( grenade )
{
// !!! HACK
// the child projectile moves even faster than other killstreak missiles.
// also the check has to come first, because it will also pass the second check
if ( isDefined ( grenade.weapon_name) && grenade.weapon_name == "switch_blade_child_mp" )
{
return SWITCHBLADE_PROTECTION_DIST_SQ;
}
// if the projectile in a predator missile or reaper missile then we need a larger radius check because of speed
else if ( trophy_grenadeIsKillstreakMissile( grenade ) )
{
return PREDATOR_PROTECTION_DIST_SQ;
}
else if ( isDefined ( grenade.weapon_name) && ( grenade.weapon_name == "hind_missile_mp" || grenade.weapon_name == "hind_bomb_mp" ) )
{
return HIND_PROTECTION_DIST_SQ;
}
else
{
return PROTECTION_DIST_SQ;
}
}
projectileExplode( projectile, trophy ) // self == owner
{
self endon( "death" );
projPosition = projectile.origin;
projType = projectile.model;
projAngles = projectile.angles;
projectile StopSounds();
projectile.exploding = true;
if ( projType == "weapon_light_marker" )
{
playFX( level.empGrenadeExplode, projPosition, AnglesToForward( projAngles ), AnglesToUp( projAngles ) );
trophy notify ( "detonateExplosive" );
waitframe();
projectile delete();
return;
}
trophy playSound( "trophy_fire" );
playFX( level.mine_explode, projPosition, AnglesToForward( projAngles ), AnglesToUp( projAngles ) );
if ( is_aliens() )
{
trophy RadiusDamage( projPosition, 128, 105, 10, self, "MOD_EXPLOSIVE", "alientrophy_mp" );
}
else
{
trophy RadiusDamage( projPosition, 128, 105, 10, self, "MOD_EXPLOSIVE", "trophy_mp" );
}
// wait for stop sounds
waitframe();
if ( IsDefined( projectile ) )
{
projectile delete();
}
}
trophyDamage( owner )
{
self maps\mp\gametypes\_damage::monitorDamage(
100,
"trophy",
::trophyHandleDeathDamage,
::trophyModifyDamage,
false // isKillstreak
);
}
trophyModifyDamage( attacker, weapon, type, damage )
{
modifiedDamage = damage;
modifiedDamage = self maps\mp\gametypes\_damage::handleMeleeDamage( weapon, type, modifiedDamage );
modifiedDamage = self maps\mp\gametypes\_damage::handleEmpDamage( weapon, type, modifiedDamage );
// modifiedDamage = self maps\mp\gametypes\_damage::handleMissileDamage( weapon, type, modifiedDamage );
modifiedDamage = self maps\mp\gametypes\_damage::handleAPDamage( weapon, type, modifiedDamage, attacker );
return modifiedDamage;
}
trophyHandleDeathDamage( attacker, weapon, type, damage ) // self == trophy
{
if( IsDefined( self.owner ) && attacker != self.owner )
{
attacker notify("destroyed_equipment");
}
self notify ( "detonateExplosive" );
}
trophyWaitForDetonation()
{
level endon ("game_ended");
self waittill ("detonateExplosive" );
self ScriptModelClearAnim();
self StopLoopSound();
self equipmentDeathVfx();
self notify( "death" );
placement = self.origin;
self.trigger MakeUnusable();
self FreeEntitySentient();
wait(3);//timer for trophy to self delete
if ( IsDefined( self ) )
{
if( IsDefined( self.killCamEnt ) )
self.killCamEnt delete();
self equipmentDeleteVfx();
self deleteExplosive();
}
}
#using_animtree( "animated_props" );
playAnimations() // self
{
self endon( "emp_damage" );
self endon( "death" );
self ScriptModelPlayAnim( "trophy_system_deploy" );
animLength = GetAnimLength( %trophy_system_deploy );
wait( animLength );
self ScriptModelPlayAnim( "trophy_system_idle" );
self PlayLoopSound( "trophy_turret_rotate_lp" );
// play vfx
// upLinkEnt thread maps\mp\gametypes\_weapons::doBlinkingLight( "tag_fx" );
}
restockTrophy( weapon_name ) // self == player
{
self PlayLocalSound( "scavenger_pack_pickup" );
self SetWeaponAmmoStock( weapon_name, self GetWeaponAmmoStock( weapon_name ) + 1 );
}
// stolen from aliens utility
is_normal_upright( normal )
{
UPRIGHT_VECTOR = ( 0, 0, 1 );
UPRIGHT_DOT = 0.85;
return ( VectorDot( normal, UPRIGHT_VECTOR ) > UPRIGHT_DOT );
}

View File

@ -0,0 +1,374 @@
#include maps\mp\_utility;
getTweakableDVarValue( category, name )
{
switch( category )
{
case "rule":
dVar = level.rules[name].dVar;
break;
case "game":
dVar = level.gameTweaks[name].dVar;
break;
case "team":
dVar = level.teamTweaks[name].dVar;
break;
case "player":
dVar = level.playerTweaks[name].dVar;
break;
case "class":
dVar = level.classTweaks[name].dVar;
break;
case "weapon":
dVar = level.weaponTweaks[name].dVar;
break;
case "hardpoint":
dVar = level.hardpointTweaks[name].dVar;
break;
case "hud":
dVar = level.hudTweaks[name].dVar;
break;
default:
dVar = undefined;
break;
}
assert( isDefined( dVar ) );
value = getDvarInt( dVar );
return value;
}
getTweakableDVar( category, name )
{
switch( category )
{
case "rule":
value = level.rules[name].dVar;
break;
case "game":
value = level.gameTweaks[name].dVar;
break;
case "team":
value = level.teamTweaks[name].dVar;
break;
case "player":
value = level.playerTweaks[name].dVar;
break;
case "class":
value = level.classTweaks[name].dVar;
break;
case "weapon":
value = level.weaponTweaks[name].dVar;
break;
case "hardpoint":
value = level.hardpointTweaks[name].dVar;
break;
case "hud":
value = level.hudTweaks[name].dVar;
break;
default:
value = undefined;
break;
}
assert( isDefined( value ) );
return value;
}
getTweakableValue( category, name )
{
switch( category )
{
case "rule":
value = level.rules[name].value;
break;
case "game":
value = level.gameTweaks[name].value;
break;
case "team":
value = level.teamTweaks[name].value;
break;
case "player":
value = level.playerTweaks[name].value;
break;
case "class":
value = level.classTweaks[name].value;
break;
case "weapon":
value = level.weaponTweaks[name].value;
break;
case "hardpoint":
value = level.hardpointTweaks[name].value;
break;
case "hud":
value = level.hudTweaks[name].value;
break;
default:
value = undefined;
break;
}
/#
overrideDvar = "scr_" + level.gameType + "_" + category + "_" + name;
return getDvarInt( overrideDvar, value );
#/
assert( isDefined( value ) );
return value;
}
getTweakableLastValue( category, name )
{
switch( category )
{
case "rule":
value = level.rules[name].lastValue;
break;
case "game":
value = level.gameTweaks[name].lastValue;
break;
case "team":
value = level.teamTweaks[name].lastValue;
break;
case "player":
value = level.playerTweaks[name].lastValue;
break;
case "class":
value = level.classTweaks[name].lastValue;
break;
case "weapon":
value = level.weaponTweaks[name].lastValue;
break;
case "hardpoint":
value = level.hardpointTweaks[name].lastValue;
break;
case "hud":
value = level.hudTweaks[name].lastValue;
break;
default:
value = undefined;
break;
}
assert( isDefined( value ) );
return value;
}
setTweakableValue( category, name, value )
{
switch( category )
{
case "rule":
dVar = level.rules[name].dVar;
break;
case "game":
dVar = level.gameTweaks[name].dVar;
break;
case "team":
dVar = level.teamTweaks[name].dVar;
break;
case "player":
dVar = level.playerTweaks[name].dVar;
break;
case "class":
dVar = level.classTweaks[name].dVar;
break;
case "weapon":
dVar = level.weaponTweaks[name].dVar;
break;
case "hardpoint":
dVar = level.hardpointTweaks[name].dVar;
break;
case "hud":
dVar = level.hudTweaks[name].dVar;
break;
default:
dVar = undefined;
break;
}
setDvar( dVar, value );
}
setTweakableLastValue( category, name, value )
{
switch( category )
{
case "rule":
level.rules[name].lastValue = value;
break;
case "game":
level.gameTweaks[name].lastValue = value;
break;
case "team":
level.teamTweaks[name].lastValue = value;
break;
case "player":
level.playerTweaks[name].lastValue = value;
break;
case "class":
level.classTweaks[name].lastValue = value;
break;
case "weapon":
level.weaponTweaks[name].lastValue = value;
break;
case "hardpoint":
level.hardpointTweaks[name].lastValue = value;
break;
case "hud":
level.hudTweaks[name].lastValue = value;
break;
default:
break;
}
}
registerTweakable( category, name, dvar, value )
{
if ( isString( value ) )
{
value = getDvar( dvar, value );
}
else
{
value = getDvarInt( dvar, value );
}
switch( category )
{
case "rule":
if ( !isDefined( level.rules[name] ) )
level.rules[name] = spawnStruct();
level.rules[name].value = value;
level.rules[name].lastValue = value;
level.rules[name].dVar = dvar;
break;
case "game":
if ( !isDefined( level.gameTweaks[name] ) )
level.gameTweaks[name] = spawnStruct();
level.gameTweaks[name].value = value;
level.gameTweaks[name].lastValue = value;
level.gameTweaks[name].dVar = dvar;
break;
case "team":
if ( !isDefined( level.teamTweaks[name] ) )
level.teamTweaks[name] = spawnStruct();
level.teamTweaks[name].value = value;
level.teamTweaks[name].lastValue = value;
level.teamTweaks[name].dVar = dvar;
break;
case "player":
if ( !isDefined( level.playerTweaks[name] ) )
level.playerTweaks[name] = spawnStruct();
level.playerTweaks[name].value = value;
level.playerTweaks[name].lastValue = value;
level.playerTweaks[name].dVar = dvar;
break;
case "class":
if ( !isDefined( level.classTweaks[name] ) )
level.classTweaks[name] = spawnStruct();
level.classTweaks[name].value = value;
level.classTweaks[name].lastValue = value;
level.classTweaks[name].dVar = dvar;
break;
case "weapon":
if ( !isDefined( level.weaponTweaks[name] ) )
level.weaponTweaks[name] = spawnStruct();
level.weaponTweaks[name].value = value;
level.weaponTweaks[name].lastValue = value;
level.weaponTweaks[name].dVar = dvar;
break;
case "hardpoint":
if ( !isDefined( level.hardpointTweaks[name] ) )
level.hardpointTweaks[name] = spawnStruct();
level.hardpointTweaks[name].value = value;
level.hardpointTweaks[name].lastValue = value;
level.hardpointTweaks[name].dVar = dvar;
break;
case "hud":
if ( !isDefined( level.hudTweaks[name] ) )
level.hudTweaks[name] = spawnStruct();
level.hudTweaks[name].value = value;
level.hudTweaks[name].lastValue = value;
level.hudTweaks[name].dVar = dvar;
break;
}
}
init()
{
level.clientTweakables = [];
level.tweakablesInitialized = true;
level.rules = [];
level.gameTweaks = [];
level.teamTweaks = [];
level.playerTweaks = [];
level.classTweaks = [];
level.weaponTweaks = [];
level.hardpointTweaks = [];
level.hudTweaks = [];
// commented out tweaks have not yet been implemented
if ( level.console )
{
// adding more time for next gen to account for variance in load times
if ( level.xb3 || level.ps4 )
registerTweakable( "game", "graceperiod", "scr_game_graceperiod", 20 ); //* maximum delay to wait before starting match start countdown
else
registerTweakable( "game", "graceperiod", "scr_game_graceperiod", 15 ); //* maximum delay to wait before starting match start countdown
registerTweakable( "game", "graceperiod_comp", "scr_game_graceperiod_comp", 60 ); //*
}
else
{
registerTweakable( "game", "playerwaittime", "scr_game_playerwaittime", 15 ); //* maximum delay to wait before starting match start countdown
registerTweakable( "game", "playerwaittime_comp", "scr_game_playerwaittime_comp", 60 ); //*
}
registerTweakable( "game", "matchstarttime", "scr_game_matchstarttime", 15 ); //* match start countdown
registerTweakable( "game", "onlyheadshots", "scr_game_onlyheadshots", 0 ); //*
registerTweakable( "game", "allowkillcam", "scr_game_allowkillcam", 1 ); //*
registerTweakable( "game", "spectatetype", "scr_game_spectatetype", 2 ); //*
registerTweakable( "game", "deathpointloss", "scr_game_deathpointloss", 0 ); //*
registerTweakable( "game", "suicidepointloss", "scr_game_suicidepointloss", 0 ); //*
registerTweakable( "team", "teamkillpointloss", "scr_team_teamkillpointloss", 0 ); //*
// registerTweakable( "team", "respawntime", "scr_team_respawntime", 0 );
registerTweakable( "team", "fftype", "scr_team_fftype", 0 );
registerTweakable( "team", "teamkillspawndelay", "scr_team_teamkillspawndelay", 0 );
// registerTweakable( "player", "respawndelay", "scr_player_respawndelay", 0 ); //*
registerTweakable( "player", "maxhealth", "scr_player_maxhealth", 100 ); //*
registerTweakable( "player", "healthregentime", "scr_player_healthregentime", 5 ); //*
registerTweakable( "player", "forcerespawn", "scr_player_forcerespawn", 1 ); //*
registerTweakable( "weapon", "allowfrag", "scr_weapon_allowfrags", 1 );
registerTweakable( "weapon", "allowsmoke", "scr_weapon_allowsmoke", 1 );
registerTweakable( "weapon", "allowflash", "scr_weapon_allowflash", 1 );
registerTweakable( "weapon", "allowc4", "scr_weapon_allowc4", 1 );
registerTweakable( "weapon", "allowclaymores", "scr_weapon_allowclaymores", 1 );
registerTweakable( "weapon", "allowrpgs", "scr_weapon_allowrpgs", 1 );
registerTweakable( "weapon", "allowmines", "scr_weapon_allowmines", 1 );
registerTweakable( "hardpoint", "allowartillery", "scr_hardpoint_allowartillery", 1 );
registerTweakable( "hardpoint", "allowuav", "scr_hardpoint_allowuav", 1 );
registerTweakable( "hardpoint", "allowsupply", "scr_hardpoint_allowsupply", 1 );
registerTweakable( "hardpoint", "allowhelicopter", "scr_hardpoint_allowhelicopter", 1 );
registerTweakable( "hud", "showobjicons", "ui_hud_showobjicons", 1 ); //*
SetDvar( "ui_hud_showobjicons", 1 );
}

File diff suppressed because it is too large Load Diff

2815
maps/mp/gametypes/aliens.gsc Normal file

File diff suppressed because it is too large Load Diff

1436
maps/mp/gametypes/blitz.gsc Normal file

File diff suppressed because it is too large Load Diff

458
maps/mp/gametypes/conf.gsc Normal file
View File

@ -0,0 +1,458 @@
#include maps\mp\_utility;
#include maps\mp\gametypes\_hud_util;
#include common_scripts\utility;
#include maps\mp\agents\_agent_utility;
/*
Confirmed Kill
Objective: Score points for your team by eliminating players on the opposing team.
Score bonus points for picking up dogtags from downed enemies.
Map ends: When one team reaches the score limit, or time limit is reached
Respawning: No wait / Near teammates
Level requirementss
------------------
Spawnpoints:
classname mp_tdm_spawn
All players spawn from these. The spawnpoint chosen is dependent on the current locations of teammates and enemies
at the time of spawn. Players generally spawn behind their teammates relative to the direction of enemies.
Spectator Spawnpoints:
classname mp_global_intermission
Spectators spawn from these and intermission is viewed from these positions.
Atleast one is required, any more and they are randomly chosen between.
*/
CONST_FRIENDLY_TAG_MODEL = "prop_dogtags_friend_iw6";
CONST_ENEMY_TAG_MODEL = "prop_dogtags_foe_iw6";
main()
{
if(getdvar("mapname") == "mp_background")
return;
maps\mp\gametypes\_globallogic::init();
maps\mp\gametypes\_callbacksetup::SetupCallbacks();
maps\mp\gametypes\_globallogic::SetupCallbacks();
if ( isUsingMatchRulesData() )
{
level.initializeMatchRules = ::initializeMatchRules;
[[level.initializeMatchRules]]();
level thread reInitializeMatchRulesOnMigration();
}
else
{
registerRoundSwitchDvar( level.gameType, 0, 0, 9 );
registerTimeLimitDvar( level.gameType, 10 );
registerScoreLimitDvar( level.gameType, 65 );
registerRoundLimitDvar( level.gameType, 1 );
registerWinLimitDvar( level.gameType, 1 );
registerNumLivesDvar( level.gameType, 0 );
registerHalfTimeDvar( level.gameType, 0 );
level.matchRules_damageMultiplier = 0;
level.matchRules_vampirism = 0;
}
level.teamBased = true;
level.initGametypeAwards = ::initGametypeAwards;
level.onStartGameType = ::onStartGameType;
level.getSpawnPoint = ::getSpawnPoint;
level.onNormalDeath = ::onNormalDeath;
level.onPrecacheGameType = ::onPrecacheGameType;
if ( level.matchRules_damageMultiplier || level.matchRules_vampirism )
level.modifyPlayerDamage = maps\mp\gametypes\_damage::gamemodeModifyPlayerDamage;
game["dialog"]["gametype"] = "kill_confirmed";
game["dialog"]["kill_confirmed"] = "kill_confirmed";
if ( getDvarInt( "g_hardcore" ) )
game["dialog"]["gametype"] = "hc_" + game["dialog"]["gametype"];
level.conf_fx["vanish"] = loadFx( "fx/impacts/small_snowhit" );
}
initializeMatchRules()
{
// set common values
setCommonRulesFromMatchRulesData();
// set everything else (private match options, default .cfg file values, and what normally is registered in the 'else' below)
SetDynamicDvar( "scr_conf_roundswitch", 0 );
registerRoundSwitchDvar( "conf", 0, 0, 9 );
SetDynamicDvar( "scr_conf_roundlimit", 1 );
registerRoundLimitDvar( "conf", 1 );
SetDynamicDvar( "scr_conf_winlimit", 1 );
registerWinLimitDvar( "conf", 1 );
SetDynamicDvar( "scr_conf_halftime", 0 );
registerHalfTimeDvar( "conf", 0 );
SetDynamicDvar( "scr_conf_promode", 0 );
}
onPrecacheGameType()
{
precacheMpAnim( "mp_dogtag_spin" );
precacheshader( "waypoint_dogtags" );
}
onStartGameType()
{
setClientNameMode("auto_change");
if ( !isdefined( game["switchedsides"] ) )
game["switchedsides"] = false;
if ( game["switchedsides"] )
{
oldAttackers = game["attackers"];
oldDefenders = game["defenders"];
game["attackers"] = oldDefenders;
game["defenders"] = oldAttackers;
}
setObjectiveText( "allies", &"OBJECTIVES_CONF" );
setObjectiveText( "axis", &"OBJECTIVES_CONF" );
if ( level.splitscreen )
{
setObjectiveScoreText( "allies", &"OBJECTIVES_CONF" );
setObjectiveScoreText( "axis", &"OBJECTIVES_CONF" );
}
else
{
setObjectiveScoreText( "allies", &"OBJECTIVES_CONF_SCORE" );
setObjectiveScoreText( "axis", &"OBJECTIVES_CONF_SCORE" );
}
setObjectiveHintText( "allies", &"OBJECTIVES_CONF_HINT" );
setObjectiveHintText( "axis", &"OBJECTIVES_CONF_HINT" );
initSpawns();
level.dogtags = [];
allowed[0] = level.gameType;
maps\mp\gametypes\_gameobjects::main(allowed);
}
initSpawns()
{
level.spawnMins = ( 0, 0, 0 );
level.spawnMaxs = ( 0, 0, 0 );
maps\mp\gametypes\_spawnlogic::addStartSpawnPoints( "mp_tdm_spawn_allies_start" );
maps\mp\gametypes\_spawnlogic::addStartSpawnPoints( "mp_tdm_spawn_axis_start" );
maps\mp\gametypes\_spawnlogic::addSpawnPoints( "allies", "mp_tdm_spawn" );
maps\mp\gametypes\_spawnlogic::addSpawnPoints( "axis", "mp_tdm_spawn" );
level.mapCenter = maps\mp\gametypes\_spawnlogic::findBoxCenter( level.spawnMins, level.spawnMaxs );
setMapCenter( level.mapCenter );
}
getSpawnPoint()
{
spawnteam = self.pers["team"];
if ( game["switchedsides"] )
spawnteam = getOtherTeam( spawnteam );
if ( maps\mp\gametypes\_spawnlogic::shouldUseTeamStartSpawn() )
{
spawnPoints = maps\mp\gametypes\_spawnlogic::getSpawnpointArray( "mp_tdm_spawn_" + spawnteam + "_start" );
spawnPoint = maps\mp\gametypes\_spawnlogic::getSpawnpoint_startSpawn( spawnPoints );
}
else
{
spawnPoints = maps\mp\gametypes\_spawnlogic::getTeamSpawnPoints( spawnteam );
spawnPoint = maps\mp\gametypes\_spawnscoring::getSpawnpoint_NearTeam( spawnPoints );
}
return spawnPoint;
}
onNormalDeath( victim, attacker, lifeId )
{
level thread spawnDogTags( victim, attacker );
if ( game["state"] == "postgame" && game["teamScores"][attacker.team] > game["teamScores"][level.otherTeam[attacker.team]] )
attacker.finalKill = true;
}
spawnDogTags( victim, attacker )
{
if ( victim maps\mp\killstreaks\_killstreaks::isUsingHeliSniper() )
{
return;
}
victim_pers_team = victim.pers["team"];
if ( isDefined( level.dogtags[victim.guid] ) )
{
PlayFx( level.conf_fx["vanish"], level.dogtags[victim.guid].curOrigin );
level.dogtags[victim.guid] notify( "reset" );
}
else
{
visuals[0] = spawn( "script_model", (0,0,0) );
visuals[0] setModel( CONST_ENEMY_TAG_MODEL );
visuals[1] = spawn( "script_model", (0,0,0) );
visuals[1] setModel( CONST_FRIENDLY_TAG_MODEL );
trigger = spawn( "trigger_radius", (0,0,0), 0, 32, 32 );
level.dogtags[victim.guid] = maps\mp\gametypes\_gameobjects::createUseObject( "any", trigger, visuals, (0,0,16) );
// we don't need these
_objective_delete( level.dogtags[victim.guid].teamObjIds["allies"] );
_objective_delete( level.dogtags[victim.guid].teamObjIds["axis"] );
maps\mp\gametypes\_objpoints::deleteObjPoint( level.dogtags[victim.guid].objPoints["allies"] );
maps\mp\gametypes\_objpoints::deleteObjPoint( level.dogtags[victim.guid].objPoints["axis"] );
level.dogtags[victim.guid] maps\mp\gametypes\_gameobjects::setUseTime( 0 );
level.dogtags[victim.guid].onUse = ::onUse;
level.dogtags[victim.guid].victim = victim;
level.dogtags[victim.guid].victimTeam = victim_pers_team;
level.dogtags[victim.guid].objId = maps\mp\gametypes\_gameobjects::getNextObjID();
objective_add( level.dogtags[victim.guid].objId, "invisible", (0,0,0) );
objective_icon( level.dogtags[victim.guid].objId, "waypoint_dogtags" );
level thread clearOnVictimDisconnect( victim );
victim thread tagTeamUpdater( level.dogtags[victim.guid] );
}
pos = victim.origin + (0,0,14);
level.dogtags[victim.guid].curOrigin = pos;
level.dogtags[victim.guid].trigger.origin = pos;
level.dogtags[victim.guid].visuals[0].origin = pos;
level.dogtags[victim.guid].visuals[1].origin = pos;
level.dogtags[victim.guid] maps\mp\gametypes\_gameobjects::initializeTagPathVariables();
level.dogtags[victim.guid] maps\mp\gametypes\_gameobjects::allowUse( "any" );
level.dogtags[victim.guid].visuals[0] thread showToTeam( level.dogtags[victim.guid], getOtherTeam( victim_pers_team ) );
level.dogtags[victim.guid].visuals[1] thread showToTeam( level.dogtags[victim.guid], victim_pers_team );
level.dogtags[victim.guid].attacker = attacker;
if ( IsPlayer(attacker) )
{
objective_position( level.dogtags[victim.guid].objId, pos );
objective_state( level.dogtags[victim.guid].objId, "active" );
objective_player( level.dogtags[victim.guid].objId, attacker getEntityNumber() );
}
playSoundAtPos( pos, "mp_killconfirm_tags_drop" );
level notify( "new_tag_spawned", level.dogtags[victim.guid] );
level.dogtags[victim.guid].visuals[0] ScriptModelPlayAnim( "mp_dogtag_spin" );
level.dogtags[victim.guid].visuals[1] ScriptModelPlayAnim( "mp_dogtag_spin" );
}
showToTeam( gameObject, team )
{
gameObject endon( "death" );
gameObject endon( "reset" );
self hide();
foreach ( player in level.players )
{
if( player.team == team )
self ShowToPlayer( player );
if( player.team == "spectator" && team == "allies" )
self ShowToPlayer( player );
}
for ( ;; )
{
level waittill ( "joined_team" );
self hide();
foreach ( player in level.players )
{
if ( player.team == team )
self ShowToPlayer( player );
if ( player.team == "spectator" && team == "allies" )
self ShowToPlayer( player );
if ( gameObject.victimTeam == player.team && player == gameObject.attacker )
objective_state( gameObject.objId, "invisible" );
}
}
}
onUse( player )
{
// If this is a squadmate, give credit to the agent's owner player
if ( IsDefined(player.owner) )
{
player = player.owner;
}
// call the function directly instead of leaning on the objective monitor notify system we were using before
player maps\mp\_events::giveObjectivePointStreaks();
// friendly pickup
player_pers_team = player.pers["team"];
if ( player_pers_team == self.victimTeam )
{
self.trigger playSound( "mp_killconfirm_tags_deny" );
player incPlayerStat( "killsdenied", 1 );
player incPersStat( "denied", 1 );
player maps\mp\gametypes\_persistence::statSetChild( "round", "denied", player.pers["denied"] );
if( IsPlayer(player) )
player setExtraScore0( player.pers[ "confirmed" ] + player.pers[ "denied" ] );
if ( self.victim == player )
{
event = "tags_retrieved";
}
else
{
event = "kill_denied";
}
// tell the attacker their kill was denied
if ( isDefined( self.attacker ) )
self.attacker thread maps\mp\gametypes\_rank::xpEventPopup( "kill_denied" );
player thread onPickup( event );
// OP_IW6 Confirmed Denier - deny X kills
player maps\mp\gametypes\_missions::processChallenge( "ch_denier" );
}
// enemy pickup
else
{
self.trigger playSound( "mp_killconfirm_tags_pickup" );
event = "kill_confirmed";
player incPlayerStat( "killsconfirmed", 1 );
player incPersStat( "confirmed", 1 );
player maps\mp\gametypes\_persistence::statSetChild( "round", "confirmed", player.pers["confirmed"] );
// if not us, tell the attacker their kill was confirmed
if ( self.attacker != player )
self.attacker thread onPickup( event );
// update the player score before updating the team score, otherwise the game will end without awarding xp to the player who collected the final tag
player onPickup( event );
if ( IsPlayer(player) )
{
player leaderDialogOnPlayer( "kill_confirmed" );
player setExtraScore0( player.pers[ "confirmed" ] + player.pers[ "denied" ] );
}
// OP_IW6 Confirmed Collector - collect X enemy tags
player maps\mp\gametypes\_missions::processChallenge( "ch_collector" );
player maps\mp\gametypes\_gamescore::giveTeamScoreForObjective( player_pers_team, 1 );
}
// do all this at the end now so the location doesn't change before playing the sound on the entity
self resetTags();
}
onPickup( event )
{
level endon( "game_ended" );
self endon( "disconnect" );
while ( !isDefined( self.pers ) )
wait( 0.05 );
self thread maps\mp\gametypes\_rank::xpEventPopup( event );
maps\mp\gametypes\_gamescore::givePlayerScore( event, self, undefined, true );
self thread maps\mp\gametypes\_rank::giveRankXP( event );
}
resetTags()
{
self.attacker = undefined;
self notify( "reset" );
self.visuals[0] hide();
self.visuals[1] hide();
self.curOrigin = (0,0,1000);
self.trigger.origin = (0,0,1000);
self.visuals[0].origin = (0,0,1000);
self.visuals[1].origin = (0,0,1000);
self maps\mp\gametypes\_gameobjects::allowUse( "none" );
objective_state( self.objId, "invisible" );
}
tagTeamUpdater( tags )
{
level endon( "game_ended" );
self endon( "disconnect" );
while( true )
{
self waittill( "joined_team" );
tags.victimTeam = self.pers["team"];
tags resetTags();
}
}
clearOnVictimDisconnect( victim )
{
level endon( "game_ended" );
guid = victim.guid;
victim waittill( "disconnect" );
if ( isDefined( level.dogtags[guid] ) )
{
// block further use
level.dogtags[guid] maps\mp\gametypes\_gameobjects::allowUse( "none" );
// tell the attacker their kill was denied
if ( isDefined( level.dogtags[guid].attacker ) )
level.dogtags[guid].attacker thread maps\mp\gametypes\_rank::xpEventPopup( "kill_denied" );
// play vanish effect, reset, and wait for reset to process
PlayFx( level.conf_fx["vanish"], level.dogtags[guid].curOrigin );
level.dogtags[guid] notify( "reset" );
wait( 0.05 );
// sanity check before removal
if ( isDefined( level.dogtags[guid] ) )
{
// delete objective and visuals
objective_delete( level.dogtags[guid].objId );
level.dogtags[guid].trigger delete();
for ( i=0; i<level.dogtags[guid].visuals.size; i++ )
level.dogtags[guid].visuals[i] delete();
level.dogtags[guid] notify ( "deleted" );
// remove from list
level.dogtags[guid] = undefined;
}
}
}
initGametypeAwards()
{
//maps\mp\_awards::initStatAward( "killsconfirmed", 0, maps\mp\_awards::highestWins );
}

View File

@ -0,0 +1,557 @@
#include maps\mp\_utility;
#include maps\mp\gametypes\_hud_util;
/*
Cranked
Objective: Score points for your team by eliminating players on the opposing team.
Players who are carrying the "hot potatoes" will score more points.
The "hot potatoes" are ticking time bombs and need kills and assists to refresh the timer.
Map ends: When one team reaches the score limit, or time limit is reached
Respawning: No wait / Near teammates
Level requirementss
------------------
Spawnpoints:
classname mp_tdm_spawn
All players spawn from these. The spawnpoint chosen is dependent on the current locations of teammates and enemies
at the time of spawn. Players generally spawn behind their teammates relative to the direction of enemies.
Spectator Spawnpoints:
classname mp_global_intermission
Spectators spawn from these and intermission is viewed from these positions.
Atleast one is required, any more and they are randomly chosen between.
*/
/*QUAKED mp_tdm_spawn (0.0 0.0 1.0) (-16 -16 0) (16 16 72)
Players spawn away from enemies and near their team at one of these positions.*/
/*QUAKED mp_tdm_spawn_axis_start (0.5 0.0 1.0) (-16 -16 0) (16 16 72)
Axis players spawn away from enemies and near their team at one of these positions at the start of a round.*/
/*QUAKED mp_tdm_spawn_allies_start (0.0 0.5 1.0) (-16 -16 0) (16 16 72)
Allied players spawn away from enemies and near their team at one of these positions at the start of a round.*/
// operations constant
OP_CRANKED_RESET_TIME = 1000; // in ms
main()
{
if(getdvar("mapname") == "mp_background")
return;
maps\mp\gametypes\_globallogic::init();
maps\mp\gametypes\_callbacksetup::SetupCallbacks();
maps\mp\gametypes\_globallogic::SetupCallbacks();
if ( isUsingMatchRulesData() )
{
level.initializeMatchRules = ::initializeMatchRules;
[[level.initializeMatchRules]]();
level thread reInitializeMatchRulesOnMigration();
}
else
{
registerRoundSwitchDvar( level.gameType, 0, 0, 9 );
registerTimeLimitDvar( level.gameType, 10 );
registerScoreLimitDvar( level.gameType, 100 );
registerRoundLimitDvar( level.gameType, 1 );
registerWinLimitDvar( level.gameType, 1 );
registerNumLivesDvar( level.gameType, 0 );
registerHalfTimeDvar( level.gameType, 0 );
level.matchRules_damageMultiplier = 0;
level.matchRules_vampirism = 0;
}
level.teamBased = ( GetDvarInt( "scr_cranked_teambased", 1 ) == 1 );
level.onStartGameType = ::onStartGameType;
level.getSpawnPoint = ::getSpawnPoint;
level.onNormalDeath = ::onNormalDeath;
level.onSuicideDeath = ::onSuicideDeath;
level.onTeamChangeDeath = ::onTeamChangeDeath;
if( !level.teamBased )
{
level.onPlayerScore = ::onPlayerScore;
SetDvar( "scr_cranked_scorelimit", GetDvarInt( "scr_cranked_scorelimit_ffa", 60 ) );
SetTeamMode( "ffa" );
}
if ( level.matchRules_damageMultiplier || level.matchRules_vampirism )
level.modifyPlayerDamage = maps\mp\gametypes\_damage::gamemodeModifyPlayerDamage;
game["dialog"]["gametype"] = "cranked";
if ( getDvarInt( "g_hardcore" ) )
game["dialog"]["gametype"] = "hc_" + game["dialog"]["gametype"];
else if ( getDvarInt( "camera_thirdPerson" ) )
game["dialog"]["gametype"] = "thirdp_" + game["dialog"]["gametype"];
else if ( getDvarInt( "scr_diehard" ) )
game["dialog"]["gametype"] = "dh_" + game["dialog"]["gametype"];
else if (getDvarInt( "scr_" + level.gameType + "_promode" ) )
game["dialog"]["gametype"] = game["dialog"]["gametype"] + "_pro";
game["dialog"]["offense_obj"] = "crnk_hint";
game["dialog"]["begin_cranked"] = "crnk_cranked";
game["dialog"]["five_seconds_left"] = "crnk_det";
game["strings"]["overtime_hint"] = &"MP_FIRST_BLOOD";
level thread onPlayerConnect();
}
onPlayerConnect()
{
while( true )
{
level waittill( "connected", player );
player thread onPlayerSpawned();
}
}
onPlayerSpawned()
{
self endon( "disconnect" );
while( true )
{
self waittill( "spawned_player" );
}
}
initializeMatchRules()
{
// set common values
setCommonRulesFromMatchRulesData();
// set everything else (private match options, default .cfg file values, and what normally is registered in the 'else' below)
SetDynamicDvar( "scr_cranked_roundswitch", 0 );
registerRoundSwitchDvar( "cranked", 0, 0, 9 );
SetDynamicDvar( "scr_cranked_roundlimit", 1 );
registerRoundLimitDvar( "cranked", 1 );
SetDynamicDvar( "scr_cranked_winlimit", 1 );
registerWinLimitDvar( "cranked", 1 );
SetDynamicDvar( "scr_cranked_halftime", 0 );
registerHalfTimeDvar( "cranked", 0 );
SetDynamicDvar( "scr_cranked_promode", 0 );
}
onStartGameType()
{
setClientNameMode("auto_change");
if ( !isdefined( game["switchedsides"] ) )
game["switchedsides"] = false;
if ( game["switchedsides"] )
{
oldAttackers = game["attackers"];
oldDefenders = game["defenders"];
game["attackers"] = oldDefenders;
game["defenders"] = oldAttackers;
}
obj_text = &"OBJECTIVES_WAR";
obj_score_text = &"OBJECTIVES_WAR_SCORE";
obj_hint_text = &"OBJECTIVES_WAR_HINT";
if( !level.teamBased )
{
obj_text = &"OBJECTIVES_DM";
obj_score_text = &"OBJECTIVES_DM_SCORE";
obj_hint_text = &"OBJECTIVES_DM_HINT";
}
setObjectiveText( "allies", obj_text );
setObjectiveText( "axis", obj_text );
if ( level.splitscreen )
{
setObjectiveScoreText( "allies", obj_text );
setObjectiveScoreText( "axis", obj_text );
}
else
{
setObjectiveScoreText( "allies", obj_score_text );
setObjectiveScoreText( "axis", obj_score_text );
}
setObjectiveHintText( "allies", obj_hint_text );
setObjectiveHintText( "axis", obj_hint_text );
initSpawns();
cranked();
allowed[0] = level.gameType;
maps\mp\gametypes\_gameobjects::main( allowed );
}
initSpawns()
{
level.spawnMins = ( 0, 0, 0 );
level.spawnMaxs = ( 0, 0, 0 );
if( level.teamBased )
{
maps\mp\gametypes\_spawnlogic::addStartSpawnPoints( "mp_tdm_spawn_allies_start" );
maps\mp\gametypes\_spawnlogic::addStartSpawnPoints( "mp_tdm_spawn_axis_start" );
maps\mp\gametypes\_spawnlogic::addSpawnPoints( "allies", "mp_tdm_spawn" );
maps\mp\gametypes\_spawnlogic::addSpawnPoints( "axis", "mp_tdm_spawn" );
}
else
{
maps\mp\gametypes\_spawnlogic::addSpawnPoints( "allies", "mp_dm_spawn" );
maps\mp\gametypes\_spawnlogic::addSpawnPoints( "axis", "mp_dm_spawn" );
}
level.mapCenter = maps\mp\gametypes\_spawnlogic::findBoxCenter( level.spawnMins, level.spawnMaxs );
setMapCenter( level.mapCenter );
}
getSpawnPoint()
{
if( level.teamBased )
{
spawnteam = self.pers["team"];
if ( game["switchedsides"] )
spawnteam = getOtherTeam( spawnteam );
if ( maps\mp\gametypes\_spawnlogic::shouldUseTeamStartSpawn() )
{
spawnPoints = maps\mp\gametypes\_spawnlogic::getSpawnpointArray( "mp_tdm_spawn_" + spawnteam + "_start" );
spawnPoint = maps\mp\gametypes\_spawnlogic::getSpawnpoint_startSpawn( spawnPoints );
}
else
{
spawnPoints = maps\mp\gametypes\_spawnlogic::getTeamSpawnPoints( spawnteam );
spawnPoint = maps\mp\gametypes\_spawnscoring::getSpawnpoint_NearTeam( spawnPoints );
}
}
else
{
spawnPoints = maps\mp\gametypes\_spawnlogic::getTeamSpawnPoints( self.team );
if( level.inGracePeriod )
{
spawnPoint = maps\mp\gametypes\_spawnlogic::getSpawnpoint_Random( spawnPoints );
}
else
{
spawnPoint = maps\mp\gametypes\_spawnscoring::getSpawnpoint_FreeForAll( spawnPoints );
}
}
return spawnPoint;
}
onNormalDeath( victim, attacker, lifeId )
{
// OP_IW6 Cranky: kill X cranked enemies
if ( IsDefined( victim.cranked )
&& attacker isEnemy( victim ) )
{
attacker maps\mp\gametypes\_missions::processChallenge( "ch_cranky" );
}
victim cleanupCrankedTimer();
score = maps\mp\gametypes\_rank::getScoreInfoValue( "score_increment" );
assert( isDefined( score ) );
if( IsDefined( attacker.cranked ) )
{
// OP_IW6 Cranked Reset - kill an enemy with 1 second left on your cranked timer
if ( attacker.cranked_end_time - GetTime() <= OP_CRANKED_RESET_TIME )
{
attacker maps\mp\gametypes\_missions::processChallenge( "ch_cranked_reset" );
}
score *= 2;
event = "kill_cranked";
attacker thread onKill( event );
attacker.pers["killChains"]++;
attacker maps\mp\gametypes\_persistence::statSetChild( "round", "killChains", attacker.pers["killChains"] );
}
else
{
// make sure they alive, they could get getting kills from something while they are dead and it will give them the bomb but not the perks
// this was repro'd by using a switchblade cluster, use it, kill self, kill enemy
if( isReallyAlive( attacker ) )
attacker makeCranked( "begin_cranked" );
}
// give half time back on assists while cranked
if( IsDefined( victim.attackers ) && !IsDefined( level.assists_disabled ) )
{
foreach( player in victim.attackers )
{
if( !IsDefined( _validateAttacker( player ) ) )
continue;
if( player == attacker )
continue;
// don't let the victim get an assist off of themselves
if( victim == player )
continue;
if( !IsDefined( player.cranked ) )
continue;
player thread onAssist( "assist_cranked" );
}
}
if( level.teamBased )
{
level maps\mp\gametypes\_gamescore::giveTeamScoreForObjective( attacker.pers["team"], score );
if ( game["state"] == "postgame" && game["teamScores"][attacker.team] > game["teamScores"][level.otherTeam[attacker.team]] )
attacker.finalKill = true;
}
else
{
// get the highest score
highestScore = 0;
foreach( player in level.players )
{
if( IsDefined( player.score ) && player.score > highestScore )
highestScore = player.score;
}
if ( game["state"] == "postgame" && attacker.score >= highestScore )
attacker.finalKill = true;
}
}
onSuicideDeath( victim )
{
victim cleanupCrankedTimer();
}
onTeamChangeDeath( victim )
{
victim cleanupCrankedTimer();
}
cleanupCrankedTimer() // self == player
{
self SetClientOmnvar( "ui_cranked_bomb_timer_end_milliseconds", 0 );
self.cranked = undefined;
self.cranked_end_time = undefined;
}
onTimeLimit()
{
level.finalKillCam_winner = "none";
if ( game["status"] == "overtime" )
{
winner = "forfeit";
}
else if ( game["teamScores"]["allies"] == game["teamScores"]["axis"] )
{
winner = "overtime";
}
else if ( game["teamScores"]["axis"] > game["teamScores"]["allies"] )
{
level.finalKillCam_winner = "axis";
winner = "axis";
}
else
{
level.finalKillCam_winner = "allies";
winner = "allies";
}
thread maps\mp\gametypes\_gamelogic::endGame( winner, game[ "end_reason" ][ "time_limit_reached" ] );
}
onPlayerScore( event, player, victim )
{
if( event == "kill" )
{
score = maps\mp\gametypes\_rank::getScoreInfoValue( "score_increment" );
assert( isDefined( score ) );
if( IsDefined( player.cranked ) )
{
score *= 2;
}
return score;
}
return 0;
}
cranked()
{
level.crankedBombTimer = 30;
/#
SetDevDvarIfUninitialized( "scr_cranked_bomb_timer", level.crankedBombTimer );
#/
}
makeCranked( event ) // self == attacker
{
self leaderDialogOnPlayer( event );
self thread maps\mp\gametypes\_rank::xpEventPopup( event );
self setCrankedBombTimer( "kill" );
self.cranked = true;
// give a little pick me up
// reloading == specialty_fastreload
self givePerk( "specialty_fastreload", false );
// ads'ing == specialty_quickdraw
self givePerk( "specialty_quickdraw", false );
// throwing grenades == specialty_fastoffhand
self givePerk( "specialty_fastoffhand", false );
// sprint recovery == specialty_fastsprintrecovery
self givePerk( "specialty_fastsprintrecovery", false );
// endless sprint == specialty_marathon
self givePerk( "specialty_marathon", false );
// switching weapons == specialty_quickswap
self givePerk( "specialty_quickswap", false );
// ads strafe == specialty_stalker
self givePerk( "specialty_stalker", false );
self.moveSpeedScaler = 1.2;
self maps\mp\gametypes\_weapons::updateMoveSpeedScale();
}
onKill( event ) // self == player
{
level endon( "game_ended" );
self endon( "disconnect" );
while ( !isDefined( self.pers ) )
wait( 0.05 );
self thread maps\mp\gametypes\_rank::xpEventPopup( event );
maps\mp\gametypes\_gamescore::givePlayerScore( event, self, undefined, true );
self thread maps\mp\gametypes\_rank::giveRankXP( event );
self setCrankedBombTimer( "kill" );
}
onAssist( event ) // self == player
{
level endon( "game_ended" );
self endon( "disconnect" );
self thread maps\mp\gametypes\_rank::xpEventPopup( event );
self setCrankedBombTimer( "assist" );
}
watchBombTimer( waitTime ) // self == player
{
self notify( "watchBombTimer" );
self endon( "watchBombTimer" );
self endon( "death" );
self endon( "disconnect" );
level endon( "game_ended" );
// when time expires, blow them up
countdown_time = 5;
maps\mp\gametypes\_hostmigration::waitLongDurationWithGameEndTimeUpdate( waitTime - countdown_time - 1 );
self leaderDialogOnPlayer( "five_seconds_left" );
maps\mp\gametypes\_hostmigration::waitLongDurationWithGameEndTimeUpdate( 1.0 );
// 5 seconds left
self SetClientOmnvar( "ui_cranked_bomb_timer_final_seconds", 1 );
while( countdown_time > 0 )
{
self PlaySoundToPlayer( "mp_cranked_countdown", self );
maps\mp\gametypes\_hostmigration::waitLongDurationWithGameEndTimeUpdate( 1.0 );
countdown_time--;
}
if( IsDefined( self ) && isReallyAlive( self ) )
{
self PlaySound( "grenade_explode_metal" );
PlayFX( level.mine_explode, self.origin + ( 0, 0, 32 ) );
self _suicide();
self SetClientOmnvar( "ui_cranked_bomb_timer_end_milliseconds", 0 );
}
}
setCrankedBombTimer( type ) // self == player
{
waitTime = level.crankedBombTimer;
// for assists add half of the time back onto their current time
if( type == "assist" )
waitTime = int( min( ( ( self.cranked_end_time - GetTime() ) / 1000 ) + ( level.crankedBombTimer * 0.5 ), level.crankedBombTimer ) );
/#
waitTime = GetDvarInt( "scr_cranked_bomb_timer" );
#/
endTime = ( waitTime * 1000 ) + GetTime();
self SetClientOmnvar( "ui_cranked_bomb_timer_end_milliseconds", endTime );
self.cranked_end_time = endTime;
self thread watchCrankedHostMigration();
self thread watchBombTimer( waitTime );
self thread watchEndGame();
}
watchCrankedHostMigration()
{
self notify( "watchCrankedHostMigration" );
self endon( "watchCrankedHostMigration" );
level endon( "game_ended" );
self endon( "death" );
self endon( "disconnect" );
level waittill( "host_migration_begin" );
timePassed = maps\mp\gametypes\_hostmigration::waitTillHostMigrationDone();
if ( self.cranked_end_time + timePassed < 5 )
{
self SetClientOmnvar( "ui_cranked_bomb_timer_final_seconds", 1 );
}
if ( timePassed > 0 )
{
self SetClientOmnvar( "ui_cranked_bomb_timer_end_milliseconds", self.cranked_end_time + timePassed );
}
else
{
self SetClientOmnvar( "ui_cranked_bomb_timer_end_milliseconds", self.cranked_end_time );
}
}
watchEndGame() // self == player
{
self notify( "watchEndGame" );
self endon( "watchEndGame" );
self endon( "death" );
self endon( "disconnect" );
// this will keep the timer from showing up in the final killcam
while( true )
{
if( game[ "state" ] == "postgame" || level.gameEnded )
{
self SetClientOmnvar( "ui_cranked_bomb_timer_end_milliseconds", 0 );
break;
}
wait( 0.1 );
}
}

181
maps/mp/gametypes/dm.gsc Normal file
View File

@ -0,0 +1,181 @@
#include maps\mp\_utility;
#include maps\mp\gametypes\_hud_util;
/*
Deathmatch
Objective: Score points by eliminating other players
Map ends: When one player reaches the score limit, or time limit is reached
Respawning: No wait / Away from other players
Level requirements
------------------
Spawnpoints:
classname mp_dm_spawn
All players spawn from these. The spawnpoint chosen is dependent on the current locations of enemies at the time of spawn.
Players generally spawn away from enemies.
Spectator Spawnpoints:
classname mp_global_intermission
Spectators spawn from these and intermission is viewed from these positions.
Atleast one is required, any more and they are randomly chosen between.
*/
/*QUAKED mp_dm_spawn (1.0 0.5 0.0) (-16 -16 0) (16 16 72)
Players spawn away from enemies at one of these positions.*/
main()
{
maps\mp\gametypes\_globallogic::init();
maps\mp\gametypes\_callbacksetup::SetupCallbacks();
maps\mp\gametypes\_globallogic::SetupCallbacks();
if ( isUsingMatchRulesData() )
{
level.initializeMatchRules = ::initializeMatchRules;
[[level.initializeMatchRules]]();
level thread reInitializeMatchRulesOnMigration();
}
else
{
registerTimeLimitDvar( level.gameType, 10 );
registerScoreLimitDvar( level.gameType, 30 );
registerWinLimitDvar( level.gameType, 1 );
registerRoundLimitDvar( level.gameType, 1 );
registerNumLivesDvar( level.gameType, 0 );
registerHalfTimeDvar( level.gameType, 0 );
level.matchRules_damageMultiplier = 0;
level.matchRules_vampirism = 0;
}
level.onStartGameType = ::onStartGameType;
level.getSpawnPoint = ::getSpawnPoint;
level.onSpawnPlayer = ::onSpawnPlayer;
level.onNormalDeath = ::onNormalDeath;
level.onPlayerScore = ::onPlayerScore;
level.assists_disabled = true;
if ( level.matchRules_damageMultiplier || level.matchRules_vampirism )
level.modifyPlayerDamage = maps\mp\gametypes\_damage::gamemodeModifyPlayerDamage;
SetTeamMode( "ffa" );
game["dialog"]["gametype"] = "freeforall";
if ( getDvarInt( "g_hardcore" ) )
game["dialog"]["gametype"] = "hc_" + game["dialog"]["gametype"];
else if ( getDvarInt( "camera_thirdPerson" ) )
game["dialog"]["gametype"] = "thirdp_" + game["dialog"]["gametype"];
else if ( getDvarInt( "scr_diehard" ) )
game["dialog"]["gametype"] = "dh_" + game["dialog"]["gametype"];
else if (getDvarInt( "scr_" + level.gameType + "_promode" ) )
game["dialog"]["gametype"] = game["dialog"]["gametype"] + "_pro";
}
initializeMatchRules()
{
// set common values
setCommonRulesFromMatchRulesData( true );
// set everything else (private match options, default .cfg file values, and what normally is registered in the 'else' below)
SetDynamicDvar( "scr_dm_winlimit", 1 );
registerWinLimitDvar( "dm", 1 );
SetDynamicDvar( "scr_dm_roundlimit", 1 );
registerRoundLimitDvar( "dm", 1 );
SetDynamicDvar( "scr_dm_halftime", 0 );
registerHalfTimeDvar( "dm", 0 );
}
onStartGameType()
{
setClientNameMode("auto_change");
setObjectiveText( "allies", &"OBJECTIVES_DM" );
setObjectiveText( "axis", &"OBJECTIVES_DM" );
if ( level.splitscreen )
{
setObjectiveScoreText( "allies", &"OBJECTIVES_DM" );
setObjectiveScoreText( "axis", &"OBJECTIVES_DM" );
}
else
{
setObjectiveScoreText( "allies", &"OBJECTIVES_DM_SCORE" );
setObjectiveScoreText( "axis", &"OBJECTIVES_DM_SCORE" );
}
setObjectiveHintText( "allies", &"OBJECTIVES_DM_HINT" );
setObjectiveHintText( "axis", &"OBJECTIVES_DM_HINT" );
level.spawnMins = ( 0, 0, 0 );
level.spawnMaxs = ( 0, 0, 0 );
maps\mp\gametypes\_spawnlogic::addSpawnPoints( "allies", "mp_dm_spawn" );
maps\mp\gametypes\_spawnlogic::addSpawnPoints( "axis", "mp_dm_spawn" );
level.mapCenter = maps\mp\gametypes\_spawnlogic::findBoxCenter( level.spawnMins, level.spawnMaxs );
setMapCenter( level.mapCenter );
allowed[0] = "dm";
maps\mp\gametypes\_gameobjects::main(allowed);
level.QuickMessageToAll = true;
}
getSpawnPoint()
{
spawnPoints = maps\mp\gametypes\_spawnlogic::getTeamSpawnPoints( self.team );
if( level.inGracePeriod )
{
spawnPoint = maps\mp\gametypes\_spawnscoring::getStartSpawnpoint_FreeForAll( spawnPoints );
}
else
{
spawnPoint = maps\mp\gametypes\_spawnscoring::getSpawnpoint_FreeForAll( spawnPoints );
}
return spawnPoint;
}
onSpawnPlayer()
{
level notify ( "spawned_player" );
// Keep track of what the "kill" value
// This value will be used to calculate the score in the front end match summary
if ( !isDefined( self.eventValue ) )
{
self.eventValue = maps\mp\gametypes\_rank::getScoreInfoValue( "kill" );
self setExtraScore0( self.eventValue );
}
}
onNormalDeath( victim, attacker, lifeId )
{
// get the highest score
highestScore = 0;
foreach( player in level.players )
{
if( IsDefined( player.score ) && player.score > highestScore )
highestScore = player.score;
}
if ( game["state"] == "postgame" && attacker.score >= highestScore )
attacker.finalKill = true;
}
onPlayerScore( event, player, victim )
{
player.assists = player getPersStat( "longestStreak" );
if( event == "kill" )
{
score = maps\mp\gametypes\_rank::getScoreInfoValue( "score_increment" );
assert( isDefined( score ) );
return score;
}
return 0;
}

1255
maps/mp/gametypes/dom.gsc Normal file

File diff suppressed because it is too large Load Diff

586
maps/mp/gametypes/grind.gsc Normal file
View File

@ -0,0 +1,586 @@
#include maps\mp\_utility;
#include common_scripts\utility;
#include maps\mp\gametypes\_hud_util;
main()
{
maps\mp\gametypes\_globallogic::init();
maps\mp\gametypes\_callbacksetup::SetupCallbacks();
maps\mp\gametypes\_globallogic::SetupCallbacks();
if ( isUsingMatchRulesData() )
{
level.initializeMatchRules = ::initializeMatchRules;
[[level.initializeMatchRules]]();
level thread reInitializeMatchRulesOnMigration();
}
else
{
registerRoundSwitchDvar( level.gameType, 0, 0, 9 );
registerTimeLimitDvar( level.gameType, 10 );
registerScoreLimitDvar( level.gameType, 500 );
registerRoundLimitDvar( level.gameType, 1 );
registerWinLimitDvar( level.gameType, 1 );
registerNumLivesDvar( level.gameType, 0 );
registerHalfTimeDvar( level.gameType, 0 );
}
level.teamBased = true;
level.onStartGameType = ::onStartGameType;
level.getSpawnPoint = ::getSpawnPoint;
level.onNormalDeath = ::onNormalDeath;
level.onPrecacheGameType = ::onPrecacheGameType;
level.onSpawnPlayer = ::onSpawnPlayer;
}
onPrecacheGameType()
{
level.flagBaseFXid[ "friendly" ] = LoadFx( "vfx/gameplay/mp/core/vfx_marker_base_cyan" );
}
initializeMatchRules()
{
// set common values
setCommonRulesFromMatchRulesData();
SetDynamicDvar( "scr_grind_roundswitch", 0 );
registerRoundSwitchDvar( "grind", 0, 0, 9 );
SetDynamicDvar( "scr_grind_roundlimit", 1 );
registerRoundLimitDvar( "grind", 1 );
SetDynamicDvar( "scr_grind_winlimit", 1 );
registerWinLimitDvar( "grind", 1 );
SetDynamicDvar( "scr_grind_halftime", 0 );
registerHalfTimeDvar( "grind", 0 );
SetDynamicDvar( "scr_grind_promode", 0 );
}
onStartGameType()
{
setClientNameMode("auto_change");
if ( !isdefined( game["switchedsides"] ) )
game["switchedsides"] = false;
setObjectiveText( "allies", &"OBJECTIVES_WAR" );
setObjectiveText( "axis", &"OBJECTIVES_WAR" );
if ( level.splitscreen )
{
setObjectiveScoreText( "allies", &"OBJECTIVES_WAR" );
setObjectiveScoreText( "axis", &"OBJECTIVES_WAR" );
}
else
{
setObjectiveScoreText( "allies", &"OBJECTIVES_WAR_SCORE" );
setObjectiveScoreText( "axis", &"OBJECTIVES_WAR_SCORE" );
}
setObjectiveHintText( "allies", &"OBJECTIVES_WAR_HINT" );
setObjectiveHintText( "axis", &"OBJECTIVES_WAR_HINT" );
initSpawns();
createTags();
allowed[0] = level.gameType;
maps\mp\gametypes\_gameobjects::main( allowed );
createZones();
level thread onPlayerConnect();
level thread runZones();
level thread removeTagsOnGameEnded();
}
onSpawnPlayer()
{
if ( IsDefined( self.tagsCarried ) )
self SetClientOmnvar( "ui_grind_tags", self.tagsCarried );
}
createTags()
{
level.dogtags = [];
for( i = 0; i < 50; i++ )
{
visual = spawn( "script_model", (0,0,0) );
visual setModel( "prop_dogtags_foe_iw6" );
visual.baseOrigin = visual.origin;
visual ScriptModelPlayAnim( "mp_dogtag_spin" );
visual hide();
trigger = spawn( "trigger_radius", (0,0,0), 0, 32, 32 );
trigger.targetname = "trigger_dogtag";
trigger Hide();
newTag = spawnStruct();
newTag.type = "useObject";
newTag.curOrigin = trigger.origin;
newTag.entNum = trigger getEntityNumber();
newTag.lastUsedTime = 0;
newTag.visual = visual;
newTag.offset3d = (0,0,16);
newTag.trigger = trigger;
newTag.triggerType = "proximity";
newTag maps\mp\gametypes\_gameobjects::allowUse( "none" );
level.dogtags[level.dogtags.size] = newTag;
}
}
getTag()
{
bestTag = level.dogtags[0];
oldestTime = GetTime();
foreach( tag in level.dogtags )
{
if( tag.interactTeam == "none" )
{
bestTag = tag;
break;
}
if( tag.lastUsedTime < oldestTime )
{
oldestTime = tag.lastUsedTime;
bestTag = tag;
}
}
bestTag notify( "reset" );
bestTag maps\mp\gametypes\_gameobjects::initializeTagPathVariables();
bestTag.lastUsedTime = GetTime();
return bestTag;
}
spawnTag( dropLocation, bRabdom )
{
startPos = dropLocation + (0,0,14);
if( IsDefined(bRabdom) && bRabdom )
{
randomAngle = (0,RandomFloat(360),0);
randomDir = AnglesToForward(randomAngle);
randomDst = RandomFloatRange( 40, 300 );
testpos = startpos + (randomDst * randomDir);
startPos = PlayerPhysicsTrace( startPos, testpos );
}
newTag = getTag();
newTag.curOrigin = startPos;
newTag.trigger.origin = startPos;
newTag.visual.origin = startPos;
newTag.trigger show();
newTag.visual show();
newTag maps\mp\gametypes\_gameobjects::allowUse( "any" );
playSoundAtPos( startPos, "mp_grind_token_drop" );
return newTag;
}
monitorTagUse( tag )
{
level endon ( "game_ended" );
tag endon ( "deleted" );
tag endon( "reset" );
while ( true )
{
tag.trigger waittill ( "trigger", player );
if ( !isReallyAlive( player ) )
continue;
if ( player isUsingRemote() || isDefined( player.spawningAfterRemoteDeath ) )
continue;
if ( IsDefined( player.classname ) && player.classname == "script_vehicle" )
continue;
if( IsAgent(player) && IsDefined(player.owner) )
player = player.owner;
tag.visual hide();
tag.trigger hide();
tag.curOrigin = (0,0,1000);
tag.trigger.origin = (0,0,1000);
tag.visual.origin = (0,0,1000);
tag maps\mp\gametypes\_gameobjects::allowUse( "none" );
player thread maps\mp\gametypes\_rank::giveRankXP( "tag" );
player playerSetTagCount(player.tagsCarried+1);
player playSound( "mp_killconfirm_tags_pickup" );
playSoundAtPos( player.origin, "mp_grind_token_pickup" );
break;
}
}
onPlayerConnect()
{
while ( true )
{
level waittill( "connected", player );
player.isScoring = false;
player thread monitorJoinTeam();
}
}
playerSetTagCount(tagCount)
{
self.tagsCarried = tagCount;
self.game_extrainfo = tagCount;
if( tagCount > 999 )
tagCount = 999;
self SetClientOmnvar( "ui_grind_tags", tagCount );
}
monitorJoinTeam()
{
self endon("disconnect");
while(1)
{
self waittill_any( "joined_team", "joined_spectators" );
if ( level.inGracePeriod )
{
self playerSetTagCount(1);
}
else
{
self playerSetTagCount(0);
}
}
}
hideHudElementOnGameEnd( hudElement )
{
level waittill( "game_ended" );
if( isDefined( hudElement ) )
hudElement.alpha = 0;
}
createZones()
{
level.zoneList = [];
game["flagmodels"] = [];
game["flagmodels"]["neutral"] = "prop_flag_neutral";
game["flagmodels"]["allies"] = maps\mp\gametypes\_teams::getTeamFlagModel( "allies" );
game["flagmodels"]["axis"] = maps\mp\gametypes\_teams::getTeamFlagModel( "axis" );
grindTriggers = getEntArray( "grind_location", "targetname" );
foreach( grindTrigger in grindTriggers )
{
level.zoneList[level.zoneList.size] = addZone( grindTrigger );
}
}
addZone( zoneTrigger )
{
AssertEx( IsDefined(zoneTrigger), "map needs grind game objects" );
zone = SpawnStruct();
zone.origin = zoneTrigger.origin;
zone.angles = zoneTrigger.angles;
zone.trigger = zoneTrigger;
zone.ownerTeam = "neutral";
traceStart = zone.origin + (0,0,32);
traceEnd = zone.origin + (0,0,-32);
trace = bulletTrace( traceStart, traceEnd, false, undefined );
zone.origin = trace["position"];
zone.upangles = vectorToAngles( trace["normal"] );
zone.forward = anglesToForward( zone.upangles );
zone.right = anglesToRight( zone.upangles );
zone.visuals[0] = spawn( "script_model", zone.origin );
zone.visuals[0].angles = zone.angles;
zone.visuals[0] SetModel( game["flagmodels"]["neutral"] );
return zone;
}
runZones()
{
foreach( zone in level.zoneList )
{
level thread startZone( zone, zone.trigger.script_label );
}
}
startZone( zone, hudIcon )
{
level thread runZoneFX( zone );
level thread runZoneStatus( zone, hudIcon );
level thread runZoneThink( zone );
}
runZoneFX( zone )
{
gameFlagWait( "prematch_done" );
zoneFX = spawnFx( level.flagBaseFXid[ "friendly" ], zone.origin, zone.forward, zone.upangles );
triggerFx( zoneFX );
}
runZoneStatus( zone, hudIcon )
{
offset = (0,0,100);
zone.objId_axis = maps\mp\gametypes\_gameobjects::getNextObjID();
objective_add( zone.objId_axis, "active", zone.origin + offset, "waypoint_target_" + hudIcon );
Objective_Team( zone.objId_axis, "axis" );
zone.objId_allies = maps\mp\gametypes\_gameobjects::getNextObjID();
objective_add( zone.objId_allies, "active", zone.origin + offset, "waypoint_target_" + hudIcon );
Objective_Team( zone.objId_allies, "allies" );
lastScoredTime = 0;
lastOwnerTeam = "none";
while( true )
{
ownerTeam = "neutral";
foreach( player in level.players )
{
if( !isReallyAlive(player) )
continue;
if( !player.tagsCarried )
continue;
if( player.team == ownerTeam )
{
continue;
}
if( isInZone( player, zone ) )
{
if( ownerTeam == "neutral" )
{
ownerTeam = player.team;
continue;
}
ownerTeam = "contested";
break;
}
}
zone.ownerTeam = ownerTeam;
// the zone status did not change this frame
if( lastOwnerTeam == ownerTeam )
{
waitframe();
continue;
}
switch(ownerTeam)
{
case "neutral":
if( (lastScoredTime + 1250) > GetTime() )
break;
lastOwnerTeam = ownerTeam;
zone.grind_headIcon_allies = zone maps\mp\_entityheadIcons::setHeadIcon( "allies", "waypoint_bank_" + hudIcon, offset, 4, 4, undefined, undefined, undefined, true, undefined, false );
zone.grind_headIcon_axis = zone maps\mp\_entityheadIcons::setHeadIcon( "axis", "waypoint_bank_" + hudIcon, offset, 4, 4, undefined, undefined, undefined, true, undefined, false );
Objective_Icon( zone.objId_allies, "waypoint_bank_" + hudIcon );
Objective_Icon( zone.objId_axis, "waypoint_bank_" + hudIcon );
break;
case "contested":
lastOwnerTeam = ownerTeam;
zone.grind_headIcon_allies = zone maps\mp\_entityheadIcons::setHeadIcon( "allies", "waypoint_contested_" + hudIcon, offset, 4, 4, undefined, undefined, undefined, true, undefined, false );
zone.grind_headIcon_axis = zone maps\mp\_entityheadIcons::setHeadIcon( "axis", "waypoint_contested_" + hudIcon, offset, 4, 4, undefined, undefined, undefined, true, undefined, false );
Objective_Icon( zone.objId_allies, "waypoint_contested_" + hudIcon );
Objective_Icon( zone.objId_axis, "waypoint_contested_" + hudIcon );
break;
case "axis":
lastOwnerTeam = ownerTeam;
zone.grind_headIcon_allies = zone maps\mp\_entityheadIcons::setHeadIcon( "allies", "waypoint_scoring_foe_" + hudIcon, offset, 4, 4, undefined, undefined, undefined, true, undefined, false );
zone.grind_headIcon_axis = zone maps\mp\_entityheadIcons::setHeadIcon( "axis", "waypoint_scoring_friend_" + hudIcon, offset, 4, 4, undefined, undefined, undefined, true, undefined, false );
Objective_Icon( zone.objId_allies, "waypoint_scoring_foe_" + hudIcon );
Objective_Icon( zone.objId_axis, "waypoint_scoring_friend_" + hudIcon );
lastScoredTime = GetTime();
break;
case "allies":
lastOwnerTeam = ownerTeam;
zone.grind_headIcon_allies = zone maps\mp\_entityheadIcons::setHeadIcon( "allies", "waypoint_scoring_friend_" + hudIcon, offset, 4, 4, undefined, undefined, undefined, true, undefined, false );
zone.grind_headIcon_axis = zone maps\mp\_entityheadIcons::setHeadIcon( "axis", "waypoint_scoring_foe_" + hudIcon, offset, 4, 4, undefined, undefined, undefined, true, undefined, false );
Objective_Icon( zone.objId_allies, "waypoint_scoring_friend_" + hudIcon );
Objective_Icon( zone.objId_axis, "waypoint_scoring_foe_" + hudIcon );
lastScoredTime = GetTime();
break;
}
waitframe();
}
}
isInZone( player, zone )
{
if( isReallyAlive(player) && (player IsTouching(zone.trigger)) )
{
return true;
}
return false;
}
runZoneThink( zone )
{
level endon( "game_ended" );
while( true )
{
zone.trigger waittill( "trigger", player );
if( IsAgent(player) )
continue;
if( !IsPlayer(player) )
continue;
if( player.isScoring )
continue;
player.isScoring = true;
level thread processScoring( player, zone );
}
}
removeTagsOnGameEnded()
{
level waittill( "game_ended" );
foreach( player in level.players )
{
if ( !isDefined (player) )
continue;
if ( !isDefined (player.tagsCarried) )
continue;
player.tagsCarried = 0;
}
}
processScoring( player, zone )
{
while( player.tagsCarried && isInZone(player, zone) )
{
player PlaySoundToPlayer( "mp_grind_token_banked", player );
player playerSetTagCount(player.tagsCarried-1);
maps\mp\gametypes\_gamescore::giveTeamScoreForObjective( player.team, 1 );
player setExtraScore0( player.extrascore0 + 1 );
maps\mp\gametypes\_gamescore::givePlayerScore( "tagScore", player );
// call the function directly instead of leaning on the objective monitor notify system we were using before
player maps\mp\_events::giveObjectivePointStreaks();
// OP_IW6 Grinder - Score X points in Grind
player maps\mp\gametypes\_missions::processChallenge( "ch_grinder" );
wait(2);
}
player.isScoring = false;
}
initSpawns()
{
level.spawnMins = ( 0, 0, 0 );
level.spawnMaxs = ( 0, 0, 0 );
maps\mp\gametypes\_spawnlogic::addStartSpawnPoints( "mp_tdm_spawn_allies_start" );
maps\mp\gametypes\_spawnlogic::addStartSpawnPoints( "mp_tdm_spawn_axis_start" );
maps\mp\gametypes\_spawnlogic::addSpawnPoints( "allies", "mp_tdm_spawn" );
maps\mp\gametypes\_spawnlogic::addSpawnPoints( "axis", "mp_tdm_spawn" );
level.mapCenter = maps\mp\gametypes\_spawnlogic::findBoxCenter( level.spawnMins, level.spawnMaxs );
setMapCenter( level.mapCenter );
}
getSpawnPoint()
{
spawnteam = self.pers["team"];
if ( game["switchedsides"] )
spawnteam = getOtherTeam( spawnteam );
if ( maps\mp\gametypes\_spawnlogic::shouldUseTeamStartSpawn() )
{
spawnPoints = maps\mp\gametypes\_spawnlogic::getSpawnpointArray( "mp_tdm_spawn_" + spawnteam + "_start" );
spawnPoint = maps\mp\gametypes\_spawnlogic::getSpawnpoint_startSpawn( spawnPoints );
}
else
{
spawnPoints = maps\mp\gametypes\_spawnlogic::getTeamSpawnPoints( spawnteam );
spawnPoint = maps\mp\gametypes\_spawnscoring::getSpawnpoint_NearTeam( spawnPoints );
}
return spawnPoint;
}
onNormalDeath( victim, attacker, lifeId )
{
level thread dropTags( victim, attacker );
if ( game["state"] == "postgame" && game["teamScores"][attacker.team] > game["teamScores"][level.otherTeam[attacker.team]] )
attacker.finalKill = true;
}
dropTags( victim, attacker )
{
if( IsAgent(victim) )
return;
dropNumber = 1;
radomDropLocation = false;
counter = 0;
while( counter < dropNumber )
{
if( counter > 0 )
radomDropLocation = true;
newTag = spawnTag( victim.origin, radomDropLocation );
newTag.victim = victim;
newTag.attacker = attacker;
level notify( "new_tag_spawned", newTag );
level thread monitorTagUse( newTag );
counter++;
}
playSoundAtPos( victim.origin, "mp_killconfirm_tags_drop" );
newTagCount = victim.tagsCarried - dropNumber;
newTagCount = int( max( 0, newTagCount ) );
victim playerSetTagCount(newTagCount);
}

961
maps/mp/gametypes/grnd.gsc Normal file
View File

@ -0,0 +1,961 @@
#include common_scripts\utility;
#include maps\mp\_utility;
#include maps\mp\gametypes\_hud_util;
/*
Drop Zone
Objective: Score points for your team over time by holding the drop zone.
Periodic carepackage awarded to player who's been in drop zone the longest.
Map ends: When one team reaches the score limit, or time limit is reached
Respawning: No wait / Near teammates / Near drop zone
Level requirementss
------------------
Start Spawnpoints:
classname mp_sd_spawn_defender, mp_sd_spawn_attacker
Spawnpoints:
classname mp_tdm_spawn
All players spawn from these. The spawnpoint chosen is dependent on the current locations of drop zone, teammates, and enemies
at the time of spawn. Players generally spawn behind their teammates relative to the direction of enemies.
Spectator Spawnpoints:
classname mp_global_intermission
Spectators spawn from these and intermission is viewed from these positions.
Atleast one is required, any more and they are randomly chosen between.
*/
GRND_ZONE_TOUCH_RADIUS = 300;
GRND_ZONE_DROP_RADIUS = 50;
main()
{
if(getdvar("mapname") == "mp_background")
return;
maps\mp\gametypes\_globallogic::init();
maps\mp\gametypes\_callbacksetup::SetupCallbacks();
maps\mp\gametypes\_globallogic::SetupCallbacks();
if ( isUsingMatchRulesData() )
{
level.initializeMatchRules = ::initializeMatchRules;
[[level.initializeMatchRules]]();
level thread reInitializeMatchRulesOnMigration();
}
else
{
registerRoundSwitchDvar( level.gameType, 0, 0, 9 );
registerTimeLimitDvar( level.gameType, 10 );
registerScoreLimitDvar( level.gameType, 7500 );
registerRoundLimitDvar( level.gameType, 1 );
registerWinLimitDvar( level.gameType, 1 );
registerNumLivesDvar( level.gameType, 0 );
registerHalfTimeDvar( level.gameType, 0 );
level.matchRules_dropTime = 15;
level.matchRules_zoneSwitchTime = 60;
level.matchRules_damageMultiplier = 0;
level.matchRules_vampirism = 0;
setDvar( "scr_game_hardpoints", 0 );
}
level.teamBased = true;
level.onStartGameType = ::onStartGameType;
level.getSpawnPoint = ::getSpawnPoint;
level.onSpawnPlayer = ::onSpawnPlayer;
if ( level.matchRules_damageMultiplier || level.matchRules_vampirism )
level.modifyPlayerDamage = maps\mp\gametypes\_damage::gamemodeModifyPlayerDamage;
level.grnd_fx["smoke"] = loadFx( "smoke/airdrop_flare_mp_effect_now" );
level.grnd_fx["flare"] = loadFx( "smoke/signal_smoke_airdrop" );
level.grnd_targetFXID = loadfx( "vfx/gameplay/mp/core/vfx_marker_base_cyan" );
level.dangerMaxRadius["drop_zone"] = 1200;
level.dangerMinRadius["drop_zone"] = 1190;
level.dangerForwardPush["drop_zone"]= 0;
level.dangerOvalScale["drop_zone"] = 1;
}
initializeMatchRules()
{
// set common values
setCommonRulesFromMatchRulesData();
// set everything else (private match options, default .cfg file values, and what normally is registered in the 'else' below)
level.matchRules_dropTime = GetMatchRulesData( "grndData", "dropTime" );
level.matchRules_zoneSwitchTime = 60 * GetMatchRulesData( "grndData", "zoneSwitchTime" );
if( level.matchRules_zoneSwitchTime < 60 )
level.matchRules_zoneSwitchTime = 60;
SetDynamicDvar( "scr_grnd_roundswitch", 0 );
registerRoundSwitchDvar( "grnd", 0, 0, 9 );
SetDynamicDvar( "scr_grnd_roundlimit", 1 );
registerRoundLimitDvar( "grnd", 1 );
SetDynamicDvar( "scr_grnd_winlimit", 1 );
registerWinLimitDvar( "grnd", 1 );
SetDynamicDvar( "scr_grnd_halftime", 0 );
registerHalfTimeDvar( "grnd", 0 );
SetDynamicDvar( "scr_grnd_promode", 0 );
}
onStartGameType()
{
setClientNameMode("auto_change");
if ( !isdefined( game["switchedsides"] ) )
game["switchedsides"] = false;
setObjectiveText( "allies", &"OBJECTIVES_GRND" );
setObjectiveText( "axis", &"OBJECTIVES_GRND" );
if ( level.splitscreen )
{
setObjectiveScoreText( "allies", &"OBJECTIVES_GRND" );
setObjectiveScoreText( "axis", &"OBJECTIVES_GRND" );
}
else
{
setObjectiveScoreText( "allies", &"OBJECTIVES_GRND_SCORE" );
setObjectiveScoreText( "axis", &"OBJECTIVES_GRND_SCORE" );
}
setObjectiveHintText( "allies", &"OBJECTIVES_DOM_HINT" );
setObjectiveHintText( "axis", &"OBJECTIVES_DOM_HINT" );
level.spawnMins = ( 0, 0, 0 );
level.spawnMaxs = ( 0, 0, 0 );
maps\mp\gametypes\_spawnlogic::addStartSpawnPoints( "mp_tdm_spawn_allies_start" );
maps\mp\gametypes\_spawnlogic::addStartSpawnPoints( "mp_tdm_spawn_axis_start" );
maps\mp\gametypes\_spawnlogic::addSpawnPoints( "allies", "mp_tdm_spawn" );
maps\mp\gametypes\_spawnlogic::addSpawnPoints( "axis", "mp_tdm_spawn" );
level.mapCenter = maps\mp\gametypes\_spawnlogic::findBoxCenter( level.spawnMins, level.spawnMaxs );
setMapCenter( level.mapCenter );
// get the central loction "b" flag
domFlags = getEntArray( "flag_primary", "targetname" );
sortedDomFlags = SortByDistance( domFlags, level.mapCenter );
centerLocObj = sortedDomFlags[0];
//end new stuff
//level.grnd_centerLoc = centerLocObj.origin;
level.grnd_centerLoc = level.mapCenter;
maps\mp\gametypes\_rank::registerScoreInfo( "kill", 50 );
maps\mp\gametypes\_rank::registerScoreInfo( "zone_kill", 100 );
maps\mp\gametypes\_rank::registerScoreInfo( "zone_tick", 20 );
allowed[0] = level.gameType;
allowed[1] = "tdm";
maps\mp\gametypes\_gameobjects::main(allowed);
// timer
level.grnd_HUD["timerDisplay"] = createServerTimer( "objective", 1.4 );
level.grnd_HUD["timerDisplay"].label = &"MP_NEXT_DROP_ZONE_IN";
level.grnd_HUD["timerDisplay"] setPoint( "BOTTOMCENTER", "BOTTOMCENTER", 0, -28 );
level.grnd_HUD["timerDisplay"].alpha = 0;
level.grnd_HUD["timerDisplay"].archived = false;
level.grnd_HUD["timerDisplay"].hideWhenInMenu = true;
level.grnd_HUD["timerDisplay"].hideWhenInDemo = true;
thread hideHudElementOnGameEnd( level.grnd_HUD["timerDisplay"] );
createZones();
initZones();
initFirstZone();
}
initFirstZone()
{
level.zonesCycling = false;
level.firstZoneActive = false;
// find the closest zone to center
shortestDistance = 999999;
shortestDistanceIndex = 0;
//Adding specialcase for dlc map mp_shipment_ns
if( toLower( getDvar("mapname") ) == "mp_shipment_ns" )
{
initialPos = (1.60, 63, 192);
}
else
{
for ( i=0; i < level.grnd_zones.size; i++ )
{
dropZone = level.grnd_zones[i];
distToCenter = distance2d( level.grnd_centerLoc, dropZone.origin );
if ( distToCenter < shortestDistance )
{
shortestDistance = distToCenter;
shortestDistanceIndex = i;
}
}
//grnd_initialIndex is currently unused.
level.grnd_initialIndex = shortestDistanceIndex;
initialPos = level.grnd_zones[shortestDistanceIndex].origin;
}
level.grnd_initialPos = initialPos;
// create marker
level.grnd_zone = spawn( "script_model", initialPos );
level.grnd_zone.origin = initialPos;
level.grnd_zone.angles = ( 90, 0, 0 );
level.grnd_zone setModel( "weapon_us_smoke_grenade_burnt2" );
// create effect entity
ringVfx = Spawn( "script_model", level.grnd_zone.origin );
ringVfx SetModel( "tag_origin" ); // tag_origin doesn't seem to work as a model with the effect
ringVfx.angles = VectorToAngles( (0, 0, 1) );
ringVfx LinkTo( level.grnd_zone );
level.grnd_zone.ringVfx = ringVfx;
// add drop zone target to danger zones so spawnlogic tries not to spawn too close to it
level.grnd_dangerCenter = spawnstruct();
level.grnd_dangerCenter.origin = initialPos;
level.grnd_dangerCenter.forward = anglesToForward( (0,0,0) );
level.grnd_dangerCenter.streakName = "drop_zone";
// spawning
level.favorCloseSpawnEnt = level.grnd_zone;
}
initZones()
{
level.grnd_zones = [];
//playing strikezone
if( GetDvar( "mapname" ) == "mp_strikezone" )
{
//zone one
if ( isDefined( level.teleport_zone_current ) && level.teleport_zone_current == "start" )
{
for ( i=0; i<level.grnd_dropZones1.size; i++ )
{
dropZone = level.grnd_dropZones1[i].origin;
level.grnd_zones[i] = spawn( "script_origin", dropZone );
level.grnd_zones[i].origin = dropZone;
wait( 0.05 );
}
}
else//zone two
{
for ( i=0; i<level.grnd_dropZones2.size; i++ )
{
dropZone = level.grnd_dropZones2[i].origin;
level.grnd_zones[i] = spawn( "script_origin", dropZone );
level.grnd_zones[i].origin = dropZone;
wait( 0.05 );
}
}
}
else
{
for ( i=0; i<level.grnd_dropZones.size; i++ )
{
dropZone = level.grnd_dropZones[i].origin;
level.grnd_zones[i] = spawn( "script_origin", dropZone );
level.grnd_zones[i].origin = dropZone;
wait( 0.05 );
}
}
}
getSpawnPoint()
{
spawnteam = self.pers["team"];
if ( game["switchedsides"] )
spawnteam = getOtherTeam( spawnteam );
if ( maps\mp\gametypes\_spawnlogic::shouldUseTeamStartSpawn() )
{
spawnPoints = maps\mp\gametypes\_spawnlogic::getSpawnpointArray( "mp_tdm_spawn_" + spawnteam + "_start" );
spawnPoint = maps\mp\gametypes\_spawnlogic::getSpawnpoint_startSpawn( spawnPoints );
}
else
{
spawnPoints = maps\mp\gametypes\_spawnlogic::getTeamSpawnPoints( spawnteam );
//this could be optimized to store on the level when the point changes.
closeSortedSpawnArray = SortByDistance( spawnPoints, level.favorCloseSpawnEnt.origin );
closestPoints = [];
//loop will continue to get points until they are 768 or further away as long as 6 have already been retreived.
for ( i = 0; i < closeSortedSpawnArray.size; i++ )
{
closestPoints[i] = closeSortedSpawnArray[i];
//level thread drawLine( level.favorCloseSpawnEnt.origin, closestPoints[i].origin+(0,0,60), 60, (0,0,1) );
if( distance_2d_squared( closestPoints[i].origin, level.favorCloseSpawnEnt.origin ) > (768*768) && i > 5 )
break;
}
spawnPoint = maps\mp\gametypes\_spawnscoring::getSpawnpoint_DZ( spawnPoints, closestPoints );
}
return spawnPoint;
}
onSpawnPlayer()
{
// in/out zone indicator
if ( !isDefined( self.inGrindZone ) )
{
if ( IsAgent(self) )
return;
level thread setPlayerMessages( self );
// let the first player in activate this
if ( !level.zonesCycling )
{
level.zonesCycling = true;
level thread cycleZones();
level thread locationStatus();
level thread locationScoring();
}
self thread waitReplaySmokeFxForNewPlayer();
}
level notify ( "spawned_player" );
}
waitReplaySmokeFxForNewPlayer()
{
level endon( "game_ended" );
self endon( "disconnect" );
gameFlagWait( "prematch_done" );
// let cycleZones() do it's initial work so we only catch people who are joining late
wait( 0.5 );
if ( !isDefined( self.grnd_fx_playing ) )
{
PlayFxOnTagForClients( level.grnd_fx["smoke"], level.grnd_zone, "tag_fx", self );
self.grnd_fx_playing = true;
}
}
createHudInfo( elemName, font, fontSize, xPos, yPos, text, color )
{
hudElem = createFontString( font, fontSize );
hudElem setText( text );
if ( level.splitscreen )
hudElem setPoint( "TOPLEFT", "TOPLEFT", (xPos-35), (yPos-5) );
else
hudElem setPoint( "TOPLEFT", "TOPLEFT", xPos, yPos );
hudElem.alpha = 1;
hudElem.color = color;
hudElem.glowColor = color;
hudElem.archived = false;
hudElem.hideWhenInMenu = true;
thread hideHudElementOnGameEnd( hudElem );
self.grnd_HUD[elemName] = hudElem;
}
setPlayerMessages( player )
{
level endon( "game_ended" );
gameFlagWait( "prematch_done" );
if( !IsDefined( player ) )
return;
// points
player.inGrindZonePoints = 0;
/* player team players in zone
elemName = player.team+"Score";
player createHudInfo( elemName, "small", 1.6, 115, 22, 0, (0.6,1.0,0.6) );
elemName = player.team+"Text";
player createHudInfo( elemName, "small", 1.6, 225, 22, maps\mp\gametypes\_teams::getTeamShortName( player.team ), (0.6,1.0,0.6) );
// enemy team players in zone
elemName = level.otherTeam[player.team]+"Score";
player createHudInfo( elemName, "small", 1.6, 115, 39, 0, (1.0,0.6,0.6) );
elemName = level.otherTeam[player.team]+"Text";
player createHudInfo( elemName, "small", 1.6, 225, 39, maps\mp\gametypes\_teams::getTeamShortName( level.otherTeam[player.team] ), (1.0,0.6,0.6) );
*/
// hud icon
player.grndHeadIcon = level.grnd_zone maps\mp\_entityheadIcons::setHeadIcon( player, "waypoint_captureneutral_b", (0,0,0), 14, 14, undefined, undefined, undefined, true, undefined, false );
// minimap waypoint
player.grndObjId = maps\mp\gametypes\_gameobjects::getNextObjID();
objective_add( player.grndObjId, "invisible", (0,0,0) );
objective_player( player.grndObjId, player getEntityNumber() );
Objective_OnEntity( player.grndObjId, level.grnd_zone );
objective_icon( player.grndObjId, "waypoint_captureneutral_b" );
objective_state( player.grndObjId, "active" );
if ( player isInGrindZone() )
{
player.inGrindZone = true;
player.grndHeadIcon.alpha = 0;
}
else
{
player.inGrindZone = false;
player.grndHeadIcon.alpha = 0.85;
}
player.grnd_wasSpectator = false;
if ( player.team == "spectator" )
{
player.inGrindZone = false;
player.inGrindZonePoints = 0;
player.grndHeadIcon.alpha = 0;
player.grnd_HUD["axisScore"].alpha = 0;
player.grnd_HUD["axisText"].alpha = 0;
player.grnd_HUD["alliesScore"].alpha = 0;
player.grnd_HUD["alliesText"].alpha = 0;
player.grnd_wasSpectator = true;
}
if( !isAI( player ) )
player thread grndTracking();
}
getNextZone()
{
pos = undefined;
index = undefined;
// get the distance to the current zone from all the remaining zones
// set index and save furthest and closest along the way
closestDistance = 99999999;
furthestDistance = 0;
if ( isDefined( level.teleport_zone_current ) && level.teleport_zone_current == "start" )
{
sortedZonesByDistance = SortByDistance( level.grnd_dropZones1, level.grnd_zone.origin );
}
else if ( isDefined( level.teleport_zone_current ) && level.teleport_zone_current != "start" )
{
//defensive check for zone 2 being active
if( !isDefined(level.grnd_dropZones2) || !level.grnd_dropZones2.size )
level initZones();
sortedZonesByDistance = SortByDistance( level.grnd_dropZones2, level.grnd_zone.origin );
}
else
{
sortedZonesByDistance = SortByDistance( level.grnd_zones, level.grnd_zone.origin );
}
//totally random except for current node
pos = sortedZonesByDistance[ RandomIntRange( 1, sortedZonesByDistance.size ) ].origin;
return pos;
}
cycleZones()
{
level notify ("cycleZones");
level endon ("cycleZones");
level endon( "game_ended" );
gameFlagWait( "prematch_done" );
while( true )
{
// move zone
pos = undefined;
if ( !level.firstZoneActive )
{
level.firstZoneActive = true;
pos = level.grnd_zone.origin;
}
else
{
pos = getNextZone();
StopFxOnTag( level.grnd_fx["smoke"], level.grnd_zone, "tag_fx" );
wait( 0.05 );
}
traceStart = pos + (0,0,30);
traceEnd = pos + (0,0,-1000);
trace = bulletTrace( traceStart, traceEnd, false, level.grnd_zone );
level.grnd_zone.origin = trace["position"]+(0,0,1);
// there may be artifacts if something is in the way of the drop zone marker
hitEntity = trace["entity"];
if ( IsDefined( hitEntity ) )
{
// search up the links until we get the moving platform
parent = hitEntity GetLinkedParent();
while ( IsDefined( parent ) )
{
hitEntity = parent;
parent = hitEntity GetLinkedParent();
}
}
if ( IsDefined( hitEntity )
// && hitEntity != level.grnd_zone
)
{
level.grnd_zone LinkTo( hitEntity );
}
else if ( level.grnd_zone IsLinked() )
{
level.grnd_zone Unlink();
}
level.alliesWeightOrg = level.grnd_zone.origin;
level.axisWeightOrg = level.grnd_zone.origin;
// update danger zone
level.grnd_dangerCenter.origin = level.grnd_zone.origin;
// target
thread spawnRegionVfx( level.grnd_zone.ringVfx, trace["position"], VectorToAngles( trace["normal"] ), 0.5 );
// smoke
wait( 0.05 );
PlayFxOnTag( level.grnd_fx["smoke"], level.grnd_zone, "tag_fx" );
foreach ( player in level.players )
player.grnd_fx_playing = true;
// reset drops
if ( level.matchRules_dropTime )
level thread randomDrops();
// wait
level.grnd_HUD["timerDisplay"].label = &"MP_NEXT_DROP_ZONE_IN";
level.grnd_HUD["timerDisplay"] setTimer( level.matchRules_zoneSwitchTime );
level.grnd_HUD["timerDisplay"].alpha = 1;
maps\mp\gametypes\_hostmigration::waitLongDurationWithHostMigrationPause( level.matchRules_zoneSwitchTime );
level.grnd_HUD["timerDisplay"].alpha = 0;
// audio cue for progress
playSoundOnPlayers( "mp_dropzone_obj_new" );
//Update bot ai
foreach( player in level.players )
{
if( isAI( player ) )
player thread maps\mp\bots\_bots_gametype_grnd::bot_grnd_think();
}
}
}
spawnFxDelay( pos, forward, right, delay )
{
if ( isDefined( level.grnd_targetFX ) )
level.grnd_targetFX delete();
wait delay;
level.grnd_targetFX = spawnFx( level.grnd_targetFXID, pos, forward, right );
triggerFx( level.grnd_targetFX );
}
spawnRegionVfx( ringEnt, newPostion, angles, delay )
{
StopFXOnTag( level.grnd_targetFXID, ringEnt, "tag_origin" );
wait delay;
ringEnt.origin = newPostion;
ringEnt.angles = angles;
PlayFXOnTag( level.grnd_targetFXID, ringEnt, "tag_origin" );
}
grndTracking()
{
self endon( "disconnect" );
level endon( "game_ended" );
AssertEx( isDefined( self.team ), self.name + "Doesnt have a team defined.");
if( !isDefined( self.team ) )
return;
while( true )
{
if( !isDefined( self.grnd_wasSpectator ) )
self.grnd_wasSpectator = false;
if ( !self.grnd_wasSpectator && self.pers["team"] == "spectator" )
{
self.inGrindZone = false;
self.inGrindZonePoints = 0;
self.grndHeadIcon.alpha = 0;
//self.grnd_HUD["axisScore"].alpha = 0;
//self.grnd_HUD["axisText"].alpha = 0;
//self.grnd_HUD["alliesScore"].alpha = 0;
//self.grnd_HUD["alliesText"].alpha = 0;
self.grnd_wasSpectator = true;
}
else if ( self.team != "spectator" )
{
if ( ( self.grnd_wasSpectator || !self.inGrindZone ) && self isInGrindZone() )
{
self.inGrindZone = true;
self.inGrindZonePoints = 0;
self iPrintLnBold( &"OBJECTIVES_GRND_CONFIRM" );
//self.grnd_HUD["axisScore"].alpha = 1;
//self.grnd_HUD["axisText"].alpha = 1;
//self.grnd_HUD["alliesScore"].alpha = 1;
//self.grnd_HUD["alliesText"].alpha = 1;
//self.grnd_HUD[self.team+"Score"].glowAlpha = 1;
//self.grnd_HUD[self.team+"Text"].glowAlpha = 1;
self.grndHeadIcon.alpha = 0;
}
else if ( ( self.grnd_wasSpectator || self.inGrindZone ) && !self isInGrindZone() )
{
self.inGrindZone = false;
self.inGrindZonePoints = 0;
self iPrintLnBold( &"OBJECTIVES_GRND_HINT" );
//self.grnd_HUD["axisScore"].alpha = 1;
//self.grnd_HUD["axisText"].alpha = 1;
//self.grnd_HUD["alliesScore"].alpha = 1;
//self.grnd_HUD["alliesText"].alpha = 1;
//self.grnd_HUD[self.team+"Score"].glowAlpha = 0;
//self.grnd_HUD[self.team+"Text"].glowAlpha = 0;
self.grndHeadIcon.alpha = 0.85;
}
self.grnd_wasSpectator = false;
}
wait( 0.05 );
}
}
locationStatus()
{
level endon( "game_ended" );
level.grnd_numPlayers["axis"] = 0;
level.grnd_numPlayers["allies"] = 0;
gameFlagWait( "prematch_done" );
while( true )
{
level.grnd_numPlayers["axis"] = 0;
level.grnd_numPlayers["allies"] = 0;
foreach( player in level.players )
{
if ( isDefined( player.inGrindZone ) && isReallyAlive( player ) && player.pers["team"] != "spectator" && player isInGrindZone() )
level.grnd_numPlayers[player.pers["team"]]++;
}
foreach( player in level.players )
{
if ( isDefined( player.inGrindZone ) && player.pers["team"] != "spectator" )
{
//axisPlayers = level.grnd_numPlayers["axis"] + 0;
//alliesPlayers = level.grnd_numPlayers["allies"] + 0;
//player.grnd_HUD["axisScore"] setText( 22 );
//player.grnd_HUD["alliesScore"] setText( 11 );
if ( level.grnd_numPlayers["axis"] == level.grnd_numPlayers["allies"] )
{
player.grndHeadIcon setShader( "waypoint_captureneutral_b", 14, 14 );
player.grndHeadIcon setWaypoint( false, true, false, false );
objective_icon( player.grndObjId, "waypoint_captureneutral_b" );
}
else if ( level.grnd_numPlayers[player.pers["team"]] > level.grnd_numPlayers[level.otherTeam[player.pers["team"]]] )
{
player.grndHeadIcon setShader( "waypoint_defend_b", 14, 14 );
player.grndHeadIcon setWaypoint( false, true, false, false );
objective_icon( player.grndObjId, "waypoint_defend_b" );
}
else
{
player.grndHeadIcon setShader( "waypoint_capture_b", 14, 14 );
player.grndHeadIcon setWaypoint( false, true, false, false );
objective_icon( player.grndObjId, "waypoint_capture_b" );
}
}
}
// wait
wait( 0.5 );
}
}
locationScoring()
{
level endon( "game_ended" );
gameFlagWait( "prematch_done" );
score = maps\mp\gametypes\_rank::getScoreInfoValue( "zone_tick" );
assert( isDefined( score ) );
while( true )
{
// player team scoring feedback
foreach( player in level.players )
{
if ( isDefined( player.inGrindZone ) && isReallyAlive( player ) && player.pers["team"] != "spectator" && player isInGrindZone() )
{
player.inGrindZonePoints += score;
maps\mp\gametypes\_gamescore::givePlayerScore( "zone_tick", player, undefined, false, true );
if ( isAI( player ) )
continue;
player.xpUpdateTotal = 0;
player thread maps\mp\gametypes\_rank::xpPointsPopup( 20 );
}
}
// update team scores
if ( level.grnd_numPlayers["axis"] )
maps\mp\gametypes\_gamescore::giveTeamScoreForObjective( "axis", score * level.grnd_numPlayers["axis"] );
if ( level.grnd_numPlayers["allies"] )
maps\mp\gametypes\_gamescore::giveTeamScoreForObjective( "allies", score * level.grnd_numPlayers["allies"] );
// wait
maps\mp\gametypes\_hostmigration::waitLongDurationWithHostMigrationPause( 1.0 );
}
}
randomDrops()
{
level endon( "game_ended" );
level notify( "reset_grnd_drops" );
level endon( "reset_grnd_drops" );
// try for no repeats per zone
level.grnd_previousCrateTypes = [];
while( true )
{
owner = getBestPlayer();
numIncomingVehicles = 1;
if( isDefined( owner ) &&
currentActiveVehicleCount() < maxVehiclesAllowed() &&
level.fauxVehicleCount + numIncomingVehicles < maxVehiclesAllowed() &&
level.numDropCrates < 8 )
{
owner thread maps\mp\gametypes\_rank::xpEventPopup( "earned_care_package" );
owner thread maps\mp\gametypes\_hud_message::SplashNotifyUrgent( "callout_earned_carepackage" );
owner thread leaderDialog( level.otherTeam[ owner.team ] + "_enemy_airdrop_assault_inbound", level.otherTeam[ owner.team ] );
owner thread leaderDialog( owner.team + "_friendly_airdrop_assault_inbound", owner.team );
playSoundOnPlayers( "mp_dropzone_obj_taken", owner.team );
playSoundOnPlayers( "mp_dropzone_obj_lost", level.otherTeam[owner.team] );
position = level.grnd_zone.origin + ( randomIntRange( (-1*GRND_ZONE_DROP_RADIUS), GRND_ZONE_DROP_RADIUS ), randomIntRange( (-1*GRND_ZONE_DROP_RADIUS), GRND_ZONE_DROP_RADIUS ), 0 );
crateType = getDropZoneCrateType();
if ( isSubStr( toLower( crateType ), "juggernaut" ) )
{
level thread maps\mp\killstreaks\_airdrop::doC130FlyBy( owner, position, randomFloat( 360 ), crateType );
}
else if ( crateType == "mega" )
{
level thread maps\mp\killstreaks\_airdrop::doMegaC130FlyBy( owner, position, randomFloat( 360 ), "airdrop_grnd", -360 );
}
else
{
incrementFauxVehicleCount();
level thread maps\mp\killstreaks\_airdrop::doFlyBy( owner, position, randomFloat( 360 ), "airdrop_grnd", 0, crateType );
}
waitTime = level.matchRules_dropTime;
}
else
waitTime = 0.5;
maps\mp\gametypes\_hostmigration::waitLongDurationWithHostMigrationPause( waitTime );
}
}
getBestPlayer()
{
bestPlayer = undefined;
bestPlayerPoints = 0;
// find the player with the currently highest accumulated points in the zone
foreach ( player in level.players )
{
if ( isReallyAlive( player ) && player.pers["team"] != "spectator" )
{
if ( player isInGrindZone() && player.inGrindZonePoints > bestPlayerPoints )
{
bestPlayer = player;
bestPlayerPoints = player.inGrindZonePoints;
}
}
}
// may return undefined
return bestPlayer;
}
getDropZoneCrateType()
{
crateType = undefined;
if ( !isDefined( level.grnd_previousCrateTypes["mega"] ) && level.numDropCrates == 0 && randomIntRange( 0, 100 ) < 5 )
{
crateType = "mega";
}
else
{
if ( level.grnd_previousCrateTypes.size )
{
maxTries = 200;
while( maxTries )
{
crateType = maps\mp\killstreaks\_airdrop::getRandomCrateType( "airdrop_grnd" );
if ( isDefined( level.grnd_previousCrateTypes[crateType] ) )
crateType = undefined;
else
break;
maxTries--;
}
}
if ( !isDefined( crateType ) )
crateType = maps\mp\killstreaks\_airdrop::getRandomCrateType( "airdrop_grnd" );
}
// track it
level.grnd_previousCrateTypes[crateType] = 1;
if ( level.grnd_previousCrateTypes.size == 15 )
level.grnd_previousCrateTypes = [];
return crateType;
}
isInGrindZone()
{
if ( distance2D( level.grnd_zone.origin, self.origin ) < GRND_ZONE_TOUCH_RADIUS && ( self.origin[2] > ( level.grnd_zone.origin[2] - 50 ) ) )
return true;
else
return false;
}
hideHudElementOnGameEnd( hudElement )
{
level waittill("game_ended");
if ( isDefined( hudElement ) )
hudElement.alpha = 0;
}
createZones()
{
level.grnd_dropZones = [];
level.grnd_dropZones1 = [];
level.grnd_dropZones2 = [];
chestSpawns = getstructarray( "sotf_chest_spawnpoint", "targetname" );
if( GetDvar( "mapname" ) == "mp_strikezone" )
{
zone2grnd_zones = [];
zone1grnd_zones = [];
foreach( zone in chestSpawns )
{
if ( zone.origin[2] > 10000 )
level.grnd_dropZones2[level.grnd_dropZones2.size] = zone;
else
level.grnd_dropZones1[level.grnd_dropZones1.size] = zone;
}
}
else
{
foreach ( zone in chestSpawns)
{
level.grnd_dropZones[level.grnd_dropZones.size] = zone;
}
}
adjustZones();
}
//Add zone adjustments here, add new stuff or move them
adjustZones()
{
levelName = toLower( getDvar("mapname") );
//adding additional zone for sz part one
if( levelName == "mp_strikezone" )
{
level.grnd_dropZones1[level.grnd_dropZones1.size] = spawnstruct();
level.grnd_dropZones1[level.grnd_dropZones1.size-1].origin = (-121,-1334,-73);
}
//Flooded Adjustments
if ( levelName == "mp_flooded" )
{
foreach( zone in level.grnd_dropZones )
{
if ( zone.origin == (-1596.9, 1315.7, 374.1) )
zone.origin = (-1561, 1278, 431 );
}
}
//Zebra Adjustments
if ( levelName == "mp_zebra" )
{
foreach( zone in level.grnd_dropZones )
{
if ( zone.origin == (4008.3, -2066.3, 482.1 ) )
zone.origin = (4048, -1985, 539 );
}
}
if ( isSubStr( levelName, "descent" ) )
{
foreach( zone in level.grnd_dropZones )
{
if ( zone.origin == (1101, 116, 5373.1) )
zone.origin = (1072, -80, 5378);
}
}
//debug prints
/#
println( "" );
println( "DROPZONE DEBUG INFORMATION" );
foreach ( zone in level.grnd_dropZones)
{
println( "Zone Origin: " + zone.origin );
}
println( "" );
#/
}

759
maps/mp/gametypes/gun.gsc Normal file
View File

@ -0,0 +1,759 @@
#include maps\mp\_utility;
#include maps\mp\gametypes\_hud_util;
#include maps\mp\gametypes\_class;
#include common_scripts\utility;
CONST_WEAPON_TABLE = "mp/gunGameWeapons.csv";
CONST_GROUP_NAME_IDX = 0;
CONST_WEAPON_BASE_IDX = 1;
CONST_WEAPON_MIN_ATTACH_IDX = 2;
CONST_WEAPON_MAX_ATTACH_IDX = 3;
CONST_WEAPON_BONUS_PERK_IDX = 4;
CONST_WEAPON_DLC_UNLOCK_IDX = 5;
CONST_CAMO_CHANCE = 0.5;
CONST_CAMO_TABLE = "mp/camotable.csv";
CONST_CAMO_ID_IDX = 4;
CONST_NUM_CAMOS = 12; // don't give gold camo?
CONST_RETICLE_CHANCE = 0.25;
CONST_NUM_RETICLES = 11;
main()
{
maps\mp\gametypes\_globallogic::init();
maps\mp\gametypes\_callbacksetup::SetupCallbacks();
maps\mp\gametypes\_globallogic::SetupCallbacks();
// must be done before scorelimit is set
setGuns();
if ( IsUsingMatchRulesData() )
{
level.initializeMatchRules = ::initializeMatchRules;
[[level.initializeMatchRules]]();
level thread reInitializeMatchRulesOnMigration();
}
else
{
registerTimeLimitDvar( level.gameType, 10 );
scoreLimit = level.gun_guns.size;
SetDynamicDvar( "scr_gun_scorelimit", scoreLimit );
registerScoreLimitDvar( level.gameType, scoreLimit );
registerRoundLimitDvar( level.gameType, 1 );
registerWinLimitDvar( level.gameType, 0 );
registerNumLivesDvar( level.gameType, 0 );
registerHalfTimeDvar( level.gameType, 0 );
level.matchRules_randomize = 0;
level.matchRules_damageMultiplier = 0;
level.matchRules_vampirism = 0;
}
setSpecialLoadout();
SetTeamMode( "ffa" );
level.teamBased = false;
level.doPrematch = true;
level.killstreakRewards = false;
level.supportIntel = false;
level.supportNuke = false;
level.assists_disabled = true;
level.onPrecacheGameType = ::onPrecacheGameType;
level.onStartGameType = ::onStartGameType;
level.onSpawnPlayer = ::onSpawnPlayer;
level.getSpawnPoint = ::getSpawnPoint;
level.onPlayerKilled = ::onPlayerKilled;
level.onTimeLimit = ::onTimeLimit;
level.onPlayerScore = ::onPlayerScore;
if ( level.matchRules_damageMultiplier || level.matchRules_vampirism )
level.modifyPlayerDamage = maps\mp\gametypes\_damage::gamemodeModifyPlayerDamage;
}
initializeMatchRules()
{
// set common values
setCommonRulesFromMatchRulesData( true );
// set everything else (private match options, default .cfg file values, and what normally is registered in the 'else' below)
level.matchRules_randomize = GetMatchRulesData( "gunData", "randomize" );
scoreLimit = level.gun_guns.size;
SetDynamicDvar( "scr_gun_scorelimit", scoreLimit );
registerScoreLimitDvar( level.gameType, scoreLimit );
SetDynamicDvar( "scr_gun_winlimit", 1 );
registerWinLimitDvar( "gun", 1 );
SetDynamicDvar( "scr_gun_roundlimit", 1 );
registerRoundLimitDvar( "gun", 1 );
SetDynamicDvar( "scr_gun_halftime", 0 );
registerHalfTimeDvar( "gun", 0 );
// Always force these values for this mode
SetDynamicDvar( "scr_gun_playerrespawndelay", 0 );
SetDynamicDvar( "scr_gun_waverespawndelay", 0 );
SetDynamicDvar( "scr_player_forcerespawn", 1 );
SetDynamicDvar( "scr_gun_promode", 0 );
}
onPrecacheGameType()
{
}
onStartGameType()
{
val = maps\mp\gametypes\_rank::getScoreInfoValue( "gained_gun_score" );
// xp_event_table ignores -1 values, so we have to manually set it
maps\mp\gametypes\_rank::registerScoreInfo( "dropped_gun_score", -1 * val );
// if we're using random guns, selecting the actual guns must wait until _weapons::init has run in order to build attachments
setGunsFinal();
setClientNameMode("auto_change");
setObjectiveText( "allies", &"OBJECTIVES_DM" );
setObjectiveText( "axis", &"OBJECTIVES_DM" );
if ( level.splitscreen )
{
setObjectiveScoreText( "allies", &"OBJECTIVES_DM" );
setObjectiveScoreText( "axis", &"OBJECTIVES_DM" );
}
else
{
setObjectiveScoreText( "allies", &"OBJECTIVES_DM_SCORE" );
setObjectiveScoreText( "axis", &"OBJECTIVES_DM_SCORE" );
}
setObjectiveHintText( "allies", &"OBJECTIVES_DM_HINT" );
setObjectiveHintText( "axis", &"OBJECTIVES_DM_HINT" );
level.spawnMins = ( 0, 0, 0 );
level.spawnMaxs = ( 0, 0, 0 );
maps\mp\gametypes\_spawnlogic::addSpawnPoints( "allies", "mp_dm_spawn" );
maps\mp\gametypes\_spawnlogic::addSpawnPoints( "axis", "mp_dm_spawn" );
level.mapCenter = maps\mp\gametypes\_spawnlogic::findBoxCenter( level.spawnMins, level.spawnMaxs );
setMapCenter( level.mapCenter );
allowed = [];
maps\mp\gametypes\_gameobjects::main(allowed);
level.QuickMessageToAll = true;
level.blockWeaponDrops = true;
// set index on enter
level thread onPlayerConnect();
level.killstreakRewards = false;
}
onPlayerConnect()
{
for ( ;; )
{
level waittill( "connected", player );
player.gun_firstSpawn = true;
player.gunGameGunIndex = 0;
player.gunGamePrevGunIndex = 0;
if ( level.matchRules_randomize )
{
player.gun_nextGuns = level.gun_guns;
player.gun_prevGuns = [];
}
player thread refillAmmo();
player thread refillSingleCountAmmo();
player setFakeLoadoutWeaponSlot( level.gun_guns[0], 1 );
}
}
getSpawnPoint()
{
// first time here?
if ( self.gun_firstSpawn )
{
self.gun_firstSpawn = false;
// everyone is a gamemode class in gun, no class selection
self.pers["class"] = "gamemode";
self.pers["lastClass"] = "";
self.class = self.pers["class"];
self.lastClass = self.pers["lastClass"];
// random team
if ( cointoss() )
self maps\mp\gametypes\_menus::addToTeam( "axis", true );
else
self maps\mp\gametypes\_menus::addToTeam( "allies", true );
}
spawnPoints = maps\mp\gametypes\_spawnlogic::getTeamSpawnPoints( self.pers["team"] );
spawnPoint = maps\mp\gametypes\_spawnscoring::getSpawnpoint_FreeForAll( spawnPoints );
return spawnPoint;
}
onSpawnPlayer()
{
// level.onSpawnPlayer() gets called before giveLoadout()
// so wait until it is done then override weapons
self.pers["gamemodeLoadout"] = level.gun_loadouts[self.pers["team"]];
self thread waitLoadoutDone();
level notify ( "spawned_player" );
}
waitLoadoutDone()
{
level endon( "game_ended" );
self endon( "disconnect" );
self waittill( "spawned_player" );
self givePerk( "specialty_bling", false );
self giveNextGun( true );
}
onPlayerKilled( eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration, lifeId )
{
if ( sMeansOfDeath == "MOD_FALLING" || ( isDefined( attacker ) && isPlayer( attacker ) ) )
{
isMeleeWeapon = maps\mp\gametypes\_weapons::isRiotShield( sWeapon ); // || maps\mp\gametypes\_weapons::isKnifeOnly( sWeapon )
if ( sMeansOfDeath == "MOD_FALLING" || attacker == self || ( sMeansOfDeath == "MOD_MELEE" && !isMeleeWeapon ) )
{
self playLocalSound( "mp_war_objective_lost" );
// drop level for suicide and getting knifed
self.gunGamePrevGunIndex = self.gunGameGunIndex;
self.gunGameGunIndex = int( max( 0, self.gunGameGunIndex-1 ) );
if ( self.gunGamePrevGunIndex > self.gunGameGunIndex )
{
self thread maps\mp\gametypes\_rank::xpEventPopup( "dropped_gun_rank" );
maps\mp\gametypes\_gamescore::givePlayerScore( "dropped_gun_score", self, undefined, true, true );
self setFakeLoadoutWeaponSlot( level.gun_guns[self.gunGameGunIndex], 1 );
}
if ( sMeansOfDeath == "MOD_MELEE" )
{
if ( self.gunGamePrevGunIndex )
{
attacker thread maps\mp\gametypes\_rank::xpEventPopup( "dropped_enemy_gun_rank" );
attacker thread maps\mp\gametypes\_rank::giveRankXP( "dropped_enemy_gun_rank" );
}
attacker.assists++;
// repurposing unused sguardWave in round stats for stabs
attacker maps\mp\gametypes\_persistence::statSetChild( "round", "sguardWave", attacker.assists );
}
}
else if ( ( sMeansOfDeath == "MOD_PISTOL_BULLET" )
|| ( sMeansOfDeath == "MOD_RIFLE_BULLET" )
|| ( sMeansOfDeath == "MOD_HEAD_SHOT" )
|| ( sMeansOfDeath == "MOD_PROJECTILE" ) || ( sMeansOfDeath == "MOD_PROJECTILE_SPLASH" )
|| ( sMeansOfDeath == "MOD_IMPACT" )
|| ( sMeansOfDeath == "MOD_GRENADE" ) || ( sMeansOfDeath == "MOD_GRENADE_SPLASH" )
|| ( sMeansOfDeath == "MOD_MELEE" && isMeleeWeapon )
)
{
// Prevent sequential kills from counting by validating the primary weapon
// Let throwing knife kills count even though they're not the primary weapon
if ( sWeapon != attacker.primaryWeapon && !attacker isValidThrowingKnifeKill( sWeapon ) )
return;
attacker.gunGamePrevGunIndex = attacker.gunGameGunIndex;
attacker.gunGameGunIndex++;
attacker thread maps\mp\gametypes\_rank::giveRankXP( "gained_gun_rank" );
maps\mp\gametypes\_gamescore::givePlayerScore( "gained_gun_score", attacker, self, true, true );
if ( attacker.gunGameGunIndex == level.gun_guns.size-1 )
{
playSoundOnPlayers( "mp_enemy_obj_captured" );
level thread teamPlayerCardSplash( "callout_top_gun_rank", attacker );
}
if ( attacker.gunGameGunIndex < level.gun_guns.size )
{
attacker thread maps\mp\gametypes\_rank::xpEventPopup( "gained_gun_rank" );
attacker playLocalSound( "mp_war_objective_taken" );
attacker giveNextGun();
attacker setFakeLoadoutWeaponSlot( level.gun_guns[attacker.gunGameGunIndex], 1 );
}
}
}
}
giveNextGun( doSetSpawnWeapon )
{
// get the next one
newWeapon = getNextGun();
// give gun
self takeAllWeapons();
_giveWeapon( newWeapon );
// set vars
if ( isDefined( doSetSpawnWeapon ) )
self setSpawnWeapon( newWeapon );
self.pers["primaryWeapon"] = newWeapon;
self.primaryWeapon = newWeapon;
// use it!
self GiveStartAmmo( newWeapon );
self SwitchToWeapon( newWeapon );
self giveOrTakeThrowingKnife( newWeapon );
// have to record the hybrid scope state?
self maps\mp\gametypes\_weapons::updateToggleScopeState( newWeapon );
// gain/drop scoring/messaging
if ( self.gunGamePrevGunIndex > self.gunGameGunIndex )
{
// we dropped :(
self thread maps\mp\gametypes\_rank::xpEventPopup( "dropped_gun_rank" );
}
else if ( self.gunGamePrevGunIndex < self.gunGameGunIndex )
{
// we gained :)
self thread maps\mp\gametypes\_rank::xpEventPopup( "gained_gun_rank" );
}
self.gunGamePrevGunIndex = self.gunGameGunIndex;
// remove old perks, add new ones
// remove old equipment, add new ones
}
getNextGun()
{
newWeapon = level.gun_guns[self.gunGameGunIndex];
return newWeapon;
}
/*
waitUntilNotFiringToGiveNextGun()
{
self endon ( "death" );
while ( self AttackButtonPressed() )
{
waitframe();
}
self giveNextGun();
}
*/
onTimeLimit()
{
level.finalKillCam_winner = "none";
winners = getHighestProgressedPlayers();
if ( !isDefined( winners ) || !winners.size )
thread maps\mp\gametypes\_gamelogic::endGame( "tie", game[ "end_reason" ][ "time_limit_reached" ] );
else if ( winners.size == 1 )
thread maps\mp\gametypes\_gamelogic::endGame( winners[0], game[ "end_reason" ][ "time_limit_reached" ] );
else
{
if ( winners[winners.size-1].gunGameGunIndex > winners[winners.size-2].gunGameGunIndex )
thread maps\mp\gametypes\_gamelogic::endGame( winners[winners.size-1], game[ "end_reason" ][ "time_limit_reached" ] );
else
thread maps\mp\gametypes\_gamelogic::endGame( "tie", game[ "end_reason" ][ "time_limit_reached" ] );
}
}
getHighestProgressedPlayers()
{
highestProgress = -1;
highestProgressedPlayers = [];
foreach( player in level.players )
{
if ( isDefined( player.gunGameGunIndex ) && player.gunGameGunIndex >= highestProgress )
{
highestProgress = player.gunGameGunIndex;
highestProgressedPlayers[highestProgressedPlayers.size] = player;
}
}
return highestProgressedPlayers;
}
refillAmmo()
{
level endon( "game_ended" );
self endon( "disconnect" );
while ( true )
{
self waittill( "reload" );
self GiveStartAmmo( self.primaryWeapon );
}
}
refillSingleCountAmmo()
{
level endon( "game_ended" );
self endon( "disconnect" );
while ( true )
{
if ( isReallyAlive( self ) && self.team != "spectator" && isDefined( self.primaryWeapon ) && self getAmmoCount( self.primaryWeapon ) == 0 )
{
// fake a reload time
wait( 2 );
self notify( "reload" );
wait( 1 );
}
else
wait( 0.05 );
}
}
setGuns()
{
level.gun_guns = [];
level.selectedWeapons = [];
numGuns = 0;
if ( isUsingMatchRulesData() )
numGuns = GetMatchRulesData( "gunData", "numGuns" );
if( numGuns > 20 )
numGuns = 20;
if ( numGuns )
{
for ( i=0; i<numGuns; i++ )
{
level.gun_guns[i] = GetMatchRulesData( "gunData", "guns", i );
}
}
else
{
// hand guns
level.gun_guns[0] = "rand_pistol";
level.gun_guns[1] = "rand_shotgun";
level.gun_guns[2] = "rand_smg";
level.gun_guns[3] = "rand_assault";
level.gun_guns[4] = "rand_lmg";
level.gun_guns[5] = "rand_dmr";
level.gun_guns[6] = "rand_smg";
level.gun_guns[7] = "rand_assault";
level.gun_guns[8] = "rand_lmg2";
level.gun_guns[9] = "rand_launcher";
level.gun_guns[10] = "rand_sniper";
level.gun_guns[11] = "rand_smg";
level.gun_guns[12] = "rand_assault2";
level.gun_guns[13] = "rand_shotgun2";
level.gun_guns[14] = "rand_dmr";
level.gun_guns[15] = "rand_sniper2";
level.gun_guns[16] = "iw6_magnum_mp_acogpistol_akimbo";
level.gun_guns[17] = "iw6_knifeonly_mp";
}
// if ( level.matchRules_randomize )
// shuffle the list if desired
}
// after weapons have initialized, set the guns for real
setGunsFinal()
{
level.selectedWeapons = []; // keep track of which weapons we've used
buildRandomWeaponTable();
for ( i = 0; i < level.gun_guns.size; i++ )
{
curGun = level.gun_guns[i];
if ( isStrStart( curGun, "rand_" ) )
{
level.gun_guns[i] = getRandomWeaponFromCategory( curGun );
}
else
{
baseWeapon = getBaseWeaponName( level.gun_guns[i] );
level.selectedWeapons[ baseWeapon ] = true;
}
}
level.selectedWeapons = undefined;
}
setSpecialLoadout()
{
// no killstreaks defined for special classes
level.gun_loadouts["axis"]["loadoutPrimary"] = "iw6_sc2010"; // can't use "none" for primary, this is replaced on spawn anyway
level.gun_loadouts["axis"]["loadoutPrimaryAttachment"] = "none";
level.gun_loadouts["axis"]["loadoutPrimaryAttachment2"] = "none";
level.gun_loadouts["axis"]["loadoutPrimaryBuff"] = "specialty_null";
level.gun_loadouts["axis"]["loadoutPrimaryCamo"] = "none";
level.gun_loadouts["axis"]["loadoutPrimaryReticle"] = "none";
level.gun_loadouts["axis"]["loadoutSecondary"] = "none";
level.gun_loadouts["axis"]["loadoutSecondaryAttachment"] = "none";
level.gun_loadouts["axis"]["loadoutSecondaryAttachment2"] = "none";
level.gun_loadouts["axis"]["loadoutSecondaryBuff"] = "specialty_null";
level.gun_loadouts["axis"]["loadoutSecondaryCamo"] = "none";
level.gun_loadouts["axis"]["loadoutSecondaryReticle"] = "none";
level.gun_loadouts["axis"]["loadoutEquipment"] = "specialty_null";
level.gun_loadouts["axis"]["loadoutOffhand"] = "none";
level.gun_loadouts[ "axis" ] [ "loadoutStreakType" ] = "assault";
level.gun_loadouts[ "axis" ] [ "loadoutKillstreak1" ] = "none";
level.gun_loadouts[ "axis" ] [ "loadoutKillstreak2" ] = "none";
level.gun_loadouts[ "axis" ] [ "loadoutKillstreak3" ] = "none";
level.gun_loadouts["axis"]["loadoutPerks"] = [ "specialty_quickswap", "specialty_marathon" ];
level.gun_loadouts["axis"]["loadoutJuggernaut"] = false;
// FFA games don't have teams, but players are allowed to choose team on the way in
// just for character model and announcer voice variety. Same loadout for both.
level.gun_loadouts["allies"] = level.gun_loadouts["axis"];
}
buildRandomWeaponTable()
{
level.weaponCategories = [];
row = 0;
while ( true )
{
// do I need to check against "#" values?
categoryName = TableLookupByRow( CONST_WEAPON_TABLE, row, CONST_GROUP_NAME_IDX );
if ( categoryName == "" )
break;
if ( !IsDefined( level.weaponCategories[ categoryName ] ) )
{
level.weaponCategories[ categoryName ] = [];
}
// 2014-01-31 wallace: we don't unlock dlc packs at the same time across all platforms
requiredPack = TableLookupByRow( CONST_WEAPON_TABLE, row, CONST_WEAPON_DLC_UNLOCK_IDX );
if ( requiredPack == "" || GetDvarInt( requiredPack, 0 ) == 1 )
{
data = [];
data[ "weapon" ] = TableLookupByRow( CONST_WEAPON_TABLE, row, CONST_WEAPON_BASE_IDX );
data[ "min" ] = Int( TableLookupByRow( CONST_WEAPON_TABLE, row, CONST_WEAPON_MIN_ATTACH_IDX ) );
data[ "max" ] = Int( TableLookupByRow( CONST_WEAPON_TABLE, row, CONST_WEAPON_MAX_ATTACH_IDX ) );
data[ "perk" ] = TableLookupByRow( CONST_WEAPON_TABLE, row, CONST_WEAPON_BONUS_PERK_IDX );
level.weaponCategories[ categoryName ][ level.weaponCategories[ categoryName ].size ] = data;
}
row++;
}
}
getRandomWeaponFromCategory( categoryName )
{
weaponList = level.weaponCategories[ categoryName ];
if ( IsDefined( weaponList ) && weaponList.size > 0 )
{
newWeapon = "";
data = undefined;
// make sure we haven't already selected this weapon
loopCount = 0;
while ( true )
{
index = RandomIntRange( 0, weaponList.size );
data = weaponList[ index ];
baseWeapon = getBaseWeaponName( data[ "weapon" ] );
if ( !IsDefined( level.selectedWeapons[ baseWeapon ] )
|| loopCount > weaponList.size ) // give up if we've looped too many times
{
level.selectedWeapons[ baseWeapon ] = true;
newWeapon = data[ "weapon" ];
break;
}
loopCount++;
}
// add random attachments
// otherwise, we assume the newWeapon already includes some attachment configs
if ( newWeapon == baseWeapon )
{
numAttachments = RandomIntRange( data[ "min" ], data[ "max" ] + 1 );
newWeapon = modifyWeapon( newWeapon, numAttachments );
}
// should try to return the perk, too?
return newWeapon;
}
else
{
// error
AssertMsg( "Unknown weapon category name " + categoryName );
return "none";
}
}
// this is adapated from sotf
modifyWeapon( baseWeapon, numAttachments )
{
// Attachments for the weapon
chosenAttachments = [];
hasScopeAttach = false;
if ( numAttachments > 0 )
{
allAttachments = getWeaponAttachmentArrayFromStats( baseWeapon );
if ( allAttachments.size > 0 )
{
validAttachments = getValidAttachments( allAttachments );
/#
Print( "gun: attempting to modify " + baseWeapon + " with " + numAttachments + " of " + validAttachments.size + " attachments\n" );
#/
//2014-01-08 wllace: arbitrary cap so we don't loop forever
// we could recreate validAttachments each time we select an attachment to filter out the bad ones, but I'm lazy.
maxAttempts = validAttachments.size;
for ( i = 0; i < numAttachments; i++ )
{
newAttachment = "";
while ( newAttachment == "" && maxAttempts > 0 )
{
maxAttempts--;
randomIndex = RandomInt( validAttachments.size );
if ( maps\mp\gametypes\sotf::attachmentCheck( validAttachments[ randomIndex ], chosenAttachments ) )
{
newAttachment = attachmentMap_toUnique( validAttachments[ randomIndex ], baseWeapon );
chosenAttachments[ chosenAttachments.size ] = newAttachment;
if ( getAttachmentType( newAttachment ) == "rail" )
{
hasScopeAttach = true;
}
}
}
}
}
}
// randomly select camos, reticles. 0 = default
camoIndex = 0;
reticleIndex = 0;
/*
modifyChance = RandomFloat(1.0);
if ( hasScopeAttach && modifyChance < CONST_RETICLE_CHANCE )
{
reticleIndex = RandomIntRange( 1, CONST_NUM_RETICLES );
}
if ( modifyChance < CONST_CAMO_CHANCE
&& maps\mp\gametypes\_class::isValidPrimary( baseWeapon, false )
&& !maps\mp\gametypes\_weapons::isKnifeOnly( baseWeapon )
)
{
camoNum = RandomIntRange( 1, CONST_NUM_CAMOS );
camoIndex = Int( TableLookup( CONST_CAMO_TABLE, 0, camoNum, CONST_CAMO_ID_IDX ) );
}
*/
// what happens if you try to attach a reticle if the gun has no scope?
newWeapon = buildWeaponName( baseWeapon, chosenAttachments, camoIndex, reticleIndex );
return newWeapon;
}
getValidAttachments( attachmentArray )
{
validAttachments = [];
foreach ( attachment in attachmentArray )
{
switch ( attachment )
{
// reject some attachments that would not be fun in gun game.
case "gl":
case "shotgun":
case "silencer":
case "firetypesingle":
case "firetypeburst":
case "firetypeauto": // this would be fine, but eh.
case "ammoslug":
break;
default:
validAttachments[ validAttachments.size ] = attachment;
}
}
return validAttachments;
}
giveOrTakeThrowingKnife( currentWeapon )
{
if ( maps\mp\gametypes\_weapons::isKnifeOnly( currentWeapon ) )
{
self givePerkEquipment( "throwingknife_mp", true );
self.loadoutPerkEquipment = "throwingknife_mp";
self givePerk( "specialty_extra_deadly", false );
self givePerk( "specialty_scavenger", false );
}
else
{
self TakeWeapon( "throwingknife_mp" );
self givePerkEquipment( "specialty_null", true );
}
}
isValidThrowingKnifeKill( killWeapon )
{
return ( killWeapon == "throwingknife_mp" && IsDefined( self.loadoutPerkEquipment ) && self.loadoutPerkEquipment == "throwingknife_mp" );
}
onPlayerScore( event, player, victim )
{
score = 0;
if ( event == "gained_gun_score"
|| event == "dropped_gun_score" )
{
score = maps\mp\gametypes\_rank::getScoreInfoValue( event );
Assert( IsDefined( score ) );
}
return score;
}

2489
maps/mp/gametypes/horde.gsc Normal file

File diff suppressed because it is too large Load Diff

1137
maps/mp/gametypes/infect.gsc Normal file

File diff suppressed because it is too large Load Diff

1456
maps/mp/gametypes/mugger.gsc Normal file

File diff suppressed because it is too large Load Diff

1332
maps/mp/gametypes/sd.gsc Normal file

File diff suppressed because it is too large Load Diff

1702
maps/mp/gametypes/siege.gsc Normal file

File diff suppressed because it is too large Load Diff

1121
maps/mp/gametypes/sotf.gsc Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1746
maps/mp/gametypes/sr.gsc Normal file

File diff suppressed because it is too large Load Diff

212
maps/mp/gametypes/war.gsc Normal file
View File

@ -0,0 +1,212 @@
#include maps\mp\_utility;
#include maps\mp\gametypes\_hud_util;
/*
War
Objective: Score points for your team by eliminating players on the opposing team
Map ends: When one team reaches the score limit, or time limit is reached
Respawning: No wait / Near teammates
Level requirementss
------------------
Spawnpoints:
classname mp_tdm_spawn
All players spawn from these. The spawnpoint chosen is dependent on the current locations of teammates and enemies
at the time of spawn. Players generally spawn behind their teammates relative to the direction of enemies.
Spectator Spawnpoints:
classname mp_global_intermission
Spectators spawn from these and intermission is viewed from these positions.
Atleast one is required, any more and they are randomly chosen between.
*/
/*QUAKED mp_tdm_spawn (0.0 0.0 1.0) (-16 -16 0) (16 16 72)
Players spawn away from enemies and near their team at one of these positions.*/
/*QUAKED mp_tdm_spawn_axis_start (0.5 0.0 1.0) (-16 -16 0) (16 16 72)
Axis players spawn away from enemies and near their team at one of these positions at the start of a round.*/
/*QUAKED mp_tdm_spawn_allies_start (0.0 0.5 1.0) (-16 -16 0) (16 16 72)
Allied players spawn away from enemies and near their team at one of these positions at the start of a round.*/
main()
{
if(getdvar("mapname") == "mp_background")
return;
maps\mp\gametypes\_globallogic::init();
maps\mp\gametypes\_callbacksetup::SetupCallbacks();
maps\mp\gametypes\_globallogic::SetupCallbacks();
if ( isUsingMatchRulesData() )
{
level.initializeMatchRules = ::initializeMatchRules;
[[level.initializeMatchRules]]();
level thread reInitializeMatchRulesOnMigration();
}
else
{
registerRoundSwitchDvar( level.gameType, 0, 0, 9 );
registerTimeLimitDvar( level.gameType, 10 );
registerScoreLimitDvar( level.gameType, 75 );
registerRoundLimitDvar( level.gameType, 1 );
registerWinLimitDvar( level.gameType, 1 );
registerNumLivesDvar( level.gameType, 0 );
registerHalfTimeDvar( level.gameType, 0 );
level.matchRules_damageMultiplier = 0;
level.matchRules_vampirism = 0;
}
level.teamBased = true;
level.onStartGameType = ::onStartGameType;
level.getSpawnPoint = ::getSpawnPoint;
level.onNormalDeath = ::onNormalDeath;
if ( level.matchRules_damageMultiplier || level.matchRules_vampirism )
level.modifyPlayerDamage = maps\mp\gametypes\_damage::gamemodeModifyPlayerDamage;
game["dialog"]["gametype"] = "tm_death";
if ( getDvarInt( "g_hardcore" ) )
game["dialog"]["gametype"] = "hc_" + game["dialog"]["gametype"];
else if ( getDvarInt( "camera_thirdPerson" ) )
game["dialog"]["gametype"] = "thirdp_" + game["dialog"]["gametype"];
else if ( getDvarInt( "scr_diehard" ) )
game["dialog"]["gametype"] = "dh_" + game["dialog"]["gametype"];
else if (getDvarInt( "scr_" + level.gameType + "_promode" ) )
game["dialog"]["gametype"] = game["dialog"]["gametype"] + "_pro";
game["strings"]["overtime_hint"] = &"MP_FIRST_BLOOD";
}
initializeMatchRules()
{
// set common values
setCommonRulesFromMatchRulesData();
// set everything else (private match options, default .cfg file values, and what normally is registered in the 'else' below)
SetDynamicDvar( "scr_war_roundswitch", 0 );
registerRoundSwitchDvar( "war", 0, 0, 9 );
SetDynamicDvar( "scr_war_roundlimit", 1 );
registerRoundLimitDvar( "war", 1 );
SetDynamicDvar( "scr_war_winlimit", 1 );
registerWinLimitDvar( "war", 1 );
SetDynamicDvar( "scr_war_halftime", 0 );
registerHalfTimeDvar( "war", 0 );
SetDynamicDvar( "scr_war_promode", 0 );
}
onStartGameType()
{
setClientNameMode("auto_change");
if ( !isdefined( game["switchedsides"] ) )
game["switchedsides"] = false;
if ( game["switchedsides"] )
{
oldAttackers = game["attackers"];
oldDefenders = game["defenders"];
game["attackers"] = oldDefenders;
game["defenders"] = oldAttackers;
}
setObjectiveText( "allies", &"OBJECTIVES_WAR" );
setObjectiveText( "axis", &"OBJECTIVES_WAR" );
if ( level.splitscreen )
{
setObjectiveScoreText( "allies", &"OBJECTIVES_WAR" );
setObjectiveScoreText( "axis", &"OBJECTIVES_WAR" );
}
else
{
setObjectiveScoreText( "allies", &"OBJECTIVES_WAR_SCORE" );
setObjectiveScoreText( "axis", &"OBJECTIVES_WAR_SCORE" );
}
setObjectiveHintText( "allies", &"OBJECTIVES_WAR_HINT" );
setObjectiveHintText( "axis", &"OBJECTIVES_WAR_HINT" );
initSpawns();
allowed[0] = level.gameType;
maps\mp\gametypes\_gameobjects::main( allowed );
}
initSpawns()
{
level.spawnMins = ( 0, 0, 0 );
level.spawnMaxs = ( 0, 0, 0 );
maps\mp\gametypes\_spawnlogic::addStartSpawnPoints( "mp_tdm_spawn_allies_start" );
maps\mp\gametypes\_spawnlogic::addStartSpawnPoints( "mp_tdm_spawn_axis_start" );
maps\mp\gametypes\_spawnlogic::addSpawnPoints( "allies", "mp_tdm_spawn" );
maps\mp\gametypes\_spawnlogic::addSpawnPoints( "axis", "mp_tdm_spawn" );
level.mapCenter = maps\mp\gametypes\_spawnlogic::findBoxCenter( level.spawnMins, level.spawnMaxs );
setMapCenter( level.mapCenter );
}
getSpawnPoint()
{
spawnteam = self.pers["team"];
if ( game["switchedsides"] )
spawnteam = getOtherTeam( spawnteam );
if ( maps\mp\gametypes\_spawnlogic::shouldUseTeamStartSpawn() )
{
spawnPoints = maps\mp\gametypes\_spawnlogic::getSpawnpointArray( "mp_tdm_spawn_" + spawnteam + "_start" );
spawnPoint = maps\mp\gametypes\_spawnlogic::getSpawnpoint_startSpawn( spawnPoints );
}
else
{
spawnPoints = maps\mp\gametypes\_spawnlogic::getTeamSpawnPoints( spawnteam );
spawnPoint = maps\mp\gametypes\_spawnscoring::getSpawnpoint_NearTeam( spawnPoints );
}
return spawnPoint;
}
onNormalDeath( victim, attacker, lifeId )
{
score = maps\mp\gametypes\_rank::getScoreInfoValue( "score_increment" );
assert( isDefined( score ) );
level maps\mp\gametypes\_gamescore::giveTeamScoreForObjective( attacker.pers["team"], score );
if ( game["state"] == "postgame" && game["teamScores"][attacker.team] > game["teamScores"][level.otherTeam[attacker.team]] )
attacker.finalKill = true;
}
onTimeLimit()
{
level.finalKillCam_winner = "none";
if ( game["status"] == "overtime" )
{
winner = "forfeit";
}
else if ( game["teamScores"]["allies"] == game["teamScores"]["axis"] )
{
winner = "overtime";
}
else if ( game["teamScores"]["axis"] > game["teamScores"]["allies"] )
{
level.finalKillCam_winner = "axis";
winner = "axis";
}
else
{
level.finalKillCam_winner = "allies";
winner = "allies";
}
thread maps\mp\gametypes\_gamelogic::endGame( winner, game[ "end_reason" ][ "time_limit_reached" ] );
}