GPC Script Basics: Syntax, Structure & Patterns
Technical introduction to GPC — variables, combos, main loops, conditionals, menu systems, and how to read commercial scripts safely.
# GPC Script Basics: Syntax, Combos, and Program Structure
GPC (GamePack Compiler language) is the domain-specific language Collective Minds developed for Cronus Zen and related devices. It is not general-purpose programming — every construct exists to read controller state, modify HID reports, and schedule timed button sequences within strict memory and timing budgets. This guide introduces GPC syntax, program structure, and the patterns commercial scripts use so you can read, customize, and debug .gpc files confidently. For advanced combo timing behavior, continue to GPC Combo, wait(), and Timing Deep Dive. For how compiled bytecode interacts with console input, see How Cronus Zen Scripts Work.
Language overview
GPC scripts compile to bytecode executed by the Cronus Zen ARM processor. At runtime the Zen sits between your physical controller and the console, intercepting USB or Bluetooth HID reports, applying script logic, and forwarding modified reports downstream.
The compilation pipeline:
.gpc source → Zen Studio compiler → bytecode → device memory slot → runtime interpreterEach main iteration receives fresh controller state. The script decides whether to pass values through unchanged, scale them, zero them, or trigger combos that override values for timed durations.
Core program sections
GPC organizes code into named sections. Commercial scripts may span thousands of lines, but the skeleton repeats consistently.
| Section | Execution model | Typical contents |
|---|---|---|
| `init` | Runs once at script load | Default variable values, slot detection |
| `main` | Runs every input poll | Input reads, conditionals, combo triggers |
| `combo` | Runs when invoked | Timed `set_val`, `wait`, button holds |
| `function` | Called from main or combos | Reusable logic (firmware-gated) |
| `const` / defines | Compile-time constants | Button masks, feature flags |
A minimal structural example:
init {
green_delay = 240;
mod_enabled = TRUE;
}
main {
if (mod_enabled && event_press(PS4_R2)) {
combo_run(AutoGreen);
}
}
combo AutoGreen {
set_val(PS4_RY, -100);
wait(green_delay);
set_val(PS4_RY, 0);
}The init block sets starting values before the first main tick. The main block watches for trigger press edges. The combo applies stick movement, waits, then releases.
Variables and types
GPC supports a small type system optimized for embedded controller logic.
| Type | Use case | Example |
|---|---|---|
| `int` | Milliseconds, percentages, toggles | `int delay = 80;` |
| `fix32` | Fixed-point stick math | Advanced aim curves |
| `bool` / `TRUE` / `FALSE` | Feature gates | `int mod_on = TRUE;` |
Example declarations at script top:
int green_delay = 240;
int aim_strength = 35;
int mod_enabled = TRUE;
int deadzone = 6;Commercial scripts expose hundreds of int variables mapped to OLED menus, LED feedback, or hold-to-adjust patterns. Do not rename menu variables without provider documentation — menu systems reference variables by name and index conventions.
Variable scope and persistence
Variables retain values across main iterations until changed by logic or user menu adjustment. They do not persist across power cycles unless the script implements save patterns via provider-specific APIs. Toggles reset to init defaults on script reload.
Input API essentials
GPC provides controller-centric functions. These appear in virtually every script.
| Function | Behavior |
|---|---|
| `get_val(BUTTON)` | Current axis or button value |
| `set_val(BUTTON, value)` | Override report value sent to console |
| `event_press(BUTTON)` | True for one poll on physical press edge |
| `event_release(BUTTON)` | True for one poll on physical release edge |
| `get_ival(BUTTON)` | Instantaneous raw value (advanced) |
Button identifiers follow PlayStation naming (PS4_R2, PS4_LX) even when targeting Xbox; Zen maps outputs per active protocol.
Press vs hold detection matters for competitive scripts:
if (event_press(PS4_R2)) {
combo_run(FireMod);
}
if (event_release(PS4_R2)) {
combo_stop(FireMod);
}event_press fires once per physical press. Holding R2 does not retrigger unless the script implements repeat logic.
Combos explained
Combos are named timed instruction lists. They are the primary mechanism for sequences longer than one poll — recoil patterns, dribble moves, rapid fire bursts.
combo AntiRecoil {
set_val(PS4_RY, recoil_pull);
wait(fire_duration);
set_val(PS4_RY, 0);
}Invocation from main:
if (get_val(PS4_R2)) {
combo_run(AntiRecoil);
}Combos run asynchronously relative to main in the sense that main continues executing while combo steps progress — but wait() inside a combo blocks that combo's own timeline. Misunderstanding this behavior causes most timing bugs. Full treatment in GPC Combo, wait(), and Timing Deep Dive.
combo_run vs combo_stop
| Call | Effect |
|---|---|
| `combo_run(Name)` | Start combo from first step (or resume if designed) |
| `combo_stop(Name)` | Halt combo immediately; releases stuck overrides |
| `combo_running(Name)` | Returns TRUE if combo active |
Always pair combo_stop on button release for hold-to-activate mods. Missing stops produce stuck stick values players describe as "drift."
Conditional logic and flow control
GPC supports if, else if, else, and while with C-like syntax.
Slot-based profile switching:
if (get_slot() == 1) {
// Profile A — aggressive timing
green_delay = 220;
} else if (get_slot() == 2) {
// Profile B — conservative timing
green_delay = 280;
}Feature toggles with early exit pattern:
if (!shoot_mod) return;
// shoot mod logic belowThe return in main skips remaining logic for that poll only — it does not terminate the script.
Avoid deeply nested conditionals without comments. Maintenance cost rises quickly in 3,000-line commercial files.
Functions and includes
Providers modularize scripts with #include directives:
#include <provider_core.gph>
#include <nba2k_timing.gph>Included files contribute variables, combos, and functions to the compilation unit. Missing includes produce undefined identifier errors at compile time.
User-defined functions (when firmware supports):
function apply_deadzone(int axis) {
if (abs(axis) < deadzone) return 0;
return axis;
}Check your firmware GPC reference for function support limits — older firmware restricts function features.
Main loop architecture patterns
Commercial scripts typically structure main as ordered phases:
- Menu handling — read adjustment inputs, update OLED
- Platform guards — skip PlayStation-specific blocks on Xbox
- Toggle checks — respect user-disabled mods
- Input edge detection — fire combos on press/release
- Passthrough defaults — ensure unstuck values each poll
Pseudo-pattern:
main {
handle_menu();
if (platform_ps5) ps5_auth_guard();
if (!master_toggle) return;
if (event_press(PS4_L2)) combo_run(AdsMod);
if (event_release(PS4_L2)) combo_stop(AdsMod);
}Order matters when multiple mods touch the same stick axis. Later set_val calls win unless combo overrides interleave.
Reading a commercial script safely
Follow this sequence before editing any downloaded .gpc:
- Identify the menu variable block at the top — document which integers map to which features.
- Locate toggle guards (
if (!feature) return;patterns). - Map combo names to marketing labels in provider documentation.
- Note platform conditionals — editing PlayStation delays may not affect Xbox builds.
- Change only values inside documented safe ranges (typically timing ±20 ms, strength ±5%).
Do not redistribute modified commercial scripts unless the license explicitly permits modification and redistribution.
Common compile errors
| Error class | Typical cause | Fix |
|---|---|---|
| Undefined identifier | Typo, missing `#include` | Restore spelling or add include |
| Combo already running | Missing `combo_stop` on release | Add release handler |
| Out of memory | Script too large for slot | Remove unused combos or request slim build |
| Syntax error | Missing semicolon or brace | Jump to reported line |
| Unknown function | Firmware too old | Update firmware or downgrade script API usage |
Zen Studio's output panel shows line numbers. Fix errors from top to bottom — later errors are sometimes cascading artifacts of the first mistake.
Debugging runtime behavior without recompiling constantly
Use incremental testing when self-tuning:
- Change one
intat a time. - Recompile and write to a test slot, not your production slot.
- Verify in private match for five minutes before merging to primary slot.
- Keep notes:
green_delay 240→260: better offline, worse online.
For systematic in-game failures, use Troubleshooting Cronus Zen Scripts.
Relationship to aim and recoil tuning
Variables like aim_strength and recoil_pull feed into set_val calls inside combos. Tuning those values is documented practically in Cronus Zen Aim Assist and Anti-Recoil Settings. Syntax knowledge tells you where values live; tuning guides tell you what ranges work online.
GPC vs other automation approaches
| Approach | What it sees | Typical use |
|---|---|---|
| GPC on Zen | Controller HID reports | Input timing, stick patterns |
| PC macros | OS-level input | PC games without Zen |
| Game trainers | Game memory | Not applicable to Zen GPC |
Zen GPC is controller-side only. Scripts cannot implement computer vision aim or packet inspection.
Installation and Studio prerequisites
You need a working compile-and-write workflow before editing matters. If you have not flashed a script yet, complete How to Install a Cronus Zen Script and Cronus Zen Studio Setup.
Frequently asked questions
Is GPC the same as Python or JavaScript?
No. GPC borrows C-like syntax but provides only Cronus controller APIs. General loops, file I/O, and networking are unavailable.
Can I write scripts without programming experience?
Simple toggle scripts with one combo are approachable. Large multi-game commercial packs require disciplined structure, commenting, and testing habits equivalent to junior embedded programming.
Where is official GPC documentation?
Collective Minds publishes language references in Zen Studio help files and community forums. Match documentation version to your firmware — APIs expand over time.
Can GPC access game memory?
No. GPC only sees controller state, Zen timers, and slot metadata. Any marketing claiming direct game reads is inaccurate for standard Zen scripting.
Why do scripts use PS4_ button names on Xbox?
Cronus normalizes internal identifiers. Output protocol mapping handles Xbox report formats. Authors document platform toggles where behavior diverges.
What is the difference between `wait` and polling in main?
wait inside combos pauses that combo's timeline in milliseconds. main polls every input cycle independently. See GPC Combo, wait(), and Timing Deep Dive.
How large can a GPC script be?
Bytecode size limits depend on firmware and slot layout. Compile output shows size. Exceeding limits fails compile with out-of-memory errors.
Can I comment GPC code?
Yes. Use // for line comments and /* */ for blocks. Comments do not affect bytecode size meaningfully but improve maintainability.
Constants, defines, and compile-time values
GPC supports define directives and const blocks for values that never change at runtime. Commercial scripts use them for button masks, feature flags, and protocol-specific thresholds.
define FIRE_BTN = PS4_R2;
define ADS_BTN = PS4_L2;
define MENU_HOLD_MS = 2000;
const int MAX_STRENGTH = 100;
const int MIN_DELAY = 40;| Construct | When to use | Runtime changeable? |
|---|---|---|
| `define` | Button aliases, magic numbers | No — compile-time substitution |
| `const` | Shared limits across combos | No |
| `int` variables | Menu-tunable parameters | Yes |
Prefer define for button identifiers you reference dozens of times. A single rename propagates through the compilation unit. Reserve int variables for values users adjust through OLED menus or hold-to-edit patterns.
OLED and in-script menu patterns
Many commercial scripts expose tuning without Zen Studio by mapping stick directions or button holds to variable increments. The pattern repeats across providers:
main {
if (get_val(PS4_OPTIONS)) {
if (event_press(PS4_UP)) {
green_delay += 5;
if (green_delay > 400) green_delay = 400;
}
if (event_press(PS4_DOWN)) {
green_delay -= 5;
if (green_delay < 100) green_delay = 100;
}
}
}| Menu pattern | User action | Script response |
|---|---|---|
| Hold Options + D-pad | Navigate menu | Increment/decrement `int` |
| LED color flash | Toggle confirm | Visual feedback on change |
| Combo activation | Enable mod category | Sets boolean gate variable |
When reading unfamiliar scripts, locate the menu block first — it reveals which int variables are safe to edit in Studio versus which are internal counters. Editing internal loop counters (combo_step, menu_page) breaks navigation silently.
Bitwise and advanced input masks
Some scripts combine button states with bitwise operators for compact conditionals:
if (get_val(PS4_L2) && get_val(PS4_R2)) {
combo_run(AdsFireMod);
}Firmware-gated APIs may expose get_controller() or protocol detection helpers. Check your firmware GPC reference before using advanced identifiers — copying snippets from forum posts targeting newer firmware causes unknown function at compile time on older devices.
Multi-file compilation units
Large scripts split across .gph include files. The compiler merges them into one bytecode image:
main.gpc → entry point, main loop
provider_core.gph → shared combos, menu system
game_fps.gph → shooter-specific mods
game_sports.gph → sports timing blocks| File role | Typical contents |
|---|---|
| Entry `.gpc` | `#include` list, `init`, `main` |
| `.gph` headers | Combos, functions, variable declarations |
| Provider license block | Activation keys (some commercial packs) |
Missing a single include produces dozens of cascading undefined identifier errors. Always compile from the provider-specified entry file — not an arbitrary included fragment.
Self-authored script starter template
For learning GPC beyond reading commercial files, start with a minimal passthrough-plus-one-mod template:
init {
mod_enabled = TRUE;
pulse_ms = 80;
}
main {
if (!mod_enabled) return;
if (event_press(PS4_CROSS)) {
combo_run(TapPulse);
}
}
combo TapPulse {
set_val(PS4_CROSS, 100);
wait(pulse_ms);
set_val(PS4_CROSS, 0);
}Test workflow:
- Compile and write to a test slot per Cronus Zen Slots, Profiles, and Backup.
- Verify passthrough when
mod_enabled = FALSE. - Enable mod and confirm single pulse per press.
- Add complexity only after baseline passes Tier 1–3 from Troubleshooting Cronus Zen Scripts.
GPC version and firmware alignment
API surface expands with firmware. Functions like advanced fix32 math, extended combo controls, or platform-specific guards appear in changelog order.
| Check | How |
|---|---|
| Firmware version | Zen Studio device footer |
| Script requirement | Provider readme or header comment |
| API reference | Studio Help → GPC Language Reference |
When a script compiles on a friend's machine but fails on yours with unknown function, compare firmware numbers before editing source. Updating firmware via Cronus Zen Studio Setup often resolves API mismatch faster than deleting script features.
Menu systems and user-facing variables
Commercial scripts expose dozens or hundreds of integers through OLED menus, LED color feedback, or hold-to-adjust patterns. Architecture pattern:
int menu_page = 0;
int aim_strength = 35;
int recoil_vert = 28;
init {
aim_strength = 35;
recoil_vert = 28;
}
main {
if (event_press(PS4_OPTIONS)) {
menu_page = cycle_menu(menu_page);
}
// menu adjust handlers read D-pad, write to aim_strength, etc.
}Rule: Never rename menu-linked variables without provider documentation. Menu index tables map OLED lines to variable names; renames break adjustability silently while compile still succeeds.
Anti-patterns when editing commercial GPC
| Anti-pattern | Risk |
|---|---|
| Copy-paste combo without matching stop handlers | Stuck stick drift |
| Duplicate combo names across merged files | Compile failure |
| Global search-replace on `PS4_` identifiers | Breaks platform guards |
| Removing `#include` to shrink size | Undefined references |
| Editing bytecode on PC directly | Corrupt slot; always edit `.gpc` |
When learning syntax, duplicate provider file to my-tuning-v2.4.gpc before any edit — preserves clean rollback source.
Building a minimal custom script from scratch
For education, a two-feature script demonstrates full structure:
init {
rapid_on = FALSE;
delay_ms = 80;
}
main {
if (event_press(PS4_SHARE)) {
rapid_on = !rapid_on;
}
if (rapid_on && get_val(PS4_R2)) {
combo_run(RapidTap);
}
if (event_release(PS4_R2)) {
combo_stop(RapidTap);
}
}
combo RapidTap {
set_val(PS4_R2, 100);
wait(delay_ms);
set_val(PS4_R2, 0);
wait(delay_ms);
}Compile, write to test slot per How to Install a Cronus Zen Script, validate passthrough toggle, then expand. Combo timing details in GPC Combo, wait(), and Timing Deep Dive.
Cross-reference map for deeper reading
| Topic | Article |
|---|---|
| Combo timing | [GPC Combo, wait(), and Timing Deep Dive](/blog/gpc-combo-wait-timing-deep-dive) |
| Input path theory | [How Cronus Zen Scripts Work](/blog/how-cronus-zen-scripts-work) |
| Tuning variables | [Cronus Zen Aim Assist and Anti-Recoil Settings](/blog/best-cronus-zen-settings-aim-assist) |
| Slot management | [Cronus Zen Slots, Profiles, and Backup](/blog/cronus-zen-slots-profiles-backup) |
| Diagnostics | [Troubleshooting Cronus Zen Scripts](/blog/troubleshooting-cronus-zen-scripts) |
Related reading
GPC Combos & wait() Timing: Deep Dive
How combos execute, what wait() blocks, combo_run vs combo_stop, overlapping combos, and debugging timing bugs in production scripts.
How YewScripts Builds NBA 2K GPC Libraries (Engineering Notes)
Inside the implemented YewScripts delivery model: access checks, server-side generation, personalization, leak tracing, user passwords, archives, and flash-only programming.
YewScripts Patch-Day GPC Workflow (Maintainer Playbook)
How a maintained YewScripts release moves through configuration, personalization, trace assignment, password policy, exact-build archiving, and controlled delivery.