How to use Spring.GiveOrderToUnit

How to use Spring.GiveOrderToUnit

Discuss Lua based Spring scripts (LuaUI widgets, mission scripts, gaia scripts, mod-rules scripts, scripted keybindings, etc...)

Moderator: Moderators

Post Reply
User avatar
Zpock
Posts: 1218
Joined: 16 Sep 2004, 23:20

How to use Spring.GiveOrderToUnit

Post by Zpock »

I'm working on learning how to give units orders using LUA scripting. Since there's only a few scarce examples and the source code itself to go from I'm having quite a hard time doing it, so I thought I'd try to structure it into this thread and hopefully make some useful eventual wiki documentation. Since I basically have no idea what I'm doing there will probably be lots of errors in here for a while, a work in progress. I'd appreciate if people who knows better can point out any blatant errors, and hopefully fill in some of the blanks.

From the current wiki, this is what we're mainly dealing with AFAIK:

Code: Select all

Spring.GiveOrderToUnit

 ( number unitID,
   number cmdID,
   params = {number, etc...},
   options = {"alt", "ctrl", "shift", "right"} ) -> nil
Ok, so basically we want to give the unit an order, wich is complicated by the fact that there's a queue of orders and several different order types. The main problem is figuring out exactly what each parameter is. Since there's different types of commands with assumedly different parameters this isn't easy. I havn't found any relevant source code or documentation on the parameters so I'll have to try and guess from example code.

The first parameter is straight forward, simply wich unit will receive the order. The second parameter, cmdID is a bit trickier. I think this refers to wich command is to be given. I found this list in the spring source code wich I think is what goes in here:
00012 #define CMD_STOP 0
00013 #define CMD_INSERT 1
00014 #define CMD_REMOVE 2
00015 #define CMD_WAIT 5
00016 #define CMD_TIMEWAIT 6
00017 #define CMD_DEATHWAIT 7
00018 #define CMD_SQUADWAIT 8
00019 #define CMD_GATHERWAIT 9
00020 #define CMD_MOVE 10
00021 #define CMD_PATROL 15
00022 #define CMD_FIGHT 16
00023 #define CMD_ATTACK 20
00024 #define CMD_AREA_ATTACK 21
00025 #define CMD_GUARD 25
00026 #define CMD_AISELECT 30
00027 #define CMD_GROUPSELECT 35
00028 #define CMD_GROUPADD 36
00029 #define CMD_GROUPCLEAR 37
00030 #define CMD_REPAIR 40
00031 #define CMD_FIRE_STATE 45
00032 #define CMD_MOVE_STATE 50
00033 #define CMD_SETBASE 55
00034 #define CMD_INTERNAL 60
00035 #define CMD_SELFD 65
00036 #define CMD_SET_WANTED_MAX_SPEED 70
00037 #define CMD_LOAD_UNITS 75
00038 #define CMD_LOAD_ONTO 76
00039 #define CMD_UNLOAD_UNITS 80
00040 #define CMD_UNLOAD_UNIT 81
00041 #define CMD_ONOFF 85
00042 #define CMD_RECLAIM 90
00043 #define CMD_CLOAK 95
00044 #define CMD_STOCKPILE 100
00045 #define CMD_DGUN 105
00046 #define CMD_RESTORE 110
00047 #define CMD_REPEAT 115
00048 #define CMD_TRAJECTORY 120
00049 #define CMD_RESURRECT 125
00050 #define CMD_CAPTURE 130
00051 #define CMD_AUTOREPAIRLEVEL 135
00052 #define CMD_LOOPBACKATTACK 140
00053 #define CMD_IDLEMODE 145
I think you have to write actually a period instead of the underscores, I have seen people redefine the command names to use an underscore. Then there's a pair of special command ids, namely:

CMD_INSERT
CMD_REMOVE

These are used to put a command into the command queue (=waypoint list) at a specified location.

