Skip to content

ScriptingTutorial1

Ed Kolis edited this page Aug 25, 2019 · 1 revision

This tutorial explains the behavior of the default dummy AI script in FrEee.

Script Code

Let's take a look at the code in AI.py, starting from the beginning.

#!python

# Default empire AI script

The first line of the script is a comment, since it begins with a # sign. Comments are just explanatory text; they can say whatever you want, and will be ignored by IronPython. Use them liberally to remind yourself (and anyone else who will maintain your scripts) what you were doing!

#!python

# import necessary classes and extension methods
clr.AddReference("System.Core");
import System;
from System.Collections.Generic import List;
clr.ImportExtensions(System.Linq);
import FrEee;
import FrEee.Utility;
from FrEee.Game.Objects.Commands import *;
clr.ImportExtensions(FrEee.Utility.Extensions);
from System import Console;

Next is a set of import statements. There are a number of types of import statements here, so let's go through each type:

  • clr.AddReference("System.Core"); - Adds a reference to a library. System.Core is not referenced by default, and we want to use its extension methods, so we need to add it here.
  • import System; - Imports a namespace so that classes within it can be used by referring to them prefixed with the namespace name.
  • from System.Collections.Generic import List; - Imports a specific class from a namespace so it can be referred to without a prefix.
  • *from FrEee.Game.Objects.Commands import ; - Imports all classes from a namespace so they can be referred to without a prefix.
  • clr.ImportExtensions(System.Linq); - Imports extension methods from a namespace, allowing them to be called on whatever type they extend (e.g. ToRomanNumeral() extends the "int" type).
#!python

# alias the domain and context variables to avoid confusion
empire = domain;
galaxy = context;

All FrEee scripts have at least two variables passed in to them: "domain" and "context". The domain is what the script has control over, and any changes made will be sent back to the game. The context is just there for reference, and any changes made will be ignored, so as to prevent cheating. In the case of an AI script, the domain is the empire that the AI is controlling, while the context is the galaxy view of the empire, so we will create new variables with more appropriate names to avoid confusing ourselves later. (Note: In Python, variables do not need to be declared; just assign a value to them and they will be implicitly declared.)

#!python

if (enabledMinisters.ContainsKey("Empire Management")):
	category = enabledMinisters["Empire Management"];
	if (category.Contains("Research")):
		# choose what to research
		cmd = ResearchCommand();
		cmd.SetSpending(galaxy.Mod.Technologies.FindByName("Propulsion"), 100);
		empire.ResearchCommand = cmd;

Here we get to the meat of this script. AI scripts are special in that they are also passed in a variable called "enabledMinisters", which specifies which "ministers", or AI subcomponents, are enabled for this empire. enabledMinisters is a dictionary (aka hashtable or map) mapping strings representing categories of ministers to lists of strings representing individual ministers. Any ministers that are enabled will appear in their appropriate category.

At this point we check to see if the "Empire Management" minister category contains any enabled ministers, and if so, if the "Research" minister in that category is enabled. If it is, we then create a research command, and set the spending on propulsion technology to 100% of the empire's total research output, then set it as the empire's research command so that the empire will perform the designated research.

#!python

# test AI data storage
if (not empire.AINotes.HasProperty("Log")):
	empire.AINotes.Log = List[str]();
empire.AINotes.Log.Add(str.Format("{0} has played its turn for stardate {1}.\n", empire.Name, galaxy.Stardate));
for msg in empire.AINotes.Log:
	Console.WriteLine(msg);

Finally, we have a demonstration of AI data storage. The AI can store arbitrary data in a property of the empire called AINotes. AINotes is a dynamic dictionary, so you can create sub-properties of this object just by assigning to them. Here we check if the Log property existss, and if not, create it as a list of strings. Then we add a message indicating that the empire has played its turn. Finally, we print out all of the logged messages to the console, to demonstrate that they are persistent between turns.

Ministers File

In addition to AI.py, there are two other files used by an AI script. The first is AI.ministers. This contains a hierarchical list of minister categories and ministers, with the ministers within a category appearing below the category and indented with tabs. At some point this will be connected to the game's GUI so that players can toggle individual ministers on, off, or on only when the player does not submit a PLR file. For now, human players have all ministers toggled off. AI players, naturally, have all ministers toggled on.

Script Include File

AI.script contains a list of other script files to be included into the AI script. This is useful for creating script libraries to be used by multiple AIs. Scripts are referenced by relative paths from the mod folder. Included scripts are automatically imported, with the namespace being the filename of the script, so for instance if you include Scripts/TestInclude.py, then the code in that file will be available in the TestInclude namespace.

Return to Scripting Tutorial

Clone this wiki locally