Announcement

Collapse
No announcement yet.

Build Queue messages

Collapse
X
Collapse
  •  

  • SLIC Scripting Language

    by Joe Rumsey
    About the author: CTP Programmer, a.k.a Mr Ogre on the forums
    Date: June 18, 1998
    Last Updated: April 13, 1999

    Contents


    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
    }
    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:

    Code:
        Text(ID_THIS_IS_A_MESSAGE_BOX);
    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.

    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 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:

    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'); 
        }
    }
    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)

    Code:
    messageBox 'MFirstMessage' {
        Text(ID_CLOSING_SENDS_ANOTHER_MESSAGE);
        OnClose {
            Message(g.player, 'MSecondMessage');
        }
    }
    
    messageBox 'MSecondMessage' {
        Text(ID_SENT_WHEN_FIRST_MESSAGE_CLOSED);
    }
    Triggers

    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
    }
    There is also a special format for triggering by UI components:

    Code:
    Trigger 'name' on "UI Component Name" when (expression) {
        commans
    }
    It behaves in the same way as the normal format, except that it is only evaluated when the UI component is used. The name follows the same rules as for message boxes.

    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
    The variables used in the expression for a trigger determine when the trigger might be run. For example, if the built-in variable unit.built is used, the trigger condition will be checked whenever a unit is built. However, any given trigger is never placed in more than one list of triggers to be checked. So while a trigger whose only built-in variable in the conditional is g.player will be checked whenever a player's turn begins, one that uses both g.player and unit.built will only be checked when a unit is built. The author has tried to make the order of which variables takes precedence as logical as possible. Some variables make no sense when used in the same expression (E.G. city.built and unit.sighted can't be fired at the same time). In other cases, the list the trigger is added to should be the one that will fire more often.

    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];
    Or a complex region built from a union of any number of simple regions:

    Code:
     Region name = name1 + name2 [+ ... + namen]
    WARNING: Regions have not been thoroughly tested, they may not work as advertised!

    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;
    And so on. Their values are global and persistent - they will not change between various slic objects or when execution stops. In addition to user variables, there are Unit, City, and Location variables. These must be declared outside of any object prior to use. They cannot be used in expressions EXCEPT with the == operator. That is, you can check to see if a unit is the same as another unit:

    Code:
    if(myUnitVariable == unit.1) {
          // they are the same unit
      }
    The same works for cities and locations.
    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');
    }
    Miscellany

    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');
    The first argument to message is a player index, but since this message isn't going to display anything, it doesn't matter what index you use.

    Loading your script

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

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

      Posting comments is disabled.

    Latest Articles

    Collapse

    • CTP MODIFICATION: MAKING UNIT GRAPHICS
      by Harlan
      Get the Full version of this guide with images and unit.txt example

      Here is what I have so far on a file to help explain how to make non-animated unit graphics. I'm going to add some more (such as an additional section on how to make shadows) but this is the basic part. When I post it, I will include a couple of files that will help the user make files easier. For now if you want to try this out, use the text I included earlier in this thread for the text file, and open up one of the cow pictures that comes with the graphics editor patch to start your graphic off from (deleting the cow, of course).
      ...
      March 5, 2012, 17:43
    • CTP MODIFICATION: AIP COMMENTS
      by Celestial_Dawn
      I think I've managed to figure out how the AIPs work. The AIPs certainly have a lot of information about the inner workings of the AI. Read and enjoy. AIP COMMENTS (based on default.aip) Default.aip is the first aip loaded at game start and contains a number of strings which are not found in the other personality aips. If repeated in the other aips, the new values take precedence over the default. // The next line was used in Dark Reign to specify a likelihood that a spy // would be seen... We can use that stuff in Civ3, too int infiltrator_period = 2; No clue. ...
      March 5, 2012, 17:33
    • CTP MODIFICATION: SET_FOOD_OR_PROD.FLI and SET_RESOURCE_DESIRE.FLI COMMENTS
      by Celestial_Dawn
      SET_FOOD_OR_PROD.FLI and SET_RESOURCE_DESIRE.FLI COMMENTS For all non-barbarians: 1. If cities = 0-1 and total population is 1, Maximise growth ratio (minimise turns to next pop) Pay as much wages as needed, minimise rations, average workday No PW Minimum workers on production tiles Maximum workers on food tiles Opening game strategy (this means explore more, and don't build roads yet - this is the same for all entries in this FLI so I won't repeat it) ...
      March 5, 2012, 17:27
    • CTP MODIFICATION: BEGINTURN.FLI&OUTPUTS.FLI COMMENTS
      by Celestial_Dawn
      BEGINTURN.FLI(S) COMMENTS beginturn.fli is a template that is unused by the game. The settings for the various personalities are: Barbarian settle_dense, science_slow, diplomacybarbarians //Barbarian Cleric settle_dense, science_fast, diplomacypeacebackstab //Religious SciFew settle_loose, science_fast, diplomacypeaceloyal //Agreeable SciMany settle_dense, science_fast, diplomacypeaceloyal //Peaceful Slaver settle_dense, science_fast, diplomacywarbackstab //Slaver WarFew settle_loose, science_slow, diplomacywarloyal //Aggressive WarMany settle_dense, science_slow, diplomacywarbackstab //Militant Note that both science_fast and science_slow are identical, Activision decided to set them all to a fast science rate, but differentiated them according to their research goals - i.e. do you research war branches rather than development brances of the tech tree. I think this approach is just fine....
      March 5, 2012, 17:23
    • CTP MODIFICATION: AIPLOADER.FLI COMMENTS
      by Celestial_Dawn
      AIPLOADER.FLI COMMENTS OUTPUT primary_loaded is only in aiploader.fli primary_loaded is to make sure that the AIPs are loaded in the correct order. This is to ensure that survival_mode.aip and citywall.aip are only loaded after the personality aips have first been loaded. Personality AIPs are always loaded on the first turn (turn 0). Otherwise, not relevant...
      February 13, 2012, 19:07
    • CTP MODIFICATION: ACTIVISION FAQ
      by Mr Ogre
      How to stagnate growth and technology

      "When you create scenarios, will you be able to stagnate growth? For example, if I wanted to create a Viking scenario would you be able to ensure the tech level remains the same for that time period as opposed to being able to develop nuclear weapons? In Civ 2 that was one of the things that bothered me most. Someone creates a WW2 scenario and it quickly turns into a Desert Storm scenario."
      You can "stagnate" technology through three routes:...
      February 11, 2012, 21:16
    Working...
    X