Now for the really tricky part, the params and options parameters. Params is a table (kind of struct/array) containing the parameters for the order itself, such as coordinates for a move order or a unit to guard for a guard order, etc. Im really not sure what options does at the moment.

For a simple example let's consider the CMD_MOVE, from the recent popular customformations widget:

Code: Select all

Spring.GiveOrderToUnit(unitID, cmdTag, pos, keyState)
cmdTag is set to:

Code: Select all

local cmdTag = CMD.MOVE
at the beginning of the code. pos is a table with the destination coordinates, {x, z, y}. The options state in this case I think is simply modifieing the order in a way similar to a meta keys being pressed if the order was given normally ingame, like shift for waypoints. So if you put {"shift"} here there is a waypoint added at the end of the order queue.

Next, we have the CMD_INSERT and CMD_REMOVE. The example in this case is the saboteur script:

Code: Select all

GiveOrderToUnit(unitID,CMD_INSERT,{-1,CMD_CAPTURE,CMD_OPT_INTERNAL+1,unitID2},{"alt"});
GiveOrderToUnit(unitID,CMD_INSERT,{cmd.tag,CMD_CAPTURE,CMD_OPT_INTERNAL+1,unitID2},{});
GiveOrderToUnit(unitID,CMD_INSERT,{0,CMD_STOP,0},{"alt"});
Ok, so looking at this code, inside the param table (third parameter of the function, being the "parameters" for the CMD_INSERT as well as the order being inserted, yeah confusing I know). The first variable, -1, cmd.tag, 0 respectively, is the position in the queue. I'm not sure yet wich position in the queue is refered to with what number. The second one is obviously what type of command is to be inserted. In the two first examples, I have no idea what the third thing, CMD_OPT_INTERNAL+1, is. The 4th, set to unitID2, is the target of the capture command. In the last example with stop, there's a zero at the third parameter, wich I have no clue about.

Future topics:
List of all parameters for all commands.
How to make and use Custom commands.
Variants, such as Spring.GiveOrderArrayToUnitMap (heh, no clue what that means).
User avatar
Zpock
Posts: 1218
Joined: 16 Sep 2004, 23:20

Post by Zpock »

Now for a simple example:

Code: Select all

function gadget:UnitDamaged(unitID, unitDefID, unitTeam, damage, paralyzer, attackerID, attackerDefID, attackerTeam)

	x, y, z = Spring.GetUnitPosition(attackerID)
	Spring.GiveOrderToUnit(unitID, CMD.MOVE, {x,y,z}, {})  

end
This will make a unit that is attacked to get a move order on top of the attacker.
User avatar
jK
Spring Developer
Posts: 2299
Joined: 28 Jun 2007, 07:30

Re: How to use Spring.GiveOrderToUnit

Post by jK »

1st Some info

CMD_* is the engine internal format, under lua you can access all those vars with CMD.* . Me and some other lua devs 'localize' those array/table vars (saves table lookups) with lines like the following at the top of the file:

Code: Select all

local CMD_MOVE = CMD.MOVE
2nd CMD.INSERT and CMD.REMOVE

and now some notes on CMD_INSERT and CMD_REMOVE: trepan's announce
trepan wrote:cmdid = CMD_INSERT
options.ALT -> treat param0 as a position instead of a tag
options.CONTROL -> use the build queue for factories
params[0] = position or command tag
params[1] = insertCmd id
params[2] = insertCmd options
params[3 ... N+2] = insertCmd params[0 ... N-1]

cmdid = CMD_REMOVE
options.ALT -> use the parameters as commandIDs
options.CONTROL -> use the build queue for factories
params[0 ... N-1] = tags or commandIDs to remove
reminder:

Code: Select all

Spring.GiveOrderToUnit 
 ( number unitID, 
   number cmdID, 
   params = {number, etc...}, 
   options = {"alt", "ctrl", "shift", "right"} ) -> nil
please take attention on:
params[2] = insertCmd options
params[3 ... N+2] = insertCmd params
The options and params values are twisted in comparison to GiveOrder!

