The best way to start learning it is to take a look at the missiontest lua. That has the basic structure for a really simple mission. I've made one mission, and thor's made a bunch and all of them are based off of that design.
http://spring.unknown-files.net/file/27 ... Onslaught/
http://spring.unknown-files.net/file/28 ... uillotine/
They are for nota and are quite good.
To make a simple mission first make a copy of the missiontest and give it a new name. Then open the file and do a search and replace for MissionTest and give it your new name, say PeeweeIsland. That will give you a new startscript to work with. Then clean out every thing inside the SlowUpdate function, the Setup function, and the SetupDelayed function.
To start making the mission load up spring from spring.exe and choose mission builder from the list. Cheat and build a friendly base with all the guys you want, and an enemy base. Then select all the guys on once side and type in the command savesel or savelist. It's important to save the lists of friendly and enemy units separately. If you don't it'll just save them all together and you won't be able to figure out which side which ones are on.
Once you save the units, quit and open up the file infolog. It'll have the code for loading in the units in there. Don't open up spring again before you copy it out or you'll lose everything.
Cut out the unit loading code from that file paste it into the PeeweeIsland:Setup() function. You still have to set the team manually for each unit for some reason. For example if it says
Code: Select all
units.Load("CORAK", float3(1200, 80, 200), 0, false)
that 0 means team 0. If it's supposed to be an enemy unit you have to set it to team 1. Once you paste everything in and change all the enemy units to 1's you can try it out. It won't do anything, but everything should be there.
The center of your mission script is the update function. It gets called by the game 30 times per second. You call all the other functions from that function. We haven't tried bringing in AI, but that should be possible. A lot of the missions we've made run on a time counter.
Code: Select all
-- This function is executed every simulated frame (30 times/sec)
function GullyOnslaught:Update()
-- Perform initialization
if self.state == 0 then
self.state = 1
self:Setup()
print("Intel reports the arm is planning a major offensive. " ..
"Defend our mining operation in this region. " ..
"We will bring in what support we can.")
end
-- Run SlowUpdate once every second
if math.mod(gs.frameNum, 30) == 0 then
self:SlowUpdate()
end
-- Do some stuff a bit later
if gs.frameNum == 30*10 then
print("There are 4 nuclear mines placed along the central pass. " ..
"If you have to, fall back and detonate them behind you.")
end
if gs.frameNum == 30*20 then
self:SetupDelayed()
end
if gs.frameNum == 30*60 then
self:ForwardTanks1()
end
if gs.frameNum == 30*75 then
self:ForwardTanks2()
end
end
The setup function only runs once, the first frame when the game starts and never again. That's where you want to put in all the code for loading the starting units and bases
The parts at the bottom are functions that get called after x amount of time. 10 seconds in the game prints a message. SetupDelayed() gets called after 20 seconds. ForwardTanks1() is called after 60 and ForwardTanks2() is called after 75.
This is the code for ForwardTanks1. It loads a bunch of units near the edge of the map where the enemy base is and tells them to move up to near the front just out of range or your defenses. You get the load unit code for them the same way you do for loading the starting units in the setup function.
Code: Select all
function GullyOnslaught:ForwardTanks1()
local unitList = {
units.Load("ARMSTUMP", float3(4294.4, 119.7, 569.2), 1, false),
units.Load("ARMSTUMP", float3(4375.3, 121.6, 555.5), 1, false),
units.Load("ARMSTUMP", float3(4424.2, 126.5, 621.0), 1, false),
units.Load("ARMSTUMP", float3(4498.7, 119.6, 509.9), 1, false),
units.Load("ARMSAM", float3(4294.2, 115.2, 449.7), 1, false),
units.Load("ARMSTUMP", float3(4555.6, 118.8, 486.7), 1, false),
units.Load("ARMSTUMP", float3(4612.9, 118.8, 471.7), 1, false),
units.Load("ARMSTUMP", float3(4298.7, 117.6, 515.2), 1, false),
units.Load("ARMSAM", float3(4332.7, 114.1, 335.6), 1, false),
units.Load("ARMSTUMP", float3(4345.2, 116.9, 497.9), 1, false),
units.Load("ARMSTUMP", float3(4445.7, 120.3, 506.3), 1, false),
units.Load("ARMSAM", float3(4472.5, 114.1, 391.7), 1, false),
units.Load("ARMSAM", float3(4571.3, 115.2, 358.5), 1, false),
units.Load("ARMSTUMP", float3(4472.8, 115.6, 450.8), 1, false),
units.Load("ARMSAM", float3(4260.4, 114.1, 396.6), 1, false),
units.Load("ARMBULL", float3(4579.6, 117.6, 427.1), 1, false)
}
local c = Command()
c.id = Command.MOVE
c:AddParam(4284)
c:AddParam(132)
c:AddParam(3886)
for i = 1, table.getn(unitList) do
unitList[i]:GiveCommand(c)
end
end
That's the basics of it. If you want to refer to a group of guys later on, somewhere else in the script you have to give them a name. For example.
Code: Select all
self.panzer1 = {
units.Load("ARMSTUMP", float3(2054.0, 109.4, 594.0), 1, false),
units.Load("ARMMART", float3(2271.0, 108.2, 606.0), 1, false),
units.Load("ARMMART", float3(2303.0, 108.2, 574.0), 1, false),
units.Load("ARMYORK", float3(2065.0, 108.2, 480.0), 1, false),
units.Load("ARMMART", float3(2207.0, 109.1, 638.0), 1, false),
units.Load("ARMYORK", float3(2113.0, 108.2, 528.0), 1, false),
units.Load("ARMYORK", float3(2113.0, 107.0, 480.0), 1, false),
units.Load("ARMSTUMP", float3(2126.0, 111.4, 606.0), 1, false),
units.Load("ARMMART", float3(2239.0, 108.2, 638.0), 1, false),
units.Load("ARMSTUMP", float3(2094.0, 110.5, 606.0), 1, false),
units.Load("ARMBULL", float3(2250.0, 108.2, 503.0), 1, false),
units.Load("ARMSTUMP", float3(2136.0, 113.8, 638.0), 1, false),
units.Load("ARMSTUMP", float3(2168.0, 111.4, 638.0), 1, false),
units.Load("ARMSTUMP", float3(2022.0, 111.1, 594.0), 1, false),
units.Load("ARMMART", float3(2239.0, 108.2, 606.0), 1, false),
units.Load("ARMYORK", float3(2065.0, 108.2, 528.0), 1, false),
units.Load("ARMMART", float3(2207.0, 108.2, 606.0), 1, false),
units.Load("ARMMART", float3(2207.0, 108.2, 574.0), 1, false),
units.Load("ARMMART", float3(2239.0, 108.2, 574.0), 1, false),
units.Load("ARMMART", float3(2271.0, 108.2, 574.0), 1, false),
units.Load("ARMYORK", float3(2161.0, 108.2, 528.0), 1, false),
units.Load("ARMYORK", float3(2161.0, 108.2, 480.0), 1, false),
units.Load("ARMMART", float3(2303.0, 109.4, 606.0), 1, false),
units.Load("ARMSTUMP", float3(2077.0, 113.0, 652.0), 1, false),
units.Load("ARMSTUMP", float3(2109.0, 115.2, 652.0), 1, false)
}
local c = Command()
c.id = Command.PATROL
c:AddParam(4645)
c:AddParam(140)
c:AddParam(8926)
for i = 1, table.getn(self.panzer1) do
self.panzer1[i]:GiveCommand(c)
end
now that group of guys is know as panzer1 and you could put them on a patrol route going somewhere else later on.
The slowupdate function is best used for checking on triggers.
Code: Select all
if( self.snipertarget1.IsValid(self.snipertarget1) ) then
--still alive
else
--ding dong the witch is dead
end
that checks if the unit named snipertarget1 is alive or not.