FOCS Scripting Tutorial

From FreeOrionWiki
Revision as of 17:32, 16 December 2004 by Drek (Talk | contribs) (Step 2: Copy n' paste the correct XML template.)

Jump to: navigation, search

Texas Drek’s Downhome Effects Tutorial

So you want to write up a technology/building/special for FO? Yeehaw: you are about to embark on an exciting adventure, with chills and thrills to rival any Hollywood blockbuster.

Creating a building or a special is basically the same process as writing up a technology, so from here on out I’ll refer to all of the above as “techs”.

Step 1: Define your tech

Give your tech a name and description, and figure out what you want it to do. Hint: In the next step you’re going to have to describe in exacting detail precisely what your tech does in a way that FreeOrion can understand. That means your tech needs to do something the actual FreeOrion program is capable of doing.

Hence you need to know how FreeOrion v.3 works. To discover how FO plays, read the requirements document and the Effects document. (instead of the requirements, you might just peek at the cliff notes, but the Effects document is a must.) Read tzlaine's FAQ on the forum. If you don’t want to read the documentation because it’s long and boring then stop at this step: We don’t need your “help” designing techs. Feel free to post stuff in brainstorming, or contribute art, or whatever….but you really do need to read the docs if you want to build techs that can be used in the actual game.

If you have any questions about requirements or effects doc, ask away on the forum. Someone will answer.

Here’s the tech I’ve come up with, for the purposes of this tutorial:

Drek’s Effects Tutorial
A marvelous, high tech tutorial that enlightens all who read it.
Effect: +2 Max Science to all friendly worlds set to the Science Focus

Step 2: Copy n' paste the correct XML template.

The templates are: tech, building, and special.

You’ll need to fill out the “fields” in the XML form. Since “Drek’s Effects Turorial” is a technology, I’ll be filling out the technology XML form:


  <Tech>
      <name>NAME</name>
      <description>DESCRIPTION</description>
      <type>TYPE</type>
      <category>CATEGORY</category>
      <research_cost>RESEARCH_COST</research_cost>
      <research_turns>RESEARCH_TURNS</research_turns>
      <prerequisites>
          NAME0
          NAME1
          ...
          NAMEN
      </prerequisites>
      <unlocked_items>
          ITEM0
          ITEM1
          ...
          ITEMN
      </unlocked_items>
      EFFECTS_GROUP [optional]
  </Tech>


NAME: this a placeholder for the name of your technology. The actual name of your technology will go into a “string table”, so you should just type out, in all caps without using spaces, a pithy name.

   <Tech>
       <name>LEARN_DREK_TUTORIAL</name>

DESCRIPTION: this is another placeholder, this time for the description of your technology. Type out the same pithy name you did in the previous field, but this time append the word “DESC”. You’ll be writing out the actual description later.

  <description>LEARN_DREK_TUTORIAL_DESC</description>

TYPE: This is the type of technology. In FreeOrion, there are three different types of techs:

  • TT_THEORY A theory. A theory contains applications, and generally should have little or no effects.
  • TT_APPLICATION An application. An application is contained by a theory, and has some sort of minor effect and/or unlocks a building.
  • TT_REFINEMENT A refinement. A refinement is contained by a theory, and often refines a building or shippart. As of this writing, refinements are not possible, so don’t worry about them.

For the Type field, you’ll need to input one of the above tech types. Most techs (esp. techs that actually do things) should be Applications.

   <type>TT_APPLICATION</type>

CATEGORY: There are five categories that “hold” techs in FreeOrion. You need to assign your technology to one of them. An application or refinement should be in the same category as it’s parent theory.

The categories you can use:

  • LEARNING_CATEGORY deals with the science meter, and fundamental technologies
  • GROWTH_CATEGORY deals with the health of a population, the size of a population, and growing food.
  • PRODUCTION_CATEGORY deal with building stuff like ships and structures. The mining and industry meters are governed here.
  • CONSTRUCTION_CATEGORY deals with developing your colonies. The construction meter is handled here.
  • ECONOMICS_CATEGORY deals with the trade meter, money, etc.

The technology I’m developing clearly falls into the Learning Category.

  <category>LEARNING_CATEGORY</category>

RESEARCH_COST: The number of research points a player needs to spend each turn to research a tech.

RESEARCH_TURNS: The number of turns required to research a tech.

In FO, all techs cost X RP for Y Turns to research. The numbers are still being decided as of this writing, for now assume a low level tech takes around 10 RP for 5 Turns to research.

   <research_cost>10</research_cost>
   <research_turns>5</research_turns>

PREREQUISITES: The techs required before research can start. An application should always have its parent theory as a prerequisite. You’ll need to read up on the forums to determine the current state of the tech tree in order to pick out some proper prerequisites for your tech.

The pithy name we gave the tech in the NAME field is its identification. All techs have such a name...it’s what you type into the prerequisites field.

Let’s say the Theory of Drek is the parent theory for my technology:

   <prerequisites>
       LEARN_THEORY_OF_DREK
   </prerequisites>

UNLOCKED_ITEMS: In the field, you’d type of the pithy names for all of the buildings your technology unlocks. An unlocked building can be constructed by a player on a planet.

If your tech doesn’t unlock any buildings, then just delete this field.

My tech doesn’t unlock a building, so *poof* I pressed delete and got rid of that section. But let’s say you did want to unlock a couple of buildings, the Tower of Babel and the Great Pyramids, for example:


  <unlocked_items>
    <Item>
      <type>UIT_BUILDING</type>
      <name>BUILDING_TOWER_BABEL</name>
    </Item>
    <Item>
      <type>UIT_BUILDING</type>
      <name>BUILDING_GREAT_PRYAMIDS</type>
    </Item>
  </unlocked_items>

Notice how each building unlocked has its own little item XML markup.

So far my tech looks like this:

  <Tech>
      <name>LEARN_DREK_TUTORIAL</name>
      <description>LEARN_DREK_TUTORIAL_DESC</description>
      <type>TT_APPLICATION </type>
      <category>LEARNING_CATEGORY</category>
      <research_cost>10</research_cost>
      <research_turns>5 </research_turns>
      <prerequisites>
          LEARN_THEORY_OF_DREK
      </prerequisites>
      EFFECTS_GROUP [optional]
  </Tech>

Step 3: The Defining the Effects Groups

This is the hard part. Defining an effects group is a little like writing a simple computer program. You’ll want to read the Effects document, print it out, read it again, and keep it around for reference. The Effects engine is versatile, it can a lot stuff. The trade off is complexity: it’s not as trivial as just filling out fields in a form.

You can have as many effects groups as you need to define what a tech does. My effect...

+2 Max Science to all friendly worlds set to Primary/Secondary Science Focus

...requires just one effects group.

Just like techs, effects groups have an XML form that you need to fill out. Here it is:

  <EffectsGroup>
      <scope>SCOPE</scope>
      <activation>ACTIVATION</activation>
      <stacking_group>STACKING_GROUP</stacking_group>
      <effects>
          EFFECT0
          EFFECT1
          ...
          EFFENTN
      </effects>
  </EffectsGroup>

SCOPE This field defines what objects in the game are influenced by your technology. My tech operates on “all friendly worlds set to Primary/Secondary Science Focus”. Most techs should constrain their effects to worlds set to a particular focus, or environment, or whatever.

First off, we need to pick out all friendly worlds. We can do that with the EmpireAffiliation condition:

  <Condition::EmpireAffiliation>
      <empire_id>Source.Owner</empire_id>
      <affiliation>AFFIL_SELF</affiliation>
      <exclusive>1</exclusive>
  </Condition::EmpireAffiliation>

Notice I filled out empire_id with source.owner. This is a variable...there are many variables you can access, listed in the Effects document.

I filled out the affiliation field with an enumeration. Certain fields require certain enumeration: it’s mostly self explanatory. For example, the PlanetType condition requires PlanetType enumerations.

Exclusive is a Boolean value, which just means true (the number 1) or false (the number 0). For this particular field, safe bet is just to enter “1” when dealing with planets.

When FreeOrion executes this EmpireAffiliation condition, it will pick out all of the objects in the game owned by your empire. This includes space ships and buildings...but we are only concerned with the planets. So, I need to add another condition to the mix--the Type condition.

 <Condition::Type>OBJ_POP_CENTER</Condition::Type>

OBJ_POP_CENTER is yet another enumeration. Now, all population centers will be selected, including any future space based colonies that are not on planets.

We need to glue these two conditions together. The And condition does exactly that:

 <Condition::And>
    <Condition::EmpireAffiliation>
       <empire_id>Source.Owner</empire_id>
       <affiliation>AFFIL_SELF</affiliation>
       <exclusive>1</exclusive>
    </Condition::EmpireAffiliation>
    <Condition::Type>OBJ_POP_CENTER</Condition::Type>
 </Condition::And>

Pretty cool, huh? By sticking our conditions into an And XML field, we are saying that we want FreeOrion to pick out everything that’s both owned by our empire and a population center.

We need a couple more conditions to make things work...remember that that we only want worlds that are set to the Primary or Secondary Science focus. Notice the word “or”.

First, let’s select all worlds that have the primary science focus, using the FocusType condition:

  <Condition::Focus>
      <primary>1</primary>
      <FocusType>FOCUS_RESEARCH</FocusType>
  </Condition::FocusType>

I filled out the primary field with a 1, meaning “true”. This will select all worlds with a Primary focus in science. It really will select ALL worlds, including those of enemy empires.

FOCUS_RESEARCH is another enumeration.

We need to do the same thing to select all worlds with Secondary focus in science, only this time the primary field would be filled in with "0".

The two FocusType conditions need to be glued together. Since the effect works on Secondary *or* Primary focus, use the condition Or:

  <Condition::Or>
     <Condition::Focus>
        <primary>1</primary>
        <FocusType>FOCUS_RESEARCH</FocusType>
     </Condition::FocusType>
     <Condition::Focus>
        <primary>1</primary>
        <FocusType>FOCUS_RESEARCH</FocusType>
     </Condition::FocusType>
  </Condition::Or>

Finally, to complete our scope field, we need to glue both pieces together. Just insert the Or condition into the And condition:

 <scope>  
   <Condition::And>
      <Condition::EmpireAffiliation>
        <empire_id>Source.Owner</empire_id>
        <affiliation>AFFIL_SELF</affiliation>
        <exclusive>1</exclusive>
      </Condition::EmpireAffiliation>
      <Condition::Type>OBJ_POP_CENTER</Condition::Type>
      <Condition::Or>
        <Condition::Focus>
          <primary>1</primary>
          <FocusType>FOCUS_RESEARCH</FocusType>
        </Condition::FocusType>
        <Condition::Focus>
          <primary>1</primary>
          <FocusType>FOCUS_RESEARCH</FocusType>
        </Condition::FocusType>
      </Condition::Or>
   </Condition::And>
 </scope>

Notice, you can nest And/Or conditions. The above states:

If the object is owned by our empire AND the object is a population center AND (the object is set to Primary Science Focus OR the object is set to Secondary Science Focus) THEN do something funky to the object.

Seems like a lot of work spelled out like that, but it’s easier once you get the hang of it.

Notice that everything above is contained by the scope XML field of the Effects Group. We now need to fill out the activation field.

 <activation>
    <Condition::Self/>
 <activeation>

The activation field is a universe that consists only of the object’s owner. You use the same conditions as the scope field—if any object is selected by the condition, then the effect fires. This is useful is you don’t want an effects group to fire under certain conditions. For example, for a building we could test it’s planet’s environment. We could set up a condition to test if the planet is Barren, or whatever.

It’s safe just to enter the Self condition, which ensures the effect always fires.

Next, the stacking group:

 <stacking_group>STACK_DREK_TUTORIAL</stacking_group>

Stacking groups are mostly for buildings. If you have two buildings in the same solar system that both effect every planet in the solar system, you’d only want one building’s effects to fire. That’s more or less what the stacking group is for.

For technologies, it’s safe just to enter the name of the tech, perhaps prefixed with the word “STACK”.

Now, the payload, the actual effects:

 <effects>
   <Effect::SetMeter>
      <meter>METER_RESEARCH</meter>
      <value>Target.MaxResearch+2</value>
      <max>1</max>
    </Effect::SetMeter>
 </effects>  

My tech has only one effect...but you can include as many effects as you need.

The most common effect is SetMeter. The first field, meter, determines which meter is effected. METER_RESEARCH is an enumeration.

The value field is filled by an expression. An expression can be nearly any math statement (4*3 or Target.MaxResearch+10). Notice, I took the value of the Target’s Max Research, then added 2. If I had just typed “2” into the value field, it would set the meter to “2”. Instead of being a bonus, my tech would suck ass.

The third field of SetMeter is max, which determines whether it’s the current value of the meter or the max value of the meter effected. In FO, techs normally operate on the max value of a meter. Then, the current value slowly rises to match at a speed based on the construction meter. Putting “1” into the max field (for “true”) will operate on the max meter, which 9 times out of 10 is exactly what you want to do.

Our tech is mostly finished. When the effects group is placed into it’s proper position, the whole thing looks like this:

  <Tech>
      <name>LEARN_DREK_TUTORIAL</name>
      <description>LEARN_DREK_TUTORIAL_DESC</description>
      <type>TT_APPLICATION </type>
      <category>LEARNING_CATEGORY</category>
      <research_cost>10</research_cost>
      <research_turns>5 </research_turns>
      <prerequisites>
          LEARN_THEORY_OF_DREK
      </prerequisites>
      <EffectsGroup>
        <scope>
          <Condition::And>
            <Condition::EmpireAffiliation>
              <empire_id>Source.Owner</empire_id>
              <affiliation>AFFIL_SELF</affiliation>
              <exclusive>1</exclusive>
            </Condition::EmpireAffiliation>
            <Condition::Type>OBJ_POP_CENTER</Condition::Type>
            <Condition::Or>
              <Condition::Focus>
                <primary>1</primary>
                <FocusType>FOCUS_RESEARCH</FocusType>
              </Condition::FocusType>
              <Condition::Focus>
                <primary>1</primary>
                <FocusType>FOCUS_RESEARCH</FocusType>
              </Condition::FocusType>
            </Condition::Or>
          </Condition::And>
        </scope>
        <activation><Condition::Self\></activation>
        <stacking_group>STACK_DREK_TUTORIAL</stacking_group>
        <effects>
          <Effect::SetMeter>
            <meter>METER_RESEARCH</meter>
            <value>Target.MaxResearch+2</value>
            <max>1</max>
          </Effect::SetMeter>
        </effects>
     </EffectsGroup>
  </Tech>

As you’ve probably noticed, the scope condition is the longest and toughest part to write.

Step 4 Composing the string table

Not everyone speaks English.

I’ll give my fellow Americans time to recover from that statement.

...

...

As tiring as it is to accommodate the English impaired, we need to anyway. This means writing out any words that appear in the game in a string table.

It can be pretty simple:

LEARN_DREK_TUTORIAL
Drek’s Effects Tutorial
LEARN_DREK_TUTORIAL_DESC
A marvelous, high tech tutorial that enlightens all who read it.\n 
Effect: +2 Max Science to all friendly worlds set to the Science Focus.

Notice the \n, for a “newline.” There’s other pieces of formatting you can use, see the FAQ for details.

That’s pretty much it. Congrats if you’ve read this far. I probably would have got bored round step #2.

Appendix: Additional Examples

Visit Geoff's house of horrors to view some examples: XML Examples