Создание карт режима "Кооперативный налёт"

From Valve Developer Community
Jump to: navigation, search
English


Совместный Налёт (далее coop) - это кооперативный режим игры, впервые включенный в Counter-Strike: Global Offensive, как часть Операции "Дикое пламя". Как и режим "Страж", он эксклюзивно доступен через саму операцию, но также возможен доступ через консоль.

В налёте, 2 игрока идут против стадий, контролируемыми ИИ, террористов по сюжетно-ориентированному сценарию. Префикс карт данного режима - "coop_".

Создание миссий налёта - долгая работа и она ожидает базовых знаний о том, как работать с сущностями (далее энтити), Вводами/Выводами (далее I/O), да и вообще о том как создавать карты... Так что не рекомендуется создавать миссии Налёта без опыта в маппинге.

Нужные энтити для миссий Совместного Налёта

Сперва, давайте рассмотрим все энтити нужные для режима игры Налёт и некоторые энтити, использовавшиеся в туториале.

  • info_enemy_terrorist_spawn: Место, где будет спавниться враг.
  • logic_script: Энтити, которая будет воспроизводить функции Vscript.
  • game_coopmission_manager: Эта энтити даёт сигнал вывода, когда специальные события происходят. Например, когда Волна пройдена, эта энтити распознаёт это и подаёт сигнал Вывода (Output).
  • item_coop_coin: Секретная монета, при подборе которой даёт дополнительные очки в конце уровня. На данный момент 3 монеты доступно, чтобы карта работала.
  • point_hiding_spot: Просто говорит ботам "Эй! Это же хорошее место, чтобы покрысить!))".
  • prop_exploding_barrel: Это бочка, при выстреле в которую, она бабахнет!
  • info_hostage_spawn: Заложник.
  • game_round_end: Это может завершить раунд, в пользу одной из команд или вничью. Используется в coop картах, где цель не спасти заложника, а просто дойти до конца уровня.

Создание карты

Environment

When starting your map keep Co-op in your mind. Make sure there are plenty of hiding spots for either the Players or the bots. Think of places where you want to place new weapons for the players to use. Think of maybe nifty ways to use the environment to the players advantage. Note that it is Players VS AI which is different from any other gamemode.

Co-op is based around a "Wave" system. This means that there is a group of enemies, usually 5, that the player has to exterminate in order to advance to the next part of the map. So when creating the map split your map up in multiple parts. Each part will have its own enemies by your choosing. Unles you want one big linear map with 40 enemies at once. Split your map up in different parts so that you can only advance once the "Wave" is completed.

Player Spawn

The players will need a spawnpoint where they can "relax" and setup for the fight that is about to commence. In the spawnroom the player will have to choose weapons and grenades that they will use in the upcoming level. In the spawn there should also be a way to adjust the difficulty of the bots so that the level is playable in "hardcore mode". For better gameplay give the players "crappy" weapons at the beginning so they will look around in your map for better gear.

The way you create your spawn is up to you. You can either have a simple door devide the spawn with the enemies or you coul have a fancy helicopter "cutscene" take you to the actual level. Be as creative as you can be.

Must have Co-op Entities

In order for Co-op strike to function properly you'll have to place a logic_script and game_coopmission_manager inside your level. Give them an easy name to find back later.

Enemy Spawn points

info_enemy_terrorist_spawn Are the entities where the enemy bots will be spawning. For each section in your map you will need to have these entities in order for bots to spawn. Also per section give those spawnpoints their own name. So lets say for the first section/part of the may you will enter you name all the info_enemy_terrorist_spawn "wave_01". Do this for each section of your map in chronological order(eg, wave_02, wave_03. etc)

A4eY6B7.png

