Setting up 1v1 Warmup Arenas

From Valve Developer Community
Jump to navigation Jump to search
English (en)Translate (Translate)
Official Maps with 1v1 Warmup Arenas
Map Name BSP name
Dust II de_dust2
Inferno de_inferno
Mirage de_mirage
Nuke de_nuke
Overpass de_overpass
Shortnuke de_shortnuke
Train de_train
Vertigo de_vertigo
Pick/Ban lobby
(Broken Fang Premier Mode)
lobby_mapveto
1v1 Weapons
AK-47
Galil AR
FAMAS
AWP
M4A4
M4A1-S
Desert Eagle
USP-S
Glock-18
Counter-Strike: Global Offensive Level Creation
Icon-delisted.png
This page documents information about a game or software, Counter-Strike: Global Offensive Counter-Strike: Global Offensive, that is no longer available for purchase or download digitally.
It is covered here for historical and technical reference.

This is the documentation of a way to use the VScripts

  • csgo/scripts/vscripts/warmup/warmup_arena.nut
  • csgo/scripts/vscripts/warmup/warmup_teleport.nut

that are designed for the management of 1v1 warmup arenas in Counter-Strike: Global Offensive Counter-Strike: Global Offensive.

The implementation described below equals the one of de_vertigo (2021-05-05).

Gameplay Description

Officially, the 1v1 warmup plays as follows:

  • It is only active during warmup of the game modes CS:GO/CS2 Competitive Competitive and CS:GO/CS2 Wingman Wingman, i.e. if game_type is 0 and game_mode is 1 or 2.
  • During warmup, respawning players are teleported to a separate room ("1v1 arena") with one enemy player (if there is one), emitting the player spawn sound used in CS:GO/CS2 Deathmatch Deathmatch.
  • Both players get 100 HP, kevlar (no helmet), their knife and a randomly chosen weapon from a hard-coded list inside warmup_arena.nut.
  • If there is only one player in an arena, he will be reset in this arena if a respawning enemy player is teleported there.
  • Dropped weapons are cleared in an arena if two players spawn, namely in a sphere around the arena's logic_script with a radius of 640 units.
  • In Competitive, 5 arenas are used. In Wingman, only 2 arenas are regarded.
Warning.pngWarning:Having more than 5 players on one team causes an infinite loop freezing the game!

Map Requirements

This section covers the requirements to a map to additionally support 1v1 warmup arenas.

Overview

This is how the following implementation will work:

  • During warmup, the players actually spawn at their default spawns on the regular part of the map, but all of the spawn points are inside a big trigger_multiple that teleports them into an arena with a free slot. The VScript warmup/warmup_teleport.nut is the entity script of those triggers and handles the assignment of players to the arenas.
  • Each of the 5 arenas has a logic_script with the VScript warmup/warmup_arena.nut keeping track of its current players.
  • In each arena there are two trigger_multiples inside each other with different team filters filling the entire volume of the arena. These shall fire outputs if a (Counter-)Terrorist enters an arena or dies in one to lock or unlock that arena for other players.

Required Entities - General

These entities are required once in the map.

Class Where? Name KeyValues Outputs Comment
trigger_multiple so that all Competitive and Wingman CT spawns are inside it not needed
Property Name Value
Entity Scripts warmup/warmup_teleport.nut
Start Disabled Yes
Filter Name @warmup.filter_ct
Delay Before Reset 0
  My Output Target Entity Target Input Parameter Delay Only Once
Io11.png OnTrigger !self RunScriptCode PlayerSpawnedCT() 0.00 No
Tip.pngTip: One can create two unique trigger brushes for Competitive and Wingman spawns of a team, select both and hit Ctrl+T to tie them to a single trigger_multiple.
trigger_multiple so that all Competitive and Wingman T spawns are inside it not needed
Property Name Value
Entity Scripts warmup/warmup_teleport.nut
Start Disabled Yes
Filter Name @warmup.filter_t
Delay Before Reset 0
  My Output Target Entity Target Input Parameter Delay Only Once
Io11.png OnTrigger !self RunScriptCode PlayerSpawnedT() 0.00 No
filter_activator_team anywhere @warmup.filter_ct
Property Name Value
Filter Team Number Counter-Terrorist
The previous and the following triggers rely on these, because the scripts must differentiate between Terrorists and Counter-Terrorists.
filter_activator_team anywhere @warmup.filter_t
Property Name Value
Filter Team Number Terrorist
game_player_equip anywhere @warmup.weapon_equip_empty
Property Name Value
Spawnflags 3 (Flags Use only and
Strip All Weapons First)
This is used to clear the weapons of (re-)spawning players before they are equipped by an arena script.

