1481 lines
50 KiB
Plaintext
1481 lines
50 KiB
Plaintext
#using scripts\shared\challenges_shared;
|
|
#using scripts\shared\demo_shared;
|
|
#using scripts\shared\exploder_shared;
|
|
#using scripts\shared\gameobjects_shared;
|
|
#using scripts\shared\hostmigration_shared;
|
|
#using scripts\shared\hud_util_shared;
|
|
#using scripts\shared\math_shared;
|
|
#using scripts\shared\medals_shared;
|
|
#using scripts\shared\popups_shared;
|
|
#using scripts\shared\rank_shared;
|
|
#using scripts\shared\scoreevents_shared;
|
|
#using scripts\shared\sound_shared;
|
|
#using scripts\mp\gametypes\_dogtags;
|
|
#using scripts\mp\gametypes\_globallogic_spawn;
|
|
|
|
|
|
|
|
#using scripts\mp\gametypes\_battlechatter;
|
|
#using scripts\mp\gametypes\_globallogic;
|
|
#using scripts\mp\gametypes\_globallogic_audio;
|
|
#using scripts\mp\gametypes\_globallogic_defaults;
|
|
#using scripts\mp\gametypes\_globallogic_score;
|
|
#using scripts\mp\gametypes\_globallogic_utils;
|
|
#using scripts\mp\gametypes\_hostmigration;
|
|
#using scripts\mp\gametypes\_spawning;
|
|
#using scripts\mp\gametypes\_spawnlogic;
|
|
#using scripts\mp\gametypes\_spectating;
|
|
|
|
#using scripts\mp\_challenges;
|
|
#using scripts\mp\_util;
|
|
|
|
// Rallypoints should be destroyed on leaving your team/getting killed
|
|
// Compass icons need to be looked at
|
|
// Doesn't seem to be setting angle on spawn so that you are facing your rallypoint
|
|
|
|
/*
|
|
Demolition
|
|
Attackers objective: Bomb 2 positions
|
|
Defenders objective: Defend these 2 positions / Defuse planted bombs
|
|
Round ends: When both bomb positions are exploded, or roundlength time is reached
|
|
Map ends: When one team reaches the score limit, or time limit or round limit is reached
|
|
Respawning: Players respawn upon death
|
|
|
|
Level requirements
|
|
------------------
|
|
Allied Spawnpoints:
|
|
classname mp_dem_spawn_attacker_start
|
|
Allied players spawn from these. Place at least 16 of these relatively close together.
|
|
|
|
Axis Spawnpoints:
|
|
classname mp_dem_spawn_defender_start
|
|
Axis players spawn from these. Place at least 16 of these relatively close together.
|
|
|
|
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.
|
|
|
|
Bombzones:
|
|
classname trigger_multiple
|
|
targetname bombzone_dem
|
|
script_gameobjectname bombzone_dem
|
|
script_bombmode_original <if defined this bombzone will be used in the original bomb mode>
|
|
script_bombmode_single <if defined this bombzone will be used in the single bomb mode>
|
|
script_bombmode_dual <if defined this bombzone will be used in the dual bomb mode>
|
|
script_team Set to allies or axis. This is used to set which team a bombzone is used by in dual bomb mode.
|
|
script_label Set to A or B. This sets the letter shown on the compass in original mode.
|
|
This is a volume of space in which the bomb can planted. Must contain an origin brush.
|
|
|
|
Bomb:
|
|
classname trigger_lookat
|
|
targetname bombtrigger
|
|
script_gameobjectname bombzone
|
|
This should be a 16x16 unit trigger with an origin brush placed so that it's center lies on the bottom plane of the trigger.
|
|
Must be in the level somewhere. This is the trigger that is used when defusing a bomb.
|
|
It gets moved to the position of the planted bomb model.
|
|
|
|
Level script requirements
|
|
-------------------------
|
|
Team Definitions:
|
|
game["allies"] = "marines";
|
|
game["axis"] = "nva";
|
|
This sets the nationalities of the teams. Allies can be american, british, or russian. Axis can be german.
|
|
|
|
game["attackers"] = "allies";
|
|
game["defenders"] = "axis";
|
|
This sets which team is attacking and which team is defending. Attackers plant the bombs. Defenders protect the targets.
|
|
|
|
If using minefields or exploders:
|
|
load::main();
|
|
|
|
Optional level script settings
|
|
------------------------------
|
|
Soldier Type and Variation:
|
|
game["soldiertypeset"] = "seals";
|
|
This sets what character models are used for each nationality on a particular map.
|
|
|
|
Valid settings:
|
|
soldiertypeset seals
|
|
|
|
Exploder Effects:
|
|
Setting script_noteworthy on a bombzone trigger to an exploder group can be used to trigger additional effects.
|
|
*/
|
|
|
|
/*QUAKED mp_dem_spawn_attacker_start (0.0 1.0 0.0) (-16 -16 0) (16 16 72)
|
|
Attacking players spawn randomly at one of these positions at the beginning of a round.*/
|
|
|
|
/*QUAKED mp_dem_spawn_defender_start (1.0 0.0 0.0) (-16 -16 0) (16 16 72)
|
|
Defending players spawn randomly at one of these positions at the beginning of a round.*/
|
|
|
|
/*QUAKED mp_dem_spawn_attackerot_start (0.0 1.0 0.0) (-16 -16 0) (16 16 72)
|
|
Attacking players spawn randomly at one of these positions at the beginning of a round.*/
|
|
|
|
/*QUAKED mp_dem_spawn_defenderot_start (1.0 0.0 0.0) (-16 -16 0) (16 16 72)
|
|
Defending players spawn randomly at one of these positions at the beginning of a round.*/
|
|
|
|
/*QUAKED mp_dem_spawn_attacker (0.0 1.0 0.0) (-16 -16 0) (16 16 72)
|
|
Attacking players may spawn randomly at one of these positions after death.*/
|
|
|
|
/*QUAKED mp_dem_spawn_attacker_a (0.0 1.0 0.0) (-16 -16 0) (16 16 72)
|
|
Attacking players may spawn randomly at one of these positions after death if site A has been destroyed.*/
|
|
|
|
/*QUAKED mp_dem_spawn_attacker_b (0.0 1.0 0.0) (-16 -16 0) (16 16 72)
|
|
Attacking players may spawn randomly at one of these positions after death if site B has been destroyed.*/
|
|
|
|
/*QUAKED mp_dem_spawn_defender (1.0 0.0 0.0) (-16 -16 0) (16 16 72)
|
|
Defending players may spawn randomly at one of these positions after death.*/
|
|
|
|
/*QUAKED mp_dem_spawn_defender_a (1.0 0.0 0.0) (-16 -16 0) (16 16 72)
|
|
Defending players may spawn randomly at one of these positions after death if site A is still intact.*/
|
|
|
|
/*QUAKED mp_dem_spawn_defender_b (1.0 0.0 0.0) (-16 -16 0) (16 16 72)
|
|
Defending players may spawn randomly at one of these positions after death if site B is still intact.*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#precache( "fx", "explosions/fx_exp_bomb_demo_mp" );
|
|
#precache( "material", "compass_waypoint_target" );
|
|
#precache( "material", "compass_waypoint_target_a" );
|
|
#precache( "material", "compass_waypoint_target_b" );
|
|
#precache( "material", "compass_waypoint_defend" );
|
|
#precache( "material", "compass_waypoint_defend_a" );
|
|
#precache( "material", "compass_waypoint_defend_b" );
|
|
#precache( "material", "compass_waypoint_defuse" );
|
|
#precache( "material", "compass_waypoint_defuse_a" );
|
|
#precache( "material", "compass_waypoint_defuse_b" );
|
|
#precache( "model", "p7_mp_suitcase_bomb" );
|
|
#precache( "objective", "dem_a" );
|
|
#precache( "objective", "dem_b" );
|
|
#precache( "objective", "dem_overtime" );
|
|
#precache( "string", "OBJECTIVES_DEM_ATTACKER" );
|
|
#precache( "string", "OBJECTIVES_SD_DEFENDER" );
|
|
#precache( "string", "OBJECTIVES_DEM_ATTACKER_SCORE" );
|
|
#precache( "string", "OBJECTIVES_SD_DEFENDER_SCORE" );
|
|
#precache( "string", "OBJECTIVES_DEM_ATTACKER_HINT" );
|
|
#precache( "string", "OBJECTIVES_DEM_ATTACKER_OVERTIME_HINT" );
|
|
#precache( "string", "OBJECTIVES_SD_DEFENDER_HINT" );
|
|
#precache( "string", "MP_EXPLOSIVES_RECOVERED_BY" );
|
|
#precache( "string", "MP_EXPLOSIVES_DROPPED_BY" );
|
|
#precache( "string", "MP_EXPLOSIVES_PLANTED_BY" );
|
|
#precache( "string", "MP_EXPLOSIVES_DEFUSED_BY" );
|
|
#precache( "string", "PLATFORM_HOLD_TO_PLANT_EXPLOSIVES" );
|
|
#precache( "string", "PLATFORM_HOLD_TO_DEFUSE_EXPLOSIVES" );
|
|
#precache( "string", "MP_PLANTING_EXPLOSIVE" );
|
|
#precache( "string", "MP_DEFUSING_EXPLOSIVE" );
|
|
#precache( "string", "MP_TIME_EXTENDED" );
|
|
#precache( "string", "MP_TARGET_DESTROYED" );
|
|
#precache( "string", "MP_BOMB_DEFUSED" );
|
|
#precache( "triggerstring", "PLATFORM_HOLD_TO_DEFUSE_EXPLOSIVES" );
|
|
#precache( "triggerstring", "PLATFORM_HOLD_TO_PLANT_EXPLOSIVES" );
|
|
|
|
function main()
|
|
{
|
|
globallogic::init();
|
|
|
|
util::registerRoundSwitch( 0, 9 );
|
|
util::registerTimeLimit( 0, 1440 );
|
|
util::registerScoreLimit( 0, 500 );
|
|
util::registerRoundLimit( 0, 12 );
|
|
util::registerRoundWinLimit( 0, 10 );
|
|
util::registerNumLives( 0, 100 );
|
|
|
|
globallogic::registerFriendlyFireDelay( level.gameType, 15, 0, 1440 );
|
|
|
|
level.teamBased = true;
|
|
level.overrideTeamScore = true;
|
|
level.onPrecacheGameType =&onPrecacheGameType;
|
|
level.onStartGameType =&onStartGameType;
|
|
level.onSpawnPlayer =&onSpawnPlayer;
|
|
level.playerSpawnedCB =&dem_playerSpawnedCB;
|
|
level.onPlayerKilled =&onPlayerKilled;
|
|
level.onDeadEvent =&onDeadEvent;
|
|
level.onOneLeftEvent =&onOneLeftEvent;
|
|
level.onTimeLimit =&onTimeLimit;
|
|
level.onRoundSwitch =&onRoundSwitch;
|
|
level.getTeamKillPenalty =&dem_getTeamKillPenalty;
|
|
level.getTeamKillScore =&dem_getTeamKillScore;
|
|
level.getTimeLimit =&getTimeLimit;
|
|
level.shouldPlayOvertimeRound =&shouldPlayOvertimeRound;
|
|
level.lastBombExplodeTime = undefined;
|
|
level.lastBombExplodeByTeam = undefined;
|
|
level.ddBombModel = [];
|
|
|
|
level.endGameOnScoreLimit = false;
|
|
|
|
level.demBombzoneName = "bombzone_dem";
|
|
|
|
gameobjects::register_allowed_gameobject( level.gameType );
|
|
gameobjects::register_allowed_gameobject( "sd" );
|
|
gameobjects::register_allowed_gameobject( "blocker" );
|
|
gameobjects::register_allowed_gameobject( level.demBombzoneName );
|
|
|
|
globallogic_audio::set_leader_gametype_dialog ( "startDemolition", "hcStartDemolition", "objDestroy", "objDefend" );
|
|
|
|
// Sets the scoreboard columns and determines with data is sent across the network
|
|
if ( !SessionModeIsSystemlink() && !SessionModeIsOnlineGame() && IsSplitScreen() )
|
|
// local matches only show the first three columns
|
|
globallogic::setvisiblescoreboardcolumns( "score", "kills", "plants", "defuses", "deaths" );
|
|
else
|
|
globallogic::setvisiblescoreboardcolumns( "score", "kills", "deaths", "plants", "defuses" );
|
|
}
|
|
|
|
function onPrecacheGameType()
|
|
{
|
|
game["bombmodelname"] = "t5_weapon_briefcase_bomb_world";
|
|
game["bombmodelnameobj"] = "t5_weapon_briefcase_bomb_world";
|
|
game["bomb_dropped_sound"] = "fly_bomb_drop_plr";
|
|
game["bomb_recovered_sound"] = "fly_bomb_pickup_plr";
|
|
}
|
|
|
|
function dem_getTeamKillPenalty( eInflictor, attacker, sMeansOfDeath, weapon )
|
|
{
|
|
teamkill_penalty = globallogic_defaults::default_getTeamKillPenalty( eInflictor, attacker, sMeansOfDeath, weapon );
|
|
|
|
if ( ( isdefined( self.isDefusing ) && self.isDefusing ) || ( isdefined( self.isPlanting ) && self.isPlanting ) )
|
|
{
|
|
teamkill_penalty = teamkill_penalty * level.teamKillPenaltyMultiplier;
|
|
}
|
|
|
|
return teamkill_penalty;
|
|
}
|
|
|
|
function dem_getTeamKillScore( eInflictor, attacker, sMeansOfDeath, weapon )
|
|
{
|
|
teamkill_score = rank::getScoreInfoValue( "team_kill" );
|
|
|
|
if ( ( isdefined( self.isDefusing ) && self.isDefusing ) || ( isdefined( self.isPlanting ) && self.isPlanting ) )
|
|
{
|
|
teamkill_score = teamkill_score * level.teamKillScoreMultiplier;
|
|
}
|
|
|
|
return int(teamkill_score);
|
|
}
|
|
|
|
|
|
function onRoundSwitch()
|
|
{
|
|
if ( !isdefined( game["switchedsides"] ) )
|
|
game["switchedsides"] = false;
|
|
|
|
if ( game["teamScores"]["allies"] == level.scorelimit - 1 && game["teamScores"]["axis"] == level.scorelimit - 1 )
|
|
{
|
|
// overtime! team that's ahead in kills gets to defend.
|
|
aheadTeam = getBetterTeam();
|
|
if ( aheadTeam != game["defenders"] )
|
|
{
|
|
game["switchedsides"] = !game["switchedsides"];
|
|
}
|
|
level.halftimeType = "overtime";
|
|
|
|
if( isdefined( level.bombZones[1] ) )
|
|
level.bombZones[1] gameobjects::disable_object();
|
|
}
|
|
else
|
|
{
|
|
level.halftimeType = "halftime";
|
|
game["switchedsides"] = !game["switchedsides"];
|
|
}
|
|
}
|
|
|
|
function getBetterTeam()
|
|
{
|
|
kills["allies"] = 0;
|
|
kills["axis"] = 0;
|
|
deaths["allies"] = 0;
|
|
deaths["axis"] = 0;
|
|
|
|
for ( i = 0; i < level.players.size; i++ )
|
|
{
|
|
player = level.players[i];
|
|
team = player.pers["team"];
|
|
if ( isdefined( team ) && (team == "allies" || team == "axis") )
|
|
{
|
|
kills[ team ] += player.kills;
|
|
deaths[ team ] += player.deaths;
|
|
}
|
|
}
|
|
|
|
if ( kills["allies"] > kills["axis"] )
|
|
return "allies";
|
|
else if ( kills["axis"] > kills["allies"] )
|
|
return "axis";
|
|
|
|
// same number of kills
|
|
|
|
if ( deaths["allies"] < deaths["axis"] )
|
|
return "allies";
|
|
else if ( deaths["axis"] < deaths["allies"] )
|
|
return "axis";
|
|
|
|
// same number of deaths
|
|
|
|
if ( randomint(2) == 0 )
|
|
return "allies";
|
|
return "axis";
|
|
}
|
|
|
|
function onStartGameType()
|
|
{
|
|
SetBombTimer( "A", 0 );
|
|
setMatchFlag( "bomb_timer_a", 0 );
|
|
SetBombTimer( "B", 0 );
|
|
setMatchFlag( "bomb_timer_b", 0 );
|
|
|
|
level.usingExtraTime = false;
|
|
|
|
// we'll handle the sideswitching ourselves
|
|
level.spawnsystem.sideSwitching = 0;
|
|
|
|
if ( !isdefined( game["switchedsides"] ) )
|
|
game["switchedsides"] = false;
|
|
|
|
if ( game["switchedsides"] )
|
|
{
|
|
oldAttackers = game["attackers"];
|
|
oldDefenders = game["defenders"];
|
|
game["attackers"] = oldDefenders;
|
|
game["defenders"] = oldAttackers;
|
|
}
|
|
|
|
setClientNameMode( "manual_change" );
|
|
|
|
game["strings"]["target_destroyed"] = &"MP_TARGET_DESTROYED";
|
|
game["strings"]["bomb_defused"] = &"MP_BOMB_DEFUSED";
|
|
|
|
level._effect["bombexplosion"] = "explosions/fx_exp_bomb_demo_mp";
|
|
|
|
if ( isdefined( game["overtime_round"] ) )
|
|
{
|
|
util::setObjectiveText( game["attackers"], &"OBJECTIVES_DEM_ATTACKER" );
|
|
util::setObjectiveText( game["defenders"], &"OBJECTIVES_DEM_ATTACKER" );
|
|
if ( level.splitscreen )
|
|
{
|
|
util::setObjectiveScoreText( game["attackers"], &"OBJECTIVES_DEM_ATTACKER" );
|
|
util::setObjectiveScoreText( game["defenders"], &"OBJECTIVES_DEM_ATTACKER" );
|
|
}
|
|
else
|
|
{
|
|
util::setObjectiveScoreText( game["attackers"], &"OBJECTIVES_DEM_ATTACKER_SCORE" );
|
|
util::setObjectiveScoreText( game["defenders"], &"OBJECTIVES_DEM_ATTACKER_SCORE" );
|
|
}
|
|
|
|
util::setObjectiveHintText( game["attackers"], &"OBJECTIVES_DEM_ATTACKER_OVERTIME_HINT" );
|
|
util::setObjectiveHintText( game["defenders"], &"OBJECTIVES_DEM_ATTACKER_OVERTIME_HINT" );
|
|
}
|
|
else
|
|
{
|
|
util::setObjectiveText( game["attackers"], &"OBJECTIVES_DEM_ATTACKER" );
|
|
util::setObjectiveText( game["defenders"], &"OBJECTIVES_SD_DEFENDER" );
|
|
if ( level.splitscreen )
|
|
{
|
|
util::setObjectiveScoreText( game["attackers"], &"OBJECTIVES_DEM_ATTACKER" );
|
|
util::setObjectiveScoreText( game["defenders"], &"OBJECTIVES_SD_DEFENDER" );
|
|
}
|
|
else
|
|
{
|
|
util::setObjectiveScoreText( game["attackers"], &"OBJECTIVES_DEM_ATTACKER_SCORE" );
|
|
util::setObjectiveScoreText( game["defenders"], &"OBJECTIVES_SD_DEFENDER_SCORE" );
|
|
}
|
|
util::setObjectiveHintText( game["attackers"], &"OBJECTIVES_DEM_ATTACKER_HINT" );
|
|
util::setObjectiveHintText( game["defenders"], &"OBJECTIVES_SD_DEFENDER_HINT" );
|
|
}
|
|
|
|
bombZones = getEntArray( level.demBombzoneName, "targetname" );
|
|
if ( bombZones.size == 0 )
|
|
level.demBombzoneName = "bombzone";
|
|
|
|
// now that the game objects have been deleted place the influencers
|
|
spawning::create_map_placed_influencers();
|
|
|
|
level.spawnMins = ( 0, 0, 0 );
|
|
level.spawnMaxs = ( 0, 0, 0 );
|
|
spawnlogic::drop_spawn_points( "mp_dem_spawn_attacker_a" );
|
|
spawnlogic::drop_spawn_points( "mp_dem_spawn_attacker_b" );
|
|
spawnlogic::drop_spawn_points( "mp_dem_spawn_defender_a" );
|
|
spawnlogic::drop_spawn_points( "mp_dem_spawn_defender_b" );
|
|
if ( !isdefined( game["overtime_round"] ) )
|
|
{
|
|
spawnlogic::place_spawn_points( "mp_dem_spawn_defender_start" );
|
|
spawnlogic::place_spawn_points( "mp_dem_spawn_attacker_start" );
|
|
}
|
|
else
|
|
{
|
|
spawnlogic::place_spawn_points( "mp_dem_spawn_attackerot_start" );
|
|
spawnlogic::place_spawn_points( "mp_dem_spawn_defenderot_start" );
|
|
}
|
|
spawnlogic::add_spawn_points( game["attackers"], "mp_dem_spawn_attacker" );
|
|
spawnlogic::add_spawn_points( game["defenders"], "mp_dem_spawn_defender" );
|
|
if ( !isdefined( game["overtime_round"] ) )
|
|
{
|
|
spawnlogic::add_spawn_points( game["defenders"], "mp_dem_spawn_defender_a" );
|
|
spawnlogic::add_spawn_points( game["defenders"], "mp_dem_spawn_defender_b" );
|
|
spawnlogic::add_spawn_points( game["attackers"], "mp_dem_spawn_attacker_remove_a" );
|
|
spawnlogic::add_spawn_points( game["attackers"], "mp_dem_spawn_attacker_remove_b" );
|
|
}
|
|
|
|
spawning::add_fallback_spawnpoints( game["attackers"], "mp_tdm_spawn" );
|
|
spawning::add_fallback_spawnpoints( game["defenders"], "mp_tdm_spawn" );
|
|
|
|
spawning::updateAllSpawnPoints();
|
|
spawning::update_fallback_spawnpoints();
|
|
|
|
level.mapCenter = math::find_box_center( level.spawnMins, level.spawnMaxs );
|
|
setMapCenter( level.mapCenter );
|
|
|
|
spawnpoint = spawnlogic::get_random_intermission_point();
|
|
setDemoIntermissionPoint( spawnpoint.origin, spawnpoint.angles );
|
|
|
|
|
|
level.spawn_start = [];
|
|
|
|
if ( isdefined( game["overtime_round"] ) )
|
|
{
|
|
level.spawn_start["axis"] = spawnlogic::get_spawnpoint_array( "mp_dem_spawn_defenderot_start" );
|
|
level.spawn_start["allies"] = spawnlogic::get_spawnpoint_array( "mp_dem_spawn_attackerot_start" );
|
|
}
|
|
else
|
|
{
|
|
level.spawn_start["axis"] = spawnlogic::get_spawnpoint_array( "mp_dem_spawn_defender_start" );
|
|
level.spawn_start["allies"] = spawnlogic::get_spawnpoint_array( "mp_dem_spawn_attacker_start" );
|
|
}
|
|
thread updateGametypeDvars();
|
|
|
|
thread bombs();
|
|
|
|
if( ( isdefined( level.droppedTagRespawn ) && level.droppedTagRespawn ) )
|
|
level.numLives = 1;
|
|
}
|
|
|
|
|
|
function onSpawnPlayer(predictedSpawn)
|
|
{
|
|
self.isPlanting = false;
|
|
self.isDefusing = false;
|
|
self.isBombCarrier = false;
|
|
|
|
spawning::onSpawnPlayer(predictedSpawn);
|
|
}
|
|
|
|
function dem_playerSpawnedCB()
|
|
{
|
|
level notify ( "spawned_player" );
|
|
}
|
|
|
|
function onPlayerKilled(eInflictor, attacker, iDamage, sMeansOfDeath, weapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration)
|
|
{
|
|
thread checkAllowSpectating();
|
|
|
|
if( ( isdefined( level.droppedTagRespawn ) && level.droppedTagRespawn ) )
|
|
{
|
|
should_spawn_tags = self dogtags::should_spawn_tags(eInflictor, attacker, iDamage, sMeansOfDeath, weapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration);
|
|
|
|
// we should spawn tags if one the previous statements were true and we may not spawn
|
|
should_spawn_tags = should_spawn_tags && !globallogic_spawn::maySpawn();
|
|
|
|
if( should_spawn_tags )
|
|
level thread dogtags::spawn_dog_tag( self, attacker, &dogtags::onUseDogTag, false );
|
|
}
|
|
|
|
bombZone = undefined;
|
|
|
|
for ( index = 0; index < level.bombZones.size; index++ )
|
|
{
|
|
if ( !isdefined( level.bombZones[index].bombExploded ) || !level.bombZones[index].bombExploded )
|
|
{
|
|
dist = Distance2dSquared(self.origin, level.bombZones[index].curorigin);
|
|
if ( dist < level.defaultOffenseRadiusSQ )
|
|
{
|
|
bombZone = level.bombZones[index];
|
|
break;
|
|
}
|
|
dist = Distance2dSquared(attacker.origin, level.bombZones[index].curorigin);
|
|
if ( dist < level.defaultOffenseRadiusSQ )
|
|
{
|
|
inBombZone = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if ( isdefined( bombZone ) && isPlayer( attacker ) && attacker.pers["team"] != self.pers["team"] )
|
|
{
|
|
if ( bombZone gameobjects::get_owner_team() != attacker.team )
|
|
{
|
|
if ( !isdefined( attacker.dem_offends ) )
|
|
attacker.dem_offends = 0;
|
|
|
|
attacker.dem_offends++;
|
|
|
|
if ( level.playerOffensiveMax >= attacker.dem_offends )
|
|
{
|
|
attacker medals::offenseGlobalCount();
|
|
attacker thread challenges::killedBaseDefender( bombZone.trigger );
|
|
self RecordKillModifier("defending");
|
|
scoreevents::processScoreEvent( "killed_defender", attacker, self, weapon );
|
|
}
|
|
else
|
|
{
|
|
/#
|
|
attacker IPrintlnBold( "GAMETYPE DEBUG: NOT GIVING YOU OFFENSIVE CREDIT AS BOOSTING PREVENTION" );
|
|
#/
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( !isdefined( attacker.dem_defends ) )
|
|
attacker.dem_defends = 0;
|
|
|
|
attacker.dem_defends++;
|
|
|
|
if ( level.playerDefensiveMax >= attacker.dem_defends )
|
|
{
|
|
if( isdefined(attacker.pers["defends"]) )
|
|
{
|
|
attacker.pers["defends"]++;
|
|
attacker.defends = attacker.pers["defends"];
|
|
}
|
|
|
|
attacker medals::defenseGlobalCount();
|
|
attacker thread challenges::killedBaseOffender( bombZone.trigger, weapon );
|
|
self RecordKillModifier("assaulting");
|
|
scoreevents::processScoreEvent( "killed_attacker", attacker, self, weapon );
|
|
}
|
|
else
|
|
{
|
|
/#
|
|
attacker IPrintlnBold( "GAMETYPE DEBUG: NOT GIVING YOU DEFENSIVE CREDIT AS BOOSTING PREVENTION" );
|
|
#/
|
|
}
|
|
}
|
|
}
|
|
|
|
if( self.isPlanting == true )
|
|
self RecordKillModifier("planting");
|
|
|
|
if( self.isDefusing == true )
|
|
self RecordKillModifier("defusing");
|
|
}
|
|
|
|
|
|
function checkAllowSpectating()
|
|
{
|
|
self endon("disconnect");
|
|
|
|
{wait(.05);};
|
|
|
|
update = false;
|
|
|
|
livesLeft = !(level.numLives && !self.pers["lives"]);
|
|
|
|
if ( !level.aliveCount[ game["attackers"] ] && !livesLeft )
|
|
{
|
|
level.spectateOverride[game["attackers"]].allowEnemySpectate = 1;
|
|
update = true;
|
|
}
|
|
if ( !level.aliveCount[ game["defenders"] ] && !livesLeft )
|
|
{
|
|
level.spectateOverride[game["defenders"]].allowEnemySpectate = 1;
|
|
update = true;
|
|
}
|
|
if ( update )
|
|
spectating::update_settings();
|
|
}
|
|
|
|
|
|
function dem_endGame( winningTeam, endReasonText )
|
|
{
|
|
// set all bombs to non-visible so the hud gets correctly reset for the next round
|
|
// going into overtime the hud might still have a bomb b otherwise
|
|
foreach( bombZone in level.bombZones )
|
|
{
|
|
bombZone gameobjects::set_visible_team( "none" );
|
|
}
|
|
|
|
if ( isdefined( winningTeam ) && ( winningTeam != "tie" ) )
|
|
globallogic_score::giveTeamScoreForObjective( winningTeam, 1 );
|
|
|
|
thread globallogic::endGame( winningTeam, endReasonText );
|
|
}
|
|
|
|
function onDeadEvent( team )
|
|
{
|
|
if ( level.bombExploded || level.bombDefused )
|
|
return;
|
|
|
|
if ( team == "all" )
|
|
{
|
|
if ( level.bombPlanted )
|
|
dem_endGame( game["attackers"], game["strings"][game["defenders"]+"_eliminated"] );
|
|
else
|
|
dem_endGame( game["defenders"], game["strings"][game["attackers"]+"_eliminated"] );
|
|
}
|
|
else if ( team == game["attackers"] )
|
|
{
|
|
if ( level.bombPlanted )
|
|
return;
|
|
|
|
dem_endGame( game["defenders"], game["strings"][game["attackers"]+"_eliminated"] );
|
|
}
|
|
else if ( team == game["defenders"] )
|
|
{
|
|
dem_endGame( game["attackers"], game["strings"][game["defenders"]+"_eliminated"] );
|
|
}
|
|
}
|
|
|
|
|
|
function onOneLeftEvent( team )
|
|
{
|
|
if ( level.bombExploded || level.bombDefused )
|
|
return;
|
|
|
|
//if ( team == game["attackers"] )
|
|
warnLastPlayer( team );
|
|
}
|
|
|
|
|
|
function onTimeLimit()
|
|
{
|
|
if ( isdefined( game["overtime_round"] ) )
|
|
{
|
|
dem_endGame( "tie", game["strings"]["time_limit_reached"] );
|
|
}
|
|
else
|
|
{
|
|
if ( level.teamBased )
|
|
{
|
|
bombZonesLeft = 0;
|
|
|
|
for ( index = 0; index < level.bombZones.size; index++ )
|
|
{
|
|
if ( !isdefined( level.bombZones[index].bombExploded ) || !level.bombZones[index].bombExploded )
|
|
bombZonesLeft++;
|
|
}
|
|
if ( bombZonesLeft == 0 )
|
|
{
|
|
dem_endGame( game["attackers"], game["strings"]["target_destroyed"] );
|
|
}
|
|
else
|
|
{
|
|
dem_endGame( game["defenders"], game["strings"]["time_limit_reached"] );
|
|
}
|
|
}
|
|
else
|
|
dem_endGame( "tie", game["strings"]["time_limit_reached"] );
|
|
}
|
|
}
|
|
|
|
|
|
function warnLastPlayer( team )
|
|
{
|
|
if ( !isdefined( level.warnedLastPlayer ) )
|
|
level.warnedLastPlayer = [];
|
|
|
|
if ( isdefined( level.warnedLastPlayer[team] ) )
|
|
return;
|
|
|
|
level.warnedLastPlayer[team] = true;
|
|
|
|
players = level.players;
|
|
for ( i = 0; i < players.size; i++ )
|
|
{
|
|
player = players[i];
|
|
|
|
if ( isdefined( player.pers["team"] ) && player.pers["team"] == team && isdefined( player.pers["class"] ) )
|
|
{
|
|
if ( player.sessionstate == "playing" && !player.afk )
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( i == players.size )
|
|
return;
|
|
|
|
players[i] thread giveLastAttackerWarning();
|
|
}
|
|
|
|
|
|
function giveLastAttackerWarning()
|
|
{
|
|
self endon("death");
|
|
self endon("disconnect");
|
|
|
|
fullHealthTime = 0;
|
|
interval = .05;
|
|
|
|
while(1)
|
|
{
|
|
if ( self.health != self.maxhealth )
|
|
fullHealthTime = 0;
|
|
else
|
|
fullHealthTime += interval;
|
|
|
|
wait interval;
|
|
|
|
if (self.health == self.maxhealth && fullHealthTime >= 3)
|
|
break;
|
|
}
|
|
|
|
//self iprintlnbold(&"MP_YOU_ARE_THE_ONLY_REMAINING_PLAYER");
|
|
self globallogic_audio::leader_dialog_on_player( "roundSuddenDeath" );
|
|
}
|
|
|
|
|
|
function updateGametypeDvars()
|
|
{
|
|
level.plantTime = GetGametypeSetting( "plantTime" );
|
|
level.defuseTime = GetGametypeSetting( "defuseTime" );
|
|
level.bombTimer = GetGametypeSetting( "bombTimer" );
|
|
level.extraTime = GetGametypeSetting( "extraTime" );
|
|
level.overtimeTimeLimit = GetGametypeSetting( "OvertimetimeLimit" );
|
|
|
|
level.teamKillPenaltyMultiplier = GetGametypeSetting( "teamKillPenalty" );
|
|
level.teamKillScoreMultiplier = GetGametypeSetting( "teamKillScore" );
|
|
level.playerEventsLPM = GetGametypeSetting( "maxPlayerEventsPerMinute" );
|
|
level.bombEventsLPM = GetGametypeSetting( "maxObjectiveEventsPerMinute" );
|
|
level.playerOffensiveMax = GetGametypeSetting( "maxPlayerOffensive" );
|
|
level.playerDefensiveMax = GetGametypeSetting( "maxPlayerDefensive" );
|
|
}
|
|
|
|
function resetBombZone()
|
|
{
|
|
if ( isdefined( game["overtime_round"] ) )
|
|
{
|
|
self gameobjects::set_owner_team( "neutral" );
|
|
self gameobjects::allow_use( "any" );
|
|
}
|
|
else
|
|
{
|
|
self gameobjects::allow_use( "enemy" );
|
|
}
|
|
self gameobjects::set_use_time( level.plantTime );
|
|
self gameobjects::set_use_text( &"MP_PLANTING_EXPLOSIVE" );
|
|
self gameobjects::set_use_hint_text( &"PLATFORM_HOLD_TO_PLANT_EXPLOSIVES" );
|
|
self gameobjects::set_key_object( level.ddBomb );
|
|
self gameobjects::set_2d_icon( "friendly", "waypoint_defend" + self.label );
|
|
self gameobjects::set_3d_icon( "friendly", "waypoint_defend" + self.label );
|
|
self gameobjects::set_2d_icon( "enemy", "waypoint_target" + self.label );
|
|
self gameobjects::set_3d_icon( "enemy", "waypoint_target" + self.label );
|
|
self gameobjects::set_visible_team( "any" );
|
|
self.useWeapon = GetWeapon( "briefcase_bomb" );
|
|
}
|
|
|
|
function setUpForDefusing()
|
|
{
|
|
self gameobjects::allow_use( "friendly" );
|
|
self gameobjects::set_use_time( level.defuseTime );
|
|
self gameobjects::set_use_text( &"MP_DEFUSING_EXPLOSIVE" );
|
|
self gameobjects::set_use_hint_text( &"PLATFORM_HOLD_TO_DEFUSE_EXPLOSIVES" );
|
|
self gameobjects::set_key_object( undefined );
|
|
self gameobjects::set_2d_icon( "friendly", "compass_waypoint_defuse" + self.label );
|
|
self gameobjects::set_3d_icon( "friendly", "waypoint_defuse" + self.label );
|
|
self gameobjects::set_2d_icon( "enemy", "compass_waypoint_defend" + self.label );
|
|
self gameobjects::set_3d_icon( "enemy", "waypoint_defend" + self.label );
|
|
self gameobjects::set_visible_team( "any" );
|
|
}
|
|
|
|
|
|
function bombs()
|
|
{
|
|
level.bombAPlanted = false;
|
|
level.bombBPlanted = false;
|
|
level.bombPlanted = false;
|
|
level.bombDefused = false;
|
|
level.bombExploded = false;
|
|
|
|
sdBomb = getEnt( "sd_bomb", "targetname" );
|
|
if ( isdefined( sdBomb ) )
|
|
sdBomb delete();
|
|
|
|
level.bombZones = [];
|
|
|
|
bombZones = getEntArray( level.demBombzoneName, "targetname" );
|
|
|
|
for ( index = 0; index < bombZones.size; index++ )
|
|
{
|
|
trigger = bombZones[index];
|
|
scriptLabel = trigger.script_label;
|
|
visuals = getEntArray( bombZones[index].target, "targetname" );
|
|
clipBrushes = getEntArray( "bombzone_clip"+scriptLabel, "targetname" );
|
|
defuseTrig = getent( visuals[0].target, "targetname" );
|
|
|
|
bombSiteTeamOwner = game["defenders"];
|
|
bombSiteAllowUse = "enemy";
|
|
if ( isdefined( game["overtime_round"] ) )
|
|
{
|
|
if ( scriptLabel != "_overtime" )
|
|
{
|
|
trigger delete();
|
|
defuseTrig delete();
|
|
visuals[0] delete();
|
|
foreach ( clip in clipBrushes )
|
|
{
|
|
clip delete();
|
|
}
|
|
continue;
|
|
}
|
|
bombSiteTeamOwner = "neutral";
|
|
bombSiteAllowUse = "any";
|
|
scriptLabel = "_a";
|
|
}
|
|
else if ( scriptLabel == "_overtime" )
|
|
{
|
|
trigger delete();
|
|
defuseTrig delete();
|
|
visuals[0] delete();
|
|
foreach ( clip in clipBrushes )
|
|
{
|
|
clip delete();
|
|
}
|
|
continue;
|
|
}
|
|
|
|
name = istring("dem" + scriptLabel);
|
|
|
|
bombZone = gameobjects::create_use_object( bombSiteTeamOwner, trigger, visuals, (0,0,0), name, true, true );
|
|
bombZone gameobjects::allow_use( bombSiteAllowUse );
|
|
bombZone gameobjects::set_use_time( level.plantTime );
|
|
bombZone gameobjects::set_use_text( &"MP_PLANTING_EXPLOSIVE" );
|
|
bombZone gameobjects::set_use_hint_text( &"PLATFORM_HOLD_TO_PLANT_EXPLOSIVES" );
|
|
bombZone gameobjects::set_key_object( level.ddBomb );
|
|
|
|
bombZone.label = scriptLabel;
|
|
bombZone.index = index;
|
|
bombZone gameobjects::set_2d_icon( "friendly", "compass_waypoint_defend" + scriptLabel );
|
|
bombZone gameobjects::set_3d_icon( "friendly", "waypoint_defend" + scriptLabel );
|
|
bombZone gameobjects::set_2d_icon( "enemy", "compass_waypoint_target" + scriptLabel );
|
|
bombZone gameobjects::set_3d_icon( "enemy", "waypoint_target" + scriptLabel );
|
|
bombZone gameobjects::set_visible_team( "any" );
|
|
bombZone.onBeginUse =&onBeginUse;
|
|
bombZone.onEndUse =&onEndUse;
|
|
bombZone.onUse =&onUseObject;
|
|
bombZone.onCantUse =&onCantUse;
|
|
bombZone.useWeapon = GetWeapon( "briefcase_bomb" );
|
|
bombZone.visuals[0].killCamEnt = spawn( "script_model", bombZone.visuals[0].origin + (0,0,128) );
|
|
|
|
if ( isdefined( level.bomb_zone_fixup ) )
|
|
[[ level.bomb_zone_fixup ]]( bombZone );
|
|
|
|
for ( i = 0; i < visuals.size; i++ )
|
|
{
|
|
if ( isdefined( visuals[i].script_exploder ) )
|
|
{
|
|
bombZone.exploderIndex = visuals[i].script_exploder;
|
|
break;
|
|
}
|
|
}
|
|
|
|
foreach( visual in bombZone.visuals )
|
|
visual.team = "free"; // for preventing red reticles when pointing at bomb zones
|
|
|
|
level.bombZones[level.bombZones.size] = bombZone;
|
|
|
|
bombZone.bombDefuseTrig = defuseTrig;
|
|
assert( isdefined( bombZone.bombDefuseTrig ) );
|
|
bombZone.bombDefuseTrig.origin += (0,0,-10000);
|
|
bombZone.bombDefuseTrig.label = scriptLabel;
|
|
|
|
// Add spawn influencer
|
|
team_mask = util::getTeamMask( game["attackers"] );
|
|
bombZone.spawnInfluencer = bombZone spawning::create_influencer( "dem_enemy_base", trigger.origin, team_mask );
|
|
}
|
|
|
|
for ( index = 0; index < level.bombZones.size; index++ )
|
|
{
|
|
array = [];
|
|
for ( otherindex = 0; otherindex < level.bombZones.size; otherindex++ )
|
|
{
|
|
if ( otherindex != index )
|
|
array[ array.size ] = level.bombZones[otherindex];
|
|
}
|
|
level.bombZones[index].otherBombZones = array;
|
|
}
|
|
}
|
|
|
|
function setBombOverheatingAfterWeaponChange( useObject, overheated, heat ) // self == player
|
|
{
|
|
self endon ( "death" );
|
|
self endon ( "disconnect" );
|
|
self endon ( "joined_team");
|
|
self endon ( "joined_spectators");
|
|
|
|
self waittill( "weapon_change", weapon );
|
|
|
|
if ( weapon == useObject.useWeapon )
|
|
{
|
|
self SetWeaponOverheating( overheated, heat, weapon ); // resetting overheating allows for quick drop anim to be played
|
|
}
|
|
}
|
|
|
|
function onBeginUse( player )
|
|
{
|
|
timeRemaining = globallogic_utils::getTimeRemaining();
|
|
if (timeRemaining <= level.plantTime * 1000 )
|
|
{
|
|
//setGameEndTime( 0 );
|
|
globallogic_utils::pauseTimer();
|
|
level.hasPausedTimer = true;
|
|
}
|
|
|
|
|
|
if ( self gameobjects::is_friendly_team( player.pers["team"] ) )
|
|
{
|
|
player playSound( "mpl_sd_bomb_defuse" );
|
|
player.isDefusing = true;
|
|
player thread setBombOverheatingAfterWeaponChange( self, false, 0 ); // overheated specific use weapons play "drop" instead of "quick drop" anims
|
|
player thread battlechatter::gametype_specific_battle_chatter( "sd_enemyplant", player.pers["team"] );
|
|
|
|
bestDistance = 9000000;
|
|
closestBomb = undefined;
|
|
|
|
if ( isdefined( level.ddBombModel ) )
|
|
{
|
|
keys = GetArrayKeys( level.ddBombModel );
|
|
for ( bombLabel = 0; bombLabel < keys.size; bombLabel++ )
|
|
{
|
|
bomb = level.ddBombModel[ keys[bombLabel] ];
|
|
|
|
if ( !isdefined( bomb ) )
|
|
continue;
|
|
|
|
dist = distanceSquared( player.origin, bomb.origin );
|
|
|
|
if ( dist < bestDistance )
|
|
{
|
|
bestDistance = dist;
|
|
closestBomb = bomb;
|
|
}
|
|
}
|
|
|
|
assert( isdefined(closestBomb) );
|
|
player.defusing = closestBomb;
|
|
closestBomb hide();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
player.isPlanting = true;
|
|
player thread setBombOverheatingAfterWeaponChange( self, false, 0 ); // overheated specific use weapons play "drop" instead of "quick drop" anims
|
|
player thread battlechatter::gametype_specific_battle_chatter( "sd_friendlyplant", player.pers["team"] );
|
|
}
|
|
|
|
player playSound( "fly_bomb_raise_plr" );
|
|
}
|
|
|
|
function onEndUse( team, player, result )
|
|
{
|
|
if ( !isdefined( player ) )
|
|
return;
|
|
|
|
if ( !level.bombAPlanted && !level.bombBPlanted )
|
|
{
|
|
globallogic_utils::resumeTimer();
|
|
level.hasPausedTimer = false;
|
|
}
|
|
|
|
player.isDefusing = false;
|
|
player.isPlanting = false;
|
|
player notify( "event_ended" );
|
|
|
|
if ( self gameobjects::is_friendly_team( player.pers["team"] ) )
|
|
{
|
|
if ( isdefined( player.defusing ) && !result )
|
|
{
|
|
player.defusing show();
|
|
}
|
|
}
|
|
}
|
|
|
|
function onCantUse( player )
|
|
{
|
|
player iPrintLnBold( &"MP_CANT_PLANT_WITHOUT_BOMB" );
|
|
}
|
|
|
|
function onUseObject( player )
|
|
{
|
|
team = player.team;
|
|
enemyTeam = util::getOtherTeam( team );
|
|
|
|
self updateEventsPerMinute();
|
|
player updateEventsPerMinute();
|
|
|
|
// planted the bomb
|
|
if ( !self gameobjects::is_friendly_team( team ) )
|
|
{
|
|
self gameobjects::set_flags( 1 );
|
|
|
|
level thread bombPlanted( self, player );
|
|
/#print( "bomb planted: " + self.label );#/
|
|
|
|
bbPrint( "mpobjective", "gametime %d objtype %s label %s team %s playerx %d playery %d playerz %d", gettime(), "dem_bombplant", self.label, team, player.origin );
|
|
|
|
// removed plant audio until finalization of assest TODO : new plant sounds when assests are online
|
|
// player playSound( "mpl_sd_bomb_plant" );
|
|
player notify ( "bomb_planted" );
|
|
|
|
thread globallogic_audio::set_music_on_team( "DEM_WE_PLANT", team, 5 );
|
|
thread globallogic_audio::set_music_on_team( "DEM_THEY_PLANT", enemyTeam, 5 );
|
|
|
|
if( isdefined(player.pers["plants"]) )
|
|
{
|
|
player.pers["plants"]++;
|
|
player.plants = player.pers["plants"];
|
|
}
|
|
|
|
if ( !isScoreBoosting( player, self ) )
|
|
{
|
|
demo::bookmark( "event", gettime(), player );
|
|
player AddPlayerStatWithGameType( "PLANTS", 1 );
|
|
|
|
scoreevents::processScoreEvent( "planted_bomb", player );
|
|
player RecordGameEvent("plant");
|
|
}
|
|
else
|
|
{
|
|
/#
|
|
player IPrintlnBold( "GAMETYPE DEBUG: NOT GIVING YOU PLANT CREDIT AS BOOSTING PREVENTION" );
|
|
#/
|
|
}
|
|
|
|
level thread popups::DisplayTeamMessageToAll( &"MP_EXPLOSIVES_PLANTED_BY", player );
|
|
globallogic_audio::leader_dialog( "bombPlanted" );
|
|
}
|
|
else
|
|
{
|
|
self gameobjects::set_flags( 0 );
|
|
|
|
player notify ( "bomb_defused" );
|
|
/#print( "bomb defused: " + self.label );#/
|
|
self thread bombDefused( player );
|
|
self resetBombzone();
|
|
|
|
bbPrint( "mpobjective", "gametime %d objtype %s label %s team %s playerx %d playery %d playerz %d", gettime(), "dem_bombdefused", self.label, team, player.origin );
|
|
|
|
if( isdefined(player.pers["defuses"]) )
|
|
{
|
|
player.pers["defuses"]++;
|
|
player.defuses = player.pers["defuses"];
|
|
}
|
|
|
|
if ( !isScoreBoosting( player, self ) )
|
|
{
|
|
demo::bookmark( "event", gettime(), player );
|
|
player AddPlayerStatWithGameType( "DEFUSES", 1 );
|
|
|
|
scoreevents::processScoreEvent( "defused_bomb", player );
|
|
player RecordGameEvent("defuse");
|
|
}
|
|
else
|
|
{
|
|
/#
|
|
player IPrintlnBold( "GAMETYPE DEBUG: NOT GIVING YOU DEFUSE CREDIT AS BOOSTING PREVENTION" );
|
|
#/
|
|
}
|
|
|
|
level thread popups::DisplayTeamMessageToAll( &"MP_EXPLOSIVES_DEFUSED_BY", player );
|
|
|
|
thread globallogic_audio::set_music_on_team( "DEM_WE_DEFUSE", team, 5 );
|
|
thread globallogic_audio::set_music_on_team( "DEM_THEY_DEFUSE", enemyTeam, 5 );
|
|
|
|
globallogic_audio::leader_dialog( "bombDefused" );
|
|
}
|
|
}
|
|
|
|
function onDrop( player )
|
|
{
|
|
if ( !level.bombPlanted )
|
|
{
|
|
globallogic_audio::leader_dialog( "bombFriendlyDropped", player.pers["team"] );
|
|
/#
|
|
if ( isdefined( player ) )
|
|
print( "bomb dropped" );
|
|
else
|
|
print( "bomb dropped" );
|
|
#/
|
|
}
|
|
|
|
player notify( "event_ended" );
|
|
|
|
self gameobjects::set_3d_icon( "friendly", "waypoint_bomb" );
|
|
|
|
sound::play_on_players( game["bomb_dropped_sound"], game["attackers"] );
|
|
}
|
|
|
|
|
|
function onPickup( player )
|
|
{
|
|
player.isBombCarrier = true;
|
|
|
|
self gameobjects::set_3d_icon( "friendly", "waypoint_defend" );
|
|
|
|
if ( !level.bombDefused )
|
|
{
|
|
thread sound::play_on_players( "mus_sd_pickup"+"_"+level.teamPostfix[player.pers["team"]], player.pers["team"] );
|
|
|
|
globallogic_audio::leader_dialog( "bombFriendlyTaken", player.pers["team"] );
|
|
/#print( "bomb taken" );#/
|
|
}
|
|
sound::play_on_players( game["bomb_recovered_sound"], game["attackers"] );
|
|
}
|
|
|
|
|
|
function onReset()
|
|
{
|
|
}
|
|
|
|
function bombReset( label, reason )
|
|
{
|
|
if ( label == "_a" )
|
|
{
|
|
level.bombAPlanted = false;
|
|
SetBombTimer( "A", 0 );
|
|
}
|
|
else
|
|
{
|
|
level.bombBPlanted = false;
|
|
SetBombTimer( "B", 0 );
|
|
}
|
|
|
|
setMatchFlag( "bomb_timer" + label, 0 );
|
|
|
|
if ( !level.bombAPlanted && !level.bombBPlanted )
|
|
globallogic_utils::resumeTimer();
|
|
|
|
self.visuals[0] globallogic_utils::stopTickingSound();
|
|
}
|
|
|
|
function dropBombModel( player, site )
|
|
{
|
|
trace = bulletTrace( player.origin + (0,0,20), player.origin - (0,0,2000), false, player );
|
|
|
|
tempAngle = randomfloat( 360 );
|
|
forward = (cos( tempAngle ), sin( tempAngle ), 0);
|
|
forward = vectornormalize( forward - VectorScale( trace["normal"], vectordot( forward, trace["normal"] ) ) );
|
|
dropAngles = vectortoangles( forward );
|
|
|
|
if ( IsDefined( trace[ "surfacetype" ] ) && trace[ "surfacetype" ] == "water" )
|
|
{
|
|
phystrace = playerPhysicsTrace( player.origin + (0,0,20), player.origin - (0,0,2000) );
|
|
|
|
if ( IsDefined( phystrace ) )
|
|
{
|
|
trace["position"] = phystrace;
|
|
}
|
|
}
|
|
|
|
level.ddBombModel[ site ] = spawn( "script_model", trace["position"] );
|
|
level.ddBombModel[ site ].angles = dropAngles;
|
|
level.ddBombModel[ site ] setModel( "p7_mp_suitcase_bomb" );
|
|
}
|
|
|
|
|
|
function bombPlanted( destroyedObj, player )
|
|
{
|
|
level endon( "game_ended" );
|
|
destroyedObj endon( "bomb_defused" );
|
|
team = player.team;
|
|
game["challenge"][team]["plantedBomb"] = true;
|
|
|
|
globallogic_utils::pauseTimer();
|
|
destroyedObj.bombPlanted = true;
|
|
player SetWeaponOverheating( true, 100, destroyedObj.useWeapon ); // overheating allows for non-quick drop anim to be played
|
|
player PlayBombPlant();
|
|
|
|
destroyedObj.visuals[0] thread globallogic_utils::playTickingSound( "mpl_sab_ui_suitcasebomb_timer" );
|
|
destroyedObj.tickingObject = destroyedObj.visuals[0];
|
|
|
|
label = destroyedObj.label;
|
|
|
|
detonateTime = int( gettime() + (level.bombTimer * 1000) );
|
|
updateBombTimers(label, detonateTime);
|
|
destroyedObj.detonateTime = detonateTime;
|
|
|
|
trace = bulletTrace( player.origin + (0,0,20), player.origin - (0,0,2000), false, player );
|
|
|
|
self dropBombModel( player, destroyedObj.label );
|
|
destroyedObj gameobjects::allow_use( "none" );
|
|
destroyedObj gameobjects::set_visible_team( "none" );
|
|
if ( isdefined( game["overtime_round"] ) )
|
|
{
|
|
destroyedObj gameobjects::set_owner_team( util::getOtherTeam( player.team ) );
|
|
}
|
|
destroyedObj setUpForDefusing();
|
|
|
|
player.isBombCarrier = false;
|
|
game["challenge"][team]["plantedBomb"] = true;
|
|
|
|
destroyedObj waitLongDurationWithBombTimeUpdate( label, level.bombTimer );
|
|
destroyedObj bombReset( label, "bomb_exploded" );
|
|
|
|
if ( level.gameEnded )
|
|
{
|
|
return;
|
|
}
|
|
|
|
origin = (0,0,0);
|
|
if ( isdefined( player ) )
|
|
{
|
|
origin = player.origin;
|
|
}
|
|
bbPrint( "mpobjective", "gametime %d objtype %s label %s team %s playerx %d playery %d playerz %d", gettime(), "dem_bombexplode", label, team, origin );
|
|
|
|
destroyedObj.bombExploded = true;
|
|
game["challenge"][team]["destroyedBombSite"] = true;
|
|
explosionOrigin = destroyedObj.curorigin;
|
|
|
|
level.ddBombModel[ destroyedObj.label ] Delete();
|
|
clips = getEntArray( "bombzone_clip"+destroyedObj.label, "targetname" );
|
|
foreach( clip in clips )
|
|
{
|
|
clip delete();
|
|
}
|
|
|
|
if ( isdefined( player ) )
|
|
{
|
|
destroyedObj.visuals[0] radiusDamage( explosionOrigin, 512, 200, 20, player, "MOD_EXPLOSIVE", GetWeapon( "briefcase_bomb" ) );
|
|
|
|
level thread popups::DisplayTeamMessageToAll( &"MP_EXPLOSIVES_BLOWUP_BY", player );
|
|
|
|
if ( player.team == team )
|
|
{
|
|
player AddPlayerStatWithGameType( "DESTRUCTIONS", 1 );
|
|
player AddPlayerStatWithGameType( "captures", 1 ); // counts towards Destroyer challenge
|
|
// give points for being the bomb destroyer for extra game mode incentive
|
|
scoreevents::processScoreEvent( "bomb_detonated", player );
|
|
}
|
|
|
|
player RecordGameEvent("destroy");
|
|
}
|
|
else
|
|
{
|
|
destroyedObj.visuals[0] radiusDamage( explosionOrigin, 512, 200, 20, undefined, "MOD_EXPLOSIVE", GetWeapon( "briefcase_bomb" ) );
|
|
}
|
|
|
|
currentTime = getTime();
|
|
|
|
if ( isdefined( level.lastBombExplodeTime ) && level.lastBombExplodeByTeam == team )
|
|
{
|
|
if ( level.lastBombExplodeTime + 10000 > currentTime )
|
|
{
|
|
for ( i = 0; i < level.players.size; i++ )
|
|
{
|
|
if ( level.players[i].team == team )
|
|
{
|
|
level.players[i] challenges::bothBombsDetonateWithinTime();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
level.lastBombExplodeTime = currentTime;
|
|
level.lastBombExplodeByTeam = team;
|
|
|
|
rot = randomfloat(360);
|
|
explosionEffect = spawnFx( level._effect["bombexplosion"], explosionOrigin + (0,0,50), (0,0,1), (cos(rot),sin(rot),0) );
|
|
triggerFx( explosionEffect );
|
|
|
|
thread sound::play_in_space( "mpl_sd_exp_suitcase_bomb_main", explosionOrigin );
|
|
|
|
if ( isdefined( destroyedObj.exploderIndex ) )
|
|
exploder::exploder( destroyedObj.exploderIndex );
|
|
|
|
bombZonesLeft = 0;
|
|
|
|
for ( index = 0; index < level.bombZones.size; index++ )
|
|
{
|
|
if ( !isdefined( level.bombZones[index].bombExploded ) || !level.bombZones[index].bombExploded )
|
|
bombZonesLeft++;
|
|
}
|
|
|
|
destroyedObj gameobjects::disable_object();
|
|
|
|
if ( bombZonesLeft == 0 )
|
|
{
|
|
|
|
globallogic_utils::pauseTimer();
|
|
level.hasPausedTimer = true;
|
|
setGameEndTime( 0 );
|
|
wait 3;
|
|
dem_endGame( team, game["strings"]["target_destroyed"] );
|
|
}
|
|
else
|
|
{
|
|
enemyTeam = util::getOtherTeam( team );
|
|
|
|
thread globallogic_audio::set_music_on_team( "DEM_WE_SCORE", team, 5 );
|
|
thread globallogic_audio::set_music_on_team( "DEM_THEY_SCORE", enemyTeam, 5 );
|
|
|
|
//level thread play_one_left_underscore( team, enemyTeam );
|
|
|
|
if( [[level.getTimeLimit]]() > 0 )
|
|
{
|
|
level.usingExtraTime = true;
|
|
}
|
|
|
|
// remove the influencer on this object
|
|
destroyedObj spawning::remove_influencer( destroyedObj.spawnInfluencer );
|
|
destroyedObj.spawnInfluencer = undefined;
|
|
|
|
spawnlogic::clear_spawn_points();
|
|
spawnlogic::add_spawn_points( game["attackers"], "mp_dem_spawn_attacker" );
|
|
spawnlogic::add_spawn_points( game["defenders"], "mp_dem_spawn_defender" );
|
|
if ( label == "_a" )
|
|
{
|
|
spawnlogic::add_spawn_points( game["attackers"], "mp_dem_spawn_attacker_remove_b" );
|
|
spawnlogic::add_spawn_points( game["attackers"], "mp_dem_spawn_attacker_a" );
|
|
spawnlogic::add_spawn_points( game["defenders"], "mp_dem_spawn_defender_b" );
|
|
}
|
|
else
|
|
{
|
|
spawnlogic::add_spawn_points( game["attackers"], "mp_dem_spawn_attacker_remove_a" );
|
|
spawnlogic::add_spawn_points( game["attackers"], "mp_dem_spawn_attacker_b" );
|
|
spawnlogic::add_spawn_points( game["defenders"], "mp_dem_spawn_defender_a" );
|
|
}
|
|
spawning::updateAllSpawnPoints();
|
|
}
|
|
}
|
|
|
|
function getTimeLimit()
|
|
{
|
|
timeLimit = globallogic_defaults::default_getTimeLimit();
|
|
if ( isdefined( game["overtime_round"] ) )
|
|
{
|
|
timeLimit = level.overtimeTimeLimit;
|
|
}
|
|
if ( level.usingExtraTime )
|
|
return timeLimit + level.extraTime;
|
|
return timeLimit;
|
|
|
|
}
|
|
|
|
function shouldPlayOvertimeRound()
|
|
{
|
|
if ( isdefined( game["overtime_round"] ) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if ( game["teamScores"]["allies"] == level.scorelimit - 1 && game["teamScores"]["axis"] == level.scorelimit - 1 )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
function waitLongDurationWithBombTimeUpdate( whichBomb, duration )
|
|
{
|
|
if ( duration == 0 )
|
|
return;
|
|
assert( duration > 0 );
|
|
|
|
starttime = gettime();
|
|
|
|
endtime = gettime() + duration * 1000;
|
|
|
|
while ( gettime() < endtime )
|
|
{
|
|
hostmigration::waitTillHostMigrationStarts( (endtime - gettime()) / 1000 );
|
|
|
|
while ( isdefined( level.hostMigrationTimer ) )
|
|
{
|
|
endTime += 250;
|
|
updateBombTimers(whichBomb, endTime);
|
|
wait 0.25;
|
|
}
|
|
}
|
|
/#
|
|
if( gettime() != endtime )
|
|
println("SCRIPT WARNING: gettime() = " + gettime() + " NOT EQUAL TO endtime = " + endtime);
|
|
#/
|
|
while ( isdefined( level.hostMigrationTimer ) )
|
|
{
|
|
endTime += 250;
|
|
updateBombTimers(whichBomb, endTime);
|
|
wait 0.250;
|
|
}
|
|
|
|
return gettime() - starttime;
|
|
}
|
|
|
|
function updateBombTimers(whichBomb, detonateTime)
|
|
{
|
|
if ( whichBomb == "_a" )
|
|
{
|
|
level.bombAPlanted = true;
|
|
SetBombTimer( "A", int(detonateTime) );
|
|
}
|
|
else
|
|
{
|
|
level.bombBPlanted = true;
|
|
SetBombTimer( "B", int(detonateTime) );
|
|
}
|
|
|
|
setMatchFlag( "bomb_timer" + whichBomb, int(detonateTime) );
|
|
}
|
|
|
|
function bombDefused( player )
|
|
{
|
|
self.tickingObject globallogic_utils::stopTickingSound();
|
|
self gameobjects::allow_use( "none" );
|
|
self gameobjects::set_visible_team( "none" );
|
|
self.bombDefused = true;
|
|
self notify( "bomb_defused" );
|
|
self.bombPlanted = false;
|
|
self bombReset( self.label, "bomb_defused" );
|
|
player SetWeaponOverheating( true, 100, self.useWeapon ); // overheating allows for non-quick drop anim to be played
|
|
player PlayBombDefuse();
|
|
}
|
|
|
|
function play_one_left_underscore( team, enemyTeam )
|
|
{
|
|
wait(3);
|
|
|
|
if( (!isdefined(team)) || (!isdefined(enemyTeam)) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
thread globallogic_audio::set_music_on_team( "DEM_ONE_LEFT_UNDERSCORE", team );
|
|
thread globallogic_audio::set_music_on_team( "DEM_ONE_LEFT_UNDERSCORE", enemyTeam );
|
|
}
|
|
|
|
function updateEventsPerMinute()
|
|
{
|
|
if ( !isdefined( self.eventsPerMinute ) )
|
|
{
|
|
self.numBombEvents = 0;
|
|
self.eventsPerMinute = 0;
|
|
}
|
|
|
|
self.numBombEvents++;
|
|
|
|
minutesPassed = globallogic_utils::getTimePassed() / ( 60 * 1000 );
|
|
|
|
// players use the actual time played
|
|
if ( IsPlayer( self ) && isdefined(self.timePlayed["total"]) )
|
|
minutesPassed = self.timePlayed["total"] / 60;
|
|
|
|
self.eventsPerMinute = self.numBombEvents / minutesPassed;
|
|
if ( self.eventsPerMinute > self.numBombEvents )
|
|
self.eventsPerMinute = self.numBombEvents;
|
|
}
|
|
|
|
function isScoreBoosting( player, flag )
|
|
{
|
|
if ( !level.rankedMatch )
|
|
return false;
|
|
|
|
if ( player.eventsPerMinute > level.playerEventsLPM )
|
|
return true;
|
|
|
|
if ( flag.eventsPerMinute > level.bombEventsLPM )
|
|
return true;
|
|
|
|
return false;
|
|
}
|