You can give the spawnpoints different properties. For starters you can give them weapons. glock is the default weapon but you can add weapon by using the "," so you can get something like "glock, ak47" and the bot on that location will spawn with a glock and a ak47. You can also give the bot a different player model by using the "Override player model". One example of this is "tm_phoenix_heavy.mdl" which is also used in coop_cementplant. After you've chosen your properties you need to set "Enabled by default" on "No" Later in the script that will have to be made for a Co-op map you will enable the desired spawn so enemies wont spawn in the wrong places. It is very important that this is done. Except for the first Wave of enemies that you come across those need to be Enabled instead of siabled. Remember to place spawnpoint atleast 8 units above the ground or bots might not spawn properly. (same goes for playerspawns)

Doorways to new Sections

Since you have to devide your map into different sections you will need to have doorways that connect these sections and can only be accesed once a "Wave" is completed. Simply put, put down a prop_door_rotating between your sections, lock them so players cant rush through the map without completing the waves and give them a proper name so you can find them later when you're working on your script.

Collectible Coins

If you want players to explore your map more in order to get more points you can use the item_coop_coin once all 3 coins are collected in a level the players will get bonus points at the end of the level. As of right now 3 coins is the minimum and maximum of coins that can be collected. So if you have 2 coins in your map, the players will never be able to get the bonus points. You can have more than 3 coins but this has no extra effect. Once the players have 3 coins they get the bonus points. Collecting more than 3 coins give nothing extra as of writing this tutorial.

Co-op Weapons/Items/Ammo

You have 2 new Items that can be used in Co-op Strike maps. You have the weapon_healthshot and the weapon_tagrenade. The healthshot can be used to heal the player and the tagrenade is used for a short "wallhack" to know where the enemies are for a brief amount of time. Healthshot are good to give before a difficult next fight. Do not give too many Healthshot otherwise your map will be to easy for the player.

Ammo is also crucial in fights. When the player runs out of ammo they will have to switch to knifing which is the greatest trategy against a Heavy Phoenix. With the use of point_give_ammo You can give the player that calls for this entitie full ammo again. In coop_cementplant they used the ammo model when once pressed the model changes to the same model but without the bullets. Make it so that players can only take ammo from that point once so they cant run back in the level to restock on ammo again.

Co-op Tasks

Since you are trying to make a coop(cooperative) map, it is fun to include simples puzzles and task that can only be achived if 2 players work together. It can go from once player standing on an elevator and the other activating this elevator or a door with 2 levers to one player being blind and the other has to guide him/her thought a darkroom. Be creative!

Glowing props

Use glowing Doors or buttons to tell the player "Go here to advance" or "Press me to advance". You can make it so that a prop (the doorway to the next part of the map) is glowing so its easy for players to find their way through your map.

dSNml7O.png

Creating the Script

Co-op Strike uses VScript to make the system function. Without the script the gamemode cant work properly. So each Co-op map will have its own script. Start by creating your script and give it a name. For example cooptutorial.nut. Make sure and this is important that the extension of the file is .nut otherwise the game wont be able to read the file. Now place this file in the correct folder inside your gamefiles. For Example: Steam\steamapps\common\Counter-Strike Global Offensive\csgo\scripts\vscripts\custom. Make sure its inside the Vscripts folder. Once you've placed it inside the correct folder you can start editing it with notepad or any other text editor.

Code used in Example

Here an example of a Co-op Script. Feel free to copy this inside your own script file since alot is usefull for every Co-op Strike map script. An example vmf will be provided at the end of this Guide that works together with this script.

wave <- 0;

function RoundInit(){
	//Will do this everytime you start the map/round because we call it in the OnLevelReset
	wave = 0;
	//Reset the difficulty to normal at start of the round
	SendToConsoleServer( "mp_coopmission_bot_difficulty_offset 1" );
	ScriptCoopSetBotQuotaAndRefreshSpawns( 0 );
}

function ChangeGameModeToCoopIfNotCorrect()
{
	// This will change the game mode and game type if the player has not initialized this before starting the map.
        local game_mode = ScriptGetGameMode();
        local game_type = ScriptGetGameType();
        local map = GetMapName();

	if (game_mode != 1 || game_type != 4)
	{
		SendToConsole("game_mode 1; game_type 4; changelevel " + map);
	}
}