Required Entities - Arenas

The following is required for every individual arena. To avoid VScript errors, there should be at least 5 arenas, which is also the maximum number of arenas that the scripts (currently) support.

Geometry and Detail

As a guideline: Valve uses room dimensions of about 512x1024x192 units for each arena. Still, it is possible to make them smaller or slightly larger.

Note.pngNote: The arena script cleans up weapons lying around within a radius of 640 units from it. To have every dropped weapon removed, the playable area must be inside this radius. To visualize it, you can e.g. make a temporary skip-cylinder brush. Some maximum rectangular floor dimensions are 900x900, 1024x768, 1152x512, but it is not wrong to use smaller areas.

The official maps use cover for both players, especially so that there is no direct line of sight between the two players' spawn points. The arenas are completely separated from the rest of the map, although they needn't.

Tip.pngTip: If you want identical arenas, make an instance to make making changes to all arenas a lot easier.

Player Spawning Logic

The following entities are required for each arena. The entity names must be exact because the scripts rely on them.

If you are done creating one arena and you want to copy-paste it, you have to make renaming changes to these entities, which is the adjustment of the yellow highlighted 1's. Replace them by 2, 3, 4 and 5 accordingly.

Tip.pngTip:

To keep the renaming work at a minimum, make an instance only with the following five arena specific entities.

  • Inside this instance, omit the prefix "arenaX-" (including the dash) wherever it appears.
  • In the actual map, place a func_instance inside an arena, select the VMF and set the Fix Up Name (the named entities' prefix) to arena1, ..., arena5. The previously omitted dash will be added automatically.
  • Make sure that the trigger dimensions (see below) fill the entire playable area of each arena. This can be ensured by adding clip brushes to the instance around the triggers.
Class Where? Name KeyValues Outputs Comment
info_target place as CT spawn point, including orientation arena1-ctspawn The scripts will only call GetOrigin() and GetAngles() from these entities to teleport players to them, so one could use any entity for this purpose if it has a name, an origin and an orientation, e.g. info_player_start, however its keyvalue targetname for the Name must be added manually with SmartEdit turned off.
info_target place as T spawn point, including orientation arena1-tspawn
logic_script in the middle of the arena on the ground arena1-script
Property Name Value
Entity Scripts warmup/warmup_arena.nut
Think Function ArenaStart
EntityGroup[0] arena1-trigger_ct
EntityGroup[1] arena1-trigger_t
This entity should be placed in the center of the arena on the ground due to the weapon clearing radius of 640 units around it.
The Think function fires the input TouchTest to the following two triggers every 0.1 seconds.[Why?]
trigger_multiple fills the entire playable area of the arena arena1-trigger_ct
Property Name Value
Filter Name @warmup.filter_ct
  My Output Target Entity Target Input Parameter Delay Only Once
Io11.png OnEndTouch arena1‑script RunScriptCode EnableCTSpawn() 0.00 No
Io11.png OnStartTouch arena1‑script RunScriptCode DisableCTSpawn() 0.00 No
Tip.pngTip: As these are two brushes with identical dimensions, use H and U in Hammer to hide and unhide one of them, to make selecting the other easier.
The functions DisableCTSpawn() and DisableTSpawn() save the activator assuming it is a player, so the trigger's output cannot be OnTouching, as it uses the trigger as activator, causing VScript errors. The OnEndTouch output is exchangeable with OnNotTouching.
trigger_multiple fills the entire playable area of the arena arena1-trigger_t
Property Name Value
Filter Name @warmup.filter_t
  My Output Target Entity Target Input Parameter Delay Only Once
Io11.png OnEndTouch arena1‑script RunScriptCode EnableTSpawn() 0.00 No
Io11.png OnStartTouch arena1‑script RunScriptCode DisableTSpawn() 0.00 No

Testing and Debugging

] ent_fire logic_script runscriptcode "DebugInfo()"
===arena1 debug info: ===
Available T spawn = false
Available CT spawn = false
Current T player = ([9] player)
Current CT player = ([6] player)
===arena1 end debug info ===
===arena2 debug info: ===
Available T spawn = false
Available CT spawn = true
Current T player = ([5] player)
Current CT player = (null : 0x00000000)
===arena2 end debug info ===
===arena3 debug info: ===
Available T spawn = false
Available CT spawn = false
Current T player = ([2] player)
Current CT player = ([3] player)
===arena3 end debug info ===
===arena4 debug info: ===
Available T spawn = false
Available CT spawn = false
Current T player = ([4] player)
Current CT player = ([1] player)
===arena4 end debug info ===
===arena5 debug info: ===
Available T spawn = true
Available CT spawn = false
Current T player = (null : 0x00000000)
Current CT player = ([7] player)
===arena5 end debug info ===

