Counter-Strike 2

Counter-Strike 2

Not enough ratings
Zombies V1.0 Custom Gamemode Documentation
By BP
The definitive, and easy to install, custom gamemode to mimic Call Of Duty's Zombies gamemode in Counter Strike: Global Offensive.

We'll go over basic gameplay and how you can add this to your own map!
   
Award
Favorite
Favorited
Unfavorite
Backstory
If you don't care about the development process of this, just skip this section.

Back in 2016, a few friends and I decided to play a map by Josh Mate called Nazi Zombies: Station https://steamproxy.com/sharedfiles/filedetails/?id=475939182&searchtext=nazi+zombies Now, I never played the original COD version before this point, but this map got me hooked. While it was fun, his maps had a few problems which did not go along with the normal Zombies formula. This includes: no wall weapons, the random weapon spawn was the only way of getting a gun, doors had to be broken instead of bought, and the powerups were just buttons on the map that had a cooldown.

Fast forward to June 26, 2018, I've always wanted to improve his system. So, I decided to create the first build of the Zombies gamemode in just a week. It fixed the wall weapon problems and doors by giving the players accounts, but it was difficult to set up. There was a heavy reliance on the logic_eventlistener entity. This was my de-facto way of reading kills. But, this method lead to the HURT CHAMBER which limited the amount of players who could play the game at one time and gave more room for errors to happen.

You could still see what this build was like on my first, not-too-great-i-don't-want-to-remember map using the old script. https://steamproxy.com/sharedfiles/filedetails/?id=1459525350 This map took a MONTH to make, and whooo god, is it bad.

After one year of inactivity, I decided to open up the old .nut file and see what I can do to fix it. This lead to the Proving grounds map. And ever since, I've been working hard to create this doc. https://steamproxy.com/sharedfiles/filedetails/?id=1864596641 To get the latest build of the script, you'll find it here!
Gameplay
For your standard game, this is designed to be a play till you lose gamemode.

You start out with a pistol on T side, with melee restricted enemies constantly respawning and increasing in numbers. Every time you kill an enemy, you are awarded with 100 points. Weapons can be obtained through wall weapons or the random case. Doors can be bought to access more areas of the map. That's it, this simple game loop is fun to play, and even greater with friends!

