#using scripts\codescripts\struct; #using scripts\shared\gameobjects_shared; #using scripts\shared\math_shared; #using scripts\shared\popups_shared; #using scripts\shared\rank_shared; #using scripts\shared\sound_shared; #using scripts\shared\scoreevents_shared; #using scripts\shared\util_shared; #using scripts\mp\gametypes\_globallogic; #using scripts\mp\gametypes\_globallogic_audio; #using scripts\mp\gametypes\_globallogic_score; #using scripts\mp\gametypes\_spawning; #using scripts\mp\gametypes\_spawnlogic; #using scripts\mp\_util; #using scripts\mp\teams\_teams; #using scripts\mp\killstreaks\_killstreaks; /* Team Defender Objective: Score points for your team by eliminating players on the opposing team. Team with flag scores double kill points. First corpse spawns the flag. Map ends: When one team reaches the score limit, or time limit is reached Respawning: No wait / Near teammates Level requirementss ------------------ Spawnpoints: classname mp_tdm_spawn All players spawn from these. The spawnpoint chosen is dependent on the current locations of teammates and enemies at the time of spawn. Players generally spawn behind their teammates relative to the direction of enemies. Spectator Spawnpoints: classname mp_global_intermission Spectators spawn from these and intermission is viewed from these positions. Atleast one is required, any more and they are randomly chosen between. */ #precache( "string", "OBJECTIVES_TDEF" ); #precache( "string", "OBJECTIVES_TDEF_SCORE" ); #precache( "string", "OBJECTIVES_TDEF_ATTACKER_HINT" ); #precache( "string", "MP_NEUTRAL_FLAG_CAPTURED_BY" ); #precache( "string", "MP_NEUTRAL_FLAG_DROPPED_BY" ); #precache( "string", "MP_GRABBING_FLAG" ); #precache( "string", "OBJECTIVES_TDEF_ATTACKER_HINT" ); #precache( "string", "OBJECTIVES_TDEF_DEFENDER_HINT" ); #precache( "string", "OBJECTIVES_TDEF" ); #precache( "string", "OBJECTIVES_TDEF_SCORE" ); #precache( "string", "OBJECTIVES_TDEF_HINT" ); #precache( "string", "MP_FIRST_BLOOD" ); function main() { globallogic::init(); util::registerRoundSwitch( 0, 9 ); util::registerTimeLimit( 0, 1440 ); util::registerScoreLimit( 0, 10000 ); util::registerRoundLimit( 0, 10 ); util::registerNumLives( 0, 100 ); level.matchRules_enemyFlagRadar = true; level.matchRules_damageMultiplier = 0; level.matchRules_vampirism = 0; setSpecialLoadouts(); level.teamBased = true; level.initGametypeAwards =&initGametypeAwards; level.onPrecacheGameType =&onPrecacheGameType; level.onStartGameType =&onStartGameType; level.onPlayerKilled =&onPlayerKilled; level.onSpawnPlayer =&onSpawnPlayer; level.onRoundEndGame =&onRoundEndGame; level.onRoundSwitch =&onRoundSwitch; gameobjects::register_allowed_gameobject( level.gameType ); gameobjects::register_allowed_gameobject( "tdm" ); game["dialog"]["gametype"] = "team_def"; if ( getDvarInt( "g_hardcore" ) ) game["dialog"]["gametype"] = "hc_" + game["dialog"]["gametype"]; game["dialog"]["got_flag"] = "ctf_wetake"; game["dialog"]["enemy_got_flag"] = "ctf_theytake"; game["dialog"]["dropped_flag"] = "ctf_wedrop"; game["dialog"]["enemy_dropped_flag"] = "ctf_theydrop"; game["strings"]["overtime_hint"] = &"MP_FIRST_BLOOD"; } function onPrecacheGameType() { } function onStartGameType() { setClientNameMode("auto_change"); if ( !isdefined( game["switchedsides"] ) ) game["switchedsides"] = false; if ( game["switchedsides"] ) { oldAttackers = game["attackers"]; oldDefenders = game["defenders"]; game["attackers"] = oldDefenders; game["defenders"] = oldAttackers; } util::setObjectiveText( "allies", &"OBJECTIVES_TDEF" ); util::setObjectiveText( "axis", &"OBJECTIVES_TDEF" ); if ( level.splitscreen ) { util::setObjectiveScoreText( "allies", &"OBJECTIVES_TDEF" ); util::setObjectiveScoreText( "axis", &"OBJECTIVES_TDEF" ); } else { util::setObjectiveScoreText( "allies", &"OBJECTIVES_TDEF_SCORE" ); util::setObjectiveScoreText( "axis", &"OBJECTIVES_TDEF_SCORE" ); } util::setObjectiveHintText( "allies", &"OBJECTIVES_TDEF_ATTACKER_HINT" ); util::setObjectiveHintText( "axis", &"OBJECTIVES_TDEF_ATTACKER_HINT" ); level.spawnMins = ( 0, 0, 0 ); level.spawnMaxs = ( 0, 0, 0 ); spawnlogic::place_spawn_points( "mp_tdm_spawn_allies_start" ); spawnlogic::place_spawn_points( "mp_tdm_spawn_axis_start" ); spawnlogic::add_spawn_points( "allies", "mp_tdm_spawn" ); spawnlogic::add_spawn_points( "axis", "mp_tdm_spawn" ); spawning::updateAllSpawnPoints(); level.mapCenter = math::find_box_center( level.spawnMins, level.spawnMaxs ); setMapCenter( level.mapCenter ); spawnpoint = spawnlogic::get_random_intermission_point(); setDemoIntermissionPoint( spawnpoint.origin, spawnpoint.angles ); if ( !util::isOneRound() ) { level.displayRoundEndText = true; if( level.scoreRoundWinBased ) { globallogic_score::resetTeamScores(); } } tdef(); } function tdef() { // level.icon2D["allies"] = teams::get_flag_icon( "allies" ); // level.icon2D["axis"] = teams::get_flag_icon( "axis" ); level.carryFlag["allies"] = teams::get_flag_carry_model( "allies" ); level.carryFlag["axis"] = teams::get_flag_carry_model( "axis" ); level.carryFlag["neutral"] = teams::get_flag_model( "neutral" ); level.gameFlag = undefined; } function onPlayerKilled( eInflictor, attacker, iDamage, sMeansOfDeath, weapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration ) { if ( !isPlayer( attacker ) || attacker.team == self.team ) return; victim = self; score = rank::getScoreInfoValue( "kill" ); assert( isdefined( score ) ); // we got the flag - give bonus if ( isdefined( level.gameFlag ) && level.gameFlag gameobjects::get_owner_team() == attacker.team ) { // I'm the carrier if ( isdefined( attacker.carryFlag ) ) { attacker AddPlayerStat( "KILLSASFLAGCARRIER", 1 ); } // someone else is else { // give flag carrier a bonus for kills achieved by team // scoreevents::processScoreEvent( "team_assist", level.gameFlag.carrier ); } //scoreevents::processScoreEvent( "kill_bonus", attacker ); score *= 2; } // no flag yet - create it else if ( !isdefined( level.gameFlag ) && canCreateFlagAtVictimOrigin( victim ) ) { level.gameFlag = createFlag( victim ); score += rank::getScoreInfoValue( "MEDAL_FIRST_BLOOD" ); } // killed carrier - give bonus else if ( isdefined( victim.carryFlag ) ) { killCarrierBonus = rank::getScoreInfoValue( "kill_carrier" ); level thread popups::DisplayTeamMessageToAll( &"MP_KILLED_FLAG_CARRIER", attacker ); scoreevents::processScoreEvent( "kill_flag_carrier", attacker ); attacker RecordGameEvent("kill_carrier"); attacker AddPlayerStat( "FLAGCARRIERKILLS", 1 ); attacker notify( "objective", "kill_carrier" ); score += killCarrierBonus; } if( !isdefined( killstreaks::get_killstreak_for_weapon( weapon ) ) || ( isdefined( level.killstreaksGiveGameScore ) && level.killstreaksGiveGameScore ) ) attacker globallogic_score::giveTeamScoreForObjective( attacker.team, score ); otherTeam = util::getOtherTeam( attacker.team ); if ( game["state"] == "postgame" && game["teamScores"][attacker.team] > game["teamScores"][otherTeam] ) attacker.finalKill = true; } function onDrop( player ) { // get the time when they dropped it if( isdefined( player ) && isdefined( player.tdef_flagTime ) ) { flagTime = int( GetTime() - player.tdef_flagTime ); player AddPlayerStat( "HOLDINGTEAMDEFENDERFLAG", flagTime ); if ( ( flagTime/100 ) / 60 < 1 ) flagMinutes = 0; else flagMinutes = int( ( flagTime/100 ) / 60 ); player AddPlayerStatWithGameType( "DESTRUCTIONS", flagMinutes ); player.tdef_flagTime = undefined; player notify( "dropped_flag" ); } team = self gameobjects::get_owner_team(); otherTeam = util::getOtherTeam( team ); self.currentCarrier = undefined; self gameobjects::set_owner_team( "neutral" ); self gameobjects::allow_carry( "any" ); self gameobjects::set_visible_team( "any" ); self gameobjects::set_2d_icon( "friendly", level.iconCaptureFlag2D ); self gameobjects::set_3d_icon( "friendly", level.iconCaptureFlag3D ); self gameobjects::set_2d_icon( "enemy", level.iconCaptureFlag2D ); self gameobjects::set_3d_icon( "enemy", level.iconCaptureFlag3D ); if ( isdefined( player ) ) { if ( isdefined( player.carryFlag ) ) player detachFlag(); util::printAndSoundOnEveryone( team, undefined, &"MP_NEUTRAL_FLAG_DROPPED_BY", &"MP_NEUTRAL_FLAG_DROPPED_BY", "mp_war_objective_lost", "mp_war_objective_lost", player ); } else { sound::play_on_players( "mp_war_objective_lost", team ); sound::play_on_players( "mp_war_objective_lost", otherTeam ); } globallogic_audio::leader_dialog( "dropped_flag", team); globallogic_audio::leader_dialog( "enemy_dropped_flag", otherTeam ); } function onPickup( player ) { self notify ( "picked_up" ); // get the time when they picked it up player.tdef_flagTime = GetTime(); player thread watchForEndGame(); score = rank::getScoreInfoValue( "capture" ); assert( isdefined( score ) ); team = player.team; otherTeam = util::getOtherTeam( team ); // flag carrier class? (do before attaching flag) if ( isdefined( level.tdef_loadouts ) && isdefined( level.tdef_loadouts[team] ) ) player thread applyFlagCarrierClass(); // attaches flag else player attachFlag(); self.currentCarrier = player; player.carryIcon setShader( level.icon2D[team], player.carryIcon.width, player.carryIcon.height ); self gameobjects::set_owner_team( team ); self gameobjects::set_visible_team( "any" ); self gameobjects::set_2d_icon( "friendly", level.iconEscort2D ); self gameobjects::set_3d_icon( "friendly", level.iconEscort2D ); self gameobjects::set_2d_icon( "enemy", level.iconKill3D ); self gameobjects::set_3d_icon( "enemy", level.iconKill3D ); globallogic_audio::leader_dialog( "got_flag", team ); globallogic_audio::leader_dialog( "enemy_got_flag", otherTeam ); level thread popups::DisplayTeamMessageToAll( &"MP_CAPTURED_THE_FLAG", player ); scoreevents::processScoreEvent( "flag_capture", player ); player RecordGameEvent("pickup"); player AddPlayerStatWithGameType( "CAPTURES", 1 ); player notify( "objective", "captured" ); util::printAndSoundOnEveryone( team, undefined, &"MP_NEUTRAL_FLAG_CAPTURED_BY", &"MP_NEUTRAL_FLAG_CAPTURED_BY", "mp_obj_captured", "mp_enemy_obj_captured", player ); // give a capture bonus to the capturing team if the flag is changing hands if ( self.currentTeam == otherTeam ) player globallogic_score::giveTeamScoreForObjective( team, score ); self.currentTeam = team; // activate portable radar on flag for the opposing team if ( level.matchRules_enemyFlagRadar ) self thread flagAttachRadar( otherTeam ); } function applyFlagCarrierClass() { self endon( "death" ); self endon( "disconnect" ); level endon( "game_ended" ); // remove placement item if carrying if ( isdefined( self.isCarrying ) && self.isCarrying == true ) { self notify( "force_cancel_placement" ); {wait(.05);}; } // set the gamemodeloadout for loadout::giveLoadout() to use self.pers["gamemodeLoadout"] = level.tdef_loadouts[self.team]; // set faux TI to respawn in place spawnPoint = spawn( "script_model", self.origin ); spawnPoint.angles = self.angles; spawnPoint.playerSpawnPos = self.origin; spawnPoint.notTI = true; self.setSpawnPoint = spawnPoint; // globallogic_spawn::spawnPlayer() calls loadout::giveLoadout() passing the player's class // save their chosen class and override their current and last class // - both so killstreaks don't get reset // - this is automatically set back to chosen class within loadout::giveLoadout() self.gamemode_chosenClass = self.curClass; self.pers["class"] = "gamemode"; self.pers["lastClass"] = "gamemode"; self.curClass = "gamemode"; self.lastClass = "gamemode"; // attach flag after faux spawn (model may change for sniper or juggernaut loadout) self thread waitAttachFlag(); } function waitAttachFlag() { level endon( "game_ende" ); self endon( "disconnect" ); self endon( "death" ); self waittill( "spawned_player" ); self attachFlag(); } function watchForEndGame() { self endon( "dropped_flag" ); self endon( "disconnect" ); level waittill( "game_ended" ); if( isdefined( self ) ) { if( isdefined( self.tdef_flagTime ) ) { flagTime = int( GetTime() - self.tdef_flagTime ); self AddPlayerStat( "HOLDINGTEAMDEFENDERFLAG", flagTime ); if ( ( flagTime/100 ) / 60 < 1 ) flagMinutes = 0; else flagMinutes = int( (flagTime/100)/60 ); self AddPlayerStatWithGameType( "DESTRUCTIONS", flagMinutes ); } } } function canCreateFlagAtVictimOrigin( victim ) { mineTriggers = getEntArray( "minefield", "targetname" ); hurtTriggers = getEntArray( "trigger_hurt", "classname" ); radTriggers = getEntArray( "radiation", "targetname" ); for ( index = 0; index < radTriggers.size; index++ ) { if ( victim isTouching( radTriggers[index] ) ) return false; } for ( index = 0; index < mineTriggers.size; index++ ) { if ( victim isTouching( mineTriggers[index] ) ) return false; } for ( index = 0; index < hurtTriggers.size; index++ ) { if ( victim isTouching( hurtTriggers[index] ) ) return false; } return true; } function createFlag( victim ) { // flag visuals[0] = spawn( "script_model", victim.origin ); visuals[0] setModel( level.carryFlag["neutral"] ); // trigger trigger = spawn( "trigger_radius", victim.origin, 0, 96, 72); gameFlag = gameobjects::create_carry_object( "neutral", trigger, visuals, (0,0,85) ); gameFlag gameobjects::allow_carry( "any" ); gameFlag gameobjects::set_visible_team( "any" ); gameFlag gameobjects::set_2d_icon( "enemy", level.iconCaptureFlag2D ); gameFlag gameobjects::set_3d_icon( "enemy", level.iconCaptureFlag3D ); gameFlag gameobjects::set_2d_icon( "friendly", level.iconCaptureFlag2D ); gameFlag gameobjects::set_3d_icon( "friendly", level.iconCaptureFlag3D ); gameFlag gameobjects::set_carry_icon( level.icon2D["axis"] ); //temp, manually changed after picked up gameFlag.allowWeapons = true; gameFlag.onPickup =&onPickup; gameFlag.onPickupFailed =&onPickup; gameFlag.onDrop =&onDrop; gameFlag.oldRadius = 96; gameFlag.currentTeam = "none"; gameFlag.requiresLOS = true; // set it as flag trigger when on ground level.favorCloseSpawnEnt = gameFlag.trigger; level.favorCloseSpawnScalar = 3; // for this mode, the flag's home position is wherever its last safe position was, not where it was initially created gameFlag thread updateBasePosition(); return gameFlag; } function updateBasePosition() { level endon( "game_ended" ); while( true ) { if ( isdefined( self.safeOrigin ) ) { self.baseOrigin = self.safeOrigin; self.trigger.baseOrigin = self.safeOrigin; self.visuals[0].baseOrigin = self.safeOrigin; } {wait(.05);}; } } function attachFlag() { self attach( level.carryFlag[self.team], "J_spine4", true ); self.carryFlag = level.carryFlag[self.team]; // set it as flag carrier when carried level.favorCloseSpawnEnt = self; } function detachFlag() { self detach( self.carryFlag, "J_spine4" ); self.carryFlag = undefined; // set it as flag trigger when on ground level.favorCloseSpawnEnt = level.gameFlag.trigger; } function flagAttachRadar( team ) { level endon("game_ended"); self endon( "dropped" ); } function getFlagRadarOwner( team ) { level endon("game_ended"); self endon( "dropped" ); while ( true ) { foreach( player in level.players ) { if ( isAlive( player ) && player.team == team ) return player; } {wait(.05);}; } } function flagRadarMover() { level endon("game_ended"); self endon( "dropped" ); self.portable_radar endon( "death" ); for( ;; ) { self.portable_radar MoveTo( self.currentCarrier.origin, .05 ); {wait(.05);}; } } function flagWatchRadarOwnerLost() { level endon("game_ended"); self endon( "dropped" ); radarTeam = self.portable_radar.team; self.portable_radar.owner util::waittill_any( "disconnect", "joined_team", "joined_spectators" ); // make a new one flagAttachRadar( radarTeam ); } function onRoundEndGame( roundWinner ) { winner = globallogic::determineTeamWinnerByGameStat( "roundswon" ); return winner; } function onSpawnPlayer(predictedSpawn) { self.usingObj = undefined; if ( level.useStartSpawns && !level.inGracePeriod ) { level.useStartSpawns = false; } spawning::onSpawnPlayer(predictedSpawn); } function onRoundSwitch() { game["switchedsides"] = !game["switchedsides"]; } function initGametypeAwards() { } function setSpecialLoadouts() { }