C2G

Revision as of 14:29, 9 July 2024 by G-lander (talk | contribs) (Remove incorrect info; modify assertion of undiscovered features)

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 may be features still undiscovered 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:

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.

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.

Level flags

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"

Unused bits of the "flags" variable itself are also available, but flipping them is unadvised, as, theoretically, future updates to CC2 could add new purposes to unused flags at any moment.

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.