No announcement yet.

SLIC2: The scripting language


  • SLIC2-Scripting-Language

    Original Author: Joe Rumsey
    Date: December 13, 2000

    This is the SLIC2 scripting language refference.


    SLIC Language Specification

    SLIC uses a C-like syntax for most things. There a few large differences, and many features of C don't exist in SLIC, but if you can read C, you can understand most everything in SLIC.
    The basic components of the SLIC language are:

    • Variables - SLIC supports integer variables, as well as special variables to contain units, cities, armies, and locations, and a large set of special built in variables (described in Built-in variables) All variables need to be declared prior to use, and are always initialized to 0 (or an invalid object for types other than integers) Both local and global variables are supported. A variable declared inside a segment is local to that segment. Variables declared outside any segment are global.
    • Statements - function calls and expressions (including assignments). Examples:
    Message(g.player, 'AMessage');
    a = b;
    a = b * c + (d / e);
    a = b + UnitsInCell(city.location);
    • If/ElseIf/Else clauses - much like C, except that ElseIf is used instead of "else if". Note that SLIC is case insensitive, thus If, if, elseif, ElseIf, ELSEIF, else, eLsE, and so on, are all valid. Example:

    elseif (b)

    • While Loops - again, these work like C. This loop sends one message for every city the given player owns:

    aCity = 0;
    while(aCity < player.cities)
    Message(player, 'AMessageAboutACity');
    aCity = aCity + 1;

    • For loops - In addition to while loops, which were present in SLIC 1, SLIC 2 has for loops. They look like C for loops:

    for(x = 0; x < 10; x = x + 1)
    // code
    Note that unlike C, the comma operator is not supported, meaning this does not work:
    for(x = 0, y = 0; x < 10; x = x + 1)
    // code
    • Arrays - User defined arrays are now implemented. The syntax for using an array is much like C. User arrays in SLIC grow dynamically - any insert is legal, the array will be grown to fit the index being inserted. An array is declared like this:

    int_t myIntArray[];
    unit_t myUnitArray[];
    Examples of array usage:
    myIntArray[2] = myIntVar + 3;
    myUnitArray[myIntVar] = myUnitVar;
    myIntArray[x] = myIntArray[x - 1];
    • Messages - Described below
    • Event handlers - Described below
    • Buttons - One of SLIC's primary functions is handling the in game messages. So a method of specifying the buttons to place on messages is provided. See the section below on buttons

    Message Boxes

    A MessageBox is a section of SLIC code that defines a dialog box to be displayed to the user. The general format is:

    MessageBox 'name'

    The name can be any string, and may contain spaces, but may not continue past the end of a line.

    A typical command might be:


    Which would cause the dialog box to display the text pointed at by the string ID "THIS_IS_A_MESSAGE_BOX". Note that string IDs in SLIC are always preceded by ID_. There are other possible commands for message boxes:
    • EyePoint(location) - Any variable that contains a location (unit, city, unit.1.location, etc.) can be used with this function to provide an "EyePoint" button that centers the map on that location.
    • EyeDropdown(startIndex, list variable) - Any builtin variable that can be used as a list (currently unit, city, and discovery) can be used with this function to provide a dropdown list of eyepoint locations to zoom to, or in discovery's case of things to research. Discovery is really only useful for the choose a discovery dialog. The startIndex parameter is useful to make the dropdown list start at an index other than 1. For example, when the discovery messagebox is invoked, discovery.1 is the discovery that was just discovered, and discoveries that can now be researched start at discovery.2.

    Alert Boxes

    An AlertBox is exactly the same as a MessageBox, the differences being that a MessageBox starts as an icon, while an AlertBox opens immediately, has a smaller window, and must contain at least one button. AlertBoxes are modal, meaning the user has to respond to them before the game can proceed..


    Messages and alerts can have buttons attached. A button can have any text on it, and can execute any valid slic code when clicked. Inside the code for a messagebox or alertbox, a button is specified like this:.

    Button (stringid)

    code is the code to be run when the button is clicked. As an example, here is a message box with an "OK" button and a "Tell me more" button:.

    messageBox 'MSampleBox'


    Kill(); // Close this message


    // Provide another messagebox with more info.
    // Does not close this box, since there is no Kill() in this button.
    Message(g.player, 'MSampleTellMeMore');

    There is also a special button-like statement called OnClose which doesn't take a name, and runs when the message is closed. Here is an example of how to send another message when one message is closed (no matter how the first message was closed).

    messageBox 'MFirstMessage'

    Message(g.player, 'MSecondMessage');

    messageBox 'MSecondMessage'

    Built-in Variables

    The SLIC engine contains many predefined variables with many different meanings. See Built-in variables for a discussion of variable concepts and a full list of builtin variables.

    Event handlers and generating events

    Event handlers let you insert scipted code to be executed when many different events happen in the game. A complete list of events that can be handled can be found in the Event List. To write an event handler, you declare a code block like this: HandleEvent(BeginTurn) 'MyBeginTurnHandler' post.


    SLIC provides a number of functions for performing operations or checking values that would otherwise be difficult or impossible. Here is a list of functions. VOID functions do not return values and cannot be used in expressions. INT functions do and can. In addition to the builtin functions, users may implement their own functions. A declaration looks like:

    int_f AddTwo(int_t num)
    return num + 2;

    Note that the type of the function is int_f not int_t. The latter will result in a syntax error. Valid function types are int_f and void_f. Any variable type can be used as an argument.

    Important note! As this documenation is being prepared, the first patch for CTP2 is about to be released. Unfortunately a bug with functions was discovered too late to fix. Specifically, in some cases, using members of unit, army, city, and location variables that are function parameters may not always work as expected. There is, however, a workaround. Copy the function parameter to a local variable and use that variable instead.


    // This version may fail sometimes!
    int_f DoesAHumanOwnThisUnit(unit_t theUnit)

    return 1;
    return 0;

    // This version should always work
    int_f DoesAHumanOwnThisUnit(unit_t theUnit)

    unit_t copiedUnit;
    copiedUnit = theUnit;
    return 1;
    return 0;

    The author apologizes for this and promises that if there is another patch it will be fixed. But the above workaround should always work.

    User variables

    In addition to the built-in variables, any number of user variables may be used. All variables need to be declared prior to use and are always initialized to 0 or an invalid object. You may assign the result of any expression to a user variable:

    my_var = 1 + 1;
    have_flanker = IsFlankingUnit(unit);
    counter = counter + 1;
    turns_to_go = turns_to_go - 1;
    last_checked_year = g.year;

    And so on. Their values are global and persistent - they will not change between various slic objects or when execution stops. In addition to integer variables, there are Unit, City, Army, and Location variables. The complete list of types is:

    army_t armyVar;
    city_t cityVar;
    int_t intVar;
    location_t locationVar;
    unit_t unitVar;

    Only integer variables can be used in mathematical expressions, but ==
    (equality), != (inequality), and =(assignment) work for all types.

    Here is an example that creates a unit in a city at the beginning of that city's turn, then as soon as that unit moves, kills it.

    unit_t myExampleUnit;
    int_t saveUnit;

    // A handler that runs at the beginning of the turn for every city
    HandleEvent(CityBeginTurn) 'MyCityBeginTurnHandler' post
    saveUnit = 1;
    Event:CreateUnit(city[0].owner, city[0].location, city[0],UnitDB(UNIT_WARRIOR), 0);

    // Disable this handler as soon as it's fired once

    // A handler that runs whenever a unit is created, use it to store our
    // created unit
    HandleEvent(CreateUnit) 'MyCreateUnitHandler' post
    // The city begin turn handler sets a flag saying the next
    // unit created is ours
    myExampleUnit = unit[0];
    saveUnit = 0;

    // Only need to run this once

    // A handler that fires whenever an army moves.
    HandleEvent(MoveUnits) 'MyMoveUnitsHandler' post
    int_t i;
    unit_t checkUnit;
    for(i = 0; i < army[0].size; i = i + 1)
    GetUnitFromArmy(army[0], i, checkUnit);
    if(checkUnit == myExampleUnit)
    Event:KillUnit(checkUnit, 0, -1);

    Database Access

    SLIC provides direct read-only access to much of the data contained in the game databases. Here is the list of databases than can be used:
    • UnitDB
    • AdvanceDB
    • TerrainDB
    • BuildingDB
    • WonderDB
    • FeatDB
    • ResourceDB
    • OrderDB
    • TerrainImprovementDB
    • GovernmentDB
    • StrategyDB
    • DiplomacyDB
    • PersonalityDB

    A record in any of these databases can be accessed by name or by index. For example, to create a tank, you can use UnitDB(UNIT_TANK) in a call to the CreateUnit event. If you have the integer index of the tank stored in a variable, you can also use UnitDB(theTankIndex) (although this is a little silly since it amounts to the same thing as writing just "theTankIndex").

    But it does not stop there. Many fields from each database are also accessible. Any bitfield, integer, or floating point value that is in the main body of a record (NOT values in sub-structures!) can be used. Floating point values are multiplied by 100 and converted to ints, since SLIC does not otherwise support floating point variables.

    tankAttack = UnitDB(UNIT_TANK).Attack;
    costOfAdvInfantryTactics = AdvanceDB(ADVANCE_ADV_INFANTRY_TACTICS).Cost;
    minimumHappinessForDefaultStrategy = StrategyDB(STRATEGY_DEFAULT).MinimumHappiness;

    Please explore the database text files to see what data you might be interested in. There are far too many fields available to enumerate here.

    Loading your script

    You can cause your SLIC file to be loaded by using a

    #include "yourfile.slc"
    in script.slc. Your file should be placed in default/gamedata, the same place as script.slc.

    Joe Rumsey

    Attached Files
      Posting comments is disabled.

    Article Tags


    Latest Articles


    • EditPlus: updated SLIC-definitions, new CTP2-DB-definitions
      by BureauBert
      Why not get back to CTP2-modding just to enjoy the luxury of syntax highliting in EditPlus?
      • for SLIC (Locutus' SLIC-definitions file updated for CTP2 AE)
      • for CTP2 AE database files (a brand new definitions file)

      I will keep updating both files as long as the Source Code Project is going on with the Information I can find in the AE Modding Wiki (or somewhere else, but preferably there).

      The EditPlus definitions for CTP2 AE database structures are currently supporting all files in \default\gamedata and \default\aidata. I will see how much I can do for the string files, but I intend to integrate at least some highliting support for editing the Great Library. Personally, I like browsing the textfiles with syntax highliting -- I can see clearly now .

      I will eventually post updates here (not too frequently though).

      Please don't hesitate to post your suggestions and complaints .

      • Requires: EditPlus
      • copy the zipped files into the EditPlus program folder
      • open EditPlus, open the menu Tools > Preferences
      • go to "Settings and Syntax"
      • hit the "Add" button
      • for SLIC enter a description like "SLIC", file extension "slc", the syntax file is "slic.stx", the auto completion file is "slic.acp" and the function pattern file is "slic.ctl"
      • for the database defintions enter a description like "CTP2 DB", the file extension is "txt" (which might be a bit annoying if you use EditPlus for other textfiles and if you frequently use words like "InvaderMovementRegardCost" in your notes ), there is just a syntax file "ctpdb.stx"
      January 29, 2011, 18:53
    • SLIC2 Table of Contents
      by Martin Gühmann
      SLIC2 scripting language
      SLIC2 is a C-like language that "moves" many things behind CTP2. By Activision * Go

      SLIC2 Events
      This is a complete listing of SLIC2 events. By Activision * Go

      SLIC2 Function Reference
      Reference of the SLIC2 Functions. By Activision * Go

      SLIC2 Built-in variable types
      There is one builtin "variable" and a number of builtin variable arrays available in SLIC2. This document contains a complete reference of the data that can be extracted from these types. By Activision * Go

      November 29, 2010, 16:32
    • SLIC2-Scripting-Language
      by Martin Gühmann
      Original Author: Joe Rumsey
      Date: December 13, 2000

      This is the SLIC2 scripting language refference.


      November 26, 2010, 20:07
    • SLIC2-Events
      by Martin Gühmann

      This is a complete listing of events. Some of these are not safe to use from SLIC. A few are just plain obsolete and do not do anything useful. Events with arguments prefaced by GEA_ cannot be generated from SLIC, but can be triggered on.

      November 20, 2010, 21:14
    • SLIC2-Builtins
      by Martin Gühmann

      There is one builtin "variable" and a number of builtin variable arrays available in SLIC. This document contains a complete reference of the data that can be extracted from these types. Note that for types supported as user types, all the members of these variables can be accessed in user variables as well. For example, the builtin unit array has a member named owner, which means that any variable of type unit_t also has a member named owner. Member data is accessed using standard c style dot notation. The one plain builtin variable is named "g" and contains three members:

      • g.year - the current round
      • g.year_str - the current year in string form. Only useful in string replacements.
      • g.player - the current player The rest of the builtins come in arrays, which are filled in when an event handler is called (but can also have values assigned by script code).

      November 19, 2010, 21:57
    • SLIC2-Functions
      by Martin Gühmann
      Following is an alphabetical list of every function available for use in SLIC scripts in Call to Power II.

      VOID Abort()
      Causes the current message to not be displayed. The code following an Abort() is still executed, however. Example:

      messagebox 'Msgbox'
      AddGold(g.player, 100);

      //No message will appear when 'Msgbox' is called, and the player will receive 100 gold.

      November 19, 2010, 21:29