From 299e5ed6250f5e80eb24bd9cfa7bd5f639951416 Mon Sep 17 00:00:00 2001 From: efinst0rm Date: Thu, 17 Aug 2023 19:33:49 -0500 Subject: [PATCH] Port allowTeamChoice & allowClassChoice from IW5 Updates gameTypesTable.csv to check if game modes allow team change & class choices. --- iw4x/iw4x_00/maps/mp/_utility.gsc | 2742 ++++++++++++++++++++++++++++ iw4x/iw4x_00/mp/gameTypesTable.csv | 39 +- 2 files changed, 2761 insertions(+), 20 deletions(-) create mode 100644 iw4x/iw4x_00/maps/mp/_utility.gsc diff --git a/iw4x/iw4x_00/maps/mp/_utility.gsc b/iw4x/iw4x_00/maps/mp/_utility.gsc new file mode 100644 index 0000000..ecd9ecf --- /dev/null +++ b/iw4x/iw4x_00/maps/mp/_utility.gsc @@ -0,0 +1,2742 @@ +#include common_scripts\utility; +#include maps\mp\gametypes\_hud_util; + +exploder_sound() +{ + if ( isdefined( self.script_delay ) ) + wait self.script_delay; + + self playSound( level.scr_sound[ self.script_sound ] ); +} + +/* +saveModel() +{ + info["model"] = self.model; + info["viewmodel"] = self getViewModel(); + attachSize = self getAttachSize(); + info["attach"] = []; + + assert(info["viewmodel"] != ""); // No viewmodel was associated with the player's model + + for(i = 0; i < attachSize; i++) + { + info["attach"][i]["model"] = self getAttachModelName(i); + info["attach"][i]["tag"] = self getAttachTagName(i); + info["attach"][i]["ignoreCollision"] = self getAttachIgnoreCollision(i); + } + + return info; +} + +loadModel(info) +{ + self detachAll(); + self setModel(info["model"]); + self setViewModel(info["viewmodel"]); + + attachInfo = info["attach"]; + attachSize = attachInfo.size; + + for(i = 0; i < attachSize; i++) + self attach(attachInfo[i]["model"], attachInfo[i]["tag"], attachInfo[i]["ignoreCollision"]); +} +*/ + +/* +============= +///ScriptDocBegin +"Name: delayThread( , , , , , )" +"Summary: Delaythread is cool! It saves you from having to write extra script for once off commands. Note you don’t have to thread it off. Delaythread is that smart!" +"Module: Utility" +"MandatoryArg: : The delay before the function occurs" +"MandatoryArg: : The function to run." +"OptionalArg: : parameter 1 to pass to the process" +"OptionalArg: : parameter 2 to pass to the process" +"OptionalArg: : parameter 3 to pass to the process" +"OptionalArg: : parameter 4 to pass to the process" +"OptionalArg: : parameter 5 to pass to the process" +"Example: delayThread( 3, ::flag_set, "player_can_rappel" ); +"SPMP: both" +///ScriptDocEnd +============= +*/ +delayThread( timer, func, param1, param2, param3, param4, param5 ) +{ + // to thread it off + thread delayThread_proc( func, timer, param1, param2, param3, param4, param5 ); +} + + +delayThread_proc( func, timer, param1, param2, param3, param4, param5 ) +{ + wait( timer ); + if ( !IsDefined( param1 ) ) + { + assertex( !isdefined( param2 ), "Delaythread does not support vars after undefined." ); + assertex( !isdefined( param3 ), "Delaythread does not support vars after undefined." ); + assertex( !isdefined( param4 ), "Delaythread does not support vars after undefined." ); + assertex( !isdefined( param5 ), "Delaythread does not support vars after undefined." ); + thread [[ func ]](); + } + else + if ( !IsDefined( param2 ) ) + { + assertex( !isdefined( param3 ), "Delaythread does not support vars after undefined." ); + assertex( !isdefined( param4 ), "Delaythread does not support vars after undefined." ); + assertex( !isdefined( param5 ), "Delaythread does not support vars after undefined." ); + thread [[ func ]]( param1 ); + } + else + if ( !IsDefined( param3 ) ) + { + assertex( !isdefined( param4 ), "Delaythread does not support vars after undefined." ); + assertex( !isdefined( param5 ), "Delaythread does not support vars after undefined." ); + thread [[ func ]]( param1, param2 ); + } + else + if ( !IsDefined( param4 ) ) + { + assertex( !isdefined( param5 ), "Delaythread does not support vars after undefined." ); + thread [[ func ]]( param1, param2, param3 ); + } + else + if ( !IsDefined( param5 ) ) + { + thread [[ func ]]( param1, param2, param3, param4 ); + } + else + { + thread [[ func ]]( param1, param2, param3, param4, param5 ); + } +} + +getPlant() +{ + start = self.origin + ( 0, 0, 10 ); + + range = 11; + forward = anglesToForward( self.angles ); + forward = vector_multiply( forward, range ); + + traceorigins[ 0 ] = start + forward; + traceorigins[ 1 ] = start; + + trace = bulletTrace( traceorigins[ 0 ], ( traceorigins[ 0 ] + ( 0, 0, -18 ) ), false, undefined ); + if ( trace[ "fraction" ] < 1 ) + { + //println("^6Using traceorigins[0], tracefraction is", trace["fraction"]); + + temp = spawnstruct(); + temp.origin = trace[ "position" ]; + temp.angles = orientToNormal( trace[ "normal" ] ); + return temp; + } + + trace = bulletTrace( traceorigins[ 1 ], ( traceorigins[ 1 ] + ( 0, 0, -18 ) ), false, undefined ); + if ( trace[ "fraction" ] < 1 ) + { + //println("^6Using traceorigins[1], tracefraction is", trace["fraction"]); + + temp = spawnstruct(); + temp.origin = trace[ "position" ]; + temp.angles = orientToNormal( trace[ "normal" ] ); + return temp; + } + + traceorigins[ 2 ] = start + ( 16, 16, 0 ); + traceorigins[ 3 ] = start + ( 16, -16, 0 ); + traceorigins[ 4 ] = start + ( -16, -16, 0 ); + traceorigins[ 5 ] = start + ( -16, 16, 0 ); + + besttracefraction = undefined; + besttraceposition = undefined; + for ( i = 0; i < traceorigins.size; i++ ) + { + trace = bulletTrace( traceorigins[ i ], ( traceorigins[ i ] + ( 0, 0, -1000 ) ), false, undefined ); + + //ent[i] = spawn("script_model",(traceorigins[i]+(0, 0, -2))); + //ent[i].angles = (0, 180, 180); + //ent[i] setmodel("105"); + + //println("^6trace ", i ," fraction is ", trace["fraction"]); + + if ( !isdefined( besttracefraction ) || ( trace[ "fraction" ] < besttracefraction ) ) + { + besttracefraction = trace[ "fraction" ]; + besttraceposition = trace[ "position" ]; + + //println("^6besttracefraction set to ", besttracefraction, " which is traceorigin[", i, "]"); + } + } + + if ( besttracefraction == 1 ) + besttraceposition = self.origin; + + temp = spawnstruct(); + temp.origin = besttraceposition; + temp.angles = orientToNormal( trace[ "normal" ] ); + return temp; +} + +orientToNormal( normal ) +{ + hor_normal = ( normal[ 0 ], normal[ 1 ], 0 ); + hor_length = length( hor_normal ); + + if ( !hor_length ) + return( 0, 0, 0 ); + + hor_dir = vectornormalize( hor_normal ); + neg_height = normal[ 2 ] * - 1; + tangent = ( hor_dir[ 0 ] * neg_height, hor_dir[ 1 ] * neg_height, hor_length ); + plant_angle = vectortoangles( tangent ); + + //println("^6hor_normal is ", hor_normal); + //println("^6hor_length is ", hor_length); + //println("^6hor_dir is ", hor_dir); + //println("^6neg_height is ", neg_height); + //println("^6tangent is ", tangent); + //println("^6plant_angle is ", plant_angle); + + return plant_angle; +} + +deletePlacedEntity( entity ) +{ + entities = getentarray( entity, "classname" ); + for ( i = 0; i < entities.size; i++ ) + { + //println("DELETED: ", entities[i].classname); + entities[ i ] delete(); + } +} + +playSoundOnPlayers( sound, team, excludeList ) +{ + assert( isdefined( level.players ) ); + + if ( level.splitscreen ) + { + if ( isdefined( level.players[ 0 ] ) ) + level.players[ 0 ] playLocalSound( sound ); + } + else + { + if ( isDefined( team ) ) + { + if ( isdefined( excludeList ) ) + { + for ( i = 0; i < level.players.size; i++ ) + { + player = level.players[ i ]; + if ( isdefined( player.pers[ "team" ] ) && ( player.pers[ "team" ] == team ) && !isExcluded( player, excludeList ) ) + player playLocalSound( sound ); + } + } + else + { + for ( i = 0; i < level.players.size; i++ ) + { + player = level.players[ i ]; + if ( isdefined( player.pers[ "team" ] ) && ( player.pers[ "team" ] == team ) ) + player playLocalSound( sound ); + } + } + } + else + { + if ( isdefined( excludeList ) ) + { + for ( i = 0; i < level.players.size; i++ ) + { + if ( !isExcluded( level.players[ i ], excludeList ) ) + level.players[ i ] playLocalSound( sound ); + } + } + else + { + for ( i = 0; i < level.players.size; i++ ) + level.players[ i ] playLocalSound( sound ); + } + } + } +} + + +sortLowerMessages() +{ + for ( i = 1; i < self.lowerMessages.size; i++ ) + { + message = self.lowerMessages[ i ]; + priority = message.priority; + for ( j = i - 1; j >= 0 && priority > self.lowerMessages[ j ].priority; j -- ) + self.lowerMessages[ j + 1 ] = self.lowerMessages[ j ]; + self.lowerMessages[ j + 1 ] = message; + } +} + + +addLowerMessage( name, text, time, priority ) +{ + newMessage = undefined; + foreach ( message in self.lowerMessages ) + { + if ( message.name == name ) + { + if ( message.text == text && message.priority == priority ) + return; + + newMessage = message; + break; + } + } + + if ( !isDefined( newMessage ) ) + { + newMessage = spawnStruct(); + self.lowerMessages[ self.lowerMessages.size ] = newMessage; + } + + newMessage.name = name; + newMessage.text = text; + newMessage.time = time; + newMessage.addTime = getTime(); + newMessage.priority = priority; + + sortLowerMessages(); +} + + +removeLowerMessage( name ) +{ + for ( i = 0; i < self.lowerMessages.size; i++ ) + { + if ( self.lowerMessages[ i ].name != name ) + continue; + + message = self.lowerMessages[ i ]; + if ( i < self.lowerMessages.size - 1 ) + self.lowerMessages[ i ] = self.lowerMessages[ self.lowerMessages.size - 1 ]; + + self.lowerMessages[ self.lowerMessages.size - 1 ] = undefined; + } + + sortLowerMessages(); +} + + +getLowerMessage() +{ + return self.lowerMessages[ 0 ]; +} + + +setLowerMessage( name, text, time, priority ) +{ + if ( !isDefined( priority ) ) + priority = 1; + + if ( !isDefined( time ) ) + time = 0; + + self addLowerMessage( name, text, time, priority ); + self updateLowerMessage(); + //self notify( "lower_message_set" ); +} + + +updateLowerMessage() +{ + message = self getLowerMessage(); + + if ( !isDefined( message ) ) + { + self.lowerMessage.alpha = 0; + self.lowerTimer.alpha = 0; + return; + } + + self.lowerMessage setText( message.text ); + if ( isDefined( message.time ) && message.time > 0 ) + self.lowerTimer setTimer( max( message.time - ( ( getTime() - message.addTime ) / 1000 ), 0.1 ) ); + else + self.lowerTimer setText( "" ); + + self.lowerMessage.alpha = 0.85; + self.lowerTimer.alpha = 1; +} + +clearLowerMessage( name, fadetime ) +{ + self removeLowerMessage( name ); + self updateLowerMessage(); +} + +clearLowerMessages() +{ + for ( i = 0; i < self.lowerMessages.size; i++ ) + self.lowerMessages[ i ] = undefined; + + if ( !isDefined( self.lowerMessage ) ) + return; + + self updateLowerMessage(); +} + +printOnTeam( printString, team ) +{ + foreach ( player in level.players ) + { + if ( player.team != team ) + continue; + + player iPrintLn( printString ); + } +} + +printBoldOnTeam( text, team ) +{ + assert( isdefined( level.players ) ); + for ( i = 0; i < level.players.size; i++ ) + { + player = level.players[ i ]; + if ( ( isdefined( player.pers[ "team" ] ) ) && ( player.pers[ "team" ] == team ) ) + player iprintlnbold( text ); + } +} + +printBoldOnTeamArg( text, team, arg ) +{ + assert( isdefined( level.players ) ); + for ( i = 0; i < level.players.size; i++ ) + { + player = level.players[ i ]; + if ( ( isdefined( player.pers[ "team" ] ) ) && ( player.pers[ "team" ] == team ) ) + player iprintlnbold( text, arg ); + } +} + +printOnTeamArg( text, team, arg ) +{ + assert( isdefined( level.players ) ); + for ( i = 0; i < level.players.size; i++ ) + { + player = level.players[ i ]; + if ( ( isdefined( player.pers[ "team" ] ) ) && ( player.pers[ "team" ] == team ) ) + player iprintln( text, arg ); + } +} + +printOnPlayers( text, team ) +{ + players = level.players; + for ( i = 0; i < players.size; i++ ) + { + if ( isDefined( team ) ) + { + if ( ( isdefined( players[ i ].pers[ "team" ] ) ) && ( players[ i ].pers[ "team" ] == team ) ) + players[ i ] iprintln( text ); + } + else + { + players[ i ] iprintln( text ); + } + } +} + +printAndSoundOnEveryone( team, otherteam, printFriendly, printEnemy, soundFriendly, soundEnemy, printarg ) +{ + shouldDoSounds = isDefined( soundFriendly ); + + shouldDoEnemySounds = false; + if ( isDefined( soundEnemy ) ) + { + assert( shouldDoSounds );// can't have an enemy sound without a friendly sound + shouldDoEnemySounds = true; + } + + if ( level.splitscreen || !shouldDoSounds ) + { + for ( i = 0; i < level.players.size; i++ ) + { + player = level.players[ i ]; + playerteam = player.pers[ "team" ]; + if ( isdefined( playerteam ) ) + { + if ( playerteam == team && isdefined( printFriendly ) ) + player iprintln( printFriendly, printarg ); + else if ( playerteam == otherteam && isdefined( printEnemy ) ) + player iprintln( printEnemy, printarg ); + } + } + if ( shouldDoSounds ) + { + assert( level.splitscreen ); + level.players[ 0 ] playLocalSound( soundFriendly ); + } + } + else + { + assert( shouldDoSounds ); + if ( shouldDoEnemySounds ) + { + for ( i = 0; i < level.players.size; i++ ) + { + player = level.players[ i ]; + playerteam = player.pers[ "team" ]; + if ( isdefined( playerteam ) ) + { + if ( playerteam == team ) + { + if ( isdefined( printFriendly ) ) + player iprintln( printFriendly, printarg ); + player playLocalSound( soundFriendly ); + } + else if ( playerteam == otherteam ) + { + if ( isdefined( printEnemy ) ) + player iprintln( printEnemy, printarg ); + player playLocalSound( soundEnemy ); + } + } + } + } + else + { + for ( i = 0; i < level.players.size; i++ ) + { + player = level.players[ i ]; + playerteam = player.pers[ "team" ]; + if ( isdefined( playerteam ) ) + { + if ( playerteam == team ) + { + if ( isdefined( printFriendly ) ) + player iprintln( printFriendly, printarg ); + player playLocalSound( soundFriendly ); + } + else if ( playerteam == otherteam ) + { + if ( isdefined( printEnemy ) ) + player iprintln( printEnemy, printarg ); + } + } + } + } + } +} + +printAndSoundOnTeam( team, printString, soundAlias ) +{ + foreach ( player in level.players ) + { + if ( player.team != team ) + continue; + + player printAndSoundOnPlayer( printString, soundAlias ); + } +} + +printAndSoundOnPlayer( printString, soundAlias ) +{ + self iPrintLn( printString ); + self playLocalSound( soundAlias ); +} + +_playLocalSound( soundAlias ) +{ + if ( level.splitscreen && self getEntityNumber() != 0 ) + return; + + self playLocalSound( soundAlias ); +} + +dvarIntValue( dVar, defVal, minVal, maxVal ) +{ + dVar = "scr_" + level.gameType + "_" + dVar; + if ( getDvar( dVar ) == "" ) + { + setDvar( dVar, defVal ); + return defVal; + } + + value = getDvarInt( dVar ); + + if ( value > maxVal ) + value = maxVal; + else if ( value < minVal ) + value = minVal; + else + return value; + + setDvar( dVar, value ); + return value; +} + +dvarFloatValue( dVar, defVal, minVal, maxVal ) +{ + dVar = "scr_" + level.gameType + "_" + dVar; + if ( getDvar( dVar ) == "" ) + { + setDvar( dVar, defVal ); + return defVal; + } + + value = getDvarFloat( dVar ); + + if ( value > maxVal ) + value = maxVal; + else if ( value < minVal ) + value = minVal; + else + return value; + + setDvar( dVar, value ); + return value; +} + +play_sound_on_tag( alias, tag ) +{ + if ( isdefined( tag ) ) + { + playsoundatpos( self getTagOrigin( tag ), alias ); + } + else + { + playsoundatpos( self.origin, alias ); + } +} + +getOtherTeam( team ) +{ + if ( team == "allies" ) + return "axis"; + else if ( team == "axis" ) + return "allies"; + + assertMsg( "getOtherTeam: invalid team " + team ); +} + +wait_endon( waitTime, endOnString, endonString2, endonString3 ) +{ + self endon( endOnString ); + if ( isDefined( endonString2 ) ) + self endon( endonString2 ); + if ( isDefined( endonString3 ) ) + self endon( endonString3 ); + + wait( waitTime ); +} + +isMG( weapon ) +{ + return ( isSubStr( weapon, "_bipod_" ) || weapon == "turret_minigun_mp" ); +} + +initPersStat( dataName ) +{ + if ( !isDefined( self.pers[ dataName ] ) ) + self.pers[ dataName ] = 0; +} + +getPersStat( dataName ) +{ + return self.pers[ dataName ]; +} + +incPersStat( dataName, increment ) +{ + self.pers[ dataName ] += increment; + self maps\mp\gametypes\_persistence::statAdd( dataName, increment ); +} + +setPersStat( dataName, value ) +{ + assertEx( isDefined( dataName ), "Called setPersStat with no dataName defined." ); + assertEx( isDefined( value ), "Called setPersStat for " + dataName + " with no value defined." ); + + self.pers[ dataName ] = value; +} + +initPlayerStat( ref, defaultvalue ) +{ + if ( !isDefined( self.stats["stats_" + ref ] ) ) + { + if ( !isDefined( defaultvalue ) ) + defaultvalue = 0; + + self.stats["stats_" + ref ] = spawnstruct(); + self.stats["stats_" + ref ].value = defaultvalue; + } +} + +incPlayerStat( ref, increment ) +{ + stat = self.stats["stats_" + ref ]; + stat.value += increment; +} + +setPlayerStat( ref, value ) +{ + stat = self.stats["stats_" + ref ]; + stat.value = value; + stat.time = getTime(); +} + +getPlayerStat( ref ) +{ + return self.stats["stats_" + ref ].value; +} + +getPlayerStatTime( ref ) +{ + return self.stats["stats_" + ref ].time; +} + +setPlayerStatIfGreater( ref, newvalue ) +{ + currentvalue = self getPlayerStat( ref ); + + if ( newvalue > currentvalue ) + self setPlayerStat( ref, newvalue ); +} + +setPlayerStatIfLower( ref, newvalue ) +{ + currentvalue = self getPlayerStat( ref ); + + if ( newvalue < currentvalue ) + self setPlayerStat( ref, newvalue ); +} + +updatePersRatio( ratio, num, denom ) +{ + numValue = self maps\mp\gametypes\_persistence::statGet( num ); + denomValue = self maps\mp\gametypes\_persistence::statGet( denom ); + if ( denomValue == 0 ) + denomValue = 1; + + self maps\mp\gametypes\_persistence::statSet( ratio, int( ( numValue * 1000 ) / denomValue ) ); +} + +updatePersRatioBuffered( ratio, num, denom ) +{ + numValue = self maps\mp\gametypes\_persistence::statGetBuffered( num ); + denomValue = self maps\mp\gametypes\_persistence::statGetBuffered( denom ); + if ( denomValue == 0 ) + denomValue = 1; + + self maps\mp\gametypes\_persistence::statSetBuffered( ratio, int( ( numValue * 1000 ) / denomValue ) ); +} + + +// to be used with things that are slow. +// unfortunately, it can only be used with things that aren't time critical. +WaitTillSlowProcessAllowed( allowLoop ) +{ + // wait only a few frames if necessary + // if we wait too long, we might get too many threads at once and run out of variables + // i'm trying to avoid using a loop because i don't want any extra variables + if ( level.lastSlowProcessFrame == gettime() ) + { + if ( isDefined( allowLoop ) && allowLoop ) + { + while ( level.lastSlowProcessFrame == getTime() ) + wait( 0.05 ); + } + else + { + wait .05; + if ( level.lastSlowProcessFrame == gettime() ) + { + wait .05; + if ( level.lastSlowProcessFrame == gettime() ) + { + wait .05; + if ( level.lastSlowProcessFrame == gettime() ) + { + wait .05; + } + } + } + } + } + + level.lastSlowProcessFrame = getTime(); +} + + +waitForTimeOrNotify( time, notifyname ) +{ + self endon( notifyname ); + wait time; +} + + +isExcluded( entity, entityList ) +{ + for ( index = 0; index < entityList.size; index++ ) + { + if ( entity == entityList[ index ] ) + return true; + } + return false; +} + + +leaderDialog( dialog, team, group, excludeList ) +{ + assert( isdefined( level.players ) ); + + if ( level.splitscreen ) + return; + + if ( dialog == "null" ) + return; + + if ( !isDefined( team ) ) + { + leaderDialogBothTeams( dialog, "allies", dialog, "axis", group, excludeList ); + return; + } + + if ( level.splitscreen ) + { + if ( level.players.size ) + level.players[ 0 ] leaderDialogOnPlayer( dialog, group ); + return; + } + + if ( isDefined( excludeList ) ) + { + for ( i = 0; i < level.players.size; i++ ) + { + player = level.players[ i ]; + if ( ( isDefined( player.pers[ "team" ] ) && ( player.pers[ "team" ] == team ) ) && !isExcluded( player, excludeList ) ) + player leaderDialogOnPlayer( dialog, group ); + } + } + else + { + for ( i = 0; i < level.players.size; i++ ) + { + player = level.players[ i ]; + if ( isDefined( player.pers[ "team" ] ) && ( player.pers[ "team" ] == team ) ) + player leaderDialogOnPlayer( dialog, group ); + } + } +} + + +leaderDialogBothTeams( dialog1, team1, dialog2, team2, group, excludeList ) +{ + assert( isdefined( level.players ) ); + + if ( level.splitscreen ) + return; + + if ( level.splitscreen ) + { + if ( level.players.size ) + level.players[ 0 ] leaderDialogOnPlayer( dialog1, group ); + return; + } + + if ( isDefined( excludeList ) ) + { + for ( i = 0; i < level.players.size; i++ ) + { + player = level.players[ i ]; + team = player.pers[ "team" ]; + + if ( !isDefined( team ) ) + continue; + + if ( isExcluded( player, excludeList ) ) + continue; + + if ( team == team1 ) + player leaderDialogOnPlayer( dialog1, group ); + else if ( team == team2 ) + player leaderDialogOnPlayer( dialog2, group ); + } + } + else + { + for ( i = 0; i < level.players.size; i++ ) + { + player = level.players[ i ]; + team = player.pers[ "team" ]; + + if ( !isDefined( team ) ) + continue; + + if ( team == team1 ) + player leaderDialogOnPlayer( dialog1, group ); + else if ( team == team2 ) + player leaderDialogOnPlayer( dialog2, group ); + } + } +} + + +leaderDialogOnPlayers( dialog, players, group ) +{ + foreach ( player in players ) + player leaderDialogOnPlayer( dialog, group ); +} + + +leaderDialogOnPlayer( dialog, group, groupOverride ) +{ + if ( !isDefined( groupOverride ) ) + groupOverride = false; + + team = self.pers[ "team" ]; + + if ( level.splitscreen ) + return; + + if ( !isDefined( team ) ) + return; + + if ( team != "allies" && team != "axis" ) + return; + + if ( isDefined( group ) ) + { + // ignore the message if one from the same group is already playing + if ( self.leaderDialogGroup == group ) + { + if ( groupOverride ) + { + self stopLocalSound( self.leaderDialogActive ); + self thread playLeaderDialogOnPlayer( dialog, team ); + } + + return; + } + + hadGroupDialog = isDefined( self.leaderDialogGroups[ group ] ); + + self.leaderDialogGroups[ group ] = dialog; + dialog = group; + + // exit because the "group" dialog call is already in the queue + if ( hadGroupDialog ) + return; + } + + if ( self.leaderDialogActive == "" ) + self thread playLeaderDialogOnPlayer( dialog, team ); + else + self.leaderDialogQueue[ self.leaderDialogQueue.size ] = dialog; +} + + +playLeaderDialogOnPlayer( dialog, team ) +{ + self endon( "disconnect" ); + + self notify ( "playLeaderDialogOnPlayer" ); + self endon ( "playLeaderDialogOnPlayer" ); + + if ( isDefined( self.leaderDialogGroups[ dialog ] ) ) + { + group = dialog; + dialog = self.leaderDialogGroups[ group ]; + self.leaderDialogGroups[ group ] = undefined; + self.leaderDialogGroup = group; + } + + assertEx( isDefined( game[ "dialog" ][ dialog ] ), "Dialog " + dialog + " was not defined in game[dialog] array." ); + + if ( isSubStr( game[ "dialog" ][ dialog ], "null" ) ) + return; + + self.leaderDialogActive = game[ "voice" ][ team ] + game[ "dialog" ][ dialog ]; + self playLocalSound( game[ "voice" ][ team ] + game[ "dialog" ][ dialog ] ); + + wait( 3.0 ); + self.leaderDialogLocalSound = ""; + + self.leaderDialogActive = ""; + self.leaderDialogGroup = ""; + + if ( self.leaderDialogQueue.size > 0 ) + { + nextDialog = self.leaderDialogQueue[ 0 ]; + + for ( i = 1; i < self.leaderDialogQueue.size; i++ ) + self.leaderDialogQueue[ i - 1 ] = self.leaderDialogQueue[ i ]; + self.leaderDialogQueue[ i - 1 ] = undefined; + + self thread playLeaderDialogOnPlayer( nextDialog, team ); + } +} + + +updateMainMenu() +{ + if (self.pers[ "team" ] == "spectator" ) + { + self setClientDvar("g_scriptMainMenu", game["menu_team"]); + } + else + { + self setClientDvar( "g_scriptMainMenu", game[ "menu_class_" + self.pers["team"] ] ); + } +} + + +updateObjectiveText() +{ + if ( self.pers[ "team" ] == "spectator" ) + { + self setClientDvar( "cg_objectiveText", "" ); + return; + } + + if ( getWatchedDvar( "scorelimit" ) > 0 && !isObjectiveBased() ) + { + if ( level.splitScreen ) + self setclientdvar( "cg_objectiveText", getObjectiveScoreText( self.pers[ "team" ] ) ); + else + self setclientdvar( "cg_objectiveText", getObjectiveScoreText( self.pers[ "team" ] ), getWatchedDvar( "scorelimit" ) ); + } + else + { + self setclientdvar( "cg_objectiveText", getObjectiveText( self.pers[ "team" ] ) ); + } +} + + +setObjectiveText( team, text ) +{ + game[ "strings" ][ "objective_" + team ] = text; + precacheString( text ); +} + +setObjectiveScoreText( team, text ) +{ + game[ "strings" ][ "objective_score_" + team ] = text; + precacheString( text ); +} + +setObjectiveHintText( team, text ) +{ + game[ "strings" ][ "objective_hint_" + team ] = text; + precacheString( text ); +} + +getObjectiveText( team ) +{ + return game[ "strings" ][ "objective_" + team ]; +} + +getObjectiveScoreText( team ) +{ + return game[ "strings" ][ "objective_score_" + team ]; +} + +getObjectiveHintText( team ) +{ + return game[ "strings" ][ "objective_hint_" + team ]; +} + + + +getTimePassed() +{ + if ( !isDefined( level.startTime ) ) + return 0; + + if ( level.timerStopped ) + return( level.timerPauseTime - level.startTime ) - level.discardTime; + else + return( gettime() - level.startTime ) - level.discardTime; + +} + +getSecondsPassed() +{ + return (getTimePassed() / 1000); +} + +getMinutesPassed() +{ + return (getSecondsPassed() / 60); +} + +ClearKillcamState() +{ + self.forcespectatorclient = -1; + self.killcamentity = -1; + self.archivetime = 0; + self.psoffsettime = 0; +} + +isInKillcam() +{ + return ( self.forcespectatorclient != -1 || self.killcamentity != -1 ); +} + +isValidClass( class ) +{ + return isDefined( class ) && class != ""; +} + + + +getValueInRange( value, minValue, maxValue ) +{ + if ( value > maxValue ) + return maxValue; + else if ( value < minValue ) + return minValue; + else + return value; +} + + + + +waitForTimeOrNotifies( desiredDelay ) +{ + startedWaiting = getTime(); + + waitedTime = ( getTime() - startedWaiting ) / 1000; + + if ( waitedTime < desiredDelay ) + { + wait desiredDelay - waitedTime; + return desiredDelay; + } + else + { + return waitedTime; + } +} + +closeMenus() +{ + self closepopupMenu(); + self closeInGameMenu(); +} + + +logXPGains() +{ + if ( !isDefined( self.xpGains ) ) + return; + + xpTypes = getArrayKeys( self.xpGains ); + for ( index = 0; index < xpTypes.size; index++ ) + { + gain = self.xpGains[ xpTypes[ index ] ]; + if ( !gain ) + continue; + + self logString( "xp " + xpTypes[ index ] + ": " + gain ); + } +} + + +registerRoundSwitchDvar( dvarString, defaultValue, minValue, maxValue ) +{ + registerWatchDvarInt( "roundswitch", defaultValue ); + + dvarString = ( "scr_" + dvarString + "_roundswitch" ); + + level.roundswitchDvar = dvarString; + level.roundswitchMin = minValue; + level.roundswitchMax = maxValue; + level.roundswitch = getDvarInt( dvarString, defaultValue ); + + if ( level.roundswitch < minValue ) + level.roundswitch = minValue; + else if ( level.roundswitch > maxValue ) + level.roundswitch = maxValue; +} + + +registerRoundLimitDvar( dvarString, defaultValue, minValue, maxValue ) +{ + registerWatchDvarInt( "roundlimit", defaultValue ); +} + + +registerWinLimitDvar( dvarString, defaultValue, minValue, maxValue ) +{ + registerWatchDvarInt( "winlimit", defaultValue ); +} + + +registerScoreLimitDvar( dvarString, defaultValue, minValue, maxValue ) +{ + registerWatchDvarInt( "scorelimit", defaultValue ); +} + + +registerTimeLimitDvar( dvarString, defaultValue, minValue, maxValue ) +{ + registerWatchDvarFloat( "timelimit", defaultValue ); + makeDvarServerInfo( "ui_timelimit", getTimeLimit() ); +} + +registerHalfTimeDvar( dvarString, defaultValue, minValue, maxValue) +{ + registerWatchDvarInt( "halftime", defaultValue ); + makeDvarServerInfo( "ui_halftime", getHalfTime() ); +} + +registerNumLivesDvar( dvarString, defaultValue, minValue, maxValue ) +{ + registerWatchDvarInt( "numlives", defaultValue ); +} + +setOverTimeLimitDvar( value ) +{ + makeDvarServerInfo( "overtimeTimeLimit", value ); +} + +get_damageable_player( player, playerpos ) +{ + newent = spawnstruct(); + newent.isPlayer = true; + newent.isADestructable = false; + newent.entity = player; + newent.damageCenter = playerpos; + return newent; +} + +get_damageable_sentry( sentry, sentryPos ) +{ + newent = spawnstruct(); + newent.isPlayer = false; + newent.isADestructable = false; + newent.isSentry = true; + newent.entity = sentry; + newent.damageCenter = sentryPos; + return newent; +} + +get_damageable_grenade( grenade, entpos ) +{ + newent = spawnstruct(); + newent.isPlayer = false; + newent.isADestructable = false; + newent.entity = grenade; + newent.damageCenter = entpos; + return newent; +} + +get_damageable_player_pos( player ) +{ + return player.origin + ( 0, 0, 32 ); +} + +get_damageable_grenade_pos( grenade ) +{ + return grenade.origin; +} + +// this should be a code function. +getDvarVec( dvarName ) +{ + dvarString = getDvar( dvarName ); + + if ( dvarString == "" ) + return( 0, 0, 0 ); + + dvarTokens = strTok( dvarString, " " ); + + if ( dvarTokens.size < 3 ) + return( 0, 0, 0 ); + + setDvar( "tempR", dvarTokens[ 0 ] ); + setDvar( "tempG", dvarTokens[ 1 ] ); + setDvar( "tempB", dvarTokens[ 2 ] ); + + return( ( getDvarFloat( "tempR" ), getDvarFloat( "tempG" ), getDvarFloat( "tempB" ) ) ); +} + +strip_suffix( lookupString, stripString ) +{ + if ( lookupString.size <= stripString.size ) + return lookupString; + + if ( getSubStr( lookupString, lookupString.size - stripString.size, lookupString.size ) == stripString ) + return getSubStr( lookupString, 0, lookupString.size - stripString.size ); + + return lookupString; +} + +_takeWeaponsExcept( saveWeapon ) +{ + weaponsList = self GetWeaponsListAll(); + + foreach ( weapon in weaponsList ) + { + if ( weapon == saveWeapon ) + { + continue; + } + else + { + self takeWeapon( weapon ); + } + } +} + +saveData() +{ + saveData = spawnstruct(); + + saveData.offhandClass = self getOffhandSecondaryClass(); + saveData.actionSlots = self.saved_actionSlotData; + + saveData.currentWeapon = self getCurrentWeapon(); + + weaponsList = self GetWeaponsListAll(); + saveData.weapons = []; + foreach ( weapon in weaponsList ) + { + if ( weaponInventoryType( weapon ) == "exclusive" ) + continue; + + if ( weaponInventoryType( weapon ) == "altmode" ) + continue; + + saveWeapon = spawnStruct(); + saveWeapon.name = weapon; + saveWeapon.clipAmmoR = self getWeaponAmmoClip( weapon, "right" ); + saveWeapon.clipAmmoL = self getWeaponAmmoClip( weapon, "left" ); + saveWeapon.stockAmmo = self getWeaponAmmoStock( weapon ); + /* save camo? */ + + if ( isDefined( self.throwingGrenade ) && self.throwingGrenade == weapon ) + saveWeapon.stockAmmo--; + + assert( saveWeapon.stockAmmo >= 0 ); + + saveData.weapons[saveData.weapons.size] = saveWeapon; + } + + self.script_saveData = saveData; +} + + +restoreData() +{ + saveData = self.script_saveData; + + self setOffhandSecondaryClass( saveData.offhandClass ); + + foreach ( weapon in saveData.weapons ) + { + //if ( weapon.name == self.loadoutPrimary + "_mp" ) + self _giveWeapon( weapon.name, int(tableLookup( "mp/camoTable.csv", 1, self.loadoutPrimaryCamo, 0 )) ); + //else + //self _giveWeapon( weapon.name ); + + self setWeaponAmmoClip( weapon.name, weapon.clipAmmoR, "right" ); + if ( isSubStr( weapon.name, "akimbo" ) ) + self setWeaponAmmoClip( weapon.name, weapon.clipAmmoL, "left" ); + + self setWeaponAmmoStock( weapon.name, weapon.stockAmmo ); + } + + foreach ( slotID, actionSlot in saveData.actionSlots ) + self _setActionSlot( slotID, actionSlot.type, actionSlot.item ); + + if ( self getCurrentWeapon() == "none" ) + { + weapon = saveData.currentWeapon; + + if ( weapon == "none" ) + weapon = self getLastWeapon(); + + // Can remove this when "spawn" isn't used after final stand + self setSpawnWeapon( weapon ); + self switchToWeapon( weapon ); + } +} + + +_setActionSlot( slotID, type, item ) +{ + self.saved_actionSlotData[slotID].type = type; + self.saved_actionSlotData[slotID].item = item; + + self setActionSlot( slotID, type, item ); +} + + +isFloat( value ) +{ + if ( int( value ) != value ) + return true; + + return false; +} + +registerWatchDvarInt( nameString, defaultValue ) +{ + dvarString = "scr_" + level.gameType + "_" + nameString; + + level.watchDvars[ dvarString ] = spawnStruct(); + level.watchDvars[ dvarString ].value = getDvarInt( dvarString, defaultValue ); + level.watchDvars[ dvarString ].type = "int"; + level.watchDvars[ dvarString ].notifyString = "update_" + nameString; +} + + +registerWatchDvarFloat( nameString, defaultValue ) +{ + dvarString = "scr_" + level.gameType + "_" + nameString; + + level.watchDvars[ dvarString ] = spawnStruct(); + level.watchDvars[ dvarString ].value = getDvarFloat( dvarString, defaultValue ); + level.watchDvars[ dvarString ].type = "float"; + level.watchDvars[ dvarString ].notifyString = "update_" + nameString; +} + + +registerWatchDvar( nameString, defaultValue ) +{ + dvarString = "scr_" + level.gameType + "_" + nameString; + + level.watchDvars[ dvarString ] = spawnStruct(); + level.watchDvars[ dvarString ].value = getDvar( dvarString, defaultValue ); + level.watchDvars[ dvarString ].type = "string"; + level.watchDvars[ dvarString ].notifyString = "update_" + nameString; +} + + +getWatchedDvar( dvarString ) +{ + dvarString = "scr_" + level.gameType + "_" + dvarString; + return( level.watchDvars[ dvarString ].value ); +} + + +updateWatchedDvars() +{ + while ( game[ "state" ] == "playing" ) + { + watchDvars = getArrayKeys( level.watchDvars ); + + foreach ( dvarString in watchDvars ) + { + if ( level.watchDvars[ dvarString ].type == "string" ) + dvarValue = getProperty( dvarString, level.watchDvars[ dvarString ].value ); + else if ( level.watchDvars[ dvarString ].type == "float" ) + dvarValue = getFloatProperty( dvarString, level.watchDvars[ dvarString ].value ); + else + dvarValue = getIntProperty( dvarString, level.watchDvars[ dvarString ].value ); + + if ( dvarValue != level.watchDvars[ dvarString ].value ) + { + level.watchDvars[ dvarString ].value = dvarValue; + level notify( level.watchDvars[ dvarString ].notifyString, dvarValue ); + } + } + + wait( 1.0 ); + } +} + + +isRoundBased() +{ + if ( !level.teamBased ) + return false; + + if ( getWatchedDvar( "winlimit" ) != 1 && getWatchedDvar( "roundlimit" ) != 1 ) + return true; + + return false; +} + + +isLastRound() +{ + if ( !level.teamBased ) + return true; + + if ( getWatchedDvar( "roundlimit" ) > 1 && game[ "roundsPlayed" ] >= ( getWatchedDvar( "roundlimit" ) - 1 ) ) + return true; + + if ( getWatchedDvar( "winlimit" ) > 1 && game[ "roundsWon" ][ "allies" ] >= getWatchedDvar( "winlimit" ) - 1 && game[ "roundsWon" ][ "axis" ] >= getWatchedDvar( "winlimit" ) - 1 ) + return true; + + return false; +} + + +wasOnlyRound() +{ + if ( !level.teamBased ) + return true; + + if ( getWatchedDvar( "winlimit" ) == 1 && hitWinLimit() ) + return true; + + if ( getWatchedDvar( "roundlimit" ) == 1 ) + return true; + + return false; +} + + +wasLastRound() +{ + if ( level.forcedEnd ) + return true; + + if ( !level.teamBased ) + return true; + + if ( hitRoundLimit() || hitWinLimit() ) + return true; + + return false; +} + + +hitRoundLimit() +{ + if ( getWatchedDvar( "roundlimit" ) <= 0 ) + return false; + + return( game[ "roundsPlayed" ] >= getWatchedDvar( "roundlimit" ) ); +} + + +hitScoreLimit() +{ + if ( isObjectiveBased() ) + return false; + + if ( getWatchedDvar( "scorelimit" ) <= 0 ) + return false; + + if ( level.teamBased ) + { + if ( game[ "teamScores" ][ "allies" ] >= getWatchedDvar( "scorelimit" ) || game[ "teamScores" ][ "axis" ] >= getWatchedDvar( "scorelimit" ) ) + return true; + } + else + { + for ( i = 0; i < level.players.size; i++ ) + { + player = level.players[ i ]; + if ( isDefined( player.score ) && player.score >= getWatchedDvar( "scorelimit" ) ) + return true; + } + } + return false; +} + + +hitWinLimit() +{ + if ( getWatchedDvar( "winlimit" ) <= 0 ) + return false; + + if ( !level.teamBased ) + return true; + + if ( getRoundsWon( "allies" ) >= getWatchedDvar( "winlimit" ) || getRoundsWon( "axis" ) >= getWatchedDvar( "winlimit" ) ) + return true; + + return false; +} + + +getScoreLimit() +{ + if ( isRoundBased() ) + { + if ( getWatchedDvar( "roundlimit" ) ) + return ( getWatchedDvar( "roundlimit" ) ); + else + return ( getWatchedDvar( "winlimit" ) ); + } + else + { + return ( getWatchedDvar( "scorelimit" ) ); + } +} + + +getRoundsWon( team ) +{ + return game[ "roundsWon" ][ team ]; +} + + +isObjectiveBased() +{ + return level.objectiveBased; +} + + +getTimeLimit() +{ + if ( inOvertime() && ( !isDefined(game[ "inNukeOvertime" ]) || !game[ "inNukeOvertime" ] ) ) + { + timeLimit = int( getDvar( "overtimeTimeLimit" ) ); + + if ( isDefined( timeLimit ) ) + return timeLimit; + else + return 1; + } + else if ( isDefined(level.dd) && level.dd && isDefined( level.bombexploded ) && level.bombexploded > 0 ) //to handle extra time added by dd bombs + { + return ( getWatchedDvar( "timelimit" ) + ( level.bombexploded * level.ddTimeToAdd ) ); + } + else + { + return getWatchedDvar( "timelimit" ); + } +} + + +getHalfTime() +{ + if ( inOvertime() ) + return false; + else if ( isDefined( game[ "inNukeOvertime" ] ) && game[ "inNukeOvertime" ] ) + return false; + else + return getWatchedDvar( "halftime" ); +} + + +inOvertime() +{ + return ( isDefined( game["status"] ) && game["status"] == "overtime" ); +} + + +gameHasStarted() +{ + if ( level.teamBased ) + return( level.hasSpawned[ "axis" ] && level.hasSpawned[ "allies" ] ); + else + return( level.maxPlayerCount > 1 ); +} + + +getAverageOrigin( ent_array ) +{ + avg_origin = ( 0, 0, 0 ); + + if ( !ent_array.size ) + return undefined; + + foreach ( ent in ent_array ) + avg_origin += ent.origin; + + avg_x = int( avg_origin[ 0 ] / ent_array.size ); + avg_y = int( avg_origin[ 1 ] / ent_array.size ); + avg_z = int( avg_origin[ 2 ] / ent_array.size ); + + avg_origin = ( avg_x, avg_y, avg_z ); + + return avg_origin; +} + + +getLivingPlayers( team ) +{ + player_array = []; + + foreach ( player in level.players ) + { + if ( !isAlive( player ) ) + continue; + + if ( level.teambased && isdefined( team ) ) + { + if ( team == player.pers[ "team" ] ) + player_array[ player_array.size ] = player; + } + else + { + player_array[ player_array.size ] = player; + } + } + + return player_array; +} + + +setUsingRemote( remoteName ) +{ + if ( isDefined( self.carryIcon) ) + self.carryIcon.alpha = 0; + + assert( !self isUsingRemote() ); + self.usingRemote = remoteName; + + self _disableOffhandWeapons(); + self notify( "using_remote" ); +} + +getRemoteName() +{ + assert( self isUsingRemote() ); + + return self.usingRemote; +} + +freezeControlsWrapper( frozen ) +{ + if ( isDefined( level.hostMigrationTimer ) ) + { + self freezeControls( true ); + return; + } + + self freezeControls( frozen ); +} + + +clearUsingRemote() +{ + //if ( !isWeaponEnabled() ) + // self disableWeapons(); + + if ( isDefined( self.carryIcon) ) + self.carryIcon.alpha = 1; + + self.usingRemote = undefined; + self _enableOffhandWeapons(); + + curWeapon = self getCurrentWeapon(); + + if( curWeapon == "none" || isKillstreakWeapon( curWeapon ) ) + self switchToWeapon( self Getlastweapon() ); + + self freezeControlsWrapper( false ); + + self notify( "stopped_using_remote" ); +} + + +isUsingRemote() +{ + return( isDefined( self.usingRemote ) ); +} + + +queueCreate( queueName ) +{ + if ( !isDefined( level.queues ) ) + level.queues = []; + + assert( !isDefined( level.queues[ queueName ] ) ); + + level.queues[ queueName ] = []; +} + + +queueAdd( queueName, entity ) +{ + assert( isDefined( level.queues[ queueName ] ) ); + level.queues[ queueName ][ level.queues[ queueName ].size ] = entity; +} + + +queueRemoveFirst( queueName ) +{ + assert( isDefined( level.queues[ queueName ] ) ); + + first = undefined; + newQueue = []; + foreach ( element in level.queues[ queueName ] ) + { + if ( !isDefined( element ) ) + continue; + + if ( !isDefined( first ) ) + first = element; + else + newQueue[ newQueue.size ] = element; + } + + level.queues[ queueName ] = newQueue; + + return first; +} + + +_giveWeapon( weapon, variant, dualWieldOverRide ) +{ + if ( !isDefined(variant) ) + variant = 0; + + if ( isSubstr( weapon, "_akimbo" ) || isDefined(dualWieldOverRide) && dualWieldOverRide == true) + self giveWeapon(weapon, variant, true); + else + self giveWeapon(weapon, variant, false); +} + +_hasPerk( perkName ) +{ + if ( isDefined( self.perks[perkName] ) ) + return true; + + return false; +} + + +_setPerk( perkName ) +{ + self.perks[perkName] = true; + + if ( isDefined( level.perkSetFuncs[perkName] ) ) + self thread [[level.perkSetFuncs[perkName]]](); + + self setPerk( perkName, !isDefined( level.scriptPerks[perkName] ) ); +} + + +_unsetPerk( perkName ) +{ + self.perks[perkName] = undefined; + + if ( isDefined( level.perkUnsetFuncs[perkName] ) ) + self thread [[level.perkUnsetFuncs[perkName]]](); + + self unsetPerk( perkName, !isDefined( level.scriptPerks[perkName] ) ); +} + + +_clearPerks() +{ + foreach ( perkName, perkValue in self.perks ) + { + if ( isDefined( level.perkUnsetFuncs[perkName] ) ) + self [[level.perkUnsetFuncs[perkName]]](); + } + + self.perks = []; + self clearPerks(); +} + +// Quick Sort - pass it an array it will come back sorted +quickSort(array) +{ + return quickSortMid(array, 0, array.size -1 ); +} + +quickSortMid(array, start, end) +{ + i = start; + k = end; + + if (end - start >= 1) + { + pivot = array[start]; + + while (k > i) + { + while (array[i] <= pivot && i <= end && k > i) + i++; + while (array[k] > pivot && k >= start && k >= i) + k--; + if (k > i) + array = swap(array, i, k); + } + array = swap(array, start, k); + array = quickSortMid(array, start, k - 1); + array = quickSortMid(array, k + 1, end); + } + else + return array; + + return array; +} + +swap(array, index1, index2) +{ + temp = array[index1]; + array[index1] = array[index2]; + array[index2] = temp; + return array; +} + +_suicide() +{ + if ( self isUsingRemote() && !isDefined( self.fauxDead ) ) + self thread maps\mp\gametypes\_damage::PlayerKilled_internal( self, self, self, 10000, "MOD_SUICIDE", "frag_grenade_mp", (0,0,0), "none", 0, 1116, true ); + else if( !self isUsingRemote() && !isDefined( self.fauxDead ) ) + self suicide(); +} + +isReallyAlive( player ) +{ + if ( isAlive( player ) && !isDefined( player.fauxDead ) ) + return true; + + return false; +} + +playDeathSound() +{ + rand = RandomIntRange( 1,8 ); + + if ( self.team == "axis" ) + self PlaySound( "generic_death_russian_"+ rand ); + else + self PlaySound( "generic_death_american_"+ rand ); + +} + + +rankingEnabled() +{ + assert( isPlayer( self ) ); + return ( level.rankedMatch && !self.usingOnlineDataOffline ); +} + +// only true for private match +privateMatch() +{ + return ( level.onlineGame && getDvarInt( "xblive_privatematch" ) ); +} + +// only true for playlist based LIVE and PSN games +matchMakingGame() +{ + return ( level.onlineGame && !getDvarInt( "xblive_privatematch" ) ); +} + +setAltSceneObj( object, tagName, fov, forceLink ) +{ + /* + if ( !isDefined( forceLink ) ) + forceLink = false; + + if ( !getDvarInt( "scr_pipmode" ) && !forceLink ) + return; + + self endon ( "disconnect" ); + + if ( !isReallyAlive( self ) ) + return; + + if ( !forceLink && isDefined( self.altSceneObject ) ) + return; + + self notify ( "altscene" ); + + self.altSceneObject = object; + + self AlternateSceneCameraLinkTo( object, tagName, fov ); + self setClientDvar( "ui_altscene", 1 ); + + self thread endSceneOnDeath( object ); + self thread endSceneOnDeath( self ); + + self waittill ( "end_altScene" ); + + self.altSceneObject = undefined; + self AlternateSceneCameraUnlink(); + + if ( !forceLink ) + { + self setClientDvar( "ui_altscene", 2 ); + + self endon ( "altscene" ); + wait ( 2.0 ); + } + self setClientDvar( "ui_altscene", 0 ); + */ +} + + +endSceneOnDeath( object ) +{ + self endon ( "altscene" ); + + object waittill ( "death" ); + self notify ( "end_altScene" ); +} + + +getGametypeNumLives() +{ + //commented out to allow diehardhard rules to support mulitiple life gametypes + //if ( level.dieHardMode && !getWatchedDvar( "numlives" ) ) + // return 1; + //else + return getWatchedDvar( "numlives" ); +} + + +registerAdrenalineInfo( type, value ) +{ + if ( !isDefined( level.adrenalineInfo ) ) + level.adrenalineInfo = []; + + level.adrenalineInfo[type] = value; +} + + +giveAdrenaline( type ) +{ + /* + if ( self.adrenaline >= 1000 ) + return; + + assertEx( isDefined( level.adrenalineInfo[type] ), "Unknown adrenaline type: " + type ); + + printLn( "setting: " + type + " " + level.adrenalineInfo[type] ); + + self setAdrenaline( self.adrenaline + level.adrenalineInfo[type] ); + + if ( self.adrenaline == 1000 ) + { + + giveCombatHigh( "specialty_endgame" ); + } + */ +} + + +setAdrenaline( value ) +{ + self.adrenaline = min( value, 1000 ); + self setClientDvar( "ui_adrenaline", self.adrenaline ); + + if ( self.adrenaline < 1000 ) + self.combatHigh = undefined; +} + + +giveCombatHigh( combatHighName ) +{ + self.combatHigh = combatHighName; +} + + +arrayInsertion( array, item, index ) +{ + if ( array.size != 0 ) + { + for ( i = array.size; i >= index; i-- ) + { + array[i+1] = array[i]; + } + } + + array[index] = item; +} + + +getProperty( dvar, defValue ) +{ + value = defValue; + /# + setDevDvarIfUninitialized( dvar, defValue ); + #/ + + value = getDvar( dvar, defValue ); + return value; +} + + +getIntProperty( dvar, defValue ) +{ + value = defValue; + + /# + setDevDvarIfUninitialized( dvar, defValue ); + #/ + + value = getDvarInt( dvar, defValue ); + return value; +} + + +getFloatProperty( dvar, defValue ) +{ + value = defValue; + /# + setDevDvarIfUninitialized( dvar, defValue ); + #/ + + value = getDvarFloat( dvar, defValue ); + return value; +} + + + +statusMenu( duration ) +{ + self endon ( "disconnect" ); + + if ( !isDefined( self._statusMenu ) ) + self.statusMenu = false; + + if ( self.statusMenu ) + return; + + self.statusMenu = true; + + self openpopupMenu( "status_update" ); + + wait ( duration ); + + self closepopupMenu( "status_update" ); + + // debounce + wait ( 10.0 ); + + self.statusMenu = false; +} + +isChangingWeapon() +{ + return ( isDefined( self.changingWeapon ) ); +} + +isKillstreakWeapon( weapon ) +{ + if ( weapon == "none" ) + return false; + + if ( weaponInventoryType( weapon ) == "exclusive" && weapon != "destructible_car" ) + return true; + + if ( isSubStr( weapon, "killstreak" ) ) + return true; + + switch ( weapon ) + { + case "airdrop_sentry_marker_mp": + case "airdrop_mega_marker_mp": + case "airdrop_marker_mp": + case "cobra_player_minigun_mp": // Chopper Gunner + case "artillery_mp": // Precision Airstrike + case "stealth_bomb_mp": // Stealth Bomber + case "pavelow_minigun_mp": // Pave Low + case "sentry_minigun_mp": // Sentry Gun + case "harrier_20mm_mp": // Harrier Strike + case "ac130_105mm_mp": // AC130 + case "ac130_40mm_mp": // AC130 + case "ac130_25mm_mp": // AC130 + case "remotemissile_projectile_mp": // Hellfire + case "cobra_20mm_mp": // Attack Helicopter + case "nuke_mp": // Nuke + return true; + default: + return false; + } +} + + +getWeaponClass( weapon ) +{ + tokens = strTok( weapon, "_" ); + + weaponClass = tablelookup( "mp/statstable.csv", 4, tokens[0], 2 ); + + // handle special case weapons like grenades, airdrop markers, etc... + if ( weaponClass == "" ) + { + weaponName = strip_suffix( weapon, "_mp" ); + weaponClass = tablelookup( "mp/statstable.csv", 4, weaponName, 2 ); + } + + if ( isMG( weapon ) ) + weaponClass = "weapon_mg"; + else if ( isKillstreakWeapon( weapon ) ) + weaponClass = "killstreak"; + else if ( isDeathStreakWeapon( weapon ) ) + weaponClass = "deathstreak"; + else if ( weapon == "none" ) //airdrop crates + weaponClass = "other"; + else if ( weaponClass == "" ) + weaponClass = "other"; + + assertEx( weaponClass != "", "ERROR: invalid weapon class for weapon " + weapon ); + + return weaponClass; +} + +isDeathStreakWeapon( weapon ) +{ + if( weapon == "c4death_mp" || weapon == "frag_grenade_short_mp" ) + return true; + else + return false; +} + +getBaseWeaponName( weaponName ) +{ + tokens = strTok( weaponName, "_" ); + return tokens[0]; +} + +playSoundinSpace( alias, origin ) +{ + playSoundAtPos( origin, alias ); +} + +limitDecimalPlaces( value, places ) +{ + modifier = 1; + for ( i = 0; i < places; i++ ) + modifier *= 10; + + newvalue = value * modifier; + newvalue = Int( newvalue ); + newvalue = newvalue / modifier; + + return newvalue; +} + +roundDecimalPlaces( value, places, style ) +{ + if ( !isdefined( style ) ) + style = "nearest"; + + modifier = 1; + for ( i = 0; i < places; i++ ) + modifier *= 10; + + newValue = value * modifier; + + if ( style == "up" ) + roundedValue = ceil( newValue ); + else if ( style == "down" ) + roundedValue = floor( newValue ); + else + roundedValue = newvalue + 0.5; + + newvalue = Int( roundedValue ); + newvalue = newvalue / modifier; + + return newvalue; +} + +playerForClientId( clientId ) +{ + foreach ( player in level.players ) + { + if ( player.clientId == clientId ) + return player; + } + + return undefined; +} + +isRested() +{ + if ( !self rankingEnabled() ) + return false; + + return ( self getPlayerData( "restXPGoal" ) > self getPlayerData( "experience" ) ); +} + +stringToFloat( stringVal ) +{ + floatElements = strtok( stringVal, "." ); + + floatVal = int( floatElements[0] ); + if ( isDefined( floatElements[1] ) ) + { + modifier = 1; + for ( i = 0; i < floatElements[1].size; i++ ) + modifier *= 0.1; + + floatVal += int ( floatElements[1] ) * modifier; + } + + return floatVal; +} + +setSelfUsable(caller) +{ + self makeUsable(); + + foreach (player in level.players) + { + if (player != caller ) + self disablePlayerUse( player ); + else + self enablePlayerUse( player ); + } +} + +makeTeamUsable( team ) +{ + self makeUsable(); + self thread _updateTeamUsable( team ); +} + +_updateTeamUsable( team ) +{ + self endon ( "death" ); + + for ( ;; ) + { + foreach (player in level.players) + { + if ( player.team == team ) + self enablePlayerUse( player ); + else + self disablePlayerUse( player ); + } + + level waittill ( "joined_team" ); + } +} + +// More general version of makeTeamUsable() which handles FFA +makeEnemyUsable( owner ) +{ + self makeUsable(); + self thread _updateEnemyUsable( owner ); +} + +// Only used for Tactical Insertion for now +// If used for other things, handle owner disappearing or changing team +_updateEnemyUsable( owner ) +{ + // check what happens if the owner leaves + + self endon ( "death" ); + + team = owner.team; + + for ( ;; ) + { + if ( level.teambased ) + { + foreach (player in level.players) + { + if ( player.team != team ) + self enablePlayerUse( player ); + else + self disablePlayerUse( player ); + } + } + else + { + foreach (player in level.players) + { + if ( player != owner ) + self enablePlayerUse( player ); + else + self disablePlayerUse( player ); + } + } + + level waittill ( "joined_team" ); + } +} + +getNextLifeId() +{ + lifeId = getMatchData( "lifeCount" ); + if ( lifeId < level.MaxLives ) + setMatchData( "lifeCount", lifeId+1 ); + + return ( lifeId ); +} + +initGameFlags() +{ + if ( !isDefined( game["flags"] ) ) + game["flags"] = []; +} + +gameFlagInit( flagName, isEnabled ) +{ + assert( isDefined( game["flags"] ) ); + game["flags"][flagName] = isEnabled; +} + +gameFlag( flagName ) +{ + assertEx( isDefined( game["flags"][flagName] ), "gameFlag " + flagName + " referenced without being initialized; usegameFlagInit( , )" ); + return ( game["flags"][flagName] ); +} + +gameFlagSet( flagName ) +{ + assertEx( isDefined( game["flags"][flagName] ), "gameFlag " + flagName + " referenced without being initialized; usegameFlagInit( , )" ); + game["flags"][flagName] = true; + + level notify ( flagName ); +} + +gameFlagClear( flagName ) +{ + assertEx( isDefined( game["flags"][flagName] ), "gameFlag " + flagName + " referenced without being initialized; usegameFlagInit( , )" ); + game["flags"][flagName] = false; +} + +gameFlagWait( flagName ) +{ + assertEx( isDefined( game["flags"][flagName] ), "gameFlag " + flagName + " referenced without being initialized; usegameFlagInit( , )" ); + while ( !gameFlag( flagName ) ) + level waittill ( flagName ); +} + +// including grenade launcher, grenade, RPG, C4, claymore +isExplosiveDamage( meansofdeath ) +{ + explosivedamage = "MOD_GRENADE MOD_GRENADE_SPLASH MOD_PROJECTILE MOD_PROJECTILE_SPLASH MOD_EXPLOSIVE mod_explosive"; + if( isSubstr( explosivedamage, meansofdeath ) ) + return true; + return false; +} + +// if primary weapon damage +isPrimaryDamage( meansofdeath ) +{ + // including pistols as well since sometimes they share ammo + if( meansofdeath == "MOD_RIFLE_BULLET" || meansofdeath == "MOD_PISTOL_BULLET" || meansofdeath == "MOD_EXPLOSIVE_BULLET" ) + return true; + return false; +} + + +initLevelFlags() +{ + if ( !isDefined( level.levelFlags ) ) + level.levelFlags = []; +} + +levelFlagInit( flagName, isEnabled ) +{ + assert( isDefined( level.levelFlags ) ); + level.levelFlags[flagName] = isEnabled; +} + +levelFlag( flagName ) +{ + assertEx( isDefined( level.levelFlags[flagName] ), "levelFlag " + flagName + " referenced without being initialized; use levelFlagInit( , )" ); + return ( level.levelFlags[flagName] ); +} + +levelFlagSet( flagName ) +{ + assertEx( isDefined( level.levelFlags[flagName] ), "levelFlag " + flagName + " referenced without being initialized; use levelFlagInit( , )" ); + level.levelFlags[flagName] = true; + + level notify ( flagName ); +} + +levelFlagClear( flagName ) +{ + assertEx( isDefined( level.levelFlags[flagName] ), "levelFlag " + flagName + " referenced without being initialized; use levelFlagInit( , )" ); + level.levelFlags[flagName] = false; + + level notify ( flagName ); +} + +levelFlagWait( flagName ) +{ + assertEx( isDefined( level.levelFlags[flagName] ), "levelFlag " + flagName + " referenced without being initialized; use levelFlagInit( , )" ); + while ( !levelFlag( flagName ) ) + level waittill ( flagName ); +} + +levelFlagWaitOpen( flagName ) +{ + assertEx( isDefined( level.levelFlags[flagName] ), "levelFlag " + flagName + " referenced without being initialized; use levelFlagInit( , )" ); + while ( levelFlag( flagName ) ) + level waittill ( flagName ); +} + +getWeaponAttachments( weapon ) +{ + tokenizedWeapon = strTok( weapon, "_" ); + attachmentArray = []; + + if( tokenizedWeapon.size < 3 || tokenizedWeapon[1] == "_mp" ) + { + attachmentArray[0] = "none"; + } + else if( tokenizedWeapon.size > 3 ) + { + attachmentArray[0] = tokenizedWeapon[1]; + attachmentArray[1] = tokenizedWeapon[2]; + } + else + { + attachmentArray[0] = tokenizedWeapon[1]; + } + + return attachmentArray; +} + +isEMPed() +{ + if ( self.team == "spectator" ) + return false; + + if ( level.teamBased ) + return ( level.teamEMPed[self.team] ); + else + return ( isDefined( level.empPlayer ) && level.empPlayer != self ); +} + +isNuked() +{ + if ( self.team == "spectator" ) + return false; + + return ( isDefined( self.nuked ) ); +} + +isBulletDamage( meansofdeath ) +{ + bulletDamage = "MOD_RIFLE_BULLET MOD_PISTOL_BULLET MOD_HEADSHOT"; + if( isSubstr( bulletDamage, meansofdeath ) ) + return true; + return false; +} + + +getPlayerForGuid( guid ) +{ + foreach ( player in level.players ) + { + if ( player.guid == guid ) + return player; + } + + return undefined; +} + +teamPlayerCardSplash( splash, owner, team ) +{ + if ( level.hardCoreMode ) + return; + + foreach ( player in level.players ) + { + if ( isDefined( team ) && player.team != team ) + continue; + + player thread maps\mp\gametypes\_hud_message::playerCardSplashNotify( splash, owner ); + } +} + + +isCACPrimaryWeapon( weapName ) +{ + switch ( getWeaponClass( weapName ) ) + { + case "weapon_smg": + case "weapon_assault": + case "weapon_riot": + case "weapon_sniper": + case "weapon_lmg": + return true; + default: + return false; + } +} + + +isCACSecondaryWeapon( weapName ) +{ + switch ( getWeaponClass( weapName ) ) + { + case "weapon_projectile": + case "weapon_pistol": + case "weapon_machine_pistol": + case "weapon_shotgun": + return true; + default: + return false; + } +} + + +getLastLivingPlayer( team ) +{ + livePlayer = undefined; + + foreach ( player in level.players ) + { + if ( isDefined( team ) && player.team != team ) + continue; + + if ( !isReallyAlive( player ) && !player maps\mp\gametypes\_playerlogic::maySpawn() ) + continue; + + assertEx( !isDefined( livePlayer ), "getLastLivingPlayer() found more than one live player on team." ); + + livePlayer = player; + } + + return livePlayer; +} + + +getPotentialLivingPlayers() +{ + livePlayers = []; + + foreach ( player in level.players ) + { + if ( !isReallyAlive( player ) && !player maps\mp\gametypes\_playerlogic::maySpawn() ) + continue; + + livePlayers[livePlayers.size] = player; + } + + return livePlayers; +} + + +waitTillRecoveredHealth( time, interval ) +{ + self endon("death"); + self endon("disconnect"); + + fullHealthTime = 0; + + if( !isDefined( interval ) ) + interval = .05; + + if( !isDefined( time ) ) + time = 0; + + while(1) + { + if ( self.health != self.maxhealth ) + fullHealthTime = 0; + else + fullHealthTime += interval; + + wait interval; + + if ( self.health == self.maxhealth && fullHealthTime >= time ) + break; + } + + return; +} + +_objective_delete( objID ) +{ + objective_delete( objID); + + if ( !isDefined( level.reclaimedReservedObjectives ) ) + { + level.reclaimedReservedObjectives = []; + level.reclaimedReservedObjectives[0] = objID; + } + else + { + level.reclaimedReservedObjectives[ level.reclaimedReservedObjectives.size ] = objID; + } +} + + +touchingBadTrigger() +{ + killTriggers = getEntArray( "trigger_hurt", "classname" ); + foreach ( trigger in killTriggers ) + { + if ( self isTouching( trigger ) ) + return true; + } + + radTriggers = getEntArray( "radiation", "targetname" ); + foreach ( trigger in radTriggers ) + { + if ( self isTouching( trigger ) ) + return true; + } + + return false; +} + +setThirdPersonDOF( isEnabled ) +{ + if ( isEnabled ) + self setDepthOfField( 0, 110, 512, 4096, 6, 1.8 ); + else + self setDepthOfField( 0, 0, 512, 512, 4, 0 ); +} + + + +killTrigger( pos, radius, height ) +{ + trig = spawn( "trigger_radius", pos, 0, radius, height ); + + /# + if ( getdvar( "scr_killtriggerdebug" ) == "1" ) + thread killTriggerDebug( pos, radius, height ); + #/ + + for ( ;; ) + { + /# + if ( getdvar( "scr_killtriggerradius" ) != "" ) + radius = int(getdvar( "scr_killtriggerradius" )); + #/ + + trig waittill( "trigger", player ); + + if ( !isPlayer( player ) ) + continue; + + player suicide(); + } +} + +/# +killTriggerDebug( pos, radius, height ) +{ + for ( ;; ) + { + for ( i = 0; i < 20; i++ ) + { + angle = i / 20 * 360; + nextangle = (i+1) / 20 * 360; + + linepos = pos + (cos(angle) * radius, sin(angle) * radius, 0); + nextlinepos = pos + (cos(nextangle) * radius, sin(nextangle) * radius, 0); + + line( linepos, nextlinepos ); + line( linepos + (0,0,height), nextlinepos + (0,0,height) ); + line( linepos, linepos + (0,0,height) ); + } + wait .05; + } +} +#/ + +allowTeamChoice() +{ + allowed = int( tableLookup( "mp/gametypesTable.csv", 0, level.gameType, 4 ) ); + assert( isDefined( allowed ) ); + + return allowed; +} + +allowClassChoice() +{ + allowed = int( tableLookup( "mp/gametypesTable.csv", 0, level.gameType, 5 ) ); + assert( isDefined( allowed ) ); + + return allowed; +} diff --git a/iw4x/iw4x_00/mp/gameTypesTable.csv b/iw4x/iw4x_00/mp/gameTypesTable.csv index 210d052..8d3df15 100644 --- a/iw4x/iw4x_00/mp/gameTypesTable.csv +++ b/iw4x/iw4x_00/mp/gameTypesTable.csv @@ -1,20 +1,19 @@ -a0,b1,c2,d3 -dm,MPUI_DEATHMATCH,MENU_KILL_EVERYONE_FIRST_PLAYER,weapon_missing_image -war,MPUI_TEAM_DEATHMATCH,MENU_KILL_PLAYERS_ON_THE_OPPOSING,weapon_missing_image -sd,MPUI_SEARCH_AND_DESTROY,MENU_TEAMS_TAKE_TURNS_DEFENDING,weapon_missing_image -sab,MPUI_SABOTAGE,MENU_1_BOMB_IN_THE_CENTER,weapon_missing_image -dom,MPUI_DOMINATION,MENU_CAPTURE_AND_HOLD_THE,weapon_missing_image -koth,MPUI_HEADQUARTERS,MENU_CAPTURE_THE_HEADQUARTERS,weapon_missing_image -oneflag,MPUI_ONE_FLAG,MENU_TEAMS_TAKE_TURNS_CAPTURING,weapon_missing_image -arena,MPUI_ARENA,MENU_ARENA,weapon_missing_image -dd,MPUI_DD,MENU_DD,weapon_missing_image -vip,MPUI_VIP,MENU_VIP,weapon_missing_image -ctf,MPUI_CTF,MENU_CTF_DESC,weapon_missing_image -gtnw,MPUI_GTNW,MENU_GTNW_DESC,weapon_missing_image -ss,MPUI_SHARPSHOOTER,MENU_SHARPSHOOTER,weapon_missing_image -gg,MPUI_GUNGAME,MENU_GUNGAME,weapon_missing_image -oitc,MPUI_OITC,MENU_OITC,weapon_missing_image -conf,MPUI_CONF,MENU_CONF,weapon_missing_image -infected,MPUI_INF,MENU_INF,weapon_missing_image -cranked,MPUI_CRANKED,MENU_CRANKED,weapon_missing_image -tdef,MPUI_TDEF,MENU_TDEF,weapon_missing_image +a0,b1,c2,d3,e4,f5 +dm,MPUI_DEATHMATCH,MENU_KILL_EVERYONE_FIRST_PLAYER,weapon_missing_image,1,1 +war,MPUI_TEAM_DEATHMATCH,MENU_KILL_PLAYERS_ON_THE_OPPOSING,weapon_missing_image,1,1 +sd,MPUI_SEARCH_AND_DESTROY,MENU_TEAMS_TAKE_TURNS_DEFENDING,weapon_missing_image,1,1 +sab,MPUI_SABOTAGE,MENU_1_BOMB_IN_THE_CENTER,weapon_missing_image,1,1 +dom,MPUI_DOMINATION,MENU_CAPTURE_AND_HOLD_THE,weapon_missing_image,1,1 +koth,MPUI_HEADQUARTERS,MENU_CAPTURE_THE_HEADQUARTERS,weapon_missing_image,1,1 +oneflag,MPUI_ONE_FLAG,MENU_TEAMS_TAKE_TURNS_CAPTURING,weapon_missing_image,1,1 +arena,MPUI_ARENA,MENU_ARENA,weapon_missing_image,1,1 +dd,MPUI_DD,MENU_DD,weapon_missing_image,1,1 +vip,MPUI_VIP,MENU_VIP,weapon_missing_image,1,1 +ctf,MPUI_CTF,MENU_CTF_DESC,weapon_missing_image,1,1 +gtnw,MPUI_GTNW,MENU_GTNW_DESC,weapon_missing_image,1,1 +gun,MPUI_GUNGAME,MENU_GUNGAME,weapon_missing_image,0,0 +oic,MPUI_OITC,MENU_OITC,weapon_missing_image,0,0 +conf,MPUI_CONF,MENU_CONF,weapon_missing_image,1,1 +infect,MPUI_INF,MENU_INF,weapon_missing_image,0,0 +cranked,MPUI_CRANKED,MENU_CRANKED,weapon_missing_image,1,1 +tdef,MPUI_TDEF,MENU_TDEF,weapon_missing_image,1,1