But that is not the only difference. In comparison to GiveOrder the options values are not strings like "shift" etc., instead they use the spring engine internal format of those -> numbers. Those are:

Code: Select all

CMD.OPT_ALT
CMD.OPT_CTRL
CMD.OPT_SHIFT
CMD.OPT_RIGHT
CMD.OPT_INTERNAL
If you don't want anything special leave the corresponding field blank with a 0 (zero).


3rd Answers
The example in this case is the saboteur script:

Code: Select all

GiveOrderToUnit(unitID,CMD_INSERT,{-1,CMD_CAPTURE,CMD_OPT_INTERNAL+1,unitID2},{"alt"});
GiveOrderToUnit(unitID,CMD_INSERT,{cmd.tag,CMD_CAPTURE,CMD_OPT_INTERNAL+1,unitID2},{});
GiveOrderToUnit(unitID,CMD_INSERT,{0,CMD_STOP,0},{"alt"});
Ok, so looking at this code, inside the param table (third parameter of the function, being the "parameters" for the CMD_INSERT as well as the order being inserted, yeah confusing I know). The first variable, -1, cmd.tag, 0 respectively, is the position in the queue. I'm not sure yet wich position in the queue is refered to with what number. The second one is obviously what type of command is to be inserted. In the two first examples, I have no idea what the third thing, CMD_OPT_INTERNAL+1, is. The 4th, set to unitID2, is the target of the capture command. In the last example with stop, there's a zero at the third parameter, wich I have no clue about.
The first variable, -1, cmd.tag, 0 respectively, is the position in the queue. I'm not sure yet wich position in the queue is refered to with what number.
-1 should append the command to the end of the command queue
I have no idea what the third thing, CMD_OPT_INTERNAL+1, is.
I used it to identify the command cause it is a fake command (it never should be executed). Please note CMD.OPT_INTERNAL != zero, some commands behave totaly different if you use it. And the name already says that it is an internal command, so you as normal dev should NOT use it, except you know what you are doing!
small info for ppl who are interested on how this workaround works:
Because the normal CMD_CAPTURE should still work on the commando/saboteur, we have to mark those fake commands, which are used to intergrate our custom command into the command queue with line stipple etc. (note: we cannot draw those command line stipples with lua).
So I gave it a special option param: CMD_OPT_INTERNAL+1. I tested and looked it up in the source, if it does anything on the CMD_CAPTURE, and I hope it does not. To identify those commands with this special flag, we can use this:

Code: Select all

local cmds = GetUnitCommands(unitID);
if (cmds)and
   (cmds[1].id==CMD_CAPTURE)and(cmds[1].options.coded==CMD_OPT_INTERNAL+1)
then .. end

The "+1" makes it unique (other codes could still use CMD_OPT_INTERNAL w/o the +1). Therefore we have to know how spring parses those option params. It uses the bit-shift operators (like ">>") and begins with 8 (=CMD_OPT_INTERNAL/DONT_REPEAT), next is 16 (=CMD_OPT_RIGHT/RIGHT_MOUSE_KEY), and so on. So all bits under 8 are free (-> +1, +2, +4).


In the last example with stop, there's a zero at the third parameter, wich I have no clue about.
explained above in the CMD.OPT_* section


4th Wiki
I planned one for the GiveOrder+CMD.* a long time ago, but I didn't had the time to do so. If you want to extend the lua wiki, you are free to do so ;)
missing wikis are:
  • LuaSyncedMoveCtrl.cpp (done)
  • LuaSyncedRead.cpp (done)
  • LuaUnitDefs.cpp (done)
  • LuaWeaponDefs.cpp (done)
  • LuaUnitRendering.cpp
  • LuaMaterial.cpp
  • LuaUnsyncedCtrl.cpp (done)
  • LuaUnsyncedRead.cpp (done)
  • LuaVFS.cpp (done)
  • LuaConst*.cpp (done)
  • CallIns
Post Reply

Return to “Lua Scripts”