function SpawnFirstEnemies( amount )
{
	ScriptCoopMissionSpawnFirstEnemies( amount );	
	ScriptCoopResetRoundStartTime();
	wave++;
}

function SpawnNextWave( amount ){
	ScriptCoopMissionSpawnNextWave( amount );
	wave++;
}

function OnMissionCompleted()
{
	//what will happen once you've completed the mission (you could play a sound)
	
}

function OnRoundLostKilled()
{
	//what will happen if you loose the round because you died (you could tell the players that your grandma is better than them)
	
}

function OnRoundLostTime()
{
	//what will happen if you loose the round because the time runs out (you could tell the player that they are like turtles)
	
}

function OnRoundReset() 
{
	//called when the round resets
	// IMPORTANT: you need a game_coopmission_manager that has the output 'OnLevelReset' when this is called you NEED to call this function
	// in order for the level to work properly every round!
	RoundInit();
}

function OnSpawnsReset()
{
	//called right before the round resets (usually used for correcting stuff when on a new round other stuff is immediately called)
	//enabled/disabled the correct spawns for the start. * means every group going from Terrorist_00 to infinite enemygroup_example
	EntFire( "wave_*", "SetDisabled", "", 0 );
	EntFire( "wave_01", "SetEnabled", "", 0 );
	EntFire( "CT_*", "SetDisabled", "", 0 );
	EntFire( "CT_1", "SetEnabled", "", 0 );
}

function OnWaveCompleted()
{	
	//Check which wave the player is and do stuff
	if ( wave == 1 )
	{
		EntFire( "wave_*", "SetDisabled", "", 0 );
		EntFire( "wave_02", "SetEnabled", "", 0 );
		EntFire( "door_wave_01", "Unlock", "", 1 );
		EntFire( "door_wave_01", "SetGlowEnabled", "", 1 );
	}
	else if ( wave == 2 )
	{
		EntFire( "wave_*", "SetDisabled", "", 0 );
		EntFire( "wave_03", "SetEnabled", "", 0 );
		EntFire( "door_wave_02", "Unlock", "", 1 );
		EntFire( "door_wave_02", "SetGlowEnabled", "", 1 );
	}
	else if ( wave == 3 )
	{
		EntFire( "door_wave_03", "Unlock", "", 1 );
		EntFire( "door_wave_03", "SetGlowEnabled", "", 1 );
	}
}

Explanation of Code

Ill go over everything inside the script and explain what it all does.

wave <- 0;

function RoundInit(){
	//Will do this everytime you start the map/round because we call it in the OnLevelReset
	wave = 0;
	//Reset the difficulty to normal at start of the round
	SendToConsoleServer( "mp_coopmission_bot_difficulty_offset 1" );
	ScriptCoopSetBotQuotaAndRefreshSpawns( 0 );
}

First wave <- 0; What we do here is initialize a variable that we will call for in later functions. Functions are names for larger pieces of code that do multiple things after each other. so we have the function RoundInit() that sets the variable wave to 0. After that it tells the console to set the bot difficulty to 1 (the easiest). After this it refreshes all the bot spawns.

function ChangeGameModeToCoopIfNotCorrect()
{
	// This will change the game mode and game type if the player has not initialized this before starting the map.
        local game_mode = ScriptGetGameMode();
        local game_type = ScriptGetGameType();
        local map = GetMapName();

	if (game_mode != 1 || game_type != 4)
	{
		SendToConsole("game_mode 1; game_type 4; changelevel " + map);
	}
}

What this function ChangeGameModeToCoopIfNotCorrect() does is it changes the game_mode and game_type to the correct ones so that the game knows its playing a Co-op map. Sadly valve didnt set it up that the game knows its a coop map with the prefix coop_ . You dont really have to know how this works just call this function when the map is startet (OnMapSpawn). More on this in "Making your Script work with your Map"

function SpawnFirstEnemies( amount )
{
	ScriptCoopMissionSpawnFirstEnemies( amount );	
	ScriptCoopResetRoundStartTime();
	wave++;
}