Players can decide to play on the zombies side (CT), but this isn't recommended.
You can also increase the amount of bots with the launch option -maxplayers_override 64 (64 is CS:GO's max!)

To make playtesting easier, if any player has their developer mode set to a non-zero number, everyone in the game gets unlimited points.
Unpacking and Installing Resources
Now, you want to make your own zombies map for CS? Great!
This guide assumes you have an advanced knowledge of Hammer and at least a basic grasp of programming syntax.
Before we begin, you'll need a tool to open up and view a .bsp's contents. I personally use PakRat, but most people use VIDE. (I won't go over how to use VIDE.)

To start, you'll need to install the prefabs, which can be found on the workshop. https://steamproxy.com/sharedfiles/filedetails/?id=1915244040 After that is completed, boot up PakRat and go to the map's directory in the game. It can be found at /csgo/maps/workshop/1915244040.


Open the file up, and save resources.zip to your desktop.


Drag and drop the folders into the Counter-Strike: Global Offensive folder (NOT csgo)


Be sure to change the map's .cfg to the name of your map. You'll find it in /maps/cfg/[YOURMAPNAME].cfg

You can import prefabs to your map by selecting the entity tool in Hammer and changing the categories to bp.
Importing zombiesGeneral_template.vmf
Now, I'm sorry, but I can not fix this; when you go to import this prefab into your map,
THERE IS A HIGH CHANCE OF HAMMER CRASHING!
The best way to lower the chance of this happening is to:
  • Hide everything else in the world.
  • Import it by pressing Insert Original Prefab
  • Pray to God Gaben.
The general prefab comes with everything you need to get the gamemode to work properly on its own.

You can create a different spawn room. But, make sure you keep the button and trigger_teleport inside of it.
The teleport destinations on top of the prefab can be moved to the play area's starting room.

Zombies will teleport to any teleport destination with the targetname destination.
Wall Weapons
Weapons can be easily added to your map by placing down a weapon_template prefab into your world.

To start, just select the weapon_template prefab and place it in the level.

To change which weapon the player can buy from this, go into the outputs for both the trigger and button then change the weapon index. To know which index to set it to, go to scripts/vscrips/bp/weapon_dir_index.txt


Don't forget to also change the prop_dynamic model to the corresponding weapon selected! You will want to use the w_... model, not the v_... or ..._dropped.

Optional argument
Other than the default buyItem(intWeaponIdx, bIsBuying), you can set your own price for the weapon with the method buyItem(intWeaponIdx, bIsBuying, intCost).

An example for this on the AK-47 would be, the default price is 2000 points, but I would like to change it to only 200. So, I would go into the button's output and set the method to buyItem(0, true, 200).
Doors
Doors will be the most tedious to set up out of everything due to it's variability on what you can set as a door. You will have to make the buttons and triggers from scratch, but I've made sure it was at least easy to setup.

Script Editing Preface
There is a problem with how hammer saves keyvalues which makes it impossible to add quotations marks to it. If you decide to do so and save, good luck trying to find the one " in notepad which crashes Hammer when you load the file.

To get around this, you can assign the room the door leads into by appending the name to the script's global variable door_names. To add another name, use a comma to separate the strings, then add what you want inside quotation marks.


Method Arguments
To allow the player to purchase doors, we use the method
buyWall(intNameIdx, intCost, bBuying)
intNameIdx: The index at which the name of the door is located in door_names. Starts at 0!
intCost: How much it costs to purchase the door. Recommended to keep it to the nearest 100's.
bBuying: Set true for buttons, set false for triggers.

Brush Entities
To make a door, you'll need:
  • trigger_multiple (Tells players the price)
  • func_button (Allows players to purchase)
  • func_nav_blocker (Stops bots from walking that way)


trigger_multiple

Make sure the trigger has a unique targetname, have the entity Scripts set to scripts/vscripts/bp/zombies.nut, and Reset Delay set to .1.

The output should have the method buyWal() fire OnStartTouch.

func_button


Make sure the button has a unique targetname, have the entity Scripts set to scripts/vscripts/bp/zombies.nut, and Reset Delay set to .1..

The output should have buyWall() fire OnPressed.

The tag, Don't Move should be activated.

func_button User1
If a purchase is completed, it will fire the button's OnUser1. This is to allow you to kill the button and trigger, open the door, unblock the nav, and do other effects. Be sure to change any zombie spawn points' targetname in the room to destination!

func_nav_blocker


If you are making your door out of models, you will need to add these!

Give the targetname the prefix blocker_close... for if it should start activated, or blocker_open... if it should start deactivated! Affects flow should be Yes This is to allow the logic_auto to reset the entities on map restart.

It's reccomended to give the opposite side of the door its own trigger and button with the same target name. This allows you to give both sides a different intNameIdx argument!
Random Weapon Case
The weapon case was made to be as easy to setup as possible, but it still requires some script and entity editing.

Script Editing Preface
Before we place the prefab, be sure you edit the first, or append onto the global variable-- case_names-- the name you want to reference the case instance by. Be sure to remember the name (case sensitive) and index of it.


Begin by placing a case_template prefab into the world.


Next, edit the targetname to each of the entities to the name you chose in the script. Except for the suffixes! (EX: _weapon, _case, .ect)
The entities you need to edit will be a:
  • trigger_multiple
  • func_button
  • prop_dynamic (x2)
  • env_explosion

The first method argument on the outputs for the trigger_multiple and func_button need to represent the index of the name you want in the case_names array.


Optional argument
Other than the default buyRandomizer(intNameIdx, bIsBuying), you can set your own price for the case with the method buyRandomizer(intNameIdx, bIsBuying, intCost). The default price is 900.

env_explosion User1
If you wan't to add additional special FXs to the case when it is opened, use OnUser1 on the env_explosion entity to call for other entities when the case has unboxed.

Multiple Cases
If there are multiple cases within the level, the script will allow one of the cases to be enabled at random, and will decide if the case should be moved by comparing if the amount of consecutive unboxes is more than a random number generated between 1 and 50.
General Purchasing
If you want a way to allow the players to purchase something that you have full control over, buyGeneral() is the method for you.

Script Editing Preface
In order to allow for a custom string you will need to edit, or append, an array in the custom_text global variable. The first index in the array should be what will be shown when the player is viewing the item, the second array displays after someone successfully purchases the item.
["Donate some money" (Will be shown by the trigger_multiple), "Much appreciated!" (Transaction is complete)]

Method Arguments
For general purchases we use the method
buyGeneral(intNameIdx, intCost, bBuying)
intNameIdx: The index to decide which strings to use. Located in custom_text. Starts at 0!
intCost: How much it costs to purchase the item. Recommended to round to the nearest 100's. Can also be set to a negative number to give the player money.
bBuying: Set true for buttons, set false for triggers.

Entities Needed
The only required entities for this to function properly are:
  • trigger_multiple
  • func_button

trigger_multiple

Make sure the trigger has a unique targetname, have the entity Scripts set to scripts/vscripts/bp/zombies.nut, and Reset Delay set to .1.

The output should have the method buyGeneral() fire OnStartTouch.

func_button


Make sure the button has a unique targetname, have the entity Scripts set to scripts/vscripts/bp/zombies.nut, and Reset Delay set to .1.

The output should have the method buyGeneral() fire OnPressed.

The tag, Don't Move should be activated.

func_button User1
If a purchase is successful, the button's OnUser1 is fired, this is to allow you to kill the button and trigger and do whatever you want with it. Be it a buyable ending, or trap.
Nav meshes
While I will not be going over it, you will have to make the nav meshes FROM SCRATCH to allow for the bots to roam the map. Be sure to create individual spaces for where you put your func_nav_blockers. And it's also recommended to nav_run all of the spaces.
Packing and Publishing
Now you've completed you map, playtested it, and it's ready to be shipped!
Not so fast there! Don't upload it to the workshop yet! The end user will not be able to run the map.

You first need to pack the powerup model and textures, map cfg, and script.

Start by opening up the map in PakRat and pressing Auto. Hit yes.
Next, delete everything except for your map's .nav and .ain, and powerup.mdl, powerup.dx90.vtx, and powerup.wd.


After that, open up materials/models/bp/powerup and drag in all of the .vmts and .vtfs


Next, open maps/cfg and put your map's config in.


NOTICE
Select the .cfg and click on edit. Change the path to maps/cfg.


Finally, go to scripts/vscripts/bp and put zombies.nut in.


NOTICE
Just like the .cfg, be sure to change the path to scripts/vscripts/bp.

Check if it Packed Correctly
On both the .cfg and .nut file; all the way at the bottom, you should see
//If you see this entire sentence, the ... has been packed correctly!


If you are missing this, recompile the map and try again. Trust me, it would be easier than trying to salvage from what you have already.

Now, just save the map, do NOT update the .nav, and publish it to the workshop.

Congratulations! You have made your own zombies map for Counter Strike: Global Offensive!
Debrief
I hope this guide has answered all of the questions needed to work with my script, and I really hope it becomes popular enough to be a de-facto custom gamemode in the community.

If there are any questions, please feel free to comment!
2 Comments
BP  [author] 25 Jan, 2020 @ 11:32am 
Valve has STILL not fixed the issue. IT'S BEEN TWO FUCKING MONTHS, C'MON!
BP  [author] 18 Nov, 2019 @ 9:12pm 
[NOTICE] As of the Operation update, game_type 3 has been broken. The game will not parse the .cfg for the time being. Please standby for the next update to hopefully patch this.