What is GSC? (Game Scripting C) Guide
Comprehensive architectural guide to Game Scripting C (GSC), the bytecode VM engine behind Call of Duty titles by Eduardo Gelain.
Game Script Code/Game Scripting C, commonly known as GSC, is the proprietary, server-side scripting language used across almost all major Call of Duty titles powered by the IW engine and Treyarch's derivatives. Its syntax is heavily inspired by C and C++, but it behaves like a dynamically-typed scripting language with built-in multithreading, event-driven execution, and game-specific data structures.
Developed initially by Infinity Ward, GSC is the invisible backbone that dictates the flow of single-player campaigns, orchestrates multiplayer game logic, and drives the intricate state machines of the iconic Zombies mode.
This guide provides a universal overview of GSC concepts, applicable (with engine-specific variations) across T4 (World at War), T5 (Black Ops 1), T6 (Black Ops 2), T7 (Black Ops 3), T8 (Black Ops 4), and T9 (Black Ops Cold War).
The GSC Virtual Machine
GSC is not compiled into native machine code (x86/x64). Instead, the game's compiler (often part of the mod tools or done at build time by the developers) translates the raw .gsc scripts into bytecode. This bytecode is then executed at runtime by a Virtual Machine (VM) embedded directly within the game engine.
The VM handles:
- Memory Management: Dynamic allocation and garbage collection for script variables.
- Thread Scheduling: GSC natively supports executing multiple functions concurrently via threads. The VM schedules these threads frame-by-frame.
- Engine Interfacing: Built-in functions allow GSC scripts to directly read and write engine memory, manipulate Dvars (developer variables), spawn 3D entities, and control HUD elements.
Basic Syntax & Grammar
GSC syntax will look instantly familiar to anyone who has programmed in C, C++, or JavaScript.
Includes and Namespaces
At the top of a file, you typically define #include directives to import functions from other scripts. In newer engines (T7+), namespaces and auto-executing directives (#using, #namespace, #autoexec) become prevalent to strictly organize the massive codebase.
#include maps\mp\_utility;
#include common_scripts\utility;
// In T7+ (Black Ops 3 onwards), namespaces are common:
#namespace custom_zombies_logic;
Variables and Types
Variables in GSC are dynamically typed. You do not declare their type (int, string, etc.). A variable can hold a string, integer, float, array, or a reference to a game entity.
Variables can have different scopes:
- Local Variables: Scoped only to the current function or thread.
- Level Variables (
level.var_name): Global variables accessible from anywhere.levelis a globally persistent entity structure. - Self Variables (
self.var_name): Variables attached to a specific entity (like a player or a zombie).
level.custom_round = 1; // Global integer
self.is_invincible = true; // Boolean attached to 'self' (the player)
local_weapon = "ray_gun"; // Local string
Arrays and Structs
GSC relies heavily on arrays. They can be indexed numerically or associatively (using strings as keys).
// Creating an array
players = get_players();
// Associative array
level.weapon_costs = [];
level.weapon_costs["m1911"] = 500;
// Structs (Useful for holding grouped data without creating full entities)
spawn_point = spawnstruct();
spawn_point.origin = (0, 0, 0);
spawn_point.angles = (0, 90, 0);
Execution Control: Threads and Events
The most powerful aspect of GSC is its event-driven, multithreaded nature.
Threads (thread)
You can launch a function in parallel alongside the current execution flow using the thread keyword. If you don't use thread, the current script will wait for the function to finish before continuing.
// Spawns a parallel process. The main script continues immediately.
level thread background_music_manager();
// Called on a specific entity
player thread monitor_player_health();
Waiting and Yielding (wait)
Because the VM runs frame-by-frame, infinite loops will crash the game (Server Command Overflow). You must yield execution using wait.
while ( true )
{
// Do something every second
print("One second passed.");
wait 1.0;
}
Event System (waittill and endon)
GSC uses a string-based publish/subscribe model for events. Entities can wait for specific events to fire, or terminate their threads if an event occurs.
waittill("event_string"): Pauses the thread until the entity broadcasts this exact string.endon("event_string"): Immediately kills the thread if the entity broadcasts this string.
monitor_damage()
{
// Stop this thread if the player disconnects or dies
self endon("disconnect");
self endon("death");
while ( true )
{
// Wait until the player takes damage.
// Capture the event arguments into variables.
self waittill("damage", amount, attacker, direction_vec);
iPrintLn("You took " + amount + " damage!");
}
}
Entities trigger these events using notify.
// Somewhere else in the code...
self notify("damage", 50, level.zombie_boss, (1,0,0));
Common Tasks Across Engines
While functions vary between World at War (T4) and Cold War (T9), the core mechanics remain the same.
Printing to Console / Screen
Useful for debugging.
Print("Console log message"); // Prints to server console
iPrintLn("On-screen message"); // Prints to the killfeed area
iPrintLnBold("Center screen text"); // Big text in the center
Modifying Players
Scripts frequently target the array of active players.
players = get_players();
for ( i = 0; i < players.size; i++ )
{
player = players[i];
// Give weapon and max ammo
player GiveWeapon("ray_gun");
player GiveMaxAmmo("ray_gun");
player SwitchToWeapon("ray_gun");
// Change health
player.maxhealth = 250;
player.health = player.maxhealth;
}
Spawning Entities
You can spawn models, triggers, and effects dynamically.
// Spawn a script model at a specific coordinate
mystery_box = spawn("script_model", (100, -500, 10));
mystery_box setModel("zombie_mystery_box");
// Move it over 5 seconds
mystery_box MoveTo((100, -500, 100), 5.0);
Conclusion
Understanding GSC is the master key to modifying Call of Duty. Whether you are building complex custom Zombies maps on Black Ops 3 (T7), injecting mod menus into Black Ops 2 (T6) via memory, or analyzing compiled bytecode in Cold War (T9), the foundational logic—threads, events, and dynamic entities—remains the universal language of the engine.