function SpawnNextWave( amount ){
	ScriptCoopMissionSpawnNextWave( amount );
	wave++;
}

These are the 2 functions that will make the bots spawn. SpawnFirstEnemies(amount) Will spawn the first wave of your level and reset the timer to 15 minutes. Within the ( ) there is amount, (amount). From within Hammer we will cal this function and give it an amount to spawn. So if we want 3 bots to spawn we would use this function like this: <code>SpawnFirstEnemies(3) What it also does wave++ which means that it adds 1 to the variable wave so when the level starts wave is 0 but once a wave is spawns it adds 1 so wave = 1. SpawnNextWave(amount) is used in every next wave. We use the variable wave to let the map know at which wave the players currently are.

function SpawnFirstEnemies( amount )
function OnMissionCompleted()
{
	//what will happen once you've completed the mission (you could play a sound)
	
}

function OnRoundLostKilled()
{
	//what will happen if you loose the round because you died (you could tell the players that your grandma is better than them)
	
}

function OnRoundLostTime()
{
	//what will happen if you loose the round because the time runs out (you could tell the player that they are like turtles)
	
}

The names of the functions already say when they should be used. As in coop_cementplant Valve made it so that your "Boss" gives a little message.

function OnRoundReset() 
{
	//called when the round resets
	// IMPORTANT: you need a game_coopmission_manager that has the output 'OnLevelReset' when this is called you NEED to call this function
	// in order for the level to work properly every round!
	RoundInit();
}

function OnSpawnsReset()
{
	//called right before the round resets (usually used for correcting stuff when on a new round other stuff is immediately called)
	//enabled/disabled the correct spawns for the start. * means every group going from Terrorist_00 to infinite enemygroup_example
	EntFire( "wave_*", "SetDisabled", "", 0 );
	EntFire( "wave_01", "SetEnabled", "", 0 );
	EntFire( "CT_*", "SetDisabled", "", 0 );
	EntFire( "CT_1", "SetEnabled", "", 0 );
}

OnRoundReset() is called when the players have died and the round "resets" we call for the function RoundInit(). RoundInit() is explained above. The we have OnSpawnsReset(). This is called just before the round resets. This gives the map time to reset the player and enemy spawns to its original state. Here we Disable every wave_ entity and enable only the first wave for enemies. You can do the same for CT spawns. Multiple CT spawns are used in bigger levels so that the player doesnt have to walk from spawn to the point they were if 1 player died and respawned. Entfire is seen as an Output like in Hammer Could be seen as the Output OnPressed - wave_* - SetDisabled.

function OnWaveCompleted()
{	
	//Check which wave the player is and do stuff
	if ( wave == 1 )
	{
		EntFire( "wave_*", "SetDisabled", "", 0 );
		EntFire( "wave_02", "SetEnabled", "", 0 );
		EntFire( "door_wave_01", "Unlock", "", 1 );
		EntFire( "door_wave_01", "SetGlowEnabled", "", 1 );
	}
	else if ( wave == 2 )
	{
		EntFire( "wave_*", "SetDisabled", "", 0 );
		EntFire( "wave_03", "SetEnabled", "", 0 );
		EntFire( "door_wave_02", "Unlock", "", 1 );
		EntFire( "door_wave_02", "SetGlowEnabled", "", 1 );
	}
	else if ( wave == 3 )
	{
		EntFire( "door_wave_03", "Unlock", "", 1 );
		EntFire( "door_wave_03", "SetGlowEnabled", "", 1 );
	}
}

Last we have OnWaveCompleted. This is called when you've killed every enemy of a wave. Because we keep track on which wave we are with the variable wave we can do different thing for different waves. Here we say: "If wave = 1" it disables all the enemy spawns but the spawnpoint for wave2. We also unlock the door to the next section of the map and set the door to Glow so its easier for the players to find their way.

This is all the code that is needed for a working co-op map. If you didnt quite understand alot of this try copying the code from here into your own.

