About the author: CTP Programmer, a.k.a Mr Ogre on the forums
Date: June 18, 1998
Last Updated: April 13, 1999
Contents
- Language
- Message Boxes
- Alert Boxes
- Buttons
- Triggers
- Built-in Variables
- Trigger Priorities
- Functions
- Regions
- User Variables
- Miscellany
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, and locations, and a large set of special built in variables (described in Built-in variables) Integer variables do not need to be declared prior to use and are always initialized to 0. Unit, City, and Location variables DO need to be declared outside of any object and before they are used in your code. They can be declared with the TypeUnit, TypeCity, and TypeLocation directives. All variables are global - if you change them in one object, they will have the same value in every other object. Builtin variables cannot be modified, only examined.
- Statements - function calls and expressions (including assignments). Examples:
Code:
Message(g.player, 'AMessage'); Text(ID_SOME_TEXT); 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:
Code:
if(a) { Text(ID_TEXT_WHEN_A_IS_TRUE); } elseif (b) { Text(ID_TEXT_WHEN_B_IS_TRUE); } else { Text(ID_TEXT_WHEN_NEITHER_A_NOR_B_IS_TRUE); }
- While Loops - again, these work like C. This loop sends one message for every city the given player owns:
Code:
aCity = 0; while(aCity < player.cities) { Message(player, 'AMessageAboutACity'); aCity = aCity + 1; }
- Messages - Described below
- Triggers - 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:
Code:
MessageBox 'name' { commands }
A typical command might be:
Code:
Text(ID_THIS_IS_A_MESSAGE_BOX);
- 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.
Buttons
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:
Code:
... Button (stringid) { code } ...
Code:
messageBox 'MSampleBox' { Text(ID_THIS_IS_A_SAMPLE); Button(ID_OK) { Kill(); // Close this message } Button(ID_TELL_ME_MORE) { // Provide another messagebox with more info. // Does not close this box, since there is no Kill() in this button. Message(g.player, 'MSampleTellMeMore'); } }
Code:
messageBox 'MFirstMessage' { Text(ID_CLOSING_SENDS_ANOTHER_MESSAGE); OnClose { Message(g.player, 'MSecondMessage'); } } messageBox 'MSecondMessage' { Text(ID_SENT_WHEN_FIRST_MESSAGE_CLOSED); }
A trigger is a section of SLIC code that is run when specific game events occur. A trigger has this format:
Code:
Trigger 'name' when (expression) { commands }
Code:
Trigger 'name' on "UI Component Name" when (expression) { commans }
The body of the trigger is executed only when the expression is true (not equal to 0).
A SLIC expression is a C-style mathematical expression. These are all valid expressions:
Code:
1 + 1 a + b a * (b + c) (a * b) + c a && b a || b a < b a > 2 a <= b a >= b a != b !a (a && !b) || c
Built-in Variables
The SLIC engine contains many predefined variables with many different meanings. See Built-in variables and trigger events for a discussion of variable concepts and a full list of builtin variables.
Trigger Priorities
As mentioned in Built-in variables and trigger events,, the built in variables used in a trigger's conditional determine when that trigger is evaluated. A trigger is never added to more than one event list, however. There is a preset prioritization of trigger lists, defined below. The list the trigger is added to is the lowest list here. For example, if a trigger has both g.year and unit.built, it is added to UNIT_BUILT. The name of the lists below are the event type the list is associated with. All the triggers in a list will be checked when that event occurs.
# YEARLY - g.year, g.pollution, g.globalwarming, g.ozone
# PLAYER - g.player, player.gold, player.cities, player.goods, player.discoveries, player.capitol, player.pollution, player.betrayedalliances
# DISCOVERY - discovery.type
# DISCOVERY_TRADED - discovery.traded
# CITY_BUILT - city.built
# CITY_PRODUCTION - city.building, city.buildingunit, city.buildingwonder, city.buildingpop
# CITY - city.population, city.food, city.owner, city.happiness, city.combatunits
# UNIT_BEGIN_TURN - unit.beginturn
# WONDER_STARTED - wonder.started
# WONDER_FINISHED - wonder.finished
# CLICKED_UNIT - clicked.unit
# IDLE - idle (NYI)
# ATTACK - special.attacked
# UNIT_MOVED - unit.moved
# UNIT_DEAD - unit.dead
# CITY_CAPTURED - city.captured
# CONTACT - special.contact, unit.sighted
# UNIT_BUILT - unit.built
# SAME_GOOD - special.samegood
# SAME_GOOD_AS_TRADED - special.samegoodastraded
# TRADE_SCREEN - special.tradescreen
# DIPLOMATIC_SCREEN - special.diplomaticscreen
# UNIT_QUEUE - special.unitqueue
# PRODUCTION_QUEUE - special.productionqueue
# CREATE_STACK - special.createstack
# CREATE_MIXED_STACK - special.createmixedstack
# AUTO_ARRANGE_OFF - special.autoarrangeoff
# BOMBARDMENT - special.bombarded
# COUNTER_BOMBARDMENT - special.counterbombarded
# ACTIVE_DEFENSE - special.activedefense
# INDULGENCES - special.indulgences
# TERRORISM - special.terrorism
# CONVERSION - special.conversion
# UNIT_LAUNCHED - special.unitlaunched
# ENSLAVEMENT - special.citizenenslaved
# POP_MOVED - special.popmoved
# BUILD_FARM - special.buildfarm
# BUILD_ROAD - special.buildroad
# BUILD_MINE - special.buildmine
# BUILD_INSTALLATION - special.buildinstallation
# BUILD_TRANSFORM - special.buildtransform
# SCIENCE_RATE - player.sciencerate
# TRADE_OFFER - special.tradeoffer
# TREATY_BROKEN - agreement.broken
Functions
SLIC provides a number of functions for performing operations or checking values that would otherwise be difficult or impossible. Here is a list. VOID functions do not return values and cannot be used in expressions. INT functions do and can.
Function reference
Regions
There are a number of functions above which act on regions. A region is a parallelogram or union of parallelograms on the map. They can be defined in two ways.
A simple region:
Code:
Region name [ x1,y2, x2, y2];
Code:
Region name = name1 + name2 [+ ... + namen]
User Variables
In addition to the built-in variables, any number of user variables may be used. Integer variables do not need to be declared prior to use, and are always initialized to 0. You may assign the result of any expression to a user variable:
Code:
my_var = 1 + 1; have_flanker = IsFlankingUnit(unit); counter = counter + 1; turns_to_go = turns_to_go - 1; last_checked_year = g.year;
Code:
if(myUnitVariable == unit.1) { // they are the same unit }
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.
Code:
TypeUnit myExampleUnit; trigger 'CreateAUnit' when(city.beginturn && g.player == 1) { CreateUnit(g.player, UnitType("UNIT_WARRIOR"), city.location, 0, myExampleUnit); DisableTrigger('CreateAUnit'); } trigger 'KillAUnit' when(unit.moved && unit == myExampleUnit) { KillUnit(myExampleUnit); DisableTrigger('KillAUnit'); }
What? No Functions?
While SLIC does not directly support user defined functions, there is a workaround. Using the Abort() function, you can create a MessageBox object that never displays a message. So call Abort() as the first line of a MessageBox object, then write any code you want inside the object, and call that MessageBox from anywhere you'd like with
Code:
Message(0, 'NameOfYourMessageBox');
Loading your script
You can cause your SLIC file to be loaded by using a
Code:
#include "yourfile.slc"