Lua Module Tutorial
This tutorial is intended to give a brief overview of the Pioneer module system.
It's expected that the reader has a basic understand of Lua. Reading Programming in Lua if you really want to get into the guts of this interesting and powerful language. All Lua features are available to Pioneer scripts.
You should also bookmark the API reference. You'll need it to learn about the various functions available to your module as your script gets more complicated.
Please note that the Pioneer module API is still a work in progress. If you can't figure out how to do something it may be that the API needs a new method or attribute or even larger changes. Talk to the Pioneer developers and we'll see what we can do to extend it.
The event model
Pioneer modules are structured around game events. At startup your module should register to receive notification of the game events it is interested in. When that event occurs, the Lua function you registered will be called by the game engine and can take appropriate action.
There are many events available, see the EventQueue documentation for details. We'll cover a couple of the basic ones here to get you started.
Your first script
The onGameStart event is called when the game is started, either from the start menu or when a save game is loaded. Since it's the first event triggered by the engine its a good place to get started with module development.
Before we can register to receive an event, we first have to define a function to do something interesting with that event.
Lets start by defining a simple function:
local myGameStart = function () UI.Message("Welcome to Pioneer, commander.", "Pioneer") end
UI.Message is a simple function that displays text on the player's control panel display (where the scanner normally appears). See the API reference for more information.
So far we've defined a function, but we haven't told Pioneer to call it at the proper time. To do that, we have to connect the function to the appropriate event queue.
EventQueue.onGameStart:Connect(myGameStart)
This calls the Connect method on the EventQueue.onGameStart object with our function as the parameter. Now that we've done this Pioneer knows about our function and will call it every time a game starts.
Start Pioneer, and start a game. Notice the message appears on the control panel. Congratulations, you've written your first Pioneer module.
Bad guys!
A fun script to write when you're starting out is one that spawns ships to attack the player, so lets write that. Here's the scenario:
The evil Badtrons have discovered the secrets of hyperspace and have placed their evil patrol ships near the hyperspace exit points of all nearby systems. Expect to be attacked the moment you leave hyperspace.
In the Pioneer engine only one system truly "exists" at any one time, so you can't just make ships and place them in all the possible systems. Instead, you catch the onEnterSystem event and watch for the player to arrive in a new system, then spawn a bunch of ships near her to make it look like they were waiting all the time.
Here's the full script:
local myEnterSystem = function (ship) if not ship:IsPlayer() then return end local badguy = Space.SpawnShipNear('Talon Military Interceptor', Game.player, 10, 20) badguy:AddEquip('PULSECANNON_1MW') badguy:AIKill(Game.player) UI.ImportantMessage("This is a Badtron system. All others must die.", badguy.label) end EventQueue.onEnterSystem:Connect(myEnterSystem)
Registering the function with the event queue we've seen before, so we won't go into it in much more detail. The major difference to notice is that the onEnterSystem gets passed a parameter ship, which is the ship that entered the system.
The first line is testing to see who entered the system. Its important to understand that a player is just a special kind of ship, and a script might want to know when non-player ships enter a system. Your script will receive a onEnterSystem event for every ship that arrives, even if that ship was created by another script. Its important that you check to make sure the ship "belongs" to you, unless of course you're doing something clever to augment or override an existing script.
If its not the player entering the system we bail out immediately - there's nothing more to do. If it is the player then we need to create a ship. Space.SpawnShipNear is one of several ship creation functions, each with a slightly different purpose. As the name implies, this one creates a ship near a specific object.
The parameters to Space.SpawnShipNear are fully described in the API reference, but they are not particularly complicated. The first parameter is the name of the ship to spawn. The second is the object to spawn it near, in this case the player (we could have used ship here; its the same object, but Game.player makes it clearer what's going on. The third and fourth arguments specify the minimum and maximum distance to spawn the ship from the object, in kilometres. The game engine will choose a distance and position at random based on these values.
The ship now exists, floating dead in space. We need it to attack, but before it can do that it needs a weapon. The Ship.AddEquip method is used to add equipment and cargo to a ship. In this case we add a basic laser to the ship.
Our enemy ship is armed so its time to attack. Ship.AIKill is one of a class of high-level methods to instruct the ship to take some complex action. AI methods exist to put ships into orbit, dock, and so on. AIKill invokes the combat AI, which keeps fighting until one of the combatants dies. Here we instruct our ship to attack and kill the player.
At this point we've done all we need to do. The ship now exists, is armed, and is trying to take out the player. We do one other thing, which is to place a message on the player's control panel. Of course this is not necessary, but it adds a little realism to the scenario. The two arguments to the message functions are the message text, and who it appears to come from. The ship's label attribute holds the registration number of the ship. By calling the method this way we get the nice message: Message from AB-1234: This is a Badtron system. All others must die.