Info about Code

There are a few functions that can be used to do different things.

  • ScriptCoopMissionSpawnFirstEnemies(#); Spawns the first enemies
  • ScriptCoopResetRoundStartTime(); Resets the roundtime
  • ScriptCoopMissionSpawnNextWave(#); Spawns a new wave # is the amount you want to spawn eg, ScriptCoopMissionSpawnNextWave(5)
  • ScriptCoopMissionRespawnDeadPlayers(); When this is called for it will respawn all dead CT's.

When creating code you have to end every line where you have written something with a ";" but not when its a function or if there are brackets "{ or }", see the code given for reference. To learn more on how coding work I suggest you look at VScript more links can be found there if intrested.

Making your Script work with your Map

We now have created a map and created our script but your map wont work without connecting the 2.

Setting up the entities to work with the script

Earlier in this guid you probably created a logic_script somewhere in your map. If not do so now and name it something easy like "logic_script". Then go to the property "Entity Scripts", click on Manage... , click on the + and search for your script which we places in "scripts/vscripts/custom". Add it and we are done with the logic_script.

tUJ0YOe.png

Now we should have also placed a game_coopmission_manager, go to this entity and go to its outputs. The properties are not important. Now for every Output, except for the OnUser ones you create one. So for example: "OnMissionCompleted - logic_script - RunScriptCode - OnMissionCompleted()" What this output does is it call for the script function OnMissionCompleted() that we created in the scripting part. Do the same for all the other outputs with its names as the Parameter.

IJ0GYU4.png

Setting up the doorways between sections

Since Co-op Strike is a waved base system we have different section in the map. With each section being unlocked when a wave is completed. Now we need to make sure that enemies will spawn once you enter a new section. So what we want to do is Spawn the bots when you for example open the door to the next section. An output would look like this: "OnOpen - logic_script - RunScriptCode - SpawnFirstEnemies(3)" this for the first Wave And for the rest of the waves "OnOpen - logic_script - RunScriptCode - SpawnNextWave(5)" Of course you do not have to use door you can use whatever entity you'd like.

Finishing touches

Ending the Map

Just a few more things to think about to complete out map. First we want out map to fix itself so create a logic_auto and add the output: "OnMapSpawn - logic_script - RunScriptCode - ChangeGameModeToCoopIfNotCorrect()" Secondsly if you have a hostage map all you need to finish your map is a hostage and a hostage rescue zone. If however you do not have a hostage in your map and just want the players to get to an end point you'll have to use a game_round_end. Setup a trigger at the end of your map with the output: "OnStartTouch - game_round_end - EndRound_CounterTerroristsWin" And voila your map is fully playable.

C2SUVCe.png

Proper bot navigation

Since you are playing against bots you'll have to make a proper navigation file so your bots dont look as much like bots. With the commands listed here: Navigation_Mesh_Commands and Navigation_Meshes, you can do many thing to improve the navigation of bots. You can also put point_hiding_spots in your map to tell your bots that, that is a good spot for them to hide.

Setting the bot difficulty to Hardcore

As with coop_cementplant there was a secret room so you can play the map in hardmode to get extra points. To do the same you'll have to use the console command mp_coopmission_bot_difficulty_offset <number> with a point_servercommand using 1 is normal and easiest. If you use 5 the game will register that its in Hardmode. And if you really want to give your players a challenge use an offset of 7. You can also give your info_enemy_terrorist_spawn a difficulty. This difficulty stacks on top of the one you give into the console with mp_coopmission_bot_difficulty_offset.

Testing your map

Now that your map is complete you'll have to test it ingame. all you have to do is open up your console type in "map mymapname" and it will load your map. If the gamemode or gametype are not correct the map should reload itself and set thos to the correct values.

I hope this guide will help alot of people. Happy Mapping :)

Here is an example of a working simple co-op map with its script: https://www.dropbox.com/s/val79djogsjzw9z/Creating%20a%20Co-op%20Strike%20Map%20Example.rar?dl=0