We are all familliar with the in-game ship's command menus. Navigation, Combat, Trade, Special... and you can also add in Turrets. Egosoft has made X² extremely extensible, and that includes these menus. Many of us by now have downloaded and installed scripts that add in more functionality, such as BurnIt!'s new Trade Command Extension Mk. 3 with it's "Start Sector Trader" command. I am going to go step-by-step on how to take your script and integrate it in the game - show you how to make your own new commands.
This is not a tutorial on scripting in general. I would caution you that with scripts, you can do almost anything - and scripting is quite complex. If the meaning of a scripting command isn't clear to you, then I advise extreme caution in playing with it. Definitely don't do it and then overwrite a save. I suggest everyone start a new game and get a save close to the beginning that you use for your script writing.
I am going to use as an example in this tutorial, a script I wrote that attaches into the trade menu. This script attempts to maintain the amount of product in a factory at a set level. This is useful if you have a factory that can only hold a very small amount of product, and you don't want to have to transfer the product manually to a transport all the time. A full explanation for the script and reasoning behind it is in my post on the subject.
- A copy of this tutorial's companion scripts.
- An XML editor is useful, but not a must. I prefer simple ones, such as Peter's XML Editor. There are lots of others though, many of them free.
There are three basic steps to attaching a script to the command menus. First of all, you obviously need the script you are going to attach in. Secondly, you need an XML language file that contains the added text for the game. Lastly, you need another script - one that is run automatically each time X² starts up and actually does the attaching of the script to the menu system.
The source script. As this isn't a tutorial on scripting in general, we're not going to cover this step in much depth at all. I will say, though, that one of the best ways to learn scripting is to go over those that have already been done. I would suggest downloading X2Modder by OlisJ and using this to decompress X²'s built-in scripts. Egosoft was nice enough to provice a fairly nice XSL stylesheet for X² scripts, so you can simply double-click on them once they have been decompressed to view them.
Here we start getting to the heart of the issue. Most of the game-text for anything from wares to ship descriptions to menu commands are stored in external XML language files. These files reside in one of two places: they can either be in the X2\t directory, or they can be inside container files (very similar to .zip files). Most of the text already in the game is in XML language files that are inside the *.CAT/*.DAT file pairs in the X² main folder. Any file that is inside one of these containers is treated just as if it were in the normal subdirectories under where you installed X². You can use X2Modder to decompress these containers and look to see what they hold. If you are using the 1.2 patch of X², then the 03.CAT/03.DAT file pair is the container that holds the language files with most of the existing in-game text. These files are 440001.XML and 440002.XML. If you have downloaded and installed BurnIt's Trade Command Extension Mk. 3, then in the X2\t directory you will find 440003.XML. This file contains the added text needed for that new script.
You will have noticed by now that there is a pattern to the way these files are named. The first two digits is actually the language code; 44 is English . You will notice that BurnIt!'s extension came with a '49' file too - which is German. If you want your added scripts to work in multiple languages, then you will need to provide XML language files for each language. This might not be a bad idea, even if the text in them is still in English.
After the language code, the rest of the filename contains a number that is used simply to identify an individual language file to any script that wants to use it. You will use this number to "load" the text from an XML language file into the game from within a script.
Put the language code and the ID number together, and you get the whole filename "440003.XML".
Many people are writing scripts with installers that actually modify the 440003.XML file in order to store text in it. This is the wrong way to do it. I suspect they are doing it this way because they don't know the correct way to add their own new files to X². The whole purpose of being able to have multiple addon language files is so that you don't need to fool with existing (ie: someone else's) language files if you want to add something later on. You simple add another file in.
You will need to pick an ID number for your file. It is important that this ID number not conflict with ID numbers used in any other script or mod. There is an effort underway right now to make a central authority for assigning these numbers, but this is not yet in place. For the time being, I highly recommend you follow these guidelines:
- Don't use fairly low numbers. 440001.XML through 440003.XML have already been used by Egosoft. It's a sure bet that official Egosoft addon scripts in the future will use more.
- If you write and release multiple scripts, use one file for all of them. Essentially, this means using one XML language file for ALL your scripts. If/when you release your scripts, release them in two parts - release your scripts seperately from your XML language file. That way anyone downloading it will always get the latest version of it that will work with any and all scripts you have released. This might mean that there is text in the language file that a person is using that is for a script he or she doesn't use. Although there are more ID numbers that are used within XML language files that are potential sources of conflicts, by the time there are enough scripts out there to make these type of conflicts likely, there should be a central method in place for assigning them.
Long and short command names
In my example, I chose "Maintain Product Quantity" for the long name, and "MaintainQuant" for the short.
The language files use an XML "PAGE" tag to identify text used for different purposes. A "PAGE" tag with an ID attribute of 2010 identifies text that is for a command's long name whereas 2011 identifies text for a command's short name. Notice as well that the 't' text tag that we are using to mark the text has an ID attribute of 421 and that it's the same ID for both the long and the short. This is important in step 3.
For a single added command, that is all the added text that needs to appear in the XML language file.
We have the script we want to use for our new command, and we have an XML language file that will be used for the command menu's text. Now we need to make a little script that links them together in the game. This is one thing that an init script is used for.
An init script is any script with a filename that starts with (surprisingly enough) "init.". Any script named with that prefix will be executed automatically every time X² is run. It is vitally important that you are careful with these. A bug in one could potentially have serious ramifications later on. The example init script is in the file "init.cmd.maintprod.xml".
Our init script must perform three tasks: it needs to load in the XML language file, it needs to tell the game what in-game ware our command is to be linked to, and then it needs to attach our script to a command and tell the game what ships can use this command.
First, loading the XML language file. The first statement in the example is:
Code: Select all
load text: id=21
Now we need to attach our script (the example one is called "ship.cmd.maintprod") to a command in the game. An X² "command" is simply an in-game action that you can reach through the menuing system somewhere. There are (obviously) a whole bunch of pre-defined in-game commands in X² - all of which are attached to scripts by the init scripts supplied with the game. While it is possible to add in wholely new commands, this adds complexity to the procedure. Luckily, we don't need to add in a new command. Egosoft was quite nice to us and made 32 extra commands of each type. These are commands that aren't attached to any script - whose sole purpose is to be there for people like us who want to use them to attach scripts to later on.
To use one of these extra commands, we first need to tell the game what "ware" will house our command. That is, what does a person need to buy in order to get access to the command. In the case of the example, we are going to have this command included with the "Trade command extension Mk. 1" ware. So we tell the game any ship that has the "Trade command extension Mk. 1" will be able to use our new command. How do we do this? The next statement in the example init script shows us:
Code: Select all
set ship command upgrade: command=COMMAND_TYPE_TRADE_21 upgrade=Trade Command Software MK1
Now we have loaded the language file, and told the system that we are adding in a new command and have told it how to find the text for the new command in the XML language file. All we need to do now is link the command to our script:
Code: Select all
global ship map: set: key=COMMAND_TYPE_TRADE_21, class=Ship, race=Player, script='ship.cmd.maintprod', prio=0 global ship map: ignore: key=COMMAND_TYPE_TRADE_21, class=Big Ship, race=Player
Now, since in our case this command is useless for a ship of class M6 or larger (since they can't dock to a factory anyway), the next statement says that the command should be attached to whatever ships it was attached to before (which was all of them) except for ships of class "Big Ship" (which is M6 or larger).
We could have done this differently. We could have had a separate statement to attach the command to each class individually (M5, M4, M3, TS, TL, Goner). It saves a little room this way, though, to say attach to all of them and then give the exception. You can decide which way is most appropriate for your script/command.
Now we've created a script, written a language file for a command for it, and attached the script to a commant. All that's left now is to deploy our new command. The scripts just need to be in X²'s script directory. The XML language file goes in X²'s "t" directory. And that's all there is to it. If you've done it correctly, you will get a menu that looks like this:
The results of our labours
I used the number 21 twice here - once to denote the ID number for the XML language file, and once to denote which extra trade command to use. This was probably a poor choice, since it might make for a little confusion. If you're confused between the difference between the XML language ID number, and the command text ID tag number within the language file, then read things over again carefully.