To see if everything works correctly, you can open in the console and

  • look for VScript errors.
  • invoke sv_cheats 1 and ent_messages_draw 1 to visualize I/O.
  • invoke sv_cheats 1 and ent_fire logic_script runscriptcode "DebugInfo()" to see the states of each arena, as seen on the right. To avoid VScript error messages from other logic_scripts, you can also do "try {DebugInfo()} catch(ex) {}".
    • The Available T/CT spawn should be false if there is a T/CT in the arena.
    • The Current T/CT player should either be null if the corresponding spawn is available or a ([?] player) if not.

Modifying Gameplay

You cannot or should not manipulate the orignal scripts

  • csgo/scripts/vscripts/warmup/warmup_arena.nut
  • csgo/scripts/vscripts/warmup/warmup_teleport.nut,

but you can still change gameplay per map by e.g. copy-pasting these scripts and editing them or by firing RunScriptCode to the arena scripts or by writing an own VScript to change variables or functions in the arena scripts.

For example, you could create a logic_script in your map and set its Entity Scripts to a .nut file with the following content which will change the weapons, replace kevlar with kevlar + helmet and increase the weapon clearing radius.

Script example for gameplay modification  
// Copy-pasted from warmup_arena.nut, renamed and modified
WEAPON_NEW <- [
	"weapon_ak47",
	"weapon_p250",
	"weapon_mp5sd",
	"weapon_nova",
	"weapon_negev",
	"weapon_ssg08",
	"weapon_breachcharge"
]

// Copy-pasted from warmup_arena.nut, renamed and modified
function RemoveDroppedWeaponsNew()
{
	local radius = 1024.0 // added radius variable and inserted it below
	local origin = self.GetOrigin();
	local DroppedGun = null;
	
		while( ( DroppedGun = Entities.FindByClassnameWithin (DroppedGun, "weapon_*", origin, radius) ) != null )
		{
			if (DroppedGun.GetOwner() == null)		// if it doesnt have a owner, kill it
			{
				DroppedGun.Destroy();
			}
		}

}

// Copy-pasted from warmup_arena.nut, renamed and modified
function GiveGunNew( weapon )
{
	local equipper = Entities.CreateByClassname( "game_player_equip" )

	// set flags and keyvalues
	equipper.__KeyValueFromInt( "spawnflags", 5 )
	equipper.__KeyValueFromInt( "weapon_knife", 0 )
	equipper.__KeyValueFromInt( "item_assaultsuit", 0 ) // replaced "item_kevlar", adds helmet
	equipper.__KeyValueFromInt( weapon, 0 )

	equipper.ValidateScriptScope()

	EntFireByHandle( equipper, "Use", "", 0, PLAYER_CT, null )
	EntFireByHandle( equipper, "Use", "", 0, PLAYER_T, null )
	
	EntFireByHandle( equipper, "Kill", "", 0.1, null, null )
}



// Get arena script handles (just like warmup_teleport.nut)
// For less redundance: We want to make the same changes to all of them, so make a list to iterate over them
ARENAS <- [
	ARENA1_SCRIPT <- Entities.FindByName(null, "arena1-script"),
	ARENA2_SCRIPT <- Entities.FindByName(null, "arena2-script"),
	ARENA3_SCRIPT <- Entities.FindByName(null, "arena3-script"),
	ARENA4_SCRIPT <- Entities.FindByName(null, "arena4-script"),
	ARENA5_SCRIPT <- Entities.FindByName(null, "arena5-script")
]

// Actual modification. This function is called automatically when all entities have spawned.
function OnPostSpawn()
{
	foreach (arena in ARENAS)
	{
		// modifications to each arena script:
		arena.GetScriptScope().WEAPON               = WEAPON_NEW              // replace weapon list
		arena.GetScriptScope().RemoveDroppedWeapons = RemoveDroppedWeaponsNew // change weapon clear radius
		arena.GetScriptScope().GiveGun              = GiveGunNew              // change armor
	}
}