From iw4x-toolkit
Use when writing, editing, or reviewing GSC (Game Script) files for IW4X/MW2. MANDATORY for all GSC tasks. Provides IW4-specific rules, a pre-flight checklist, and a strict lint-then-fix workflow using gsc_lint, gsc_lookup, gsc_anti_patterns, and gsc_outline.
How this skill is triggered — by the user, by Claude, or both
Slash command
/iw4x-toolkit:gsc-writerThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
You are writing GSC for **IW4 (Call of Duty: Modern Warfare 2, 2009)**. IW4 uses an **older GSC dialect** that is NOT JavaScript, NOT Python, NOT C#, and NOT BO3 GSC. If you assume it works like any of those languages, you will produce broken scripts.
You are writing GSC for IW4 (Call of Duty: Modern Warfare 2, 2009). IW4 uses an older GSC dialect that is NOT JavaScript, NOT Python, NOT C#, and NOT BO3 GSC. If you assume it works like any of those languages, you will produce broken scripts.
The linter will catch your mistakes. Your job is to not make them in the first place.
gsc_outline first. Understand what functions exist before touching anything.gsc_lookup to verify the exact signature.gsc_anti_patterns with a relevant keyword (e.g. query="push", query="null", query="object").gsc_template with list=true to find existing templates before writing from scratch.gsc_lint on every file you touched — zero tolerance for errors. Re-write until clean.gsc_fix if the linter reports fixable issues, then lint again.gsc_lint returns zero errors.Answer YES to all before writing a single line:
gsc_outline on the file I am editing? (existing files only)gsc_lookup for every built-in function I plan to use?gsc_anti_patterns for any pattern I am unsure about?function keyword?var, let, or const in my code?for with .size?wait or waittill inside it?waittill, notify, and endon have an entity prefix?isDefined() instead of null checks?spawnstruct() instead of {} object literals?| Rule | WRONG | RIGHT |
|---|---|---|
No function keyword | function init() {} | init() {} |
No var/let/const | var x = 5; | x = 5; |
No .push() | arr.push(item) | arr[arr.size] = item; |
No .length | arr.length | arr.size |
No ===/!== | x === 5 | x == 5 |
No ternary ?: | x > 0 ? a : b | if (x > 0) ... else ... |
| No arrow functions | (x) => x + 1 | write a named function |
No {key: val} objects | obj = {x: 1} | obj = spawnstruct(); obj.x = 1; |
No null | if (x == null) | if (!isDefined(x)) |
No Math.*/parseInt | Math.floor(x) | int(x) |
| No template literals | `hi ${name}` | "hi " + name |
No new | new Object() | spawnstruct() |
No this. | this.health | self.health |
No for...of/forEach | for (p of players) | for (i=0; i<players.size; i++) |
No .concat()/.join() | "a".concat("b") | "a" + "b" |
self = the entity the current function is called on. Never use this.level = shared global game state. Common fields: level.players, level.teamBased, level.time.game = game mode state. Access with game["key"].entity methodName(args) — NOT entity.methodName(args).if (isDefined(player.customProp)) before using any custom property.// ALWAYS prefix waittill/notify/endon with an entity:
self waittill("damage", amount, attacker); // correct
waittill("damage"); // WRONG — missing entity
// ALWAYS include wait in infinite loops:
for (;;)
{
doWork();
wait 0.05; // required — server freezes without this
}
// Spawn threads for async work:
level thread watchGame(); // non-blocking — correct
watchGame(); // blocks the calling function
// Append to array:
arr[arr.size] = newItem; // correct
arr.push(newItem); // WRONG
// Get length:
count = arr.size; // correct
count = arr.length; // WRONG
// Iterate:
for (i = 0; i < arr.size; i++) // correct
for (item of arr) // WRONG
// Create objects:
data = spawnstruct(); // correct
data.x = 1;
data.y = 2;
data = { x: 1, y: 2 }; // WRONG — invalid syntax
// Null checks:
if (!isDefined(x)) {} // correct
if (x == null) {} // WRONG — null does not exist
// Remove a property:
obj.prop = undefined; // correct
delete obj.prop; // WRONG — no delete operator
A valid IW4 GSC file:
// Optional includes
#include maps\mp\gametypes\_hud_util;
// Entry point — no function keyword
init()
{
level thread onPlayerConnect();
}
onPlayerConnect()
{
for (;;)
{
level waittill("connected", player);
player thread onPlayerSpawn();
}
}
onPlayerSpawn()
{
self endon("disconnect");
for (;;)
{
self waittill("spawned_player");
// self is the player entity here
}
}
Key points:
function keyword anywhere{ on a new line (IW4 convention)wait or waittillself endon("disconnect")Before calling a file done, scan for:
function keywords in definitionsvar/let/const.push()/.pop()/.length===/!==null literalsthis. referenceswaittill/notify/endon has an entity prefixwait or waittill insidegsc_lint returns zero errorsCreates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub back1ply/iw4x-toolkit --plugin iw4x-toolkit