C2G
C2G files are a file extension used by Chip's Challenge 2. Despite the C2G extension, C2G files are plain text and can be edited with any text editor.
While individual levels are stored in C2M files, C2G files arrange these levels in levelsets. C2G files can also be used to specify music tracks, text between levels, and several forms of advanced scripting.
The official set does not use any advanced C2G features, nor did Chuck Sommerville provide any documentation; there are several features that have not yet been discovered by the community.
Basic usage
Set name
The first line of the C2G file must absolutely specify the set's name. Such lines must begin with the "game" directive, followed by the set's name in quotes. For example:
game "Levelset Name"
In the above example, the levelset will be known "Levelset Name" in Chip's Challenge 2's "Load Level Set" window.
Levels
Most of the C2G file consists of loading individual C2M files. This is done using the "map" directive, followed by the file name/path in quotes. For example:
map "ShortLevel.c2m"
In the example above, the game engine will load the level stored in the file ShortLevel.c2m in the same directory as the C2G file.
It is also possible to specify custom directories for C2M files.
map "1-20\VeryLongLevel.c2m"
In the example above, the game will load the level stored in the file VeryLongLevel.c2m in the 1-20 subfolder of the folder where the C2G file is stored.
map "..\crazy-levels\OrdinaryLevel.c2m"
In the example above, the game will go back one directory, enter the crazy-levels folder and load the level stored in the file OrdinaryLevel.c2m
Music
If music is to be played during a specific level, it must be specified in the C2G file; otherwise there will be silence. Only files in MP3 format are supported.
Music is using the "music" directive; followed by the file name/path in quotes, and then, on the same line, the level file. Advanced paths can be specified, like with level files.
After the track is finished, the game will fall silent; this can be avoided by using the + symbol before the path (but inside the quotes). For example:
music "+..\music\DeletingLife.mp3" map "21-40\IntenseDodging.c2m"
In the example above, the game will load the level in the file IntenseDodging.c2m in the 21-40 subfolder. It will also go back one directory, enter the music folder, and play the track DeletingLife.mp3. After playback has finished, it will start playing again.
Comments
A semicolon (;) can be placed at the end of any line in a C2G file. Any text after the semicolon will be ignored by the engine. This can allow the designer to write notes in the C2G file. For example:
music "+..\music\DeletingLife.mp3" map "21-40\IntenseDodging.c2m" ; Intense music for an intense level
In the example above, the text "Intense music for an intense level" will be ignored by the game; the level and music specified will be loaded normally.
Text
C2G files make it possible to put text, between levels, as well as at the beginning and end of the set. This is done using the "script" directive, followed by up to 10 lines of text. All text must be between quotes, and lines may not be longer than 20 characters (excluding the quotes). It is possible to put blank lines by simply putting a space inside the quotes. For example:
script "The following level" "uses some really" "clever tricks and" ; some are also evil "is guaranteed" "to be enjoyable" " " "Have fun!" map "AwesomeLevel.c2m"
In the example above, the text will be displayed in-game like this:
THE FOLLOWING LEVEL
USES SOME REALLY
CLEVER TRICKS AND
IS GUARANTEED
TO BE ENJOYABLE
HAVE FUN!
The text "some are also evil" is a comment and will not be displayed. After the text is displayed, the game will then load the level in the file AwesomeLevel.c2m
Advanced scripting
In addition to the features described above, C2G files can support some additional keywords that provide extra features. Note that any information beyond this point may be incomplete or inaccurate.
Syntax
The syntax of the .c2m file appears to be a mix of Reverse Polish Notation expressions and simple statements. For example, to set the global "flags" variable to (reg1 + 42) * 3, you would write:
reg1 42 + 3 * flags =
Other statements, such as "map" or "music" take a parameter after the keyword:
map "somemap.c2m"
In addition, variables can be formatted into strings in script sections by placing the variable after a string with a printf-style format specifier:
"flags = %ld" flags
If a variable name is invalid, CC2 will search the substrings of the variable name to find a variable name:
10 highspeed = ; Same as 10 speed =
Variables
In most cases, the way C2G scripts interact with gameplay is by writing values to variables.
C2G scrips have access to quite a few variables (see Reference), and some of them are for C2G scripters to use for custom data (reg1 through 4).
All variables are signed 32-bit integers.
Score
The following line, when inserted in a "script"
"%ld" score
will print the player's current total score for the set.
Permanently change directory
By default, C2G files will look for files to be loaded in the same directory as the C2G file itself. This can be changed by the
chdir
directive. This will apply for any future files to be loaded (although custom paths can still be specified, like described above).
Keeping items across levels
C2G files can make it possible to allow the player to keep items and keys across levels.
In order to do this, the C2G script needs this line at the beginning of the file (after the set name):
ktools flags | flags =
This allows the player to keep tools (and keys) into the next level, instead of the key and tool inventories being reset like normal. With this flag set, the player can set up his inventories in one level and keep them into the next.
Alternatively, the set designer can use the C2G script to preset the player's inventories explicitly. This can be done with the following code, placed before calling the level's "map":
<#> keys = ; to preset the key inventory <#> tools = ; to preset the tools inventory
For each inventory, "<#>" is a 4-byte number in which each byte represents a different inventory slot. Its value can be calculated as follows:
(tool 1 code OR red key count) + (tool 2 code OR blue key count) * 256 + (tool 3 code OR yellow key count) * 65,536 + (tool 4 code OR green key count) * 16,777,216
Or if you know hexadecimal, just write it out as a hex integer in little-endian order, then convert to decimal - CC2 does not read hex literals.
Here are the number codes for items:
- 1: suction boots
- 2: skates
- 3: fire boots
- 4: flippers
- 5: time bomb
- 6: helmet
- 7: hiking boots
- 8: lightning bolt
- 9: bowling ball
- 10: yellow teleport
- 11: railroad sign
- 12: steel foil
- 13: secret eye
- 14: bribe
- 15: speed boots
- 16: hook
For example, a key inventory with 1 yellow key and 2 red keys can be set with
65538 keys =
and a tool inventory with flippers in slot 1 and a yellow teleport in slot 2 can be set with
2564 tools =
Note that tool codes > 16 will be reduced to a value <= 16, and key counts > 9 will be reduced to 9. These limits do not apply when either inventory is carried over from the previous level.
Timed levelset
C2G files make it possible to set a time limit for the entire levelset, rather than individual levels. In order to do this, the following code must be added to the beginning of the file, after the "game" directive:
ktime flags | flags =
Before the first level, this code will also be required:
<#> tleft =
Replace "<#>" with the desired time limit for the set. This will ignore any time limits set for individual levels. Time limits will be carried over from one level to the next, and restarting the level does not reset the time limit. Time bonuses and time penalties can still be used. After the time limit reaches 0, or if a level is skipped, all future levels will be untimed.
Conditional execution
By default, all of the lines in a C2G script are executed, with the only condition of not being invalid. "do" statements can allow for directives to be executed under conditions.
To do this, the directive which is supposed to be conditioned should be prefixed with:
<condition> do
Replace <condition> with the expression which should be checked for being true.
100000 score > do 13 tools =
The above example will give the player a secret eye going into the next level if their overall score is greater than 100000.
Goto
By default, C2G files are read linearly from top to bottom, but "goto" directives can allow level skipping or looping.
In order to do this, the end point of the jump must be given a label starting with a pound (#) character. For example:
#loop map "DejaVu.c2m" map "StuckInALoop.c2m"
In the example above, the levels DejaVu.c2m and StuckInALoop.c2m are given the label "loop".
map "NormalProgression.c2m" #loop map "DejaVu.c2m" map "StuckInALoop.c2m" goto #loop
In the example above, completing StuckInALoop.c2m will always take you back by one level to DejaVu.c2m.
"goto" directives can be combined with "do" directives, for example:
map ManyKeys.c2m keys 67306285 != do goto #normalPath script "you have found" "the secret key" "combination!" "you should rest" "a bit" map RelaxingBeach.c2m #normalPath map ManyTools.c2m
In the above example, if after playing ManyKeys.c2m, the last exited player has exactly 1 red, 2 blue, 3 yelow and 4 green keys, they see the text message and play RelaxingBeach.c2m. After that, the secret and normal paths join and in both cases ManyTools.c2m is played next.
Entry choices
If a level has several Player characters, C2G scripting can be used to force only one player to appear, and set which player appears based on conditions.
Players are numbered in reading order, starting at 1; there does not appear to be any limit. In order to use the feature, before calling the "map" of the level containing the players, the "enter" variable must be set, for example:
<#> enter =
Replace <#> with an expression (which must evaluate to a number) or a number. For example:
1 enter = 0 rand > do 2 enter = map UltimatePain.c2m
In the above example, with about 50% chance, the second player will appear in the level UltimatePain.c2m instead of the first one.
CC2 crashes if "enter" is set to a value which does not lead to a player. Make sure to reset enter to 0 where necessary!
Exit choices
If a level has several exits, C2G scripting can be used to send the player to different levels depending on what exit is entered.
Exits are numbered in reading order, starting at 1; there does not appear to be any limit. In order to use the feature, after calling the "map" of the level containing the exits, "do" and "goto" need to be combined in a similar manner:
<#> exit == do goto #label
Replace <#> with the exit number, and #label with the label name (including the #). For example:
map "ChooseYourFuture.c2m" 1 exit == do goto #end 2 exit == do goto #secret #secret map "SuperSecretFinalLevel.c2m" #end script "This is the end."
In the example above, the game will load the level stored in the file ChooseYourFuture.c2m; if the player exits using the first exit in reading order, the game will then display the THIS IS THE END message. If the player exits using the second exit, however, the game will load the level in the file SuperSecretFinalLevel.c2m instead, and the THIS IS THE END message will be displayed after the level has been solved.
If there are several players in the level, the exit used by the last player to finish the level will be the one used by the C2G script. If an invalid label is called, or no label is assigned for the exit that was used, the game will continue to work through the C2G file as it would normally.
Gender choices
C2G scripting can be used to send the player to different levels depending on whether they finished the level as Chip or Melinda. This will require setting up labels, similar to exit checkpoints.
After calling the appropriate level's "map", the following lines will be required:
male gender == do goto <#label> female gender == do goto <#label>
Replace <#label> with the appropriate labels. The "male" line is for Chip, and the "female" line for Melinda; the order of the two lines can be changed.
If there are several players in the level, the gender of the last one to finish the level will be the one used by the C2G script. If an invalid label is called, or no line is specified for a specific gender, the game will continue to work through the C2G file as it would normally.
Fake level numbers
C2G scripting can be used to assign specific numbers to levels. To do this, the following line must be added before calling the level's "map":
<#> level =
Replace <#> with the desired level number. This makes it possible to skip (nonexistent) levels and go backwards (for example, going from level 2 to 5 to 248 to 125). Any number can be specified, including four digit numbers (although this will be displayed in-game as 999) and 0. It is also possible to have several levels with the same number.
It is not required to specify numbers for all levels; if the line is absent, or an invalid value (such as a string of number) is given, the game will simply add 1 to the previous level's number. For example:
game "Jumping Around" 2 level = map "Wheres1.c2m" 0 level = map "Backwards.c2m" 8 level = map "Jumping.c2m" map "Normal.c2m"
In the example above, Normal.c2m will be level 9.
No matter how your level numbering is set up, completing a level will always briefly display the current level as being its previous value + 1. This is unavoidable.
Speed
C2G scripting can be used to modify the speed at which the game is played. To do this, the following line must be added before calling the map:
1 speed =
The number determines the speed, where 1 is normal speed; the upper limit is unknown. This flag will apply for all future levels; in order to restore normal speed, the flag must be called again before a later level.
Blocking flags
C2G scripting can be used to prevent bonus flags from being picked up. This will apply to the entire set, rather than individual levels.
The following line must be added at the beginning of the file (after the set's name):
no_bonus flags | flags =
With this flag set, bonus flags become acting floor to Chip, Melinda, their mirrors and rovers. It has no impact on other monsters and blocks that would not normally pick up the flags.
Editor
The following line
edit
will open the game's built-in editor.
Automatic replays
The following lines
1 level = 50 speed = continue replay | silent | flags =
added to the beginning of the file (after the set name) will cause the game to automatically replay the recorded solutions for all levels in the set, in extremely high speed. This can be used to quickly verify that all levels are solvable and have recorded replays.
Chaining
Scripts can be "chained" using the chain directive; immediately stopping the parsing of the current script and starting again on the first line of the chained script. This can be useful for compartmentalizing long scripts associated with particular levels.
chain "anotherscript.c2g"
chdir "anotherdirectory\" chain "scriptinanotherdirectory.c2g"
Note that if the first c2g file CC2 reads chains to another script but does not provide a map itself, CC2 will say the levelset is invalid. This is because it specifically checks the first c2g it reads for the use of "map" followed by a valid map. To avoid this, put a valid map after calling the chain, such that it will never be accessed since the parser will be chained away from the script before reaching it.
Registers
Variables reg1 to reg4 can be used to store arbitrary flags, will be stored between chained scripts, and will be included in the player's save data. Here, a "switch palace" level includes two exits, the second of which sets the lowest bit in reg4 to 1, which the script then detects to swap out a later level for an alternate version:
map "SwitchPalace.c2m" 1 exit == do goto #afterpalace script "You touched the switch!" "This will swap some" "walls and floors in" "a future level" 1 reg4 | reg4 = #afterpalace map "BoringLevel.c2m" map "NormalLevel.c2m" map "GreatLevel.c2m" 1 reg4 && do goto #switchon #switchoff map "AwesomeLevel.c2m" goto #afterawesome #switchon map "AwesomeLevelAlt.c2m" #afterawesome map "OkayLevel.c2m"
Comments box
Certain C2G scripts, notably ktools and speed can be placed inside a specific level file's comments field, and will apply to the level itself. To do this, the comments field must contain the following line:
[COM]
followed, on subsequent lines, by the C2G parameters.
Reference
The following is a list of all keywords and tokens recognized by the c2g parser. The function of some keywords in here is unknown, and some formerly did something but are now just gibberish to the engine (NO_L_DOORS for example). Note that keywords are case-insensitive.
Token | Type | Syntax | Description |
---|---|---|---|
MUSIC | directive | music "<filename>" |
Specifies a music file to play for the next script element. |
GOTO | directive | goto #<label> |
Move script execution to the specified #label |
DO | directive | <conditional> do ... |
If the preceding condition is true, do the following command. Example:
2 exit == do goto #secret |
== <= >= != < > && || + - * / % & | ^ |
binary operator | <expressions...> <operator> |
Pop two values from the preceding expressions and compare them with the specified operator, then push the result. The operators have the same meanings as in C. |
= | assignment | <expression> <variable> = |
Assign the specified value from the preceding expression to <variable>. |
LEVEL | variable | level |
Contains the current level number. The first level is 1. |
GENDER | variable | gender |
Contains the player's current gender (male or female). |
EXIT | variable | exit |
Contains the most recently used exit (see above). |
ENTER | variable | enter |
Contains the used playable in the next level (see above). |
SCORE | variable | score |
Contains the current score for the levelset. |
BONUS | unknown | Appears to be unused. | |
MENU | variable | menu |
Use is currently unknown. |
CHIPS | unknown | Appears to be unused. | |
START | unknown | Appears to be unused. | |
MALE | constant | male |
Value: 0x16 "male" constant for gender variable. |
FEMALE | constant | female |
Value: 0x56 "female" constant for gender variable. |
MAP | directive | map "<filename>" |
Specifies the map file to use for the next level. |
SCRIPT | directive | script |
Begins "script" mode for displaying text (see above). |
" | string | "..." "... %<format> ..." <value> |
Strings begin and end with a double-quote ("). There does not appear to be any capability for escaping characters. However, formatting can be applied with printf-style format strings (see above). |
# | label | #<name> |
Labels can be jumped to with the "goto" directive. There appears to be some interaction with the end directive, but this is untested. |
0..9 | integer | 1234 |
Integer literal. Can only be specified in decimal (digits 0-9). |
; // |
comment | ; comment text // comment text |
Comments are ignored until the end of the current line. |
END | directive | end |
There appears to be some interaction with labels, but this is untested. |
RESULT | variable | result |
Use is currently unknown. Possibly contains the result of arithmetic expressions? |
REG1 REG2 REG3 REG4 |
variable | reg1 reg2 reg3 reg4 |
Variables intended for use for complex operations in scripts. |
FLAGS | variable | flags |
Specifies flags (bitwise OR'ed) for the current gameplay. See sections above for details. |
EDIT | directive | edit |
Start the built-in level editor. |
CHAIN | directive | chain "<filename>" |
Stops the current script and starts the one specified in <filename>. |
LINE | variable | line |
The currently processed line in the current C2G script. |
CHDIR | directive | chdir "<path>" |
Change the game's current working directory to <path>. |
SCREEN | unknown | Appears to be unused. | |
* / + - && & || | % ^ |
binary operator | <expressions...> <operator> |
Pop two values from the preceding expressions and evaluate them with the specified operator, then push the result. The operators have the same meanings as in C. |
REPLAY | constant | replay |
Value: 0x2 When set in flags, automatically replay recorded solutions. |
CONTINUE | constant | continue |
Value: 0x1 When set in flags, automatically continue to the next level. This only works if 0x2 (replay) is also set and the replays make it to the exit, otherwise exiting a level will do nothing and you will not be able to continue to the next level. This also skips text interludes from the "script" directive. |
SILENT | constant | silent |
Value: 0x4 When set in flags, suppresses popup dialogs like the score improvement one. |
KTIME | constant | ktime |
Value: 0x20 When set in flags, keep the time limit across levels. |
KTOOLS | constant | ktools |
Value: 0x10 When set in flags, keep collected tools (items and keys) across levels. |
TLEFT | variable | tleft |
Contains the global time limit when ktime is set in flags. |
TOOLS | variable | tools |
Contains the current tools inventory (see above). |
KEYS | variable | keys |
Contains the current keys inventory (see above). |
ART | directive | art "..." |
Was supposed to replace a part of the tileset with custom art. Was removed due to being impossible to implement. |
WAV | directive | wav "..." |
May have been inteded to load a custom set of sound effects from a path. |
RAND | pseudo-variable | rand |
When read, generates a pseudo-random integer. (since all variables are signed 32-bit values, the minimal and maximum values are −2,147,483,648 and 2,147,483,647, respectively) |
SPEED | variable | speed |
Contains the current gameplay speed. 1 = 100% (normal speed). |
NO_BONUS | constant | no_bonus |
Value: 0x40 When set in flags, disables bonus flag pickup (see above for details). |
NO_L_DOORS | unknown | Appears to be used. May have been used to debug swivel behavior. | |
MAIN | directive | main |
Use is currently unknown. Appears to jump to "playcc2.c2g" from the current levelset or script. |
GAME | directive | game "<name>" |
Sets the name of the current levelset to <name> |
DLC | directive | dlc "..." |
Use is currently unknown. |