<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://springrts-wiki.p2004a.com/mediawiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Knorke</id>
	<title>Spring - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://springrts-wiki.p2004a.com/mediawiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Knorke"/>
	<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/wiki/Special:Contributions/Knorke"/>
	<updated>2026-11-08T22:05:44Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.11</generator>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=LUPS&amp;diff=10328</id>
		<title>LUPS</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=LUPS&amp;diff=10328"/>
		<updated>2014-12-06T19:18:57Z</updated>

		<summary type="html">&lt;p&gt;Knorke: github link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
Lua Particle System (LUPS)&lt;br /&gt;
&lt;br /&gt;
Licensed under the terms of the GNU GPL, v2 or later.&lt;br /&gt;
&lt;br /&gt;
== github ==&lt;br /&gt;
https://github.com/jk3064/lups&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Implementation ==&lt;br /&gt;
First, you need to differ between synced and unsynced FX,&lt;br /&gt;
so there are 2 LUPS instances running:&lt;br /&gt;
one in LuaUI (widget) and&lt;br /&gt;
one in LuaRules (gadget).&lt;br /&gt;
(To start a new instance simply include lups/lups.lua)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Why differ between synced and unsynced FX? ==&lt;br /&gt;
LuaUI has only a limited access to engine values, so it&lt;br /&gt;
could never determine the unittype of enemy units in airlos,&lt;br /&gt;
nor is it able to catch weapon explosion or to interact with&lt;br /&gt;
cob.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Which files are used by LUPS? ==&lt;br /&gt;
the core uses the following:&lt;br /&gt;
lups/*&lt;br /&gt;
bitmaps/GPL/lups/*&lt;br /&gt;
LuaUI/Widgets/lups_wrapper.lua&lt;br /&gt;
LuaRules/Gadgets/lups_wrapper.lua (only if you want synced&lt;br /&gt;
FX like shockwaves/nanolasers)&lt;br /&gt;
and there are the managers:&lt;br /&gt;
LuaUI/Widgets/gfx_lups_manager.lua&lt;br /&gt;
LuaRules/Gadgets/gfx_lups_manager.lua&lt;br /&gt;
the shockwaves gadget:&lt;br /&gt;
LuaRules/Gadgets/lups_shockwaves.lua&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== What are those managers? ==&lt;br /&gt;
LUPS itself doesn&#039;t start any FX. It needs other lua files&lt;br /&gt;
to tell LUPS when it should start a new FX.&lt;br /&gt;
There are many widgets and gadgets, which start LUPS FXs,&lt;br /&gt;
but the most interesting ones are the managers (and perhaps&lt;br /&gt;
the shockwaves gadget).&lt;br /&gt;
Also the manager in LuaRules differ from that one in LuaUI.&lt;br /&gt;
The manager in LuaUI starts FXs everytime an new unit gets&lt;br /&gt;
finished or an enemy unit enters the LOS, so those FX only&lt;br /&gt;
vanish if the unit dies or leaves the LOS again.&lt;br /&gt;
The LuaRules manager is much less customizable, it creates&lt;br /&gt;
very special FXs like cloaking and it also manage parts of&lt;br /&gt;
the LUPS nano particle handling.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== How do I implement my own FX? ==&lt;br /&gt;
Okay, in the case you use the LuaUI manager and you want to&lt;br /&gt;
create a per-unit FX (like a fusion FX, airjets, ...):&lt;br /&gt;
&lt;br /&gt;
1. open LuaUI/Widgets/gfx_lups_manager.lua&lt;br /&gt;
(don&#039;t shock the file seems huge, but most is only config,&lt;br /&gt;
and yeah it needs a cleanup ... someday :x)&lt;br /&gt;
2. scroll down (~50% scrollbar)&lt;br /&gt;
you will find the following table/array:&lt;br /&gt;
&amp;quot;local UnitEffects = {...}&amp;quot;&lt;br /&gt;
It holds the FX per-unitdef.&lt;br /&gt;
3. create a new sub-table like the following:&lt;br /&gt;
[UnitDefNames[&amp;quot;%UNITDEF_NAME%&amp;quot;].id] = {&lt;br /&gt;
{class=&#039;%FXCLASS%&#039;,options=%MY_FXOPTIONS_TABLE%}&lt;br /&gt;
},&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== What FXClasses exist and how do I know their options? ==&lt;br /&gt;
All FXClasses are located here:&lt;br /&gt;
/lups/ParticleClasses/*&lt;br /&gt;
If you open on of those files, you will see a function like this:&lt;br /&gt;
&lt;br /&gt;
function ShieldSphereParticle.GetInfo()&lt;br /&gt;
return {&lt;br /&gt;
name      = &amp;quot;ShieldSphere&amp;quot;,&lt;br /&gt;
}&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
That returned name is what you fill in %FXCLASS% (uppercase&lt;br /&gt;
doesn&#039;t matter), also it is in most cases same as the filename.&lt;br /&gt;
To see possible options of the FXClass scroll a bit down, you&lt;br /&gt;
will find a table like this:&lt;br /&gt;
&lt;br /&gt;
ShieldSphereParticle.Default = {&lt;br /&gt;
pos        = {0,0,0}, -- start pos&lt;br /&gt;
layer      = -23,&lt;br /&gt;
life       = 0, --in frames&lt;br /&gt;
size       = 0,&lt;br /&gt;
sizeGrowth = 0,&lt;br /&gt;
margin     = 1,&lt;br /&gt;
colormap1  = { {0, 0, 0, 0} },&lt;br /&gt;
colormap2  = { {0, 0, 0, 0} },&lt;br /&gt;
repeatEffect = false,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
The table contains all options and their default values.&lt;br /&gt;
So an example fx placed in LuaUI/Widgets/gfx_lups_manager.lua&lt;br /&gt;
could look like this:&lt;br /&gt;
[UnitDefNames[&amp;quot;armcom&amp;quot;].id] = {&lt;br /&gt;
{class=&#039;ShieldSphere&#039;,options={ life=3000, repeatEffect=true, size=300, colormap1={1,0,0,0.5}, colormap2={0,1,0,0.5} } }&lt;br /&gt;
},&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== How do I start my own FX from my widget/gadget? ==&lt;br /&gt;
First, you need a link to the interface, to do so you need&lt;br /&gt;
to access the global shared table of the widget-/gadgetHandler.&lt;br /&gt;
for LuaUI:&lt;br /&gt;
local LupsApi = WG.Lups&lt;br /&gt;
for LuaRules:&lt;br /&gt;
local LupsApi = GG.Lups&lt;br /&gt;
(nil check those, it is possible that Lups hasn&#039;t started yet!)&lt;br /&gt;
&lt;br /&gt;
That Api contains the following functions:&lt;br /&gt;
LupsApi.GetStats()&lt;br /&gt;
LupsApi.GetErrorLog(minPriority)&lt;br /&gt;
-&amp;gt;  LupsApi.AddParticles(class,options)   //returns a fxID&lt;br /&gt;
-&amp;gt;  LupsApi.RemoveParticles(fxID)&lt;br /&gt;
LupsApi.AddParticlesArray({ {class=className, ..FX options..},{class=className, ..FX options..},.. } )&lt;br /&gt;
LupsApi.HasParticleClass(className)&lt;br /&gt;
and&lt;br /&gt;
LupsApi.Config = {...}  //contains the options of lups.cfg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Example usage of AddParticles() ==&lt;br /&gt;
LupsApi.AddParticles(&#039;ShieldSphere&#039;, {&lt;br /&gt;
unit=unitID,&lt;br /&gt;
piece=&amp;quot;head&amp;quot;,&lt;br /&gt;
pos={0,100,0},&lt;br /&gt;
life=3000,&lt;br /&gt;
repeatEffect=true,&lt;br /&gt;
size=300,&lt;br /&gt;
colormap1={1,0,0,0.5},&lt;br /&gt;
colormap2={0,1,0,0.5}&lt;br /&gt;
})&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== How do I bind a FX to an unit/unitpiece? ==&lt;br /&gt;
There are some special options tags, those are:&lt;br /&gt;
unit := binds fx to unitID&lt;br /&gt;
piece:= binds fx to pieceNAME&lt;br /&gt;
pos  := worldspace coord or offset coord from the unit/unitpiece center&lt;br /&gt;
onActive := only show FX if the unit is active (e.g. used for airjets - a plane is active, if it flies)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Can I modify FX on runtime? ==&lt;br /&gt;
Sure you can. There is only one issue in 76b1 (it will&lt;br /&gt;
be fixed in the next spring release):&lt;br /&gt;
you can&#039;t modify widgets if they are in a .sdd, so you&lt;br /&gt;
have to copy it to your local widgets folder,&lt;br /&gt;
then you can run:&lt;br /&gt;
/luaui reload&lt;br /&gt;
each time you modified the file.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== I heard some options can contain Lua code? ==&lt;br /&gt;
Yeah, but only the SimpleParticles class support them and&lt;br /&gt;
_only_ in the &amp;quot;partpos&amp;quot; param:&lt;br /&gt;
&lt;br /&gt;
LupsApi.AddParticles(&#039;SimpleParticles&#039;, {&lt;br /&gt;
...&lt;br /&gt;
partpos = &amp;quot;r*cos(beta)*sin(alpha),r*cos(alpha),r*sin(beta)*sin(alpha) | r=random()*20, alpha=2*math.pi*random(), beta=2*math.pi*random()&amp;quot;&lt;br /&gt;
...&lt;br /&gt;
})&lt;br /&gt;
&lt;br /&gt;
The syntax is a bit extended so it looks similar to the&lt;br /&gt;
definitions of a mathical sets, but it can still contain&lt;br /&gt;
any lua code.&lt;br /&gt;
&lt;br /&gt;
Valid examples are:&lt;br /&gt;
&amp;quot;x,y,z | x=10,y=30,z=0&amp;quot;&lt;br /&gt;
&amp;quot;10,30,0&amp;quot;&lt;br /&gt;
&amp;quot;random(),random(),random()&amp;quot;&lt;br /&gt;
&amp;quot;x,y,z | r=random(), if (r&amp;gt;10) then x=10; y=30; z=0; else x=-10; y=-30; z=-0; end&amp;quot;&lt;br /&gt;
&lt;br /&gt;
[[Category:Libraries]]&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=User:Knorke/Sandbox3&amp;diff=20883</id>
		<title>User:Knorke/Sandbox3</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=User:Knorke/Sandbox3&amp;diff=20883"/>
		<updated>2014-11-08T03:55:41Z</updated>

		<summary type="html">&lt;p&gt;Knorke: /* Lua rocks */ pic&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
{{Caution|The Lua examples on this page has been tested and &#039;&#039;should&#039;&#039; work. However there is always the possibility that between copying from script into this text sometimes has been lost. If you notice something missing/wrong or something absolutely does not work then please tell in forum.}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Introduction=&lt;br /&gt;
This text talks about how to put features onto the map, using Lua.&lt;br /&gt;
&lt;br /&gt;
The text can be read in two ways:&lt;br /&gt;
*As a Lua tutorial that expands on [[Lua:Tutorial_GettingStarted]] and {{FIXME}} that other page in sandbox&lt;br /&gt;
*For mappers as way to put features onto their map. &lt;br /&gt;
**In this case you can skip some of the &amp;quot;finer details&amp;quot; and just copypaste what seems interessting.&lt;br /&gt;
&lt;br /&gt;
To follow the examples you can either...&lt;br /&gt;
* ...use your WIP map in .sdd format&lt;br /&gt;
* ...or unpack an existing map&lt;br /&gt;
* ...or use the test-mutator example from previous tutorial.&lt;br /&gt;
&lt;br /&gt;
This text will be based around the map &#039;&#039;&#039;&amp;quot;DesertTriad&amp;quot;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=Creating a feature: Spring.CreateFeature=&lt;br /&gt;
&lt;br /&gt;
Again we use our test-hill in the bottom right corner, of which we already know the coordinates:&lt;br /&gt;
&lt;br /&gt;
[[File:DesertTriadHillCoordinates.jpg]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;We want to create a feature on this hill.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Create a file: &amp;lt;code&amp;gt;LuaRules\gadgets\MyLuaFeatureTesting.lua&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
At [[Lua_SyncedCtrl#Feature_Handling]] we find the function &amp;lt;code&amp;gt;Spring.CreateFeature&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We need the parameters: &#039;&#039;featurename&#039;&#039; and &#039;&#039;x,y,z&#039;&#039; coordinates. The other parameters do not matter for now.&lt;br /&gt;
&lt;br /&gt;
The map &amp;quot;DesertTriad&amp;quot; already includes some rock features that we could use. If using the test-mutator then we can also use whatever features the game includes, usually that is mostly wrecks of destroyed units.&lt;br /&gt;
&lt;br /&gt;
Another group of features that we can use are the ones hardcoded in the engine: Geovents and trees.&lt;br /&gt;
&lt;br /&gt;
We use a feature named &amp;quot;treetype0&amp;quot;, it is a tree that comes with Spring engine.&lt;br /&gt;
&lt;br /&gt;
Putting feature name and coordinates as parameters:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Spring.CreateFeature (&amp;quot;treetype0&amp;quot;, 3830,  390, 3600)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==GameStart() or Initialize() or GamePreload() ?==&lt;br /&gt;
Where should we put the CreateFeature code?&lt;br /&gt;
&lt;br /&gt;
There are three callin functions that appear suitable:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;GameStart() Initialize() GamePreload() - can callin can I take?&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;GameStart()&amp;lt;/code&amp;gt; is called as soon as the game begins. &lt;br /&gt;
**However, it is not yet called when the players are ingame but have not readied up yet.&lt;br /&gt;
** =&amp;gt; If this callin was used then features would not appear until the game is started. Thus players could not see while choosing their start positions etc.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;GamePreload()&amp;lt;/code&amp;gt; is called as soon as soon the &amp;quot;game is ingame.&amp;quot;&lt;br /&gt;
**Features spawned in this function will be visible before readying up.&lt;br /&gt;
**However, it is only called once: Right after the game has finished loading.&lt;br /&gt;
***That means if we want to test our Lua by typing &#039;&#039;/luarules reload&#039;&#039; then it will not trigger again.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Initialize()&amp;lt;/code&amp;gt; is called when the gadget is initialized.&lt;br /&gt;
**Features spawned in this function will be visible before readying up.&lt;br /&gt;
**When typing &#039;&#039;/luarules reload&#039;&#039; the gadgets get initialized again and the function gets called again.&lt;br /&gt;
***This makes it suitable for testing.&lt;br /&gt;
&lt;br /&gt;
=&amp;gt; Both &amp;lt;code&amp;gt;Initialize()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;GamePreload()&amp;lt;/code&amp;gt; can be used to spawn features without &amp;quot;delay.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=&amp;gt; Maybe &amp;lt;code&amp;gt;GamePreload()&amp;lt;/code&amp;gt; is a bit &amp;quot;more technical correct&amp;quot; but &amp;lt;code&amp;gt;Initialize()&amp;lt;/code&amp;gt; is more suited for testing, so we use that.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=complete gadget that plants a tree=&lt;br /&gt;
Thus the gadget now looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function gadget:GetInfo()&lt;br /&gt;
  return {&lt;br /&gt;
    name      = &amp;quot;lua map stuff&amp;quot;,&lt;br /&gt;
    desc      = &amp;quot;create some features&amp;quot;,&lt;br /&gt;
    author    = &amp;quot;youe name&amp;quot;,&lt;br /&gt;
    date      = &amp;quot;the day a lua was made&amp;quot;,&lt;br /&gt;
    license   = &amp;quot;GNU GPL, v2&amp;quot;,&lt;br /&gt;
    layer     = 0,&lt;br /&gt;
    enabled   = true,&lt;br /&gt;
  }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if not gadgetHandler:IsSyncedCode() then&lt;br /&gt;
&lt;br /&gt;
function gadget:Initialize()&lt;br /&gt;
	Spring.CreateFeature (&amp;quot;treetype0&amp;quot;, 3830,  390, 3600)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
else --unsynced part below&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The result:&lt;br /&gt;
&lt;br /&gt;
[[File:OneTreeOnHill.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Tip|&#039;&#039;&#039;Such simple code is really all it takes to put features on a map.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If one wanted one could now replaces the featurename and coordinates and use it to populate a map. In fact some maps do just that.}}&lt;br /&gt;
&lt;br /&gt;
{{Tip|If you need to remove the tree for testing purposes, then reclaim it with the Commander or a constructor. (We will learn a better way soon)}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==If a tree falls from the sky... does it make a sound?==&lt;br /&gt;
One interessting thing is that Spring physics do not get activated until the game actually starts.&lt;br /&gt;
&lt;br /&gt;
Why is that relevant for spawning features?&lt;br /&gt;
&lt;br /&gt;
If we use a too high y-coordinate (vertical axis / height) then the tree will hover in the air until the game starts. &lt;br /&gt;
&lt;br /&gt;
[[File:FeaturesFallAtGameStart.gif]]&lt;br /&gt;
 &lt;br /&gt;
And then it will suddendly fall down! (Look at above gif and watch the small countdown)&lt;br /&gt;
&lt;br /&gt;
Similiar if we use too low y-coordinate then the tree will be created underground and only &amp;quot;pop&amp;quot; above ground once the game starts!&lt;br /&gt;
&lt;br /&gt;
{{Tip|It is important to spawn features (and units) at the correct y-coordinate.}}&lt;br /&gt;
&lt;br /&gt;
===GetGroundHeight===&lt;br /&gt;
Instead of reading the ground height from the tooltip we can also use the function &amp;lt;code&amp;gt;Spring.GetGroundHeight&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function gadget:Initialize()&lt;br /&gt;
	x = 3830&lt;br /&gt;
	z = 3600&lt;br /&gt;
	y = Spring.GetGroundHeight (x,z)&lt;br /&gt;
	Spring.CreateFeature (&amp;quot;treetype0&amp;quot;, x,y,z)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Functional forest=&lt;br /&gt;
We can put our tree-spawner code into a function and call it from &amp;lt;code&amp;gt;Initialize()&amp;lt;/code&amp;gt; multiple times with different coordinates:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function PlantTree (x,z)&lt;br /&gt;
	y = Spring.GetGroundHeight (x,z)&lt;br /&gt;
	Spring.CreateFeature (&amp;quot;treetype0&amp;quot;, x,y,z)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function gadget:Initialize()&lt;br /&gt;
	PlantTree (3830,3600)&lt;br /&gt;
	PlantTree (3850,3650)&lt;br /&gt;
	PlantTree (3800,3650)&lt;br /&gt;
	PlantTree (3810,320)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
&lt;br /&gt;
[[File:TreesSpawnedOnHill.jpg]]&lt;br /&gt;
&lt;br /&gt;
{{Tip|For practice try to make a function that spawns geothermal spots! The featurename is &amp;quot;geovent&amp;quot;.}}&lt;br /&gt;
&lt;br /&gt;
=Deleting all features from map=&lt;br /&gt;
Sometimes one might want to test the spawning of features again &amp;amp; again, on a clean plate.&lt;br /&gt;
The function below deletes all features on the map:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function DestroyAllFeatures ()&lt;br /&gt;
	local features = Spring.GetAllFeatures ()&lt;br /&gt;
	for i in pairs(features) do&lt;br /&gt;
		Spring.DestroyFeature (features[i])&lt;br /&gt;
	end&lt;br /&gt;
end&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It can be called in &amp;lt;code&amp;gt;Initialize()&amp;lt;/code&amp;gt; &#039;&#039;before&#039;&#039; we spawn our features, to ensure we always test on an empty map.&lt;br /&gt;
&lt;br /&gt;
When packing the map for release, one might want to comment it out again.&lt;br /&gt;
&lt;br /&gt;
=A forest is many, many, many trees=&lt;br /&gt;
A handful of trees is often not enough for a map. Let&#039;s turn the whole bottom left corner of the map into a forest. &lt;br /&gt;
&lt;br /&gt;
But planting a whole forest by typing coordinates of many trees seems very cumbersome?&lt;br /&gt;
&lt;br /&gt;
What about randomizing the placement of the tree?&lt;br /&gt;
&lt;br /&gt;
We look up the coordinates of that area: x-coordinate we want 3500 to 4000, for z-coordinate we want 3000 to 4000.&lt;br /&gt;
&lt;br /&gt;
...and put it into a random number generator function.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
x = math.random (3500,4000)&lt;br /&gt;
z = math.random (3000,4000)&lt;br /&gt;
PlantTree (x,z)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We want to plant many trees. Instead of copy-pasting those lines 100 times, we use a loop:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function gadget:Initialize()&lt;br /&gt;
	DestroyAllFeatures ()&lt;br /&gt;
	for i=1,100 do&lt;br /&gt;
		x = math.random (3500,4000)&lt;br /&gt;
		z = math.random (3000,4000)&lt;br /&gt;
		PlantTree (x,z)&lt;br /&gt;
	end&lt;br /&gt;
end&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The result:&lt;br /&gt;
&lt;br /&gt;
[[File:TreesSpawnedRandomly.jpg]]&lt;br /&gt;
&lt;br /&gt;
{{Tip|Forests are perfect for such random placement because the excact position of an indiviual tree does not matter much.}}&lt;br /&gt;
&lt;br /&gt;
==Spawning features in patterns==&lt;br /&gt;
With a little creativity one can quickly fill the map in interessting ways.&lt;br /&gt;
&lt;br /&gt;
For example try to create a function that spawns small clusters of trees. &lt;br /&gt;
&lt;br /&gt;
Or imagine a function that spawns a big mineral crystal, surrounded by smaller rocks.&lt;br /&gt;
&lt;br /&gt;
Or imagine an ore-mining facility with pieces of ore spread around it. &lt;br /&gt;
&lt;br /&gt;
etc&lt;br /&gt;
&lt;br /&gt;
Below is some examples that are hopefully understandable without too lenghty explainations.&lt;br /&gt;
&lt;br /&gt;
==Lua rocks==&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function Rock (x,z)&lt;br /&gt;
	local featureName = &amp;quot;pdrock&amp;quot; .. math.random (1, 4)&lt;br /&gt;
	Spring.CreateFeature (featureName, x,Spring.GetGroundHeight (x,z),z, math.random (0,32000))&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function rockCircle (x,z, radius, numberOfRocks)&lt;br /&gt;
for d = 0,360, 360/numberOfRocks do&lt;br /&gt;
		local x = x + (math.sin (math.rad(d)) * radius)&lt;br /&gt;
		local z = z + (math.cos (math.rad(d)) * radius)&lt;br /&gt;
		Rock (x, z)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
Example usage: &lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;rockCircle (2000,2000, 240, 25)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
&lt;br /&gt;
[[File:Circle_of_Rocks.jpg]]&lt;br /&gt;
&lt;br /&gt;
*Note 1: &amp;lt;code&amp;gt;local featureName = &amp;quot;pdrock&amp;quot; .. math.random (1, 4)&amp;lt;/code&amp;gt;&lt;br /&gt;
The rock features included in map &amp;quot;DesertTriad&amp;quot; are named &amp;quot;pdrock1&amp;quot; to &amp;quot;pdrock4&amp;quot;. So we take &amp;quot;pdrock&amp;quot; and append a random number in range of 1 to 4 to that base name.&lt;br /&gt;
&lt;br /&gt;
*Note 2: The heading-parameter is used here too, randomized. The heading (rotation) of features is probally not measured 0 to 32000, but for this case that does not matter. If the number is too high it will simply &amp;quot;wrap around.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==In my maps I have seen rings of smoke through the trees...==&lt;br /&gt;
&#039;&#039;...and the voices of those who stand looking.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function TreeSpiral (x,z)&lt;br /&gt;
	for d = 0,720, 20 do&lt;br /&gt;
		local x = x + (math.sin (math.rad(d)) * d/2)&lt;br /&gt;
		local z = z + (math.cos (math.rad(d)) * d/2)&lt;br /&gt;
		PlantTree (x,z)&lt;br /&gt;
	end&lt;br /&gt;
	y = Spring.GetGroundHeight (x,z)&lt;br /&gt;
	Spring.CreateFeature (&amp;quot;geovent&amp;quot;, x,y,z)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example usage: &lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;TreeSpiral (2000,2000)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
&lt;br /&gt;
A geothermal vent in the middle of a spiral of trees.&lt;br /&gt;
&lt;br /&gt;
[[File:TreeSpiralWithGeovent.jpg]]&lt;br /&gt;
&lt;br /&gt;
=Typing so many coordinates sucks!=&lt;br /&gt;
We saw how some typing could be saved by using loops or random placement.&lt;br /&gt;
But surely there must be another way?&lt;br /&gt;
&lt;br /&gt;
We could try to save the coordinates of all features of the map into a file.&lt;br /&gt;
&lt;br /&gt;
If we wanted to do that, we would preferably save the coordinates in a way that can also be read back by another script. &lt;br /&gt;
For now that seems too difficult so we think of another way.&lt;br /&gt;
&lt;br /&gt;
* think * think * think *&lt;br /&gt;
&lt;br /&gt;
==Coordinates Helper widget==&lt;br /&gt;
Spring allows players to mark tactical locations on the map by holding ~ or ^ and clicking the mousewheel.&lt;br /&gt;
&lt;br /&gt;
That might also be useful for marking locations of features, if we can just save those coordinates?&lt;br /&gt;
&lt;br /&gt;
Let&#039;s see if we can create a small &#039;&#039;&#039;helper widget&#039;&#039;&#039; for that purpose.&lt;br /&gt;
&lt;br /&gt;
Create a file &amp;lt;code&amp;gt;LuaUI\widgets\MapMarkerCoordinatesLogger.lua&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==MapDrawCmd: 1,2,3 testing!==&lt;br /&gt;
For start let&#039;s just see if we can print the coordinates of a map marker to the console.&lt;br /&gt;
&lt;br /&gt;
We discover the callin: &amp;lt;code&amp;gt;MapDrawCmd(playerID, cmdType, px, py, pz, label)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function widget:GetInfo()&lt;br /&gt;
  return {&lt;br /&gt;
    name      = &amp;quot;MapMarkerCoordinatesLogger&amp;quot;,&lt;br /&gt;
    desc      = &amp;quot;prints map marker coordinates&amp;quot;,&lt;br /&gt;
    author    = &amp;quot;this lame tutorial or something&amp;quot;,&lt;br /&gt;
    date      = &amp;quot;9 Nov 2010&amp;quot;,&lt;br /&gt;
    license   = &amp;quot;GNU GPL, v2&amp;quot;,&lt;br /&gt;
    layer     = -5,&lt;br /&gt;
    enabled   = true,&lt;br /&gt;
  }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function widget:MapDrawCmd(playerID, cmdType, px, py, pz, label)&lt;br /&gt;
	Spring.Echo (px, py,pz)&lt;br /&gt;
end&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
&lt;br /&gt;
[[File:MapMarkerCoordinatesToChat.jpg]]&lt;br /&gt;
&lt;br /&gt;
We see that the coordinates of the markers get printed to chat. (and thus to infolog.txt, too)&lt;br /&gt;
&lt;br /&gt;
Not bad, but could be less bad.&lt;br /&gt;
&lt;br /&gt;
==Turning test into something useful==&lt;br /&gt;
&lt;br /&gt;
One obvious issue is that it does not just log placing markers but also outputs numbers when drawing lines or deleting.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s upgrade the widget so that:&lt;br /&gt;
#It only logs placing markers but not erasing or lines.&lt;br /&gt;
#instead of coordinates it outputs a whole function call like &amp;lt;code&amp;gt;PlantTree (3830,3600)&amp;lt;/code&amp;gt;&lt;br /&gt;
#writes to a file instead of chat&lt;br /&gt;
#The functionname that gets written should be changeable from within game&lt;br /&gt;
#It has a cooler name&lt;br /&gt;
&lt;br /&gt;
{{Tip|&#039;&#039;&#039;Before reading onwards: Try figure out a solution by yourself!&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) Sadly the wiki does not tell us how we know the difference between marker/lines/erasing. We must figure it out!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;MapDrawCmd(playerID, cmdType, px, py, pz, label)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The paremter &#039;&#039;cmdType&#039;&#039; looks interessting. Let&#039;s just print that one too:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;Spring.Echo (px, py,pz, cmdType)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We see that cmdType has the value &amp;quot;point&amp;quot; when placing markers and other values when doing other things.&lt;br /&gt;
&lt;br /&gt;
So if cmdType is of wrong value we just return and do nothing:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function widget:MapDrawCmd(playerID, cmdType, px, py, pz, label)&lt;br /&gt;
	if cmdType ~= &amp;quot;point&amp;quot; then return end&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2) Creating the complete function call like &amp;quot;PlantTree (3830,3600)&amp;quot; is just a matter of appending some strings:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
local functionName = &amp;quot;PlantTree&amp;quot;&lt;br /&gt;
local s = functionName .. &amp;quot; (&amp;quot; .. px ..&amp;quot;, &amp;quot; .. pz .. &amp;quot;)&amp;quot;&lt;br /&gt;
Spring.Echo (s)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that we only save the X and Z coordinates because the Y-coordinate we can later get anyway with Spring.GetGroundHeight&lt;br /&gt;
&lt;br /&gt;
3) About writing to file we can find many tutorials on web if we google something like &amp;quot;Lua write to file&amp;quot; or similiar.&lt;br /&gt;
&lt;br /&gt;
The result:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
local file = io.open(&amp;quot;myCoordinatesFile.txt&amp;quot;, &amp;quot;a&amp;quot;)&lt;br /&gt;
file:write(s)&lt;br /&gt;
file:flush()&lt;br /&gt;
file:close()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Markers can have a label text attached to them. Let&#039;s use that to allow user to change the functionname.&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;if label ~= &amp;quot;&amp;quot; then functionName = label end&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Since the widget writes points into files for features placement, we name it: &#039;&#039;&#039;Pifffp&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Complete Pifffp widget=&lt;br /&gt;
Putting everything together we get:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function widget:GetInfo()&lt;br /&gt;
  return {&lt;br /&gt;
    name      = &amp;quot;Pifffp aka MapMarkerCoordinatesLogger&amp;quot;,&lt;br /&gt;
    desc      = &amp;quot;prints Lua functions for placing featues&amp;quot;,&lt;br /&gt;
    author    = &amp;quot;this lame tutorial or something&amp;quot;,&lt;br /&gt;
    date      = &amp;quot;today&amp;quot;,&lt;br /&gt;
    license   = &amp;quot;GNU GPL, v2&amp;quot;,&lt;br /&gt;
    layer     = -5,&lt;br /&gt;
    enabled   = true,&lt;br /&gt;
  }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local functionName = &amp;quot;PlantTree&amp;quot;&lt;br /&gt;
function widget:MapDrawCmd(playerID, cmdType, px, py, pz, label)&lt;br /&gt;
	if cmdType ~= &amp;quot;point&amp;quot; then return end&lt;br /&gt;
	if label ~= &amp;quot;&amp;quot; then functionName = label end&lt;br /&gt;
	--Spring.Echo (px, py,pz, cmdType, &amp;quot;-&amp;quot;..label..&amp;quot;-&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	local s = functionName .. &amp;quot; (&amp;quot; .. px ..&amp;quot;, &amp;quot; .. pz .. &amp;quot;)&amp;quot;&lt;br /&gt;
	Spring.Echo (s)&lt;br /&gt;
	&lt;br /&gt;
	local file = io.open(&amp;quot;myCoordinatesFile.txt&amp;quot;, &amp;quot;a&amp;quot;)&lt;br /&gt;
	file:write(s .. &amp;quot;\n&amp;quot;)&lt;br /&gt;
	file:flush()&lt;br /&gt;
	file:close()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Using the Pifffp tool as a user/mapper==&lt;br /&gt;
Activate the widget in F11 list.&lt;br /&gt;
&lt;br /&gt;
Now start placing map markers. Every time you place a marker the coordinates get logged into &#039;&#039;&#039;myCoordinatesFile.txt&#039;&#039;&#039;, already formated as parameters to a function call.&lt;br /&gt;
&lt;br /&gt;
(The file should usually be written next to spring.exe)&lt;br /&gt;
&lt;br /&gt;
To change the name of the function place a marker with a label text. All folling markers will then use that text, until a new label text is used.&lt;br /&gt;
&lt;br /&gt;
Example usage:&lt;br /&gt;
&lt;br /&gt;
[[File:Pifffp_Markers.jpg]]&lt;br /&gt;
&lt;br /&gt;
Example output:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
PlantTree (1977, 3569)&lt;br /&gt;
PlantTree (1933, 3372)&lt;br /&gt;
PlantTree (1901, 3489)&lt;br /&gt;
PlantTree (1850, 3612)&lt;br /&gt;
PlantTree (2008, 3643)&lt;br /&gt;
PlantTree (2101, 3497)&lt;br /&gt;
PlantTree (2112, 3637)&lt;br /&gt;
PlantTree (2228, 3605)&lt;br /&gt;
PlantTree (2226, 3464)&lt;br /&gt;
PlantTree (2043, 3406)&lt;br /&gt;
PlantTree (2163, 3357)&lt;br /&gt;
PlantTree (2293, 3278)&lt;br /&gt;
PlantTree (2125, 3179)&lt;br /&gt;
PlantTree (1986, 3193)&lt;br /&gt;
Rock (1526, 3099)&lt;br /&gt;
Rock (1576, 3024)&lt;br /&gt;
Rock (1500, 2926)&lt;br /&gt;
Rock (1373, 3035)&lt;br /&gt;
Rock (1438, 3212)&lt;br /&gt;
Rock (1556, 3264)&lt;br /&gt;
Rock (1699, 3122)&lt;br /&gt;
Rock (1670, 2919)&lt;br /&gt;
Rock (1398, 2918)&lt;br /&gt;
Geovent (1818, 3298)&lt;br /&gt;
rockCircle (2308, 2788)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We recognize these functions from the beginning of the tutorial. &lt;br /&gt;
&lt;br /&gt;
Hopefully still have them ready in our &amp;lt;code&amp;gt;LuaRules\gadgets\MyLuaFeatureTesting.lua&amp;lt;/code&amp;gt; file so that we only need to paste the Pifffp output into &amp;lt;code&amp;gt;Initialize&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(I you are making a real map you might want to use a better filename like &amp;quot;spawnMyFeatures.lua&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
Note that for the function rockCircle we still need to fill in the parameters radius and amount of rocks like so:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
rockCircle (2308, 2788, 200, 25)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example result:&lt;br /&gt;
&lt;br /&gt;
[[File:Pifffp_ResultFeatures.jpg]]&lt;br /&gt;
&lt;br /&gt;
Now we have created ourselves a quick way to put features onto map with Lua.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Making a map? How to turn LuaRules into LuaGaia!=&lt;br /&gt;
&amp;quot;LuaRules&amp;quot; is meant for games while maps should use &amp;quot;LuaGaia&amp;quot;. {{FIXME}} maybe link to some more detailed explaination of LuaStates.&lt;br /&gt;
&lt;br /&gt;
So if you want to move the scripts from the test-mutator (or other game archive) into a map then some minor changes are needed.&lt;br /&gt;
&lt;br /&gt;
The folder structure should be like:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;LuaGaia\gadgets\MyMapGadget.lua&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Also include two &amp;quot;base files&amp;quot; like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;LuaGaia\draw.lua&amp;lt;/pre&amp;gt; with content:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;VFS.Include(&amp;quot;LuaGadgets/gadgets.lua&amp;quot;,nil, VFS.BASE)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;LuaGaia\main.lua&amp;lt;/pre&amp;gt; with content:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;VFS.Include(&amp;quot;LuaGadgets/gadgets.lua&amp;quot;,nil, VFS.BASE)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For reloading this LuaGaia Lua type: /luagaia reload&lt;br /&gt;
&lt;br /&gt;
Everything else stays the same.&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=User:Knorke/Sandbox3&amp;diff=20882</id>
		<title>User:Knorke/Sandbox3</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=User:Knorke/Sandbox3&amp;diff=20882"/>
		<updated>2014-11-08T01:56:43Z</updated>

		<summary type="html">&lt;p&gt;Knorke: wiki images work again&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
{{Caution|The Lua examples on this page has been tested and &#039;&#039;should&#039;&#039; work. However there is always the possibility that between copying from script into this text sometimes has been lost. If you notice something missing/wrong or something absolutely does not work then please tell in forum.}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Introduction=&lt;br /&gt;
This text talks about how to put features onto the map, using Lua.&lt;br /&gt;
&lt;br /&gt;
The text can be read in two ways:&lt;br /&gt;
*As a Lua tutorial that expands on [[Lua:Tutorial_GettingStarted]] and {{FIXME}} that other page in sandbox&lt;br /&gt;
*For mappers as way to put features onto their map. &lt;br /&gt;
**In this case you can skip some of the &amp;quot;finer details&amp;quot; and just copypaste what seems interessting.&lt;br /&gt;
&lt;br /&gt;
To follow the examples you can either...&lt;br /&gt;
* ...use your WIP map in .sdd format&lt;br /&gt;
* ...or unpack an existing map&lt;br /&gt;
* ...or use the test-mutator example from previous tutorial.&lt;br /&gt;
&lt;br /&gt;
This text will be based around the map &#039;&#039;&#039;&amp;quot;DesertTriad&amp;quot;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=Creating a feature: Spring.CreateFeature=&lt;br /&gt;
&lt;br /&gt;
Again we use our test-hill in the bottom right corner, of which we already know the coordinates:&lt;br /&gt;
&lt;br /&gt;
[[File:DesertTriadHillCoordinates.jpg]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;We want to create a feature on this hill.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Create a file: &amp;lt;code&amp;gt;LuaRules\gadgets\MyLuaFeatureTesting.lua&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
At [[Lua_SyncedCtrl#Feature_Handling]] we find the function &amp;lt;code&amp;gt;Spring.CreateFeature&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We need the parameters: &#039;&#039;featurename&#039;&#039; and &#039;&#039;x,y,z&#039;&#039; coordinates. The other parameters do not matter for now.&lt;br /&gt;
&lt;br /&gt;
The map &amp;quot;DesertTriad&amp;quot; already includes some rock features that we could use. If using the test-mutator then we can also use whatever features the game includes, usually that is mostly wrecks of destroyed units.&lt;br /&gt;
&lt;br /&gt;
Another group of features that we can use are the ones hardcoded in the engine: Geovents and trees.&lt;br /&gt;
&lt;br /&gt;
We use a feature named &amp;quot;treetype0&amp;quot;, it is a tree that comes with Spring engine.&lt;br /&gt;
&lt;br /&gt;
Putting feature name and coordinates as parameters:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Spring.CreateFeature (&amp;quot;treetype0&amp;quot;, 3830,  390, 3600)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==GameStart() or Initialize() or GamePreload() ?==&lt;br /&gt;
Where should we put the CreateFeature code?&lt;br /&gt;
&lt;br /&gt;
There are three callin functions that appear suitable:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;GameStart() Initialize() GamePreload() - can callin can I take?&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;GameStart()&amp;lt;/code&amp;gt; is called as soon as the game begins. &lt;br /&gt;
**However, it is not yet called when the players are ingame but have not readied up yet.&lt;br /&gt;
** =&amp;gt; If this callin was used then features would not appear until the game is started. Thus players could not see while choosing their start positions etc.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;GamePreload()&amp;lt;/code&amp;gt; is called as soon as soon the &amp;quot;game is ingame.&amp;quot;&lt;br /&gt;
**Features spawned in this function will be visible before readying up.&lt;br /&gt;
**However, it is only called once: Right after the game has finished loading.&lt;br /&gt;
***That means if we want to test our Lua by typing &#039;&#039;/luarules reload&#039;&#039; then it will not trigger again.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Initialize()&amp;lt;/code&amp;gt; is called when the gadget is initialized.&lt;br /&gt;
**Features spawned in this function will be visible before readying up.&lt;br /&gt;
**When typing &#039;&#039;/luarules reload&#039;&#039; the gadgets get initialized again and the function gets called again.&lt;br /&gt;
***This makes it suitable for testing.&lt;br /&gt;
&lt;br /&gt;
=&amp;gt; Both &amp;lt;code&amp;gt;Initialize()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;GamePreload()&amp;lt;/code&amp;gt; can be used to spawn features without &amp;quot;delay.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=&amp;gt; Maybe &amp;lt;code&amp;gt;GamePreload()&amp;lt;/code&amp;gt; is a bit &amp;quot;more technical correct&amp;quot; but &amp;lt;code&amp;gt;Initialize()&amp;lt;/code&amp;gt; is more suited for testing, so we use that.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=complete gadget that plants a tree=&lt;br /&gt;
Thus the gadget now looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function gadget:GetInfo()&lt;br /&gt;
  return {&lt;br /&gt;
    name      = &amp;quot;lua map stuff&amp;quot;,&lt;br /&gt;
    desc      = &amp;quot;create some features&amp;quot;,&lt;br /&gt;
    author    = &amp;quot;youe name&amp;quot;,&lt;br /&gt;
    date      = &amp;quot;the day a lua was made&amp;quot;,&lt;br /&gt;
    license   = &amp;quot;GNU GPL, v2&amp;quot;,&lt;br /&gt;
    layer     = 0,&lt;br /&gt;
    enabled   = true,&lt;br /&gt;
  }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if not gadgetHandler:IsSyncedCode() then&lt;br /&gt;
&lt;br /&gt;
function gadget:Initialize()&lt;br /&gt;
	Spring.CreateFeature (&amp;quot;treetype0&amp;quot;, 3830,  390, 3600)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
else --unsynced part below&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The result:&lt;br /&gt;
&lt;br /&gt;
[[File:OneTreeOnHill.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Tip|&#039;&#039;&#039;Such simple code is really all it takes to put features on a map.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If one wanted one could now replaces the featurename and coordinates and use it to populate a map. In fact some maps do just that.}}&lt;br /&gt;
&lt;br /&gt;
{{Tip|If you need to remove the tree for testing purposes, then reclaim it with the Commander or a constructor. (We will learn a better way soon)}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==If a tree falls from the sky... does it make a sound?==&lt;br /&gt;
One interessting thing is that Spring physics do not get activated until the game actually starts.&lt;br /&gt;
&lt;br /&gt;
Why is that relevant for spawning features?&lt;br /&gt;
&lt;br /&gt;
If we use a too high y-coordinate (vertical axis / height) then the tree will hover in the air until the game starts. &lt;br /&gt;
&lt;br /&gt;
[[File:FeaturesFallAtGameStart.gif]]&lt;br /&gt;
 &lt;br /&gt;
And then it will suddendly fall down! (Look at above gif and watch the small countdown)&lt;br /&gt;
&lt;br /&gt;
Similiar if we use too low y-coordinate then the tree will be created underground and only &amp;quot;pop&amp;quot; above ground once the game starts!&lt;br /&gt;
&lt;br /&gt;
{{Tip|It is important to spawn features (and units) at the correct y-coordinate.}}&lt;br /&gt;
&lt;br /&gt;
===GetGroundHeight===&lt;br /&gt;
Instead of reading the ground height from the tooltip we can also use the function &amp;lt;code&amp;gt;Spring.GetGroundHeight&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function gadget:Initialize()&lt;br /&gt;
	x = 3830&lt;br /&gt;
	z = 3600&lt;br /&gt;
	y = Spring.GetGroundHeight (x,z)&lt;br /&gt;
	Spring.CreateFeature (&amp;quot;treetype0&amp;quot;, x,y,z)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Functional forest=&lt;br /&gt;
We can put our tree-spawner code into a function and call it from &amp;lt;code&amp;gt;Initialize()&amp;lt;/code&amp;gt; multiple times with different coordinates:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function PlantTree (x,z)&lt;br /&gt;
	y = Spring.GetGroundHeight (x,z)&lt;br /&gt;
	Spring.CreateFeature (&amp;quot;treetype0&amp;quot;, x,y,z)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function gadget:Initialize()&lt;br /&gt;
	PlantTree (3830,3600)&lt;br /&gt;
	PlantTree (3850,3650)&lt;br /&gt;
	PlantTree (3800,3650)&lt;br /&gt;
	PlantTree (3810,320)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
&lt;br /&gt;
[[File:TreesSpawnedOnHill.jpg]]&lt;br /&gt;
&lt;br /&gt;
{{Tip|For practice try to make a function that spawns geothermal spots! The featurename is &amp;quot;geovent&amp;quot;.}}&lt;br /&gt;
&lt;br /&gt;
=Deleting all features from map=&lt;br /&gt;
Sometimes one might want to test the spawning of features again &amp;amp; again, on a clean plate.&lt;br /&gt;
The function below deletes all features on the map:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function DestroyAllFeatures ()&lt;br /&gt;
	local features = Spring.GetAllFeatures ()&lt;br /&gt;
	for i in pairs(features) do&lt;br /&gt;
		Spring.DestroyFeature (features[i])&lt;br /&gt;
	end&lt;br /&gt;
end&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It can be called in &amp;lt;code&amp;gt;Initialize()&amp;lt;/code&amp;gt; &#039;&#039;before&#039;&#039; we spawn our features, to ensure we always test on an empty map.&lt;br /&gt;
&lt;br /&gt;
When packing the map for release, one might want to comment it out again.&lt;br /&gt;
&lt;br /&gt;
=A forest is many, many, many trees=&lt;br /&gt;
A handful of trees is often not enough for a map. Let&#039;s turn the whole bottom left corner of the map into a forest. &lt;br /&gt;
&lt;br /&gt;
But planting a whole forest by typing coordinates of many trees seems very cumbersome?&lt;br /&gt;
&lt;br /&gt;
What about randomizing the placement of the tree?&lt;br /&gt;
&lt;br /&gt;
We look up the coordinates of that area: x-coordinate we want 3500 to 4000, for z-coordinate we want 3000 to 4000.&lt;br /&gt;
&lt;br /&gt;
...and put it into a random number generator function.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
x = math.random (3500,4000)&lt;br /&gt;
z = math.random (3000,4000)&lt;br /&gt;
PlantTree (x,z)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We want to plant many trees. Instead of copy-pasting those lines 100 times, we use a loop:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function gadget:Initialize()&lt;br /&gt;
	DestroyAllFeatures ()&lt;br /&gt;
	for i=1,100 do&lt;br /&gt;
		x = math.random (3500,4000)&lt;br /&gt;
		z = math.random (3000,4000)&lt;br /&gt;
		PlantTree (x,z)&lt;br /&gt;
	end&lt;br /&gt;
end&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The result:&lt;br /&gt;
&lt;br /&gt;
[[File:TreesSpawnedRandomly.jpg]]&lt;br /&gt;
&lt;br /&gt;
{{Tip|Forests are perfect for such random placement because the excact position of an indiviual tree does not matter much.}}&lt;br /&gt;
&lt;br /&gt;
==Spawning features in patterns==&lt;br /&gt;
With a little creativity one can quickly fill the map in interessting ways.&lt;br /&gt;
&lt;br /&gt;
For example try to create a function that spawns small clusters of trees. &lt;br /&gt;
&lt;br /&gt;
Or imagine a function that spawns a big mineral crystal, surrounded by smaller rocks.&lt;br /&gt;
&lt;br /&gt;
Or imagine an ore-mining facility with pieces of ore spread around it. &lt;br /&gt;
&lt;br /&gt;
etc&lt;br /&gt;
&lt;br /&gt;
Below is some examples that are hopefully understandable without too lenghty explainations.&lt;br /&gt;
&lt;br /&gt;
==Lua rocks==&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function Rock (x,z)&lt;br /&gt;
	local featureName = &amp;quot;pdrock&amp;quot; .. math.random (1, 4)&lt;br /&gt;
	Spring.CreateFeature (featureName, x,Spring.GetGroundHeight (x,z),z, math.random (0,32000))&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function rockCircle (x,z, radius, numberOfRocks)&lt;br /&gt;
for d = 0,360, 360/numberOfRocks do&lt;br /&gt;
		local x = x + (math.sin (math.rad(d)) * radius)&lt;br /&gt;
		local z = z + (math.cos (math.rad(d)) * radius)&lt;br /&gt;
		Rock (x, z)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
Example usage: &lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;rockCircle (2000,2000, 240, 25)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
&lt;br /&gt;
[[File:CircleOfRocks.jpg]]&lt;br /&gt;
&lt;br /&gt;
*Note 1: &amp;lt;code&amp;gt;local featureName = &amp;quot;pdrock&amp;quot; .. math.random (1, 4)&amp;lt;/code&amp;gt;&lt;br /&gt;
The rock features included in map &amp;quot;DesertTriad&amp;quot; are named &amp;quot;pdrock1&amp;quot; to &amp;quot;pdrock4&amp;quot;. So we take &amp;quot;pdrock&amp;quot; and append a random number in range of 1 to 4 to that base name.&lt;br /&gt;
&lt;br /&gt;
*Note 2: The heading-parameter is used here too, randomized. The heading (rotation) of features is probally not measured 0 to 32000, but for this case that does not matter. If the number is too high it will simply &amp;quot;wrap around.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==In my maps I have seen rings of smoke through the trees...==&lt;br /&gt;
&#039;&#039;...and the voices of those who stand looking.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function TreeSpiral (x,z)&lt;br /&gt;
	for d = 0,720, 20 do&lt;br /&gt;
		local x = x + (math.sin (math.rad(d)) * d/2)&lt;br /&gt;
		local z = z + (math.cos (math.rad(d)) * d/2)&lt;br /&gt;
		PlantTree (x,z)&lt;br /&gt;
	end&lt;br /&gt;
	y = Spring.GetGroundHeight (x,z)&lt;br /&gt;
	Spring.CreateFeature (&amp;quot;geovent&amp;quot;, x,y,z)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example usage: &lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;TreeSpiral (2000,2000)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
&lt;br /&gt;
A geothermal vent in the middle of a spiral of trees.&lt;br /&gt;
&lt;br /&gt;
[[File:TreeSpiralWithGeovent.jpg]]&lt;br /&gt;
&lt;br /&gt;
=Typing so many coordinates sucks!=&lt;br /&gt;
We saw how some typing could be saved by using loops or random placement.&lt;br /&gt;
But surely there must be another way?&lt;br /&gt;
&lt;br /&gt;
We could try to save the coordinates of all features of the map into a file.&lt;br /&gt;
&lt;br /&gt;
If we wanted to do that, we would preferably save the coordinates in a way that can also be read back by another script. &lt;br /&gt;
For now that seems too difficult so we think of another way.&lt;br /&gt;
&lt;br /&gt;
* think * think * think *&lt;br /&gt;
&lt;br /&gt;
==Coordinates Helper widget==&lt;br /&gt;
Spring allows players to mark tactical locations on the map by holding ~ or ^ and clicking the mousewheel.&lt;br /&gt;
&lt;br /&gt;
That might also be useful for marking locations of features, if we can just save those coordinates?&lt;br /&gt;
&lt;br /&gt;
Let&#039;s see if we can create a small &#039;&#039;&#039;helper widget&#039;&#039;&#039; for that purpose.&lt;br /&gt;
&lt;br /&gt;
Create a file &amp;lt;code&amp;gt;LuaUI\widgets\MapMarkerCoordinatesLogger.lua&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==MapDrawCmd: 1,2,3 testing!==&lt;br /&gt;
For start let&#039;s just see if we can print the coordinates of a map marker to the console.&lt;br /&gt;
&lt;br /&gt;
We discover the callin: &amp;lt;code&amp;gt;MapDrawCmd(playerID, cmdType, px, py, pz, label)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function widget:GetInfo()&lt;br /&gt;
  return {&lt;br /&gt;
    name      = &amp;quot;MapMarkerCoordinatesLogger&amp;quot;,&lt;br /&gt;
    desc      = &amp;quot;prints map marker coordinates&amp;quot;,&lt;br /&gt;
    author    = &amp;quot;this lame tutorial or something&amp;quot;,&lt;br /&gt;
    date      = &amp;quot;9 Nov 2010&amp;quot;,&lt;br /&gt;
    license   = &amp;quot;GNU GPL, v2&amp;quot;,&lt;br /&gt;
    layer     = -5,&lt;br /&gt;
    enabled   = true,&lt;br /&gt;
  }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function widget:MapDrawCmd(playerID, cmdType, px, py, pz, label)&lt;br /&gt;
	Spring.Echo (px, py,pz)&lt;br /&gt;
end&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
&lt;br /&gt;
[[File:MapMarkerCoordinatesToChat.jpg]]&lt;br /&gt;
&lt;br /&gt;
We see that the coordinates of the markers get printed to chat. (and thus to infolog.txt, too)&lt;br /&gt;
&lt;br /&gt;
Not bad, but could be less bad.&lt;br /&gt;
&lt;br /&gt;
==Turning test into something useful==&lt;br /&gt;
&lt;br /&gt;
One obvious issue is that it does not just log placing markers but also outputs numbers when drawing lines or deleting.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s upgrade the widget so that:&lt;br /&gt;
#It only logs placing markers but not erasing or lines.&lt;br /&gt;
#instead of coordinates it outputs a whole function call like &amp;lt;code&amp;gt;PlantTree (3830,3600)&amp;lt;/code&amp;gt;&lt;br /&gt;
#writes to a file instead of chat&lt;br /&gt;
#The functionname that gets written should be changeable from within game&lt;br /&gt;
#It has a cooler name&lt;br /&gt;
&lt;br /&gt;
{{Tip|&#039;&#039;&#039;Before reading onwards: Try figure out a solution by yourself!&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) Sadly the wiki does not tell us how we know the difference between marker/lines/erasing. We must figure it out!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;MapDrawCmd(playerID, cmdType, px, py, pz, label)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The paremter &#039;&#039;cmdType&#039;&#039; looks interessting. Let&#039;s just print that one too:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;Spring.Echo (px, py,pz, cmdType)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We see that cmdType has the value &amp;quot;point&amp;quot; when placing markers and other values when doing other things.&lt;br /&gt;
&lt;br /&gt;
So if cmdType is of wrong value we just return and do nothing:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function widget:MapDrawCmd(playerID, cmdType, px, py, pz, label)&lt;br /&gt;
	if cmdType ~= &amp;quot;point&amp;quot; then return end&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2) Creating the complete function call like &amp;quot;PlantTree (3830,3600)&amp;quot; is just a matter of appending some strings:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
local functionName = &amp;quot;PlantTree&amp;quot;&lt;br /&gt;
local s = functionName .. &amp;quot; (&amp;quot; .. px ..&amp;quot;, &amp;quot; .. pz .. &amp;quot;)&amp;quot;&lt;br /&gt;
Spring.Echo (s)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that we only save the X and Z coordinates because the Y-coordinate we can later get anyway with Spring.GetGroundHeight&lt;br /&gt;
&lt;br /&gt;
3) About writing to file we can find many tutorials on web if we google something like &amp;quot;Lua write to file&amp;quot; or similiar.&lt;br /&gt;
&lt;br /&gt;
The result:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
local file = io.open(&amp;quot;myCoordinatesFile.txt&amp;quot;, &amp;quot;a&amp;quot;)&lt;br /&gt;
file:write(s)&lt;br /&gt;
file:flush()&lt;br /&gt;
file:close()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Markers can have a label text attached to them. Let&#039;s use that to allow user to change the functionname.&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;if label ~= &amp;quot;&amp;quot; then functionName = label end&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Since the widget writes points into files for features placement, we name it: &#039;&#039;&#039;Pifffp&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Complete Pifffp widget=&lt;br /&gt;
Putting everything together we get:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function widget:GetInfo()&lt;br /&gt;
  return {&lt;br /&gt;
    name      = &amp;quot;Pifffp aka MapMarkerCoordinatesLogger&amp;quot;,&lt;br /&gt;
    desc      = &amp;quot;prints Lua functions for placing featues&amp;quot;,&lt;br /&gt;
    author    = &amp;quot;this lame tutorial or something&amp;quot;,&lt;br /&gt;
    date      = &amp;quot;today&amp;quot;,&lt;br /&gt;
    license   = &amp;quot;GNU GPL, v2&amp;quot;,&lt;br /&gt;
    layer     = -5,&lt;br /&gt;
    enabled   = true,&lt;br /&gt;
  }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local functionName = &amp;quot;PlantTree&amp;quot;&lt;br /&gt;
function widget:MapDrawCmd(playerID, cmdType, px, py, pz, label)&lt;br /&gt;
	if cmdType ~= &amp;quot;point&amp;quot; then return end&lt;br /&gt;
	if label ~= &amp;quot;&amp;quot; then functionName = label end&lt;br /&gt;
	--Spring.Echo (px, py,pz, cmdType, &amp;quot;-&amp;quot;..label..&amp;quot;-&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	local s = functionName .. &amp;quot; (&amp;quot; .. px ..&amp;quot;, &amp;quot; .. pz .. &amp;quot;)&amp;quot;&lt;br /&gt;
	Spring.Echo (s)&lt;br /&gt;
	&lt;br /&gt;
	local file = io.open(&amp;quot;myCoordinatesFile.txt&amp;quot;, &amp;quot;a&amp;quot;)&lt;br /&gt;
	file:write(s .. &amp;quot;\n&amp;quot;)&lt;br /&gt;
	file:flush()&lt;br /&gt;
	file:close()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Using the Pifffp tool as a user/mapper==&lt;br /&gt;
Activate the widget in F11 list.&lt;br /&gt;
&lt;br /&gt;
Now start placing map markers. Every time you place a marker the coordinates get logged into &#039;&#039;&#039;myCoordinatesFile.txt&#039;&#039;&#039;, already formated as parameters to a function call.&lt;br /&gt;
&lt;br /&gt;
(The file should usually be written next to spring.exe)&lt;br /&gt;
&lt;br /&gt;
To change the name of the function place a marker with a label text. All folling markers will then use that text, until a new label text is used.&lt;br /&gt;
&lt;br /&gt;
Example usage:&lt;br /&gt;
&lt;br /&gt;
[[File:Pifffp_Markers.jpg]]&lt;br /&gt;
&lt;br /&gt;
Example output:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
PlantTree (1977, 3569)&lt;br /&gt;
PlantTree (1933, 3372)&lt;br /&gt;
PlantTree (1901, 3489)&lt;br /&gt;
PlantTree (1850, 3612)&lt;br /&gt;
PlantTree (2008, 3643)&lt;br /&gt;
PlantTree (2101, 3497)&lt;br /&gt;
PlantTree (2112, 3637)&lt;br /&gt;
PlantTree (2228, 3605)&lt;br /&gt;
PlantTree (2226, 3464)&lt;br /&gt;
PlantTree (2043, 3406)&lt;br /&gt;
PlantTree (2163, 3357)&lt;br /&gt;
PlantTree (2293, 3278)&lt;br /&gt;
PlantTree (2125, 3179)&lt;br /&gt;
PlantTree (1986, 3193)&lt;br /&gt;
Rock (1526, 3099)&lt;br /&gt;
Rock (1576, 3024)&lt;br /&gt;
Rock (1500, 2926)&lt;br /&gt;
Rock (1373, 3035)&lt;br /&gt;
Rock (1438, 3212)&lt;br /&gt;
Rock (1556, 3264)&lt;br /&gt;
Rock (1699, 3122)&lt;br /&gt;
Rock (1670, 2919)&lt;br /&gt;
Rock (1398, 2918)&lt;br /&gt;
Geovent (1818, 3298)&lt;br /&gt;
rockCircle (2308, 2788)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We recognize these functions from the beginning of the tutorial. &lt;br /&gt;
&lt;br /&gt;
Hopefully still have them ready in our &amp;lt;code&amp;gt;LuaRules\gadgets\MyLuaFeatureTesting.lua&amp;lt;/code&amp;gt; file so that we only need to paste the Pifffp output into &amp;lt;code&amp;gt;Initialize&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(I you are making a real map you might want to use a better filename like &amp;quot;spawnMyFeatures.lua&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
Note that for the function rockCircle we still need to fill in the parameters radius and amount of rocks like so:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
rockCircle (2308, 2788, 200, 25)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example result:&lt;br /&gt;
&lt;br /&gt;
[[File:Pifffp_ResultFeatures.jpg]]&lt;br /&gt;
&lt;br /&gt;
Now we have created ourselves a quick way to put features onto map with Lua.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Making a map? How to turn LuaRules into LuaGaia!=&lt;br /&gt;
&amp;quot;LuaRules&amp;quot; is meant for games while maps should use &amp;quot;LuaGaia&amp;quot;. {{FIXME}} maybe link to some more detailed explaination of LuaStates.&lt;br /&gt;
&lt;br /&gt;
So if you want to move the scripts from the test-mutator (or other game archive) into a map then some minor changes are needed.&lt;br /&gt;
&lt;br /&gt;
The folder structure should be like:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;LuaGaia\gadgets\MyMapGadget.lua&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Also include two &amp;quot;base files&amp;quot; like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;LuaGaia\draw.lua&amp;lt;/pre&amp;gt; with content:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;VFS.Include(&amp;quot;LuaGadgets/gadgets.lua&amp;quot;,nil, VFS.BASE)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;LuaGaia\main.lua&amp;lt;/pre&amp;gt; with content:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;VFS.Include(&amp;quot;LuaGadgets/gadgets.lua&amp;quot;,nil, VFS.BASE)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For reloading this LuaGaia Lua type: /luagaia reload&lt;br /&gt;
&lt;br /&gt;
Everything else stays the same.&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=File:TreesSpawnedRandomly.jpg&amp;diff=22139</id>
		<title>File:TreesSpawnedRandomly.jpg</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=File:TreesSpawnedRandomly.jpg&amp;diff=22139"/>
		<updated>2014-11-08T01:55:30Z</updated>

		<summary type="html">&lt;p&gt;Knorke: a rectangular area has been filled with trees as result of a Lua.
the commander is looking at the forest.
for use in Lua/mapping tutorial.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;a rectangular area has been filled with trees as result of a Lua.&lt;br /&gt;
the commander is looking at the forest.&lt;br /&gt;
for use in Lua/mapping tutorial.&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=File:TreesSpawnedOnHill.jpg&amp;diff=22138</id>
		<title>File:TreesSpawnedOnHill.jpg</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=File:TreesSpawnedOnHill.jpg&amp;diff=22138"/>
		<updated>2014-11-08T01:54:34Z</updated>

		<summary type="html">&lt;p&gt;Knorke: several trees have been spawned on a hill by a Lua.
the commander is looking at the trees or maybe just at the hill.
for use in Lua/mapping tutorial.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;several trees have been spawned on a hill by a Lua.&lt;br /&gt;
the commander is looking at the trees or maybe just at the hill.&lt;br /&gt;
for use in Lua/mapping tutorial.&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=File:TreeSpiralWithGeovent.jpg&amp;diff=22137</id>
		<title>File:TreeSpiralWithGeovent.jpg</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=File:TreeSpiralWithGeovent.jpg&amp;diff=22137"/>
		<updated>2014-11-08T01:53:42Z</updated>

		<summary type="html">&lt;p&gt;Knorke: A spiral of trees with a smoking geovent in the center was created by a Lua.
for use in Lua/mapping tutorial.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A spiral of trees with a smoking geovent in the center was created by a Lua.&lt;br /&gt;
for use in Lua/mapping tutorial.&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=File:Pifffp_ResultFeatures.jpg&amp;diff=21984</id>
		<title>File:Pifffp ResultFeatures.jpg</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=File:Pifffp_ResultFeatures.jpg&amp;diff=21984"/>
		<updated>2014-11-08T01:53:08Z</updated>

		<summary type="html">&lt;p&gt;Knorke: some features sit on the map as result of a Lua.
for use in Lua/mapping tutorial.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;some features sit on the map as result of a Lua.&lt;br /&gt;
for use in Lua/mapping tutorial.&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=File:Pifffp_Markers.jpg&amp;diff=21983</id>
		<title>File:Pifffp Markers.jpg</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=File:Pifffp_Markers.jpg&amp;diff=21983"/>
		<updated>2014-11-08T01:52:34Z</updated>

		<summary type="html">&lt;p&gt;Knorke: several markers, some with text, are used to mark coordinates where features will be created.
for use in Lua/mapping tutorial.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;several markers, some with text, are used to mark coordinates where features will be created.&lt;br /&gt;
for use in Lua/mapping tutorial.&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=File:OneTreeOnHill.jpg&amp;diff=21973</id>
		<title>File:OneTreeOnHill.jpg</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=File:OneTreeOnHill.jpg&amp;diff=21973"/>
		<updated>2014-11-08T01:51:47Z</updated>

		<summary type="html">&lt;p&gt;Knorke: one tree stands on a hill.
for use in Lua/mapping tutorial.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;one tree stands on a hill.&lt;br /&gt;
for use in Lua/mapping tutorial.&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=File:MapMarkerCoordinatesToChat.jpg&amp;diff=21902</id>
		<title>File:MapMarkerCoordinatesToChat.jpg</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=File:MapMarkerCoordinatesToChat.jpg&amp;diff=21902"/>
		<updated>2014-11-08T01:51:22Z</updated>

		<summary type="html">&lt;p&gt;Knorke: map markers and their coordinates in chat
for use in Lua/mapping tutorial.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;map markers and their coordinates in chat&lt;br /&gt;
for use in Lua/mapping tutorial.&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=File:FeaturesFallAtGameStart.gif&amp;diff=21734</id>
		<title>File:FeaturesFallAtGameStart.gif</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=File:FeaturesFallAtGameStart.gif&amp;diff=21734"/>
		<updated>2014-11-08T01:50:50Z</updated>

		<summary type="html">&lt;p&gt;Knorke: a feature floats in midair before the game starts, physics kick in, and it falls downwards.
for use in Lua/mapping tutorial.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;a feature floats in midair before the game starts, physics kick in, and it falls downwards.&lt;br /&gt;
for use in Lua/mapping tutorial.&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=File:Circle_of_Rocks.jpg&amp;diff=21614</id>
		<title>File:Circle of Rocks.jpg</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=File:Circle_of_Rocks.jpg&amp;diff=21614"/>
		<updated>2014-11-08T01:50:05Z</updated>

		<summary type="html">&lt;p&gt;Knorke: a circle of rocks features.
a commander is looking at the rocks.
for use in Lua/mapping tutorial.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;a circle of rocks features.&lt;br /&gt;
a commander is looking at the rocks.&lt;br /&gt;
for use in Lua/mapping tutorial.&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=User:Knorke/Sandbox3&amp;diff=20881</id>
		<title>User:Knorke/Sandbox3</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=User:Knorke/Sandbox3&amp;diff=20881"/>
		<updated>2014-11-08T00:58:05Z</updated>

		<summary type="html">&lt;p&gt;Knorke: LuaRules / LuaGaia&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
{{FIXME}} remove off-site links for images once uploading works again http://springrts.com/mantis/view.php?id=4612&lt;br /&gt;
&lt;br /&gt;
{{Caution|The Lua examples on this page has been tested and &#039;&#039;should&#039;&#039; work. However there is always the possibility that between copying from script into this text sometimes has been lost. If you notice something missing/wrong or something absolutely does not work then please tell in forum.}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Introduction=&lt;br /&gt;
This text talks about how to put features onto the map, using Lua.&lt;br /&gt;
&lt;br /&gt;
The text can be read in two ways:&lt;br /&gt;
*As a Lua tutorial that expands on [[Lua:Tutorial_GettingStarted]] and {{FIXME}} that other page in sandbox&lt;br /&gt;
*For mappers as way to put features onto their map. &lt;br /&gt;
**In this case you can skip some of the &amp;quot;finer details&amp;quot; and just copypaste what seems interessting.&lt;br /&gt;
&lt;br /&gt;
To follow the examples you can either...&lt;br /&gt;
* ...use your WIP map in .sdd format&lt;br /&gt;
* ...or unpack an existing map&lt;br /&gt;
* ...or use the test-mutator example from previous tutorial.&lt;br /&gt;
&lt;br /&gt;
This text will be based around the map &#039;&#039;&#039;&amp;quot;DesertTriad&amp;quot;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=Creating a feature: Spring.CreateFeature=&lt;br /&gt;
&lt;br /&gt;
Again we use our test-hill in the bottom right corner, of which we already know the coordinates:&lt;br /&gt;
&lt;br /&gt;
[[File:DesertTriadHillCoordinates.jpg]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;We want to create a feature on this hill.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Create a file: &amp;lt;code&amp;gt;LuaRules\gadgets\MyLuaFeatureTesting.lua&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
At [[Lua_SyncedCtrl#Feature_Handling]] we find the function &amp;lt;code&amp;gt;Spring.CreateFeature&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We need the parameters: &#039;&#039;featurename&#039;&#039; and &#039;&#039;x,y,z&#039;&#039; coordinates. The other parameters do not matter for now.&lt;br /&gt;
&lt;br /&gt;
The map &amp;quot;DesertTriad&amp;quot; already includes some rock features that we could use. If using the test-mutator then we can also use whatever features the game includes, usually that is mostly wrecks of destroyed units.&lt;br /&gt;
&lt;br /&gt;
Another group of features that we can use are the ones hardcoded in the engine: Geovents and trees.&lt;br /&gt;
&lt;br /&gt;
We use a feature named &amp;quot;treetype0&amp;quot;, it is a tree that comes with Spring engine.&lt;br /&gt;
&lt;br /&gt;
Putting feature name and coordinates as parameters:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Spring.CreateFeature (&amp;quot;treetype0&amp;quot;, 3830,  390, 3600)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==GameStart() or Initialize() or GamePreload() ?==&lt;br /&gt;
Where should we put the CreateFeature code?&lt;br /&gt;
&lt;br /&gt;
There are three callin functions that appear suitable:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;GameStart() Initialize() GamePreload() - can callin can I take?&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;GameStart()&amp;lt;/code&amp;gt; is called as soon as the game begins. &lt;br /&gt;
**However, it is not yet called when the players are ingame but have not readied up yet.&lt;br /&gt;
** =&amp;gt; If this callin was used then features would not appear until the game is started. Thus players could not see while choosing their start positions etc.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;GamePreload()&amp;lt;/code&amp;gt; is called as soon as soon the &amp;quot;game is ingame.&amp;quot;&lt;br /&gt;
**Features spawned in this function will be visible before readying up.&lt;br /&gt;
**However, it is only called once: Right after the game has finished loading.&lt;br /&gt;
***That means if we want to test our Lua by typing &#039;&#039;/luarules reload&#039;&#039; then it will not trigger again.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Initialize()&amp;lt;/code&amp;gt; is called when the gadget is initialized.&lt;br /&gt;
**Features spawned in this function will be visible before readying up.&lt;br /&gt;
**When typing &#039;&#039;/luarules reload&#039;&#039; the gadgets get initialized again and the function gets called again.&lt;br /&gt;
***This makes it suitable for testing.&lt;br /&gt;
&lt;br /&gt;
=&amp;gt; Both &amp;lt;code&amp;gt;Initialize()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;GamePreload()&amp;lt;/code&amp;gt; can be used to spawn features without &amp;quot;delay.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=&amp;gt; Maybe &amp;lt;code&amp;gt;GamePreload()&amp;lt;/code&amp;gt; is a bit &amp;quot;more technical correct&amp;quot; but &amp;lt;code&amp;gt;Initialize()&amp;lt;/code&amp;gt; is more suited for testing, so we use that.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=complete gadget that plants a tree=&lt;br /&gt;
Thus the gadget now looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function gadget:GetInfo()&lt;br /&gt;
  return {&lt;br /&gt;
    name      = &amp;quot;lua map stuff&amp;quot;,&lt;br /&gt;
    desc      = &amp;quot;create some features&amp;quot;,&lt;br /&gt;
    author    = &amp;quot;youe name&amp;quot;,&lt;br /&gt;
    date      = &amp;quot;the day a lua was made&amp;quot;,&lt;br /&gt;
    license   = &amp;quot;GNU GPL, v2&amp;quot;,&lt;br /&gt;
    layer     = 0,&lt;br /&gt;
    enabled   = true,&lt;br /&gt;
  }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if not gadgetHandler:IsSyncedCode() then&lt;br /&gt;
&lt;br /&gt;
function gadget:Initialize()&lt;br /&gt;
	Spring.CreateFeature (&amp;quot;treetype0&amp;quot;, 3830,  390, 3600)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
else --unsynced part below&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The result:&lt;br /&gt;
&lt;br /&gt;
[[File:OneTreeOnHill.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/onetreeonhillpcs0m.jpg]&lt;br /&gt;
&lt;br /&gt;
{{Tip|&#039;&#039;&#039;Such simple code is really all it takes to put features on a map.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If one wanted one could now replaces the featurename and coordinates and use it to populate a map. In fact some maps do just that.}}&lt;br /&gt;
&lt;br /&gt;
{{Tip|If you need to remove the tree for testing purposes, then reclaim it with the Commander or a constructor. (We will learn a better way soon)}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==If a tree falls from the sky... does it make a sound?==&lt;br /&gt;
One interessting thing is that Spring physics do not get activated until the game actually starts.&lt;br /&gt;
&lt;br /&gt;
Why is that relevant for spawning features?&lt;br /&gt;
&lt;br /&gt;
If we use a too high y-coordinate (vertical axis / height) then the tree will hover in the air until the game starts. &lt;br /&gt;
&lt;br /&gt;
[[File:FeaturesFallAtGameStart.gif]]&lt;br /&gt;
 &lt;br /&gt;
 [File:http://abload.de/img/featuresfallatgamestaaesnm.gif]&lt;br /&gt;
&lt;br /&gt;
And then it will suddendly fall down! (Look at above gif and watch the small countdown)&lt;br /&gt;
&lt;br /&gt;
Similiar if we use too low y-coordinate then the tree will be created underground and only &amp;quot;pop&amp;quot; above ground once the game starts!&lt;br /&gt;
&lt;br /&gt;
{{Tip|It is important to spawn features (and units) at the correct y-coordinate.}}&lt;br /&gt;
&lt;br /&gt;
===GetGroundHeight===&lt;br /&gt;
Instead of reading the ground height from the tooltip we can also use the function &amp;lt;code&amp;gt;Spring.GetGroundHeight&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function gadget:Initialize()&lt;br /&gt;
	x = 3830&lt;br /&gt;
	z = 3600&lt;br /&gt;
	y = Spring.GetGroundHeight (x,z)&lt;br /&gt;
	Spring.CreateFeature (&amp;quot;treetype0&amp;quot;, x,y,z)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Functional forest=&lt;br /&gt;
We can put our tree-spawner code into a function and call it from &amp;lt;code&amp;gt;Initialize()&amp;lt;/code&amp;gt; multiple times with different coordinates:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function PlantTree (x,z)&lt;br /&gt;
	y = Spring.GetGroundHeight (x,z)&lt;br /&gt;
	Spring.CreateFeature (&amp;quot;treetype0&amp;quot;, x,y,z)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function gadget:Initialize()&lt;br /&gt;
	PlantTree (3830,3600)&lt;br /&gt;
	PlantTree (3850,3650)&lt;br /&gt;
	PlantTree (3800,3650)&lt;br /&gt;
	PlantTree (3810,320)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
&lt;br /&gt;
[[File:TreesSpawnedOnHill.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/treesspawnedonhill74shj.jpg]&lt;br /&gt;
&lt;br /&gt;
{{Tip|For practice try to make a function that spawns geothermal spots! The featurename is &amp;quot;geovent&amp;quot;.}}&lt;br /&gt;
&lt;br /&gt;
=Deleting all features from map=&lt;br /&gt;
Sometimes one might want to test the spawning of features again &amp;amp; again, on a clean plate.&lt;br /&gt;
The function below deletes all features on the map:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function DestroyAllFeatures ()&lt;br /&gt;
	local features = Spring.GetAllFeatures ()&lt;br /&gt;
	for i in pairs(features) do&lt;br /&gt;
		Spring.DestroyFeature (features[i])&lt;br /&gt;
	end&lt;br /&gt;
end&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It can be called in &amp;lt;code&amp;gt;Initialize()&amp;lt;/code&amp;gt; &#039;&#039;before&#039;&#039; we spawn our features, to ensure we always test on an empty map.&lt;br /&gt;
&lt;br /&gt;
When packing the map for release, one might want to comment it out again.&lt;br /&gt;
&lt;br /&gt;
=A forest is many, many, many trees=&lt;br /&gt;
A handful of trees is often not enough for a map. Let&#039;s turn the whole bottom left corner of the map into a forest. &lt;br /&gt;
&lt;br /&gt;
But planting a whole forest by typing coordinates of many trees seems very cumbersome?&lt;br /&gt;
&lt;br /&gt;
What about randomizing the placement of the tree?&lt;br /&gt;
&lt;br /&gt;
We look up the coordinates of that area: x-coordinate we want 3500 to 4000, for z-coordinate we want 3000 to 4000.&lt;br /&gt;
&lt;br /&gt;
...and put it into a random number generator function.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
x = math.random (3500,4000)&lt;br /&gt;
z = math.random (3000,4000)&lt;br /&gt;
PlantTree (x,z)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We want to plant many trees. Instead of copy-pasting those lines 100 times, we use a loop:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function gadget:Initialize()&lt;br /&gt;
	DestroyAllFeatures ()&lt;br /&gt;
	for i=1,100 do&lt;br /&gt;
		x = math.random (3500,4000)&lt;br /&gt;
		z = math.random (3000,4000)&lt;br /&gt;
		PlantTree (x,z)&lt;br /&gt;
	end&lt;br /&gt;
end&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The result:&lt;br /&gt;
&lt;br /&gt;
[[File:TreesSpawnedRandomly.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/treesspawnedrandomlyf3snt.jpg]&lt;br /&gt;
&lt;br /&gt;
{{Tip|Forests are perfect for such random placement because the excact position of an indiviual tree does not matter much.}}&lt;br /&gt;
&lt;br /&gt;
==Spawning features in patterns==&lt;br /&gt;
With a little creativity one can quickly fill the map in interessting ways.&lt;br /&gt;
&lt;br /&gt;
For example try to create a function that spawns small clusters of trees. &lt;br /&gt;
&lt;br /&gt;
Or imagine a function that spawns a big mineral crystal, surrounded by smaller rocks.&lt;br /&gt;
&lt;br /&gt;
Or imagine an ore-mining facility with pieces of ore spread around it. &lt;br /&gt;
&lt;br /&gt;
etc&lt;br /&gt;
&lt;br /&gt;
Below is some examples that are hopefully understandable without too lenghty explainations.&lt;br /&gt;
&lt;br /&gt;
==Lua rocks==&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function Rock (x,z)&lt;br /&gt;
	local featureName = &amp;quot;pdrock&amp;quot; .. math.random (1, 4)&lt;br /&gt;
	Spring.CreateFeature (featureName, x,Spring.GetGroundHeight (x,z),z, math.random (0,32000))&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function rockCircle (x,z, radius, numberOfRocks)&lt;br /&gt;
for d = 0,360, 360/numberOfRocks do&lt;br /&gt;
		local x = x + (math.sin (math.rad(d)) * radius)&lt;br /&gt;
		local z = z + (math.cos (math.rad(d)) * radius)&lt;br /&gt;
		Rock (x, z)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
Example usage: &lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;rockCircle (2000,2000, 240, 25)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
&lt;br /&gt;
[[File:CircleOfRocks.jpg]]&lt;br /&gt;
[File:http://abload.de/img/circle_of_rockso5stt.jpg]&lt;br /&gt;
&lt;br /&gt;
*Note 1: &amp;lt;code&amp;gt;local featureName = &amp;quot;pdrock&amp;quot; .. math.random (1, 4)&amp;lt;/code&amp;gt;&lt;br /&gt;
The rock features included in map &amp;quot;DesertTriad&amp;quot; are named &amp;quot;pdrock1&amp;quot; to &amp;quot;pdrock4&amp;quot;. So we take &amp;quot;pdrock&amp;quot; and append a random number in range of 1 to 4 to that base name.&lt;br /&gt;
&lt;br /&gt;
*Note 2: The heading-parameter is used here too, randomized. The heading (rotation) of features is probally not measured 0 to 32000, but for this case that does not matter. If the number is too high it will simply &amp;quot;wrap around.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==In my maps I have seen rings of smoke through the trees...==&lt;br /&gt;
&#039;&#039;...and the voices of those who stand looking.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function TreeSpiral (x,z)&lt;br /&gt;
	for d = 0,720, 20 do&lt;br /&gt;
		local x = x + (math.sin (math.rad(d)) * d/2)&lt;br /&gt;
		local z = z + (math.cos (math.rad(d)) * d/2)&lt;br /&gt;
		PlantTree (x,z)&lt;br /&gt;
	end&lt;br /&gt;
	y = Spring.GetGroundHeight (x,z)&lt;br /&gt;
	Spring.CreateFeature (&amp;quot;geovent&amp;quot;, x,y,z)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example usage: &lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;TreeSpiral (2000,2000)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
&lt;br /&gt;
A geothermal vent in the middle of a spiral of trees.&lt;br /&gt;
&lt;br /&gt;
[[File:TreeSpiralWithGeovent.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/treespiralwithgeoventu1swc.jpg]&lt;br /&gt;
&lt;br /&gt;
=Typing so many coordinates sucks!=&lt;br /&gt;
We saw how some typing could be saved by using loops or random placement.&lt;br /&gt;
But surely there must be another way?&lt;br /&gt;
&lt;br /&gt;
We could try to save the coordinates of all features of the map into a file.&lt;br /&gt;
&lt;br /&gt;
If we wanted to do that, we would preferably save the coordinates in a way that can also be read back by another script. &lt;br /&gt;
For now that seems too difficult so we think of another way.&lt;br /&gt;
&lt;br /&gt;
* think * think * think *&lt;br /&gt;
&lt;br /&gt;
==Coordinates Helper widget==&lt;br /&gt;
Spring allows players to mark tactical locations on the map by holding ~ or ^ and clicking the mousewheel.&lt;br /&gt;
&lt;br /&gt;
That might also be useful for marking locations of features, if we can just save those coordinates?&lt;br /&gt;
&lt;br /&gt;
Let&#039;s see if we can create a small &#039;&#039;&#039;helper widget&#039;&#039;&#039; for that purpose.&lt;br /&gt;
&lt;br /&gt;
Create a file &amp;lt;code&amp;gt;LuaUI\widgets\MapMarkerCoordinatesLogger.lua&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==MapDrawCmd: 1,2,3 testing!==&lt;br /&gt;
For start let&#039;s just see if we can print the coordinates of a map marker to the console.&lt;br /&gt;
&lt;br /&gt;
We discover the callin: &amp;lt;code&amp;gt;MapDrawCmd(playerID, cmdType, px, py, pz, label)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function widget:GetInfo()&lt;br /&gt;
  return {&lt;br /&gt;
    name      = &amp;quot;MapMarkerCoordinatesLogger&amp;quot;,&lt;br /&gt;
    desc      = &amp;quot;prints map marker coordinates&amp;quot;,&lt;br /&gt;
    author    = &amp;quot;this lame tutorial or something&amp;quot;,&lt;br /&gt;
    date      = &amp;quot;9 Nov 2010&amp;quot;,&lt;br /&gt;
    license   = &amp;quot;GNU GPL, v2&amp;quot;,&lt;br /&gt;
    layer     = -5,&lt;br /&gt;
    enabled   = true,&lt;br /&gt;
  }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function widget:MapDrawCmd(playerID, cmdType, px, py, pz, label)&lt;br /&gt;
	Spring.Echo (px, py,pz)&lt;br /&gt;
end&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
&lt;br /&gt;
[[File:MapMarkerCoordinatesToChat.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/mapmarkercoordinatestnwsng.jpg]&lt;br /&gt;
&lt;br /&gt;
We see that the coordinates of the markers get printed to chat. (and thus to infolog.txt, too)&lt;br /&gt;
&lt;br /&gt;
Not bad, but could be less bad.&lt;br /&gt;
&lt;br /&gt;
==Turning test into something useful==&lt;br /&gt;
&lt;br /&gt;
One obvious issue is that it does not just log placing markers but also outputs numbers when drawing lines or deleting.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s upgrade the widget so that:&lt;br /&gt;
#It only logs placing markers but not erasing or lines.&lt;br /&gt;
#instead of coordinates it outputs a whole function call like &amp;lt;code&amp;gt;PlantTree (3830,3600)&amp;lt;/code&amp;gt;&lt;br /&gt;
#writes to a file instead of chat&lt;br /&gt;
#The functionname that gets written should be changeable from within game&lt;br /&gt;
#It has a cooler name&lt;br /&gt;
&lt;br /&gt;
{{Tip|&#039;&#039;&#039;Before reading onwards: Try figure out a solution by yourself!&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) Sadly the wiki does not tell us how we know the difference between marker/lines/erasing. We must figure it out!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;MapDrawCmd(playerID, cmdType, px, py, pz, label)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The paremter &#039;&#039;cmdType&#039;&#039; looks interessting. Let&#039;s just print that one too:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;Spring.Echo (px, py,pz, cmdType)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We see that cmdType has the value &amp;quot;point&amp;quot; when placing markers and other values when doing other things.&lt;br /&gt;
&lt;br /&gt;
So if cmdType is of wrong value we just return and do nothing:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function widget:MapDrawCmd(playerID, cmdType, px, py, pz, label)&lt;br /&gt;
	if cmdType ~= &amp;quot;point&amp;quot; then return end&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2) Creating the complete function call like &amp;quot;PlantTree (3830,3600)&amp;quot; is just a matter of appending some strings:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
local functionName = &amp;quot;PlantTree&amp;quot;&lt;br /&gt;
local s = functionName .. &amp;quot; (&amp;quot; .. px ..&amp;quot;, &amp;quot; .. pz .. &amp;quot;)&amp;quot;&lt;br /&gt;
Spring.Echo (s)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that we only save the X and Z coordinates because the Y-coordinate we can later get anyway with Spring.GetGroundHeight&lt;br /&gt;
&lt;br /&gt;
3) About writing to file we can find many tutorials on web if we google something like &amp;quot;Lua write to file&amp;quot; or similiar.&lt;br /&gt;
&lt;br /&gt;
The result:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
local file = io.open(&amp;quot;myCoordinatesFile.txt&amp;quot;, &amp;quot;a&amp;quot;)&lt;br /&gt;
file:write(s)&lt;br /&gt;
file:flush()&lt;br /&gt;
file:close()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Markers can have a label text attached to them. Let&#039;s use that to allow user to change the functionname.&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;if label ~= &amp;quot;&amp;quot; then functionName = label end&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Since the widget writes points into files for features placement, we name it: &#039;&#039;&#039;Pifffp&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Complete Pifffp widget=&lt;br /&gt;
Putting everything together we get:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function widget:GetInfo()&lt;br /&gt;
  return {&lt;br /&gt;
    name      = &amp;quot;Pifffp aka MapMarkerCoordinatesLogger&amp;quot;,&lt;br /&gt;
    desc      = &amp;quot;prints Lua functions for placing featues&amp;quot;,&lt;br /&gt;
    author    = &amp;quot;this lame tutorial or something&amp;quot;,&lt;br /&gt;
    date      = &amp;quot;today&amp;quot;,&lt;br /&gt;
    license   = &amp;quot;GNU GPL, v2&amp;quot;,&lt;br /&gt;
    layer     = -5,&lt;br /&gt;
    enabled   = true,&lt;br /&gt;
  }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local functionName = &amp;quot;PlantTree&amp;quot;&lt;br /&gt;
function widget:MapDrawCmd(playerID, cmdType, px, py, pz, label)&lt;br /&gt;
	if cmdType ~= &amp;quot;point&amp;quot; then return end&lt;br /&gt;
	if label ~= &amp;quot;&amp;quot; then functionName = label end&lt;br /&gt;
	--Spring.Echo (px, py,pz, cmdType, &amp;quot;-&amp;quot;..label..&amp;quot;-&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	local s = functionName .. &amp;quot; (&amp;quot; .. px ..&amp;quot;, &amp;quot; .. pz .. &amp;quot;)&amp;quot;&lt;br /&gt;
	Spring.Echo (s)&lt;br /&gt;
	&lt;br /&gt;
	local file = io.open(&amp;quot;myCoordinatesFile.txt&amp;quot;, &amp;quot;a&amp;quot;)&lt;br /&gt;
	file:write(s .. &amp;quot;\n&amp;quot;)&lt;br /&gt;
	file:flush()&lt;br /&gt;
	file:close()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Using the Pifffp tool as a user/mapper==&lt;br /&gt;
Activate the widget in F11 list.&lt;br /&gt;
&lt;br /&gt;
Now start placing map markers. Every time you place a marker the coordinates get logged into &#039;&#039;&#039;myCoordinatesFile.txt&#039;&#039;&#039;, already formated as parameters to a function call.&lt;br /&gt;
&lt;br /&gt;
(The file should usually be written next to spring.exe)&lt;br /&gt;
&lt;br /&gt;
To change the name of the function place a marker with a label text. All folling markers will then use that text, until a new label text is used.&lt;br /&gt;
&lt;br /&gt;
Example usage:&lt;br /&gt;
&lt;br /&gt;
[[File:Pifffp_Markers.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/pifffp_markers7lsq1.jpg]&lt;br /&gt;
&lt;br /&gt;
Example output:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
PlantTree (1977, 3569)&lt;br /&gt;
PlantTree (1933, 3372)&lt;br /&gt;
PlantTree (1901, 3489)&lt;br /&gt;
PlantTree (1850, 3612)&lt;br /&gt;
PlantTree (2008, 3643)&lt;br /&gt;
PlantTree (2101, 3497)&lt;br /&gt;
PlantTree (2112, 3637)&lt;br /&gt;
PlantTree (2228, 3605)&lt;br /&gt;
PlantTree (2226, 3464)&lt;br /&gt;
PlantTree (2043, 3406)&lt;br /&gt;
PlantTree (2163, 3357)&lt;br /&gt;
PlantTree (2293, 3278)&lt;br /&gt;
PlantTree (2125, 3179)&lt;br /&gt;
PlantTree (1986, 3193)&lt;br /&gt;
Rock (1526, 3099)&lt;br /&gt;
Rock (1576, 3024)&lt;br /&gt;
Rock (1500, 2926)&lt;br /&gt;
Rock (1373, 3035)&lt;br /&gt;
Rock (1438, 3212)&lt;br /&gt;
Rock (1556, 3264)&lt;br /&gt;
Rock (1699, 3122)&lt;br /&gt;
Rock (1670, 2919)&lt;br /&gt;
Rock (1398, 2918)&lt;br /&gt;
Geovent (1818, 3298)&lt;br /&gt;
rockCircle (2308, 2788)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We recognize these functions from the beginning of the tutorial. &lt;br /&gt;
&lt;br /&gt;
Hopefully still have them ready in our &amp;lt;code&amp;gt;LuaRules\gadgets\MyLuaFeatureTesting.lua&amp;lt;/code&amp;gt; file so that we only need to paste the Pifffp output into &amp;lt;code&amp;gt;Initialize&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(I you are making a real map you might want to use a better filename like &amp;quot;spawnMyFeatures.lua&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
Note that for the function rockCircle we still need to fill in the parameters radius and amount of rocks like so:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
rockCircle (2308, 2788, 200, 25)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example result:&lt;br /&gt;
&lt;br /&gt;
[[File:Pifffp_ResultFeatures.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/pifffp_resultfeaturesiisdi.jpg]&lt;br /&gt;
&lt;br /&gt;
Now we have created ourselves a quick way to put features onto map with Lua.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Making a map? How to turn LuaRules into LuaGaia!=&lt;br /&gt;
&amp;quot;LuaRules&amp;quot; is meant for games while maps should use &amp;quot;LuaGaia&amp;quot;. {{FIXME}} maybe link to some more detailed explaination of LuaStates.&lt;br /&gt;
&lt;br /&gt;
So if you want to move the scripts from the test-mutator (or other game archive) into a map then some minor changes are needed.&lt;br /&gt;
&lt;br /&gt;
The folder structure should be like:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;LuaGaia\gadgets\MyMapGadget.lua&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Also include two &amp;quot;base files&amp;quot; like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;LuaGaia\draw.lua&amp;lt;/pre&amp;gt; with content:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;VFS.Include(&amp;quot;LuaGadgets/gadgets.lua&amp;quot;,nil, VFS.BASE)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;LuaGaia\main.lua&amp;lt;/pre&amp;gt; with content:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;VFS.Include(&amp;quot;LuaGadgets/gadgets.lua&amp;quot;,nil, VFS.BASE)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For reloading this LuaGaia Lua type: /luagaia reload&lt;br /&gt;
&lt;br /&gt;
Everything else stays the same.&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=User:Knorke/Sandbox3&amp;diff=20880</id>
		<title>User:Knorke/Sandbox3</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=User:Knorke/Sandbox3&amp;diff=20880"/>
		<updated>2014-11-08T00:01:33Z</updated>

		<summary type="html">&lt;p&gt;Knorke: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
{{FIXME}} remove off-site links for images once uploading works again http://springrts.com/mantis/view.php?id=4612&lt;br /&gt;
&lt;br /&gt;
{{Caution|The Lua examples on this page has been tested and &#039;&#039;should&#039;&#039; work. However there is always the possibility that between copying from script into this text sometimes has been lost. If you notice something missing/wrong or something absolutely does not work then please tell in forum.}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Introduction=&lt;br /&gt;
This text talks about how to put features onto the map, using Lua.&lt;br /&gt;
&lt;br /&gt;
The text can be read in two ways:&lt;br /&gt;
*As a Lua tutorial that expands on [[Lua:Tutorial_GettingStarted]] and {{FIXME}} that other page in sandbox&lt;br /&gt;
*For mappers as way to put features onto their map. &lt;br /&gt;
**In this case you can skip some of the &amp;quot;finer details&amp;quot; and just copypaste what seems interessting.&lt;br /&gt;
&lt;br /&gt;
To follow the examples you can either...&lt;br /&gt;
* ...use your WIP map in .sdd format&lt;br /&gt;
* ...or unpack an existing map&lt;br /&gt;
* ...or use the test-mutator example from previous tutorial.&lt;br /&gt;
&lt;br /&gt;
This text will be based around the map &#039;&#039;&#039;&amp;quot;DesertTriad&amp;quot;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=Creating a feature: Spring.CreateFeature=&lt;br /&gt;
&lt;br /&gt;
Again we use our test-hill in the bottom right corner, of which we already know the coordinates:&lt;br /&gt;
&lt;br /&gt;
[[File:DesertTriadHillCoordinates.jpg]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;We want to create a feature on this hill.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Create a file: &amp;lt;code&amp;gt;LuaRules\gadgets\MyLuaFeatureTesting.lua&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
At [[Lua_SyncedCtrl#Feature_Handling]] we find the function &amp;lt;code&amp;gt;Spring.CreateFeature&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We need the parameters: &#039;&#039;featurename&#039;&#039; and &#039;&#039;x,y,z&#039;&#039; coordinates. The other parameters do not matter for now.&lt;br /&gt;
&lt;br /&gt;
The map &amp;quot;DesertTriad&amp;quot; already includes some rock features that we could use. If using the test-mutator then we can also use whatever features the game includes, usually that is mostly wrecks of destroyed units.&lt;br /&gt;
&lt;br /&gt;
Another group of features that we can use are the ones hardcoded in the engine: Geovents and trees.&lt;br /&gt;
&lt;br /&gt;
We use a feature named &amp;quot;treetype0&amp;quot;, it is a tree that comes with Spring engine.&lt;br /&gt;
&lt;br /&gt;
Putting feature name and coordinates as parameters:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Spring.CreateFeature (&amp;quot;treetype0&amp;quot;, 3830,  390, 3600)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==GameStart() or Initialize() or GamePreload() ?==&lt;br /&gt;
Where should we put the CreateFeature code?&lt;br /&gt;
&lt;br /&gt;
There are three callin functions that appear suitable:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;GameStart() Initialize() GamePreload() - can callin can I take?&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;GameStart()&amp;lt;/code&amp;gt; is called as soon as the game begins. &lt;br /&gt;
**However, it is not yet called when the players are ingame but have not readied up yet.&lt;br /&gt;
** =&amp;gt; If this callin was used then features would not appear until the game is started. Thus players could not see while choosing their start positions etc.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;GamePreload()&amp;lt;/code&amp;gt; is called as soon as soon the &amp;quot;game is ingame.&amp;quot;&lt;br /&gt;
**Features spawned in this function will be visible before readying up.&lt;br /&gt;
**However, it is only called once: Right after the game has finished loading.&lt;br /&gt;
***That means if we want to test our Lua by typing &#039;&#039;/luarules reload&#039;&#039; then it will not trigger again.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Initialize()&amp;lt;/code&amp;gt; is called when the gadget is initialized.&lt;br /&gt;
**Features spawned in this function will be visible before readying up.&lt;br /&gt;
**When typing &#039;&#039;/luarules reload&#039;&#039; the gadgets get initialized again and the function gets called again.&lt;br /&gt;
***This makes it suitable for testing.&lt;br /&gt;
&lt;br /&gt;
=&amp;gt; Both &amp;lt;code&amp;gt;Initialize()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;GamePreload()&amp;lt;/code&amp;gt; can be used to spawn features without &amp;quot;delay.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=&amp;gt; Maybe &amp;lt;code&amp;gt;GamePreload()&amp;lt;/code&amp;gt; is a bit &amp;quot;more technical correct&amp;quot; but &amp;lt;code&amp;gt;Initialize()&amp;lt;/code&amp;gt; is more suited for testing, so we use that.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=complete gadget that plants a tree=&lt;br /&gt;
Thus the gadget now looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function gadget:GetInfo()&lt;br /&gt;
  return {&lt;br /&gt;
    name      = &amp;quot;lua map stuff&amp;quot;,&lt;br /&gt;
    desc      = &amp;quot;create some features&amp;quot;,&lt;br /&gt;
    author    = &amp;quot;youe name&amp;quot;,&lt;br /&gt;
    date      = &amp;quot;the day a lua was made&amp;quot;,&lt;br /&gt;
    license   = &amp;quot;GNU GPL, v2&amp;quot;,&lt;br /&gt;
    layer     = 0,&lt;br /&gt;
    enabled   = true,&lt;br /&gt;
  }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if not gadgetHandler:IsSyncedCode() then&lt;br /&gt;
&lt;br /&gt;
function gadget:Initialize()&lt;br /&gt;
	Spring.CreateFeature (&amp;quot;treetype0&amp;quot;, 3830,  390, 3600)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
else --unsynced part below&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The result:&lt;br /&gt;
&lt;br /&gt;
[[File:OneTreeOnHill.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/onetreeonhillpcs0m.jpg]&lt;br /&gt;
&lt;br /&gt;
{{Tip|&#039;&#039;&#039;Such simple code is really all it takes to put features on a map.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If one wanted one could now replaces the featurename and coordinates and use it to populate a map. In fact some maps do just that.}}&lt;br /&gt;
&lt;br /&gt;
{{Tip|If you need to remove the tree for testing purposes, then reclaim it with the Commander or a constructor. (We will learn a better way soon)}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==If a tree falls from the sky... does it make a sound?==&lt;br /&gt;
One interessting thing is that Spring physics do not get activated until the game actually starts.&lt;br /&gt;
&lt;br /&gt;
Why is that relevant for spawning features?&lt;br /&gt;
&lt;br /&gt;
If we use a too high y-coordinate (vertical axis / height) then the tree will hover in the air until the game starts. &lt;br /&gt;
&lt;br /&gt;
[[File:FeaturesFallAtGameStart.gif]]&lt;br /&gt;
 &lt;br /&gt;
 [File:http://abload.de/img/featuresfallatgamestaaesnm.gif]&lt;br /&gt;
&lt;br /&gt;
And then it will suddendly fall down! (Look at above gif and watch the small countdown)&lt;br /&gt;
&lt;br /&gt;
Similiar if we use too low y-coordinate then the tree will be created underground and only &amp;quot;pop&amp;quot; above ground once the game starts!&lt;br /&gt;
&lt;br /&gt;
{{Tip|It is important to spawn features (and units) at the correct y-coordinate.}}&lt;br /&gt;
&lt;br /&gt;
===GetGroundHeight===&lt;br /&gt;
Instead of reading the ground height from the tooltip we can also use the function &amp;lt;code&amp;gt;Spring.GetGroundHeight&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function gadget:Initialize()&lt;br /&gt;
	x = 3830&lt;br /&gt;
	z = 3600&lt;br /&gt;
	y = Spring.GetGroundHeight (x,z)&lt;br /&gt;
	Spring.CreateFeature (&amp;quot;treetype0&amp;quot;, x,y,z)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Functional forest=&lt;br /&gt;
We can put our tree-spawner code into a function and call it from &amp;lt;code&amp;gt;Initialize()&amp;lt;/code&amp;gt; multiple times with different coordinates:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function PlantTree (x,z)&lt;br /&gt;
	y = Spring.GetGroundHeight (x,z)&lt;br /&gt;
	Spring.CreateFeature (&amp;quot;treetype0&amp;quot;, x,y,z)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function gadget:Initialize()&lt;br /&gt;
	PlantTree (3830,3600)&lt;br /&gt;
	PlantTree (3850,3650)&lt;br /&gt;
	PlantTree (3800,3650)&lt;br /&gt;
	PlantTree (3810,320)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
&lt;br /&gt;
[[File:TreesSpawnedOnHill.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/treesspawnedonhill74shj.jpg]&lt;br /&gt;
&lt;br /&gt;
{{Tip|For practice try to make a function that spawns geothermal spots! The featurename is &amp;quot;geovent&amp;quot;.}}&lt;br /&gt;
&lt;br /&gt;
=Deleting all features from map=&lt;br /&gt;
Sometimes one might want to test the spawning of features again &amp;amp; again, on a clean plate.&lt;br /&gt;
The function below deletes all features on the map:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function DestroyAllFeatures ()&lt;br /&gt;
	local features = Spring.GetAllFeatures ()&lt;br /&gt;
	for i in pairs(features) do&lt;br /&gt;
		Spring.DestroyFeature (features[i])&lt;br /&gt;
	end&lt;br /&gt;
end&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It can be called in &amp;lt;code&amp;gt;Initialize()&amp;lt;/code&amp;gt; &#039;&#039;before&#039;&#039; we spawn our features, to ensure we always test on an empty map.&lt;br /&gt;
&lt;br /&gt;
When packing the map for release, one might want to comment it out again.&lt;br /&gt;
&lt;br /&gt;
=A forest is many, many, many trees=&lt;br /&gt;
A handful of trees is often not enough for a map. Let&#039;s turn the whole bottom left corner of the map into a forest. &lt;br /&gt;
&lt;br /&gt;
But planting a whole forest by typing coordinates of many trees seems very cumbersome?&lt;br /&gt;
&lt;br /&gt;
What about randomizing the placement of the tree?&lt;br /&gt;
&lt;br /&gt;
We look up the coordinates of that area: x-coordinate we want 3500 to 4000, for z-coordinate we want 3000 to 4000.&lt;br /&gt;
&lt;br /&gt;
...and put it into a random number generator function.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
x = math.random (3500,4000)&lt;br /&gt;
z = math.random (3000,4000)&lt;br /&gt;
PlantTree (x,z)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We want to plant many trees. Instead of copy-pasting those lines 100 times, we use a loop:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function gadget:Initialize()&lt;br /&gt;
	DestroyAllFeatures ()&lt;br /&gt;
	for i=1,100 do&lt;br /&gt;
		x = math.random (3500,4000)&lt;br /&gt;
		z = math.random (3000,4000)&lt;br /&gt;
		PlantTree (x,z)&lt;br /&gt;
	end&lt;br /&gt;
end&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The result:&lt;br /&gt;
&lt;br /&gt;
[[File:TreesSpawnedRandomly.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/treesspawnedrandomlyf3snt.jpg]&lt;br /&gt;
&lt;br /&gt;
{{Tip|Forests are perfect for such random placement because the excact position of an indiviual tree does not matter much.}}&lt;br /&gt;
&lt;br /&gt;
==Spawning features in patterns==&lt;br /&gt;
With a little creativity one can quickly fill the map in interessting ways.&lt;br /&gt;
&lt;br /&gt;
For example try to create a function that spawns small clusters of trees. &lt;br /&gt;
&lt;br /&gt;
Or imagine a function that spawns a big mineral crystal, surrounded by smaller rocks.&lt;br /&gt;
&lt;br /&gt;
Or imagine an ore-mining facility with pieces of ore spread around it. &lt;br /&gt;
&lt;br /&gt;
etc&lt;br /&gt;
&lt;br /&gt;
Below is some examples that are hopefully understandable without too lenghty explainations.&lt;br /&gt;
&lt;br /&gt;
==Lua rocks==&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function Rock (x,z)&lt;br /&gt;
	local featureName = &amp;quot;pdrock&amp;quot; .. math.random (1, 4)&lt;br /&gt;
	Spring.CreateFeature (featureName, x,Spring.GetGroundHeight (x,z),z, math.random (0,32000))&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function rockCircle (x,z, radius, numberOfRocks)&lt;br /&gt;
for d = 0,360, 360/numberOfRocks do&lt;br /&gt;
		local x = x + (math.sin (math.rad(d)) * radius)&lt;br /&gt;
		local z = z + (math.cos (math.rad(d)) * radius)&lt;br /&gt;
		Rock (x, z)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
Example usage: &lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;rockCircle (2000,2000, 240, 25)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
&lt;br /&gt;
[[File:CircleOfRocks.jpg]]&lt;br /&gt;
[File:http://abload.de/img/circle_of_rockso5stt.jpg]&lt;br /&gt;
&lt;br /&gt;
*Note 1: &amp;lt;code&amp;gt;local featureName = &amp;quot;pdrock&amp;quot; .. math.random (1, 4)&amp;lt;/code&amp;gt;&lt;br /&gt;
The rock features included in map &amp;quot;DesertTriad&amp;quot; are named &amp;quot;pdrock1&amp;quot; to &amp;quot;pdrock4&amp;quot;. So we take &amp;quot;pdrock&amp;quot; and append a random number in range of 1 to 4 to that base name.&lt;br /&gt;
&lt;br /&gt;
*Note 2: The heading-parameter is used here too, randomized. The heading (rotation) of features is probally not measured 0 to 32000, but for this case that does not matter. If the number is too high it will simply &amp;quot;wrap around.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==In my maps I have seen rings of smoke through the trees...==&lt;br /&gt;
&#039;&#039;...and the voices of those who stand looking.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function TreeSpiral (x,z)&lt;br /&gt;
	for d = 0,720, 20 do&lt;br /&gt;
		local x = x + (math.sin (math.rad(d)) * d/2)&lt;br /&gt;
		local z = z + (math.cos (math.rad(d)) * d/2)&lt;br /&gt;
		PlantTree (x,z)&lt;br /&gt;
	end&lt;br /&gt;
	y = Spring.GetGroundHeight (x,z)&lt;br /&gt;
	Spring.CreateFeature (&amp;quot;geovent&amp;quot;, x,y,z)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example usage: &lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;TreeSpiral (2000,2000)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
&lt;br /&gt;
A geothermal vent in the middle of a spiral of trees.&lt;br /&gt;
&lt;br /&gt;
[[File:TreeSpiralWithGeovent.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/treespiralwithgeoventu1swc.jpg]&lt;br /&gt;
&lt;br /&gt;
=Typing so many coordinates sucks!=&lt;br /&gt;
We saw how some typing could be saved by using loops or random placement.&lt;br /&gt;
But surely there must be another way?&lt;br /&gt;
&lt;br /&gt;
We could try to save the coordinates of all features of the map into a file.&lt;br /&gt;
&lt;br /&gt;
If we wanted to do that, we would preferably save the coordinates in a way that can also be read back by another script. &lt;br /&gt;
For now that seems too difficult so we think of another way.&lt;br /&gt;
&lt;br /&gt;
* think * think * think *&lt;br /&gt;
&lt;br /&gt;
==Coordinates Helper widget==&lt;br /&gt;
Spring allows players to mark tactical locations on the map by holding ~ or ^ and clicking the mousewheel.&lt;br /&gt;
&lt;br /&gt;
That might also be useful for marking locations of features, if we can just save those coordinates?&lt;br /&gt;
&lt;br /&gt;
Let&#039;s see if we can create a small &#039;&#039;&#039;helper widget&#039;&#039;&#039; for that purpose.&lt;br /&gt;
&lt;br /&gt;
Create a file &amp;lt;code&amp;gt;LuaUI\widgets\MapMarkerCoordinatesLogger.lua&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==MapDrawCmd: 1,2,3 testing!==&lt;br /&gt;
For start let&#039;s just see if we can print the coordinates of a map marker to the console.&lt;br /&gt;
&lt;br /&gt;
We discover the callin: &amp;lt;code&amp;gt;MapDrawCmd(playerID, cmdType, px, py, pz, label)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function widget:GetInfo()&lt;br /&gt;
  return {&lt;br /&gt;
    name      = &amp;quot;MapMarkerCoordinatesLogger&amp;quot;,&lt;br /&gt;
    desc      = &amp;quot;prints map marker coordinates&amp;quot;,&lt;br /&gt;
    author    = &amp;quot;this lame tutorial or something&amp;quot;,&lt;br /&gt;
    date      = &amp;quot;9 Nov 2010&amp;quot;,&lt;br /&gt;
    license   = &amp;quot;GNU GPL, v2&amp;quot;,&lt;br /&gt;
    layer     = -5,&lt;br /&gt;
    enabled   = true,&lt;br /&gt;
  }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function widget:MapDrawCmd(playerID, cmdType, px, py, pz, label)&lt;br /&gt;
	Spring.Echo (px, py,pz)&lt;br /&gt;
end&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
&lt;br /&gt;
[[File:MapMarkerCoordinatesToChat.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/mapmarkercoordinatestnwsng.jpg]&lt;br /&gt;
&lt;br /&gt;
We see that the coordinates of the markers get printed to chat. (and thus to infolog.txt, too)&lt;br /&gt;
&lt;br /&gt;
Not bad, but could be less bad.&lt;br /&gt;
&lt;br /&gt;
==Turning test into something useful==&lt;br /&gt;
&lt;br /&gt;
One obvious issue is that it does not just log placing markers but also outputs numbers when drawing lines or deleting.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s upgrade the widget so that:&lt;br /&gt;
#It only logs placing markers but not erasing or lines.&lt;br /&gt;
#instead of coordinates it outputs a whole function call like &amp;lt;code&amp;gt;PlantTree (3830,3600)&amp;lt;/code&amp;gt;&lt;br /&gt;
#writes to a file instead of chat&lt;br /&gt;
#The functionname that gets written should be changeable from within game&lt;br /&gt;
#It has a cooler name&lt;br /&gt;
&lt;br /&gt;
{{Tip|&#039;&#039;&#039;Before reading onwards: Try figure out a solution by yourself!&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) Sadly the wiki does not tell us how we know the difference between marker/lines/erasing. We must figure it out!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;MapDrawCmd(playerID, cmdType, px, py, pz, label)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The paremter &#039;&#039;cmdType&#039;&#039; looks interessting. Let&#039;s just print that one too:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;Spring.Echo (px, py,pz, cmdType)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We see that cmdType has the value &amp;quot;point&amp;quot; when placing markers and other values when doing other things.&lt;br /&gt;
&lt;br /&gt;
So if cmdType is of wrong value we just return and do nothing:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function widget:MapDrawCmd(playerID, cmdType, px, py, pz, label)&lt;br /&gt;
	if cmdType ~= &amp;quot;point&amp;quot; then return end&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2) Creating the complete function call like &amp;quot;PlantTree (3830,3600)&amp;quot; is just a matter of appending some strings:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
local functionName = &amp;quot;PlantTree&amp;quot;&lt;br /&gt;
local s = functionName .. &amp;quot; (&amp;quot; .. px ..&amp;quot;, &amp;quot; .. pz .. &amp;quot;)&amp;quot;&lt;br /&gt;
Spring.Echo (s)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that we only save the X and Z coordinates because the Y-coordinate we can later get anyway with Spring.GetGroundHeight&lt;br /&gt;
&lt;br /&gt;
3) About writing to file we can find many tutorials on web if we google something like &amp;quot;Lua write to file&amp;quot; or similiar.&lt;br /&gt;
&lt;br /&gt;
The result:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
local file = io.open(&amp;quot;myCoordinatesFile.txt&amp;quot;, &amp;quot;a&amp;quot;)&lt;br /&gt;
file:write(s)&lt;br /&gt;
file:flush()&lt;br /&gt;
file:close()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Markers can have a label text attached to them. Let&#039;s use that to allow user to change the functionname.&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;if label ~= &amp;quot;&amp;quot; then functionName = label end&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Since the widget writes points into files for features placement, we name it: &#039;&#039;&#039;Pifffp&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Complete Pifffp widget=&lt;br /&gt;
Putting everything together we get:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function widget:GetInfo()&lt;br /&gt;
  return {&lt;br /&gt;
    name      = &amp;quot;Pifffp aka MapMarkerCoordinatesLogger&amp;quot;,&lt;br /&gt;
    desc      = &amp;quot;prints Lua functions for placing featues&amp;quot;,&lt;br /&gt;
    author    = &amp;quot;this lame tutorial or something&amp;quot;,&lt;br /&gt;
    date      = &amp;quot;today&amp;quot;,&lt;br /&gt;
    license   = &amp;quot;GNU GPL, v2&amp;quot;,&lt;br /&gt;
    layer     = -5,&lt;br /&gt;
    enabled   = true,&lt;br /&gt;
  }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local functionName = &amp;quot;PlantTree&amp;quot;&lt;br /&gt;
function widget:MapDrawCmd(playerID, cmdType, px, py, pz, label)&lt;br /&gt;
	if cmdType ~= &amp;quot;point&amp;quot; then return end&lt;br /&gt;
	if label ~= &amp;quot;&amp;quot; then functionName = label end&lt;br /&gt;
	--Spring.Echo (px, py,pz, cmdType, &amp;quot;-&amp;quot;..label..&amp;quot;-&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	local s = functionName .. &amp;quot; (&amp;quot; .. px ..&amp;quot;, &amp;quot; .. pz .. &amp;quot;)&amp;quot;&lt;br /&gt;
	Spring.Echo (s)&lt;br /&gt;
	&lt;br /&gt;
	local file = io.open(&amp;quot;myCoordinatesFile.txt&amp;quot;, &amp;quot;a&amp;quot;)&lt;br /&gt;
	file:write(s .. &amp;quot;\n&amp;quot;)&lt;br /&gt;
	file:flush()&lt;br /&gt;
	file:close()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Using the Pifffp tool as a user/mapper==&lt;br /&gt;
Activate the widget in F11 list.&lt;br /&gt;
&lt;br /&gt;
Now start placing map markers. Every time you place a marker the coordinates get logged into &#039;&#039;&#039;myCoordinatesFile.txt&#039;&#039;&#039;, already formated as parameters to a function call.&lt;br /&gt;
&lt;br /&gt;
(The file should usually be written next to spring.exe)&lt;br /&gt;
&lt;br /&gt;
To change the name of the function place a marker with a label text. All folling markers will then use that text, until a new label text is used.&lt;br /&gt;
&lt;br /&gt;
Example usage:&lt;br /&gt;
&lt;br /&gt;
[[File:Pifffp_Markers.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/pifffp_markers7lsq1.jpg]&lt;br /&gt;
&lt;br /&gt;
Example output:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
PlantTree (1977, 3569)&lt;br /&gt;
PlantTree (1933, 3372)&lt;br /&gt;
PlantTree (1901, 3489)&lt;br /&gt;
PlantTree (1850, 3612)&lt;br /&gt;
PlantTree (2008, 3643)&lt;br /&gt;
PlantTree (2101, 3497)&lt;br /&gt;
PlantTree (2112, 3637)&lt;br /&gt;
PlantTree (2228, 3605)&lt;br /&gt;
PlantTree (2226, 3464)&lt;br /&gt;
PlantTree (2043, 3406)&lt;br /&gt;
PlantTree (2163, 3357)&lt;br /&gt;
PlantTree (2293, 3278)&lt;br /&gt;
PlantTree (2125, 3179)&lt;br /&gt;
PlantTree (1986, 3193)&lt;br /&gt;
Rock (1526, 3099)&lt;br /&gt;
Rock (1576, 3024)&lt;br /&gt;
Rock (1500, 2926)&lt;br /&gt;
Rock (1373, 3035)&lt;br /&gt;
Rock (1438, 3212)&lt;br /&gt;
Rock (1556, 3264)&lt;br /&gt;
Rock (1699, 3122)&lt;br /&gt;
Rock (1670, 2919)&lt;br /&gt;
Rock (1398, 2918)&lt;br /&gt;
Geovent (1818, 3298)&lt;br /&gt;
rockCircle (2308, 2788)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We recognize these functions from the beginning of the tutorial. &lt;br /&gt;
&lt;br /&gt;
Hopefully still have them ready in our &amp;lt;code&amp;gt;LuaRules\gadgets\MyLuaFeatureTesting.lua&amp;lt;/code&amp;gt; file so that we only need to paste the Pifffp output into &amp;lt;code&amp;gt;Initialize&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(I you are making a real map you might want to use a better filename like &amp;quot;spawnMyFeatures.lua&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
Note that for the function rockCircle we still need to fill in the parameters radius and amount of rocks like so:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
rockCircle (2308, 2788, 200, 25)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example result:&lt;br /&gt;
&lt;br /&gt;
[[File:Pifffp_ResultFeatures.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/pifffp_resultfeaturesiisdi.jpg]&lt;br /&gt;
&lt;br /&gt;
Now we have created ourselves a quick way to put features onto map with Lua.&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=User:Knorke/Sandbox3&amp;diff=20879</id>
		<title>User:Knorke/Sandbox3</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=User:Knorke/Sandbox3&amp;diff=20879"/>
		<updated>2014-11-07T23:54:42Z</updated>

		<summary type="html">&lt;p&gt;Knorke: lame disclaimer&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
{{FIXME}} remove off-site links for images once uploading works again http://springrts.com/mantis/view.php?id=4612&lt;br /&gt;
&lt;br /&gt;
{{Caution|The Lua examples on this page has been tested and &#039;&#039;should&#039;&#039; work. However there is always the possibility that between copying from script into this text sometimes has been lost. If you notice something missing/wrong or something absolutely does not work then please tell in forum.}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Introduction=&lt;br /&gt;
This text talks about how to put features onto the map, using Lua.&lt;br /&gt;
&lt;br /&gt;
The text can be read in two ways:&lt;br /&gt;
*As a Lua tutorial that expands on [[Lua:Tutorial_GettingStarted]] and {{FIXME}} that other page in sandbox&lt;br /&gt;
*For mappers as way to put features onto their map. &lt;br /&gt;
**In this case you can skip some of the &amp;quot;finer details&amp;quot; and just copypaste what seems interessting.&lt;br /&gt;
&lt;br /&gt;
To follow the examples you can either...&lt;br /&gt;
* ...use your WIP map in .sdd format&lt;br /&gt;
* ...or unpack an existing map&lt;br /&gt;
* ...or use the test-mutator example from previous tutorial.&lt;br /&gt;
&lt;br /&gt;
This text will be based around the map &#039;&#039;&#039;&amp;quot;DesertTriad&amp;quot;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=Creating a feature: Spring.CreateFeature=&lt;br /&gt;
&lt;br /&gt;
Again we use our test-hill in the bottom right corner, of which we already know the coordinates:&lt;br /&gt;
&lt;br /&gt;
[[File:DesertTriadHillCoordinates.jpg]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;We want to create a feature on this hill.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Create a file: &amp;lt;code&amp;gt;LuaRules\gadgets\MyLuaFeatureTesting.lua&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
At [[Lua_SyncedCtrl#Feature_Handling]] we find the function &amp;lt;code&amp;gt;Spring.CreateFeature&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We need the parameters: &#039;&#039;featurename&#039;&#039; and &#039;&#039;x,y,z&#039;&#039; coordinates. The other parameters do not matter for now.&lt;br /&gt;
&lt;br /&gt;
The map &amp;quot;DesertTriad&amp;quot; already includes some rock features that we could use. If using the test-mutator then we can also use whatever features the game includes, usually that is mostly wrecks of destroyed units.&lt;br /&gt;
&lt;br /&gt;
Another group of features that we can use are the ones hardcoded in the engine: Geovents and trees.&lt;br /&gt;
&lt;br /&gt;
We use a feature named &amp;quot;treetype0&amp;quot;, it is a tree that comes with Spring engine.&lt;br /&gt;
&lt;br /&gt;
Putting feature name and coordinates as parameters:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Spring.CreateFeature (&amp;quot;treetype0&amp;quot;, 3830,  390, 3600)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==GameStart() or Initialize() or GamePreload() ?==&lt;br /&gt;
Where should we put the CreateFeature code?&lt;br /&gt;
&lt;br /&gt;
There are three callin functions that appear suitable:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;GameStart() Initialize() GamePreload() - can callin can I take?&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;GameStart()&amp;lt;/code&amp;gt; is called as soon as the game begins. &lt;br /&gt;
**However, it is not yet called when the players are ingame but have not readied up yet.&lt;br /&gt;
** =&amp;gt; If this callin was used then features would not appear until the game is started. Thus players could not see while choosing their start positions etc.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;GamePreload()&amp;lt;/code&amp;gt; is called as soon as soon the &amp;quot;game is ingame.&amp;quot;&lt;br /&gt;
**Features spawned in this function will be visible before readying up.&lt;br /&gt;
**However, it is only called once: Right after the game has finished loading.&lt;br /&gt;
***That means if we want to test our Lua by typing &#039;&#039;/luarules reload&#039;&#039; then it will not trigger again.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Initialize()&amp;lt;/code&amp;gt; is called when the gadget is initialized.&lt;br /&gt;
**Features spawned in this function will be visible before readying up.&lt;br /&gt;
**When typing &#039;&#039;/luarules reload&#039;&#039; the gadgets get initialized again and the function gets called again.&lt;br /&gt;
***This makes it suitable for testing.&lt;br /&gt;
&lt;br /&gt;
=&amp;gt; Both &amp;lt;code&amp;gt;Initialize()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;GamePreload()&amp;lt;/code&amp;gt; can be used to spawn features without &amp;quot;delay.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=&amp;gt; Maybe &amp;lt;code&amp;gt;GamePreload()&amp;lt;/code&amp;gt; is a bit &amp;quot;more technical correct&amp;quot; but &amp;lt;code&amp;gt;Initialize()&amp;lt;/code&amp;gt; is more suited for testing, so we use that.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=complete gadget that plants a tree=&lt;br /&gt;
Thus the gadget now looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function gadget:GetInfo()&lt;br /&gt;
  return {&lt;br /&gt;
    name      = &amp;quot;lua map stuff&amp;quot;,&lt;br /&gt;
    desc      = &amp;quot;create some features&amp;quot;,&lt;br /&gt;
    author    = &amp;quot;youe name&amp;quot;,&lt;br /&gt;
    date      = &amp;quot;the day a lua was made&amp;quot;,&lt;br /&gt;
    license   = &amp;quot;GNU GPL, v2&amp;quot;,&lt;br /&gt;
    layer     = 0,&lt;br /&gt;
    enabled   = true,&lt;br /&gt;
  }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if not gadgetHandler:IsSyncedCode() then&lt;br /&gt;
&lt;br /&gt;
function gadget:Initialize()&lt;br /&gt;
	Spring.CreateFeature (&amp;quot;treetype0&amp;quot;, 3830,  390, 3600)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
else --unsynced part below&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The result:&lt;br /&gt;
&lt;br /&gt;
[[File:OneTreeOnHill.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/onetreeonhillpcs0m.jpg]&lt;br /&gt;
&lt;br /&gt;
{{Tip|&#039;&#039;&#039;Such simple code is really all it takes to put features on a map.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If one wanted one could now replaces the featurename and coordinates and use it to populate a map. In fact some maps do just that.}}&lt;br /&gt;
&lt;br /&gt;
{{Tip|If you need to remove the tree for testing purposes, then reclaim it with the Commander or a constructor. (We will learn a better way soon)}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==If a tree falls from the sky... does it make a sound?==&lt;br /&gt;
One interessting thing is that Spring physics do not get activated until the game actually starts.&lt;br /&gt;
&lt;br /&gt;
Why is that relevant for spawning features?&lt;br /&gt;
&lt;br /&gt;
If we use a too high y-coordinate (vertical axis / height) then the tree will hover in the air until the game starts. &lt;br /&gt;
&lt;br /&gt;
[[File:FeaturesFallAtGameStart.gif]]&lt;br /&gt;
 &lt;br /&gt;
 [File:http://abload.de/img/featuresfallatgamestaaesnm.gif]&lt;br /&gt;
&lt;br /&gt;
And then it will suddendly fall down! (Look at above gif and watch the small countdown)&lt;br /&gt;
&lt;br /&gt;
Similiar if we use too low y-coordinate then the tree will be created underground and only &amp;quot;pop&amp;quot; above ground once the game starts!&lt;br /&gt;
&lt;br /&gt;
{{Tip|It is important to spawn features (and units) at the correct y-coordinate.}}&lt;br /&gt;
&lt;br /&gt;
===GetGroundHeight===&lt;br /&gt;
Instead of reading the ground height from the tooltip we can also use the function &amp;lt;code&amp;gt;Spring.GetGroundHeight&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function gadget:Initialize()&lt;br /&gt;
	x = 3830&lt;br /&gt;
	z = 3600&lt;br /&gt;
	y = Spring.GetGroundHeight (x,z)&lt;br /&gt;
	Spring.CreateFeature (&amp;quot;treetype0&amp;quot;, x,y,z)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Functional forest=&lt;br /&gt;
We can put our tree-spawner code into a function and call it from &amp;lt;code&amp;gt;Initialize()&amp;lt;/code&amp;gt; multiple times with different coordinates:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function PlantTree (x,z)&lt;br /&gt;
	y = Spring.GetGroundHeight (x,z)&lt;br /&gt;
	Spring.CreateFeature (&amp;quot;treetype0&amp;quot;, x,y,z)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function gadget:Initialize()&lt;br /&gt;
	PlantTree (3830,3600)&lt;br /&gt;
	PlantTree (3850,3650)&lt;br /&gt;
	PlantTree (3800,3650)&lt;br /&gt;
	PlantTree (3810,320)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
&lt;br /&gt;
[[File:TreesSpawnedOnHill.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/treesspawnedonhill74shj.jpg]&lt;br /&gt;
&lt;br /&gt;
{{Tip|For practice try to make a function that spawns geothermal spots! The featurename is &amp;quot;geovent&amp;quot;.}}&lt;br /&gt;
&lt;br /&gt;
=Deleting all features from map=&lt;br /&gt;
Sometimes one might want to test the spawning of features again &amp;amp; again, on a clean plate.&lt;br /&gt;
The function below deletes all features on the map:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function DestroyAllFeatures ()&lt;br /&gt;
	local features = Spring.GetAllFeatures ()&lt;br /&gt;
	for i in pairs(features) do&lt;br /&gt;
		Spring.DestroyFeature (features[i])&lt;br /&gt;
	end&lt;br /&gt;
end&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It can be called in &amp;lt;code&amp;gt;Initialize()&amp;lt;/code&amp;gt; &#039;&#039;before&#039;&#039; we spawn our features, to ensure we always test on an empty map.&lt;br /&gt;
&lt;br /&gt;
When packing the map for release, one might want to comment it out again.&lt;br /&gt;
&lt;br /&gt;
=A forest is many, many, many trees=&lt;br /&gt;
A handful of trees is often not enough for a map. Let&#039;s turn the whole bottom left corner of the map into a forest. &lt;br /&gt;
&lt;br /&gt;
But planting a whole forest by typing coordinates of many trees seems very cumbersome?&lt;br /&gt;
&lt;br /&gt;
What about randomizing the placement of the tree?&lt;br /&gt;
&lt;br /&gt;
We look up the coordinates of that area: x-coordinate we want 3500 to 4000, for z-coordinate we want 3000 to 4000.&lt;br /&gt;
&lt;br /&gt;
...and put it into a random number generator function.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
x = math.random (3500,4000)&lt;br /&gt;
z = math.random (3000,4000)&lt;br /&gt;
PlantTree (x,z)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We want to plant many trees. Instead of copy-pasting those lines 100 times, we use a loop:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function gadget:Initialize()&lt;br /&gt;
	DestroyAllFeatures ()&lt;br /&gt;
	for i=1,100 do&lt;br /&gt;
		x = math.random (3500,4000)&lt;br /&gt;
		z = math.random (3000,4000)&lt;br /&gt;
		PlantTree (x,z)&lt;br /&gt;
	end&lt;br /&gt;
end&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The result:&lt;br /&gt;
&lt;br /&gt;
[[File:TreesSpawnedRandomly.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/treesspawnedrandomlyf3snt.jpg]&lt;br /&gt;
&lt;br /&gt;
{{Tip|Forests are perfect for such random placement because the excact position of an indiviual tree does not matter much.}}&lt;br /&gt;
&lt;br /&gt;
==Spawning features in patterns==&lt;br /&gt;
With a little creativity one can quickly fill the map in interessting ways.&lt;br /&gt;
&lt;br /&gt;
For example try to create a function that spawns small clusters of trees. &lt;br /&gt;
&lt;br /&gt;
Or imagine a function that spawns a big mineral crystal, surrounded by smaller rocks.&lt;br /&gt;
&lt;br /&gt;
Or imagine an ore-mining facility with pieces of ore spread around it. &lt;br /&gt;
&lt;br /&gt;
etc&lt;br /&gt;
&lt;br /&gt;
Below is some examples that are hopefully understandable without too lenghty explainations.&lt;br /&gt;
&lt;br /&gt;
==Lua rocks==&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function Rock (x,z)&lt;br /&gt;
	local featureName = &amp;quot;pdrock&amp;quot; .. math.random (1, 4)&lt;br /&gt;
	Spring.CreateFeature (featureName, x,Spring.GetGroundHeight (x,z),z, math.random (0,32000))&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function rockCircle (x,z, radius, numberOfRocks)&lt;br /&gt;
for d = 0,360, 360/numberOfRocks do&lt;br /&gt;
		local x = x + (math.sin (math.rad(d)) * radius)&lt;br /&gt;
		local z = z + (math.cos (math.rad(d)) * radius)&lt;br /&gt;
		Rock (x, z)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
Example usage: &lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;rockCircle (2000,2000, 240, 25)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
&lt;br /&gt;
[[File:CircleOfRocks.jpg]]&lt;br /&gt;
[File:http://abload.de/img/circle_of_rockso5stt.jpg]&lt;br /&gt;
&lt;br /&gt;
*Note 1: &amp;lt;code&amp;gt;local featureName = &amp;quot;pdrock&amp;quot; .. math.random (1, 4)&amp;lt;/code&amp;gt;&lt;br /&gt;
The rock features included in map &amp;quot;DesertTriad&amp;quot; are named &amp;quot;pdrock1&amp;quot; to &amp;quot;pdrock4&amp;quot;. So we take &amp;quot;pdrock&amp;quot; and append a random number in range of 1 to 4 to that base name.&lt;br /&gt;
&lt;br /&gt;
*Note 2: The heading-parameter is used here too, randomized. The heading (rotation) of features is probally not measured 0 to 32000, but for this case that does not matter. If the number is too high it will simply &amp;quot;wrap around.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==In my maps I have seen rings of smoke through the trees...==&lt;br /&gt;
&#039;&#039;...and the voices of those who stand looking.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function TreeSpiral (x,z)&lt;br /&gt;
	for d = 0,720, 20 do&lt;br /&gt;
		local x = x + (math.sin (math.rad(d)) * d/2)&lt;br /&gt;
		local z = z + (math.cos (math.rad(d)) * d/2)&lt;br /&gt;
		PlantTree (x,z)&lt;br /&gt;
	end&lt;br /&gt;
	y = Spring.GetGroundHeight (x,z)&lt;br /&gt;
	Spring.CreateFeature (&amp;quot;geovent&amp;quot;, x,y,z)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example usage: &lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;TreeSpiral (2000,2000)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
&lt;br /&gt;
A geothermal vent in the middle of a spiral of trees.&lt;br /&gt;
&lt;br /&gt;
[[File:TreeSpiralWithGeovent.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/treespiralwithgeoventu1swc.jpg]&lt;br /&gt;
&lt;br /&gt;
=Typing so many coordinates sucks!=&lt;br /&gt;
We saw how some typing could be saved by using loops or random placement.&lt;br /&gt;
But surely there must be another way?&lt;br /&gt;
&lt;br /&gt;
We could try to save the coordinates of all features of the map into a file.&lt;br /&gt;
&lt;br /&gt;
If we wanted to do that, we would preferably save the coordinates in a way that can also be read back by another script. &lt;br /&gt;
For now that seems too difficult so we think of another way.&lt;br /&gt;
&lt;br /&gt;
* think * think * think *&lt;br /&gt;
&lt;br /&gt;
==Coordinates Helper widget==&lt;br /&gt;
Spring allows players to mark tactical locations on the map by holding ~ or ^ and clicking the mousewheel.&lt;br /&gt;
&lt;br /&gt;
That might also be useful for marking locations of features, if we can just save those coordinates?&lt;br /&gt;
&lt;br /&gt;
Let&#039;s see if we can create a small &#039;&#039;&#039;helper widget&#039;&#039;&#039; for that purpose.&lt;br /&gt;
&lt;br /&gt;
Create a file &amp;lt;code&amp;gt;LuaUI\widgets\MapMarkerCoordinatesLogger.lua&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==MapDrawCmd: 1,2,3 testing!==&lt;br /&gt;
For start let&#039;s just see if we can print the coordinates of a map marker to the console.&lt;br /&gt;
&lt;br /&gt;
We discover the callin: &amp;lt;code&amp;gt;MapDrawCmd(playerID, cmdType, px, py, pz, label)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function widget:GetInfo()&lt;br /&gt;
  return {&lt;br /&gt;
    name      = &amp;quot;MapMarkerCoordinatesLogger&amp;quot;,&lt;br /&gt;
    desc      = &amp;quot;prints map marker coordinates&amp;quot;,&lt;br /&gt;
    author    = &amp;quot;this lame tutorial or something&amp;quot;,&lt;br /&gt;
    date      = &amp;quot;9 Nov 2010&amp;quot;,&lt;br /&gt;
    license   = &amp;quot;GNU GPL, v2&amp;quot;,&lt;br /&gt;
    layer     = -5,&lt;br /&gt;
    enabled   = true,&lt;br /&gt;
  }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function widget:MapDrawCmd(playerID, cmdType, px, py, pz, label)&lt;br /&gt;
	Spring.Echo (px, py,pz)&lt;br /&gt;
end&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
&lt;br /&gt;
[[File:MapMarkerCoordinatesToChat.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/mapmarkercoordinatestnwsng.jpg]&lt;br /&gt;
&lt;br /&gt;
We see that the coordinates of the markers get printed to chat. (and thus to infolog.txt, too)&lt;br /&gt;
&lt;br /&gt;
Not bad, but could be less bad.&lt;br /&gt;
&lt;br /&gt;
==Turning test into something useful==&lt;br /&gt;
&lt;br /&gt;
One obvious issue is that it does not just log placing markers but also outputs numbers when drawing lines or deleting.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s upgrade the widget so that:&lt;br /&gt;
#It only logs placing markers but not erasing or lines.&lt;br /&gt;
#instead of coordinates it outputs a whole function call like &amp;lt;code&amp;gt;PlantTree (3830,3600)&amp;lt;/code&amp;gt;&lt;br /&gt;
#writes to a file instead of chat&lt;br /&gt;
#The functionname that gets written should be changeable from within game&lt;br /&gt;
#It has a cooler name&lt;br /&gt;
&lt;br /&gt;
{{Tip|&#039;&#039;&#039;Before reading onwards: Try figure out a solution by yourself!&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) Sadly the wiki does not tell us how we know the difference between marker/lines/erasing. We must figure it out!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;MapDrawCmd(playerID, cmdType, px, py, pz, label)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The paremter &#039;&#039;cmdType&#039;&#039; looks interessting. Let&#039;s just print that one too:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;Spring.Echo (px, py,pz, cmdType)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We see that cmdType has the value &amp;quot;point&amp;quot; when placing markers and other values when doing other things.&lt;br /&gt;
&lt;br /&gt;
So if cmdType is of wrong value we just return and do nothing:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function widget:MapDrawCmd(playerID, cmdType, px, py, pz, label)&lt;br /&gt;
	if cmdType ~= &amp;quot;point&amp;quot; then return end&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2) Creating the complete function call like &amp;quot;PlantTree (3830,3600)&amp;quot; is just a matter of appending some strings:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
local functionName = &amp;quot;PlantTree&amp;quot;&lt;br /&gt;
local s = functionName .. &amp;quot; (&amp;quot; .. px ..&amp;quot;, &amp;quot; .. pz .. &amp;quot;)&amp;quot;&lt;br /&gt;
Spring.Echo (s)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that we only save the X and Z coordinates because the Y-coordinate we can later get anyway with Spring.GetGroundHeight&lt;br /&gt;
&lt;br /&gt;
3) About writing to file we can find many tutorials on web if we google something like &amp;quot;Lua write to file&amp;quot; or similiar.&lt;br /&gt;
&lt;br /&gt;
The result:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
local file = io.open(&amp;quot;myCoordinatesFile.txt&amp;quot;, &amp;quot;a&amp;quot;)&lt;br /&gt;
file:write(s)&lt;br /&gt;
file:flush()&lt;br /&gt;
file:close()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Markers can have a label text attached to them. Let&#039;s use that to allow user to change the functionname.&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;if label ~= &amp;quot;&amp;quot; then functionName = label end&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Since the widget writes points into files for features placement, we name it: &#039;&#039;&#039;Pifffp&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Complete Pifffp widget==&lt;br /&gt;
Putting everything together we get:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function widget:GetInfo()&lt;br /&gt;
  return {&lt;br /&gt;
    name      = &amp;quot;Pifffp aka MapMarkerCoordinatesLogger&amp;quot;,&lt;br /&gt;
    desc      = &amp;quot;prints Lua functions for placing featues&amp;quot;,&lt;br /&gt;
    author    = &amp;quot;this lame tutorial or something&amp;quot;,&lt;br /&gt;
    date      = &amp;quot;today&amp;quot;,&lt;br /&gt;
    license   = &amp;quot;GNU GPL, v2&amp;quot;,&lt;br /&gt;
    layer     = -5,&lt;br /&gt;
    enabled   = true,&lt;br /&gt;
  }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local functionName = &amp;quot;PlantTree&amp;quot;&lt;br /&gt;
function widget:MapDrawCmd(playerID, cmdType, px, py, pz, label)&lt;br /&gt;
	if cmdType ~= &amp;quot;point&amp;quot; then return end&lt;br /&gt;
	if label ~= &amp;quot;&amp;quot; then functionName = label end&lt;br /&gt;
	--Spring.Echo (px, py,pz, cmdType, &amp;quot;-&amp;quot;..label..&amp;quot;-&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	local s = functionName .. &amp;quot; (&amp;quot; .. px ..&amp;quot;, &amp;quot; .. pz .. &amp;quot;)&amp;quot;&lt;br /&gt;
	Spring.Echo (s)&lt;br /&gt;
	&lt;br /&gt;
	local file = io.open(&amp;quot;myCoordinatesFile.txt&amp;quot;, &amp;quot;a&amp;quot;)&lt;br /&gt;
	file:write(s .. &amp;quot;\n&amp;quot;)&lt;br /&gt;
	file:flush()&lt;br /&gt;
	file:close()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Using the Pifffp tool as a user/mapper==&lt;br /&gt;
Activate the widget in F11 list.&lt;br /&gt;
&lt;br /&gt;
Now start placing map markers. Every time you place a marker the coordinates get logged into &#039;&#039;&#039;myCoordinatesFile.txt&#039;&#039;&#039;, already formated as parameters to a function call.&lt;br /&gt;
&lt;br /&gt;
(The file should usually be written next to spring.exe)&lt;br /&gt;
&lt;br /&gt;
To change the name of the function place a marker with a label text. All folling markers will then use that text, until a new label text is used.&lt;br /&gt;
&lt;br /&gt;
Example usage:&lt;br /&gt;
&lt;br /&gt;
[[File:Pifffp_Markers.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/pifffp_markers7lsq1.jpg]&lt;br /&gt;
&lt;br /&gt;
Example output:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
PlantTree (1977, 3569)&lt;br /&gt;
PlantTree (1933, 3372)&lt;br /&gt;
PlantTree (1901, 3489)&lt;br /&gt;
PlantTree (1850, 3612)&lt;br /&gt;
PlantTree (2008, 3643)&lt;br /&gt;
PlantTree (2101, 3497)&lt;br /&gt;
PlantTree (2112, 3637)&lt;br /&gt;
PlantTree (2228, 3605)&lt;br /&gt;
PlantTree (2226, 3464)&lt;br /&gt;
PlantTree (2043, 3406)&lt;br /&gt;
PlantTree (2163, 3357)&lt;br /&gt;
PlantTree (2293, 3278)&lt;br /&gt;
PlantTree (2125, 3179)&lt;br /&gt;
PlantTree (1986, 3193)&lt;br /&gt;
Rock (1526, 3099)&lt;br /&gt;
Rock (1576, 3024)&lt;br /&gt;
Rock (1500, 2926)&lt;br /&gt;
Rock (1373, 3035)&lt;br /&gt;
Rock (1438, 3212)&lt;br /&gt;
Rock (1556, 3264)&lt;br /&gt;
Rock (1699, 3122)&lt;br /&gt;
Rock (1670, 2919)&lt;br /&gt;
Rock (1398, 2918)&lt;br /&gt;
Geovent (1818, 3298)&lt;br /&gt;
rockCircle (2308, 2788)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We recognize these functions from the beginning of the tutorial. &lt;br /&gt;
&lt;br /&gt;
Hopefully still have them ready in our &amp;lt;code&amp;gt;LuaRules\gadgets\MyLuaFeatureTesting.lua&amp;lt;/code&amp;gt; file so that we only need to paste the Pifffp output into &amp;lt;code&amp;gt;Initialize&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(I you are making a real map you might want to use a better filename like &amp;quot;spawnMyFeatures.lua&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
Note that for the function rockCircle we still need to fill in the parameters radius and amount of rocks like so:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
rockCircle (2308, 2788, 200, 25)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example result:&lt;br /&gt;
&lt;br /&gt;
[[File:Pifffp_ResultFeatures.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/pifffp_resultfeaturesiisdi.jpg]&lt;br /&gt;
&lt;br /&gt;
Now we have created ourselves a quick way to put features onto map with Lua.&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=User:Knorke/Sandbox3&amp;diff=20878</id>
		<title>User:Knorke/Sandbox3</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=User:Knorke/Sandbox3&amp;diff=20878"/>
		<updated>2014-11-07T23:24:43Z</updated>

		<summary type="html">&lt;p&gt;Knorke: /* A forest is many, many, many trees */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{FIXME}} remove off-site links for images once uploading works again http://springrts.com/mantis/view.php?id=4612&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This text talks about how to put features onto the map, using Lua.&lt;br /&gt;
&lt;br /&gt;
The text can be read in two ways:&lt;br /&gt;
*As a Lua tutorial that expands on [[Lua:Tutorial_GettingStarted]] and {{FIXME}} that other page in sandbox&lt;br /&gt;
*For mappers as way to put features onto their map. &lt;br /&gt;
**In this case you can skip some of the &amp;quot;finer details&amp;quot; and just copypaste what seems interessting.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To follow the examples you can either...&lt;br /&gt;
* ...use your WIP map in .sdd format&lt;br /&gt;
* ...or unpack an existing map&lt;br /&gt;
* ...or use the test-mutator example from previous tutorial.&lt;br /&gt;
&lt;br /&gt;
This text will be based around the map &#039;&#039;&#039;&amp;quot;DesertTriad&amp;quot;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=Creating a feature: Spring.CreateFeature=&lt;br /&gt;
&lt;br /&gt;
Again we use our test-hill in the bottom right corner, of which we already know the coordinates:&lt;br /&gt;
&lt;br /&gt;
[[File:DesertTriadHillCoordinates.jpg]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;We want to create a feature on this hill.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Create a file: &amp;lt;code&amp;gt;LuaRules\gadgets\MyLuaFeatureTesting.lua&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
At [[Lua_SyncedCtrl#Feature_Handling]] we find the function &amp;lt;code&amp;gt;Spring.CreateFeature&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We need the parameters: &#039;&#039;featurename&#039;&#039; and &#039;&#039;x,y,z&#039;&#039; coordinates. The other parameters do not matter for now.&lt;br /&gt;
&lt;br /&gt;
The map &amp;quot;DesertTriad&amp;quot; already includes some rock features that we could use. If using the test-mutator then we can also use whatever features the game includes, usually that is mostly wrecks of destroyed units.&lt;br /&gt;
&lt;br /&gt;
Another group of features that we can use are the ones hardcoded in the engine: Geovents and trees.&lt;br /&gt;
&lt;br /&gt;
We use a feature named &amp;quot;treetype0&amp;quot;, it is a tree that comes with Spring engine.&lt;br /&gt;
&lt;br /&gt;
Putting feature name and coordinates as parameters:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Spring.CreateFeature (&amp;quot;treetype0&amp;quot;, 3830,  390, 3600)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==GameStart() or Initialize() or GamePreload() ?==&lt;br /&gt;
Where should we put the CreateFeature code?&lt;br /&gt;
&lt;br /&gt;
There are three callin functions that appear suitable:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;GameStart() Initialize() GamePreload() - can callin can I take?&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;GameStart()&amp;lt;/code&amp;gt; is called as soon as the game begins. &lt;br /&gt;
**However, it is not yet called when the players are ingame but have not readied up yet.&lt;br /&gt;
** =&amp;gt; If this callin was used then features would not appear until the game is started. Thus players could not see while choosing their start positions etc.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;GamePreload()&amp;lt;/code&amp;gt; is called as soon as soon the &amp;quot;game is ingame.&amp;quot;&lt;br /&gt;
**Features spawned in this function will be visible before readying up.&lt;br /&gt;
**However, it is only called once: Right after the game has finished loading.&lt;br /&gt;
***That means if we want to test our Lua by typing &#039;&#039;/luarules reload&#039;&#039; then it will not trigger again.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Initialize()&amp;lt;/code&amp;gt; is called when the gadget is initialized.&lt;br /&gt;
**Features spawned in this function will be visible before readying up.&lt;br /&gt;
**When typing &#039;&#039;/luarules reload&#039;&#039; the gadgets get initialized again and the function gets called again.&lt;br /&gt;
***This makes it suitable for testing.&lt;br /&gt;
&lt;br /&gt;
=&amp;gt; Both &amp;lt;code&amp;gt;Initialize()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;GamePreload()&amp;lt;/code&amp;gt; can be used to spawn features without &amp;quot;delay.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=&amp;gt; Maybe &amp;lt;code&amp;gt;GamePreload()&amp;lt;/code&amp;gt; is a bit &amp;quot;more technical correct&amp;quot; but &amp;lt;code&amp;gt;Initialize()&amp;lt;/code&amp;gt; is more suited for testing, so we use that.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=complete gadget that plants a tree=&lt;br /&gt;
Thus the gadget now looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function gadget:GetInfo()&lt;br /&gt;
  return {&lt;br /&gt;
    name      = &amp;quot;lua map stuff&amp;quot;,&lt;br /&gt;
    desc      = &amp;quot;create some features&amp;quot;,&lt;br /&gt;
    author    = &amp;quot;youe name&amp;quot;,&lt;br /&gt;
    date      = &amp;quot;the day a lua was made&amp;quot;,&lt;br /&gt;
    license   = &amp;quot;GNU GPL, v2&amp;quot;,&lt;br /&gt;
    layer     = 0,&lt;br /&gt;
    enabled   = true,&lt;br /&gt;
  }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if not gadgetHandler:IsSyncedCode() then&lt;br /&gt;
&lt;br /&gt;
function gadget:Initialize()&lt;br /&gt;
	Spring.CreateFeature (&amp;quot;treetype0&amp;quot;, 3830,  390, 3600)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
else --unsynced part below&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The result:&lt;br /&gt;
&lt;br /&gt;
[[File:OneTreeOnHill.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/onetreeonhillpcs0m.jpg]&lt;br /&gt;
&lt;br /&gt;
{{Tip|&#039;&#039;&#039;Such simple code is really all it takes to put features on a map.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If one wanted one could now replaces the featurename and coordinates and use it to populate a map. In fact some maps do just that.}}&lt;br /&gt;
&lt;br /&gt;
{{Tip|If you need to remove the tree for testing purposes, then reclaim it with the Commander or a constructor. (We will learn a better way soon)}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==If a tree falls from the sky... does it make a sound?==&lt;br /&gt;
One interessting thing is that Spring physics do not get activated until the game actually starts.&lt;br /&gt;
&lt;br /&gt;
Why is that relevant for spawning features?&lt;br /&gt;
&lt;br /&gt;
If we use a too high y-coordinate (vertical axis / height) then the tree will hover in the air until the game starts. &lt;br /&gt;
&lt;br /&gt;
[[File:FeaturesFallAtGameStart.gif]]&lt;br /&gt;
 &lt;br /&gt;
 [File:http://abload.de/img/featuresfallatgamestaaesnm.gif]&lt;br /&gt;
&lt;br /&gt;
And then it will suddendly fall down! (Look at above gif and watch the small countdown)&lt;br /&gt;
&lt;br /&gt;
Similiar if we use too low y-coordinate then the tree will be created underground and only &amp;quot;pop&amp;quot; above ground once the game starts!&lt;br /&gt;
&lt;br /&gt;
{{Tip|It is important to spawn features (and units) at the correct y-coordinate.}}&lt;br /&gt;
&lt;br /&gt;
===GetGroundHeight===&lt;br /&gt;
Instead of reading the ground height from the tooltip we can also use the function &amp;lt;code&amp;gt;Spring.GetGroundHeight&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function gadget:Initialize()&lt;br /&gt;
	x = 3830&lt;br /&gt;
	z = 3600&lt;br /&gt;
	y = Spring.GetGroundHeight (x,z)&lt;br /&gt;
	Spring.CreateFeature (&amp;quot;treetype0&amp;quot;, x,y,z)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Functional forest=&lt;br /&gt;
We can put our tree-spawner code into a function and call it from &amp;lt;code&amp;gt;Initialize()&amp;lt;/code&amp;gt; multiple times with different coordinates:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function PlantTree (x,z)&lt;br /&gt;
	y = Spring.GetGroundHeight (x,z)&lt;br /&gt;
	Spring.CreateFeature (&amp;quot;treetype0&amp;quot;, x,y,z)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function gadget:Initialize()&lt;br /&gt;
	PlantTree (3830,3600)&lt;br /&gt;
	PlantTree (3850,3650)&lt;br /&gt;
	PlantTree (3800,3650)&lt;br /&gt;
	PlantTree (3810,320)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
&lt;br /&gt;
[[File:TreesSpawnedOnHill.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/treesspawnedonhill74shj.jpg]&lt;br /&gt;
&lt;br /&gt;
{{Tip|For practice try to make a function that spawns geothermal spots! The featurename is &amp;quot;geovent&amp;quot;.}}&lt;br /&gt;
&lt;br /&gt;
=Deleting all features from map=&lt;br /&gt;
Sometimes one might want to test the spawning of features again &amp;amp; again, on a clean plate.&lt;br /&gt;
The function below deletes all features on the map:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function DestroyAllFeatures ()&lt;br /&gt;
	local features = Spring.GetAllFeatures ()&lt;br /&gt;
	for i in pairs(features) do&lt;br /&gt;
		Spring.DestroyFeature (features[i])&lt;br /&gt;
	end&lt;br /&gt;
end&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It can be called in &amp;lt;code&amp;gt;Initialize()&amp;lt;/code&amp;gt; &#039;&#039;before&#039;&#039; we spawn our features, to ensure we always test on an empty map.&lt;br /&gt;
&lt;br /&gt;
When packing the map for release, one might want to comment it out again.&lt;br /&gt;
&lt;br /&gt;
=A forest is many, many, many trees=&lt;br /&gt;
A handful of trees is often not enough for a map. Let&#039;s turn the whole bottom left corner of the map into a forest. &lt;br /&gt;
&lt;br /&gt;
But planting a whole forest by typing coordinates of many trees seems very cumbersome?&lt;br /&gt;
&lt;br /&gt;
What about randomizing the placement of the tree?&lt;br /&gt;
&lt;br /&gt;
We look up the coordinates of that area: x-coordinate we want 3500 to 4000, for z-coordinate we want 3000 to 4000.&lt;br /&gt;
&lt;br /&gt;
...and put it into a random number generator function.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
x = math.random (3500,4000)&lt;br /&gt;
z = math.random (3000,4000)&lt;br /&gt;
PlantTree (x,z)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We want to plant many trees. Instead of copy-pasting those lines 100 times, we use a loop:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function gadget:Initialize()&lt;br /&gt;
	DestroyAllFeatures ()&lt;br /&gt;
	for i=1,100 do&lt;br /&gt;
		x = math.random (3500,4000)&lt;br /&gt;
		z = math.random (3000,4000)&lt;br /&gt;
		PlantTree (x,z)&lt;br /&gt;
	end&lt;br /&gt;
end&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The result:&lt;br /&gt;
&lt;br /&gt;
[[File:TreesSpawnedRandomly.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/treesspawnedrandomlyf3snt.jpg]&lt;br /&gt;
&lt;br /&gt;
{{Tip|Forests are perfect for such random placement because the excact position of an indiviual tree does not matter much.}}&lt;br /&gt;
&lt;br /&gt;
==Spawning features in patterns==&lt;br /&gt;
With a little creativity one can quickly fill the map in interessting ways.&lt;br /&gt;
&lt;br /&gt;
For example try to create a function that spawns small clusters of trees. &lt;br /&gt;
&lt;br /&gt;
Or imagine a function that spawns a big mineral crystal, surrounded by smaller rocks.&lt;br /&gt;
&lt;br /&gt;
Or imagine an ore-mining facility with pieces of ore spread around it. &lt;br /&gt;
&lt;br /&gt;
etc&lt;br /&gt;
&lt;br /&gt;
Below is some examples that are hopefully understandable without too lenghty explainations.&lt;br /&gt;
&lt;br /&gt;
==Lua rocks==&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function Rock (x,z)&lt;br /&gt;
	local featureName = &amp;quot;pdrock&amp;quot; .. math.random (1, 4)&lt;br /&gt;
	Spring.CreateFeature (featureName, x,Spring.GetGroundHeight (x,z),z, math.random (0,32000))&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function rockCircle (x,z, radius, numberOfRocks)&lt;br /&gt;
for d = 0,360, 360/numberOfRocks do&lt;br /&gt;
		local x = x + (math.sin (math.rad(d)) * radius)&lt;br /&gt;
		local z = z + (math.cos (math.rad(d)) * radius)&lt;br /&gt;
		Rock (x, z)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
Example usage: &lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;rockCircle (2000,2000, 240, 25)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
&lt;br /&gt;
[[File:CircleOfRocks.jpg]]&lt;br /&gt;
[File:http://abload.de/img/circle_of_rockso5stt.jpg]&lt;br /&gt;
&lt;br /&gt;
*Note 1: &amp;lt;code&amp;gt;local featureName = &amp;quot;pdrock&amp;quot; .. math.random (1, 4)&amp;lt;/code&amp;gt;&lt;br /&gt;
The rock features included in map &amp;quot;DesertTriad&amp;quot; are named &amp;quot;pdrock1&amp;quot; to &amp;quot;pdrock4&amp;quot;. So we take &amp;quot;pdrock&amp;quot; and append a random number in range of 1 to 4 to that base name.&lt;br /&gt;
&lt;br /&gt;
*Note 2: The heading-parameter is used here too, randomized. The heading (rotation) of features is probally not measured 0 to 32000, but for this case that does not matter. If the number is too high it will simply &amp;quot;wrap around.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==In my maps I have seen rings of smoke through the trees...==&lt;br /&gt;
&#039;&#039;...and the voices of those who stand looking.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function TreeSpiral (x,z)&lt;br /&gt;
	for d = 0,720, 20 do&lt;br /&gt;
		local x = x + (math.sin (math.rad(d)) * d/2)&lt;br /&gt;
		local z = z + (math.cos (math.rad(d)) * d/2)&lt;br /&gt;
		PlantTree (x,z)&lt;br /&gt;
	end&lt;br /&gt;
	y = Spring.GetGroundHeight (x,z)&lt;br /&gt;
	Spring.CreateFeature (&amp;quot;geovent&amp;quot;, x,y,z)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example usage: &lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;TreeSpiral (2000,2000)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
&lt;br /&gt;
A geothermal vent in the middle of a spiral of trees.&lt;br /&gt;
&lt;br /&gt;
[[File:TreeSpiralWithGeovent.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/treespiralwithgeoventu1swc.jpg]&lt;br /&gt;
&lt;br /&gt;
=Typing so many coordinates sucks!=&lt;br /&gt;
We saw how some typing could be saved by using loops or random placement.&lt;br /&gt;
But surely there must be another way?&lt;br /&gt;
&lt;br /&gt;
We could try to save the coordinates of all features of the map into a file.&lt;br /&gt;
&lt;br /&gt;
If we wanted to do that, we would preferably save the coordinates in a way that can also be read back by another script. &lt;br /&gt;
For now that seems too difficult so we think of another way.&lt;br /&gt;
&lt;br /&gt;
* think * think * think *&lt;br /&gt;
&lt;br /&gt;
==Coordinates Helper widget==&lt;br /&gt;
Spring allows players to mark tactical locations on the map by holding ~ or ^ and clicking the mousewheel.&lt;br /&gt;
&lt;br /&gt;
That might also be useful for marking locations of features, if we can just save those coordinates?&lt;br /&gt;
&lt;br /&gt;
Let&#039;s see if we can create a small &#039;&#039;&#039;helper widget&#039;&#039;&#039; for that purpose.&lt;br /&gt;
&lt;br /&gt;
Create a file &amp;lt;code&amp;gt;LuaUI\widgets\MapMarkerCoordinatesLogger.lua&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==MapDrawCmd: 1,2,3 testing!==&lt;br /&gt;
For start let&#039;s just see if we can print the coordinates of a map marker to the console.&lt;br /&gt;
&lt;br /&gt;
We discover the callin: &amp;lt;code&amp;gt;MapDrawCmd(playerID, cmdType, px, py, pz, label)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function widget:GetInfo()&lt;br /&gt;
  return {&lt;br /&gt;
    name      = &amp;quot;MapMarkerCoordinatesLogger&amp;quot;,&lt;br /&gt;
    desc      = &amp;quot;prints map marker coordinates&amp;quot;,&lt;br /&gt;
    author    = &amp;quot;this lame tutorial or something&amp;quot;,&lt;br /&gt;
    date      = &amp;quot;9 Nov 2010&amp;quot;,&lt;br /&gt;
    license   = &amp;quot;GNU GPL, v2&amp;quot;,&lt;br /&gt;
    layer     = -5,&lt;br /&gt;
    enabled   = true,&lt;br /&gt;
  }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function widget:MapDrawCmd(playerID, cmdType, px, py, pz, label)&lt;br /&gt;
	Spring.Echo (px, py,pz)&lt;br /&gt;
end&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
&lt;br /&gt;
[[File:MapMarkerCoordinatesToChat.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/mapmarkercoordinatestnwsng.jpg]&lt;br /&gt;
&lt;br /&gt;
We see that the coordinates of the markers get printed to chat. (and thus to infolog.txt, too)&lt;br /&gt;
&lt;br /&gt;
Not bad, but could be less bad.&lt;br /&gt;
&lt;br /&gt;
==Turning test into something useful==&lt;br /&gt;
&lt;br /&gt;
One obvious issue is that it does not just log placing markers but also outputs numbers when drawing lines or deleting.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s upgrade the widget so that:&lt;br /&gt;
#It only logs placing markers but not erasing or lines.&lt;br /&gt;
#instead of coordinates it outputs a whole function call like &amp;lt;code&amp;gt;PlantTree (3830,3600)&amp;lt;/code&amp;gt;&lt;br /&gt;
#writes to a file instead of chat&lt;br /&gt;
#The functionname that gets written should be changeable from within game&lt;br /&gt;
#It has a cooler name&lt;br /&gt;
&lt;br /&gt;
{{Tip|&#039;&#039;&#039;Before reading onwards: Try figure out a solution by yourself!&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) Sadly the wiki does not tell us how we know the difference between marker/lines/erasing. We must figure it out!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;MapDrawCmd(playerID, cmdType, px, py, pz, label)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The paremter &#039;&#039;cmdType&#039;&#039; looks interessting. Let&#039;s just print that one too:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;Spring.Echo (px, py,pz, cmdType)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We see that cmdType has the value &amp;quot;point&amp;quot; when placing markers and other values when doing other things.&lt;br /&gt;
&lt;br /&gt;
So if cmdType is of wrong value we just return and do nothing:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function widget:MapDrawCmd(playerID, cmdType, px, py, pz, label)&lt;br /&gt;
	if cmdType ~= &amp;quot;point&amp;quot; then return end&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2) Creating the complete function call like &amp;quot;PlantTree (3830,3600)&amp;quot; is just a matter of appending some strings:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
local functionName = &amp;quot;PlantTree&amp;quot;&lt;br /&gt;
local s = functionName .. &amp;quot; (&amp;quot; .. px ..&amp;quot;, &amp;quot; .. pz .. &amp;quot;)&amp;quot;&lt;br /&gt;
Spring.Echo (s)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that we only save the X and Z coordinates because the Y-coordinate we can later get anyway with Spring.GetGroundHeight&lt;br /&gt;
&lt;br /&gt;
3) About writing to file we can find many tutorials on web if we google something like &amp;quot;Lua write to file&amp;quot; or similiar.&lt;br /&gt;
&lt;br /&gt;
The result:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
local file = io.open(&amp;quot;myCoordinatesFile.txt&amp;quot;, &amp;quot;a&amp;quot;)&lt;br /&gt;
file:write(s)&lt;br /&gt;
file:flush()&lt;br /&gt;
file:close()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Markers can have a label text attached to them. Let&#039;s use that to allow user to change the functionname.&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;if label ~= &amp;quot;&amp;quot; then functionName = label end&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Since the widget writes points into files for features placement, we name it: &#039;&#039;&#039;Pifffp&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Complete Pifffp widget==&lt;br /&gt;
Putting everything together we get:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function widget:GetInfo()&lt;br /&gt;
  return {&lt;br /&gt;
    name      = &amp;quot;Pifffp aka MapMarkerCoordinatesLogger&amp;quot;,&lt;br /&gt;
    desc      = &amp;quot;prints Lua functions for placing featues&amp;quot;,&lt;br /&gt;
    author    = &amp;quot;this lame tutorial or something&amp;quot;,&lt;br /&gt;
    date      = &amp;quot;today&amp;quot;,&lt;br /&gt;
    license   = &amp;quot;GNU GPL, v2&amp;quot;,&lt;br /&gt;
    layer     = -5,&lt;br /&gt;
    enabled   = true,&lt;br /&gt;
  }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local functionName = &amp;quot;PlantTree&amp;quot;&lt;br /&gt;
function widget:MapDrawCmd(playerID, cmdType, px, py, pz, label)&lt;br /&gt;
	if cmdType ~= &amp;quot;point&amp;quot; then return end&lt;br /&gt;
	if label ~= &amp;quot;&amp;quot; then functionName = label end&lt;br /&gt;
	--Spring.Echo (px, py,pz, cmdType, &amp;quot;-&amp;quot;..label..&amp;quot;-&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	local s = functionName .. &amp;quot; (&amp;quot; .. px ..&amp;quot;, &amp;quot; .. pz .. &amp;quot;)&amp;quot;&lt;br /&gt;
	Spring.Echo (s)&lt;br /&gt;
	&lt;br /&gt;
	local file = io.open(&amp;quot;myCoordinatesFile.txt&amp;quot;, &amp;quot;a&amp;quot;)&lt;br /&gt;
	file:write(s .. &amp;quot;\n&amp;quot;)&lt;br /&gt;
	file:flush()&lt;br /&gt;
	file:close()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Using the Pifffp tool as a user/mapper==&lt;br /&gt;
Activate the widget in F11 list.&lt;br /&gt;
&lt;br /&gt;
Now start placing map markers. Every time you place a marker the coordinates get logged into &#039;&#039;&#039;myCoordinatesFile.txt&#039;&#039;&#039;, already formated as parameters to a function call.&lt;br /&gt;
&lt;br /&gt;
(The file should usually be written next to spring.exe)&lt;br /&gt;
&lt;br /&gt;
To change the name of the function place a marker with a label text. All folling markers will then use that text, until a new label text is used.&lt;br /&gt;
&lt;br /&gt;
Example usage:&lt;br /&gt;
&lt;br /&gt;
[[File:Pifffp_Markers.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/pifffp_markers7lsq1.jpg]&lt;br /&gt;
&lt;br /&gt;
Example output:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
PlantTree (1977, 3569)&lt;br /&gt;
PlantTree (1933, 3372)&lt;br /&gt;
PlantTree (1901, 3489)&lt;br /&gt;
PlantTree (1850, 3612)&lt;br /&gt;
PlantTree (2008, 3643)&lt;br /&gt;
PlantTree (2101, 3497)&lt;br /&gt;
PlantTree (2112, 3637)&lt;br /&gt;
PlantTree (2228, 3605)&lt;br /&gt;
PlantTree (2226, 3464)&lt;br /&gt;
PlantTree (2043, 3406)&lt;br /&gt;
PlantTree (2163, 3357)&lt;br /&gt;
PlantTree (2293, 3278)&lt;br /&gt;
PlantTree (2125, 3179)&lt;br /&gt;
PlantTree (1986, 3193)&lt;br /&gt;
Rock (1526, 3099)&lt;br /&gt;
Rock (1576, 3024)&lt;br /&gt;
Rock (1500, 2926)&lt;br /&gt;
Rock (1373, 3035)&lt;br /&gt;
Rock (1438, 3212)&lt;br /&gt;
Rock (1556, 3264)&lt;br /&gt;
Rock (1699, 3122)&lt;br /&gt;
Rock (1670, 2919)&lt;br /&gt;
Rock (1398, 2918)&lt;br /&gt;
Geovent (1818, 3298)&lt;br /&gt;
rockCircle (2308, 2788)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We recognize these functions from the beginning of the tutorial. &lt;br /&gt;
&lt;br /&gt;
Hopefully still have them ready in our &amp;lt;code&amp;gt;LuaRules\gadgets\MyLuaFeatureTesting.lua&amp;lt;/code&amp;gt; file so that we only need to paste the Pifffp output into &amp;lt;code&amp;gt;Initialize&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(I you are making a real map you might want to use a better filename like &amp;quot;spawnMyFeatures.lua&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
Note that for the function rockCircle we still need to fill in the parameters radius and amount of rocks like so:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
rockCircle (2308, 2788, 200, 25)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example result:&lt;br /&gt;
&lt;br /&gt;
[[File:Pifffp_ResultFeatures.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/pifffp_resultfeaturesiisdi.jpg]&lt;br /&gt;
&lt;br /&gt;
Now we have created ourselves a quick way to put features onto map with Lua.&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=User:Knorke/Sandbox3&amp;diff=20877</id>
		<title>User:Knorke/Sandbox3</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=User:Knorke/Sandbox3&amp;diff=20877"/>
		<updated>2014-11-07T23:12:17Z</updated>

		<summary type="html">&lt;p&gt;Knorke: /* Deleting all features from map */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{FIXME}} remove off-site links for images once uploading works again http://springrts.com/mantis/view.php?id=4612&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This text talks about how to put features onto the map, using Lua.&lt;br /&gt;
&lt;br /&gt;
The text can be read in two ways:&lt;br /&gt;
*As a Lua tutorial that expands on [[Lua:Tutorial_GettingStarted]] and {{FIXME}} that other page in sandbox&lt;br /&gt;
*For mappers as way to put features onto their map. &lt;br /&gt;
**In this case you can skip some of the &amp;quot;finer details&amp;quot; and just copypaste what seems interessting.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To follow the examples you can either...&lt;br /&gt;
* ...use your WIP map in .sdd format&lt;br /&gt;
* ...or unpack an existing map&lt;br /&gt;
* ...or use the test-mutator example from previous tutorial.&lt;br /&gt;
&lt;br /&gt;
This text will be based around the map &#039;&#039;&#039;&amp;quot;DesertTriad&amp;quot;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=Creating a feature: Spring.CreateFeature=&lt;br /&gt;
&lt;br /&gt;
Again we use our test-hill in the bottom right corner, of which we already know the coordinates:&lt;br /&gt;
&lt;br /&gt;
[[File:DesertTriadHillCoordinates.jpg]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;We want to create a feature on this hill.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Create a file: &amp;lt;code&amp;gt;LuaRules\gadgets\MyLuaFeatureTesting.lua&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
At [[Lua_SyncedCtrl#Feature_Handling]] we find the function &amp;lt;code&amp;gt;Spring.CreateFeature&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We need the parameters: &#039;&#039;featurename&#039;&#039; and &#039;&#039;x,y,z&#039;&#039; coordinates. The other parameters do not matter for now.&lt;br /&gt;
&lt;br /&gt;
The map &amp;quot;DesertTriad&amp;quot; already includes some rock features that we could use. If using the test-mutator then we can also use whatever features the game includes, usually that is mostly wrecks of destroyed units.&lt;br /&gt;
&lt;br /&gt;
Another group of features that we can use are the ones hardcoded in the engine: Geovents and trees.&lt;br /&gt;
&lt;br /&gt;
We use a feature named &amp;quot;treetype0&amp;quot;, it is a tree that comes with Spring engine.&lt;br /&gt;
&lt;br /&gt;
Putting feature name and coordinates as parameters:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Spring.CreateFeature (&amp;quot;treetype0&amp;quot;, 3830,  390, 3600)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==GameStart() or Initialize() or GamePreload() ?==&lt;br /&gt;
Where should we put the CreateFeature code?&lt;br /&gt;
&lt;br /&gt;
There are three callin functions that appear suitable:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;GameStart() Initialize() GamePreload() - can callin can I take?&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;GameStart()&amp;lt;/code&amp;gt; is called as soon as the game begins. &lt;br /&gt;
**However, it is not yet called when the players are ingame but have not readied up yet.&lt;br /&gt;
** =&amp;gt; If this callin was used then features would not appear until the game is started. Thus players could not see while choosing their start positions etc.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;GamePreload()&amp;lt;/code&amp;gt; is called as soon as soon the &amp;quot;game is ingame.&amp;quot;&lt;br /&gt;
**Features spawned in this function will be visible before readying up.&lt;br /&gt;
**However, it is only called once: Right after the game has finished loading.&lt;br /&gt;
***That means if we want to test our Lua by typing &#039;&#039;/luarules reload&#039;&#039; then it will not trigger again.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Initialize()&amp;lt;/code&amp;gt; is called when the gadget is initialized.&lt;br /&gt;
**Features spawned in this function will be visible before readying up.&lt;br /&gt;
**When typing &#039;&#039;/luarules reload&#039;&#039; the gadgets get initialized again and the function gets called again.&lt;br /&gt;
***This makes it suitable for testing.&lt;br /&gt;
&lt;br /&gt;
=&amp;gt; Both &amp;lt;code&amp;gt;Initialize()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;GamePreload()&amp;lt;/code&amp;gt; can be used to spawn features without &amp;quot;delay.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=&amp;gt; Maybe &amp;lt;code&amp;gt;GamePreload()&amp;lt;/code&amp;gt; is a bit &amp;quot;more technical correct&amp;quot; but &amp;lt;code&amp;gt;Initialize()&amp;lt;/code&amp;gt; is more suited for testing, so we use that.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=complete gadget that plants a tree=&lt;br /&gt;
Thus the gadget now looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function gadget:GetInfo()&lt;br /&gt;
  return {&lt;br /&gt;
    name      = &amp;quot;lua map stuff&amp;quot;,&lt;br /&gt;
    desc      = &amp;quot;create some features&amp;quot;,&lt;br /&gt;
    author    = &amp;quot;youe name&amp;quot;,&lt;br /&gt;
    date      = &amp;quot;the day a lua was made&amp;quot;,&lt;br /&gt;
    license   = &amp;quot;GNU GPL, v2&amp;quot;,&lt;br /&gt;
    layer     = 0,&lt;br /&gt;
    enabled   = true,&lt;br /&gt;
  }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if not gadgetHandler:IsSyncedCode() then&lt;br /&gt;
&lt;br /&gt;
function gadget:Initialize()&lt;br /&gt;
	Spring.CreateFeature (&amp;quot;treetype0&amp;quot;, 3830,  390, 3600)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
else --unsynced part below&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The result:&lt;br /&gt;
&lt;br /&gt;
[[File:OneTreeOnHill.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/onetreeonhillpcs0m.jpg]&lt;br /&gt;
&lt;br /&gt;
{{Tip|&#039;&#039;&#039;Such simple code is really all it takes to put features on a map.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If one wanted one could now replaces the featurename and coordinates and use it to populate a map. In fact some maps do just that.}}&lt;br /&gt;
&lt;br /&gt;
{{Tip|If you need to remove the tree for testing purposes, then reclaim it with the Commander or a constructor. (We will learn a better way soon)}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==If a tree falls from the sky... does it make a sound?==&lt;br /&gt;
One interessting thing is that Spring physics do not get activated until the game actually starts.&lt;br /&gt;
&lt;br /&gt;
Why is that relevant for spawning features?&lt;br /&gt;
&lt;br /&gt;
If we use a too high y-coordinate (vertical axis / height) then the tree will hover in the air until the game starts. &lt;br /&gt;
&lt;br /&gt;
[[File:FeaturesFallAtGameStart.gif]]&lt;br /&gt;
 &lt;br /&gt;
 [File:http://abload.de/img/featuresfallatgamestaaesnm.gif]&lt;br /&gt;
&lt;br /&gt;
And then it will suddendly fall down! (Look at above gif and watch the small countdown)&lt;br /&gt;
&lt;br /&gt;
Similiar if we use too low y-coordinate then the tree will be created underground and only &amp;quot;pop&amp;quot; above ground once the game starts!&lt;br /&gt;
&lt;br /&gt;
{{Tip|It is important to spawn features (and units) at the correct y-coordinate.}}&lt;br /&gt;
&lt;br /&gt;
===GetGroundHeight===&lt;br /&gt;
Instead of reading the ground height from the tooltip we can also use the function &amp;lt;code&amp;gt;Spring.GetGroundHeight&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function gadget:Initialize()&lt;br /&gt;
	x = 3830&lt;br /&gt;
	z = 3600&lt;br /&gt;
	y = Spring.GetGroundHeight (x,z)&lt;br /&gt;
	Spring.CreateFeature (&amp;quot;treetype0&amp;quot;, x,y,z)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Functional forest=&lt;br /&gt;
We can put our tree-spawner code into a function and call it from &amp;lt;code&amp;gt;Initialize()&amp;lt;/code&amp;gt; multiple times with different coordinates:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function PlantTree (x,z)&lt;br /&gt;
	y = Spring.GetGroundHeight (x,z)&lt;br /&gt;
	Spring.CreateFeature (&amp;quot;treetype0&amp;quot;, x,y,z)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function gadget:Initialize()&lt;br /&gt;
	PlantTree (3830,3600)&lt;br /&gt;
	PlantTree (3850,3650)&lt;br /&gt;
	PlantTree (3800,3650)&lt;br /&gt;
	PlantTree (3810,320)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
&lt;br /&gt;
[[File:TreesSpawnedOnHill.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/treesspawnedonhill74shj.jpg]&lt;br /&gt;
&lt;br /&gt;
{{Tip|For practice try to make a function that spawns geothermal spots! The featurename is &amp;quot;geovent&amp;quot;.}}&lt;br /&gt;
&lt;br /&gt;
=Deleting all features from map=&lt;br /&gt;
Sometimes one might want to test the spawning of features again &amp;amp; again, on a clean plate.&lt;br /&gt;
The function below deletes all features on the map:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function DestroyAllFeatures ()&lt;br /&gt;
	local features = Spring.GetAllFeatures ()&lt;br /&gt;
	for i in pairs(features) do&lt;br /&gt;
		Spring.DestroyFeature (features[i])&lt;br /&gt;
	end&lt;br /&gt;
end&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It can be called in &amp;lt;code&amp;gt;Initialize()&amp;lt;/code&amp;gt; &#039;&#039;before&#039;&#039; we spawn our features, to ensure we always test on an empty map.&lt;br /&gt;
&lt;br /&gt;
When packing the map for release, one might want to comment it out again.&lt;br /&gt;
&lt;br /&gt;
=A forest is many, many, many trees=&lt;br /&gt;
A handful of trees is often not enough for a map. Let&#039;s turn the whole bottom left corner of the map into a forest. &lt;br /&gt;
&lt;br /&gt;
But planting a whole forest by typing coordinates of many trees seems very cumbersome?&lt;br /&gt;
&lt;br /&gt;
What about randomizing the placement of the tree?&lt;br /&gt;
&lt;br /&gt;
We look up the coordinates of that area: x-coordinate we want 3500 to 4000, for z-coordinate we want 3000 to 4000.&lt;br /&gt;
&lt;br /&gt;
...and put it into a random number generator function.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
x = math.random (3500,4000)&lt;br /&gt;
z = math.random (3000,4000)&lt;br /&gt;
PlantTree (x,z)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We want to plant many trees. Instead of copy-pasting those lines 100 times, we use a loop:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;code&amp;gt;&lt;br /&gt;
function gadget:Initialize()&lt;br /&gt;
	DestroyAllFeatures ()&lt;br /&gt;
	for i=1,100 do&lt;br /&gt;
		x = math.random (3500,4000)&lt;br /&gt;
		z = math.random (3000,4000)&lt;br /&gt;
		PlantTree (x,z)&lt;br /&gt;
	end&lt;br /&gt;
end&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The result:&lt;br /&gt;
&lt;br /&gt;
[[File:TreesSpawnedRandomly.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/treesspawnedrandomlyf3snt.jpg]&lt;br /&gt;
&lt;br /&gt;
{{Tip|Forests are perfect for such random placement because the excact position of an indiviual tree does not matter much.}}&lt;br /&gt;
&lt;br /&gt;
==Spawning features in patterns==&lt;br /&gt;
With a little creativity one can quickly fill the map in interessting ways.&lt;br /&gt;
&lt;br /&gt;
For example try to create a function that spawns small clusters of trees. &lt;br /&gt;
&lt;br /&gt;
Or imagine a function that spawns a big mineral crystal, surrounded by smaller rocks.&lt;br /&gt;
&lt;br /&gt;
Or imagine an ore-mining facility with pieces of ore spread around it. &lt;br /&gt;
&lt;br /&gt;
etc&lt;br /&gt;
&lt;br /&gt;
Below is some examples that are hopefully understandable without too lenghty explainations.&lt;br /&gt;
&lt;br /&gt;
==Lua rocks==&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function Rock (x,z)&lt;br /&gt;
	local featureName = &amp;quot;pdrock&amp;quot; .. math.random (1, 4)&lt;br /&gt;
	Spring.CreateFeature (featureName, x,Spring.GetGroundHeight (x,z),z, math.random (0,32000))&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function rockCircle (x,z, radius, numberOfRocks)&lt;br /&gt;
for d = 0,360, 360/numberOfRocks do&lt;br /&gt;
		local x = x + (math.sin (math.rad(d)) * radius)&lt;br /&gt;
		local z = z + (math.cos (math.rad(d)) * radius)&lt;br /&gt;
		Rock (x, z)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
Example usage: &lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;rockCircle (2000,2000, 240, 25)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
&lt;br /&gt;
[[File:CircleOfRocks.jpg]]&lt;br /&gt;
[File:http://abload.de/img/circle_of_rockso5stt.jpg]&lt;br /&gt;
&lt;br /&gt;
*Note 1: &amp;lt;code&amp;gt;local featureName = &amp;quot;pdrock&amp;quot; .. math.random (1, 4)&amp;lt;/code&amp;gt;&lt;br /&gt;
The rock features included in map &amp;quot;DesertTriad&amp;quot; are named &amp;quot;pdrock1&amp;quot; to &amp;quot;pdrock4&amp;quot;. So we take &amp;quot;pdrock&amp;quot; and append a random number in range of 1 to 4 to that base name.&lt;br /&gt;
&lt;br /&gt;
*Note 2: The heading-parameter is used here too, randomized. The heading (rotation) of features is probally not measured 0 to 32000, but for this case that does not matter. If the number is too high it will simply &amp;quot;wrap around.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==In my maps I have seen rings of smoke through the trees...==&lt;br /&gt;
&#039;&#039;...and the voices of those who stand looking.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function TreeSpiral (x,z)&lt;br /&gt;
	for d = 0,720, 20 do&lt;br /&gt;
		local x = x + (math.sin (math.rad(d)) * d/2)&lt;br /&gt;
		local z = z + (math.cos (math.rad(d)) * d/2)&lt;br /&gt;
		PlantTree (x,z)&lt;br /&gt;
	end&lt;br /&gt;
	y = Spring.GetGroundHeight (x,z)&lt;br /&gt;
	Spring.CreateFeature (&amp;quot;geovent&amp;quot;, x,y,z)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example usage: &lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;code&amp;gt;TreeSpiral (2000,2000)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
&lt;br /&gt;
A geothermal vent in the middle of a spiral of trees.&lt;br /&gt;
&lt;br /&gt;
[[File:TreeSpiralWithGeovent.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/treespiralwithgeoventu1swc.jpg]&lt;br /&gt;
&lt;br /&gt;
=Typing so many coordinates sucks!=&lt;br /&gt;
We saw how some typing could be saved by using loops or random placement.&lt;br /&gt;
But surely there must be another way?&lt;br /&gt;
&lt;br /&gt;
We could try to save the coordinates of all features of the map into a file.&lt;br /&gt;
&lt;br /&gt;
If we wanted to do that, we would preferably save the coordinates in a way that can also be read back by another script. &lt;br /&gt;
For now that seems too difficult so we think of another way.&lt;br /&gt;
&lt;br /&gt;
* think * think * think *&lt;br /&gt;
&lt;br /&gt;
==Coordinates Helper widget==&lt;br /&gt;
Spring allows players to mark tactical locations on the map by holding ~ or ^ and clicking the mousewheel.&lt;br /&gt;
&lt;br /&gt;
That might also be useful for marking locations of features, if we can just save those coordinates?&lt;br /&gt;
&lt;br /&gt;
Let&#039;s see if we can create a small &#039;&#039;&#039;helper widget&#039;&#039;&#039; for that purpose.&lt;br /&gt;
&lt;br /&gt;
Create a file &amp;lt;code&amp;gt;LuaUI\widgets\MapMarkerCoordinatesLogger.lua&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==MapDrawCmd: 1,2,3 testing!==&lt;br /&gt;
For start let&#039;s just see if we can print the coordinates of a map marker to the console.&lt;br /&gt;
&lt;br /&gt;
We discover the callin: &amp;lt;code&amp;gt;MapDrawCmd(playerID, cmdType, px, py, pz, label)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function widget:GetInfo()&lt;br /&gt;
  return {&lt;br /&gt;
    name      = &amp;quot;MapMarkerCoordinatesLogger&amp;quot;,&lt;br /&gt;
    desc      = &amp;quot;prints map marker coordinates&amp;quot;,&lt;br /&gt;
    author    = &amp;quot;this lame tutorial or something&amp;quot;,&lt;br /&gt;
    date      = &amp;quot;9 Nov 2010&amp;quot;,&lt;br /&gt;
    license   = &amp;quot;GNU GPL, v2&amp;quot;,&lt;br /&gt;
    layer     = -5,&lt;br /&gt;
    enabled   = true,&lt;br /&gt;
  }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function widget:MapDrawCmd(playerID, cmdType, px, py, pz, label)&lt;br /&gt;
	Spring.Echo (px, py,pz)&lt;br /&gt;
end&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
&lt;br /&gt;
[[File:MapMarkerCoordinatesToChat.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/mapmarkercoordinatestnwsng.jpg]&lt;br /&gt;
&lt;br /&gt;
We see that the coordinates of the markers get printed to chat. (and thus to infolog.txt, too)&lt;br /&gt;
&lt;br /&gt;
Not bad, but could be less bad.&lt;br /&gt;
&lt;br /&gt;
==Turning test into something useful==&lt;br /&gt;
&lt;br /&gt;
One obvious issue is that it does not just log placing markers but also outputs numbers when drawing lines or deleting.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s upgrade the widget so that:&lt;br /&gt;
#It only logs placing markers but not erasing or lines.&lt;br /&gt;
#instead of coordinates it outputs a whole function call like &amp;lt;code&amp;gt;PlantTree (3830,3600)&amp;lt;/code&amp;gt;&lt;br /&gt;
#writes to a file instead of chat&lt;br /&gt;
#The functionname that gets written should be changeable from within game&lt;br /&gt;
#It has a cooler name&lt;br /&gt;
&lt;br /&gt;
{{Tip|&#039;&#039;&#039;Before reading onwards: Try figure out a solution by yourself!&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) Sadly the wiki does not tell us how we know the difference between marker/lines/erasing. We must figure it out!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;MapDrawCmd(playerID, cmdType, px, py, pz, label)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The paremter &#039;&#039;cmdType&#039;&#039; looks interessting. Let&#039;s just print that one too:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;Spring.Echo (px, py,pz, cmdType)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We see that cmdType has the value &amp;quot;point&amp;quot; when placing markers and other values when doing other things.&lt;br /&gt;
&lt;br /&gt;
So if cmdType is of wrong value we just return and do nothing:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function widget:MapDrawCmd(playerID, cmdType, px, py, pz, label)&lt;br /&gt;
	if cmdType ~= &amp;quot;point&amp;quot; then return end&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2) Creating the complete function call like &amp;quot;PlantTree (3830,3600)&amp;quot; is just a matter of appending some strings:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
local functionName = &amp;quot;PlantTree&amp;quot;&lt;br /&gt;
local s = functionName .. &amp;quot; (&amp;quot; .. px ..&amp;quot;, &amp;quot; .. pz .. &amp;quot;)&amp;quot;&lt;br /&gt;
Spring.Echo (s)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that we only save the X and Z coordinates because the Y-coordinate we can later get anyway with Spring.GetGroundHeight&lt;br /&gt;
&lt;br /&gt;
3) About writing to file we can find many tutorials on web if we google something like &amp;quot;Lua write to file&amp;quot; or similiar.&lt;br /&gt;
&lt;br /&gt;
The result:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
local file = io.open(&amp;quot;myCoordinatesFile.txt&amp;quot;, &amp;quot;a&amp;quot;)&lt;br /&gt;
file:write(s)&lt;br /&gt;
file:flush()&lt;br /&gt;
file:close()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Markers can have a label text attached to them. Let&#039;s use that to allow user to change the functionname.&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;if label ~= &amp;quot;&amp;quot; then functionName = label end&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Since the widget writes points into files for features placement, we name it: &#039;&#039;&#039;Pifffp&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Complete Pifffp widget==&lt;br /&gt;
Putting everything together we get:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function widget:GetInfo()&lt;br /&gt;
  return {&lt;br /&gt;
    name      = &amp;quot;Pifffp aka MapMarkerCoordinatesLogger&amp;quot;,&lt;br /&gt;
    desc      = &amp;quot;prints Lua functions for placing featues&amp;quot;,&lt;br /&gt;
    author    = &amp;quot;this lame tutorial or something&amp;quot;,&lt;br /&gt;
    date      = &amp;quot;today&amp;quot;,&lt;br /&gt;
    license   = &amp;quot;GNU GPL, v2&amp;quot;,&lt;br /&gt;
    layer     = -5,&lt;br /&gt;
    enabled   = true,&lt;br /&gt;
  }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local functionName = &amp;quot;PlantTree&amp;quot;&lt;br /&gt;
function widget:MapDrawCmd(playerID, cmdType, px, py, pz, label)&lt;br /&gt;
	if cmdType ~= &amp;quot;point&amp;quot; then return end&lt;br /&gt;
	if label ~= &amp;quot;&amp;quot; then functionName = label end&lt;br /&gt;
	--Spring.Echo (px, py,pz, cmdType, &amp;quot;-&amp;quot;..label..&amp;quot;-&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	local s = functionName .. &amp;quot; (&amp;quot; .. px ..&amp;quot;, &amp;quot; .. pz .. &amp;quot;)&amp;quot;&lt;br /&gt;
	Spring.Echo (s)&lt;br /&gt;
	&lt;br /&gt;
	local file = io.open(&amp;quot;myCoordinatesFile.txt&amp;quot;, &amp;quot;a&amp;quot;)&lt;br /&gt;
	file:write(s .. &amp;quot;\n&amp;quot;)&lt;br /&gt;
	file:flush()&lt;br /&gt;
	file:close()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Using the Pifffp tool as a user/mapper==&lt;br /&gt;
Activate the widget in F11 list.&lt;br /&gt;
&lt;br /&gt;
Now start placing map markers. Every time you place a marker the coordinates get logged into &#039;&#039;&#039;myCoordinatesFile.txt&#039;&#039;&#039;, already formated as parameters to a function call.&lt;br /&gt;
&lt;br /&gt;
(The file should usually be written next to spring.exe)&lt;br /&gt;
&lt;br /&gt;
To change the name of the function place a marker with a label text. All folling markers will then use that text, until a new label text is used.&lt;br /&gt;
&lt;br /&gt;
Example usage:&lt;br /&gt;
&lt;br /&gt;
[[File:Pifffp_Markers.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/pifffp_markers7lsq1.jpg]&lt;br /&gt;
&lt;br /&gt;
Example output:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
PlantTree (1977, 3569)&lt;br /&gt;
PlantTree (1933, 3372)&lt;br /&gt;
PlantTree (1901, 3489)&lt;br /&gt;
PlantTree (1850, 3612)&lt;br /&gt;
PlantTree (2008, 3643)&lt;br /&gt;
PlantTree (2101, 3497)&lt;br /&gt;
PlantTree (2112, 3637)&lt;br /&gt;
PlantTree (2228, 3605)&lt;br /&gt;
PlantTree (2226, 3464)&lt;br /&gt;
PlantTree (2043, 3406)&lt;br /&gt;
PlantTree (2163, 3357)&lt;br /&gt;
PlantTree (2293, 3278)&lt;br /&gt;
PlantTree (2125, 3179)&lt;br /&gt;
PlantTree (1986, 3193)&lt;br /&gt;
Rock (1526, 3099)&lt;br /&gt;
Rock (1576, 3024)&lt;br /&gt;
Rock (1500, 2926)&lt;br /&gt;
Rock (1373, 3035)&lt;br /&gt;
Rock (1438, 3212)&lt;br /&gt;
Rock (1556, 3264)&lt;br /&gt;
Rock (1699, 3122)&lt;br /&gt;
Rock (1670, 2919)&lt;br /&gt;
Rock (1398, 2918)&lt;br /&gt;
Geovent (1818, 3298)&lt;br /&gt;
rockCircle (2308, 2788)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We recognize these functions from the beginning of the tutorial. &lt;br /&gt;
&lt;br /&gt;
Hopefully still have them ready in our &amp;lt;code&amp;gt;LuaRules\gadgets\MyLuaFeatureTesting.lua&amp;lt;/code&amp;gt; file so that we only need to paste the Pifffp output into &amp;lt;code&amp;gt;Initialize&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(I you are making a real map you might want to use a better filename like &amp;quot;spawnMyFeatures.lua&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
Note that for the function rockCircle we still need to fill in the parameters radius and amount of rocks like so:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
rockCircle (2308, 2788, 200, 25)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example result:&lt;br /&gt;
&lt;br /&gt;
[[File:Pifffp_ResultFeatures.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/pifffp_resultfeaturesiisdi.jpg]&lt;br /&gt;
&lt;br /&gt;
Now we have created ourselves a quick way to put features onto map with Lua.&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=User:Knorke/Sandbox3&amp;diff=20876</id>
		<title>User:Knorke/Sandbox3</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=User:Knorke/Sandbox3&amp;diff=20876"/>
		<updated>2014-11-07T23:10:57Z</updated>

		<summary type="html">&lt;p&gt;Knorke: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{FIXME}} remove off-site links for images once uploading works again http://springrts.com/mantis/view.php?id=4612&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This text talks about how to put features onto the map, using Lua.&lt;br /&gt;
&lt;br /&gt;
The text can be read in two ways:&lt;br /&gt;
*As a Lua tutorial that expands on [[Lua:Tutorial_GettingStarted]] and {{FIXME}} that other page in sandbox&lt;br /&gt;
*For mappers as way to put features onto their map. &lt;br /&gt;
**In this case you can skip some of the &amp;quot;finer details&amp;quot; and just copypaste what seems interessting.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To follow the examples you can either...&lt;br /&gt;
* ...use your WIP map in .sdd format&lt;br /&gt;
* ...or unpack an existing map&lt;br /&gt;
* ...or use the test-mutator example from previous tutorial.&lt;br /&gt;
&lt;br /&gt;
This text will be based around the map &#039;&#039;&#039;&amp;quot;DesertTriad&amp;quot;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=Creating a feature: Spring.CreateFeature=&lt;br /&gt;
&lt;br /&gt;
Again we use our test-hill in the bottom right corner, of which we already know the coordinates:&lt;br /&gt;
&lt;br /&gt;
[[File:DesertTriadHillCoordinates.jpg]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;We want to create a feature on this hill.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Create a file: &amp;lt;code&amp;gt;LuaRules\gadgets\MyLuaFeatureTesting.lua&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
At [[Lua_SyncedCtrl#Feature_Handling]] we find the function &amp;lt;code&amp;gt;Spring.CreateFeature&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We need the parameters: &#039;&#039;featurename&#039;&#039; and &#039;&#039;x,y,z&#039;&#039; coordinates. The other parameters do not matter for now.&lt;br /&gt;
&lt;br /&gt;
The map &amp;quot;DesertTriad&amp;quot; already includes some rock features that we could use. If using the test-mutator then we can also use whatever features the game includes, usually that is mostly wrecks of destroyed units.&lt;br /&gt;
&lt;br /&gt;
Another group of features that we can use are the ones hardcoded in the engine: Geovents and trees.&lt;br /&gt;
&lt;br /&gt;
We use a feature named &amp;quot;treetype0&amp;quot;, it is a tree that comes with Spring engine.&lt;br /&gt;
&lt;br /&gt;
Putting feature name and coordinates as parameters:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Spring.CreateFeature (&amp;quot;treetype0&amp;quot;, 3830,  390, 3600)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==GameStart() or Initialize() or GamePreload() ?==&lt;br /&gt;
Where should we put the CreateFeature code?&lt;br /&gt;
&lt;br /&gt;
There are three callin functions that appear suitable:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;GameStart() Initialize() GamePreload() - can callin can I take?&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;GameStart()&amp;lt;/code&amp;gt; is called as soon as the game begins. &lt;br /&gt;
**However, it is not yet called when the players are ingame but have not readied up yet.&lt;br /&gt;
** =&amp;gt; If this callin was used then features would not appear until the game is started. Thus players could not see while choosing their start positions etc.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;GamePreload()&amp;lt;/code&amp;gt; is called as soon as soon the &amp;quot;game is ingame.&amp;quot;&lt;br /&gt;
**Features spawned in this function will be visible before readying up.&lt;br /&gt;
**However, it is only called once: Right after the game has finished loading.&lt;br /&gt;
***That means if we want to test our Lua by typing &#039;&#039;/luarules reload&#039;&#039; then it will not trigger again.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Initialize()&amp;lt;/code&amp;gt; is called when the gadget is initialized.&lt;br /&gt;
**Features spawned in this function will be visible before readying up.&lt;br /&gt;
**When typing &#039;&#039;/luarules reload&#039;&#039; the gadgets get initialized again and the function gets called again.&lt;br /&gt;
***This makes it suitable for testing.&lt;br /&gt;
&lt;br /&gt;
=&amp;gt; Both &amp;lt;code&amp;gt;Initialize()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;GamePreload()&amp;lt;/code&amp;gt; can be used to spawn features without &amp;quot;delay.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=&amp;gt; Maybe &amp;lt;code&amp;gt;GamePreload()&amp;lt;/code&amp;gt; is a bit &amp;quot;more technical correct&amp;quot; but &amp;lt;code&amp;gt;Initialize()&amp;lt;/code&amp;gt; is more suited for testing, so we use that.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=complete gadget that plants a tree=&lt;br /&gt;
Thus the gadget now looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function gadget:GetInfo()&lt;br /&gt;
  return {&lt;br /&gt;
    name      = &amp;quot;lua map stuff&amp;quot;,&lt;br /&gt;
    desc      = &amp;quot;create some features&amp;quot;,&lt;br /&gt;
    author    = &amp;quot;youe name&amp;quot;,&lt;br /&gt;
    date      = &amp;quot;the day a lua was made&amp;quot;,&lt;br /&gt;
    license   = &amp;quot;GNU GPL, v2&amp;quot;,&lt;br /&gt;
    layer     = 0,&lt;br /&gt;
    enabled   = true,&lt;br /&gt;
  }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if not gadgetHandler:IsSyncedCode() then&lt;br /&gt;
&lt;br /&gt;
function gadget:Initialize()&lt;br /&gt;
	Spring.CreateFeature (&amp;quot;treetype0&amp;quot;, 3830,  390, 3600)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
else --unsynced part below&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The result:&lt;br /&gt;
&lt;br /&gt;
[[File:OneTreeOnHill.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/onetreeonhillpcs0m.jpg]&lt;br /&gt;
&lt;br /&gt;
{{Tip|&#039;&#039;&#039;Such simple code is really all it takes to put features on a map.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If one wanted one could now replaces the featurename and coordinates and use it to populate a map. In fact some maps do just that.}}&lt;br /&gt;
&lt;br /&gt;
{{Tip|If you need to remove the tree for testing purposes, then reclaim it with the Commander or a constructor. (We will learn a better way soon)}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==If a tree falls from the sky... does it make a sound?==&lt;br /&gt;
One interessting thing is that Spring physics do not get activated until the game actually starts.&lt;br /&gt;
&lt;br /&gt;
Why is that relevant for spawning features?&lt;br /&gt;
&lt;br /&gt;
If we use a too high y-coordinate (vertical axis / height) then the tree will hover in the air until the game starts. &lt;br /&gt;
&lt;br /&gt;
[[File:FeaturesFallAtGameStart.gif]]&lt;br /&gt;
 &lt;br /&gt;
 [File:http://abload.de/img/featuresfallatgamestaaesnm.gif]&lt;br /&gt;
&lt;br /&gt;
And then it will suddendly fall down! (Look at above gif and watch the small countdown)&lt;br /&gt;
&lt;br /&gt;
Similiar if we use too low y-coordinate then the tree will be created underground and only &amp;quot;pop&amp;quot; above ground once the game starts!&lt;br /&gt;
&lt;br /&gt;
{{Tip|It is important to spawn features (and units) at the correct y-coordinate.}}&lt;br /&gt;
&lt;br /&gt;
===GetGroundHeight===&lt;br /&gt;
Instead of reading the ground height from the tooltip we can also use the function &amp;lt;code&amp;gt;Spring.GetGroundHeight&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function gadget:Initialize()&lt;br /&gt;
	x = 3830&lt;br /&gt;
	z = 3600&lt;br /&gt;
	y = Spring.GetGroundHeight (x,z)&lt;br /&gt;
	Spring.CreateFeature (&amp;quot;treetype0&amp;quot;, x,y,z)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Functional forest=&lt;br /&gt;
We can put our tree-spawner code into a function and call it from &amp;lt;code&amp;gt;Initialize()&amp;lt;/code&amp;gt; multiple times with different coordinates:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function PlantTree (x,z)&lt;br /&gt;
	y = Spring.GetGroundHeight (x,z)&lt;br /&gt;
	Spring.CreateFeature (&amp;quot;treetype0&amp;quot;, x,y,z)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function gadget:Initialize()&lt;br /&gt;
	PlantTree (3830,3600)&lt;br /&gt;
	PlantTree (3850,3650)&lt;br /&gt;
	PlantTree (3800,3650)&lt;br /&gt;
	PlantTree (3810,320)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
&lt;br /&gt;
[[File:TreesSpawnedOnHill.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/treesspawnedonhill74shj.jpg]&lt;br /&gt;
&lt;br /&gt;
{{Tip|For practice try to make a function that spawns geothermal spots! The featurename is &amp;quot;geovent&amp;quot;.}}&lt;br /&gt;
&lt;br /&gt;
=Deleting all features from map=&lt;br /&gt;
Sometimes one might want to test the spawning of features again &amp;amp; again, on a clean plate.&lt;br /&gt;
The function below deletes all features on the map:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function DestroyAllFeatures ()&lt;br /&gt;
	local features = Spring.GetAllFeatures ()&lt;br /&gt;
	for i in pairs(features) do&lt;br /&gt;
		Spring.DestroyFeature (features[i])&lt;br /&gt;
	end&lt;br /&gt;
end&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It can be called in &amp;lt;code&amp;gt;Initialize()&amp;lt;/code&amp;gt; &#039;&#039;before&#039;&#039; we spawn our features, to ensure we also test on an empty map.&lt;br /&gt;
&lt;br /&gt;
When packing the map for release, one might want to comment it out again.&lt;br /&gt;
&lt;br /&gt;
=A forest is many, many, many trees=&lt;br /&gt;
A handful of trees is often not enough for a map. Let&#039;s turn the whole bottom left corner of the map into a forest. &lt;br /&gt;
&lt;br /&gt;
But planting a whole forest by typing coordinates of many trees seems very cumbersome?&lt;br /&gt;
&lt;br /&gt;
What about randomizing the placement of the tree?&lt;br /&gt;
&lt;br /&gt;
We look up the coordinates of that area: x-coordinate we want 3500 to 4000, for z-coordinate we want 3000 to 4000.&lt;br /&gt;
&lt;br /&gt;
...and put it into a random number generator function.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
x = math.random (3500,4000)&lt;br /&gt;
z = math.random (3000,4000)&lt;br /&gt;
PlantTree (x,z)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We want to plant many trees. Instead of copy-pasting those lines 100 times, we use a loop:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;code&amp;gt;&lt;br /&gt;
function gadget:Initialize()&lt;br /&gt;
	DestroyAllFeatures ()&lt;br /&gt;
	for i=1,100 do&lt;br /&gt;
		x = math.random (3500,4000)&lt;br /&gt;
		z = math.random (3000,4000)&lt;br /&gt;
		PlantTree (x,z)&lt;br /&gt;
	end&lt;br /&gt;
end&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The result:&lt;br /&gt;
&lt;br /&gt;
[[File:TreesSpawnedRandomly.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/treesspawnedrandomlyf3snt.jpg]&lt;br /&gt;
&lt;br /&gt;
{{Tip|Forests are perfect for such random placement because the excact position of an indiviual tree does not matter much.}}&lt;br /&gt;
&lt;br /&gt;
==Spawning features in patterns==&lt;br /&gt;
With a little creativity one can quickly fill the map in interessting ways.&lt;br /&gt;
&lt;br /&gt;
For example try to create a function that spawns small clusters of trees. &lt;br /&gt;
&lt;br /&gt;
Or imagine a function that spawns a big mineral crystal, surrounded by smaller rocks.&lt;br /&gt;
&lt;br /&gt;
Or imagine an ore-mining facility with pieces of ore spread around it. &lt;br /&gt;
&lt;br /&gt;
etc&lt;br /&gt;
&lt;br /&gt;
Below is some examples that are hopefully understandable without too lenghty explainations.&lt;br /&gt;
&lt;br /&gt;
==Lua rocks==&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function Rock (x,z)&lt;br /&gt;
	local featureName = &amp;quot;pdrock&amp;quot; .. math.random (1, 4)&lt;br /&gt;
	Spring.CreateFeature (featureName, x,Spring.GetGroundHeight (x,z),z, math.random (0,32000))&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function rockCircle (x,z, radius, numberOfRocks)&lt;br /&gt;
for d = 0,360, 360/numberOfRocks do&lt;br /&gt;
		local x = x + (math.sin (math.rad(d)) * radius)&lt;br /&gt;
		local z = z + (math.cos (math.rad(d)) * radius)&lt;br /&gt;
		Rock (x, z)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
Example usage: &lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;rockCircle (2000,2000, 240, 25)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
&lt;br /&gt;
[[File:CircleOfRocks.jpg]]&lt;br /&gt;
[File:http://abload.de/img/circle_of_rockso5stt.jpg]&lt;br /&gt;
&lt;br /&gt;
*Note 1: &amp;lt;code&amp;gt;local featureName = &amp;quot;pdrock&amp;quot; .. math.random (1, 4)&amp;lt;/code&amp;gt;&lt;br /&gt;
The rock features included in map &amp;quot;DesertTriad&amp;quot; are named &amp;quot;pdrock1&amp;quot; to &amp;quot;pdrock4&amp;quot;. So we take &amp;quot;pdrock&amp;quot; and append a random number in range of 1 to 4 to that base name.&lt;br /&gt;
&lt;br /&gt;
*Note 2: The heading-parameter is used here too, randomized. The heading (rotation) of features is probally not measured 0 to 32000, but for this case that does not matter. If the number is too high it will simply &amp;quot;wrap around.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==In my maps I have seen rings of smoke through the trees...==&lt;br /&gt;
&#039;&#039;...and the voices of those who stand looking.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function TreeSpiral (x,z)&lt;br /&gt;
	for d = 0,720, 20 do&lt;br /&gt;
		local x = x + (math.sin (math.rad(d)) * d/2)&lt;br /&gt;
		local z = z + (math.cos (math.rad(d)) * d/2)&lt;br /&gt;
		PlantTree (x,z)&lt;br /&gt;
	end&lt;br /&gt;
	y = Spring.GetGroundHeight (x,z)&lt;br /&gt;
	Spring.CreateFeature (&amp;quot;geovent&amp;quot;, x,y,z)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example usage: &lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;code&amp;gt;TreeSpiral (2000,2000)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
&lt;br /&gt;
A geothermal vent in the middle of a spiral of trees.&lt;br /&gt;
&lt;br /&gt;
[[File:TreeSpiralWithGeovent.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/treespiralwithgeoventu1swc.jpg]&lt;br /&gt;
&lt;br /&gt;
=Typing so many coordinates sucks!=&lt;br /&gt;
We saw how some typing could be saved by using loops or random placement.&lt;br /&gt;
But surely there must be another way?&lt;br /&gt;
&lt;br /&gt;
We could try to save the coordinates of all features of the map into a file.&lt;br /&gt;
&lt;br /&gt;
If we wanted to do that, we would preferably save the coordinates in a way that can also be read back by another script. &lt;br /&gt;
For now that seems too difficult so we think of another way.&lt;br /&gt;
&lt;br /&gt;
* think * think * think *&lt;br /&gt;
&lt;br /&gt;
==Coordinates Helper widget==&lt;br /&gt;
Spring allows players to mark tactical locations on the map by holding ~ or ^ and clicking the mousewheel.&lt;br /&gt;
&lt;br /&gt;
That might also be useful for marking locations of features, if we can just save those coordinates?&lt;br /&gt;
&lt;br /&gt;
Let&#039;s see if we can create a small &#039;&#039;&#039;helper widget&#039;&#039;&#039; for that purpose.&lt;br /&gt;
&lt;br /&gt;
Create a file &amp;lt;code&amp;gt;LuaUI\widgets\MapMarkerCoordinatesLogger.lua&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==MapDrawCmd: 1,2,3 testing!==&lt;br /&gt;
For start let&#039;s just see if we can print the coordinates of a map marker to the console.&lt;br /&gt;
&lt;br /&gt;
We discover the callin: &amp;lt;code&amp;gt;MapDrawCmd(playerID, cmdType, px, py, pz, label)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function widget:GetInfo()&lt;br /&gt;
  return {&lt;br /&gt;
    name      = &amp;quot;MapMarkerCoordinatesLogger&amp;quot;,&lt;br /&gt;
    desc      = &amp;quot;prints map marker coordinates&amp;quot;,&lt;br /&gt;
    author    = &amp;quot;this lame tutorial or something&amp;quot;,&lt;br /&gt;
    date      = &amp;quot;9 Nov 2010&amp;quot;,&lt;br /&gt;
    license   = &amp;quot;GNU GPL, v2&amp;quot;,&lt;br /&gt;
    layer     = -5,&lt;br /&gt;
    enabled   = true,&lt;br /&gt;
  }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function widget:MapDrawCmd(playerID, cmdType, px, py, pz, label)&lt;br /&gt;
	Spring.Echo (px, py,pz)&lt;br /&gt;
end&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
&lt;br /&gt;
[[File:MapMarkerCoordinatesToChat.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/mapmarkercoordinatestnwsng.jpg]&lt;br /&gt;
&lt;br /&gt;
We see that the coordinates of the markers get printed to chat. (and thus to infolog.txt, too)&lt;br /&gt;
&lt;br /&gt;
Not bad, but could be less bad.&lt;br /&gt;
&lt;br /&gt;
==Turning test into something useful==&lt;br /&gt;
&lt;br /&gt;
One obvious issue is that it does not just log placing markers but also outputs numbers when drawing lines or deleting.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s upgrade the widget so that:&lt;br /&gt;
#It only logs placing markers but not erasing or lines.&lt;br /&gt;
#instead of coordinates it outputs a whole function call like &amp;lt;code&amp;gt;PlantTree (3830,3600)&amp;lt;/code&amp;gt;&lt;br /&gt;
#writes to a file instead of chat&lt;br /&gt;
#The functionname that gets written should be changeable from within game&lt;br /&gt;
#It has a cooler name&lt;br /&gt;
&lt;br /&gt;
{{Tip|&#039;&#039;&#039;Before reading onwards: Try figure out a solution by yourself!&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) Sadly the wiki does not tell us how we know the difference between marker/lines/erasing. We must figure it out!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;MapDrawCmd(playerID, cmdType, px, py, pz, label)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The paremter &#039;&#039;cmdType&#039;&#039; looks interessting. Let&#039;s just print that one too:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;Spring.Echo (px, py,pz, cmdType)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We see that cmdType has the value &amp;quot;point&amp;quot; when placing markers and other values when doing other things.&lt;br /&gt;
&lt;br /&gt;
So if cmdType is of wrong value we just return and do nothing:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function widget:MapDrawCmd(playerID, cmdType, px, py, pz, label)&lt;br /&gt;
	if cmdType ~= &amp;quot;point&amp;quot; then return end&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2) Creating the complete function call like &amp;quot;PlantTree (3830,3600)&amp;quot; is just a matter of appending some strings:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
local functionName = &amp;quot;PlantTree&amp;quot;&lt;br /&gt;
local s = functionName .. &amp;quot; (&amp;quot; .. px ..&amp;quot;, &amp;quot; .. pz .. &amp;quot;)&amp;quot;&lt;br /&gt;
Spring.Echo (s)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that we only save the X and Z coordinates because the Y-coordinate we can later get anyway with Spring.GetGroundHeight&lt;br /&gt;
&lt;br /&gt;
3) About writing to file we can find many tutorials on web if we google something like &amp;quot;Lua write to file&amp;quot; or similiar.&lt;br /&gt;
&lt;br /&gt;
The result:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
local file = io.open(&amp;quot;myCoordinatesFile.txt&amp;quot;, &amp;quot;a&amp;quot;)&lt;br /&gt;
file:write(s)&lt;br /&gt;
file:flush()&lt;br /&gt;
file:close()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Markers can have a label text attached to them. Let&#039;s use that to allow user to change the functionname.&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;if label ~= &amp;quot;&amp;quot; then functionName = label end&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Since the widget writes points into files for features placement, we name it: &#039;&#039;&#039;Pifffp&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Complete Pifffp widget==&lt;br /&gt;
Putting everything together we get:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function widget:GetInfo()&lt;br /&gt;
  return {&lt;br /&gt;
    name      = &amp;quot;Pifffp aka MapMarkerCoordinatesLogger&amp;quot;,&lt;br /&gt;
    desc      = &amp;quot;prints Lua functions for placing featues&amp;quot;,&lt;br /&gt;
    author    = &amp;quot;this lame tutorial or something&amp;quot;,&lt;br /&gt;
    date      = &amp;quot;today&amp;quot;,&lt;br /&gt;
    license   = &amp;quot;GNU GPL, v2&amp;quot;,&lt;br /&gt;
    layer     = -5,&lt;br /&gt;
    enabled   = true,&lt;br /&gt;
  }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local functionName = &amp;quot;PlantTree&amp;quot;&lt;br /&gt;
function widget:MapDrawCmd(playerID, cmdType, px, py, pz, label)&lt;br /&gt;
	if cmdType ~= &amp;quot;point&amp;quot; then return end&lt;br /&gt;
	if label ~= &amp;quot;&amp;quot; then functionName = label end&lt;br /&gt;
	--Spring.Echo (px, py,pz, cmdType, &amp;quot;-&amp;quot;..label..&amp;quot;-&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	local s = functionName .. &amp;quot; (&amp;quot; .. px ..&amp;quot;, &amp;quot; .. pz .. &amp;quot;)&amp;quot;&lt;br /&gt;
	Spring.Echo (s)&lt;br /&gt;
	&lt;br /&gt;
	local file = io.open(&amp;quot;myCoordinatesFile.txt&amp;quot;, &amp;quot;a&amp;quot;)&lt;br /&gt;
	file:write(s .. &amp;quot;\n&amp;quot;)&lt;br /&gt;
	file:flush()&lt;br /&gt;
	file:close()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Using the Pifffp tool as a user/mapper==&lt;br /&gt;
Activate the widget in F11 list.&lt;br /&gt;
&lt;br /&gt;
Now start placing map markers. Every time you place a marker the coordinates get logged into &#039;&#039;&#039;myCoordinatesFile.txt&#039;&#039;&#039;, already formated as parameters to a function call.&lt;br /&gt;
&lt;br /&gt;
(The file should usually be written next to spring.exe)&lt;br /&gt;
&lt;br /&gt;
To change the name of the function place a marker with a label text. All folling markers will then use that text, until a new label text is used.&lt;br /&gt;
&lt;br /&gt;
Example usage:&lt;br /&gt;
&lt;br /&gt;
[[File:Pifffp_Markers.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/pifffp_markers7lsq1.jpg]&lt;br /&gt;
&lt;br /&gt;
Example output:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
PlantTree (1977, 3569)&lt;br /&gt;
PlantTree (1933, 3372)&lt;br /&gt;
PlantTree (1901, 3489)&lt;br /&gt;
PlantTree (1850, 3612)&lt;br /&gt;
PlantTree (2008, 3643)&lt;br /&gt;
PlantTree (2101, 3497)&lt;br /&gt;
PlantTree (2112, 3637)&lt;br /&gt;
PlantTree (2228, 3605)&lt;br /&gt;
PlantTree (2226, 3464)&lt;br /&gt;
PlantTree (2043, 3406)&lt;br /&gt;
PlantTree (2163, 3357)&lt;br /&gt;
PlantTree (2293, 3278)&lt;br /&gt;
PlantTree (2125, 3179)&lt;br /&gt;
PlantTree (1986, 3193)&lt;br /&gt;
Rock (1526, 3099)&lt;br /&gt;
Rock (1576, 3024)&lt;br /&gt;
Rock (1500, 2926)&lt;br /&gt;
Rock (1373, 3035)&lt;br /&gt;
Rock (1438, 3212)&lt;br /&gt;
Rock (1556, 3264)&lt;br /&gt;
Rock (1699, 3122)&lt;br /&gt;
Rock (1670, 2919)&lt;br /&gt;
Rock (1398, 2918)&lt;br /&gt;
Geovent (1818, 3298)&lt;br /&gt;
rockCircle (2308, 2788)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We recognize these functions from the beginning of the tutorial. &lt;br /&gt;
&lt;br /&gt;
Hopefully still have them ready in our &amp;lt;code&amp;gt;LuaRules\gadgets\MyLuaFeatureTesting.lua&amp;lt;/code&amp;gt; file so that we only need to paste the Pifffp output into &amp;lt;code&amp;gt;Initialize&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(I you are making a real map you might want to use a better filename like &amp;quot;spawnMyFeatures.lua&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
Note that for the function rockCircle we still need to fill in the parameters radius and amount of rocks like so:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
rockCircle (2308, 2788, 200, 25)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example result:&lt;br /&gt;
&lt;br /&gt;
[[File:Pifffp_ResultFeatures.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/pifffp_resultfeaturesiisdi.jpg]&lt;br /&gt;
&lt;br /&gt;
Now we have created ourselves a quick way to put features onto map with Lua.&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=User:Knorke/Sandbox3&amp;diff=20875</id>
		<title>User:Knorke/Sandbox3</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=User:Knorke/Sandbox3&amp;diff=20875"/>
		<updated>2014-11-07T23:06:31Z</updated>

		<summary type="html">&lt;p&gt;Knorke: first version of LuaMapStuff&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This text talks about how to put features onto the map, using Lua.&lt;br /&gt;
&lt;br /&gt;
The text can be read in two ways:&lt;br /&gt;
*As a Lua tutorial that expands on [[Lua:Tutorial_GettingStarted]] and {{FIXME}} that other page in sandbox&lt;br /&gt;
*For mappers as way to put features onto their map. &lt;br /&gt;
**In this case you can skip some of the &amp;quot;finer details&amp;quot; and just copypaste what seems interessting.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To follow the examples you can either...&lt;br /&gt;
* ...use your WIP map in .sdd format&lt;br /&gt;
* ...or unpack an existing map&lt;br /&gt;
* ...or use the test-mutator example from previous tutorial.&lt;br /&gt;
&lt;br /&gt;
This text will be based around the map &#039;&#039;&#039;&amp;quot;DesertTriad&amp;quot;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=Creating a feature: Spring.CreateFeature=&lt;br /&gt;
&lt;br /&gt;
Again we use our test-hill in the bottom right corner, of which we already know the coordinates:&lt;br /&gt;
&lt;br /&gt;
[[File:DesertTriadHillCoordinates.jpg]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;We want to create a feature on this hill.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Create a file: &amp;lt;code&amp;gt;LuaRules\gadgets\MyLuaFeatureTesting.lua&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
At [[Lua_SyncedCtrl#Feature_Handling]] we find the function &amp;lt;code&amp;gt;Spring.CreateFeature&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We need the parameters: &#039;&#039;featurename&#039;&#039; and &#039;&#039;x,y,z&#039;&#039; coordinates. The other parameters do not matter for now.&lt;br /&gt;
&lt;br /&gt;
The map &amp;quot;DesertTriad&amp;quot; already includes some rock features that we could use. If using the test-mutator then we can also use whatever features the game includes, usually that is mostly wrecks of destroyed units.&lt;br /&gt;
&lt;br /&gt;
Another group of features that we can use are the ones hardcoded in the engine: Geovents and trees.&lt;br /&gt;
&lt;br /&gt;
We use a feature named &amp;quot;treetype0&amp;quot;, it is a tree that comes with Spring engine.&lt;br /&gt;
&lt;br /&gt;
Putting feature name and coordinates as parameters:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Spring.CreateFeature (&amp;quot;treetype0&amp;quot;, 3830,  390, 3600)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==GameStart() or Initialize() or GamePreload() ?==&lt;br /&gt;
Where should we put the CreateFeature code?&lt;br /&gt;
&lt;br /&gt;
There are three callin functions that appear suitable:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;GameStart() Initialize() GamePreload() - can callin can I take?&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;GameStart()&amp;lt;/code&amp;gt; is called as soon as the game begins. &lt;br /&gt;
**However, it is not yet called when the players are ingame but have not readied up yet.&lt;br /&gt;
** =&amp;gt; If this callin was used then features would not appear until the game is started. Thus players could not see while choosing their start positions etc.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;GamePreload()&amp;lt;/code&amp;gt; is called as soon as soon the &amp;quot;game is ingame.&amp;quot;&lt;br /&gt;
**Features spawned in this function will be visible before readying up.&lt;br /&gt;
**However, it is only called once: Right after the game has finished loading.&lt;br /&gt;
***That means if we want to test our Lua by typing &#039;&#039;/luarules reload&#039;&#039; then it will not trigger again.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Initialize()&amp;lt;/code&amp;gt; is called when the gadget is initialized.&lt;br /&gt;
**Features spawned in this function will be visible before readying up.&lt;br /&gt;
**When typing &#039;&#039;/luarules reload&#039;&#039; the gadgets get initialized again and the function gets called again.&lt;br /&gt;
***This makes it suitable for testing.&lt;br /&gt;
&lt;br /&gt;
=&amp;gt; Both &amp;lt;code&amp;gt;Initialize()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;GamePreload()&amp;lt;/code&amp;gt; can be used to spawn features without &amp;quot;delay.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=&amp;gt; Maybe &amp;lt;code&amp;gt;GamePreload()&amp;lt;/code&amp;gt; is a bit &amp;quot;more technical correct&amp;quot; but &amp;lt;code&amp;gt;Initialize()&amp;lt;/code&amp;gt; is more suited for testing, so we use that.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=complete gadget that plants a tree=&lt;br /&gt;
Thus the gadget now looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function gadget:GetInfo()&lt;br /&gt;
  return {&lt;br /&gt;
    name      = &amp;quot;lua map stuff&amp;quot;,&lt;br /&gt;
    desc      = &amp;quot;create some features&amp;quot;,&lt;br /&gt;
    author    = &amp;quot;youe name&amp;quot;,&lt;br /&gt;
    date      = &amp;quot;the day a lua was made&amp;quot;,&lt;br /&gt;
    license   = &amp;quot;GNU GPL, v2&amp;quot;,&lt;br /&gt;
    layer     = 0,&lt;br /&gt;
    enabled   = true,&lt;br /&gt;
  }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if not gadgetHandler:IsSyncedCode() then&lt;br /&gt;
&lt;br /&gt;
function gadget:Initialize()&lt;br /&gt;
	Spring.CreateFeature (&amp;quot;treetype0&amp;quot;, 3830,  390, 3600)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
else --unsynced part below&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The result:&lt;br /&gt;
&lt;br /&gt;
[[File:OneTreeOnHill.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/onetreeonhillpcs0m.jpg]&lt;br /&gt;
&lt;br /&gt;
{{Tip|&#039;&#039;&#039;Such simple code is really all it takes to put features on a map.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If one wanted one could now replaces the featurename and coordinates and use it to populate a map. In fact some maps do just that.}}&lt;br /&gt;
&lt;br /&gt;
{{Tip|If you need to remove the tree for testing purposes, then reclaim it with the Commander or a constructor. (We will learn a better way soon)}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==If a tree falls from the sky... does it make a sound?==&lt;br /&gt;
One interessting thing is that Spring physics do not get activated until the game actually starts.&lt;br /&gt;
&lt;br /&gt;
Why is that relevant for spawning features?&lt;br /&gt;
&lt;br /&gt;
If we use a too high y-coordinate (vertical axis / height) then the tree will hover in the air until the game starts. &lt;br /&gt;
&lt;br /&gt;
[[File:FeaturesFallAtGameStart.gif]]&lt;br /&gt;
 &lt;br /&gt;
 [File:http://abload.de/img/lfs2014-10-1818-14-44swfl9.gif]&lt;br /&gt;
&lt;br /&gt;
And then it will suddendly fall down! (Look at above gif)&lt;br /&gt;
&lt;br /&gt;
Similiar if we use too low y-coordinate then the tree will be created underground and only &amp;quot;pop&amp;quot; above ground once the game starts!&lt;br /&gt;
&lt;br /&gt;
{{Tip|It is important to spawn features (and units) at the correct y-coordinate.}}&lt;br /&gt;
&lt;br /&gt;
===GetGroundHeight===&lt;br /&gt;
Instead of reading the ground height from the tooltip we can also use the function &amp;lt;code&amp;gt;Spring.GetGroundHeight&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function gadget:Initialize()&lt;br /&gt;
	x = 3830&lt;br /&gt;
	z = 3600&lt;br /&gt;
	y = Spring.GetGroundHeight (x,z)&lt;br /&gt;
	Spring.CreateFeature (&amp;quot;treetype0&amp;quot;, x,y,z)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Functional forest=&lt;br /&gt;
We can put our tree-spawner code into a function and call it from &amp;lt;code&amp;gt;Initialize()&amp;lt;/code&amp;gt; multiple times with different coordinates:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function PlantTree (x,z)&lt;br /&gt;
	y = Spring.GetGroundHeight (x,z)&lt;br /&gt;
	Spring.CreateFeature (&amp;quot;treetype0&amp;quot;, x,y,z)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function gadget:Initialize()&lt;br /&gt;
	PlantTree (3830,3600)&lt;br /&gt;
	PlantTree (3850,3650)&lt;br /&gt;
	PlantTree (3800,3650)&lt;br /&gt;
	PlantTree (3810,320)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
&lt;br /&gt;
[[File:TreesSpawnedOnHill.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/treesspawnedonhill74shj.jpg]&lt;br /&gt;
&lt;br /&gt;
{{Tip|For practice try to make a function that spawns geothermal spots! The featurename is &amp;quot;geovent&amp;quot;.}}&lt;br /&gt;
&lt;br /&gt;
=Deleting all features from map=&lt;br /&gt;
Sometimes one might want to test the spawning of features again &amp;amp; again, on a clean plate.&lt;br /&gt;
The function below deletes all features on the map:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function DestroyAllFeatures ()&lt;br /&gt;
	local features = Spring.GetAllFeatures ()&lt;br /&gt;
	for i in pairs(features) do&lt;br /&gt;
		Spring.DestroyFeature (features[i])&lt;br /&gt;
	end&lt;br /&gt;
end&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It can be called in &amp;lt;code&amp;gt;Initialize()&amp;lt;/code&amp;gt; &#039;&#039;before&#039;&#039; we spawn our features, to ensure we also test on an empty map.&lt;br /&gt;
&lt;br /&gt;
When packing the map for release, one might want to comment it out again.&lt;br /&gt;
&lt;br /&gt;
=A forest is many, many, many trees=&lt;br /&gt;
A handful of trees is often not enough for a map. Let&#039;s turn the whole bottom left corner of the map into a forest. &lt;br /&gt;
&lt;br /&gt;
But planting a whole forest by typing coordinates of many trees seems very cumbersome?&lt;br /&gt;
&lt;br /&gt;
What about randomizing the placement of the tree?&lt;br /&gt;
&lt;br /&gt;
We look up the coordinates of that area: x-coordinate we want 3500 to 4000, for z-coordinate we want 3000 to 4000.&lt;br /&gt;
&lt;br /&gt;
...and put it into a random number generator function.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
x = math.random (3500,4000)&lt;br /&gt;
z = math.random (3000,4000)&lt;br /&gt;
PlantTree (x,z)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We want to plant many trees. Instead of copy-pasting those lines 100 times, we use a loop:&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;code&amp;gt;&lt;br /&gt;
function gadget:Initialize()&lt;br /&gt;
	DestroyAllFeatures ()&lt;br /&gt;
	for i=1,100 do&lt;br /&gt;
		x = math.random (3500,4000)&lt;br /&gt;
		z = math.random (3000,4000)&lt;br /&gt;
		PlantTree (x,z)&lt;br /&gt;
	end&lt;br /&gt;
end&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The result:&lt;br /&gt;
&lt;br /&gt;
[[File:TreesSpawnedRandomly.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/treesspawnedrandomlyf3snt.jpg]&lt;br /&gt;
&lt;br /&gt;
{{Tip|Forests are perfect for such random placement because the excact position of an indiviual tree does not matter much.}}&lt;br /&gt;
&lt;br /&gt;
==Spawning features in patterns==&lt;br /&gt;
With a little creativity one can quickly fill the map in interessting ways.&lt;br /&gt;
&lt;br /&gt;
For example try to create a function that spawns small clusters of trees. &lt;br /&gt;
&lt;br /&gt;
Or imagine a function that spawns a big mineral crystal, surrounded by smaller rocks.&lt;br /&gt;
&lt;br /&gt;
Or imagine an ore-mining facility with pieces of ore spread around it. &lt;br /&gt;
&lt;br /&gt;
etc&lt;br /&gt;
&lt;br /&gt;
Below is some examples that are hopefully understandable without too lenghty explainations.&lt;br /&gt;
&lt;br /&gt;
==Lua rocks==&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function Rock (x,z)&lt;br /&gt;
	local featureName = &amp;quot;pdrock&amp;quot; .. math.random (1, 4)&lt;br /&gt;
	Spring.CreateFeature (featureName, x,Spring.GetGroundHeight (x,z),z, math.random (0,32000))&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function rockCircle (x,z, radius, numberOfRocks)&lt;br /&gt;
for d = 0,360, 360/numberOfRocks do&lt;br /&gt;
		local x = x + (math.sin (math.rad(d)) * radius)&lt;br /&gt;
		local z = z + (math.cos (math.rad(d)) * radius)&lt;br /&gt;
		Rock (x, z)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
Example usage: &lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;rockCircle (2000,2000, 240, 25)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
&lt;br /&gt;
[[File:CircleOfRocks.jpg]]&lt;br /&gt;
[File:http://abload.de/img/circle_of_rockso5stt.jpg]&lt;br /&gt;
&lt;br /&gt;
*Note 1: &amp;lt;code&amp;gt;local featureName = &amp;quot;pdrock&amp;quot; .. math.random (1, 4)&amp;lt;/code&amp;gt;&lt;br /&gt;
The rock features included in map &amp;quot;DesertTriad&amp;quot; are named &amp;quot;pdrock1&amp;quot; to &amp;quot;pdrock4&amp;quot;. So we take &amp;quot;pdrock&amp;quot; and append a random number in range of 1 to 4 to that base name.&lt;br /&gt;
&lt;br /&gt;
*Note 2: The heading-parameter is used here too, randomized. The heading (rotation) of features is probally not measured 0 to 32000, but for this case that does not matter. If the number is too high it will simply &amp;quot;wrap around.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==In my maps I have seen rings of smoke through the trees...==&lt;br /&gt;
&#039;&#039;...and the voices of those who stand looking.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function TreeSpiral (x,z)&lt;br /&gt;
	for d = 0,720, 20 do&lt;br /&gt;
		local x = x + (math.sin (math.rad(d)) * d/2)&lt;br /&gt;
		local z = z + (math.cos (math.rad(d)) * d/2)&lt;br /&gt;
		PlantTree (x,z)&lt;br /&gt;
	end&lt;br /&gt;
	y = Spring.GetGroundHeight (x,z)&lt;br /&gt;
	Spring.CreateFeature (&amp;quot;geovent&amp;quot;, x,y,z)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example usage: &lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;code&amp;gt;TreeSpiral (2000,2000)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
&lt;br /&gt;
A geothermal vent in the middle of a spiral of trees.&lt;br /&gt;
&lt;br /&gt;
[[File:TreeSpiralWithGeovent.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/treespiralwithgeoventu1swc.jpg]&lt;br /&gt;
&lt;br /&gt;
=Typing so many coordinates sucks!=&lt;br /&gt;
We saw how some typing could be saved by using loops or random placement.&lt;br /&gt;
But surely there must be another way?&lt;br /&gt;
&lt;br /&gt;
We could try to save the coordinates of all features of the map into a file.&lt;br /&gt;
&lt;br /&gt;
If we wanted to do that, we would preferably save the coordinates in a way that can also be read back by another script. &lt;br /&gt;
For now that seems too difficult so we think of another way.&lt;br /&gt;
&lt;br /&gt;
* think * think * think *&lt;br /&gt;
&lt;br /&gt;
==Coordinates Helper widget==&lt;br /&gt;
Spring allows players to mark tactical locations on the map by holding ~ or ^ and clicking the mousewheel.&lt;br /&gt;
&lt;br /&gt;
That might also be useful for marking locations of features, if we can just save those coordinates?&lt;br /&gt;
&lt;br /&gt;
Let&#039;s see if we can create a small &#039;&#039;&#039;helper widget&#039;&#039;&#039; for that purpose.&lt;br /&gt;
&lt;br /&gt;
Create a file &amp;lt;code&amp;gt;LuaUI\widgets\MapMarkerCoordinatesLogger.lua&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==MapDrawCmd: 1,2,3 testing!==&lt;br /&gt;
For start let&#039;s just see if we can print the coordinates of a map marker to the console.&lt;br /&gt;
&lt;br /&gt;
We discover the callin: &amp;lt;code&amp;gt;MapDrawCmd(playerID, cmdType, px, py, pz, label)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function widget:GetInfo()&lt;br /&gt;
  return {&lt;br /&gt;
    name      = &amp;quot;MapMarkerCoordinatesLogger&amp;quot;,&lt;br /&gt;
    desc      = &amp;quot;prints map marker coordinates&amp;quot;,&lt;br /&gt;
    author    = &amp;quot;this lame tutorial or something&amp;quot;,&lt;br /&gt;
    date      = &amp;quot;9 Nov 2010&amp;quot;,&lt;br /&gt;
    license   = &amp;quot;GNU GPL, v2&amp;quot;,&lt;br /&gt;
    layer     = -5,&lt;br /&gt;
    enabled   = true,&lt;br /&gt;
  }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function widget:MapDrawCmd(playerID, cmdType, px, py, pz, label)&lt;br /&gt;
	Spring.Echo (px, py,pz)&lt;br /&gt;
end&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
&lt;br /&gt;
[[File:MapMarkerCoordinatesToChat.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/mapmarkercoordinatestnwsng.jpg]&lt;br /&gt;
&lt;br /&gt;
We see that the coordinates of the markers get printed to chat. (and thus to infolog.txt, too)&lt;br /&gt;
&lt;br /&gt;
Not bad, but could be less bad.&lt;br /&gt;
&lt;br /&gt;
==Turning test into something useful==&lt;br /&gt;
&lt;br /&gt;
One obvious issue is that it does not just log placing markers but also outputs numbers when drawing lines or deleting.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s upgrade the widget so that:&lt;br /&gt;
#It only logs placing markers but not erasing or lines.&lt;br /&gt;
#instead of coordinates it outputs a whole function call like &amp;lt;code&amp;gt;PlantTree (3830,3600)&amp;lt;/code&amp;gt;&lt;br /&gt;
#writes to a file instead of chat&lt;br /&gt;
#The functionname that gets written should be changeable from within game&lt;br /&gt;
#It has a cooler name&lt;br /&gt;
&lt;br /&gt;
{{Tip|&#039;&#039;&#039;Before reading onwards: Try figure out a solution by yourself!&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) Sadly the wiki does not tell us how we know the difference between marker/lines/erasing. We must figure it out!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;MapDrawCmd(playerID, cmdType, px, py, pz, label)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The paremter &#039;&#039;cmdType&#039;&#039; looks interessting. Let&#039;s just print that one too:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;Spring.Echo (px, py,pz, cmdType)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We see that cmdType has the value &amp;quot;point&amp;quot; when placing markers and other values when doing other things.&lt;br /&gt;
&lt;br /&gt;
So if cmdType is of wrong value we just return and do nothing:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function widget:MapDrawCmd(playerID, cmdType, px, py, pz, label)&lt;br /&gt;
	if cmdType ~= &amp;quot;point&amp;quot; then return end&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2) Creating the complete function call like &amp;quot;PlantTree (3830,3600)&amp;quot; is just a matter of appending some strings:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
local functionName = &amp;quot;PlantTree&amp;quot;&lt;br /&gt;
local s = functionName .. &amp;quot; (&amp;quot; .. px ..&amp;quot;, &amp;quot; .. pz .. &amp;quot;)&amp;quot;&lt;br /&gt;
Spring.Echo (s)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that we only save the X and Z coordinates because the Y-coordinate we can later get anyway with Spring.GetGroundHeight&lt;br /&gt;
&lt;br /&gt;
3) About writing to file we can find many tutorials on web if we google something like &amp;quot;Lua write to file&amp;quot; or similiar.&lt;br /&gt;
&lt;br /&gt;
The result:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
local file = io.open(&amp;quot;myCoordinatesFile.txt&amp;quot;, &amp;quot;a&amp;quot;)&lt;br /&gt;
file:write(s)&lt;br /&gt;
file:flush()&lt;br /&gt;
file:close()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4) Markers can have a label text attached to them. Let&#039;s use that to allow user to change the functionname.&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;if label ~= &amp;quot;&amp;quot; then functionName = label end&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5) Since the widget writes points into files for features placement, we name it: &#039;&#039;&#039;Pifffp&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Complete Pifffp widget==&lt;br /&gt;
Putting everything together we get:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function widget:GetInfo()&lt;br /&gt;
  return {&lt;br /&gt;
    name      = &amp;quot;Pifffp aka MapMarkerCoordinatesLogger&amp;quot;,&lt;br /&gt;
    desc      = &amp;quot;prints Lua functions for placing featues&amp;quot;,&lt;br /&gt;
    author    = &amp;quot;this lame tutorial or something&amp;quot;,&lt;br /&gt;
    date      = &amp;quot;today&amp;quot;,&lt;br /&gt;
    license   = &amp;quot;GNU GPL, v2&amp;quot;,&lt;br /&gt;
    layer     = -5,&lt;br /&gt;
    enabled   = true,&lt;br /&gt;
  }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local functionName = &amp;quot;PlantTree&amp;quot;&lt;br /&gt;
function widget:MapDrawCmd(playerID, cmdType, px, py, pz, label)&lt;br /&gt;
	if cmdType ~= &amp;quot;point&amp;quot; then return end&lt;br /&gt;
	if label ~= &amp;quot;&amp;quot; then functionName = label end&lt;br /&gt;
	--Spring.Echo (px, py,pz, cmdType, &amp;quot;-&amp;quot;..label..&amp;quot;-&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	local s = functionName .. &amp;quot; (&amp;quot; .. px ..&amp;quot;, &amp;quot; .. pz .. &amp;quot;)&amp;quot;&lt;br /&gt;
	Spring.Echo (s)&lt;br /&gt;
	&lt;br /&gt;
	local file = io.open(&amp;quot;myCoordinatesFile.txt&amp;quot;, &amp;quot;a&amp;quot;)&lt;br /&gt;
	file:write(s .. &amp;quot;\n&amp;quot;)&lt;br /&gt;
	file:flush()&lt;br /&gt;
	file:close()&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Using the Pifffp tool as a user/mapper==&lt;br /&gt;
Activate the widget in F11 list.&lt;br /&gt;
&lt;br /&gt;
Now start placing map markers. Every time you place a marker the coordinates get logged into &#039;&#039;&#039;myCoordinatesFile.txt&#039;&#039;&#039;, already formated as parameters to a function call.&lt;br /&gt;
&lt;br /&gt;
(The file should usually be written next to spring.exe)&lt;br /&gt;
&lt;br /&gt;
To change the name of the function place a marker with a label text. All folling markers will then use that text, until a new label text is used.&lt;br /&gt;
&lt;br /&gt;
Example usage:&lt;br /&gt;
&lt;br /&gt;
[[File:Pifffp_Markers.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:http://abload.de/img/pifffp_markers7lsq1.jpg]&lt;br /&gt;
&lt;br /&gt;
Example output:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
PlantTree (1977, 3569)&lt;br /&gt;
PlantTree (1933, 3372)&lt;br /&gt;
PlantTree (1901, 3489)&lt;br /&gt;
PlantTree (1850, 3612)&lt;br /&gt;
PlantTree (2008, 3643)&lt;br /&gt;
PlantTree (2101, 3497)&lt;br /&gt;
PlantTree (2112, 3637)&lt;br /&gt;
PlantTree (2228, 3605)&lt;br /&gt;
PlantTree (2226, 3464)&lt;br /&gt;
PlantTree (2043, 3406)&lt;br /&gt;
PlantTree (2163, 3357)&lt;br /&gt;
PlantTree (2293, 3278)&lt;br /&gt;
PlantTree (2125, 3179)&lt;br /&gt;
PlantTree (1986, 3193)&lt;br /&gt;
Rock (1526, 3099)&lt;br /&gt;
Rock (1576, 3024)&lt;br /&gt;
Rock (1500, 2926)&lt;br /&gt;
Rock (1373, 3035)&lt;br /&gt;
Rock (1438, 3212)&lt;br /&gt;
Rock (1556, 3264)&lt;br /&gt;
Rock (1699, 3122)&lt;br /&gt;
Rock (1670, 2919)&lt;br /&gt;
Rock (1398, 2918)&lt;br /&gt;
Geovent (1818, 3298)&lt;br /&gt;
rockCircle (2308, 2788)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We recognize these functions from the beginning of the tutorial. &lt;br /&gt;
&lt;br /&gt;
Hopefully still have them ready in our &amp;lt;code&amp;gt;LuaRules\gadgets\MyLuaFeatureTesting.lua&amp;lt;/code&amp;gt; file so that we only need to paste the Pifffp output into &amp;lt;code&amp;gt;Initialize&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(I you are making a real map you might want to use a better filename like &amp;quot;spawnMyFeatures.lua&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
Note that for the function rockCircle we still need to fill in the parameters radius and amount of rocks like so:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
rockCircle (2308, 2788, 200, 25)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example result:&lt;br /&gt;
&lt;br /&gt;
[[File:Pifffp_ResultFeatures.jpg]]&lt;br /&gt;
&lt;br /&gt;
[File:ttp://abload.de/img/pifffp_resultfeaturesiisdi.jpg]&lt;br /&gt;
&lt;br /&gt;
Now we have created ourselves a quick way to put features onto map with Lua.&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=User:Knorke/Sandbox2&amp;diff=20873</id>
		<title>User:Knorke/Sandbox2</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=User:Knorke/Sandbox2&amp;diff=20873"/>
		<updated>2014-11-07T19:15:51Z</updated>

		<summary type="html">&lt;p&gt;Knorke: voOOOoolcanooOooo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This text describes making gadgets.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Gadgets must be in a map or game=&lt;br /&gt;
For getting started with a widget, we could just put the file in the spring folder and start coding.&lt;br /&gt;
Unlike widgets, gadgets can not be used &amp;quot;locally&amp;quot; like this: They must be contained in a game or map archive.&lt;br /&gt;
So we must find a way to put the gadget into the game or map. &lt;br /&gt;
&lt;br /&gt;
{{Tip|If you just want to know &amp;quot;How to set up a test-folder&amp;quot; then skip directly to next chapter.}}&lt;br /&gt;
&lt;br /&gt;
The problem is that games and maps usually come in form of zipped archives, or in case of lobby downloaders as many small files.&lt;br /&gt;
&lt;br /&gt;
[[File:rapid_pool_filedust.png]]&lt;br /&gt;
&lt;br /&gt;
That makes adding new files cumbersome:&lt;br /&gt;
#Unpack the archive&lt;br /&gt;
#Add the new script file or edit it&lt;br /&gt;
#Repack the archive&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
So we must turn a map or game into an .sdd archive.&lt;br /&gt;
&lt;br /&gt;
That is explain in more detail in general modding tutorial: ADDLINK FIXME&lt;br /&gt;
&lt;br /&gt;
For first experiment it does not matter if the gadget is in the map or in the game.&lt;br /&gt;
&lt;br /&gt;
Another way is to create a test-mutator. That is basically a game that &amp;quot;includes&amp;quot; another game, like an add-on.&lt;br /&gt;
The advantages are:&lt;br /&gt;
* No need to edit existing game and maybe run into problems.&lt;br /&gt;
* The test-game filesize stays small enough to share easily with others, to get help.&lt;br /&gt;
* One can still use all the units, features &amp;amp; effects of the original game. That is useful for testing.&lt;br /&gt;
&lt;br /&gt;
Personally I recommend the test-mutator.&lt;br /&gt;
XTA is a good canidate as base-game choice because:&lt;br /&gt;
*in some ways it is more basic&lt;br /&gt;
*the unitnames are human-readable. For example &amp;quot;arm_windgenerator&amp;quot; instead of &amp;quot;armwingntor&amp;quot;&lt;br /&gt;
*Some games try to hide as much engine GUI as possible, however for testing that is not so useful.&lt;br /&gt;
&lt;br /&gt;
=The Test Mutator folder=&lt;br /&gt;
1) Create folder: games\MyLuaStuff.sdd&lt;br /&gt;
&lt;br /&gt;
2) Create file: games\MyLuaStuff.sdd\modinfo.lua  (  [[Modinfo.lua]]  )&lt;br /&gt;
&lt;br /&gt;
With this content:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
return {&lt;br /&gt;
  name=&#039;XTA LuaStuff&#039;,&lt;br /&gt;
  description=&#039;lolool&#039;,&lt;br /&gt;
  URL=&#039;http://code.google.com/p/xta-springrts/&#039;,&lt;br /&gt;
  shortname=&#039;XTA&#039;,&lt;br /&gt;
  version = &#039;9.744&#039;,&lt;br /&gt;
  mutator=&#039;LuaStuff&#039;,&lt;br /&gt;
  game=&#039;Total Annihilation&#039;,&lt;br /&gt;
  shortGame=&#039;TA&#039;,&lt;br /&gt;
  depend = {&amp;quot;XTA 9.744&amp;quot;},&lt;br /&gt;
  modtype=1,&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt; &lt;br /&gt;
{{FIXME}} mutator details, can it work with any xta version&lt;br /&gt;
&lt;br /&gt;
3) Test with spring.exe if the mutator shows in game list and can be played&lt;br /&gt;
&lt;br /&gt;
=First gadget: Welcome, new unit!=&lt;br /&gt;
&lt;br /&gt;
1) Create folders: games\MyLuaStuff.sdd\LuaRules\gadgets&lt;br /&gt;
&lt;br /&gt;
2) Create file: games\MyLuaStuff.sdd\LuaRules\gadgets\mytestgadget.lua&lt;br /&gt;
&lt;br /&gt;
3) For first widget we had done an empty widget that did nothing. In the widget-selector-menu we could still check if things were working right.&lt;br /&gt;
So we just take the Hello-Unit widget example and turn it into a gadget:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function gadget:GetInfo()&lt;br /&gt;
  return {&lt;br /&gt;
    name      = &amp;quot;test gadget&amp;quot;,&lt;br /&gt;
    desc      = &amp;quot;testing Lua things&amp;quot;,&lt;br /&gt;
    author    = &amp;quot;your name&amp;quot;,&lt;br /&gt;
    date      = &amp;quot;today&amp;quot;,&lt;br /&gt;
    license   = &amp;quot;GNU GPL, v2&amp;quot;,&lt;br /&gt;
    layer     = 0,&lt;br /&gt;
    enabled   = true,&lt;br /&gt;
  }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if gadgetHandler:IsSyncedCode() then&lt;br /&gt;
&lt;br /&gt;
function gadget:UnitFinished(unitID, unitDefID, teamID)&lt;br /&gt;
	Spring.Echo (&amp;quot;Welcome, new unit!&amp;quot;)	&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
else --unsynced below&lt;br /&gt;
&lt;br /&gt;
end&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We notice it looks very similiar to the widget, except instead of widget::xxx there is gadget:xxx&lt;br /&gt;
&lt;br /&gt;
The GetInfo()-thing again contains some informations about the script, but is otherwise not interessting and to save space will be left out when posting code.&lt;br /&gt;
&lt;br /&gt;
4) Load the game and build a few units. The gadget should welcome each unit.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Volcano example=&lt;br /&gt;
An example of the process when making gadget.&lt;br /&gt;
&lt;br /&gt;
Pretend you are making a map and want to add a volcano.&lt;br /&gt;
[[File:thinkingAboutVulcano.png]]&lt;br /&gt;
&lt;br /&gt;
{{Tip|If we wanted, at this point we could move the Lua into a map-archive. But for testing it is easier to continue using the test-mutator-game.}}&lt;br /&gt;
&lt;br /&gt;
==Define volcano problem== &lt;br /&gt;
We want to make a volcano. Now need to think  &#039;&#039;what excactly is this volcano is supposed to do.&#039;&#039;&lt;br /&gt;
*Should the volcano damage near units?&lt;br /&gt;
*Should it throw burning rocks across the map?&lt;br /&gt;
*Should it merely be a visual effect, just some smoke on a hill?&lt;br /&gt;
&lt;br /&gt;
For this tutorial we chose the last option. (superlame!)&lt;br /&gt;
&lt;br /&gt;
==How to make smoke==&lt;br /&gt;
Now that we know we want to make smoke, the new question is: How to make smoke?&lt;br /&gt;
One way is to use Spring&#039;s particle system called [[CEG:Main]]&lt;br /&gt;
Games can use these CEGS to create explosion, muzzle flashes, fire and so on.&lt;br /&gt;
&lt;br /&gt;
Since our test-mutator is based on XTA, we can use all its effects.&lt;br /&gt;
&lt;br /&gt;
Here we are going to use the effect &amp;quot;BERTHASHOT&amp;quot; which is defined in the file &amp;lt;code&amp;gt;gamedata\explosions\berthashot.tdf&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As the name implies, that effect is usually used when a &amp;quot;Big Bertha&amp;quot; cannon fires a shot. We pick it because it might vaguely look like a smoking volcano.&lt;br /&gt;
&lt;br /&gt;
==How to spawn the CEG?==&lt;br /&gt;
So how can we make this &amp;quot;BERTHASHOT&amp;quot; effect appear on our volcano hill? Surely there must be some function call...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We clicked arond the [[CEG:Main]] page a bit and discover [[CEG:Calls]]&lt;br /&gt;
&lt;br /&gt;
It seems there are various ways to use CEGs, for example weapons can use them.&lt;br /&gt;
&lt;br /&gt;
Since we already decided we want to make a gadget, the relevant part is [[CEG:Calls#Synced_Lua_Gadget_CEGs]] which brings us to&lt;br /&gt;
[[Lua_SyncedCtrl#Other]]&lt;br /&gt;
&lt;br /&gt;
==Spring.SpawnCEG==&lt;br /&gt;
On [[Lua_SyncedCtrl#Other]] we discover the function Spring.SpawnCEG and its parameter list:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
( string &amp;quot;cegname&amp;quot; | number cegID,&lt;br /&gt;
   number posX = 0, number posY = 0, number posZ = 0,&lt;br /&gt;
   number dirX = 0, number dirY = 0, number dirZ = 0,&lt;br /&gt;
   number radius = 0, number damage = 0&lt;br /&gt;
 ) -&amp;gt; nil | boolean success, cegID&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*It seems to expect the name of the CEG as first parameter.&lt;br /&gt;
**We already got a CEG name: &amp;quot;BERTHASHOT&amp;quot;&lt;br /&gt;
*The posX,posY,posZ parameters seem to be the coordinates where the effect appears.&lt;br /&gt;
**Note to self: Find coordinates of some hill that looks like it needs some smoke.&lt;br /&gt;
*We have the effectname and where it should appear. The other parameters seems useless to our purpose so we ignore them.&lt;br /&gt;
**They will use default values.&lt;br /&gt;
&lt;br /&gt;
==Location, location, location==&lt;br /&gt;
We decide to use the map &#039;&#039;&#039;&amp;quot;DesertTriad&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
At the bottom right corner there seems a be small hill, perfect volcano material:&lt;br /&gt;
&lt;br /&gt;
[[File:DesertTriadHillCoordinates.jpg]]&lt;br /&gt;
&lt;br /&gt;
1) The hill where we want smoke to appear.&lt;br /&gt;
&lt;br /&gt;
2) The tooltip that shows the coordinates, when we mouse pointer onto the hill.&lt;br /&gt;
&lt;br /&gt;
Protip: Look at [[Gamedev:UnitsOfMeasurement]] to learn about coordinates system!&lt;br /&gt;
&lt;br /&gt;
==Putting parameters into Spawn.CEG==&lt;br /&gt;
Putting it together:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;Spring.SpawnCEG (&amp;quot;BERTHASHOT&amp;quot;, 3830,  390, 3600)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Where in the gadget should we put that?&lt;br /&gt;
Into &amp;lt;code&amp;gt;gadget:UnitFinished()&amp;lt;/code&amp;gt; callin, like with the Hello-Unit example?&lt;br /&gt;
Then the volcano would only smoke when a new unit is created.&lt;br /&gt;
&lt;br /&gt;
We need to find a better callin-function from the [[Lua:Callins]] page!&lt;br /&gt;
&lt;br /&gt;
Some callin that gets triggered regularly... so we can have nice constant smoking.&lt;br /&gt;
&lt;br /&gt;
We find:&lt;br /&gt;
&lt;br /&gt;
GameFrame(frame) - &#039;&#039;Called for every game simulation frame (30 per second). &#039;&#039;&lt;br /&gt;
&lt;br /&gt;
...thus we write:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
if gadgetHandler:IsSyncedCode() then&lt;br /&gt;
&lt;br /&gt;
	function gadget:GameFrame (f)&lt;br /&gt;
		if (f%10 == 0) then&lt;br /&gt;
			Spring.SpawnCEG (&amp;quot;BERTHASHOT&amp;quot;, 3830,  390, 3600)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
else --unsynced below&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if (f%10 == 0) then&amp;lt;/code&amp;gt; is added so that a new effect is only spawned every 10 frames.&lt;br /&gt;
&lt;br /&gt;
Also see http://answers.springlobby.info/questions/412/gadgetgameframe-modulo-operation-explained - oh 404! {{FIXME}}&lt;br /&gt;
&lt;br /&gt;
==Smoke in your eyes==&lt;br /&gt;
Save, start spring, look at the mountain.&lt;br /&gt;
&lt;br /&gt;
Do you see smoke? Likely not because this smoke-effect is only visible when units have vision on it.&lt;br /&gt;
&lt;br /&gt;
So either move a unit to the hill or type into chat:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
/cheat&lt;br /&gt;
/globallos&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now we finally see the smoke:&lt;br /&gt;
&lt;br /&gt;
[[File:DesertTriadVulcano.gif]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==What did we learn?==&lt;br /&gt;
Writting the script is just part one part of making gadget. &lt;br /&gt;
&lt;br /&gt;
From programming perspective, the volcano example is quite simple.&lt;br /&gt;
&lt;br /&gt;
The harder part was...&lt;br /&gt;
*finding a starting point&lt;br /&gt;
*setting up an editable archive&lt;br /&gt;
*finding the right functions&lt;br /&gt;
*learning about CEGs&lt;br /&gt;
*figuring out general &amp;quot;Spring stuff&amp;quot; like coordinates.&lt;br /&gt;
&lt;br /&gt;
For example had we not known that some particle-effects require vision to be visible, we might have been wondering forever why the volcano does not work - even if everything in the script was correct.&lt;br /&gt;
&lt;br /&gt;
Luckily, after a while this general &amp;quot;Spring stuff&amp;quot; becomes more familiar.&lt;br /&gt;
&lt;br /&gt;
{{FIXME}} wording&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=User:Knorke/Sandbox2&amp;diff=20872</id>
		<title>User:Knorke/Sandbox2</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=User:Knorke/Sandbox2&amp;diff=20872"/>
		<updated>2014-11-05T17:47:00Z</updated>

		<summary type="html">&lt;p&gt;Knorke: templates for tips,fixmes&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This text describes making gadgets.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Gadgets must be in a map or game=&lt;br /&gt;
For getting started with a widget, we could just put the file in the spring folder and start coding.&lt;br /&gt;
Unlike widgets, gadgets can not be used &amp;quot;locally&amp;quot; like this: They must be contained in a game or map archive.&lt;br /&gt;
So we must find a way to put the gadget into the game or map. &lt;br /&gt;
&lt;br /&gt;
{{Tip|If you just want to know &amp;quot;How to set up a test-folder&amp;quot; then skip directly to next chapter.}}&lt;br /&gt;
&lt;br /&gt;
The problem is that games and maps usually come in form of zipped archives, or in case of lobby downloaders as many small files.&lt;br /&gt;
&lt;br /&gt;
[[File:rapid_pool_filedust.png]]&lt;br /&gt;
&lt;br /&gt;
That makes adding new files cumbersome:&lt;br /&gt;
#Unpack the archive&lt;br /&gt;
#Add the new script file or edit it&lt;br /&gt;
#Repack the archive&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
So we must turn a map or game into an .sdd archive.&lt;br /&gt;
&lt;br /&gt;
That is explain in more detail in general modding tutorial: ADDLINK FIXME&lt;br /&gt;
&lt;br /&gt;
For first experiment it does not matter if the gadget is in the map or in the game.&lt;br /&gt;
&lt;br /&gt;
Another way is to create a test-mutator. That is basically a game that &amp;quot;includes&amp;quot; another game, like an add-on.&lt;br /&gt;
The advantages are:&lt;br /&gt;
* No need to edit existing game and maybe run into problems.&lt;br /&gt;
* The test-game filesize stays small enough to share easily with others, to get help.&lt;br /&gt;
* One can still use all the units, features &amp;amp; effects of the original game. That is useful for testing.&lt;br /&gt;
&lt;br /&gt;
Personally I recommend the test-mutator.&lt;br /&gt;
XTA is a good canidate as base-game choice because:&lt;br /&gt;
*in some ways it is more basic&lt;br /&gt;
*the unitnames are human-readable. For example &amp;quot;arm_windgenerator&amp;quot; instead of &amp;quot;armwingntor&amp;quot;&lt;br /&gt;
*Some games try to hide as much engine GUI as possible, however for testing that is not so useful.&lt;br /&gt;
&lt;br /&gt;
=The Test Mutator folder=&lt;br /&gt;
1) Create folder: games\MyLuaStuff.sdd&lt;br /&gt;
&lt;br /&gt;
2) Create file: games\MyLuaStuff.sdd\modinfo.lua  (  [[Modinfo.lua]]  )&lt;br /&gt;
&lt;br /&gt;
With this content:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
return {&lt;br /&gt;
  name=&#039;XTA LuaStuff&#039;,&lt;br /&gt;
  description=&#039;lolool&#039;,&lt;br /&gt;
  URL=&#039;http://code.google.com/p/xta-springrts/&#039;,&lt;br /&gt;
  shortname=&#039;XTA&#039;,&lt;br /&gt;
  version = &#039;9.744&#039;,&lt;br /&gt;
  mutator=&#039;LuaStuff&#039;,&lt;br /&gt;
  game=&#039;Total Annihilation&#039;,&lt;br /&gt;
  shortGame=&#039;TA&#039;,&lt;br /&gt;
  depend = {&amp;quot;XTA 9.744&amp;quot;},&lt;br /&gt;
  modtype=1,&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt; &lt;br /&gt;
{{FIXME}} mutator details, can it work with any xta version&lt;br /&gt;
&lt;br /&gt;
3) Test with spring.exe if the mutator shows in game list and can be played&lt;br /&gt;
&lt;br /&gt;
=First gadget: Welcome, new unit!=&lt;br /&gt;
&lt;br /&gt;
1) Create folders: games\MyLuaStuff.sdd\LuaRules\gadgets&lt;br /&gt;
&lt;br /&gt;
2) Create file: games\MyLuaStuff.sdd\LuaRules\gadgets\mytestgadget.lua&lt;br /&gt;
&lt;br /&gt;
3) For first widget we had done an empty widget that did nothing. In the widget-selector-menu we could still check if things were working right.&lt;br /&gt;
So we just take the Hello-Unit widget example and turn it into a gadget:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function gadget:GetInfo()&lt;br /&gt;
  return {&lt;br /&gt;
    name      = &amp;quot;test gadget&amp;quot;,&lt;br /&gt;
    desc      = &amp;quot;testing Lua things&amp;quot;,&lt;br /&gt;
    author    = &amp;quot;your name&amp;quot;,&lt;br /&gt;
    date      = &amp;quot;today&amp;quot;,&lt;br /&gt;
    license   = &amp;quot;GNU GPL, v2&amp;quot;,&lt;br /&gt;
    layer     = 0,&lt;br /&gt;
    enabled   = true,&lt;br /&gt;
  }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if gadgetHandler:IsSyncedCode() then&lt;br /&gt;
&lt;br /&gt;
function gadget:UnitFinished(unitID, unitDefID, teamID)&lt;br /&gt;
	Spring.Echo (&amp;quot;Welcome, new unit!&amp;quot;)	&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
else --unsynced below&lt;br /&gt;
&lt;br /&gt;
end&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We notice it looks very similiar to the widget, except instead of widget::xxx there is gadget:xxx&lt;br /&gt;
&lt;br /&gt;
The GetInfo()-thing again contains some informations about the script, but is otherwise not interessting and to save space will be left out when posting code.&lt;br /&gt;
&lt;br /&gt;
4) Load the game and build a few units. The gadget should welcome each unit.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Vulcano example=&lt;br /&gt;
An example of the process when making gadget.&lt;br /&gt;
&lt;br /&gt;
Pretend you are making a map and want to add a vulcano.&lt;br /&gt;
[[File:thinkingAboutVulcano.png]]&lt;br /&gt;
&lt;br /&gt;
{{Tip|If we wanted, at this point we could move the Lua into a map-archive. But for testing it is easier to continue using the test-mutator-game.}}&lt;br /&gt;
&lt;br /&gt;
==Define vulcano problem== &lt;br /&gt;
We want to make a vulcano. Now need to think  &#039;&#039;what excactly is this vulcano is supposed to do.&#039;&#039;&lt;br /&gt;
*Should the vulcano damage near units?&lt;br /&gt;
*Should it throw burning rocks across the map?&lt;br /&gt;
*Should it merely be a visual effect, just some smoke on a hill?&lt;br /&gt;
&lt;br /&gt;
For this tutorial we chose the last option. (superlame!)&lt;br /&gt;
&lt;br /&gt;
==How to make smoke==&lt;br /&gt;
Now that we know we want to make smoke, the new question is: How to make smoke?&lt;br /&gt;
One way is to use Spring&#039;s particle system called [[CEG:Main]]&lt;br /&gt;
Games can use these CEGS to create explosion, muzzle flashes, fire and so on.&lt;br /&gt;
&lt;br /&gt;
Since our test-mutator is based on XTA, we can use all its effects.&lt;br /&gt;
&lt;br /&gt;
Here we are going to use the effect &amp;quot;BERTHASHOT&amp;quot; which is defined in the file &amp;lt;code&amp;gt;gamedata\explosions\berthashot.tdf&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As the name implies, that effect is usually used when a &amp;quot;Big Bertha&amp;quot; cannon fires a shot. We pick it because it might vaguely look like a smoking vulcano.&lt;br /&gt;
&lt;br /&gt;
==How to spawn the CEG?==&lt;br /&gt;
So how can we make this &amp;quot;BERTHASHOT&amp;quot; effect appear on our vulcano hill? Surely there must be some function call...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We clicked arond the [[CEG:Main]] page a bit and discover [[CEG:Calls]]&lt;br /&gt;
&lt;br /&gt;
It seems there are various ways to use CEGs, for example weapons can use them.&lt;br /&gt;
&lt;br /&gt;
Since we already decided we want to make a gadget, the relevant part is [[CEG:Calls#Synced_Lua_Gadget_CEGs]] which brings us to&lt;br /&gt;
[[Lua_SyncedCtrl#Other]]&lt;br /&gt;
&lt;br /&gt;
==Spring.SpawnCEG==&lt;br /&gt;
On [[Lua_SyncedCtrl#Other]] we discover the function Spring.SpawnCEG and its parameter list:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
( string &amp;quot;cegname&amp;quot; | number cegID,&lt;br /&gt;
   number posX = 0, number posY = 0, number posZ = 0,&lt;br /&gt;
   number dirX = 0, number dirY = 0, number dirZ = 0,&lt;br /&gt;
   number radius = 0, number damage = 0&lt;br /&gt;
 ) -&amp;gt; nil | boolean success, cegID&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*It seems to expect the name of the CEG as first parameter.&lt;br /&gt;
**We already got a CEG name: &amp;quot;BERTHASHOT&amp;quot;&lt;br /&gt;
*The posX,posY,posZ parameters seem to be the coordinates where the effect appears.&lt;br /&gt;
**Note to self: Find coordinates of some hill that looks like it needs some smoke.&lt;br /&gt;
*We have the effectname and where it should appear. The other parameters seems useless to our purpose so we ignore them.&lt;br /&gt;
**They will use default values.&lt;br /&gt;
&lt;br /&gt;
==Location, location, location==&lt;br /&gt;
We decide to use the map &#039;&#039;&#039;&amp;quot;DesertTriad&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
At the bottom right corner there seems a be small hill, perfect vulcano material:&lt;br /&gt;
&lt;br /&gt;
[[File:DesertTriadHillCoordinates.jpg]]&lt;br /&gt;
&lt;br /&gt;
1) The hill where we want smoke to appear.&lt;br /&gt;
&lt;br /&gt;
2) The tooltip that shows the coordinates, when we mouse pointer onto the hill.&lt;br /&gt;
&lt;br /&gt;
Protip: Look at [[Gamedev:UnitsOfMeasurement]] to learn about coordinates system!&lt;br /&gt;
&lt;br /&gt;
==Putting parameters into Spawn.CEG==&lt;br /&gt;
Putting it together:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;Spring.SpawnCEG (&amp;quot;BERTHASHOT&amp;quot;, 3830,  390, 3600)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Where in the gadget should we put that?&lt;br /&gt;
Into &amp;lt;code&amp;gt;gadget:UnitFinished()&amp;lt;/code&amp;gt; callin, like with the Hello-Unit example?&lt;br /&gt;
Then the vulcano would only smoke when a new unit is created.&lt;br /&gt;
&lt;br /&gt;
We need to find a better callin-function from the [[Lua:Callins]] page!&lt;br /&gt;
&lt;br /&gt;
Some callin that gets triggered regularly... so we can have nice constant smoking.&lt;br /&gt;
&lt;br /&gt;
We find:&lt;br /&gt;
&lt;br /&gt;
GameFrame(frame) - &#039;&#039;Called for every game simulation frame (30 per second). &#039;&#039;&lt;br /&gt;
&lt;br /&gt;
...thus we write:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
if gadgetHandler:IsSyncedCode() then&lt;br /&gt;
&lt;br /&gt;
	function gadget:GameFrame (f)&lt;br /&gt;
		if (f%10 == 0) then&lt;br /&gt;
			Spring.SpawnCEG (&amp;quot;BERTHASHOT&amp;quot;, 3830,  390, 3600)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
else --unsynced below&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if (f%10 == 0) then&amp;lt;/code&amp;gt; is added so that a new effect is only spawned every 10 frames.&lt;br /&gt;
&lt;br /&gt;
Also see http://answers.springlobby.info/questions/412/gadgetgameframe-modulo-operation-explained - oh 404! {{FIXME}}&lt;br /&gt;
&lt;br /&gt;
==Smoke in your eyes==&lt;br /&gt;
Save, start spring, look at the mountain.&lt;br /&gt;
&lt;br /&gt;
Do you see smoke? Likely not because this smoke-effect is only visible when units have vision on it.&lt;br /&gt;
&lt;br /&gt;
So either move a unit to the hill or type into chat:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
/cheat&lt;br /&gt;
/globallos&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now we finally see the smoke:&lt;br /&gt;
&lt;br /&gt;
[[File:DesertTriadVulcano.gif]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==What did we learn?==&lt;br /&gt;
Writting the script is just part one part of making gadget. &lt;br /&gt;
&lt;br /&gt;
From programming perspective, the vulcano example is quite simple.&lt;br /&gt;
&lt;br /&gt;
The harder part was...&lt;br /&gt;
*finding a starting point&lt;br /&gt;
*setting up an editable archive&lt;br /&gt;
*finding the right functions&lt;br /&gt;
*learning about CEGs&lt;br /&gt;
*figuring out general &amp;quot;Spring stuff&amp;quot; like coordinates.&lt;br /&gt;
&lt;br /&gt;
For example had we not known that some particle-effects require vision to be visible, we might have been wondering forever why the vulcano does not work - even if everything in the script was correct.&lt;br /&gt;
&lt;br /&gt;
Luckily, after a while this general &amp;quot;Spring stuff&amp;quot; becomes more familiar.&lt;br /&gt;
&lt;br /&gt;
{{FIXME}} wording&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=User:Knorke/Sandbox2&amp;diff=20871</id>
		<title>User:Knorke/Sandbox2</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=User:Knorke/Sandbox2&amp;diff=20871"/>
		<updated>2014-11-05T15:20:09Z</updated>

		<summary type="html">&lt;p&gt;Knorke: typos&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This text describes making gadgets.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Gadgets must be in a map or game=&lt;br /&gt;
For getting started with a widget, we could just put the file in the spring folder and start coding.&lt;br /&gt;
Unlike widgets, gadgets can not be used &amp;quot;locally&amp;quot; like this: They must be contained in a game or map archive.&lt;br /&gt;
So we must find a way to put the gadget into the game or map. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;gt;&amp;gt;&amp;gt; If you just want to know &amp;quot;How to do this&amp;quot; then skip directly to next chapter. &amp;lt;&amp;lt;&amp;lt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The problem is that games and maps usually come in form of zipped archives, or in case of lobby downloaders as many small files.&lt;br /&gt;
&lt;br /&gt;
[[File:rapid_pool_filedust.png]]&lt;br /&gt;
&lt;br /&gt;
That makes adding new files cumbersome:&lt;br /&gt;
#Unpack the archive&lt;br /&gt;
#Add the new script file or edit it&lt;br /&gt;
#Repack the archive&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
So we must turn a map or game into an .sdd archive.&lt;br /&gt;
&lt;br /&gt;
That is explain in more detail in general modding tutorial: ADDLINK FIXME&lt;br /&gt;
&lt;br /&gt;
For first experiment it does not matter if the gadget is in the map or in the game.&lt;br /&gt;
&lt;br /&gt;
Another way is to create a test-mutator. That is basically a game that &amp;quot;includes&amp;quot; another game, like an add-on.&lt;br /&gt;
The advantages are:&lt;br /&gt;
* No need to edit existing game and maybe run into problems.&lt;br /&gt;
* The test-game filesize stays small enough to share easily with others, to get help.&lt;br /&gt;
* One can still use all the units, features &amp;amp; effects of the original game. That is useful for testing.&lt;br /&gt;
&lt;br /&gt;
Personally I recommend the test-mutator.&lt;br /&gt;
XTA is a good canidate as base-game choice because:&lt;br /&gt;
*in some ways it is more basic&lt;br /&gt;
*the unitnames are human-readable. For example &amp;quot;arm_windgenerator&amp;quot; instead of &amp;quot;armwingntor&amp;quot;&lt;br /&gt;
*Some games try to hide as much engine GUI as possible, however for testing that is not so useful.&lt;br /&gt;
&lt;br /&gt;
=The Test Mutator folder=&lt;br /&gt;
1) Create folder: games\MyLuaStuff.sdd&lt;br /&gt;
&lt;br /&gt;
2) Create file: games\MyLuaStuff.sdd\modinfo.lua  (  [[Modinfo.lua]]  )&lt;br /&gt;
&lt;br /&gt;
With this content:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
return {&lt;br /&gt;
  name=&#039;XTA LuaStuff&#039;,&lt;br /&gt;
  description=&#039;lolool&#039;,&lt;br /&gt;
  URL=&#039;http://code.google.com/p/xta-springrts/&#039;,&lt;br /&gt;
  shortname=&#039;XTA&#039;,&lt;br /&gt;
  version = &#039;9.744&#039;,&lt;br /&gt;
  mutator=&#039;LuaStuff&#039;,&lt;br /&gt;
  game=&#039;Total Annihilation&#039;,&lt;br /&gt;
  shortGame=&#039;TA&#039;,&lt;br /&gt;
  depend = {&amp;quot;XTA 9.744&amp;quot;},&lt;br /&gt;
  modtype=1,&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt; &lt;br /&gt;
FIXME: mutator details, can it work with any xta version&lt;br /&gt;
&lt;br /&gt;
3) Test with spring.exe if the mutator shows in game list and can be played&lt;br /&gt;
&lt;br /&gt;
=First gadget: Welcome, new unit!=&lt;br /&gt;
&lt;br /&gt;
1) Create folders: games\MyLuaStuff.sdd\LuaRules\gadgets&lt;br /&gt;
&lt;br /&gt;
2) Create file: games\MyLuaStuff.sdd\LuaRules\gadgets\mytestgadget.lua&lt;br /&gt;
&lt;br /&gt;
3) For first widget we had done an empty widget that did nothing. In the widget-selector-menu we could still check if things were working right.&lt;br /&gt;
So we just take the Hello-Unit widget example and turn it into a gadget:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function gadget:GetInfo()&lt;br /&gt;
  return {&lt;br /&gt;
    name      = &amp;quot;test gadget&amp;quot;,&lt;br /&gt;
    desc      = &amp;quot;testing Lua things&amp;quot;,&lt;br /&gt;
    author    = &amp;quot;your name&amp;quot;,&lt;br /&gt;
    date      = &amp;quot;today&amp;quot;,&lt;br /&gt;
    license   = &amp;quot;GNU GPL, v2&amp;quot;,&lt;br /&gt;
    layer     = 0,&lt;br /&gt;
    enabled   = true,&lt;br /&gt;
  }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if gadgetHandler:IsSyncedCode() then&lt;br /&gt;
&lt;br /&gt;
function gadget:UnitFinished(unitID, unitDefID, teamID)&lt;br /&gt;
	Spring.Echo (&amp;quot;Welcome, new unit!&amp;quot;)	&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
else --unsynced below&lt;br /&gt;
&lt;br /&gt;
end&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We notice it looks very similiar to the widget, except instead of widget::xxx there is gadget:xxx&lt;br /&gt;
&lt;br /&gt;
The GetInfo()-thing again contains some informations about the script, but is otherwise not interessting and to save space will be left out when posting code.&lt;br /&gt;
&lt;br /&gt;
4) Load the game and build a few units. The gadget should welcome each unit.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Vulcano example=&lt;br /&gt;
An example of the process when making gadget.&lt;br /&gt;
&lt;br /&gt;
Pretend you are making a map and want to add a vulcano.&lt;br /&gt;
[[File:thinkingAboutVulcano.png]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note:&#039;&#039; If we wanted, at this point we could move the Lua into a map-archive. But for testing it is easier to continue using the test-mutator-game.&lt;br /&gt;
&lt;br /&gt;
==Define vulcano problem== &lt;br /&gt;
We want to make a vulcano. Now need to think  &#039;&#039;what excactly is this vulcano is supposed to do.&#039;&#039;&lt;br /&gt;
*Should the vulcano damage near units?&lt;br /&gt;
*Should it throw burning rocks across the map?&lt;br /&gt;
*Should it merely be a visual effect, just some smoke on a hill?&lt;br /&gt;
&lt;br /&gt;
For this tutorial we chose the last option. (superlame!)&lt;br /&gt;
&lt;br /&gt;
==How to make smoke==&lt;br /&gt;
Now that we know we want to make smoke, the new question is: How to make smoke?&lt;br /&gt;
One way is to use Spring&#039;s particle system called [[CEG:Main]]&lt;br /&gt;
Games can use these CEGS to create explosion, muzzle flashes, fire and so on.&lt;br /&gt;
&lt;br /&gt;
Since our test-mutator is based on XTA, we can use all its effects.&lt;br /&gt;
&lt;br /&gt;
Here we are going to use the effect &amp;quot;BERTHASHOT&amp;quot; which is defined in the file &amp;lt;code&amp;gt;gamedata\explosions\berthashot.tdf&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As the name implies, that effect is usually used when a &amp;quot;Big Bertha&amp;quot; cannon fires a shot. We pick it because it might vaguely look like a smoking vulcano.&lt;br /&gt;
&lt;br /&gt;
==How to spawn the CEG?==&lt;br /&gt;
So how can we make this &amp;quot;BERTHASHOT&amp;quot; effect appear on our vulcano hill? Surely there must be some function call...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We clicked arond the [[CEG:Main]] page a bit and discover [[CEG:Calls]]&lt;br /&gt;
&lt;br /&gt;
It seems there are various ways to use CEGs, for example weapons can use them.&lt;br /&gt;
&lt;br /&gt;
Since we already decided we want to make a gadget, the relevant part is [[CEG:Calls#Synced_Lua_Gadget_CEGs]] which brings us to&lt;br /&gt;
[[Lua_SyncedCtrl#Other]]&lt;br /&gt;
&lt;br /&gt;
==Spring.SpawnCEG==&lt;br /&gt;
On [[Lua_SyncedCtrl#Other]] we discover the function Spring.SpawnCEG and its parameter list:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
( string &amp;quot;cegname&amp;quot; | number cegID,&lt;br /&gt;
   number posX = 0, number posY = 0, number posZ = 0,&lt;br /&gt;
   number dirX = 0, number dirY = 0, number dirZ = 0,&lt;br /&gt;
   number radius = 0, number damage = 0&lt;br /&gt;
 ) -&amp;gt; nil | boolean success, cegID&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*It seems to expect the name of the CEG as first parameter.&lt;br /&gt;
**We already got a CEG name: &amp;quot;BERTHASHOT&amp;quot;&lt;br /&gt;
*The posX,posY,posZ parameters seem to be the coordinates where the effect appears.&lt;br /&gt;
**Note to self: Find coordinates of some hill that looks like it needs some smoke.&lt;br /&gt;
*We have the effectname and where it should appear. The other parameters seems useless to our purpose so we ignore them.&lt;br /&gt;
**They will use default values.&lt;br /&gt;
&lt;br /&gt;
==Location, location, location==&lt;br /&gt;
We decide to use the map &#039;&#039;&#039;&amp;quot;DesertTriad&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
At the bottom right corner there seems a be small hill, perfect vulcano material:&lt;br /&gt;
&lt;br /&gt;
[[File:DesertTriadHillCoordinates.jpg]]&lt;br /&gt;
&lt;br /&gt;
1) The hill where we want smoke to appear.&lt;br /&gt;
&lt;br /&gt;
2) The tooltip that shows the coordinates, when we mouse pointer onto the hill.&lt;br /&gt;
&lt;br /&gt;
Protip: Look at [[Gamedev:UnitsOfMeasurement]] to learn about coordinates system!&lt;br /&gt;
&lt;br /&gt;
==Putting parameters into Spawn.CEG==&lt;br /&gt;
Putting it together:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;Spring.SpawnCEG (&amp;quot;BERTHASHOT&amp;quot;, 3830,  390, 3600)&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Where in the gadget should we put that?&lt;br /&gt;
Into &amp;lt;code&amp;gt;gadget:UnitFinished()&amp;lt;/code&amp;gt; callin, like with the Hello-Unit example?&lt;br /&gt;
Then the vulcano would only smoke when a new unit is created.&lt;br /&gt;
&lt;br /&gt;
We need to find a better callin-function from the [[Lua:Callins]] page!&lt;br /&gt;
&lt;br /&gt;
Some callin that gets triggered regularly... so we can have nice constant smoking.&lt;br /&gt;
&lt;br /&gt;
We find:&lt;br /&gt;
&lt;br /&gt;
GameFrame(frame) - &#039;&#039;Called for every game simulation frame (30 per second). &#039;&#039;&lt;br /&gt;
&lt;br /&gt;
...thus we write:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
if gadgetHandler:IsSyncedCode() then&lt;br /&gt;
&lt;br /&gt;
	function gadget:GameFrame (f)&lt;br /&gt;
		if (f%10 == 0) then&lt;br /&gt;
			Spring.SpawnCEG (&amp;quot;BERTHASHOT&amp;quot;, 3830,  390, 3600)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
else --unsynced below&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if (f%10 == 0) then&amp;lt;/code&amp;gt; is added so that a new effect is only spawned every 10 frames.&lt;br /&gt;
&lt;br /&gt;
Also see http://answers.springlobby.info/questions/412/gadgetgameframe-modulo-operation-explained - oh 404! (FIXME)&lt;br /&gt;
&lt;br /&gt;
==Smoke in your eyes==&lt;br /&gt;
Save, start spring, look at the mountain.&lt;br /&gt;
&lt;br /&gt;
Do you see smoke? Likely not because this smoke-effect is only visible when units have vision on it.&lt;br /&gt;
&lt;br /&gt;
So either move a unit to the hill or type into chat:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
/cheat&lt;br /&gt;
/globallos&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now we finally see the smoke:&lt;br /&gt;
&lt;br /&gt;
[[File:DesertTriadVulcano.gif]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==What did we learn?==&lt;br /&gt;
Writting the script is just part one part of making gadget. &lt;br /&gt;
&lt;br /&gt;
From programming perspective, the vulcano example is quite simple.&lt;br /&gt;
&lt;br /&gt;
The harder part was...&lt;br /&gt;
*finding a starting point&lt;br /&gt;
*setting up an editable archive&lt;br /&gt;
*finding the right functions&lt;br /&gt;
*learning about CEGs&lt;br /&gt;
*figuring out general &amp;quot;Spring stuff&amp;quot; like coordinates.&lt;br /&gt;
&lt;br /&gt;
For example had we not known that some particle-effects require vision to be visible, we might have been wondering forever why the vulcano does not work - even if everything in the script was correct.&lt;br /&gt;
&lt;br /&gt;
Luckily, after a while this general &amp;quot;Spring stuff&amp;quot; becomes more familiar.&lt;br /&gt;
&lt;br /&gt;
FIXME: wording&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=User:Knorke/Sandbox2&amp;diff=20870</id>
		<title>User:Knorke/Sandbox2</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=User:Knorke/Sandbox2&amp;diff=20870"/>
		<updated>2014-11-05T00:55:42Z</updated>

		<summary type="html">&lt;p&gt;Knorke: /* Vulcano example */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This text describes making gadgets.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Gadgets must be in a map or game=&lt;br /&gt;
For getting started with a widget, we could just put the file in the spring folder and start coding.&lt;br /&gt;
Unlike widgets, gadgets can not be used &amp;quot;locally&amp;quot; like this: They must be contained in a game or map archive.&lt;br /&gt;
So we must find a way to put the gadget into the game or map. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;gt;&amp;gt;&amp;gt; If you just want to know &amp;quot;How to do this&amp;quot; then skip directly to next chapter. &amp;lt;&amp;lt;&amp;lt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The problem is that games and maps usually come in form of zipped archives, or in case of lobby downloaders as many small files.&lt;br /&gt;
&lt;br /&gt;
[[File:rapid_pool_filedust.png]]&lt;br /&gt;
&lt;br /&gt;
That makes adding new files cumbersome:&lt;br /&gt;
#Unpack the archive&lt;br /&gt;
#Add the new script file or edit it&lt;br /&gt;
#Repack the archive&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
So we must turn a map or game into an .sdd archive.&lt;br /&gt;
&lt;br /&gt;
That is explain in more detail in general modding tutorial: ADDLINK FIXME&lt;br /&gt;
&lt;br /&gt;
For first experiment it does not matter if the gadget is in the map or in the game.&lt;br /&gt;
&lt;br /&gt;
Another way is to create a test-mutator. That is basically a game that &amp;quot;includes&amp;quot; another game, like an add-on.&lt;br /&gt;
The advantages are:&lt;br /&gt;
* No need to edit existing game and maybe run into problems.&lt;br /&gt;
* The test-game filesize stays small enough to share easily with others, to get help.&lt;br /&gt;
* One can still use all the units, features &amp;amp; effects of the original game. That is useful for testing.&lt;br /&gt;
&lt;br /&gt;
Personally I recommend the test-mutator.&lt;br /&gt;
XTA is a good canidate as base-game choice because:&lt;br /&gt;
*in some ways it is more basic&lt;br /&gt;
*the unitnames are human-readable. For example &amp;quot;arm_windgenerator&amp;quot; instead of &amp;quot;armwingntor&amp;quot;&lt;br /&gt;
*Some games try to hide as much engine GUI as possible, however for testing that is not so useful.&lt;br /&gt;
&lt;br /&gt;
=The Test Mutator folder=&lt;br /&gt;
1) Create folder: games\MyLuaStuff.sdd&lt;br /&gt;
&lt;br /&gt;
2) Create file: games\MyLuaStuff.sdd\modinfo.lua  (  [[Modinfo.lua]]  )&lt;br /&gt;
&lt;br /&gt;
With this content:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
return {&lt;br /&gt;
  name=&#039;XTA LuaStuff&#039;,&lt;br /&gt;
  description=&#039;lolool&#039;,&lt;br /&gt;
  URL=&#039;http://code.google.com/p/xta-springrts/&#039;,&lt;br /&gt;
  shortname=&#039;XTA&#039;,&lt;br /&gt;
  version = &#039;9.744&#039;,&lt;br /&gt;
  mutator=&#039;LuaStuff&#039;,&lt;br /&gt;
  game=&#039;Total Annihilation&#039;,&lt;br /&gt;
  shortGame=&#039;TA&#039;,&lt;br /&gt;
  depend = {&amp;quot;XTA 9.744&amp;quot;},&lt;br /&gt;
  modtype=1,&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt; &lt;br /&gt;
FIXME: mutator details, can it work with any xta version&lt;br /&gt;
&lt;br /&gt;
3) Test with spring.exe if the mutator shows in game list and can be played&lt;br /&gt;
&lt;br /&gt;
=First gadget: Welcome, new unit!=&lt;br /&gt;
&lt;br /&gt;
1) Create folders: games\MyLuaStuff.sdd\LuaRules\gadgets&lt;br /&gt;
&lt;br /&gt;
2) Create file: games\MyLuaStuff.sdd\LuaRules\gadgets\mytestgadget.lua&lt;br /&gt;
&lt;br /&gt;
3) For first widget we had done an empty widget that did nothing. In the widget-selector-menu we could still check if things were working right.&lt;br /&gt;
So we just take the Hello-Unit widget example and turn it into a gadget:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function gadget:GetInfo()&lt;br /&gt;
  return {&lt;br /&gt;
    name      = &amp;quot;test gadget&amp;quot;,&lt;br /&gt;
    desc      = &amp;quot;testing Lua things&amp;quot;,&lt;br /&gt;
    author    = &amp;quot;your name&amp;quot;,&lt;br /&gt;
    date      = &amp;quot;today&amp;quot;,&lt;br /&gt;
    license   = &amp;quot;GNU GPL, v2&amp;quot;,&lt;br /&gt;
    layer     = 0,&lt;br /&gt;
    enabled   = true,&lt;br /&gt;
  }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if gadgetHandler:IsSyncedCode() then&lt;br /&gt;
&lt;br /&gt;
function gadget:UnitFinished(unitID, unitDefID, teamID)&lt;br /&gt;
	Spring.Echo (&amp;quot;Welcome, new unit!&amp;quot;)	&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
else --unsynced below&lt;br /&gt;
&lt;br /&gt;
end&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We notice it looks very similiar to the widget, except instead of widget::xxx there is gadget:xxx&lt;br /&gt;
&lt;br /&gt;
The GetInfo()-thing again contains some informations about the script, but is otherwise not interessting and to save space will be left out when posting code.&lt;br /&gt;
&lt;br /&gt;
4) Load the game and build a few units. The gadget should welcome each unit.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Vulcano example=&lt;br /&gt;
An example of the process when making gadget.&lt;br /&gt;
&lt;br /&gt;
Pretend you are making a map and want to add a vulcano.&lt;br /&gt;
[[File:thinkingAboutVulcano.png]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note:&#039;&#039; If we wanted, at this point we could move the Lua into a map-archive. But for testing it is easier to continue using the test-mutator-game.&lt;br /&gt;
&lt;br /&gt;
==Define vulcano problem== &lt;br /&gt;
We want to make a vulcano. Now need to think  &#039;&#039;what excactly is this vulcano is supposed to do.&#039;&#039;&lt;br /&gt;
*Should the vulcano damage near units?&lt;br /&gt;
*Should it throw burning rocks across the map?&lt;br /&gt;
*Should it merely be a visual effect, just some smoke on a hill?&lt;br /&gt;
&lt;br /&gt;
For this tutorial we just the last option. (superlame!)&lt;br /&gt;
&lt;br /&gt;
==How to make smoke==&lt;br /&gt;
Now that we know we want to make smoke, the new question is: How to make smoke?&lt;br /&gt;
One way is to use Spring&#039;s particle system called [[CEG:Main]]&lt;br /&gt;
Games can use these CEGS to create explosion, muzzle flashes, fire and so on.&lt;br /&gt;
&lt;br /&gt;
Since our test-mutator is based on XTA, we can use all its effects.&lt;br /&gt;
&lt;br /&gt;
Here we are going to use the effect &amp;quot;BERTHASHOT&amp;quot; which is defined in the file &amp;lt;code&amp;gt;gamedata\explosions\berthashot.tdf&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As the name implies, that effect is usually used when a &amp;quot;Big Bertha&amp;quot; cannon fires a shot. We pick it because it might vaguely look like a smoking vulcano.&lt;br /&gt;
&lt;br /&gt;
==How to spawn the CEG?==&lt;br /&gt;
So how can we make this &amp;quot;BERTHASHOT&amp;quot; effect appear on our vulcano hill? Surely there must be some function call...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We clicked arond the [[CEG:Main]] page a bit and discover [[CEG:Calls]]&lt;br /&gt;
&lt;br /&gt;
It seems there are various ways to use CEGs, for example weapons can use them.&lt;br /&gt;
&lt;br /&gt;
Since we already decided we want to make a gadget, the relevant part is [[CEG:Calls#Synced_Lua_Gadget_CEGs]] which brings us to&lt;br /&gt;
[[Lua_SyncedCtrl#Other]]&lt;br /&gt;
&lt;br /&gt;
==Spring.SpawnCEG==&lt;br /&gt;
On [[Lua_SyncedCtrl#Other]] we discover the function Spring.SpawnCEG and its parameter list:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
( string &amp;quot;cegname&amp;quot; | number cegID,&lt;br /&gt;
   number posX = 0, number posY = 0, number posZ = 0,&lt;br /&gt;
   number dirX = 0, number dirY = 0, number dirZ = 0,&lt;br /&gt;
   number radius = 0, number damage = 0&lt;br /&gt;
 ) -&amp;gt; nil | boolean success, cegID&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*It seems to expect the name of the CEG as first parameter.&lt;br /&gt;
**We already got a CEG name: &amp;quot;BERTHASHOT&amp;quot;&lt;br /&gt;
*The posX,posY,posZ parameters seem to be the coordinates where the effect appears.&lt;br /&gt;
**Note to self: Find coordinates of some hill that looks like it needs some smoke.&lt;br /&gt;
*We have the effectname and where it should appear. The other parameters seems useless to our purpose so we ignore them.&lt;br /&gt;
**They will use default values.&lt;br /&gt;
&lt;br /&gt;
==Location, location, location==&lt;br /&gt;
We decide to use the map &#039;&#039;&#039;&amp;quot;DesertTriad&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
At the bottom right corner there seems a be small hill, perfect vulcano material:&lt;br /&gt;
&lt;br /&gt;
[[File:DesertTriadHillCoordinates.jpg]]&lt;br /&gt;
&lt;br /&gt;
1) The hill where we want smoke to appear.&lt;br /&gt;
&lt;br /&gt;
2) The tooltip that shows the coordinates, when we mouse pointer onto the hill.&lt;br /&gt;
&lt;br /&gt;
Protip: Look at [[Gamedev:UnitsOfMeasurement]] to learn about coordinates system!&lt;br /&gt;
&lt;br /&gt;
==Putting parameters into Spawn.CEG==&lt;br /&gt;
Putting it together:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;Spring.SpawnCEG (&amp;quot;BERTHASHOT&amp;quot;, 3830,  390, 3600)&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Where in the gadget should we put that?&lt;br /&gt;
Into &amp;lt;code&amp;gt;gadget:UnitFinished()&amp;lt;code&amp;gt; callin, like with the Hello-Unit example?&lt;br /&gt;
Then the vulcano would only smoke when a new unit is created.&lt;br /&gt;
&lt;br /&gt;
We need to find a better callin-function from the [[Lua:Callins]] page!&lt;br /&gt;
&lt;br /&gt;
Some callin that gets triggered regularly... so we can have nice constant smoking.&lt;br /&gt;
&lt;br /&gt;
We find:&lt;br /&gt;
&lt;br /&gt;
GameFrame(frame) - &#039;&#039;Called for every game simulation frame (30 per second). &#039;&#039;&lt;br /&gt;
&lt;br /&gt;
...thus we write:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
if gadgetHandler:IsSyncedCode() then&lt;br /&gt;
&lt;br /&gt;
	function gadget:GameFrame (f)&lt;br /&gt;
		if (f%10 == 0) then&lt;br /&gt;
			Spring.SpawnCEG (&amp;quot;BERTHASHOT&amp;quot;, 3830,  390, 3600)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
else --unsynced below&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if (f%10 == 0) then&amp;lt;/code&amp;gt; is added so that a new effect is only spawned every 10 frames.&lt;br /&gt;
&lt;br /&gt;
Also see http://answers.springlobby.info/questions/412/gadgetgameframe-modulo-operation-explained - oh 404! (FIXME)&lt;br /&gt;
&lt;br /&gt;
==Smoke in your eyes==&lt;br /&gt;
Save, start spring, look at the mountain.&lt;br /&gt;
&lt;br /&gt;
Do you see smoke? Likely not because this smoke-effect is only visible when units have vision on it.&lt;br /&gt;
&lt;br /&gt;
So either move a unit to the hill or type into chat:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
/cheat&lt;br /&gt;
/globallos&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now we finally see the smoke:&lt;br /&gt;
&lt;br /&gt;
[[File:DesertTriadVulcano.gif]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==What did we learn?==&lt;br /&gt;
Writting the script is just part one part of making gadget. &lt;br /&gt;
&lt;br /&gt;
From programming perspective, the vulcano example is quite simple.&lt;br /&gt;
&lt;br /&gt;
The harder part was...&lt;br /&gt;
*finding a starting point&lt;br /&gt;
*setting up an editable archive&lt;br /&gt;
*finding the right functions&lt;br /&gt;
*learning about CEGs&lt;br /&gt;
*figuring out general &amp;quot;Spring stuff&amp;quot; like coordinates.&lt;br /&gt;
&lt;br /&gt;
For example had we not known that some particle-effects require vision to be visible, we might have been wondering forever why the vulcano does not work - even if everything in the script was correct.&lt;br /&gt;
&lt;br /&gt;
Luckily, after a while this general &amp;quot;Spring stuff&amp;quot; becomes more familiar.&lt;br /&gt;
&lt;br /&gt;
FIXME: wording&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=User:Knorke/Sandbox2&amp;diff=20869</id>
		<title>User:Knorke/Sandbox2</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=User:Knorke/Sandbox2&amp;diff=20869"/>
		<updated>2014-11-05T00:55:12Z</updated>

		<summary type="html">&lt;p&gt;Knorke: /* What did we learn? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This text describes making gadgets.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Gadgets must be in a map or game=&lt;br /&gt;
For getting started with a widget, we could just put the file in the spring folder and start coding.&lt;br /&gt;
Unlike widgets, gadgets can not be used &amp;quot;locally&amp;quot; like this: They must be contained in a game or map archive.&lt;br /&gt;
So we must find a way to put the gadget into the game or map. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;gt;&amp;gt;&amp;gt; If you just want to know &amp;quot;How to do this&amp;quot; then skip directly to next chapter. &amp;lt;&amp;lt;&amp;lt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The problem is that games and maps usually come in form of zipped archives, or in case of lobby downloaders as many small files.&lt;br /&gt;
&lt;br /&gt;
[[File:rapid_pool_filedust.png]]&lt;br /&gt;
&lt;br /&gt;
That makes adding new files cumbersome:&lt;br /&gt;
#Unpack the archive&lt;br /&gt;
#Add the new script file or edit it&lt;br /&gt;
#Repack the archive&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
So we must turn a map or game into an .sdd archive.&lt;br /&gt;
&lt;br /&gt;
That is explain in more detail in general modding tutorial: ADDLINK FIXME&lt;br /&gt;
&lt;br /&gt;
For first experiment it does not matter if the gadget is in the map or in the game.&lt;br /&gt;
&lt;br /&gt;
Another way is to create a test-mutator. That is basically a game that &amp;quot;includes&amp;quot; another game, like an add-on.&lt;br /&gt;
The advantages are:&lt;br /&gt;
* No need to edit existing game and maybe run into problems.&lt;br /&gt;
* The test-game filesize stays small enough to share easily with others, to get help.&lt;br /&gt;
* One can still use all the units, features &amp;amp; effects of the original game. That is useful for testing.&lt;br /&gt;
&lt;br /&gt;
Personally I recommend the test-mutator.&lt;br /&gt;
XTA is a good canidate as base-game choice because:&lt;br /&gt;
*in some ways it is more basic&lt;br /&gt;
*the unitnames are human-readable. For example &amp;quot;arm_windgenerator&amp;quot; instead of &amp;quot;armwingntor&amp;quot;&lt;br /&gt;
*Some games try to hide as much engine GUI as possible, however for testing that is not so useful.&lt;br /&gt;
&lt;br /&gt;
=The Test Mutator folder=&lt;br /&gt;
1) Create folder: games\MyLuaStuff.sdd&lt;br /&gt;
&lt;br /&gt;
2) Create file: games\MyLuaStuff.sdd\modinfo.lua  (  [[Modinfo.lua]]  )&lt;br /&gt;
&lt;br /&gt;
With this content:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
return {&lt;br /&gt;
  name=&#039;XTA LuaStuff&#039;,&lt;br /&gt;
  description=&#039;lolool&#039;,&lt;br /&gt;
  URL=&#039;http://code.google.com/p/xta-springrts/&#039;,&lt;br /&gt;
  shortname=&#039;XTA&#039;,&lt;br /&gt;
  version = &#039;9.744&#039;,&lt;br /&gt;
  mutator=&#039;LuaStuff&#039;,&lt;br /&gt;
  game=&#039;Total Annihilation&#039;,&lt;br /&gt;
  shortGame=&#039;TA&#039;,&lt;br /&gt;
  depend = {&amp;quot;XTA 9.744&amp;quot;},&lt;br /&gt;
  modtype=1,&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt; &lt;br /&gt;
FIXME: mutator details, can it work with any xta version&lt;br /&gt;
&lt;br /&gt;
3) Test with spring.exe if the mutator shows in game list and can be played&lt;br /&gt;
&lt;br /&gt;
=First gadget: Welcome, new unit!=&lt;br /&gt;
&lt;br /&gt;
1) Create folders: games\MyLuaStuff.sdd\LuaRules\gadgets&lt;br /&gt;
&lt;br /&gt;
2) Create file: games\MyLuaStuff.sdd\LuaRules\gadgets\mytestgadget.lua&lt;br /&gt;
&lt;br /&gt;
3) For first widget we had done an empty widget that did nothing. In the widget-selector-menu we could still check if things were working right.&lt;br /&gt;
So we just take the Hello-Unit widget example and turn it into a gadget:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function gadget:GetInfo()&lt;br /&gt;
  return {&lt;br /&gt;
    name      = &amp;quot;test gadget&amp;quot;,&lt;br /&gt;
    desc      = &amp;quot;testing Lua things&amp;quot;,&lt;br /&gt;
    author    = &amp;quot;your name&amp;quot;,&lt;br /&gt;
    date      = &amp;quot;today&amp;quot;,&lt;br /&gt;
    license   = &amp;quot;GNU GPL, v2&amp;quot;,&lt;br /&gt;
    layer     = 0,&lt;br /&gt;
    enabled   = true,&lt;br /&gt;
  }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if gadgetHandler:IsSyncedCode() then&lt;br /&gt;
&lt;br /&gt;
function gadget:UnitFinished(unitID, unitDefID, teamID)&lt;br /&gt;
	Spring.Echo (&amp;quot;Welcome, new unit!&amp;quot;)	&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
else --unsynced below&lt;br /&gt;
&lt;br /&gt;
end&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We notice it looks very similiar to the widget, except instead of widget::xxx there is gadget:xxx&lt;br /&gt;
&lt;br /&gt;
The GetInfo()-thing again contains some informations about the script, but is otherwise not interessting and to save space will be left out when posting code.&lt;br /&gt;
&lt;br /&gt;
4) Load the game and build a few units. The gadget should welcome each unit.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Vulcano example=&lt;br /&gt;
An example of the process when making gadget.&lt;br /&gt;
&lt;br /&gt;
Pretend you are making a map and want to add a vulcano.&lt;br /&gt;
[[File::thinkingAboutVulcano.png]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note:&#039;&#039; If we wanted, at this point we could move the Lua into a map-archive. But for testing it is easier to continue using the test-mutator-game.&lt;br /&gt;
&lt;br /&gt;
==Define vulcano problem== &lt;br /&gt;
We want to make a vulcano. Now need to think  &#039;&#039;what excactly is this vulcano is supposed to do.&#039;&#039;&lt;br /&gt;
*Should the vulcano damage near units?&lt;br /&gt;
*Should it throw burning rocks across the map?&lt;br /&gt;
*Should it merely be a visual effect, just some smoke on a hill?&lt;br /&gt;
&lt;br /&gt;
For this tutorial we just the last option. (superlame!)&lt;br /&gt;
&lt;br /&gt;
==How to make smoke==&lt;br /&gt;
Now that we know we want to make smoke, the new question is: How to make smoke?&lt;br /&gt;
One way is to use Spring&#039;s particle system called [[CEG:Main]]&lt;br /&gt;
Games can use these CEGS to create explosion, muzzle flashes, fire and so on.&lt;br /&gt;
&lt;br /&gt;
Since our test-mutator is based on XTA, we can use all its effects.&lt;br /&gt;
&lt;br /&gt;
Here we are going to use the effect &amp;quot;BERTHASHOT&amp;quot; which is defined in the file &amp;lt;code&amp;gt;gamedata\explosions\berthashot.tdf&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As the name implies, that effect is usually used when a &amp;quot;Big Bertha&amp;quot; cannon fires a shot. We pick it because it might vaguely look like a smoking vulcano.&lt;br /&gt;
&lt;br /&gt;
==How to spawn the CEG?==&lt;br /&gt;
So how can we make this &amp;quot;BERTHASHOT&amp;quot; effect appear on our vulcano hill? Surely there must be some function call...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We clicked arond the [[CEG:Main]] page a bit and discover [[CEG:Calls]]&lt;br /&gt;
&lt;br /&gt;
It seems there are various ways to use CEGs, for example weapons can use them.&lt;br /&gt;
&lt;br /&gt;
Since we already decided we want to make a gadget, the relevant part is [[CEG:Calls#Synced_Lua_Gadget_CEGs]] which brings us to&lt;br /&gt;
[[Lua_SyncedCtrl#Other]]&lt;br /&gt;
&lt;br /&gt;
==Spring.SpawnCEG==&lt;br /&gt;
On [[Lua_SyncedCtrl#Other]] we discover the function Spring.SpawnCEG and its parameter list:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
( string &amp;quot;cegname&amp;quot; | number cegID,&lt;br /&gt;
   number posX = 0, number posY = 0, number posZ = 0,&lt;br /&gt;
   number dirX = 0, number dirY = 0, number dirZ = 0,&lt;br /&gt;
   number radius = 0, number damage = 0&lt;br /&gt;
 ) -&amp;gt; nil | boolean success, cegID&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*It seems to expect the name of the CEG as first parameter.&lt;br /&gt;
**We already got a CEG name: &amp;quot;BERTHASHOT&amp;quot;&lt;br /&gt;
*The posX,posY,posZ parameters seem to be the coordinates where the effect appears.&lt;br /&gt;
**Note to self: Find coordinates of some hill that looks like it needs some smoke.&lt;br /&gt;
*We have the effectname and where it should appear. The other parameters seems useless to our purpose so we ignore them.&lt;br /&gt;
**They will use default values.&lt;br /&gt;
&lt;br /&gt;
==Location, location, location==&lt;br /&gt;
We decide to use the map &#039;&#039;&#039;&amp;quot;DesertTriad&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
At the bottom right corner there seems a be small hill, perfect vulcano material:&lt;br /&gt;
&lt;br /&gt;
[[File:DesertTriadHillCoordinates.jpg]]&lt;br /&gt;
&lt;br /&gt;
1) The hill where we want smoke to appear.&lt;br /&gt;
&lt;br /&gt;
2) The tooltip that shows the coordinates, when we mouse pointer onto the hill.&lt;br /&gt;
&lt;br /&gt;
Protip: Look at [[Gamedev:UnitsOfMeasurement]] to learn about coordinates system!&lt;br /&gt;
&lt;br /&gt;
==Putting parameters into Spawn.CEG==&lt;br /&gt;
Putting it together:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;Spring.SpawnCEG (&amp;quot;BERTHASHOT&amp;quot;, 3830,  390, 3600)&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Where in the gadget should we put that?&lt;br /&gt;
Into &amp;lt;code&amp;gt;gadget:UnitFinished()&amp;lt;code&amp;gt; callin, like with the Hello-Unit example?&lt;br /&gt;
Then the vulcano would only smoke when a new unit is created.&lt;br /&gt;
&lt;br /&gt;
We need to find a better callin-function from the [[Lua:Callins]] page!&lt;br /&gt;
&lt;br /&gt;
Some callin that gets triggered regularly... so we can have nice constant smoking.&lt;br /&gt;
&lt;br /&gt;
We find:&lt;br /&gt;
&lt;br /&gt;
GameFrame(frame) - &#039;&#039;Called for every game simulation frame (30 per second). &#039;&#039;&lt;br /&gt;
&lt;br /&gt;
...thus we write:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
if gadgetHandler:IsSyncedCode() then&lt;br /&gt;
&lt;br /&gt;
	function gadget:GameFrame (f)&lt;br /&gt;
		if (f%10 == 0) then&lt;br /&gt;
			Spring.SpawnCEG (&amp;quot;BERTHASHOT&amp;quot;, 3830,  390, 3600)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
else --unsynced below&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if (f%10 == 0) then&amp;lt;/code&amp;gt; is added so that a new effect is only spawned every 10 frames.&lt;br /&gt;
&lt;br /&gt;
Also see http://answers.springlobby.info/questions/412/gadgetgameframe-modulo-operation-explained - oh 404! (FIXME)&lt;br /&gt;
&lt;br /&gt;
==Smoke in your eyes==&lt;br /&gt;
Save, start spring, look at the mountain.&lt;br /&gt;
&lt;br /&gt;
Do you see smoke? Likely not because this smoke-effect is only visible when units have vision on it.&lt;br /&gt;
&lt;br /&gt;
So either move a unit to the hill or type into chat:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
/cheat&lt;br /&gt;
/globallos&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now we finally see the smoke:&lt;br /&gt;
&lt;br /&gt;
[[File:DesertTriadVulcano.gif]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==What did we learn?==&lt;br /&gt;
Writting the script is just part one part of making gadget. &lt;br /&gt;
&lt;br /&gt;
From programming perspective, the vulcano example is quite simple.&lt;br /&gt;
&lt;br /&gt;
The harder part was...&lt;br /&gt;
*finding a starting point&lt;br /&gt;
*setting up an editable archive&lt;br /&gt;
*finding the right functions&lt;br /&gt;
*learning about CEGs&lt;br /&gt;
*figuring out general &amp;quot;Spring stuff&amp;quot; like coordinates.&lt;br /&gt;
&lt;br /&gt;
For example had we not known that some particle-effects require vision to be visible, we might have been wondering forever why the vulcano does not work - even if everything in the script was correct.&lt;br /&gt;
&lt;br /&gt;
Luckily, after a while this general &amp;quot;Spring stuff&amp;quot; becomes more familiar.&lt;br /&gt;
&lt;br /&gt;
FIXME: wording&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=User:Knorke/Sandbox2&amp;diff=20868</id>
		<title>User:Knorke/Sandbox2</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=User:Knorke/Sandbox2&amp;diff=20868"/>
		<updated>2014-11-05T00:52:58Z</updated>

		<summary type="html">&lt;p&gt;Knorke: first version&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This text describes making gadgets.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Gadgets must be in a map or game=&lt;br /&gt;
For getting started with a widget, we could just put the file in the spring folder and start coding.&lt;br /&gt;
Unlike widgets, gadgets can not be used &amp;quot;locally&amp;quot; like this: They must be contained in a game or map archive.&lt;br /&gt;
So we must find a way to put the gadget into the game or map. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;gt;&amp;gt;&amp;gt; If you just want to know &amp;quot;How to do this&amp;quot; then skip directly to next chapter. &amp;lt;&amp;lt;&amp;lt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The problem is that games and maps usually come in form of zipped archives, or in case of lobby downloaders as many small files.&lt;br /&gt;
&lt;br /&gt;
[[File:rapid_pool_filedust.png]]&lt;br /&gt;
&lt;br /&gt;
That makes adding new files cumbersome:&lt;br /&gt;
#Unpack the archive&lt;br /&gt;
#Add the new script file or edit it&lt;br /&gt;
#Repack the archive&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
So we must turn a map or game into an .sdd archive.&lt;br /&gt;
&lt;br /&gt;
That is explain in more detail in general modding tutorial: ADDLINK FIXME&lt;br /&gt;
&lt;br /&gt;
For first experiment it does not matter if the gadget is in the map or in the game.&lt;br /&gt;
&lt;br /&gt;
Another way is to create a test-mutator. That is basically a game that &amp;quot;includes&amp;quot; another game, like an add-on.&lt;br /&gt;
The advantages are:&lt;br /&gt;
* No need to edit existing game and maybe run into problems.&lt;br /&gt;
* The test-game filesize stays small enough to share easily with others, to get help.&lt;br /&gt;
* One can still use all the units, features &amp;amp; effects of the original game. That is useful for testing.&lt;br /&gt;
&lt;br /&gt;
Personally I recommend the test-mutator.&lt;br /&gt;
XTA is a good canidate as base-game choice because:&lt;br /&gt;
*in some ways it is more basic&lt;br /&gt;
*the unitnames are human-readable. For example &amp;quot;arm_windgenerator&amp;quot; instead of &amp;quot;armwingntor&amp;quot;&lt;br /&gt;
*Some games try to hide as much engine GUI as possible, however for testing that is not so useful.&lt;br /&gt;
&lt;br /&gt;
=The Test Mutator folder=&lt;br /&gt;
1) Create folder: games\MyLuaStuff.sdd&lt;br /&gt;
&lt;br /&gt;
2) Create file: games\MyLuaStuff.sdd\modinfo.lua  (  [[Modinfo.lua]]  )&lt;br /&gt;
&lt;br /&gt;
With this content:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
return {&lt;br /&gt;
  name=&#039;XTA LuaStuff&#039;,&lt;br /&gt;
  description=&#039;lolool&#039;,&lt;br /&gt;
  URL=&#039;http://code.google.com/p/xta-springrts/&#039;,&lt;br /&gt;
  shortname=&#039;XTA&#039;,&lt;br /&gt;
  version = &#039;9.744&#039;,&lt;br /&gt;
  mutator=&#039;LuaStuff&#039;,&lt;br /&gt;
  game=&#039;Total Annihilation&#039;,&lt;br /&gt;
  shortGame=&#039;TA&#039;,&lt;br /&gt;
  depend = {&amp;quot;XTA 9.744&amp;quot;},&lt;br /&gt;
  modtype=1,&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt; &lt;br /&gt;
FIXME: mutator details, can it work with any xta version&lt;br /&gt;
&lt;br /&gt;
3) Test with spring.exe if the mutator shows in game list and can be played&lt;br /&gt;
&lt;br /&gt;
=First gadget: Welcome, new unit!=&lt;br /&gt;
&lt;br /&gt;
1) Create folders: games\MyLuaStuff.sdd\LuaRules\gadgets&lt;br /&gt;
&lt;br /&gt;
2) Create file: games\MyLuaStuff.sdd\LuaRules\gadgets\mytestgadget.lua&lt;br /&gt;
&lt;br /&gt;
3) For first widget we had done an empty widget that did nothing. In the widget-selector-menu we could still check if things were working right.&lt;br /&gt;
So we just take the Hello-Unit widget example and turn it into a gadget:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function gadget:GetInfo()&lt;br /&gt;
  return {&lt;br /&gt;
    name      = &amp;quot;test gadget&amp;quot;,&lt;br /&gt;
    desc      = &amp;quot;testing Lua things&amp;quot;,&lt;br /&gt;
    author    = &amp;quot;your name&amp;quot;,&lt;br /&gt;
    date      = &amp;quot;today&amp;quot;,&lt;br /&gt;
    license   = &amp;quot;GNU GPL, v2&amp;quot;,&lt;br /&gt;
    layer     = 0,&lt;br /&gt;
    enabled   = true,&lt;br /&gt;
  }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
if gadgetHandler:IsSyncedCode() then&lt;br /&gt;
&lt;br /&gt;
function gadget:UnitFinished(unitID, unitDefID, teamID)&lt;br /&gt;
	Spring.Echo (&amp;quot;Welcome, new unit!&amp;quot;)	&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
else --unsynced below&lt;br /&gt;
&lt;br /&gt;
end&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We notice it looks very similiar to the widget, except instead of widget::xxx there is gadget:xxx&lt;br /&gt;
&lt;br /&gt;
The GetInfo()-thing again contains some informations about the script, but is otherwise not interessting and to save space will be left out when posting code.&lt;br /&gt;
&lt;br /&gt;
4) Load the game and build a few units. The gadget should welcome each unit.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Vulcano example=&lt;br /&gt;
An example of the process when making gadget.&lt;br /&gt;
&lt;br /&gt;
Pretend you are making a map and want to add a vulcano.&lt;br /&gt;
[[File::thinkingAboutVulcano.png]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note:&#039;&#039; If we wanted, at this point we could move the Lua into a map-archive. But for testing it is easier to continue using the test-mutator-game.&lt;br /&gt;
&lt;br /&gt;
==Define vulcano problem== &lt;br /&gt;
We want to make a vulcano. Now need to think  &#039;&#039;what excactly is this vulcano is supposed to do.&#039;&#039;&lt;br /&gt;
*Should the vulcano damage near units?&lt;br /&gt;
*Should it throw burning rocks across the map?&lt;br /&gt;
*Should it merely be a visual effect, just some smoke on a hill?&lt;br /&gt;
&lt;br /&gt;
For this tutorial we just the last option. (superlame!)&lt;br /&gt;
&lt;br /&gt;
==How to make smoke==&lt;br /&gt;
Now that we know we want to make smoke, the new question is: How to make smoke?&lt;br /&gt;
One way is to use Spring&#039;s particle system called [[CEG:Main]]&lt;br /&gt;
Games can use these CEGS to create explosion, muzzle flashes, fire and so on.&lt;br /&gt;
&lt;br /&gt;
Since our test-mutator is based on XTA, we can use all its effects.&lt;br /&gt;
&lt;br /&gt;
Here we are going to use the effect &amp;quot;BERTHASHOT&amp;quot; which is defined in the file &amp;lt;code&amp;gt;gamedata\explosions\berthashot.tdf&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As the name implies, that effect is usually used when a &amp;quot;Big Bertha&amp;quot; cannon fires a shot. We pick it because it might vaguely look like a smoking vulcano.&lt;br /&gt;
&lt;br /&gt;
==How to spawn the CEG?==&lt;br /&gt;
So how can we make this &amp;quot;BERTHASHOT&amp;quot; effect appear on our vulcano hill? Surely there must be some function call...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We clicked arond the [[CEG:Main]] page a bit and discover [[CEG:Calls]]&lt;br /&gt;
&lt;br /&gt;
It seems there are various ways to use CEGs, for example weapons can use them.&lt;br /&gt;
&lt;br /&gt;
Since we already decided we want to make a gadget, the relevant part is [[CEG:Calls#Synced_Lua_Gadget_CEGs]] which brings us to&lt;br /&gt;
[[Lua_SyncedCtrl#Other]]&lt;br /&gt;
&lt;br /&gt;
==Spring.SpawnCEG==&lt;br /&gt;
On [[Lua_SyncedCtrl#Other]] we discover the function Spring.SpawnCEG and its parameter list:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
( string &amp;quot;cegname&amp;quot; | number cegID,&lt;br /&gt;
   number posX = 0, number posY = 0, number posZ = 0,&lt;br /&gt;
   number dirX = 0, number dirY = 0, number dirZ = 0,&lt;br /&gt;
   number radius = 0, number damage = 0&lt;br /&gt;
 ) -&amp;gt; nil | boolean success, cegID&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*It seems to expect the name of the CEG as first parameter.&lt;br /&gt;
**We already got a CEG name: &amp;quot;BERTHASHOT&amp;quot;&lt;br /&gt;
*The posX,posY,posZ parameters seem to be the coordinates where the effect appears.&lt;br /&gt;
**Note to self: Find coordinates of some hill that looks like it needs some smoke.&lt;br /&gt;
*We have the effectname and where it should appear. The other parameters seems useless to our purpose so we ignore them.&lt;br /&gt;
**They will use default values.&lt;br /&gt;
&lt;br /&gt;
==Location, location, location==&lt;br /&gt;
We decide to use the map &#039;&#039;&#039;&amp;quot;DesertTriad&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
At the bottom right corner there seems a be small hill, perfect vulcano material:&lt;br /&gt;
&lt;br /&gt;
[[File:DesertTriadHillCoordinates.jpg]]&lt;br /&gt;
&lt;br /&gt;
1) The hill where we want smoke to appear.&lt;br /&gt;
&lt;br /&gt;
2) The tooltip that shows the coordinates, when we mouse pointer onto the hill.&lt;br /&gt;
&lt;br /&gt;
Protip: Look at [[Gamedev:UnitsOfMeasurement]] to learn about coordinates system!&lt;br /&gt;
&lt;br /&gt;
==Putting parameters into Spawn.CEG==&lt;br /&gt;
Putting it together:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;Spring.SpawnCEG (&amp;quot;BERTHASHOT&amp;quot;, 3830,  390, 3600)&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Where in the gadget should we put that?&lt;br /&gt;
Into &amp;lt;code&amp;gt;gadget:UnitFinished()&amp;lt;code&amp;gt; callin, like with the Hello-Unit example?&lt;br /&gt;
Then the vulcano would only smoke when a new unit is created.&lt;br /&gt;
&lt;br /&gt;
We need to find a better callin-function from the [[Lua:Callins]] page!&lt;br /&gt;
&lt;br /&gt;
Some callin that gets triggered regularly... so we can have nice constant smoking.&lt;br /&gt;
&lt;br /&gt;
We find:&lt;br /&gt;
&lt;br /&gt;
GameFrame(frame) - &#039;&#039;Called for every game simulation frame (30 per second). &#039;&#039;&lt;br /&gt;
&lt;br /&gt;
...thus we write:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
if gadgetHandler:IsSyncedCode() then&lt;br /&gt;
&lt;br /&gt;
	function gadget:GameFrame (f)&lt;br /&gt;
		if (f%10 == 0) then&lt;br /&gt;
			Spring.SpawnCEG (&amp;quot;BERTHASHOT&amp;quot;, 3830,  390, 3600)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
else --unsynced below&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;if (f%10 == 0) then&amp;lt;/code&amp;gt; is added so that a new effect is only spawned every 10 frames.&lt;br /&gt;
&lt;br /&gt;
Also see http://answers.springlobby.info/questions/412/gadgetgameframe-modulo-operation-explained - oh 404! (FIXME)&lt;br /&gt;
&lt;br /&gt;
==Smoke in your eyes==&lt;br /&gt;
Save, start spring, look at the mountain.&lt;br /&gt;
&lt;br /&gt;
Do you see smoke? Likely not because this smoke-effect is only visible when units have vision on it.&lt;br /&gt;
&lt;br /&gt;
So either move a unit to the hill or type into chat:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
/cheat&lt;br /&gt;
/globallos&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now we finally see the smoke:&lt;br /&gt;
&lt;br /&gt;
[[File:DesertTriadVulcano.gif]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==What did we learn?==&lt;br /&gt;
Writting the script is just part one part of making gadget. &lt;br /&gt;
&lt;br /&gt;
From programming perspective, the vulcano example is quite simple.&lt;br /&gt;
&lt;br /&gt;
The harder part was...&lt;br /&gt;
*finding a starting point&lt;br /&gt;
*setting up an editable archive&lt;br /&gt;
*finding the right functions&lt;br /&gt;
*learning about CEGs&lt;br /&gt;
*figuring out general &amp;quot;Spring stuff&amp;quot; like coordinates.&lt;br /&gt;
&lt;br /&gt;
Luckily, after a while this general &amp;quot;Spring stuff&amp;quot; becomes more familiar.&lt;br /&gt;
FIXME: wording&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=File:DesertTriadVulcano.gif&amp;diff=21693</id>
		<title>File:DesertTriadVulcano.gif</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=File:DesertTriadVulcano.gif&amp;diff=21693"/>
		<updated>2014-11-05T00:34:50Z</updated>

		<summary type="html">&lt;p&gt;Knorke: animation of lame vulcano made using Spawn.CEG
commander is looking at the vulcano.
for use in Lua tutorial&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;animation of lame vulcano made using Spawn.CEG&lt;br /&gt;
commander is looking at the vulcano.&lt;br /&gt;
for use in Lua tutorial&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=File:DesertTriadHillCoordinates.jpg&amp;diff=21692</id>
		<title>File:DesertTriadHillCoordinates.jpg</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=File:DesertTriadHillCoordinates.jpg&amp;diff=21692"/>
		<updated>2014-11-05T00:33:46Z</updated>

		<summary type="html">&lt;p&gt;Knorke: Hill on map DesertTriad
The tooltip shows hill coordinates
for use in Lua tutorial&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Hill on map DesertTriad&lt;br /&gt;
The tooltip shows hill coordinates&lt;br /&gt;
for use in Lua tutorial&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=File:Rapid_pool_filedust.png&amp;diff=21990</id>
		<title>File:Rapid pool filedust.png</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=File:Rapid_pool_filedust.png&amp;diff=21990"/>
		<updated>2014-11-05T00:32:53Z</updated>

		<summary type="html">&lt;p&gt;Knorke: screenshot of pool folder.
there is filedust to be seen.
for use in Lua tutorial.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;screenshot of pool folder.&lt;br /&gt;
there is filedust to be seen.&lt;br /&gt;
for use in Lua tutorial.&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=File:ThinkingAboutVulcano.png&amp;diff=22132</id>
		<title>File:ThinkingAboutVulcano.png</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=File:ThinkingAboutVulcano.png&amp;diff=22132"/>
		<updated>2014-11-05T00:32:07Z</updated>

		<summary type="html">&lt;p&gt;Knorke: a person thinking about a vulcano.
for use in Lua tutorial.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;a person thinking about a vulcano.&lt;br /&gt;
for use in Lua tutorial.&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=Lua_Beginners_FAQ&amp;diff=11105</id>
		<title>Lua Beginners FAQ</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=Lua_Beginners_FAQ&amp;diff=11105"/>
		<updated>2014-09-27T09:46:46Z</updated>

		<summary type="html">&lt;p&gt;Knorke: dead link, tutorial links more clear&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Engine_Development|Development]] &amp;lt; [[Lua_Scripting|Lua Scripting]] &amp;lt; {{FULLPAGENAME}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This page only tries to answer general questions, for more specific Questions please ask in the forum.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Q: I&#039;m interested in learning to use Lua with Spring. Where should I start?==&lt;br /&gt;
A: You can start by reading general Lua tutorials  [http://lua-users.org/wiki/LuaTutorial here]. &lt;br /&gt;
After that, you can try following try using Lua in Spring, for example [[Lua:Tutorial_GettingStarted|by following this tutorial.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Q: Where can I find documentation?==&lt;br /&gt;
A: On the [[Lua_Scripting|Lua_Scripting page.]]&lt;br /&gt;
&lt;br /&gt;
==Q: What can&#039;t Lua do in the current version of Spring?==&lt;br /&gt;
&lt;br /&gt;
A: You can&#039;t ...&lt;br /&gt;
*control the ground LOS (but you can set the los status of units!).&lt;br /&gt;
&lt;br /&gt;
==Q: How do I open &amp;quot;.lua&amp;quot; files?==&lt;br /&gt;
&lt;br /&gt;
A: Notepad or any text editor might be enough. If you are using windows and the text is all garbled, try a programmer&#039;s editor. [http://notepad-plus.sourceforge.net/uk/site.htm Notepad++] can read Lua files with syntax highlighting.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Q: What is a call-in? And a call-out?==&lt;br /&gt;
&lt;br /&gt;
Call-ins are functions defined in your script that Spring calls when a determined event takes place. For example, the gadget:Initialize() call-in is run by Spring when the widget is loaded.&lt;br /&gt;
Call-outs are functions defined in Spring you can run at whichever moment you desire. For example, when you call Spring.GetUnitTeam(unitID), the engine returns the teamID of the unit identified by &amp;quot;unitID&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Q: What is the difference between a widget and a gadget?==&lt;br /&gt;
&lt;br /&gt;
A: A widget is a Lua script that works with LuaUI. A gadget works with LuaRules, LuaCob or LuaGaia. Widgets allow you to customize your interface, and must be unsynced. They can be bundled with the mod or you can save them in your &amp;quot;Spring/LuaUI/Wigets&amp;quot; directory. Gadgets can be synced or unsynced. LuaRules and LuaCob gadgets are usually part of a mod. LuaGaia gadgets should be part of a map. Gadgets can contain both synced and unsynced code.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Q: Where can I find examples?==&lt;br /&gt;
&lt;br /&gt;
A: The &amp;quot;Spring\examples\Widgets&amp;quot; directory contains many examples. More can be found in almost every game, especially in the [http://zero-k.info/ Zero-K] game.&lt;br /&gt;
&lt;br /&gt;
==Q: Can I reload a script without restarting Spring?==&lt;br /&gt;
&lt;br /&gt;
Yes, you can type &amp;quot;/luaui reload&amp;quot; with &amp;quot;/cheats&amp;quot; enabled.&lt;br /&gt;
[http://answers.springlobby.info/questions/393/how-can-i-easily-test-my-mod More usefull commands.]&lt;br /&gt;
&lt;br /&gt;
==Q: Why does the print function seem to do nothing?==&lt;br /&gt;
&lt;br /&gt;
A: Its output is displayed in stdout. If you have no easy way to see it, you can is Spring.Echo which prints to the ingame chat and infolog.txt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Q: How do I print the &amp;quot;UnitDefs[unitDefID]&amp;quot; or &amp;quot;WeaponDefs[weaponDefID]&amp;quot; tables? &amp;quot;for k, v in ipairs(t) do print(k, v) end&amp;quot; does not behave as expected.==&lt;br /&gt;
&lt;br /&gt;
A: Use &amp;quot;for k,v in UnitDefs[unitDefID]:pairs() do print(k, v) end&amp;quot; instead.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Q: Where can I find help?==&lt;br /&gt;
&lt;br /&gt;
A: There is a [http://springrts.com/phpbb/viewforum.php?f=23 Lua section] in the Spring forums. Probably the most effective way, though, is to join #lua on the lobby.&lt;br /&gt;
&lt;br /&gt;
==Q: Who implemented LuaUI, LuaRules and LuaGaia?==&lt;br /&gt;
&lt;br /&gt;
A: They were written by trepan.&lt;br /&gt;
[[Category: Lua]]&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=Lua:Tutorial_GettingStarted&amp;diff=10914</id>
		<title>Lua:Tutorial GettingStarted</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=Lua:Tutorial_GettingStarted&amp;diff=10914"/>
		<updated>2014-09-25T11:42:11Z</updated>

		<summary type="html">&lt;p&gt;Knorke: /* My first wupdget */ folder Widgets\ might not exist&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Engine_Development|Development]] &amp;lt; [[Lua_Scripting|Lua Scripting]] &amp;lt; {{FULLPAGENAME}}&lt;br /&gt;
&lt;br /&gt;
==What this is==&lt;br /&gt;
This page explains how to get started making scripts for spring.&lt;br /&gt;
&lt;br /&gt;
==What this is not==&lt;br /&gt;
This page does not explains how to make scripts for spring.&lt;br /&gt;
&lt;br /&gt;
This page is not a Lua tutorial.&lt;br /&gt;
&lt;br /&gt;
==Requirements==&lt;br /&gt;
* having played spring game for some days&lt;br /&gt;
* text editor with synthax coloring&lt;br /&gt;
* copy of [[SpringTutorialGame]]&lt;br /&gt;
* [http://springfiles.com/spring/spring-maps/aliendesert some small map] because those load faster&lt;br /&gt;
* Spring set to [[Springsettings.cfg#Fullscreen|windowed mode]] for easier switching between editor/game&lt;br /&gt;
* a very bit familiar with programing (variables, functions, loops, arrays = enough)&lt;br /&gt;
* read through [[TestingYourGame|this tips page]] once&lt;br /&gt;
&lt;br /&gt;
==Wupget and friends==&lt;br /&gt;
In Spring games there are 3 kinds of Lua scripts.&lt;br /&gt;
Crude and simple explaination:&lt;br /&gt;
# gadgets: these are the &amp;quot;gameplay logic code.&amp;quot;&lt;br /&gt;
# widgets: these are for interface.&lt;br /&gt;
# unit scripts: animate units &amp;amp; controll their weapons.&lt;br /&gt;
&lt;br /&gt;
Making those 3 is not very different but widgets are the easiest to start with.&lt;br /&gt;
&lt;br /&gt;
There is also 4) functionality provided by the engine.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Also look at this:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
http://springrts.com/mediawiki/images/1/13/Gadgets_widgets_and_friends.png&lt;br /&gt;
&lt;br /&gt;
All 4 are in a constant fight against each other.&lt;br /&gt;
&lt;br /&gt;
==My first wupdget==&lt;br /&gt;
The [[SpringTutorialGame]] is simple and good for testing:&lt;br /&gt;
You can use any other game but some games block player widgets or are very confusing.&lt;br /&gt;
&lt;br /&gt;
Create a txt file like this and there:&lt;br /&gt;
&#039;&#039;Spring\LuaUI\Widgets\myfirstwidget.lua&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If the &#039;&#039;Widgets&#039;&#039; folder does not exist, then create it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;span class=&amp;quot;warning&amp;quot;&amp;gt;Alternative way:&amp;lt;/span&amp;gt;&lt;br /&gt;
If you already know how to edit game-archives then you can also put&#039;&#039;myfirstwidget.lua&#039;&#039; inside the game-archive. &lt;br /&gt;
&lt;br /&gt;
For example: &#039;&#039;SpringTutorialGame.sdd\LuaUI\Widgets\myfirstwidget.lua&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Copypaste this text into the myfirstwidget.lua :&lt;br /&gt;
-----&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function widget:GetInfo()&lt;br /&gt;
  return {&lt;br /&gt;
    name      = &amp;quot;my first widget&amp;quot;,&lt;br /&gt;
    desc      = &amp;quot;this is so awesome&amp;quot;,&lt;br /&gt;
    author    = &amp;quot;horse 3000&amp;quot;,&lt;br /&gt;
    date      = &amp;quot;2009&amp;quot;,&lt;br /&gt;
    license   = &amp;quot;GNU GPL, v2 or later&amp;quot;,&lt;br /&gt;
    layer     = -10,&lt;br /&gt;
    enabled   = true&lt;br /&gt;
  }&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
-----&lt;br /&gt;
For now it does not matter what excactly this does but here you can put informations about your widget. &lt;br /&gt;
&lt;br /&gt;
What matters is that without such &#039;&#039;GetInfo()&#039;&#039; function Spring will not load the widget correctly.&lt;br /&gt;
It is usually not interessting and will be left out when code is posted, to save screen space.&lt;br /&gt;
Of course it must still be there.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Start spring.exe, load a game and press F11. The &amp;quot;widget menu&amp;quot; opens:&lt;br /&gt;
&lt;br /&gt;
http://springrts.com/mediawiki/images/8/80/Widget_F11menu.png&lt;br /&gt;
&lt;br /&gt;
It is likely already filled with some other widgets contained in the game.&lt;br /&gt;
Find your new widget in the list. Click on it to turn it on and off: The name in list should go green or red accordingly.&lt;br /&gt;
&lt;br /&gt;
If that works - congratulation: You made a new widget that does excactly nothing.&lt;br /&gt;
&lt;br /&gt;
=&amp;quot;Hello unit&amp;quot; wupdget=&lt;br /&gt;
Add the following at the end of myfirstwidget.lua:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function widget:UnitFinished(unitID, unitDefID, teamID)&lt;br /&gt;
	Spring.Echo (&amp;quot;a new unit was finished! It belongs to team &amp;quot; .. teamID)	&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
UnitFinished(...) is a [[Lua:Callins|callin function]] : Those are functions that the engine calls when certain events happen.&lt;br /&gt;
Captain Obvious has already figured out: This function gets called when a new unit is finished.&lt;br /&gt;
&lt;br /&gt;
Spring.Echo is used to output text to the chat/console.&lt;br /&gt;
So this widget should tell when a new unit is made.&lt;br /&gt;
&lt;br /&gt;
4)&lt;br /&gt;
Open the widget menu and disable then re-enable your widget: This will reload the widget.&lt;br /&gt;
Now build some units to test it.&lt;br /&gt;
&lt;br /&gt;
===Finding errors and infolog.txt===&lt;br /&gt;
For test add an error like this:&lt;br /&gt;
	Spring.Echo (100 + nil)&lt;br /&gt;
and reload the widget.&lt;br /&gt;
The widgets name is green but turns yellow as soon a unit is build: &amp;quot;nil&amp;quot; can not be used in math like that.&lt;br /&gt;
&lt;br /&gt;
The error is also displayed in chat and [[infolog.txt]]&lt;br /&gt;
In that logfile you can look up all errors even if they have disappeared from chat.&lt;br /&gt;
Fix the error, reload the widget and it is green again. Oha.&lt;br /&gt;
&lt;br /&gt;
FIXME: expand this&lt;br /&gt;
&lt;br /&gt;
===widget sees you and only you and your allies===&lt;br /&gt;
Even if there is a bot/other player building stuff, the widget will not notify on all  their new units if they are outside line of sight.&lt;br /&gt;
That is because widgets are limited in what they can &amp;quot;see.&amp;quot;&lt;br /&gt;
The widget only sees what what the player who is running the widget can see, too. This is to prevent cheating.&lt;br /&gt;
&lt;br /&gt;
==&amp;quot;Hello unit&amp;quot; 2 - with markers and advancement==&lt;br /&gt;
change the widget to this and guess what it does:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function widget:UnitFinished(unitID, unitDefID, teamID)&lt;br /&gt;
	local x,y,z = Spring.GetUnitPosition (unitID)&lt;br /&gt;
	Spring.MarkerAddPoint (x,y,z, &amp;quot;a new unit! id=&amp;quot; .. unitID)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It adds a marker point on every new unit!&lt;br /&gt;
Note how the unitID parameter from UnitFinished() is passed to GetUnitPosition()&lt;br /&gt;
&lt;br /&gt;
===unitIDs===&lt;br /&gt;
Previous paragraph featured &#039;&#039;unitID&#039;&#039; variable.&lt;br /&gt;
Every unit, feature or weapon projectile in spring has an ID number:&lt;br /&gt;
&lt;br /&gt;
http://springrts.com/mediawiki/images/3/3c/Units_features_projectiles.png&lt;br /&gt;
&lt;br /&gt;
There are never two units with the same unitID at the same time. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;#YOLO?&amp;lt;/pre&amp;gt;&lt;br /&gt;
No YOLO: when a unit is destroyed its unitID might be reused later for a different unit.&lt;br /&gt;
&lt;br /&gt;
=a boring counter widget=&lt;br /&gt;
A counter that is increased when units are made:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
local counter = 0&lt;br /&gt;
function widget:UnitFinished (unitID, unitDefID, teamID)	&lt;br /&gt;
	counter = counter +1&lt;br /&gt;
	Spring.Echo (&amp;quot;now there are &amp;quot; .. counter .. &amp;quot; units&amp;quot;)&lt;br /&gt;
	if counter &amp;gt; 10 then&lt;br /&gt;
		Spring.Echo (&amp;quot;wow, more than 10 units!&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[TestingYourGame#Lua|Reload the widget]] and note how the counter gets reseted. &lt;br /&gt;
That is how widgets roll: Their variables get cleared on reload.&lt;br /&gt;
&lt;br /&gt;
===boring counter widget with tables===&lt;br /&gt;
Imagine you want a counter that stores for each factory how many units it has already produced. One variable will not be enought here but an array can store multiple things.&lt;br /&gt;
&lt;br /&gt;
Arrays in Lua are tables. Read about tables: http://lua-users.org/wiki/TablesTutorial&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
local buildCount = {}&lt;br /&gt;
function widget:UnitFromFactory(unitID, unitDefID, unitTeam, factoryID, factoryDefID, userOrders)&lt;br /&gt;
	--read from table how many units this factory already built&lt;br /&gt;
	local n = buildCount[factoryID]&lt;br /&gt;
&lt;br /&gt;
	--was the entry empty?&lt;br /&gt;
	if n == nil then					&lt;br /&gt;
		n = 0 --if yes, start counting from 0&lt;br /&gt;
	end&lt;br /&gt;
	n = n +1 --increase n by 1 (best comment ever)&lt;br /&gt;
	Spring.Echo (&amp;quot;This was unit number &amp;quot; .. n .. &amp;quot; from factory &amp;quot; .. factoryID)&lt;br /&gt;
	--store new buildCount for this factory&lt;br /&gt;
	buildCount[factoryID] = n&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
UnitFromFactory is basically the same as UnitFinished, but has the usefull &#039;&#039;factoryID&#039;&#039; parameter.&lt;br /&gt;
&#039;&#039;&#039;Why the if n == nil?&#039;&#039;&#039;&lt;br /&gt;
In Lua everything not initialized is nil (=nothing) and nil can not be used in any math. &lt;br /&gt;
&lt;br /&gt;
(n = n +1  is a math)&lt;br /&gt;
&lt;br /&gt;
Btw a shorter version could be:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;buildCount[factoryID] = (buildCount[factoryID] or 0) + 1&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==I made enough &amp;quot;hello world&amp;quot; widgets. What now?==&lt;br /&gt;
On [[Lua_Scripting]] the most important are the pages under &#039;&#039;&#039;GameState&#039;&#039;&#039; and &#039;&#039;&#039;Client&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
See these [[TestingYourGame|pro-tips]] to make testing less frustrating.&lt;br /&gt;
&lt;br /&gt;
While widgets are initially easiest to make, soon there is a problem:&lt;br /&gt;
widgets are for interface stuff. &lt;br /&gt;
&lt;br /&gt;
That means widgets usually need to either...&lt;br /&gt;
* ...draw something on the screen. (for example the health of Commander)&lt;br /&gt;
and/or&lt;br /&gt;
* ...give orders to units. (for example make Commander automatically run away from danger)&lt;br /&gt;
&lt;br /&gt;
Both graphics and the whole order-system can be bit tricky for starters.&lt;br /&gt;
Without graphics and orders, the awesomeness potential of a widget is small.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Pro tip:&#039;&#039;&#039; gadgets can be awesome without either!&lt;br /&gt;
&lt;br /&gt;
==go go gadgets time!==&lt;br /&gt;
We learned widgets can only &amp;quot;look at&amp;quot; the gamestate or do things that players can do, for example ordering units to attack another unit.&lt;br /&gt;
&lt;br /&gt;
On the other hand gadgets are scripts that are able to alter the state of the game.&lt;br /&gt;
With gadgets it is possible to implent new game logic like jumpjets, drop pods, tech tree systems, etc.&lt;br /&gt;
&lt;br /&gt;
Unlike widgets, gadgets must be [[Gamedev:Structure#LuaRules.5C|included in a game or in a map.]]&lt;br /&gt;
&lt;br /&gt;
To do so it is best to unpack the game file into an [[Gamedev:Archives|.sdd archive]]&lt;br /&gt;
&lt;br /&gt;
Writing gadgets is similiar to widgets, except the getInfo() header and callin functions are prefixed with &amp;lt;code&amp;gt;gadget:xxx&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;widget:xxx&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===synced &amp;amp; unsynced===&lt;br /&gt;
Gadgets are split into a synced and into an unsynced part.&lt;br /&gt;
&lt;br /&gt;
In simple terms that means the synced part is usually for controlling the game logic.&lt;br /&gt;
The unsynced part is for drawig graphics.&lt;br /&gt;
&lt;br /&gt;
For example look at this lava tide gadget:&lt;br /&gt;
&lt;br /&gt;
http://springrts.com/mediawiki/images/3/33/Beachbuggysuicidecult_lava_sync_unsync.gif&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;synced&#039;&#039;&#039; part is responsible for &#039;&#039;damaging/destroying the units&#039;&#039; in the lava. It actually alters the gamestate.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;unsynced&#039;&#039;&#039; part is only for &#039;&#039;drawing&#039;&#039; the graphic of the lava. The graphic itself does not influence the gamestate in any way.&lt;br /&gt;
&lt;br /&gt;
In code it looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
if (gadgetHandler:IsSyncedCode()) then&lt;br /&gt;
  --synced code&lt;br /&gt;
  ..&lt;br /&gt;
  damage all units that are underneath the lava tide level&lt;br /&gt;
  ..&lt;br /&gt;
else&lt;br /&gt;
  --unsynced code&lt;br /&gt;
  ..&lt;br /&gt;
  drawing the lava with GL-api functions&lt;br /&gt;
  ..&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Of course that also means that some functions or callins can only be used in synced or unsynced part. For example the synced part can not draw anything and the unsynced part can not spawn units.&lt;br /&gt;
&lt;br /&gt;
Sometimes it is nessecary to transfer some data/information &amp;quot;across the sync-unsynced border&amp;quot; - but the scope of variables is only in the part they were declared in.&lt;br /&gt;
In lava-exampe that might be the current height of lava.&lt;br /&gt;
How this still works is explained here: [[LuaTutorials::InterCommunications]]&lt;br /&gt;
&lt;br /&gt;
==Look at more examples==&lt;br /&gt;
Common hint for learning spring Lua is: &#039;&#039;&amp;quot;Look at some examples in other games.&amp;quot;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
But a spring game usually has dozen of wupdgets and only a few are useful examples for beginners. Many scripts deal with some very specifique problem or are just way too long.&lt;br /&gt;
Or one has to be familiar with the game to even understand what the script even does.&lt;br /&gt;
Or if one wants to use the wupdget in ones own game, suddendly nothing works anymore because it depends on so many configs or other files.&lt;br /&gt;
&lt;br /&gt;
Two simple examples are:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Linked units&amp;quot; (hub dies, child-units explode too)&lt;br /&gt;
http://springrts.com/phpbb/viewtopic.php?f=23&amp;amp;t=25435&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Moveable metal extractor&amp;quot;&lt;br /&gt;
http://springrts.com/phpbb/viewtopic.php?f=14&amp;amp;t=26877&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
==Feedback? Questions?==&lt;br /&gt;
This page is open for feedback {{forumlink|topic=32047|title=in the forum.}}&lt;br /&gt;
&lt;br /&gt;
[[category: Lua]]&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=Lua:Callins&amp;diff=10745</id>
		<title>Lua:Callins</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=Lua:Callins&amp;diff=10745"/>
		<updated>2014-07-11T14:53:37Z</updated>

		<summary type="html">&lt;p&gt;Knorke: /* Units */ add: AllowBuilderHoldFire&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Lua Callins =&lt;br /&gt;
This page is future looking to unified widget/gadget (aka &amp;quot;addon&amp;quot;) handler, which may yet be some way off, c.f. the [https://github.com/spring/spring/blob/ebb704e008f6ea645947d07be1cfcc272af0428f/doc/changelog.txt#L71 changelog].&lt;br /&gt;
&lt;br /&gt;
Some functions may differ between (synced) gadget and widgets; those are in the [[#Synced_-_Unsynced_Shared]] section. Essentially the reason is that all information should be available to synced (game logic controlling) gadgets, but restricted to unsynced gadget/widget (e.g. information about an enemy unit only detected via radar and not yet in LOS). In such cases the full (synced) param list is documented.&lt;br /&gt;
&lt;br /&gt;
== Common ==&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = Initialize&lt;br /&gt;
|params = &lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called when the addon is (re)loaded.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = Shutdown&lt;br /&gt;
|params = &lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called when the addon or the game is shutdown.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Unsynced Only ==&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = DefaultCommand&lt;br /&gt;
|params = type, id&lt;br /&gt;
|return = number cmdID&lt;br /&gt;
|description = Used to set the default command when a unit is selected.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = CommandNotify&lt;br /&gt;
|params = cmdID, cmdParams, cmdOptions&lt;br /&gt;
|return = bool removeCmd&lt;br /&gt;
|description = Called when a command is issued. Returning &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; deletes the command and does not send it through the network.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = WorldTooltip&lt;br /&gt;
|params = ttType, data1, data2, data3&lt;br /&gt;
|return = string newTooltip&lt;br /&gt;
|description = The parameters can be &amp;lt;code&amp;gt;&amp;quot;unit&amp;quot;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;unitID&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;&amp;quot;feature&amp;quot;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;featureID&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;&amp;quot;ground&amp;quot;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;posX&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;posY&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;posZ&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;&amp;quot;selection&amp;quot;&amp;lt;/code&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = UnsyncedHeightMapUpdate&lt;br /&gt;
|params = ???&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called when the unsynced copy of the height-map is altered.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = GameProgress&lt;br /&gt;
|params = serverFrameNum&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called every 60 frames, calculating delta between GameFrame and GameProgress. Can give an ETA about catching up with simulation for mid-game join players.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = GameSetup&lt;br /&gt;
|params =  state, ready, playerStates&lt;br /&gt;
|return = bool success, bool newReady&lt;br /&gt;
|description = ???&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = SunChanged&lt;br /&gt;
|params = ???&lt;br /&gt;
|return = none&lt;br /&gt;
|description = ???&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = AddConsoleLine&lt;br /&gt;
|params = msg, priority&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called when text is entered into the console (e.g. Spring.Echo).&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = RecvSkirmishAIMessage&lt;br /&gt;
|params = aiTeam, dataStr&lt;br /&gt;
|return = ???&lt;br /&gt;
|description = ???&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = RecvFromSynced&lt;br /&gt;
|params = ...&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Receives data sent via [[Lua_System#Synced|SendToUnsynced]] callout.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = Save&lt;br /&gt;
|params = zip&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called when a chat command &#039;/save&#039; or &#039;/savegame&#039; is received. The single argument is a userdatum representing the savegame zip file. See [[Lua_SaveLoad#Save_.28_zip_.29_-.3E_nil|Lua_SaveLoad]].&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = LoadProgress&lt;br /&gt;
|params = message, replaceLastLine&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Only available to LuaIntro.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = GroupChanged&lt;br /&gt;
|params = ???&lt;br /&gt;
|return = ???&lt;br /&gt;
|description = ???&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = ConfigureLayout&lt;br /&gt;
|params = ???&lt;br /&gt;
|return = ???&lt;br /&gt;
|description = ???&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Input ===&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = IsAbove&lt;br /&gt;
|params = x, y&lt;br /&gt;
|return = bool isAbove&lt;br /&gt;
|description = Called every Update. Must return &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; for &amp;lt;code&amp;gt;Mouse*&amp;lt;/code&amp;gt; events and &amp;lt;code&amp;gt;GetToolTip&amp;lt;/code&amp;gt; to be called.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = GetTooltip&lt;br /&gt;
|params = x, y&lt;br /&gt;
|return = string tooltip&lt;br /&gt;
|description = Called when &amp;lt;code&amp;gt;IsAbove&amp;lt;/code&amp;gt; returns true.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = KeyPress&lt;br /&gt;
|params = key, mods, isRepeat&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called repeatedly when a key is pressed down. If you want an action to occur only once check for &amp;lt;code&amp;gt;isRepeat == false&amp;lt;/code&amp;gt;. The &amp;lt;code&amp;gt;mods&amp;lt;/code&amp;gt; parameter is a table, with keys &amp;lt;code&amp;gt;alt&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ctrl&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;shift&amp;lt;/code&amp;gt; each having a boolean value. &lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = KeyRelease&lt;br /&gt;
|params = key&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called when the key is released.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = JoystickEvent&lt;br /&gt;
|params = ???&lt;br /&gt;
|return = none&lt;br /&gt;
|description = ???&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = MousePress&lt;br /&gt;
|params = x, y, button&lt;br /&gt;
|return = bool becomeMouseOwner&lt;br /&gt;
|description = Called when a mouse button is pressed. The &amp;lt;code&amp;gt;button&amp;lt;/code&amp;gt; parameter supports up to 7 buttons. Must return &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; for &amp;lt;code&amp;gt;MouseRelease&amp;lt;/code&amp;gt; and other functions to be called.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = MouseRelease&lt;br /&gt;
|params = x, y, button&lt;br /&gt;
|return = bool becomeMouseOwner&lt;br /&gt;
|description = Called when a mouse button is released. Please note that in order to have Spring call &amp;lt;code&amp;gt;MouseRelease&amp;lt;/code&amp;gt;, you need to have a &amp;lt;code&amp;gt;MousePress&amp;lt;/code&amp;gt; call-in in the same addon that returns &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = MouseWheel&lt;br /&gt;
|params = up, value&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called when the mouse wheel is moved. The parameters indicate the direction and amount of travel.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = MouseMove&lt;br /&gt;
|params = x, y, dx, dy, button&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called when the mouse is moved. The &amp;lt;code&amp;gt;dx&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;dy&amp;lt;/code&amp;gt; parameters indicate the distance travelled, whereas the first two indicate the final position.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Players ===&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = PlayerChanged&lt;br /&gt;
|params = playerID&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called whenever a player&#039;s status changes e.g. becoming a spectator.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = PlayerAdded&lt;br /&gt;
|params = playerID&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called whenever a new player joins the game.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = PlayerRemoved&lt;br /&gt;
|params = playerID, reason&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called whenever a player is removed from the game.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Drawing ===&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = ViewResize&lt;br /&gt;
|params = viewSizeX, viewSizeY&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called whenever the window is resized.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = Update&lt;br /&gt;
|params = none&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called for every draw frame. The parameter is the time since the last update. Perform calculations in here and only drawing in Draw* callins.}}&lt;br /&gt;
&lt;br /&gt;
Inside the Draw* functions, you can use the [[Lua_OpenGL_Api | Lua OpenGL Api]] to draw graphics.&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = DrawGenesis&lt;br /&gt;
|params =&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Doesn&#039;t render to screen! Use this callin to update textures, shaders, etc.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = DrawWorldPreUnit&lt;br /&gt;
|params = &lt;br /&gt;
|return = none&lt;br /&gt;
|description = Spring draws units, features, some water types, cloaked units, and the sun.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = DrawWorld&lt;br /&gt;
|params =&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Spring draws command queues, &#039;map stuff&#039;, and map marks.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = DrawWorldShadow&lt;br /&gt;
|params =&lt;br /&gt;
|return = none&lt;br /&gt;
|description = ???&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = DrawWorldReflection&lt;br /&gt;
|params =&lt;br /&gt;
|return = none&lt;br /&gt;
|description = ???&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = DrawWorldRefraction&lt;br /&gt;
|params =&lt;br /&gt;
|return = none&lt;br /&gt;
|description = ???&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = DrawScreen&lt;br /&gt;
|params = &lt;br /&gt;
|return = none&lt;br /&gt;
|description = ???&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = DrawScreenEffects&lt;br /&gt;
|params = vsx, vsy&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Where &amp;lt;code&amp;gt;vsx&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;vsy&amp;lt;/code&amp;gt; are screen coords.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = DrawLoadScreen&lt;br /&gt;
|params =&lt;br /&gt;
|return = none&lt;br /&gt;
|description = {{new|95.0}} Only available to LuaIntro, draws custom load screens.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = DrawInMinimap&lt;br /&gt;
|params = sx, sy&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Where &amp;lt;code&amp;gt;sx&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;sy&amp;lt;/code&amp;gt; are values relative to the minimap&#039;s position and scale.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Custom Object Rendering ===&lt;br /&gt;
For the following calls &amp;lt;code&amp;gt;drawMode&amp;lt;/code&amp;gt; can be one of the following, &amp;lt;code&amp;gt;notDrawing = 0&amp;lt;/code&amp;gt;,	&amp;lt;code&amp;gt;normalDraw = 1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;shadowDraw = 2&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;reflectionDraw = 3&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;refractionDraw = 4&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = DrawUnit&lt;br /&gt;
|params = unitID, drawMode&lt;br /&gt;
|return = bool suppressEngineDraw&lt;br /&gt;
|description = For custom rendering of units, [[Lua_UnitRendering#Lua.27s_DrawXYZ-Callin|enabled here]].	&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = DrawFeature&lt;br /&gt;
|params = unitID, drawMode&lt;br /&gt;
|return = bool suppressEngineDraw&lt;br /&gt;
|description = For custom rendering of features, [[Lua_UnitRendering#Lua.27s_DrawXYZ-Callin|enabled here]].	&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = DrawShield&lt;br /&gt;
|params = unitID, weaponID, drawMode&lt;br /&gt;
|return = bool suppressEngineDraw&lt;br /&gt;
|description = For custom rendering of [[Gamedev:WeaponDefs#Shield_(WeaponType)|shields]].&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = DrawProjectile&lt;br /&gt;
|params = projectileID, drawMode&lt;br /&gt;
|return = bool suppressEngineDraw&lt;br /&gt;
|description = For custom rendering of weapon (&amp;amp; other) projectiles.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Synced - Unsynced Shared ==&lt;br /&gt;
&lt;br /&gt;
=== Game ===&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = GameID&lt;br /&gt;
|params = gameID&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called once to deliver the gameID.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = GamePaused&lt;br /&gt;
|params = &lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called when the game is paused.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = GameOver&lt;br /&gt;
|params = winningAllyTeams&lt;br /&gt;
|return = none&lt;br /&gt;
|description = The parameter is a list of winning allyTeams, if empty the game result was undecided (like when dropping from an host).&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = GameFrame&lt;br /&gt;
|params = frame&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called for every game simulation frame (30 per second).&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = GamePreload&lt;br /&gt;
|params = &lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called before the 0 gameframe.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = GameStart&lt;br /&gt;
|params =&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called upon the start of the game.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Teams ===&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = TeamChanged&lt;br /&gt;
|params = teamID&lt;br /&gt;
|return = none&lt;br /&gt;
|description = ???&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = TeamDied&lt;br /&gt;
|params = teamID&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called when a team dies (see [[Lua_SyncedCtrl#Game_End|Spring.KillTeam]]).&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Units ===&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = UnitCreated&lt;br /&gt;
|params = unitID, unitDefID, unitTeam, builderID&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called at the moment the unit is created.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = UnitFinished&lt;br /&gt;
|params = unitID, unitDefID, unitTeam&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called at the moment the unit is completed.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = UnitFromFactory&lt;br /&gt;
|params = unitID, unitDefID, unitTeam, factID, factDefID, userOrders&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called when a factory finishes construction of a unit.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = UnitGiven&lt;br /&gt;
|params = unitID, unitDefID, newTeam, oldTeam&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called when a unit is transferred between teams.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = UnitTaken&lt;br /&gt;
|params = unitID, unitDefID, oldTeam, newTeam&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called when a unit is transferred between teams.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = UnitDamaged&lt;br /&gt;
|params =  unitID, unitDefID, unitTeam, damage, paralyzer, weaponDefID, projectileID, attackerID, attackerDefID, attackerTeam&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called when a unit is damaged (after &amp;lt;code&amp;gt;UnitPreDamaged&amp;lt;/code&amp;gt;).&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = UnitDestroyed&lt;br /&gt;
|params = unitID, unitDefID, unitTeam, attackerID, attackerDefID, attackerTeam&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called when a unit is destroyed.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = UnitUnitCollision&lt;br /&gt;
|params = colliderID, collideeID&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called when two units collide. Both units must be registered with [[Lua_System#Synced|Script.SetWatchUnit]].&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = UnitFeatureCollision&lt;br /&gt;
|params = colliderID, collideeID&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called when a unit collides with a feature. The unit must be registered with [[Lua_System#Synced|Script.SetWatchUnit]] and the feature registered with [[Lua_System#Synced|Script.SetWatchFeature]].&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = UnitCommand&lt;br /&gt;
|params = unitID, unitDefID, teamID, cmdID, cmdParams, cmdOptions&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called after when a unit accepts a command, after &amp;lt;code&amp;gt;AllowCommand&amp;lt;/code&amp;gt; returns &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = UnitCmdDone&lt;br /&gt;
|params = unitID, unitDefID, unitTeam, cmdID, cmdTag, cmdParams, cmdOpts&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called when a unit completes a command.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = UnitLoaded&lt;br /&gt;
|params = unitID, unitDefID, unitTeam, transportID, transportTeam&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called when a unit is loaded by a transport.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = UnitUnloaded&lt;br /&gt;
|params = unitID, unitDefID, unitTeam, transportID, transportTeam&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called when a unit is unloaded by a transport.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = UnitExperience&lt;br /&gt;
|params = unitID, unitDefID, unitTeam, experience, oldExperience&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called when a unit gains experience greater or equal to the minimum limit set by calling [[Lua_SyncedCtrl#Other|Spring.SetExperienceGrade]].&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = UnitIdle&lt;br /&gt;
|params = unitID, unitDefID, unitTeam&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called when a unit is idle (empty command queue).&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = UnitCloaked&lt;br /&gt;
|params = unitID, unitDefID, unitTeam&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called when a unit cloaks.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = UnitDecloaked&lt;br /&gt;
|params = unitID, unitDefID, unitTeam&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called when a unit decloaks.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = UnitMoved&lt;br /&gt;
|params = ???&lt;br /&gt;
|return = none&lt;br /&gt;
|description = ??? Not implemented in base handler&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = UnitMoveFailed&lt;br /&gt;
|params = ???&lt;br /&gt;
|return = none&lt;br /&gt;
|description = ??? Not implemented in base handler&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = StockpileChanged&lt;br /&gt;
|params = unitID, unitDefID, unitTeam, weaponNum, oldCount, newCount&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called when a units stockpile of weapons increases or decreases. See {{xtaglink|Gamedev:WeaponDefs|stockpile}}.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = UnitEnteredLos&lt;br /&gt;
|params = unitID, unitTeam, allyTeam, unitDefID&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called when a unit enters LOS of an allyteam.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = UnitLeftLos&lt;br /&gt;
|params = unitID, unitTeam, allyTeam, unitDefID&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called when a unit leaves LOS of an allyteam.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = UnitEnteredRadar&lt;br /&gt;
|params = unitID, unitTeam, allyTeam, unitDefID&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called when a unit enters radar of an allyteam.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = UnitLeftRadar&lt;br /&gt;
|params = unitID, unitTeam, allyTeam, unitDefID&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called when a unit leaves radar of an allyteam.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = UnitEnteredAir&lt;br /&gt;
|params = ???&lt;br /&gt;
|return = none&lt;br /&gt;
|description = ??? Not implemented by base handler&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = UnitLeftAir&lt;br /&gt;
|params = ???&lt;br /&gt;
|return = none&lt;br /&gt;
|description = ??? Not implemented by base handler&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = UnitEnteredWater&lt;br /&gt;
|params = ???&lt;br /&gt;
|return = none&lt;br /&gt;
|description = ??? Not implemented by base handler&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = UnitLeftWater&lt;br /&gt;
|params = ???&lt;br /&gt;
|return = none&lt;br /&gt;
|description = ??? Not implemented by base handler&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = UnitSeismicPing&lt;br /&gt;
|params = x, y, z, strength, allyTeam, unitID, unitDefID&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called when a unit emits a seismic ping. See {{xtaglink|Gamedev:UnitDefs|seismicSignature}}.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = AllowBuilderHoldFire&lt;br /&gt;
|params = unitID, unitDefID, action&lt;br /&gt;
|return = bool actionAllowed&lt;br /&gt;
|description = {{new|98.0}} {{Sourcelinkhash|5a82d750b89e72024bb0bb62cf05ea257737e0ac}}   Called when a construction unit wants to &amp;quot;use his nano beams&amp;quot;&amp;lt;br&amp;gt;action can be of following values: CMD.REPAIR, CMD.RECLAIM, CMD.RESTORE, CMD.RESURRECT, CMD.CAPTURE&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Features ===&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = FeatureCreated&lt;br /&gt;
|params = featureID, allyTeamID&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called when a feature is created.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = FeatureDamaged&lt;br /&gt;
|params =  featureID, featureDefID, featureTeam, damage, weaponDefID, projectileID, attackerID, attackerDefID, attackerTeam&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called when a feature is damaged.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = FeatureDestroyed&lt;br /&gt;
|params = featureID, allyTeamID&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called when a feature is destroyed.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = FeatureMoved&lt;br /&gt;
|params = ???&lt;br /&gt;
|return = none&lt;br /&gt;
|description = ???&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Projectiles ===&lt;br /&gt;
The following Callins are only called for weaponDefIDs registered via [[Lua_System#Synced|Script.SetWatchWeapon]].&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = ProjectileCreated&lt;br /&gt;
|params = proID, proOwnerID, weaponDefID&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called when the projectile is created.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = ProjectileDestroyed&lt;br /&gt;
|params = proID&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called when the projectile is destroyed.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Synced Only ==&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = CommandFallback&lt;br /&gt;
|params = unitID, unitDefID, unitTeam, cmdID, cmdParams, cmdOptions, cmdTag&lt;br /&gt;
|return = bool used, bool finished&lt;br /&gt;
|description = Called when the unit reaches an unknown command in its queue (i.e. one not handled by the engine). If no addon returns &amp;lt;code&amp;gt;used&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; the command is dropped, if an addon returns &amp;lt;code&amp;gt;true, true&amp;lt;/code&amp;gt; the command is removed because it&#039;s done, with &amp;lt;code&amp;gt;true, false&amp;lt;/code&amp;gt; it&#039;s kept in the queue and &amp;lt;code&amp;gt;CommandFallback&amp;lt;/code&amp;gt; gets called again on the next slowupdate.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = AllowCommand&lt;br /&gt;
|params = unitID, unitDefID, unitTeam, cmdID, cmdParams, cmdOptions, cmdTag, synced&lt;br /&gt;
|return = bool allow&lt;br /&gt;
|description = Called when the command is given, before the unit&#039;s queue is altered. The return value is whether it should be let into the queue. The queue remains untouched when a command is blocked, whether it would be queued or replace the queue.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = AllowUnitCreation&lt;br /&gt;
|params = unitDefID, builderID, builderTeam, x, y, z, facing&lt;br /&gt;
|return = bool allow&lt;br /&gt;
|description = Called just before unit is created, the boolean return value determines whether or not the creation is permitted.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = AllowUnitTransfer&lt;br /&gt;
|params = unitID, unitDefID, oldTeam, newTeam, capture&lt;br /&gt;
|return = bool allow&lt;br /&gt;
|description = Called just before a unit is transferred to a different team, the boolean return value determines whether or not the transfer is permitted.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = AllowUnitBuildStep&lt;br /&gt;
|params = builderID, builderTeam, unitID, unitDefID, part&lt;br /&gt;
|return = bool allow&lt;br /&gt;
|description = Called just before a unit progresses its build percentage, the boolean return value determines whether or not the build makes progress.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = AllowFeatureCreation&lt;br /&gt;
|params = featureDefID, teamID, x, y, z&lt;br /&gt;
|return = bool allow&lt;br /&gt;
|description = Called just before feature is created, the boolean return value determines whether or not the creation is permitted.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = AllowFeatureBuildStep&lt;br /&gt;
|params = builderID, builderTeam, featureID, featureDefID, part&lt;br /&gt;
|return = bool allow&lt;br /&gt;
|description = Called just before a feature progresses its build percentage, the boolean return value determines whether or not the progress change is permitted.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = AllowResourceLevel&lt;br /&gt;
|params = teamID, res, level&lt;br /&gt;
|return = bool allow&lt;br /&gt;
|description = Called when a team sets the sharing level of a resource, the boolean return value determines whether or not the sharing level is permitted.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = AllowResourceTransfer&lt;br /&gt;
|params = oldTeamID, newTeamID, res, amount&lt;br /&gt;
|return = bool allow&lt;br /&gt;
|description = Called just before resources are transferred between players, the boolean return value determines whether or not the transfer is permitted.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = AllowStartPosition&lt;br /&gt;
|params =  clampedX, clampedY, clampedZ, playerID, readyState, rawX, rawY, rawZ&lt;br /&gt;
|return = bool allow&lt;br /&gt;
|description = &amp;lt;code&amp;gt;clamped&amp;lt;/code&amp;gt; are the coordinates clamped into start-boxes, &amp;lt;code&amp;gt;raw&amp;lt;/code&amp;gt; is where player tried to place their marker. The &amp;lt;code&amp;gt;readyState&amp;lt;/code&amp;gt; can be any one of &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; - player picked a position, &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; - player clicked ready, &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; - game was force-started (player did not click ready) or &amp;lt;code&amp;gt;3&amp;lt;/code&amp;gt; the player failed to load. {{new|95.0}} the default &#039;failed to choose&#039; start-position is now just &amp;lt;code&amp;gt;(0,0,0)&amp;lt;/code&amp;gt;, not &amp;lt;code&amp;gt;(0,-500,0)&amp;lt;/code&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = AllowDirectUnitControl&lt;br /&gt;
|params = unitID, unitDefID, unitTeam, playerID&lt;br /&gt;
|return = bool allow&lt;br /&gt;
|description = Determines if this unit can be controlled directly in FPS view.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = AllowWeaponTargetCheck&lt;br /&gt;
|params = attackerID, attackerWeaponNum, attackerWeaponDefID&lt;br /&gt;
|return = bool allow&lt;br /&gt;
|description = Determines if this weapon can automatically generate targets itself. See also {{xtaglink|Gamedev:WeaponDefs|commandFire}} weaponDef tag.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = AllowWeaponTarget&lt;br /&gt;
|params = attackerID, targetID, attackerWeaponNum, attackerWeaponDefID, defPriority&lt;br /&gt;
|return = bool allowed, number priority&lt;br /&gt;
|description = Controls blocking of a specific target from being considered during a weapon&#039;s periodic auto-targeting sweep. The second return value controls the priority of the target (maximum of &amp;lt;code&amp;gt;1.0&amp;lt;/code&amp;gt;).&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = AllowWeaponInterceptTarget&lt;br /&gt;
|params = interceptorUnitID, interceptorWeaponID, targetProjectileID&lt;br /&gt;
|return = bool allowed&lt;br /&gt;
|description = Controls blocking of a specific intercept target from being considered during an {{xtaglink|Gamedev:WeaponDefs|interceptor}} weapon&#039;s periodic auto-targeting sweep. Only called for weaponDefIDs registered via [[Lua_System#Synced|Script.SetWatchWeapon]].&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = Explosion&lt;br /&gt;
|params = weaponDefID, px, py, pz, ownerTeamID&lt;br /&gt;
|return = bool noGfx&lt;br /&gt;
|description = Called when an explosion occurs. If it returns &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; then no graphical effects are drawn by the engine for this explosion.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = TerraformComplete&lt;br /&gt;
|params = unitID, unitDefID, unitTeam, buildUnitID, buildUnitDefID, buildUnitTeam&lt;br /&gt;
|return = bool stop&lt;br /&gt;
|description = Called when pre-building terrain levelling terraforms are completed (c.f. {{xtaglink|Gamedev:UnitDefs|levelGround}}). If the return value is &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; the current build order is terminated.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = MoveCtrlNotify&lt;br /&gt;
|params = unitID, unitDefID, unitTeam, data&lt;br /&gt;
|return = bool moveCtrlComplete&lt;br /&gt;
|description = Enable both [[Lua_MoveCtrl#Options|Spring.MoveCtrl.SetCollideStop]] and [[Lua_MoveCtrl#Options|Spring.MoveCtrl.SetTrackGround]] to enable this call-in, data was supposed to indicate the type of notification but currently never has a value other than &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; (&amp;quot;unit hit the ground&amp;quot;). The return value determines whether or not the unit should remain script-controlled (&amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt;) or return to engine controlled movement (&amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt;).&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = RecvLuaMsg&lt;br /&gt;
|params = msg, playerID&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Receives messages from unsynced sent via [[Lua_UnsyncedCtrl#SendLuaMessage|Spring.SendLuaRulesMsg]].&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = Load&lt;br /&gt;
|params = zip&lt;br /&gt;
|return = none&lt;br /&gt;
|description = Called after &amp;lt;code&amp;gt;GamePreload&amp;lt;/code&amp;gt; and before &amp;lt;code&amp;gt;GameStart&amp;lt;/code&amp;gt;. See [[Lua_SaveLoad#Load_.28_zip_.29_-.3E_nil|Lua_SaveLoad]].&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Damage Controllers ===&lt;br /&gt;
For the following callins, in addition to being a regular weapon, &amp;lt;code&amp;gt;weaponDefID&amp;lt;/code&amp;gt; may be one of the following:&lt;br /&gt;
* &amp;lt;code&amp;gt;-1&amp;lt;/code&amp;gt; - debris collision, also default of [[Lua_SyncedCtrl#Unit_Control|Spring.AddUnitDamage]]&lt;br /&gt;
* &amp;lt;code&amp;gt;-2&amp;lt;/code&amp;gt; - ground collision&lt;br /&gt;
* &amp;lt;code&amp;gt;-3&amp;lt;/code&amp;gt; - object collision&lt;br /&gt;
* &amp;lt;code&amp;gt;-4&amp;lt;/code&amp;gt; - fire damage&lt;br /&gt;
* &amp;lt;code&amp;gt;-5&amp;lt;/code&amp;gt; - water damage&lt;br /&gt;
* &amp;lt;code&amp;gt;-6&amp;lt;/code&amp;gt; - kill damage&lt;br /&gt;
* &amp;lt;code&amp;gt;-7&amp;lt;/code&amp;gt; - crush damage&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = UnitPreDamaged&lt;br /&gt;
|params = unitID, unitDefID, unitTeam, damage, paralyzer, weaponDefID, projectileID, attackerID, attackerDefID, attackerTeam&lt;br /&gt;
|return = number newDamage, number impulseMult&lt;br /&gt;
|description = Called before damage is applied to the unit, allows fine control over how much damage and [http://en.wikipedia.org/wiki/Impulse_(physics) impulse] is applied.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = ShieldPreDamaged&lt;br /&gt;
|params = proID, proOwnerID, shieldEmitterWeaponNum, shieldCarrierUnitID, bounceProjectile&lt;br /&gt;
|return = bool handleCollision&lt;br /&gt;
|description = Called before any engine shield-vs-projectile logic executes. If the return value is &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; the gadget handles the collision event and the engine does not remove the projectile.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{LuaCallin&lt;br /&gt;
|name = FeaturePreDamaged&lt;br /&gt;
|params = featureID, featureDefID, featureTeam, damage, weaponDefID, projectileID, attackerID, attackerDefID, attackerTeam&lt;br /&gt;
|return = number newDamage, number impulseMult&lt;br /&gt;
|description = Called before damage is applied to the feature, allows fine control over how much damage and [http://en.wikipedia.org/wiki/Impulse_(physics) impulse] is applied.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
[[Category: Lua]]&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=EngineChangelogForContentDevs&amp;diff=6331</id>
		<title>EngineChangelogForContentDevs</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=EngineChangelogForContentDevs&amp;diff=6331"/>
		<updated>2014-07-11T14:37:48Z</updated>

		<summary type="html">&lt;p&gt;Knorke: 98.0 small things&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==About this page==&lt;br /&gt;
This page holds informations about engine changes that are relevant to game/map makers.&lt;br /&gt;
The idea is to replace the &amp;quot;make your game ready for next release&amp;quot;-threads with a wiki page because unlike a forumpost, everybody can edit this.&lt;br /&gt;
So if you find a thread (or mantis post etc) that explains a fix, please add it here.&lt;br /&gt;
{{forumlink|topic=27777|title=Back-link to forum. Use for bumping.}}&lt;br /&gt;
&lt;br /&gt;
==Spring 98.0==&lt;br /&gt;
slight changes:&lt;br /&gt;
* fix definitions of UnitDef::Is{Strafing,Hovering}AirUnit  {{Sourcelinkhash|b95764cd25f1ad6e3972f5fb0d48cd2353a1d23f}}&lt;br /&gt;
* experience has slightly different effects: {{Sourcelinkhash|0f59e103731bb1fb7133cd0ea0693affa0372a4a}} , http://springrts.com/mantis/view.php?id=4446&lt;br /&gt;
&lt;br /&gt;
==Spring 97.0==&lt;br /&gt;
&lt;br /&gt;
==Spring 96.0==&lt;br /&gt;
&lt;br /&gt;
==Spring 95.0==&lt;br /&gt;
NOT COMPLETE: interessting changes from 25 Aug backwards to Aug 09, 2013&lt;br /&gt;
&lt;br /&gt;
* new folder structure: http://springrts.com/phpbb/viewtopic.php?f=12&amp;amp;t=30044&lt;br /&gt;
&lt;br /&gt;
* the folder &amp;quot;mods&amp;quot; isn&#039;t supported any more: {{Sourcelinkhash|7d3830a01c7e81377c1fd3369658d95b82979612}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Lua:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* change to weapon indexing in lua gadgets: {{Sourcelinkhash|ba9721b4e4a296f35efd9838a36c94ab7a9f476e}} (likely to cause index out of bounds errors in any gadgets using weapon related API calls)  ALL weapon API functions are 1-based now!&lt;br /&gt;
&lt;br /&gt;
* .moveData has been removed, use .moveDef instead {{Sourcelinkhash|4e58b8b0f7af04065878d34e5e17523246739b0c}} (detecting what type of unit a unit is, isCommander etc)&lt;br /&gt;
&lt;br /&gt;
* Spring.GetUnitNearestEnemy doesn&#039;t return neutral units anymore&lt;br /&gt;
&lt;br /&gt;
* {{Sourcelinkhash|90c897393de9dbb6ca9b5678c3efef201ee1231c}}&lt;br /&gt;
* add third return-value to Spring.GetUnitBlocking&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;new functions:&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
* {{Sourcelinkhash|90c897393de9dbb6ca9b5678c3efef201ee1231c}}&lt;br /&gt;
** add Spring.SetFeatureBlocking&lt;br /&gt;
** add Spring.GetFeatureBlockin&lt;br /&gt;
** add Spring.SetPieceProjectileParams&lt;br /&gt;
*add SetProjectileAlwaysVisible {{Sourcelinkhash|9435ac706c4955e7d7063600fa861d15b0c2bf40}}&lt;br /&gt;
* add callins FeatureDamaged and FeaturePreDamaged  {{Sourcelinkhash|85779b57d7b45010b3f6e975ce65ca601e36747d}} &lt;br /&gt;
* add Spring.GetRadarErrorParams {{Sourcelinkhash|475828d8516e048680c7467cc00085f32867ee0e}} &lt;br /&gt;
* add Spring.SetRadarErrorParams see above&lt;br /&gt;
* add Spring.SetUnitPosErrorParams {{Sourcelinkhash|0f4ed485d7eeb56b54a1953edfc21512a2b8cb91}} &lt;br /&gt;
* add Spring.GetUnitPosErrorParams see above&lt;br /&gt;
* add Spring.GetUnitWeaponCanFireunitID, weaponNum {{Sourcelinkhash|66117e4c4d57b511b8818a7f1ad3e2f5d613ede6}} &lt;br /&gt;
* add  LuaSyncedCtrl: add callouts SetFeatureVelocity and SetFeaturePhysics {{Sourcelinkhash|765994b40633798d88011ddd00cf3f4a8c5a4012}} &lt;br /&gt;
&lt;br /&gt;
* add new Game.constants: Game.gameName, Game.gameVersion, ... {{Sourcelinkhash|a813447139a01deede046723db1194c929f8704c}}  See [[Lua_ConstGame]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Misc:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;warning&amp;quot;&amp;gt;armordefs.lua MUST be updated. The fix is to simple the converter loop at end of file:&amp;lt;/span&amp;gt; [[Armordefs.lua#Example]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* load only image formats which work on all platforms, current supported image formats are:&lt;br /&gt;
 PNG, JPG, TGA, DDS, BMP  (note: no more .jp2)&lt;br /&gt;
&lt;br /&gt;
* make Gaia the default feature team, not -1/0 &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Sim&#039;&#039;&#039;&lt;br /&gt;
* sweepfiring beamlaser works (someone test?) {{Sourcelinkhash|b0295a72c42a828f4dcf9e4672dc1798c6a6abf2}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Someone check if relevant:&#039;&#039;&#039;&lt;br /&gt;
{{Sourcelinkhash|66a2b96f71ff7f1e8838038f0aeb0d5f45990c22}}&lt;br /&gt;
something with startmoving/stopmoving?&lt;br /&gt;
&lt;br /&gt;
{{Sourcelinkhash|e4dc43a3f1d622168a5634030842d6e609a5b30d}}&lt;br /&gt;
something startposition bla&lt;br /&gt;
&lt;br /&gt;
==Spring 94.0 (or 93, or 92)==&lt;br /&gt;
* gadget:UnitPreDamaged has a new projectileId argument inserted in the middle, so attackerID, attackerDefID, attackerTeam shifted position&lt;br /&gt;
* Bomb weapons need a range, or they won&#039;t be fired&lt;br /&gt;
* Spring.AddUnitDamage requires a weaponDefID (may be a bug, may be corrected for 95) http://springrts.com/mantis/view.php?id=3841&lt;br /&gt;
* QueryNanoPiece is called much less often&lt;br /&gt;
&lt;br /&gt;
==Spring 86.0, 87.0==&lt;br /&gt;
* {{forumlink|topic=27749|title=movedefs: depthmod is now a subtable.}}&lt;br /&gt;
* toairweapon tag has been removed, use onlytargetcategory instead&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* {{forumlink|topic=27773&amp;amp;start=45|title=ERROR_TYPE in WeaponDefs __index}} when looping over WeaponDefs - causes several fails.&lt;br /&gt;
[http://springrts.com/mantis/view.php?id=3019 mantis 3019]&amp;lt;br&amp;gt;&lt;br /&gt;
fixed in next release.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* builders stop reclaiming sometimes.&lt;br /&gt;
&lt;br /&gt;
fixed for next engine release: http://springrts.com/mantis/view.php?id=3012&amp;lt;br&amp;gt;&lt;br /&gt;
want it to work right now: {{forumlink|topic=27816|title=use a gadget as workaround}}&lt;br /&gt;
&lt;br /&gt;
==Spring 0.83, 84.0, 85.0==&lt;br /&gt;
* {{forumlink|topic=26358|title=Make your game ready for the next release!}}&lt;br /&gt;
* {{forumlink|topic=27057|title=instant infolog.txt}}&lt;br /&gt;
&lt;br /&gt;
* [http://springrts.com/mantis/view.php?id=2877 Changing of unit&#039;s max velocity is no longer possible]&lt;br /&gt;
* {{forumlink|topic=23992|title=Announcement: game end condition moved to Lua}}&lt;br /&gt;
* {{forumlink|topic=26993|title=Announcement: gui_buildspacing &amp;amp; minimap_startbox removed (0.83)}}&lt;br /&gt;
* {{forumlink|topic=26302|title=To Game-Devs: The &amp;quot;n&amp;quot; entry in array-like tables was removed}}&lt;br /&gt;
* AttachUnit obeys cantbetransported http://springrts.com/phpbb/viewtopic.php?f=23&amp;amp;t=30468&lt;br /&gt;
&lt;br /&gt;
==Spring 0.82==&lt;br /&gt;
* {{forumlink|topic=21883|title= Engine will stop spawning start units and resources.}} Now needs a Lua gadget.&lt;br /&gt;
&lt;br /&gt;
[[Category:Game Dev]]&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=Armordefs.lua&amp;diff=2137</id>
		<title>Armordefs.lua</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=Armordefs.lua&amp;diff=2137"/>
		<updated>2014-07-11T14:25:05Z</updated>

		<summary type="html">&lt;p&gt;Knorke: mantis 4450: [PR] Shields having entries in armorDefs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This file sorts units into different armor classes. Weapons can deal different amount of damage to different armor classes. &lt;br /&gt;
&lt;br /&gt;
=Location=&lt;br /&gt;
&amp;lt;code&amp;gt;armordefs.lua&amp;lt;/code&amp;gt; is a file in the &amp;lt;code&amp;gt;Gamedata/&amp;lt;/code&amp;gt; directory of a Spring Game.&lt;br /&gt;
&lt;br /&gt;
=Source=&lt;br /&gt;
The engine source code which parses the data from this file is viewable here:&lt;br /&gt;
&lt;br /&gt;
* {{sourcelink|file=rts/Sim/Misc/DamageArrayHandler.cpp}}&lt;br /&gt;
&lt;br /&gt;
=Details=&lt;br /&gt;
By default a damage class named &amp;quot;default&amp;quot; exists and every unit is in it.&lt;br /&gt;
So if all your weapons only deal &amp;quot;default&amp;quot; damage then this file is not needed.&lt;br /&gt;
&lt;br /&gt;
=Example=&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
local armorDefs = {&lt;br /&gt;
	tanks = {&lt;br /&gt;
		&amp;quot;supertank&amp;quot;,&lt;br /&gt;
		&amp;quot;megatank&amp;quot;,&lt;br /&gt;
	},&lt;br /&gt;
&lt;br /&gt;
	infantry = {&lt;br /&gt;
		&amp;quot;dude&amp;quot;,&lt;br /&gt;
	},&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
--NOTE: only needed for &amp;lt;95.0 (before engine was expecting a cryptic format)&lt;br /&gt;
if not(Game) or not(Game.version) then&lt;br /&gt;
  for categoryName, categoryTable in pairs(armorDefs) do&lt;br /&gt;
    local t = {}&lt;br /&gt;
    for _, unitName in pairs(categoryTable) do&lt;br /&gt;
      t[unitName] = 1&lt;br /&gt;
    end&lt;br /&gt;
    armorDefs[categoryName] = t&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return armorDefs&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Weapon Example=&lt;br /&gt;
Goes with above example, a weapon that deals 60 damage to infantry but only 5 damage to tanks:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
damage = {&lt;br /&gt;
	infantry = 60,&lt;br /&gt;
	tanks = 5,&lt;br /&gt;
},&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Shields=&lt;br /&gt;
In engine versions =&amp;lt; 96.0 the damage dealt to shields is the weapon&#039;s &#039;&#039;default&#039;&#039; value.&lt;br /&gt;
This [http://springrts.com/mantis/view.php?id=4450 changed] in v98.0&lt;br /&gt;
&lt;br /&gt;
Putting a shield into an armor class is analogical to units, ie. the armorDefs entry is its weaponDef name:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
armorDefs = {&lt;br /&gt;
  units = { &amp;quot;shieldbot&amp;quot; },&lt;br /&gt;
  shields = { &amp;quot;shieldbot_shield&amp;quot; }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then in some damage table:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;damage = {&lt;br /&gt;
  default = 123,&lt;br /&gt;
  units = 456,&lt;br /&gt;
  shields = 789&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Links to more Examples=&lt;br /&gt;
[http://code.google.com/p/zero-k/source/browse/trunk/mods/zk/gamedata/armordefs.lua zero-K]&amp;lt;br&amp;gt;&lt;br /&gt;
Contains scripting to take into account various things like EMP damage.&lt;br /&gt;
&lt;br /&gt;
[http://code.google.com/p/springtutorialgame/source/browse/trunk/SpringTutorialGame.sdd/Gamedata/armordefs.lua|Spring Tutorial Game]&amp;lt;br&amp;gt;&lt;br /&gt;
Uses default damage class, except for one unit that is &amp;quot;armored.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
[http://sourceforge.net/p/mwspring/code/899/tree/Gamedata/armordefs.lua MechCommander: Legacy]&amp;lt;br&amp;gt;&lt;br /&gt;
Automatically assigns units to an armor class based on [[Gamedev:UnitDefs|UnitDef]] tags and custom params.&lt;br /&gt;
&lt;br /&gt;
[[Category:gamedata]]&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=Lua_SyncedCtrl&amp;diff=11773</id>
		<title>Lua SyncedCtrl</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=Lua_SyncedCtrl&amp;diff=11773"/>
		<updated>2014-06-20T20:23:29Z</updated>

		<summary type="html">&lt;p&gt;Knorke: /* Teams */ AssignPlayerToTeam&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Engine_Development|Development]] &amp;lt; [[Lua_Scripting|Lua Scripting]] &amp;lt; {{FULLPAGENAME}}&lt;br /&gt;
&lt;br /&gt;
= Game End =&lt;br /&gt;
&#039;&#039;&#039;Spring.KillTeam&#039;&#039;&#039; {{new|83.0}}&lt;br /&gt;
  ( number teamID ) -&amp;gt; nil&lt;br /&gt;
&amp;lt;span class=&amp;quot;note&amp;quot;&amp;gt;Will declare a team to be dead ( no further orders can be assigned to such teams&#039;s units ), Gaia team cannot be killed.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.GameOver&#039;&#039;&#039; {{new|83.0}}&lt;br /&gt;
  ( {number allyTeamID1, number allyTeamID2, ...} ) -&amp;gt; nil&lt;br /&gt;
&amp;lt;span class=&amp;quot;note&amp;quot;&amp;gt;Will declare game over, a list of winning allyteams can be passed, if undecided ( like when dropped from the host ) it should be empty ( no winner ), in the case of a draw with multiple winners, all should be listed&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= RulesParams =&lt;br /&gt;
&amp;lt;span class=warning&amp;gt;string values are new since 95.0&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitRulesParam&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, string paramName, number|string paramValue [, table &amp;lt;span class=note&amp;gt;losAccess&amp;lt;/span&amp;gt;] ) -&amp;gt; nil&lt;br /&gt;
   &amp;lt;span class=note&amp;gt;possible keys for the losAccess table are:&lt;br /&gt;
    `private` : only readable by the ally (default)&lt;br /&gt;
    `allied`  : readable by ally + ingame allied&lt;br /&gt;
    `inlos`   : readable if the unit is in LOS&lt;br /&gt;
    `inradar` : readable if the unit is in AirLOS&lt;br /&gt;
    `public`  : readable by all&lt;br /&gt;
   note: if one condition is fulfilled all beneath it are too (e.g. if an unit is in LOS it&amp;lt;br/&amp;gt;     can read params with `inradar=true` even if the param has `inlos=false`)&lt;br /&gt;
   note2: all GameRulesParam are public, TeamRulesParams can just be `private`,`allied`&amp;lt;br/&amp;gt;     and/or `public`&lt;br /&gt;
   note3: You can read RulesParams from &#039;&#039;&#039;any&#039;&#039;&#039; Lua enviroments! With those losAccess&amp;lt;br/&amp;gt;     policies you can limit their access.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetTeamRulesParam&#039;&#039;&#039;&lt;br /&gt;
  ( number teamID, string paramName, number|string paramValue [, table &amp;lt;span class=note&amp;gt;losAccess&amp;lt;/span&amp;gt;] ) -&amp;gt; nil&lt;br /&gt;
   &amp;lt;span class=note&amp;gt;see above for further documentation of losAccess&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetGameRulesParam&#039;&#039;&#039;&lt;br /&gt;
  ( string paramName, number|string paramValue [, table &amp;lt;span class=note&amp;gt;losAccess&amp;lt;/span&amp;gt;] ) -&amp;gt; nil&lt;br /&gt;
   &amp;lt;span class=note&amp;gt;see above for further documentation of losAccess&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Resources =&lt;br /&gt;
&#039;&#039;&#039;Spring.AddTeamResource&#039;&#039;&#039;&lt;br /&gt;
  ( number teamID, string &amp;quot;metal&amp;quot; | &amp;quot;energy&amp;quot;, number amount ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.UseTeamResource&#039;&#039;&#039;&lt;br /&gt;
  ( number teamID, &lt;br /&gt;
    string &amp;quot;metal&amp;quot; | &amp;quot;energy&amp;quot;,number amount |&lt;br /&gt;
    { metal = number amount, energy = number amount}&lt;br /&gt;
  ) -&amp;gt; nil | boolean hadEnough&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetTeamResource&#039;&#039;&#039;&lt;br /&gt;
  ( number teamID, string res, number amount ) -&amp;gt; nil&lt;br /&gt;
&amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;&lt;br /&gt;
  possible values for res are:&lt;br /&gt;
    &amp;quot;m&amp;quot;  = metal&lt;br /&gt;
    &amp;quot;e&amp;quot;  = energy&lt;br /&gt;
    &amp;quot;ms&amp;quot;  = metal storage&lt;br /&gt;
    &amp;quot;es&amp;quot;  = energy storage&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetTeamShareLevel&#039;&#039;&#039;&lt;br /&gt;
  ( number teamID, string &amp;quot;metal&amp;quot; | &amp;quot;energy&amp;quot;, number amount ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.ShareTeamResource&#039;&#039;&#039; &amp;lt;span class=note&amp;gt;0.82 and later&amp;lt;/span&amp;gt;&lt;br /&gt;
  ( number teamID_src, number teamID_recv, string &amp;quot;metal&amp;quot; | &amp;quot;energy&amp;quot;, number amount ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
= Teams =&lt;br /&gt;
&#039;&#039;&#039;Spring.SetAlly&#039;&#039;&#039; {{new|98.0}}&lt;br /&gt;
  ( number firstAllyTeamID, number secondAllyTeamID, boolean ally ) -&amp;gt; nil&lt;br /&gt;
&amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;&lt;br /&gt;
Changes the value of the (one-sided) alliance between: firstAllyTeamID -&amp;gt; secondAllyTeamID&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.AssignPlayerToTeam&#039;&#039;&#039; {{new|98.0}}  {{Sourcelinkhash|7ed9a7e34814c60e5ae16281520cccc4daf3c367}}&lt;br /&gt;
  ( number playerID, number teamID)&lt;br /&gt;
&lt;br /&gt;
= Unit Handling =&lt;br /&gt;
&#039;&#039;&#039;Spring.CreateUnit&#039;&#039;&#039; &amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;note: offmap positions are clamped! (you still can use MoveCtrl todo so)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( string &amp;quot;defName&amp;quot; | number unitDefID,&lt;br /&gt;
    number x, number y, number z,&lt;br /&gt;
    (number facing | string &amp;quot;facing&amp;quot;),&lt;br /&gt;
    number teamID&lt;br /&gt;
    [, boolean build = false] &lt;br /&gt;
    [, boolean flattenGround = true]&lt;br /&gt;
    [, number unitID]&lt;br /&gt;
    [, number builderID]) -&amp;gt; number unitID | nil (meaning unit was not created)&lt;br /&gt;
&amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;&lt;br /&gt;
  possible values for facing are:&lt;br /&gt;
    &amp;quot;south&amp;quot; | &amp;quot;s&amp;quot; | 0&lt;br /&gt;
    &amp;quot;east&amp;quot;  | &amp;quot;e&amp;quot; | 1&lt;br /&gt;
    &amp;quot;north&amp;quot; | &amp;quot;n&amp;quot; | 2&lt;br /&gt;
    &amp;quot;west&amp;quot;  | &amp;quot;w&amp;quot; | 3&lt;br /&gt;
  if build is true the unit is created in &amp;quot;being built&amp;quot; state, with buildProgress = 0&lt;br /&gt;
  unitID and builderID are {{new|92.0}}, the former allowing to spawn a unit with&lt;br /&gt;
  a specific ID.&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.DestroyUnit&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID&lt;br /&gt;
    [, boolean selfd = false]&lt;br /&gt;
    [, boolean reclaimed = false]&lt;br /&gt;
    [, number attackerID ] ) -&amp;gt; nil&lt;br /&gt;
&amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;&lt;br /&gt;
 selfd := makes the unit act like it self-destructed&lt;br /&gt;
 reclaimed := don&#039;t show any DeathSequences, don&#039;t leave a wreckage.&lt;br /&gt;
   NOTE this does _not_ give back the resources to the team!&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.TransferUnit&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID,&lt;br /&gt;
    numer newTeamID&lt;br /&gt;
    [, boolean given = true ] ) -&amp;gt; nil&lt;br /&gt;
&amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;if given=false, the unit is captured&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Unit Control ==&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitCosts&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, { &lt;br /&gt;
     [ buildTime  = number amount ],&lt;br /&gt;
     [ metalCost  = number amount ],&lt;br /&gt;
     [ energyCost = number amount ]&lt;br /&gt;
   } ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitTooltip&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, string &amp;quot;tooltip&amp;quot; ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitHealth&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID,&lt;br /&gt;
    number health |&lt;br /&gt;
    { [ health   = number health ],&lt;br /&gt;
      [ capture  = number capture ],&lt;br /&gt;
      [ paralyze = number paralyze ],&lt;br /&gt;
      [ build    = number build ] }&lt;br /&gt;
  ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitMaxHealth&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, number maxHealth ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.AddUnitDamage&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, number damage&lt;br /&gt;
    [, number paralyze = 0 [, number attackerID = -1 [, number weaponID = -1&lt;br /&gt;
      [, number impulse_x [, number impulse_y [, number impulse_z ]]] ]]] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitStockpile&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID [, number stockpile [, number buildPercent ]]) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitExperience&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, number experience ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitFuel&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, number fuel ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitCrashing&#039;&#039;&#039; {{new|83.0}}&lt;br /&gt;
  ( number unitID, boolean crashing ) -&amp;gt; boolean success&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitLineage&#039;&#039;&#039; &amp;lt;span class=&amp;quot;warning&amp;quot;&amp;gt; Removed from version 83.0&amp;lt;/span&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
  ( number unitID, number teamID [, boolean isRoot] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitNeutral&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, boolean neutral ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitTarget&#039;&#039;&#039; &amp;lt;span class=&amp;quot;warning&amp;quot;&amp;gt;userTarget &amp;amp; sucess new in version 95.0&amp;lt;/span&amp;gt;&lt;br /&gt;
  ( number unitID,&lt;br /&gt;
    number enemyUnitID | number x, number y, number z,&lt;br /&gt;
    [ boolean dgun = false ], [ boolean userTarget = false ] ) -&amp;gt;  success&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitBlocking&#039;&#039;&#039; &amp;lt;span class=&amp;quot;warning&amp;quot;&amp;gt;crushable new in version 85.0&amp;lt;/span&amp;gt;&lt;br /&gt;
  ( number unitID, boolean blocking [, boolean collide [, boolean crushable]] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitBlocking&#039;&#039;&#039; {{new|95.0}} changed parameters:&lt;br /&gt;
  number unitID,&lt;br /&gt;
  boolean isBlocking,&lt;br /&gt;
  boolean isSolidObjectCollidable,&lt;br /&gt;
  boolean isProjectileCollidable,&lt;br /&gt;
  boolean isRaySegmentCollidable,&lt;br /&gt;
  boolean crushable,&lt;br /&gt;
  boolean blockEnemyPushing,&lt;br /&gt;
  boolean blockHeightChanges&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitMetalExtraction&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, number depth [,number range] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitBuildSpeed&#039;&#039;&#039;&lt;br /&gt;
  ( number builderID,&lt;br /&gt;
    number buildSpeed, [ number repairSpeed [, number reclaimSpeed&lt;br /&gt;
  [,number resurrectSpeed [, number captureSpeed [, number terraformSpeed ]] ]]] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitNanoPieces&#039;&#039;&#039; {{new|92.0}}&lt;br /&gt;
  ( number builderID, table pieces ) -&amp;gt; nil&lt;br /&gt;
This saves a lot of engine calls, by replacing:&lt;br /&gt;
function script.QueryNanoPiece() return currentpiece end&lt;br /&gt;
Use it!&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitArmored&#039;&#039;&#039; &amp;lt;span class=&amp;quot;warning&amp;quot;&amp;gt;armorMultiple new in version 0.83.x&amp;lt;/span&amp;gt;&lt;br /&gt;
  ( number unitID, boolean armored [, number armorMultiple] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitShieldState&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID [, number weaponID = -1] [, boolean enabled] [, number power] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitFlanking&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, string &amp;quot;mode&amp;quot;, number mode ) -&amp;gt; nil&lt;br /&gt;
  ( number unitID, string &amp;quot;moveFactor&amp;quot;, number factor) -&amp;gt; nil&lt;br /&gt;
  ( number unitID, string &amp;quot;minDamage&amp;quot;, number minDamage ) -&amp;gt; nil&lt;br /&gt;
  ( number unitID, string &amp;quot;mazDamage&amp;quot;, number maxDamage ) -&amp;gt; nil&lt;br /&gt;
  ( number unitID, string &amp;quot;dir&amp;quot;, number x, number y, number z) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitWeaponState&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, number weaponNum, table states ) -&amp;gt; nil&lt;br /&gt;
  ( number unitID, number weaponNum, string key, number value ) -&amp;gt; nil&lt;br /&gt;
  &amp;lt;span class=&amp;quot;note&amp;quot;&amp;gt;format of the states table:&lt;br /&gt;
    {&lt;br /&gt;
      [&amp;quot;reloadState&amp;quot; = number value,]&lt;br /&gt;
      [&amp;quot;reloadFrame&amp;quot; = number value,]   (synonym for reloadState!)&lt;br /&gt;
      [&amp;quot;reloadTime&amp;quot;  = number value,]&lt;br /&gt;
      [&amp;quot;accuracy&amp;quot;    = number value,]&lt;br /&gt;
      [&amp;quot;sprayAngle&amp;quot;  = number value,]&lt;br /&gt;
      [&amp;quot;range&amp;quot;       = number value,]&lt;br /&gt;
      [&amp;quot;projectileSpeed&amp;quot; = number value,]&lt;br /&gt;
      [&amp;quot;burst&amp;quot; = number value,]&lt;br /&gt;
      [&amp;quot;burstRate&amp;quot; = number value,]&lt;br /&gt;
      [&amp;quot;projectiles&amp;quot; = number value,]&lt;br /&gt;
      [&amp;quot;aimReady&amp;quot; = number value,] &amp;lt;span class=note&amp;gt;(&amp;lt;&amp;gt;0.0f := true)&amp;lt;/span&amp;gt;&lt;br /&gt;
    }&lt;br /&gt;
  &amp;lt;/span&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitCollisionVolumeData&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, number scaleX, number scaleY, number scaleZ,&lt;br /&gt;
    number offsetX, number offsetY, number offsetX,&lt;br /&gt;
    number vType, number tType, number Axis&lt;br /&gt;
  ) -&amp;gt; nil&lt;br /&gt;
  &amp;lt;span class=&amp;quot;note&amp;quot;&amp;gt;enum COLVOL_TYPES {&lt;br /&gt;
      COLVOL_TYPE_DISABLED = -1,&lt;br /&gt;
      COLVOL_TYPE_ELLIPSOID = 0,&lt;br /&gt;
      COLVOL_TYPE_CYLINDER,&lt;br /&gt;
      COLVOL_TYPE_BOX,&lt;br /&gt;
      COLVOL_TYPE_SPHERE,&lt;br /&gt;
      COLVOL_NUM_TYPES       // number of non-disabled collision volume types&lt;br /&gt;
    };&lt;br /&gt;
    enum COLVOL_TESTS {&lt;br /&gt;
      COLVOL_TEST_DISC = 0,&lt;br /&gt;
      COLVOL_TEST_CONT = 1,&lt;br /&gt;
      COLVOL_NUM_TESTS = 2   // number of tests&lt;br /&gt;
    };&lt;br /&gt;
    enum COLVOL_AXES {&lt;br /&gt;
      COLVOL_AXIS_X   = 0,&lt;br /&gt;
      COLVOL_AXIS_Y   = 1,&lt;br /&gt;
      COLVOL_AXIS_Z   = 2,&lt;br /&gt;
      COLVOL_NUM_AXES = 3    // number of collision volume axes&lt;br /&gt;
    };&lt;br /&gt;
  &amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitPieceCollisionVolumeData&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, number pieceIndex, boolean enable, &lt;br /&gt;
    number scaleX, number scaleY, number scaleZ,&lt;br /&gt;
    number offsetX, number offsetY, number offsetZ&lt;br /&gt;
    [, number volumeType [, number primaryAxis]]&lt;br /&gt;
  ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitTravel&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, number travel [, number travelPeriod] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitMoveGoal&#039;&#039;&#039;   &amp;lt;span class=&amp;quot;note&amp;quot;&amp;gt;used by default commands to get in build-,attackrange etc.&amp;lt;/span&amp;gt;&lt;br /&gt;
  (number unitID, number goalx, number goaly, number goalz &lt;br /&gt;
  [, number goalRadius [, number moveSpeed [, bool moveRaw ]]] )&lt;br /&gt;
{{new|98.0}} &amp;lt;span class=&amp;quot;note&amp;quot;&amp;gt;moveRaw: [http://springrts.com/mantis/view.php?id=4412 allow unit to dumbly move to a coordinate without calculating path.]&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitPhysics&#039;&#039;&#039; &amp;lt;span class=&amp;quot;warning&amp;quot;&amp;gt;drag new in version 95.0&amp;lt;/span&amp;gt;&lt;br /&gt;
  ( number unitID,&lt;br /&gt;
    number posx, number posy, number posz,&lt;br /&gt;
    number velx, number vely, number velz,&lt;br /&gt;
    number rotx, number roty, number rotz,&lt;br /&gt;
    number dragx, number dragy, number dragz,&lt;br /&gt;
  ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitPosition&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, number x, number z [, boolean alwaysAboveSea] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitDirection&#039;&#039;&#039; {{new|90.0}}&lt;br /&gt;
  ( number unitID, number x, number y, number z ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitVelocity&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, number velx, number vely, number velz ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitRotation&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, number rotx, number roty, number rotz ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.AddUnitImpulse&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, number x, number y, number z [, decayRate ] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.AddUnitSeismicPing&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, number pingSize ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.RemoveBuildingDecal&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitMidAndAimPos&#039;&#039;&#039; {{new|89.0}}&lt;br /&gt;
  ( number unitID, &lt;br /&gt;
    number mpx, number mpy, number mpz, &lt;br /&gt;
    number apx, number apy, number apz, &lt;br /&gt;
    [, boolean relative] ) -&amp;gt; boolean success&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;&lt;br /&gt;
mpx, mpy, mpz: new middle position of unit&lt;br /&gt;
&lt;br /&gt;
apx, apy, apz: new position that enemies aim at on this unit&lt;br /&gt;
&lt;br /&gt;
relative: are the new coordinates relative to world or unit coordinates?&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitRadiusAndHeight&#039;&#039;&#039; {{new|89.0}}&lt;br /&gt;
  ( number unitID, number radius, number height ) -&amp;gt; boolean success&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitWeaponFire&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, number weaponID ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitWeaponHoldFire&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, number weaponID ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
== Unit LOS ==&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitCloak&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID,&lt;br /&gt;
    boolean cloaked | number scriptCloak,&lt;br /&gt;
    [ number decloakDistance | boolean decloakAbs ] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;&lt;br /&gt;
  If the 2nd argument is a number, the value works like this:&lt;br /&gt;
   1:=normal cloak&lt;br /&gt;
   2:=for free cloak (cost no E)&lt;br /&gt;
   3:=for free + no decloaking (except the unit is stunned)&lt;br /&gt;
   4&amp;gt;=ultimative cloak (no ecost, no decloaking, no stunned decloak)&lt;br /&gt;
&lt;br /&gt;
  The decloak distance is only changed if the 3th argument is a number or a boolean.&lt;br /&gt;
   If the boolean is false it takes the default decloak distance for that unitdef,&lt;br /&gt;
   if the boolean is true it takes the absolute value of it.&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitSonarStealth&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, boolean sonarStealth ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitStealth&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, boolean stealth ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitAlwaysVisible&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, boolean alwaysVisible ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitLosMask&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, number allyTeam, number los | table losTypes ) -&amp;gt; nil&lt;br /&gt;
&amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;the 3th argument is either the bit-and combination of the following numbers:&lt;br /&gt;
  LOS_INLOS     = 1&lt;br /&gt;
  LOS_INRADAR   = 2&lt;br /&gt;
  LOS_PREVLOS   = 4&lt;br /&gt;
  LOS_CONTRADAR = 8&lt;br /&gt;
&amp;lt;/font&amp;gt;&amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;or a table of the following form:&lt;br /&gt;
  losTypes = {&lt;br /&gt;
    [los = boolean,]&lt;br /&gt;
    [radar = boolean,]&lt;br /&gt;
    [prevLos = boolean,]&lt;br /&gt;
    [contRadar = boolean,]&lt;br /&gt;
  }&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitLosState&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, number allyTeam, number los | table losTypes ) -&amp;gt; nil&lt;br /&gt;
  &amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;see above for more info on the arguments&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitSensorRadius&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, string type, number radius ) -&amp;gt; nil | number newRadius&lt;br /&gt;
  &amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;type can be:&lt;br /&gt;
  &amp;quot;los&amp;quot;,&amp;quot;airLos&amp;quot;,&amp;quot;radar&amp;quot;,&amp;quot;sonar&amp;quot;,&amp;quot;seismic&amp;quot;,&amp;quot;radarJammer&amp;quot;,&amp;quot;sonarJammer&amp;quot;&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetRadarErrorParams&#039;&#039;&#039; {{new|95.0}}&lt;br /&gt;
  (number allyTeamID, number allyteamErrorSize &lt;br /&gt;
  [, number baseErrorSize [, number baseErrorMult ]]) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitPosErrorParams&#039;&#039;&#039; {{new|95.0}}&lt;br /&gt;
  (number unitID, number posErrorVector.x, number posErrorVector.y, number posErrorVector.z,&lt;br /&gt;
  number posErrorDelta.x, number posErrorDelta.y, number posErrorDelta.z&lt;br /&gt;
  [ , number nextPosErrorUpdate]) --&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
== Unit Resourcing ==&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitResourcing&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID,&lt;br /&gt;
    string res, number amount |&lt;br /&gt;
    { res = number amount, ... }&lt;br /&gt;
  ) -&amp;gt; nil&lt;br /&gt;
&amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;&lt;br /&gt;
  possible values for res are: &amp;quot;[u|c][u|m][m|e]&amp;quot;&lt;br /&gt;
       unconditional | conditional&lt;br /&gt;
                 use | make&lt;br /&gt;
               metal | energy&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.AddUnitResource&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, string &amp;quot;m&amp;quot; | &amp;quot;e&amp;quot;, number amount ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UseUnitResource&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, string &amp;quot;m&amp;quot; | &amp;quot;e&amp;quot;, number amount ) -&amp;gt; nil | boolean okay&lt;br /&gt;
  ( number unitID, { [&amp;quot;m&amp;quot; | &amp;quot;metal&amp;quot; | &amp;quot;e&amp;quot; | &amp;quot;energy&amp;quot;] = amount, ... } ) -&amp;gt; nil | boolean okay&lt;br /&gt;
&lt;br /&gt;
= Feature Handling =&lt;br /&gt;
&#039;&#039;&#039;Spring.CreateFeature&#039;&#039;&#039;&lt;br /&gt;
  ( string &amp;quot;defName&amp;quot; | number featureDefID, &lt;br /&gt;
    number x, number y, number z&lt;br /&gt;
    [, number heading &lt;br /&gt;
    [, number AllyTeamID &lt;br /&gt;
    [, number featureID ]]] ) -&amp;gt; number featureID&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.DestroyFeature&#039;&#039;&#039;&lt;br /&gt;
  ( number featureID ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.TransferFeature&#039;&#039;&#039;&lt;br /&gt;
  ( number featureID, number teamID ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Feature Control ==&lt;br /&gt;
&#039;&#039;&#039;Spring.SetFeatureHealth&#039;&#039;&#039;&lt;br /&gt;
  ( number featureID, number health) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetFeatureReclaim&#039;&#039;&#039;&lt;br /&gt;
  ( number featureID, number reclaimLeft) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetFeatureResurrect&#039;&#039;&#039;&lt;br /&gt;
  ( number featureID, string &amp;quot;UnitDefName?&amp;quot; [, number facing | string &amp;quot;facing&amp;quot; ] ) -&amp;gt; nil&lt;br /&gt;
&amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;&lt;br /&gt;
  possible values for facing are:&lt;br /&gt;
    &amp;quot;south&amp;quot; | &amp;quot;s&amp;quot; | 0&lt;br /&gt;
    &amp;quot;east&amp;quot;  | &amp;quot;e&amp;quot; | 1&lt;br /&gt;
    &amp;quot;north&amp;quot; | &amp;quot;n&amp;quot; | 2&lt;br /&gt;
    &amp;quot;west&amp;quot;  | &amp;quot;w&amp;quot; | 3&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetFeaturePosition&#039;&#039;&#039;&lt;br /&gt;
  ( number featureID, number x, number y, number z [, boolean snapToGround]) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetFeatureDirection&#039;&#039;&#039;&lt;br /&gt;
  ( number featureID, number x, number y, number z ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetFeatureVelocity&#039;&#039;&#039; {{New|95.0}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetFeaturePhysics&#039;&#039;&#039; {{New|95.0}}&lt;br /&gt;
&lt;br /&gt;
(like their feature counterparts at [[Lua_SyncedCtrl#Unit_Control]])&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetFeatureNoSelect&#039;&#039;&#039;&lt;br /&gt;
  ( number featureID, boolean noSelect ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetFeatureAlwaysVisible&#039;&#039;&#039;&lt;br /&gt;
  ( number featureID, boolean enable ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetFeatureCollisionVolumeData&#039;&#039;&#039;&lt;br /&gt;
  ( number featureID, number scaleX, number scaleY, number scaleZ,&lt;br /&gt;
    number offsetX, number offsetY, number offsetX,&lt;br /&gt;
    number vType, number tType, number Axis&lt;br /&gt;
  ) -&amp;gt; nil&lt;br /&gt;
  &amp;lt;span class=note&amp;gt;check Spring.SetUnitCollisionVolumeData for further explanation of the arguments&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetFeatureMidAndAimPos&#039;&#039;&#039; {{new|89.0}}&lt;br /&gt;
  ( number unitID, &lt;br /&gt;
    number mpx, number mpy, number mpz, &lt;br /&gt;
    number apx, number apy, number apz, &lt;br /&gt;
    [, boolean relative] ) -&amp;gt; boolean success&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;span class=note&amp;gt;check Spring.SetUnitMidAndAimPos for further explanation of the arguments&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetFeatureRadiusAndHeight&#039;&#039;&#039; {{new|89.0}}&lt;br /&gt;
  ( number unitID, number radius, number height ) -&amp;gt; boolean success&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetFeatureBlocking&#039;&#039;&#039;&lt;br /&gt;
  (number featureID, boolean blocking, boolean collidable) --&amp;gt; boolean&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetFeatureBlocking&#039;&#039;&#039; {{new|95.0}} changed parameters:&lt;br /&gt;
  number featureID,&lt;br /&gt;
  boolean isBlocking,&lt;br /&gt;
  boolean isSolidObjectCollidable,&lt;br /&gt;
  boolean isProjectileCollidable,&lt;br /&gt;
  boolean isRaySegmentCollidable,&lt;br /&gt;
  boolean crushable,&lt;br /&gt;
  boolean blockEnemyPushing,&lt;br /&gt;
  boolean blockHeightChanges&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Lua to COB =&lt;br /&gt;
&#039;&#039;&#039;Spring.CallCOBScript&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, number funcID | string funcName, number retArgs, COBArg1, COBArg2, ... )&lt;br /&gt;
    -&amp;gt; nil | number returnValue, number retArg1, number retArg2, ...&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.CallCOBScriptCB&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;font style=&amp;quot;color:red;font-weight:600&amp;quot;&amp;gt;broken in 0.78.2.1; will be removed with the introduction of Lua as COB replacement&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( number unitID, number funcID | string funcName, number retArgs, COBArg1, COBArg2, ... )&lt;br /&gt;
    -&amp;gt; nil | number returnValue, number CallbackData, number retArg1, number retArg2, ...&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.GetCOBScriptID&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, string funcName ) -&amp;gt; nil | number funcID&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;warning&amp;quot;&amp;gt;&amp;lt;b&amp;gt;Note: Don&#039;t use Spring.[Get|Set]UnitCOBValue in LUS just because you are familar with it since bos/cob, use the mighty LuaSpringAPI instead!&amp;lt;/b&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.GetUnitCOBValue&#039;&#039;&#039; &lt;br /&gt;
  ( number unitID [, boolean splitData=false], number COBValue&lt;br /&gt;
    [, number param1 [,number param2 [, number param3 [, number param4 ] ] ] ] )&lt;br /&gt;
  -&amp;gt; number result | number result1, number result2&lt;br /&gt;
  &amp;lt;span class=note&amp;gt;you find the possible values for `COBValue` in [[Lua_ConstCOB#Get.2FSet|Lua_ConstCOB]]&amp;lt;/span&amp;gt;&lt;br /&gt;
  &amp;lt;span class=note&amp;gt; also see [[Animation-CobConstants#Custom_Variables|Custom_Variables]]&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitCOBValue&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, number COBValue, number param1 [,number param2] ) -&amp;gt; nil&lt;br /&gt;
  &amp;lt;span class=note&amp;gt;you find the possible values for `COBValue` in [[Lua_ConstCOB#Get.2FSet|Lua_ConstCOB]]&amp;lt;/span&amp;gt;&lt;br /&gt;
  &amp;lt;span class=note&amp;gt; also see [[Animation-CobConstants#Custom_Variables|Custom_Variables]]&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Give Order =&lt;br /&gt;
&amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;options can also be a bitmask; e.g. 0 instead of an empty table (can avoid performance hit on table creation)&amp;lt;br&amp;gt;&lt;br /&gt;
see [[Lua CMDs]] for relevant constants&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.GiveOrderToUnit&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID,&lt;br /&gt;
    number cmdID,&lt;br /&gt;
    params = {number, etc...},&lt;br /&gt;
    options = {&amp;quot;alt&amp;quot;, &amp;quot;ctrl&amp;quot;, &amp;quot;shift&amp;quot;, &amp;quot;right&amp;quot;} ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.GiveOrderToUnitMap&#039;&#039;&#039;&lt;br /&gt;
  ( unitMap = { [unitID] = dontCare, etc... },&lt;br /&gt;
    number cmdID,&lt;br /&gt;
    params = {number, etc...},&lt;br /&gt;
    options = {&amp;quot;alt&amp;quot;, &amp;quot;ctrl&amp;quot;, &amp;quot;shift&amp;quot;, &amp;quot;right&amp;quot;} ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.GiveOrderToUnitArray&#039;&#039;&#039;&lt;br /&gt;
  ( unitArray = { [1] = unitID, etc... },&lt;br /&gt;
    number cmdID,&lt;br /&gt;
    params = {number, etc...},&lt;br /&gt;
    options = {&amp;quot;alt&amp;quot;, &amp;quot;ctrl&amp;quot;, &amp;quot;shift&amp;quot;, &amp;quot;right&amp;quot;} ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.GiveOrderArrayToUnitMap&#039;&#039;&#039;&lt;br /&gt;
  ( unitMap = { [number unitID] = dontCare, etc... },&lt;br /&gt;
    orderArray = {&lt;br /&gt;
      { number cmdID,&lt;br /&gt;
        {number, etc...},     &amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;params&amp;lt;/font&amp;gt;&lt;br /&gt;
        {&amp;quot;alt&amp;quot;, &amp;quot;ctrl&amp;quot;, &amp;quot;shift&amp;quot;, &amp;quot;right&amp;quot;}   &amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;options&amp;lt;/font&amp;gt;&lt;br /&gt;
      }, ..&lt;br /&gt;
    }&lt;br /&gt;
  ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.GiveOrderArrayToUnitArray&#039;&#039;&#039;&lt;br /&gt;
  ( unitArray = { [1] = number unitID, etc... },&lt;br /&gt;
    orderArray = {&lt;br /&gt;
      { number cmdID,&lt;br /&gt;
        {number, etc...},    &amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;params&amp;lt;/font&amp;gt;&lt;br /&gt;
        {&amp;quot;alt&amp;quot;, &amp;quot;ctrl&amp;quot;, &amp;quot;shift&amp;quot;, &amp;quot;right&amp;quot;}   &amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;options&amp;lt;/font&amp;gt;&lt;br /&gt;
      }, ..&lt;br /&gt;
    }&lt;br /&gt;
  ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
=Ground=&lt;br /&gt;
== Grass ==&lt;br /&gt;
&#039;&#039;&#039;Spring.AddGrass&#039;&#039;&#039;&lt;br /&gt;
  ( number x, number z ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.RemoveGrass&#039;&#039;&#039;&lt;br /&gt;
  ( number x, number z ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
== Heightmap ==&lt;br /&gt;
&amp;lt;span class=&amp;quot;note&amp;quot;&amp;gt;Note that x &amp;amp; z coords are in worldspace (Game.mapSizeX/Z), still the heightmap resolution is Game.squareSize.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.LevelHeightMap&#039;&#039;&#039;&lt;br /&gt;
  ( number x1, number z1 [, number x2, number z2], number height ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.AdjustHeightMap&#039;&#039;&#039; &amp;lt;span class=&amp;quot;note&amp;quot;&amp;gt;(heightmap[x][z] += height;)&amp;lt;/span&amp;gt;&lt;br /&gt;
  ( number x1, number z1 [, number x2, number z2], number height ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.RevertHeightMap&#039;&#039;&#039;&lt;br /&gt;
  ( number x1, number z1 [, number x2, number z2], number origFactor ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetHeightMapFunc&#039;&#039;&#039;&lt;br /&gt;
  ( lua_function [, arg1 ,[ arg2 [, ... ] ] ) -&amp;gt; nil | number absTotalHeightMapAmountChanged&lt;br /&gt;
&amp;lt;span class=&amp;quot;note&amp;quot;&amp;gt;Example code:&amp;lt;/span&amp;gt;&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
Spring.SetHeightMapFunc(function()&lt;br /&gt;
	for z=0,Game.mapSizeZ, Game.squareSize do&lt;br /&gt;
		for x=0,Game.mapSizeX, Game.squareSize do&lt;br /&gt;
			Spring.SetHeightMap( x, z, 200 + 20 * math.cos((x + z) / 90) )&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Spring.AddHeightMap&#039;&#039;&#039; &amp;lt;span class=&amp;quot;warning&amp;quot;&amp;gt;can only be called in SetHeightMapFunc()&amp;lt;/span&amp;gt; &lt;br /&gt;
  ( number x, number z, number height ) -&amp;gt; nil | number newHeight&lt;br /&gt;
&#039;&#039;&#039;Spring.SetHeightMap&#039;&#039;&#039; &amp;lt;span class=&amp;quot;warning&amp;quot;&amp;gt;can only be called in SetHeightMapFunc()&amp;lt;/span&amp;gt;&lt;br /&gt;
  ( number x, number z, number height [,number terraform = 1] ) -&amp;gt; nil | number absHeightDiff&lt;br /&gt;
&amp;lt;span class=&amp;quot;note&amp;quot;&amp;gt;the terraform argument is a scaling factor:&lt;br /&gt;
so if 0 nothing will be changed (the terraform starts) and if it is 1 the terraform will be finished.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.LevelSmoothMesh&#039;&#039;&#039;&lt;br /&gt;
  ( number x1, number z1 [, number x2, number z2], number height ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.AdjustSmoothMesh&#039;&#039;&#039;&lt;br /&gt;
  ( number x1, number z1 [, number x2, number z2], number height ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.RevertSmoothMesh&#039;&#039;&#039;&lt;br /&gt;
  ( number x1, number z1 [, number x2, number z2], number origFactor ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetSmoothMeshFunc&#039;&#039;&#039;&lt;br /&gt;
  ( lua_function [, arg1 ,[ arg2 [, ... ] ] ) -&amp;gt; nil | number absTotalHeightMapAmountChanged&lt;br /&gt;
&#039;&#039;&#039;Spring.AddSmoothMesh&#039;&#039;&#039; &amp;lt;span class=&amp;quot;warning&amp;quot;&amp;gt;can only be called in SetSmoothMeshFunc()&amp;lt;/span&amp;gt; &lt;br /&gt;
  ( number x, number z, number height ) -&amp;gt; nil | number newHeight&lt;br /&gt;
&#039;&#039;&#039;Spring.SetSmoothMesh&#039;&#039;&#039; &amp;lt;span class=&amp;quot;warning&amp;quot;&amp;gt;can only be called in SetSmoothMeshFunc()&amp;lt;/span&amp;gt;&lt;br /&gt;
  ( number x, number z, number height [,number terraform = 1] ) -&amp;gt; nil | number absHeightDiff&lt;br /&gt;
&lt;br /&gt;
== TerrainTypes ==&lt;br /&gt;
&#039;&#039;&#039;Spring.SetMapSquareTerrainType&#039;&#039;&#039;&lt;br /&gt;
  ( number x, number z, int newType ) -&amp;gt; nil | int oldType&lt;br /&gt;
&#039;&#039;&#039;Spring.SetTerrainTypeData&#039;&#039;&#039;&lt;br /&gt;
  ( int typeIndex&lt;br /&gt;
  [, number speedTanks = nil ]&lt;br /&gt;
  [, number speedKBOTs = nil ]&lt;br /&gt;
  [, number speedHovers = nil ]&lt;br /&gt;
  [, number speedShips = nil ] ) -&amp;gt; nil | boolean true&lt;br /&gt;
&lt;br /&gt;
== MetalAmount ==&lt;br /&gt;
&#039;&#039;&#039;Spring.SetMetalAmount&#039;&#039;&#039; {{new|83.0}}&lt;br /&gt;
  ( number x, number z, number metalAmount)&lt;br /&gt;
&amp;lt;span class=&amp;quot;note&amp;quot;&amp;gt;x &amp;amp; z coords are in worldspace/16&amp;lt;br&amp;gt;metalAmount must be between 0 and 255*maxMetal (with maxMetal from the .smd or mapinfo.lua)&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Command Descriptions =&lt;br /&gt;
&amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-size:120%; font-weight:600&amp;quot;&amp;gt;Doesn&#039;t work in unsynced code!&amp;lt;/font&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.EditUnitCmdDesc&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, number cmdDescID, table cmdArray ) -&amp;gt; nil&lt;br /&gt;
&amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;&lt;br /&gt;
  structure of cmdArray:&lt;br /&gt;
  {&lt;br /&gt;
    [ id          = int ],&lt;br /&gt;
    [ type        = int ],&lt;br /&gt;
    [ name        = string ],&lt;br /&gt;
    [ action      = string ],&lt;br /&gt;
    [ tooltip     = string ],&lt;br /&gt;
    [ texture     = string ],&lt;br /&gt;
    [ cursor      = string ],&lt;br /&gt;
    [ hidden      = boolean ],&lt;br /&gt;
    [ disabled    = boolean ],&lt;br /&gt;
    [ showUnique  = boolean ],&lt;br /&gt;
    [ onlyTexture = boolean ],&lt;br /&gt;
    [ params      = { string = string, ... } ]&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.InsertUnitCmdDesc&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID [, number cmdDescID ] , table cmdArray ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.RemoveUnitCmdDesc&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID [, number cmdDescID ] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
= Other =&lt;br /&gt;
&#039;&#039;&#039;Spring.SetNoPause&#039;&#039;&#039;&lt;br /&gt;
  ( boolean noPause ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitToFeature&#039;&#039;&#039;&lt;br /&gt;
  ( boolean tofeature ) -&amp;gt; nil&lt;br /&gt;
&amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;&lt;br /&gt;
an ugly global switch that can be used to block units turning into features when they finish being built (like *A DT&#039;s do, which have the isFeature tag)&lt;br /&gt;
[http://springrts.com/phpbb/viewtopic.php?f=14&amp;amp;p=481521 thread]&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetExperienceGrade&#039;&#039;&#039;&lt;br /&gt;
  ( number expGrade&lt;br /&gt;
   &amp;lt;font color=#55ee99&amp;gt;[, number ExpPowerScale [, number ExpHealthScale [, number ExpReloadScale ]]]&amp;lt;/font&amp;gt; ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;expGrade defines how often UnitExperience() will be called,&lt;br /&gt;
   it is based on the following equation:&lt;br /&gt;
     (int) [exp/(exp+1)] / expGrade&lt;br /&gt;
   If this integer differs from the one before the experience change&lt;br /&gt;
   it will call UnitExperience().&lt;br /&gt;
  Also those 3 last params are only available in .cheat&lt;br /&gt;
  &amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SpawnCEG&#039;&#039;&#039;&lt;br /&gt;
  ( string &amp;quot;cegname&amp;quot; | number cegID,&lt;br /&gt;
    number posX = 0, number posY = 0, number posZ = 0,&lt;br /&gt;
    number dirX = 0, number dirY = 0, number dirZ = 0,&lt;br /&gt;
    number radius = 0, number damage = 0&lt;br /&gt;
  ) -&amp;gt; nil | boolean success, cegID&lt;br /&gt;
&amp;lt;span class=&amp;quot;warning&amp;quot;&amp;gt;cegID new in 95.0&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Projectiles =&lt;br /&gt;
&#039;&#039;&#039;Spring.SpawnProjectile&#039;&#039;&#039;&lt;br /&gt;
  ( number weaponDefID, table projectileParams ) -&amp;gt; nil | number projectileID&lt;br /&gt;
  &amp;lt;span class=note&amp;gt;possible keys of projectileParams are:&lt;br /&gt;
    pos = {number x, number y, number z},&lt;br /&gt;
    end = {number x, number y, number z},&lt;br /&gt;
    speed = {number x, number y, number z},&lt;br /&gt;
    spread = {number x, number y, number z},&lt;br /&gt;
    error = {number x, number y, number z},&lt;br /&gt;
    owner = number,&lt;br /&gt;
    team = number,&lt;br /&gt;
    ttl = number,&lt;br /&gt;
    gravity = number,&lt;br /&gt;
    tracking = number,&lt;br /&gt;
    maxRange = number,&lt;br /&gt;
    startAlpha = number,&lt;br /&gt;
    endAlpha = number,&lt;br /&gt;
    model = string,&lt;br /&gt;
    cegTag = string,&lt;br /&gt;
  &amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetProjectileTarget&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class = &amp;quot;warning&amp;quot;&amp;gt;Pre 95.0:&amp;lt;/span&amp;gt;  ( number projectileID, &lt;br /&gt;
    [ number targetID, string targetTypeStr ] | [ number posX, number posY, number posZ ] ) &lt;br /&gt;
    -&amp;gt; nil | boolean validTarget&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class = &amp;quot;warning&amp;quot;&amp;gt;Post 95.0:&amp;lt;/span&amp;gt;  ( number projectileID, &lt;br /&gt;
    [ number targetID [, number targetType]]  |  [number posX, number posY, number posZ]) &lt;br /&gt;
    --&amp;gt; nil | boolean validTarget&lt;br /&gt;
  &amp;lt;span class=note&amp;gt;targetTypeStr can be one of: &lt;br /&gt;
    &#039;u&#039; - unit&lt;br /&gt;
    &#039;f&#039; - feature&lt;br /&gt;
    &#039;p&#039; - projectile&lt;br /&gt;
  while targetTypeInt is one of:&lt;br /&gt;
    string.byte(&#039;g&#039;) := GROUND&lt;br /&gt;
    string.byte(&#039;u&#039;) := UNIT&lt;br /&gt;
    string.byte(&#039;f&#039;) := FEATURE&lt;br /&gt;
    string.byte(&#039;p&#039;) := PROJECTILE&lt;br /&gt;
  &amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetProjectileMoveControl&#039;&#039;&#039; &amp;lt;span class=note&amp;gt;(disables engine movecontrol, so lua can fully control the physics)&amp;lt;/span&amp;gt;&lt;br /&gt;
  ( number projID, boolean enable ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.SetProjectilePosition&#039;&#039;&#039;&lt;br /&gt;
  ( number projID [, number x = 0 [, number y = 0 [, number z = 0 ]]] ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.SetProjectileVelocity&#039;&#039;&#039;&lt;br /&gt;
  ( number projID [, number x = 0 [, number y = 0 [, number z = 0 ]]] ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.SetProjectileCollision&#039;&#039;&#039;&lt;br /&gt;
  ( number projID ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.SetProjectileGravity&#039;&#039;&#039; &lt;br /&gt;
  ( number projID [, number grav = 0] ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.SetProjectileSpinAngle&#039;&#039;&#039; {{new|95.0}} Deprecated&lt;br /&gt;
  ( number projID [, number spinAngle = 0] ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.SetProjectileSpinSpeed&#039;&#039;&#039; {{new|95.0}} Deprecated&lt;br /&gt;
  ( number projID [, number speed = 0] ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.SetProjectileSpinVec&#039;&#039;&#039; {{new|95.0}} Deprecated&lt;br /&gt;
  ( number projID [, number x = 0 [, number y = 0 [, number z = 0]]] ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.SetProjectileCEG&#039;&#039;&#039;&lt;br /&gt;
  ( number projID, string ceg_name ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetPieceProjectileParams&#039;&#039;&#039; {{new|95.0}} &lt;br /&gt;
  (number projectileID,&lt;br /&gt;
  [ number explosionFlags, [ number spinAngle, [ number spinSpeed,&lt;br /&gt;
  [ number spinVector.x, [ number spinVector.y, [ number spinVector.z ]]]]]]) --&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetProjectileAlwaysVisible&#039;&#039;&#039; {{new|95.0}} &lt;br /&gt;
    (number projectileID, boolean alwaysVisible) --&amp;gt; nil&lt;br /&gt;
[[category: Lua]]&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=Lua_UnsyncedRead&amp;diff=12389</id>
		<title>Lua UnsyncedRead</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=Lua_UnsyncedRead&amp;diff=12389"/>
		<updated>2014-06-20T19:52:01Z</updated>

		<summary type="html">&lt;p&gt;Knorke: /* Unsynced Read */ GetClipboard&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Engine_Development|Development]] &amp;lt; [[Lua_Scripting|Lua Scripting]] &amp;lt; {{FULLPAGENAME}}&lt;br /&gt;
=Unsynced Read=&lt;br /&gt;
&lt;br /&gt;
== Replay/Spectating ==&lt;br /&gt;
&#039;&#039;&#039;Spring.IsReplay&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; nil | boolean&lt;br /&gt;
&#039;&#039;&#039;Spring.GetReplayLength&#039;&#039;&#039; {{new|92.0}}&lt;br /&gt;
  ( ) -&amp;gt; nil | number (in gameframes)&lt;br /&gt;
&#039;&#039;&#039;Spring.GetSpectatingState&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; boolean spectating, boolean fullView, boolean fullSelect&lt;br /&gt;
&lt;br /&gt;
== ModUI ==&lt;br /&gt;
&#039;&#039;&#039;Spring.GetModUICtrl&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; boolean&lt;br /&gt;
&lt;br /&gt;
== MyInfo ==&lt;br /&gt;
&#039;&#039;&#039;Spring.GetMyAllyTeamID&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; number&lt;br /&gt;
&#039;&#039;&#039;Spring.GetMyTeamID&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; number&lt;br /&gt;
&#039;&#039;&#039;Spring.GetMyPlayerID&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; number&lt;br /&gt;
&lt;br /&gt;
== Local Player,Team,Ally ==&lt;br /&gt;
&amp;lt;span class=&amp;quot;note&amp;quot;&amp;gt;Redundant same as the GetMyXYZ functions!&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.GetLocalPlayerID&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; number playerID&lt;br /&gt;
&#039;&#039;&#039;Spring.GetLocalTeamID&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; number teamID&lt;br /&gt;
&#039;&#039;&#039;Spring.GetLocalAllyTeamID&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; number allyID&lt;br /&gt;
&lt;br /&gt;
== Team/Player Info ==&lt;br /&gt;
&#039;&#039;&#039;Spring.GetPlayerRoster&#039;&#039;&#039;&lt;br /&gt;
  ( [number sortType] | [number sortType], [bool showPathingPlayers] ) -&amp;gt;&lt;br /&gt;
    nil | playerTable = {&lt;br /&gt;
            [1] = {&lt;br /&gt;
              string  name,&lt;br /&gt;
              number  playerID,&lt;br /&gt;
              number  teamID,&lt;br /&gt;
              number  allyTeamID,&lt;br /&gt;
              boolean spectator,&lt;br /&gt;
              number  cpuUsage,&lt;br /&gt;
              number  pingTime&lt;br /&gt;
            },&lt;br /&gt;
            etc...&lt;br /&gt;
          }&lt;br /&gt;
   if pingTime is == -1, the player is pathfinding, in order to find the progress, use:&lt;br /&gt;
   cpuUsage&amp;amp;0x1 if it&#039;s PC or BO, cpuUsage&amp;amp; 0xFE to get path res, (cpuUsage&amp;gt;&amp;gt;8)*1000&lt;br /&gt;
   for the progress&lt;br /&gt;
  &amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;  Sort codes:&lt;br /&gt;
     1 = Sort by allies  (the default)&lt;br /&gt;
     2 = Sort by teamID&lt;br /&gt;
     3 = Sort by playerName&lt;br /&gt;
     4 = Sort by CPU usage&lt;br /&gt;
     5 = Sort by ping time&amp;lt;/font&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Spring.GetTeamColor&#039;&#039;&#039;&lt;br /&gt;
  ( number teamID ) -&amp;gt; nil | number r, number g, number b,  number a&lt;br /&gt;
&#039;&#039;&#039;Spring.GetTeamOrigColor&#039;&#039;&#039;&lt;br /&gt;
  ( number teamID ) -&amp;gt; nil | number r, number g, number b,  number a&lt;br /&gt;
&#039;&#039;&#039;Spring.GetPlayerTraffic&#039;&#039;&#039;&lt;br /&gt;
  ( number playerID [, number packetID] ) -&amp;gt; number&lt;br /&gt;
&lt;br /&gt;
== Sound ==&lt;br /&gt;
&#039;&#039;&#039;Spring.GetSoundStreamTime&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; number playedTime, number totalTime&lt;br /&gt;
&lt;br /&gt;
== Camera ==&lt;br /&gt;
&#039;&#039;&#039;Spring.GetCameraNames&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; { [camName] = number camNum, ... }&lt;br /&gt;
&#039;&#039;&#039;Spring.GetCameraState&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; { &amp;quot;name&amp;quot; = string, &amp;quot;mode&amp;quot; = number camIdx, state1 = number, state2 = number, ... }&lt;br /&gt;
&lt;br /&gt;
See [[Lua_camState]] for details about Spring.GetCameraState output.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.GetCameraPosition&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; number x, number y, number z&lt;br /&gt;
&#039;&#039;&#039;Spring.GetCameraDirection&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; number forward_x, number forward_y, number forward_z&lt;br /&gt;
&#039;&#039;&#039;Spring.GetCameraFOV&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; number fov&lt;br /&gt;
&#039;&#039;&#039;Spring.GetCameraVectors&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; vectorTable = {&lt;br /&gt;
    forward   = { [1] = number x, [2] = number y, [3] = number z },&lt;br /&gt;
    up        = { [1] = number x, [2] = number y, [3] = number z },&lt;br /&gt;
    right     = { [1] = number x, [2] = number y, [3] = number z },&lt;br /&gt;
    top       = { [1] = number x, [2] = number y, [3] = number z },&lt;br /&gt;
    bottom    = { [1] = number x, [2] = number y, [3] = number z },&lt;br /&gt;
    leftside  = { [1] = number x, [2] = number y, [3] = number z },&lt;br /&gt;
    rightside = { [1] = number x, [2] = number y, [3] = number z }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
=== Inview ===&lt;br /&gt;
&#039;&#039;&#039;Spring.GetVisibleUnits&#039;&#039;&#039;&lt;br /&gt;
  ( [number teamID = -1 [, number radius = 30 [, boolean Icons = true ]]] )&lt;br /&gt;
    -&amp;gt; nil | unitTable = { [1] = number unitID, ... }&lt;br /&gt;
&#039;&#039;&#039;Spring.GetVisibleFeatures&#039;&#039;&#039;&lt;br /&gt;
  ( [number allyTeamID = -1 [, number radius = 30 [, boolean Icons = true [, boolean geos = true ]]]] )&lt;br /&gt;
    -&amp;gt; nil | featureTable = { [1] = number featureID, ... }&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.IsAABBInView&#039;&#039;&#039;&lt;br /&gt;
  ( number minX, number minY, number minZ,&lt;br /&gt;
    number maxX, number maxY, number maxZ ) -&amp;gt; nil | boolean&lt;br /&gt;
&#039;&#039;&#039;Spring.IsSphereInView&#039;&#039;&#039;&lt;br /&gt;
  ( number x, number y, number z [, number radius ] ) -&amp;gt; nil | boolean&lt;br /&gt;
&#039;&#039;&#039;Spring.IsUnitIcon&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID ) -&amp;gt; nil | boolean&lt;br /&gt;
&#039;&#039;&#039;Spring.IsUnitInView&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID ) -&amp;gt; nil | boolean&lt;br /&gt;
&#039;&#039;&#039;Spring.IsUnitVisible&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID [, number radius [, boolean checkIcons] ] ) -&amp;gt; nil | boolean&lt;br /&gt;
&lt;br /&gt;
=== Screen Trace ===&lt;br /&gt;
&#039;&#039;&#039;Spring.WorldToScreenCoords&#039;&#039;&#039;&lt;br /&gt;
  ( number x, number y, number z ) -&amp;gt; number x, number y, number z&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.TraceScreenRay&#039;&#039;&#039;&lt;br /&gt;
  ( number mouseX, number mouseY [, boolean onlyCoords &lt;br /&gt;
  [, boolean useMinimap [, boolean includeSky [, boolean ignoreWater ] ] ] ] )&lt;br /&gt;
    -&amp;gt; nil |&lt;br /&gt;
    string &amp;quot;unit&amp;quot;,    number unitID    |&lt;br /&gt;
    string &amp;quot;feature&amp;quot;, number featureID |&lt;br /&gt;
    string &amp;quot;ground&amp;quot;,  { [1] = number x, [2] = number y, [3] = number z }&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.GetPixelDir&#039;&#039;&#039; {{New|95.0}}&lt;br /&gt;
  ( number x, number y ) -&amp;gt; number dirx, number diry, number dirz&lt;br /&gt;
&lt;br /&gt;
=== Screen &amp;amp; Window Geometry ===&lt;br /&gt;
&#039;&#039;&#039;Spring.GetViewGeometry&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; number viewSizeX, number viewSizeY, number viewPosX, number viewPosY&lt;br /&gt;
&#039;&#039;&#039;Spring.GetWindowGeometry&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; number winSizeX, number winSizeY, number winPosX, number winPosY&lt;br /&gt;
&#039;&#039;&#039;Spring.GetScreenGeometry&#039;&#039;&#039; (is missing multiscreen support!)&lt;br /&gt;
  ( ) -&amp;gt; number screenSizeX, number screenSizeY, number ZERO, number ZERO&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Unit ==&lt;br /&gt;
&#039;&#039;&#039;Spring.IsUnitAllied&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID ) -&amp;gt; nil | boolean&lt;br /&gt;
&#039;&#039;&#039;Spring.GetUnitViewPosition&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID [, boolean midPos = false ] ) -&amp;gt; nil | number x, number y, number z&lt;br /&gt;
&#039;&#039;&#039;Spring.GetUnitTransformMatrix&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID [, boolean invert = false] ) -&amp;gt; nil | number a11, number a12 ..., number a44    &amp;lt;span class=note&amp;gt;(4x4 matrix)&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Selected Units ===&lt;br /&gt;
&#039;&#039;&#039;Spring.GetSelectedUnits&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; { [1] = unitID, ... }&lt;br /&gt;
&#039;&#039;&#039;Spring.GetSelectedUnitsSorted&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; { [number unitDefID] = { [1] = [number unitID], etc...}, ... }&lt;br /&gt;
&#039;&#039;&#039;Spring.GetSelectedUnitsCounts&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; { [number unitDefID] = number count, etc... }&lt;br /&gt;
&#039;&#039;&#039;Spring.GetSelectedUnitsCount&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; number count&lt;br /&gt;
&#039;&#039;&#039;Spring.IsUnitSelected&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID ) -&amp;gt; nil | boolean&lt;br /&gt;
&lt;br /&gt;
=== Unit Groups ===&lt;br /&gt;
&#039;&#039;&#039;Spring.GetUnitGroup&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID ) -&amp;gt; nil | number&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.GetGroupList&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; nil | {&lt;br /&gt;
    [number] = number unitCount,&lt;br /&gt;
    ...&lt;br /&gt;
  }&lt;br /&gt;
&#039;&#039;&#039;Spring.GetSelectedGroup&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; number&lt;br /&gt;
&#039;&#039;&#039;Spring.GetGroupAIName&#039;&#039;&#039;&lt;br /&gt;
  ( number groupID ) -&amp;gt; string aiName&lt;br /&gt;
&#039;&#039;&#039;Spring.GetGroupAIList&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; {&lt;br /&gt;
    [1] = string aiName, ...&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.GetGroupUnits&#039;&#039;&#039;&lt;br /&gt;
  ( number groupID ) -&amp;gt; nil | {&lt;br /&gt;
    [1] = number unitID, ...&lt;br /&gt;
  }&lt;br /&gt;
&#039;&#039;&#039;Spring.GetGroupUnitsSorted&#039;&#039;&#039;&lt;br /&gt;
  ( number groupID ) -&amp;gt; nil | {&lt;br /&gt;
    [number unitDefID] = {number unitID, ...}, ...&lt;br /&gt;
  }&lt;br /&gt;
&#039;&#039;&#039;Spring.GetGroupUnitsCounts&#039;&#039;&#039;&lt;br /&gt;
  ( number groupID ) -&amp;gt; nil | {&lt;br /&gt;
    [number unitDefID] = number count, ...&lt;br /&gt;
  }&lt;br /&gt;
&#039;&#039;&#039;Spring.GetGroupUnitsCount&#039;&#039;&#039;&lt;br /&gt;
  ( number groupID ) -&amp;gt; nil | number count&lt;br /&gt;
== Projectiles ==&lt;br /&gt;
&#039;&#039;&#039;Spring.GetVisibleProjectiles&#039;&#039;&#039; {{New|95.0}}&lt;br /&gt;
   ([ number allyTeamID = -1&lt;br /&gt;
   [ , boolean addSyncedProjectiles = true&lt;br /&gt;
   [ , boolean addWeaponProjectiles = true&lt;br /&gt;
   [ , boolean addPieceProjectiles = true ]]]]&lt;br /&gt;
   ) --&amp;gt; nil | {[1] = projectileID, ...}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== UI ==&lt;br /&gt;
&lt;br /&gt;
=== GUI Settings ===&lt;br /&gt;
&#039;&#039;&#039;Spring.IsGUIHidden&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; nil | boolean&lt;br /&gt;
&#039;&#039;&#039;Spring.HaveShadows&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; nil | boolean&lt;br /&gt;
&#039;&#039;&#039;Spring.HaveAdvShading&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; nil | boolean&lt;br /&gt;
&#039;&#039;&#039;Spring.GetWaterMode&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; nil | number mode, string &amp;quot;mode&amp;quot;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;  mode numbers:&lt;br /&gt;
      0 - basic&lt;br /&gt;
      1 - reflective&lt;br /&gt;
      2 - dynamic&lt;br /&gt;
      3 - refractive&lt;br /&gt;
      4 - bumpwater&lt;br /&gt;
      default - unknown&amp;lt;/font&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Spring.GetMapDrawMode&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; nil | &amp;quot;normal&amp;quot; | &amp;quot;height&amp;quot; | &amp;quot;metal&amp;quot; | &amp;quot;pathTraversability&amp;quot; | &amp;quot;los&amp;quot;&lt;br /&gt;
&#039;&#039;&#039;Spring.GetDrawSelectionInfo&#039;&#039;&#039; &amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;Returns whether &amp;amp;quot;Selected units&amp;amp;quot; text is displayed.&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( ) -&amp;gt; boolean&lt;br /&gt;
&lt;br /&gt;
=== Unit GUI States ===&lt;br /&gt;
&#039;&#039;&#039;Spring.GetUnitLuaDraw&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID ) -&amp;gt; nil | boolean&lt;br /&gt;
&#039;&#039;&#039;Spring.GetUnitNoDraw&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID ) -&amp;gt; nil | boolean&lt;br /&gt;
&#039;&#039;&#039;Spring.GetUnitNoMinimap&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID ) -&amp;gt; nil | boolean&lt;br /&gt;
&#039;&#039;&#039;Spring.GetUnitNoSelect&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID ) -&amp;gt; nil | boolean&lt;br /&gt;
&lt;br /&gt;
=== Minimap ===&lt;br /&gt;
&#039;&#039;&#039;Spring.GetMiniMapGeometry&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; number posX, number posY, number sizeX, number sizeY,&lt;br /&gt;
    boolean minimized, boolean maximized&lt;br /&gt;
&#039;&#039;&#039;Spring.GetMiniMapDualScreen&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; boolean false | string &amp;quot;left&amp;quot; | string &amp;quot;right&amp;quot;&lt;br /&gt;
&#039;&#039;&#039;Spring.IsAboveMiniMap&#039;&#039;&#039;&lt;br /&gt;
  ( number x, number y ) -&amp;gt; nil | boolean&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== (Build-)Menu ===&lt;br /&gt;
&#039;&#039;&#039;Spring.GetActiveCommand&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; nil | number index (, number cmd_id, number cmd_type, string cmd_name)&lt;br /&gt;
&#039;&#039;&#039;Spring.GetDefaultCommand&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; nil | number index (, number cmd_id, number cmd_type, string cmd_name)&lt;br /&gt;
&#039;&#039;&#039;Spring.GetActiveCmdDescs&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; nil | {&lt;br /&gt;
    [1] = {&lt;br /&gt;
      id=number,&lt;br /&gt;
      type=number,&lt;br /&gt;
      name=string,&lt;br /&gt;
      action=string,&lt;br /&gt;
      tooltip=string,&lt;br /&gt;
      texture=string,&lt;br /&gt;
      cursor=string,&lt;br /&gt;
      hidden=boolean,&lt;br /&gt;
      disabled=boolean,&lt;br /&gt;
      showUnique=boolean,&lt;br /&gt;
      onlyTexture=boolean,&lt;br /&gt;
      params = { [1] = string, .. }&lt;br /&gt;
    }, ...&lt;br /&gt;
  }&lt;br /&gt;
&#039;&#039;&#039;Spring.GetActiveCmdDesc&#039;&#039;&#039;&lt;br /&gt;
  ( number index ) -&amp;gt; nil | {&lt;br /&gt;
      id=number,&lt;br /&gt;
      type=number,&lt;br /&gt;
      name=string,&lt;br /&gt;
      action=string,&lt;br /&gt;
      tooltip=string,&lt;br /&gt;
      texture=string,&lt;br /&gt;
      cursor=string,&lt;br /&gt;
      hidden=boolean,&lt;br /&gt;
      disabled=boolean,&lt;br /&gt;
      showUnique=boolean,&lt;br /&gt;
      onlyTexture=boolean,&lt;br /&gt;
      params = { [1] = string, .. }&lt;br /&gt;
  }&lt;br /&gt;
&#039;&#039;&#039;Spring.GetCmdDescIndex&#039;&#039;&#039;&lt;br /&gt;
  ( number cmdID ) -&amp;gt; nil | number index&lt;br /&gt;
&#039;&#039;&#039;Spring.GetActivePage&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; nil | number pageNum, number maxPages&lt;br /&gt;
&lt;br /&gt;
=== Build Facing ===&lt;br /&gt;
&#039;&#039;&#039;Spring.GetBuildFacing&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; nil | number&lt;br /&gt;
&#039;&#039;&#039;Spring.GetBuildSpacing&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; nil | number&lt;br /&gt;
&lt;br /&gt;
=== GatherMode &amp;amp; InvertQueueKey ===&lt;br /&gt;
&#039;&#039;&#039;Spring.GetGatherMode&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; nil | number&lt;br /&gt;
&#039;&#039;&#039;Spring.GetInvertQueueKey&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; nil | boolean&lt;br /&gt;
&lt;br /&gt;
=== Mouse States ===&lt;br /&gt;
&#039;&#039;&#039;Spring.GetMouseState&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; number X, number Y,&lt;br /&gt;
    boolean leftPressed, boolean middlePressed, boolean rightPressed&lt;br /&gt;
&#039;&#039;&#039;Spring.GetMouseCursor&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; string name, number scale&lt;br /&gt;
&#039;&#039;&#039;Spring.GetMouseStartPosition&#039;&#039;&#039;&lt;br /&gt;
  ( number mouseButton ) -&amp;gt; nil | number pressedX, number pressedY,&lt;br /&gt;
    number camPosX, number camPosY, number camPosZ,&lt;br /&gt;
    number dirX, number dirY, number dirZ&lt;br /&gt;
&lt;br /&gt;
=== (Hot-)Keys ===&lt;br /&gt;
&#039;&#039;&#039;Spring.GetKeyState&#039;&#039;&#039;&lt;br /&gt;
  ( number key ) -&amp;gt; nil | boolean&lt;br /&gt;
&#039;&#039;&#039;Spring.GetModKeyState&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; boolean alt, boolean ctrl, boolean meta, boolean shift&lt;br /&gt;
&#039;&#039;&#039;Spring.GetPressedKeys&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; {&lt;br /&gt;
    [number] = boolean,&lt;br /&gt;
    ...&lt;br /&gt;
  }&lt;br /&gt;
&#039;&#039;&#039;Spring.GetKeyCode&#039;&#039;&#039;&lt;br /&gt;
  ( string keysym ) -&amp;gt; number&lt;br /&gt;
&#039;&#039;&#039;Spring.GetKeySymbol&#039;&#039;&#039;&lt;br /&gt;
  ( number key ) -&amp;gt; string &amp;quot;keysym1&amp;quot;, string &amp;quot;keysym2&amp;quot;&lt;br /&gt;
&#039;&#039;&#039;Spring.GetKeyBindings&#039;&#039;&#039;&lt;br /&gt;
  ( string keyset ) -&amp;gt; nil | {&lt;br /&gt;
    [1] = {&lt;br /&gt;
      [string actionCmd] = string actionExtra,&lt;br /&gt;
      command   = string actionCmd,    {{new|97}}&lt;br /&gt;
      boundWith = string boundWith,    {{new|97}}&lt;br /&gt;
      extra     = string actionExtra,  {{new|97}}&lt;br /&gt;
    }, ...&lt;br /&gt;
  }&lt;br /&gt;
&#039;&#039;&#039;Spring.GetActionHotKeys&#039;&#039;&#039;&lt;br /&gt;
  ( string action ) -&amp;gt; nil | { [1] = string hotKey, ... }&lt;br /&gt;
&lt;br /&gt;
=== Console ===&lt;br /&gt;
&#039;&#039;&#039;Spring.GetLastMessagePositions&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; nil | {&lt;br /&gt;
    [1] = { number X, number Y, number Z },&lt;br /&gt;
    ...&lt;br /&gt;
  }&lt;br /&gt;
&#039;&#039;&#039;Spring.GetConsoleBuffer&#039;&#039;&#039;&lt;br /&gt;
  ( [number maxLines] ) -&amp;gt; nil | {&lt;br /&gt;
    [1] = {&lt;br /&gt;
      text = string,&lt;br /&gt;
      priority = number&lt;br /&gt;
   }, ...&lt;br /&gt;
  }&lt;br /&gt;
&#039;&#039;&#039;Spring.GetCurrentTooltip&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; string&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Config ==&lt;br /&gt;
&#039;&#039;&#039;Spring.GetConfigParams&#039;&#039;&#039; &amp;lt;span class=&amp;quot;note&amp;quot;&amp;gt;same information as &amp;lt;code&amp;gt;spring --list-config-vars&amp;lt;/code&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
  ( ) -&amp;gt; table {&lt;br /&gt;
    {&lt;br /&gt;
      name = string,&lt;br /&gt;
      type = string,&lt;br /&gt;
      [ description = string, ]&lt;br /&gt;
      [ defaultValue = string, ]&lt;br /&gt;
      [ minimumValue = string, ]&lt;br /&gt;
      [ maximumValue = string, ]&lt;br /&gt;
      [ safemodeValue = string, ]&lt;br /&gt;
      [ declarationFile = string, ]&lt;br /&gt;
      [ declarationLine = number, ]&lt;br /&gt;
      [ readOnly = bool, ]&lt;br /&gt;
    },&lt;br /&gt;
    ...&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
== FPS &amp;amp; GetDrawFrame ==&lt;br /&gt;
&#039;&#039;&#039;Spring.GetFPS&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; number&lt;br /&gt;
&#039;&#039;&#039;Spring.GetDrawFrame&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; number low 16bit, number high 16bit&lt;br /&gt;
&lt;br /&gt;
== Time ==&lt;br /&gt;
&#039;&#039;&#039;Spring.GetFrameTimeOffset&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; nil | number&lt;br /&gt;
&#039;&#039;&#039;Spring.GetLastUpdateSeconds&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; nil | number&lt;br /&gt;
&#039;&#039;&#039;Spring.GetHasLag&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; boolean&lt;br /&gt;
&#039;&#039;&#039;Spring.GetTimer&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; timer&lt;br /&gt;
&#039;&#039;&#039;Spring.DiffTimers&#039;&#039;&#039;&lt;br /&gt;
  ( timer cur, timer ago, [boolean inMilliseconds]) -&amp;gt; number seconds&lt;br /&gt;
{{New|95.0}} optional third argument (boolean) to return dt in milliseconds&lt;br /&gt;
&lt;br /&gt;
== Rendering ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.GetMapSquareTexture&#039;&#039;&#039;&lt;br /&gt;
  (number texSqrX, number texSqrY, number texMipLvl, string luaTexName) -&amp;gt; boolean success&lt;br /&gt;
&lt;br /&gt;
== Logging ==&lt;br /&gt;
&#039;&#039;&#039;Spring.GetLogSections&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; table { &amp;quot;KeyBindings&amp;quot; = LOG.INFO, &amp;quot;Font&amp;quot; = LOG.INFO, &amp;quot;Sound&amp;quot; = LOG.WARNING, ... }&lt;br /&gt;
&lt;br /&gt;
== Misc ==&lt;br /&gt;
&#039;&#039;&#039;Spring.GetClipboard&#039;&#039;&#039; {{new|98.0}}&lt;br /&gt;
  ( ) -&amp;gt; string text&lt;br /&gt;
&lt;br /&gt;
[[category: Lua]]&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=Lua_UnsyncedCtrl&amp;diff=12294</id>
		<title>Lua UnsyncedCtrl</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=Lua_UnsyncedCtrl&amp;diff=12294"/>
		<updated>2014-06-20T19:51:16Z</updated>

		<summary type="html">&lt;p&gt;Knorke: /* Misc */  Set...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Engine_Development|Development]] &amp;lt; [[Lua_Scripting|Lua Scripting]] &amp;lt; {{FULLPAGENAME}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
NOTE: Entries below marked &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt; require the setting ModUICtrl to be enabled in the users [[springrc]], if you want to use them in unsynced LuaRules/LuaGaia. It is enabled by default so you generally don&#039;t need to care.&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= UI =&lt;br /&gt;
&#039;&#039;&#039;Spring.SetLastMessagePosition&#039;&#039;&#039;&lt;br /&gt;
  ( number x, number y, number z ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
= Ingame Console =&lt;br /&gt;
&#039;&#039;&#039;Spring.Echo&#039;&#039;&#039;&lt;br /&gt;
  ( arg1 [, arg2 [, ... ] ] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;Useful for debugging.&amp;lt;br&amp;gt; Prints values in the spring chat console.&amp;lt;br&amp;gt; Hint: the default print() writes to STDOUT.&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.Log&#039;&#039;&#039;&lt;br /&gt;
  ( string section, int logLevel | string logLevel,&lt;br /&gt;
    arg2 [, arg3 [, ... ] ] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;Possible values for logLevel are:&lt;br /&gt;
    &amp;quot;debug&amp;quot;   | LOG.DEBUG&lt;br /&gt;
    &amp;quot;info&amp;quot;    | LOG.INFO&lt;br /&gt;
    &amp;quot;notice&amp;quot;  | LOG.NOTICE (engine default) {{new|97}}&lt;br /&gt;
    &amp;quot;warning&amp;quot; | LOG.WARNING&lt;br /&gt;
    &amp;quot;error&amp;quot;   | LOG.ERROR&lt;br /&gt;
    &amp;quot;fatal&amp;quot;   | LOG.FATAL&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SendCommands&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( string command1 [, string command2 [ ... ] ] ) -&amp;gt; nil&lt;br /&gt;
  ( {string command1, string command2, ...} ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
== GUI ==&lt;br /&gt;
&#039;&#039;&#039;Spring.SetActiveCommand&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( string action [, string actionExtra ] ) -&amp;gt; nil | boolean&lt;br /&gt;
  ( number cmdIndex [, number button = 1&lt;br /&gt;
    [, boolean leftClick, boolean rightClick,&lt;br /&gt;
     boolean alt, boolean ctrl, boolean meta, boolean shift]] ) -&amp;gt; nil | boolean&lt;br /&gt;
&#039;&#039;&#039;Spring.LoadCmdColorsConfig&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( string config ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.LoadCtrlPanelConfig&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( string config ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.ForceLayoutUpdate&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.SetDrawSelectionInfo&#039;&#039;&#039; &amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;disables the &amp;quot;Selected Units x&amp;quot; box in the GUI&amp;lt;/font&amp;gt; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( boolean enable ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
== Mouse ==&lt;br /&gt;
&#039;&#039;&#039;Spring.SetMouseCursor&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( string cursorName [, number scale ] ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.WarpMouse&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( number x, number y ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
== LOS Colors ==&lt;br /&gt;
&#039;&#039;&#039;Spring.SetLosViewColors&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( table reds = { number always, number LOS, number radar, number jam }, &lt;br /&gt;
    table greens = { number always, number LOS, number radar, number jam },&lt;br /&gt;
    table blues = { number always, number LOS, number radar, number jam } ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
== SendMessage ==&lt;br /&gt;
&#039;&#039;&#039;Spring.SendMessage&#039;&#039;&#039;&lt;br /&gt;
  ( string &amp;quot;message&amp;quot; ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.SendMessageToPlayer&#039;&#039;&#039;&lt;br /&gt;
  ( number playerID, string &amp;quot;message&amp;quot; ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.SendMessageToTeam&#039;&#039;&#039;&lt;br /&gt;
  ( number teamID, string &amp;quot;message&amp;quot; ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.SendMessageToAllyTeam&#039;&#039;&#039;&lt;br /&gt;
  ( number allyID, string &amp;quot;message&amp;quot; ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.SendMessageToSpectators&#039;&#039;&#039;&lt;br /&gt;
  ( string &amp;quot;message&amp;quot; ) -&amp;gt; nil&lt;br /&gt;
Funfact:&lt;br /&gt;
&amp;lt;PLAYER#&amp;gt; (with # being a playerid) inside the string will be replaced with the players name.&lt;br /&gt;
ie&lt;br /&gt;
Spring.SendMessage (&amp;quot;&amp;lt;PLAYER1&amp;gt; did something&amp;quot;)&lt;br /&gt;
might display as &amp;quot;ProRusher did something&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Markers ==&lt;br /&gt;
&#039;&#039;&#039;Spring.MarkerAddPoint&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( number x, number y, number z [, string text = &amp;quot;&amp;quot; [, bool localOnly] ] ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.MarkerAddLine&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( number x1, number y1, number z1, number x2, number y2, number z2 ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.MarkerErasePosition&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( number x, number y, number z ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
= Sounds =&lt;br /&gt;
&#039;&#039;&#039;Spring.LoadSoundDef&#039;&#039;&#039;&lt;br /&gt;
  ( string &amp;quot;soundfile&amp;quot; ) -&amp;gt; nil | boolean success&lt;br /&gt;
  &amp;lt;span class=note&amp;gt;Loads a SoundDefs file, the format is the same as in `gamedata/sounds.lua`.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.PlaySoundFile&#039;&#039;&#039;  &amp;lt;span class=note&amp;gt;Plays WAV or OGG sounds.&amp;lt;/span&amp;gt;&lt;br /&gt;
  ( string &amp;quot;soundfile&amp;quot; [, number volume = 1.0&lt;br /&gt;
    [, number posx, number posy, number posz &lt;br /&gt;
    [, number speedx, number speedy, number speedz ] ] ], [string/number &amp;lt;span class=note&amp;gt;channel&amp;lt;/span&amp;gt; ] ) -&amp;gt; nil | boolean&lt;br /&gt;
  &amp;lt;span class=note&amp;gt;`channel` is new in Spring0.83, and can be one of those:&lt;br /&gt;
    &amp;quot;general&amp;quot; || 0 || nil (default)&lt;br /&gt;
    &amp;quot;battle&amp;quot; || &amp;quot;sfx&amp;quot; | 1&lt;br /&gt;
    &amp;quot;unitreply&amp;quot; || &amp;quot;voice&amp;quot; || 2&lt;br /&gt;
    &amp;quot;userinterface&amp;quot; || &amp;quot;ui&amp;quot; || 3&lt;br /&gt;
  &amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.PlaySoundStream&#039;&#039;&#039;&lt;br /&gt;
  ( string &amp;quot;oggfile&amp;quot; [, number volume = 1.0&lt;br /&gt;
    [, number x, number y, number z ]] ) -&amp;gt; nil | boolean true&lt;br /&gt;
  &amp;lt;span class=note&amp;gt;Allow you to play an Ogg Vorbis (.OGG) compressed sound file.&amp;lt;br&amp;gt; In 83.0 and up multiple sound streams may be played at once &amp;lt;/span&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Spring.StopSoundStream&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; nil&lt;br /&gt;
  &amp;lt;span class=note&amp;gt;Terminates any SoundStream currently running.&amp;lt;/span&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Spring.PauseSoundStream&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.SetSoundStreamVolume&#039;&#039;&#039;&lt;br /&gt;
  ( number volume ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
= SendLuaMessage =&lt;br /&gt;
&amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;Very important! (allows synced inter-lua-enviroment communications)&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SendLuaUIMsg&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( string message, string mode ) -&amp;gt; nil&lt;br /&gt;
  &amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;possible modes are:&amp;lt;br&amp;gt;&amp;quot;s&amp;quot;/&amp;quot;specs&amp;quot; &amp;amp; &amp;quot;a&amp;quot;/&amp;quot;allies&amp;quot;&amp;lt;/font&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Spring.SendLuaGaiaMsg&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( string message ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.SendLuaRulesMsg&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( string message ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
= AI =&lt;br /&gt;
&#039;&#039;&#039;Spring.SendSkirmishAIMessage&#039;&#039;&#039; {{new|83.0}}&lt;br /&gt;
  ( number aiTeam, string message )&lt;br /&gt;
  -&amp;gt; nil | boolean ai_processed, { [1] = string response1, etc... }&lt;br /&gt;
&amp;lt;span class=&amp;quot;note&amp;quot;&amp;gt;Note there is nothing in this table due to &amp;quot;limitations&amp;quot; of the AI interface.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Units =&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitLeaveTracks&#039;&#039;&#039; {{new|83.0}}&lt;br /&gt;
  ( number unitID, boolean leavetracks ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
== Unit Selection ==&lt;br /&gt;
&#039;&#039;&#039;Spring.SelectUnitMap&#039;&#039;&#039;&lt;br /&gt;
  ( { [unitID] = anything, ...} [,boolean append] ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.SelectUnitArray&#039;&#039;&#039;&lt;br /&gt;
  ( { [1] = unitID1 , [2] = unitID2 , ...} [,boolean append] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetDrawSelectionInfo&#039;&#039;&#039;&lt;br /&gt;
  ( boolean drawSelectionInfo ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
== Unit Group ==&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitGroup&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( number unitID, number groupID ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
== Give Order ==&lt;br /&gt;
&#039;&#039;&#039;Spring.GiveOrder&#039;&#039;&#039; &amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;gives order to all selected units&amp;lt;/font&amp;gt; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( number cmdID,&lt;br /&gt;
    params = {number, etc...},&lt;br /&gt;
    options = {&amp;quot;alt&amp;quot;, &amp;quot;ctrl&amp;quot;, &amp;quot;shift&amp;quot;, &amp;quot;right&amp;quot;} ) -&amp;gt; nil | boolean true&lt;br /&gt;
&#039;&#039;&#039;Spring.GiveOrderToUnit&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( number unitID,&lt;br /&gt;
    number cmdID,&lt;br /&gt;
    params = {number, etc...},&lt;br /&gt;
    options = {&amp;quot;alt&amp;quot;, &amp;quot;ctrl&amp;quot;, &amp;quot;shift&amp;quot;, &amp;quot;right&amp;quot;} ) -&amp;gt; nil | boolean true&lt;br /&gt;
&#039;&#039;&#039;Spring.GiveOrderToUnitMap&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( unitMap = { [unitID] = dontCare, etc... },&lt;br /&gt;
    number cmdID,&lt;br /&gt;
    params = {number, etc...},&lt;br /&gt;
    options = {&amp;quot;alt&amp;quot;, &amp;quot;ctrl&amp;quot;, &amp;quot;shift&amp;quot;, &amp;quot;right&amp;quot;} ) -&amp;gt; nil | boolean true&lt;br /&gt;
&#039;&#039;&#039;Spring.GiveOrderToUnitArray&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( unitArray = { [1] = unitID, etc... },&lt;br /&gt;
    number cmdID,&lt;br /&gt;
    params = {number, etc...},&lt;br /&gt;
    options = {&amp;quot;alt&amp;quot;, &amp;quot;ctrl&amp;quot;, &amp;quot;shift&amp;quot;, &amp;quot;right&amp;quot;} ) -&amp;gt; nil | boolean true&lt;br /&gt;
&#039;&#039;&#039;Spring.GiveOrderArrayToUnitMap&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( unitMap = { [number unitID] = dontCare, etc... },&lt;br /&gt;
    orderArray = {&lt;br /&gt;
      { number cmdID,&lt;br /&gt;
        params = {number, etc...},&lt;br /&gt;
        options = {&amp;quot;alt&amp;quot;, &amp;quot;ctrl&amp;quot;, &amp;quot;shift&amp;quot;, &amp;quot;right&amp;quot;}&lt;br /&gt;
      }, ..&lt;br /&gt;
    }&lt;br /&gt;
  ) -&amp;gt; nil | boolean true&lt;br /&gt;
&#039;&#039;&#039;Spring.GiveOrderArrayToUnitArray&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( unitArray = { [1] = number unitID, etc... },&lt;br /&gt;
    orderArray = {&lt;br /&gt;
      { number cmdID,&lt;br /&gt;
        params = {number, etc...},&lt;br /&gt;
        options = {&amp;quot;alt&amp;quot;, &amp;quot;ctrl&amp;quot;, &amp;quot;shift&amp;quot;, &amp;quot;right&amp;quot;}&lt;br /&gt;
      }, ..&lt;br /&gt;
    },&lt;br /&gt;
    [boolean pairwise]&lt;br /&gt;
  ) -&amp;gt; nil | boolean true&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;note&amp;quot;&amp;gt;pairwise param ({{new|89.0}}) is used to send multiple units a single individual command&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetBuildFacing&#039;&#039;&#039;&lt;br /&gt;
  ( int Facing ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetBuildSpacing&#039;&#039;&#039;&lt;br /&gt;
  ( int Spacing ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
== Unit NoDraw,NoSelect,NoMinimap ==&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitNoDraw&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;LuaGadgets only!&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( number unitID, boolean noDraw ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitNoSelect&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;LuaGadgets only!&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( number unitID, boolean noSelect ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitNoMinimap&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;LuaGadgets only!&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( number unitID, boolean noMinimap ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
= Developers =&lt;br /&gt;
&#039;&#039;&#039;Spring.SetDrawSky&#039;&#039;&#039;&lt;br /&gt;
  ( boolean drawSky ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.SetDrawWater&#039;&#039;&#039;&lt;br /&gt;
  ( boolean drawWater ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.SetDrawGround&#039;&#039;&#039;&lt;br /&gt;
  ( boolean drawGround ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetWaterParams&#039;&#039;&#039; &amp;lt;span class=warning&amp;gt;needs cheating enabled!&amp;lt;/span&amp;gt;&lt;br /&gt;
  ( table params ) -&amp;gt; nil&lt;br /&gt;
&amp;lt;span class=note&amp;gt;Allows to change water params (mostly BumpWater ones) at runtime. You may want to set BumpWaterUseUniforms in your [[springrc]] to 1, then you don&#039;t even need to restart BumpWater via `/water 4`.&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
  &amp;lt;span class=note&amp;gt;`params` table may contain:&lt;br /&gt;
  params = {&lt;br /&gt;
    absorb = {number r, number g, number b},&lt;br /&gt;
    baseColor = {number r, number g, number b},&lt;br /&gt;
    minColor = {number r, number g, number b},&lt;br /&gt;
    surfaceColor = {number r, number g, number b},&lt;br /&gt;
    diffuseColor = {number r, number g, number b},&lt;br /&gt;
    specularColor = {number r, number g, number b},&lt;br /&gt;
    planeColor = {number r, number g, number b},&lt;br /&gt;
    texture = string file,&lt;br /&gt;
    foamTexture = string file,&lt;br /&gt;
    normalTexture = string file,&lt;br /&gt;
    damage = number value,&lt;br /&gt;
    repeatX = number value,&lt;br /&gt;
    repeatY = number value,&lt;br /&gt;
    surfaceAlpha = number value,&lt;br /&gt;
    ambientFactor = number value,&lt;br /&gt;
    diffuseFactor = number value,&lt;br /&gt;
    specularFactor = number value,&lt;br /&gt;
    specularPower = number value,&lt;br /&gt;
    fresnelMin = number value,&lt;br /&gt;
    fresnelMax = number value,&lt;br /&gt;
    fresnelPower = number value,&lt;br /&gt;
    reflectionDistortion = number value,&lt;br /&gt;
    blurBase = number value,&lt;br /&gt;
    blurExponent = number value,&lt;br /&gt;
    perlinStartFreq = number value,&lt;br /&gt;
    perlinLacunarity = number value,&lt;br /&gt;
    perlinAmplitude = number value,&lt;br /&gt;
    numTiles = number value,&lt;br /&gt;
    shoreWaves = boolean value,&lt;br /&gt;
    forceRendering = boolean value,&lt;br /&gt;
    hasWaterPlane = boolean value,&lt;br /&gt;
  }&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetLogSectionFilterLevel&#039;&#039;&#039; {{New|95.0}}&lt;br /&gt;
   (string sectionName, string|number logLevel)&lt;br /&gt;
see [[infolog.txt]] for possible log setctions (?)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetDrawGroundDeferred&#039;&#039;&#039; {{New|95.0}}&lt;br /&gt;
    (boolean) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.SetDrawModelsDeferred&#039;&#039;&#039; {{New|95.0}}&lt;br /&gt;
    (boolean) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
= GUI =&lt;br /&gt;
&#039;&#039;&#039;Spring.DrawUnitCommands&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID ) -&amp;gt; nil&lt;br /&gt;
  ( { [1] = unitID, ... } [, false ] ) -&amp;gt; nil&lt;br /&gt;
  ( { [unitID] = anything, ... }, true  ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetTeamColor&#039;&#039;&#039;&lt;br /&gt;
  ( number teamID, number r, number g, number b ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.AssignMouseCursor&#039;&#039;&#039; &amp;lt;font class=note&amp;gt;changes/creates the cursor of a single CursorCmd&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( string &amp;quot;cmdName&amp;quot;, string &amp;quot;iconFileName&amp;quot;&lt;br /&gt;
    [, boolean overwrite = true [, boolean hotSpotTopLeft = false] ] ) -&amp;gt; nil | boolean&lt;br /&gt;
&amp;lt;font class=note&amp;gt;Note, that iconFileName is not the full filename instead it is like this:&amp;lt;br/&amp;gt;&lt;br /&gt;
wanted filename: Anims/cursorattack_0.bmp&amp;lt;br/&amp;gt;&lt;br /&gt;
=&amp;gt; iconFileName: cursorattack&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.ReplaceMouseCursor&#039;&#039;&#039; &amp;lt;font class=note&amp;gt;mass replace all occurrence of the cursor in all CursorCmds&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( string &amp;quot;oldFileName&amp;quot;, string &amp;quot;newFileName&amp;quot; [, boolean hotSpotTopLeft = false] ) -&amp;gt; nil | boolean&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetCustomCommandDrawData&#039;&#039;&#039; &amp;lt;font class=note&amp;gt;register your custom cmd so it gets visible in the unit&#039;s cmd queue&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( number cmdID,&lt;br /&gt;
    number cmdID_cloneIcon | string iconname,&lt;br /&gt;
    { number r, number g, number b, number a } [, boolean showArea ] ) -&amp;gt; nil&lt;br /&gt;
  ( number cmdID, nil) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
= Sharing =&lt;br /&gt;
&#039;&#039;&#039;Spring.SetShareLevel&#039;&#039;&#039; &amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;note: shareLevel is 0&amp;lt;= x &amp;lt;= 1&amp;lt;/font&amp;gt; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( string &amp;quot;metal&amp;quot; | &amp;quot;energy&amp;quot;, number shareLevel ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.ShareResources&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( number teamID, string &amp;quot;units&amp;quot; ) -&amp;gt; nil&lt;br /&gt;
  ( number teamID, string &amp;quot;metal&amp;quot; | &amp;quot;energy&amp;quot;, number amount ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
= UnitDef RadarIcons &amp;amp; BuildPics =&lt;br /&gt;
&#039;&#039;&#039;Spring.AddUnitIcon&#039;&#039;&#039;&lt;br /&gt;
  ( string iconName, string texFile [, number size [, number dist [, boolean radAdjust ]]] )&lt;br /&gt;
  -&amp;gt; nil | boolean&lt;br /&gt;
&#039;&#039;&#039;Spring.FreeUnitIcon&#039;&#039;&#039;&lt;br /&gt;
  ( string iconName ) -&amp;gt; nil | boolean&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitDefIcon&#039;&#039;&#039;  &amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;(RadarIcon)&amp;lt;/font&amp;gt; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( number unitDefID, string iconName ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitDefImage&#039;&#039;&#039;   &amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;(BuildPic)&amp;lt;/font&amp;gt; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( number unitDefID, luaTexture | string texFile ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
= Camera =&lt;br /&gt;
&#039;&#039;&#039;Spring.SetCameraState&#039;&#039;&#039;&lt;br /&gt;
  ( table camState, number camTime) -&amp;gt; nil | boolean&lt;br /&gt;
&amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;camState has the same format as the output of Spring.GetCameraState(). See [[Lua_camState]] for details about camState.&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetCameraTarget&#039;&#039;&#039;&lt;br /&gt;
  ( number x, number y, number z [,number transTime] ) -&amp;gt; nil&lt;br /&gt;
&amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;For Spring Engine XZ represents horizontal, from north west corner of map and Y vertical, from water level and rising.&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetCameraOffset&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( [number px = 0 [, number py = 0 [, number pz = 0&lt;br /&gt;
     [, number tx = 0 [, number ty = 0 [, number tz = 0]]]]]] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
= (Virtual-)FileSystem =&lt;br /&gt;
&#039;&#039;&#039;Spring.ExtractModArchiveFile&#039;&#039;&#039;&lt;br /&gt;
  ( string modfile ) -&amp;gt; boolean&lt;br /&gt;
&#039;&#039;&#039;Spring.CreateDir&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( number path ) -&amp;gt; nil | boolean&lt;br /&gt;
&lt;br /&gt;
= Engine Config =&lt;br /&gt;
&amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;The following functions read the engine configs saved in [[springrc]], a version-ed instance of these or a custom file supplied on the command line.&lt;br /&gt;
If &#039;&#039;*Overlay&#039;&#039; is &#039;&#039;true&#039;&#039;, the value will only be set in memory, and not be restored for the next game&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.GetConfigInt&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( string name [, number default [, boolean setInOverlay = false]] ) -&amp;gt; nil | number&lt;br /&gt;
&#039;&#039;&#039;Spring.SetConfigInt&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( string name, number value [, boolean useOverlay = false] ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.GetConfigString&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( string name [, string default [, boolean setInOverlay = false]] ) -&amp;gt; nil | string&lt;br /&gt;
&#039;&#039;&#039;Spring.SetConfigString&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( string name, string value [, boolean useOverlay = false] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
= World Primitives =&lt;br /&gt;
&amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;outdated! use opengl api instead!&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.AddWorldIcon&#039;&#039;&#039;&lt;br /&gt;
  ( number cmdID, number x, number y, number z ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.AddWorldText&#039;&#039;&#039;&lt;br /&gt;
  ( string &amp;quot;text&amp;quot;, number x, number y, number z ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.AddWorldUnit&#039;&#039;&#039;&lt;br /&gt;
  ( number unitDefID,&lt;br /&gt;
    number x, number y, number z,&lt;br /&gt;
    number team, number facing) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
= Sun  =&lt;br /&gt;
&#039;&#039;&#039;Spring.SetSunManualControl&#039;&#039;&#039;&lt;br /&gt;
  ( boolean setManualControl ) - &amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetSunParameters&#039;&#039;&#039;&lt;br /&gt;
  ( number dirX, number dirY, number dirZ, number dist, number startTime, number orbitTime ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetSunDirection&#039;&#039;&#039;&lt;br /&gt;
  ( number dirX, number dirY, number dirZ ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
= Misc =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.Restart&#039;&#039;&#039; {{new|0.79}}&lt;br /&gt;
  ( string commandline_args, string startscript )&lt;br /&gt;
    -&amp;gt; if this call returns, something went wrong&lt;br /&gt;
&amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;&#039;&#039;commandline_args&#039;&#039; are commandline arguments passed to spring executable&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;start-script is the CONTENT of the script.txt spring should use to start (if empty, no start-script is added, you can still point spring to your custom script.txt when you add the file-path to &#039;&#039;commandline_args&#039;&#039;&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetWMIcon&#039;&#039;&#039; {{new|83.0}}&lt;br /&gt;
  ( string iconFileName ) -&amp;gt; nil&lt;br /&gt;
&amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;Sets the icon for the process which is seen in the OS task-bar and other places (default: spring-logo).&amp;lt;br/&amp;gt;&lt;br /&gt;
Note: has to be 24bit or 32bit&amp;lt;br/&amp;gt;&lt;br /&gt;
Note: on windows, it has to be 32x32 pixels in size (recommended for cross-platform)&amp;lt;br/&amp;gt;&lt;br /&gt;
Note: &#039;&#039;*.bmp&#039;&#039; images have to be in BGR format (default for m$ ones).&amp;lt;br/&amp;gt;&lt;br /&gt;
Note: &#039;&#039;*.ico&#039;&#039; images are not supported.&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetWMCaption&#039;&#039;&#039; {{new|83.0}}&lt;br /&gt;
  ( string title [, string titleShort = title ] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;Sets the window &#039;&#039;title&#039;&#039; for the process (default: &amp;quot;Spring &amp;lt;version&amp;gt;&amp;quot;).&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;The &#039;&#039;shortTitle&#039;&#039; is displayed in the OS task-bar (default: &amp;quot;Spring &amp;lt;version&amp;gt;&amp;quot;).&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;&#039;&#039;&#039;NOTE:&#039;&#039;&#039; &#039;&#039;shortTitle&#039;&#039; is only ever possibly used under X11 (Linux &amp;amp; OS X), but not with QT (KDE) and never under Windows. See [http://www.gpwiki.org/index.php/SDL:Tutorials:Initializing_SDL_Libraries#About_the_icon_.28.22Icon_Title.22.29_parameter_on_different_window-managers this site] for more details.&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.ClearWatchdogTimer&#039;&#039;&#039; {{new|83.0}}&lt;br /&gt;
  ( [ string threadName = main ] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetClipboard&#039;&#039;&#039; {{new|98.0}}&lt;br /&gt;
  ( string text) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
= Rendering =&lt;br /&gt;
&amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;NOTE: these (0.83+) lighting callouts only work when called from unsynced gadgets!&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.AddMapLight&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(requires MaxDynamicMapLights &amp;amp;gt; 0)&amp;lt;/font&amp;gt;&lt;br /&gt;
  (table lightParams) -&amp;gt; number lightHandle&lt;br /&gt;
&#039;&#039;&#039;Spring.AddModelLight&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(requires MaxDynamicModelLights &amp;amp;gt; 0)&amp;lt;/font&amp;gt;&lt;br /&gt;
  (table lightParams) -&amp;gt; number lightHandle&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UpdateMapLight&#039;&#039;&#039;&lt;br /&gt;
  (number lightHandle, table lightParams) -&amp;gt; boolean success&lt;br /&gt;
&#039;&#039;&#039;Spring.UpdateModelLight&#039;&#039;&#039;&lt;br /&gt;
  (number lightHandle, table lightParams) -&amp;gt; boolean success&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetMapLightTrackingState&#039;&#039;&#039;&lt;br /&gt;
  (number lightHandle, number unitOrProjectileID,&lt;br /&gt;
   boolean enableTracking, boolean unitOrProjectile) -&amp;gt; boolean success&lt;br /&gt;
&#039;&#039;&#039;Spring.SetModelLightTrackingState&#039;&#039;&#039;&lt;br /&gt;
  (number lightHandle, number unitOrProjectileID,&lt;br /&gt;
   boolean enableTracking, boolean unitOrProjectile) -&amp;gt; boolean success&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;lightParams&#039;&#039;&#039; is a table that should contain at least one of the following recognized key/value pairs:&lt;br /&gt;
&lt;br /&gt;
    lightParams = {&lt;br /&gt;
        position = {px, py, pz},&lt;br /&gt;
        direction = {dx, dy, dz},&lt;br /&gt;
        ambientColor = {red, green, blue},&lt;br /&gt;
        diffuseColor = {red, green, blue},&lt;br /&gt;
        specularColor = {red, green, blue},&lt;br /&gt;
        intensityWeight = {ambientWeight, diffuseWeight, specularWeight},&lt;br /&gt;
&lt;br /&gt;
        -- per-frame decay of ambientColor (spread over TTL frames)&lt;br /&gt;
        ambientDecayRate = {ambientRedDecay, ambientGreenDecay, ambientBlueDecay},&lt;br /&gt;
        -- per-frame decay of diffuseColor (spread over TTL frames)&lt;br /&gt;
        diffuseDecayRate = {diffuseRedDecay, diffuseGreenDecay, diffuseBlueDecay},&lt;br /&gt;
        -- per-frame decay of specularColor (spread over TTL frames)&lt;br /&gt;
        specularDecayRate = {specularRedDecay, specularGreenDecay, specularBlueDecay},&lt;br /&gt;
        -- *DecayType = 0.0 -&amp;gt; interpret *DecayRate values as linear, else as exponential&lt;br /&gt;
        decayFunctionType = {ambientDecayType, diffuseDecayType, specularDecayType},&lt;br /&gt;
&lt;br /&gt;
        radius = number elmos,&lt;br /&gt;
        fov = number degrees,&lt;br /&gt;
        ttl = number frames,&lt;br /&gt;
        priority = number,&lt;br /&gt;
        ignoreLOS = boolean,&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetMapSquareTexture&#039;&#039;&#039;&lt;br /&gt;
  (number texSqrX, number texSqrY, string luaTexName) -&amp;gt; boolean success&lt;br /&gt;
&lt;br /&gt;
[[category: Lua]]&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=Lua_UnsyncedCtrl&amp;diff=12293</id>
		<title>Lua UnsyncedCtrl</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=Lua_UnsyncedCtrl&amp;diff=12293"/>
		<updated>2014-06-20T19:47:20Z</updated>

		<summary type="html">&lt;p&gt;Knorke: /* Misc */ GetClipboard&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Engine_Development|Development]] &amp;lt; [[Lua_Scripting|Lua Scripting]] &amp;lt; {{FULLPAGENAME}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
NOTE: Entries below marked &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt; require the setting ModUICtrl to be enabled in the users [[springrc]], if you want to use them in unsynced LuaRules/LuaGaia. It is enabled by default so you generally don&#039;t need to care.&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= UI =&lt;br /&gt;
&#039;&#039;&#039;Spring.SetLastMessagePosition&#039;&#039;&#039;&lt;br /&gt;
  ( number x, number y, number z ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
= Ingame Console =&lt;br /&gt;
&#039;&#039;&#039;Spring.Echo&#039;&#039;&#039;&lt;br /&gt;
  ( arg1 [, arg2 [, ... ] ] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;Useful for debugging.&amp;lt;br&amp;gt; Prints values in the spring chat console.&amp;lt;br&amp;gt; Hint: the default print() writes to STDOUT.&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.Log&#039;&#039;&#039;&lt;br /&gt;
  ( string section, int logLevel | string logLevel,&lt;br /&gt;
    arg2 [, arg3 [, ... ] ] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;Possible values for logLevel are:&lt;br /&gt;
    &amp;quot;debug&amp;quot;   | LOG.DEBUG&lt;br /&gt;
    &amp;quot;info&amp;quot;    | LOG.INFO&lt;br /&gt;
    &amp;quot;notice&amp;quot;  | LOG.NOTICE (engine default) {{new|97}}&lt;br /&gt;
    &amp;quot;warning&amp;quot; | LOG.WARNING&lt;br /&gt;
    &amp;quot;error&amp;quot;   | LOG.ERROR&lt;br /&gt;
    &amp;quot;fatal&amp;quot;   | LOG.FATAL&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SendCommands&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( string command1 [, string command2 [ ... ] ] ) -&amp;gt; nil&lt;br /&gt;
  ( {string command1, string command2, ...} ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
== GUI ==&lt;br /&gt;
&#039;&#039;&#039;Spring.SetActiveCommand&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( string action [, string actionExtra ] ) -&amp;gt; nil | boolean&lt;br /&gt;
  ( number cmdIndex [, number button = 1&lt;br /&gt;
    [, boolean leftClick, boolean rightClick,&lt;br /&gt;
     boolean alt, boolean ctrl, boolean meta, boolean shift]] ) -&amp;gt; nil | boolean&lt;br /&gt;
&#039;&#039;&#039;Spring.LoadCmdColorsConfig&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( string config ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.LoadCtrlPanelConfig&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( string config ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.ForceLayoutUpdate&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.SetDrawSelectionInfo&#039;&#039;&#039; &amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;disables the &amp;quot;Selected Units x&amp;quot; box in the GUI&amp;lt;/font&amp;gt; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( boolean enable ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
== Mouse ==&lt;br /&gt;
&#039;&#039;&#039;Spring.SetMouseCursor&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( string cursorName [, number scale ] ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.WarpMouse&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( number x, number y ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
== LOS Colors ==&lt;br /&gt;
&#039;&#039;&#039;Spring.SetLosViewColors&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( table reds = { number always, number LOS, number radar, number jam }, &lt;br /&gt;
    table greens = { number always, number LOS, number radar, number jam },&lt;br /&gt;
    table blues = { number always, number LOS, number radar, number jam } ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
== SendMessage ==&lt;br /&gt;
&#039;&#039;&#039;Spring.SendMessage&#039;&#039;&#039;&lt;br /&gt;
  ( string &amp;quot;message&amp;quot; ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.SendMessageToPlayer&#039;&#039;&#039;&lt;br /&gt;
  ( number playerID, string &amp;quot;message&amp;quot; ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.SendMessageToTeam&#039;&#039;&#039;&lt;br /&gt;
  ( number teamID, string &amp;quot;message&amp;quot; ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.SendMessageToAllyTeam&#039;&#039;&#039;&lt;br /&gt;
  ( number allyID, string &amp;quot;message&amp;quot; ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.SendMessageToSpectators&#039;&#039;&#039;&lt;br /&gt;
  ( string &amp;quot;message&amp;quot; ) -&amp;gt; nil&lt;br /&gt;
Funfact:&lt;br /&gt;
&amp;lt;PLAYER#&amp;gt; (with # being a playerid) inside the string will be replaced with the players name.&lt;br /&gt;
ie&lt;br /&gt;
Spring.SendMessage (&amp;quot;&amp;lt;PLAYER1&amp;gt; did something&amp;quot;)&lt;br /&gt;
might display as &amp;quot;ProRusher did something&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Markers ==&lt;br /&gt;
&#039;&#039;&#039;Spring.MarkerAddPoint&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( number x, number y, number z [, string text = &amp;quot;&amp;quot; [, bool localOnly] ] ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.MarkerAddLine&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( number x1, number y1, number z1, number x2, number y2, number z2 ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.MarkerErasePosition&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( number x, number y, number z ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
= Sounds =&lt;br /&gt;
&#039;&#039;&#039;Spring.LoadSoundDef&#039;&#039;&#039;&lt;br /&gt;
  ( string &amp;quot;soundfile&amp;quot; ) -&amp;gt; nil | boolean success&lt;br /&gt;
  &amp;lt;span class=note&amp;gt;Loads a SoundDefs file, the format is the same as in `gamedata/sounds.lua`.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.PlaySoundFile&#039;&#039;&#039;  &amp;lt;span class=note&amp;gt;Plays WAV or OGG sounds.&amp;lt;/span&amp;gt;&lt;br /&gt;
  ( string &amp;quot;soundfile&amp;quot; [, number volume = 1.0&lt;br /&gt;
    [, number posx, number posy, number posz &lt;br /&gt;
    [, number speedx, number speedy, number speedz ] ] ], [string/number &amp;lt;span class=note&amp;gt;channel&amp;lt;/span&amp;gt; ] ) -&amp;gt; nil | boolean&lt;br /&gt;
  &amp;lt;span class=note&amp;gt;`channel` is new in Spring0.83, and can be one of those:&lt;br /&gt;
    &amp;quot;general&amp;quot; || 0 || nil (default)&lt;br /&gt;
    &amp;quot;battle&amp;quot; || &amp;quot;sfx&amp;quot; | 1&lt;br /&gt;
    &amp;quot;unitreply&amp;quot; || &amp;quot;voice&amp;quot; || 2&lt;br /&gt;
    &amp;quot;userinterface&amp;quot; || &amp;quot;ui&amp;quot; || 3&lt;br /&gt;
  &amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.PlaySoundStream&#039;&#039;&#039;&lt;br /&gt;
  ( string &amp;quot;oggfile&amp;quot; [, number volume = 1.0&lt;br /&gt;
    [, number x, number y, number z ]] ) -&amp;gt; nil | boolean true&lt;br /&gt;
  &amp;lt;span class=note&amp;gt;Allow you to play an Ogg Vorbis (.OGG) compressed sound file.&amp;lt;br&amp;gt; In 83.0 and up multiple sound streams may be played at once &amp;lt;/span&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Spring.StopSoundStream&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; nil&lt;br /&gt;
  &amp;lt;span class=note&amp;gt;Terminates any SoundStream currently running.&amp;lt;/span&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Spring.PauseSoundStream&#039;&#039;&#039;&lt;br /&gt;
  ( ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.SetSoundStreamVolume&#039;&#039;&#039;&lt;br /&gt;
  ( number volume ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
= SendLuaMessage =&lt;br /&gt;
&amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;Very important! (allows synced inter-lua-enviroment communications)&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SendLuaUIMsg&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( string message, string mode ) -&amp;gt; nil&lt;br /&gt;
  &amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;possible modes are:&amp;lt;br&amp;gt;&amp;quot;s&amp;quot;/&amp;quot;specs&amp;quot; &amp;amp; &amp;quot;a&amp;quot;/&amp;quot;allies&amp;quot;&amp;lt;/font&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Spring.SendLuaGaiaMsg&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( string message ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.SendLuaRulesMsg&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( string message ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
= AI =&lt;br /&gt;
&#039;&#039;&#039;Spring.SendSkirmishAIMessage&#039;&#039;&#039; {{new|83.0}}&lt;br /&gt;
  ( number aiTeam, string message )&lt;br /&gt;
  -&amp;gt; nil | boolean ai_processed, { [1] = string response1, etc... }&lt;br /&gt;
&amp;lt;span class=&amp;quot;note&amp;quot;&amp;gt;Note there is nothing in this table due to &amp;quot;limitations&amp;quot; of the AI interface.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Units =&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitLeaveTracks&#039;&#039;&#039; {{new|83.0}}&lt;br /&gt;
  ( number unitID, boolean leavetracks ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
== Unit Selection ==&lt;br /&gt;
&#039;&#039;&#039;Spring.SelectUnitMap&#039;&#039;&#039;&lt;br /&gt;
  ( { [unitID] = anything, ...} [,boolean append] ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.SelectUnitArray&#039;&#039;&#039;&lt;br /&gt;
  ( { [1] = unitID1 , [2] = unitID2 , ...} [,boolean append] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetDrawSelectionInfo&#039;&#039;&#039;&lt;br /&gt;
  ( boolean drawSelectionInfo ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
== Unit Group ==&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitGroup&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( number unitID, number groupID ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
== Give Order ==&lt;br /&gt;
&#039;&#039;&#039;Spring.GiveOrder&#039;&#039;&#039; &amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;gives order to all selected units&amp;lt;/font&amp;gt; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( number cmdID,&lt;br /&gt;
    params = {number, etc...},&lt;br /&gt;
    options = {&amp;quot;alt&amp;quot;, &amp;quot;ctrl&amp;quot;, &amp;quot;shift&amp;quot;, &amp;quot;right&amp;quot;} ) -&amp;gt; nil | boolean true&lt;br /&gt;
&#039;&#039;&#039;Spring.GiveOrderToUnit&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( number unitID,&lt;br /&gt;
    number cmdID,&lt;br /&gt;
    params = {number, etc...},&lt;br /&gt;
    options = {&amp;quot;alt&amp;quot;, &amp;quot;ctrl&amp;quot;, &amp;quot;shift&amp;quot;, &amp;quot;right&amp;quot;} ) -&amp;gt; nil | boolean true&lt;br /&gt;
&#039;&#039;&#039;Spring.GiveOrderToUnitMap&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( unitMap = { [unitID] = dontCare, etc... },&lt;br /&gt;
    number cmdID,&lt;br /&gt;
    params = {number, etc...},&lt;br /&gt;
    options = {&amp;quot;alt&amp;quot;, &amp;quot;ctrl&amp;quot;, &amp;quot;shift&amp;quot;, &amp;quot;right&amp;quot;} ) -&amp;gt; nil | boolean true&lt;br /&gt;
&#039;&#039;&#039;Spring.GiveOrderToUnitArray&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( unitArray = { [1] = unitID, etc... },&lt;br /&gt;
    number cmdID,&lt;br /&gt;
    params = {number, etc...},&lt;br /&gt;
    options = {&amp;quot;alt&amp;quot;, &amp;quot;ctrl&amp;quot;, &amp;quot;shift&amp;quot;, &amp;quot;right&amp;quot;} ) -&amp;gt; nil | boolean true&lt;br /&gt;
&#039;&#039;&#039;Spring.GiveOrderArrayToUnitMap&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( unitMap = { [number unitID] = dontCare, etc... },&lt;br /&gt;
    orderArray = {&lt;br /&gt;
      { number cmdID,&lt;br /&gt;
        params = {number, etc...},&lt;br /&gt;
        options = {&amp;quot;alt&amp;quot;, &amp;quot;ctrl&amp;quot;, &amp;quot;shift&amp;quot;, &amp;quot;right&amp;quot;}&lt;br /&gt;
      }, ..&lt;br /&gt;
    }&lt;br /&gt;
  ) -&amp;gt; nil | boolean true&lt;br /&gt;
&#039;&#039;&#039;Spring.GiveOrderArrayToUnitArray&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( unitArray = { [1] = number unitID, etc... },&lt;br /&gt;
    orderArray = {&lt;br /&gt;
      { number cmdID,&lt;br /&gt;
        params = {number, etc...},&lt;br /&gt;
        options = {&amp;quot;alt&amp;quot;, &amp;quot;ctrl&amp;quot;, &amp;quot;shift&amp;quot;, &amp;quot;right&amp;quot;}&lt;br /&gt;
      }, ..&lt;br /&gt;
    },&lt;br /&gt;
    [boolean pairwise]&lt;br /&gt;
  ) -&amp;gt; nil | boolean true&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;note&amp;quot;&amp;gt;pairwise param ({{new|89.0}}) is used to send multiple units a single individual command&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetBuildFacing&#039;&#039;&#039;&lt;br /&gt;
  ( int Facing ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetBuildSpacing&#039;&#039;&#039;&lt;br /&gt;
  ( int Spacing ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
== Unit NoDraw,NoSelect,NoMinimap ==&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitNoDraw&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;LuaGadgets only!&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( number unitID, boolean noDraw ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitNoSelect&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;LuaGadgets only!&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( number unitID, boolean noSelect ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitNoMinimap&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;LuaGadgets only!&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( number unitID, boolean noMinimap ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
= Developers =&lt;br /&gt;
&#039;&#039;&#039;Spring.SetDrawSky&#039;&#039;&#039;&lt;br /&gt;
  ( boolean drawSky ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.SetDrawWater&#039;&#039;&#039;&lt;br /&gt;
  ( boolean drawWater ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.SetDrawGround&#039;&#039;&#039;&lt;br /&gt;
  ( boolean drawGround ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetWaterParams&#039;&#039;&#039; &amp;lt;span class=warning&amp;gt;needs cheating enabled!&amp;lt;/span&amp;gt;&lt;br /&gt;
  ( table params ) -&amp;gt; nil&lt;br /&gt;
&amp;lt;span class=note&amp;gt;Allows to change water params (mostly BumpWater ones) at runtime. You may want to set BumpWaterUseUniforms in your [[springrc]] to 1, then you don&#039;t even need to restart BumpWater via `/water 4`.&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
  &amp;lt;span class=note&amp;gt;`params` table may contain:&lt;br /&gt;
  params = {&lt;br /&gt;
    absorb = {number r, number g, number b},&lt;br /&gt;
    baseColor = {number r, number g, number b},&lt;br /&gt;
    minColor = {number r, number g, number b},&lt;br /&gt;
    surfaceColor = {number r, number g, number b},&lt;br /&gt;
    diffuseColor = {number r, number g, number b},&lt;br /&gt;
    specularColor = {number r, number g, number b},&lt;br /&gt;
    planeColor = {number r, number g, number b},&lt;br /&gt;
    texture = string file,&lt;br /&gt;
    foamTexture = string file,&lt;br /&gt;
    normalTexture = string file,&lt;br /&gt;
    damage = number value,&lt;br /&gt;
    repeatX = number value,&lt;br /&gt;
    repeatY = number value,&lt;br /&gt;
    surfaceAlpha = number value,&lt;br /&gt;
    ambientFactor = number value,&lt;br /&gt;
    diffuseFactor = number value,&lt;br /&gt;
    specularFactor = number value,&lt;br /&gt;
    specularPower = number value,&lt;br /&gt;
    fresnelMin = number value,&lt;br /&gt;
    fresnelMax = number value,&lt;br /&gt;
    fresnelPower = number value,&lt;br /&gt;
    reflectionDistortion = number value,&lt;br /&gt;
    blurBase = number value,&lt;br /&gt;
    blurExponent = number value,&lt;br /&gt;
    perlinStartFreq = number value,&lt;br /&gt;
    perlinLacunarity = number value,&lt;br /&gt;
    perlinAmplitude = number value,&lt;br /&gt;
    numTiles = number value,&lt;br /&gt;
    shoreWaves = boolean value,&lt;br /&gt;
    forceRendering = boolean value,&lt;br /&gt;
    hasWaterPlane = boolean value,&lt;br /&gt;
  }&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetLogSectionFilterLevel&#039;&#039;&#039; {{New|95.0}}&lt;br /&gt;
   (string sectionName, string|number logLevel)&lt;br /&gt;
see [[infolog.txt]] for possible log setctions (?)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetDrawGroundDeferred&#039;&#039;&#039; {{New|95.0}}&lt;br /&gt;
    (boolean) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.SetDrawModelsDeferred&#039;&#039;&#039; {{New|95.0}}&lt;br /&gt;
    (boolean) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
= GUI =&lt;br /&gt;
&#039;&#039;&#039;Spring.DrawUnitCommands&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID ) -&amp;gt; nil&lt;br /&gt;
  ( { [1] = unitID, ... } [, false ] ) -&amp;gt; nil&lt;br /&gt;
  ( { [unitID] = anything, ... }, true  ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetTeamColor&#039;&#039;&#039;&lt;br /&gt;
  ( number teamID, number r, number g, number b ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.AssignMouseCursor&#039;&#039;&#039; &amp;lt;font class=note&amp;gt;changes/creates the cursor of a single CursorCmd&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( string &amp;quot;cmdName&amp;quot;, string &amp;quot;iconFileName&amp;quot;&lt;br /&gt;
    [, boolean overwrite = true [, boolean hotSpotTopLeft = false] ] ) -&amp;gt; nil | boolean&lt;br /&gt;
&amp;lt;font class=note&amp;gt;Note, that iconFileName is not the full filename instead it is like this:&amp;lt;br/&amp;gt;&lt;br /&gt;
wanted filename: Anims/cursorattack_0.bmp&amp;lt;br/&amp;gt;&lt;br /&gt;
=&amp;gt; iconFileName: cursorattack&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.ReplaceMouseCursor&#039;&#039;&#039; &amp;lt;font class=note&amp;gt;mass replace all occurrence of the cursor in all CursorCmds&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( string &amp;quot;oldFileName&amp;quot;, string &amp;quot;newFileName&amp;quot; [, boolean hotSpotTopLeft = false] ) -&amp;gt; nil | boolean&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetCustomCommandDrawData&#039;&#039;&#039; &amp;lt;font class=note&amp;gt;register your custom cmd so it gets visible in the unit&#039;s cmd queue&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( number cmdID,&lt;br /&gt;
    number cmdID_cloneIcon | string iconname,&lt;br /&gt;
    { number r, number g, number b, number a } [, boolean showArea ] ) -&amp;gt; nil&lt;br /&gt;
  ( number cmdID, nil) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
= Sharing =&lt;br /&gt;
&#039;&#039;&#039;Spring.SetShareLevel&#039;&#039;&#039; &amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;note: shareLevel is 0&amp;lt;= x &amp;lt;= 1&amp;lt;/font&amp;gt; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( string &amp;quot;metal&amp;quot; | &amp;quot;energy&amp;quot;, number shareLevel ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.ShareResources&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( number teamID, string &amp;quot;units&amp;quot; ) -&amp;gt; nil&lt;br /&gt;
  ( number teamID, string &amp;quot;metal&amp;quot; | &amp;quot;energy&amp;quot;, number amount ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
= UnitDef RadarIcons &amp;amp; BuildPics =&lt;br /&gt;
&#039;&#039;&#039;Spring.AddUnitIcon&#039;&#039;&#039;&lt;br /&gt;
  ( string iconName, string texFile [, number size [, number dist [, boolean radAdjust ]]] )&lt;br /&gt;
  -&amp;gt; nil | boolean&lt;br /&gt;
&#039;&#039;&#039;Spring.FreeUnitIcon&#039;&#039;&#039;&lt;br /&gt;
  ( string iconName ) -&amp;gt; nil | boolean&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitDefIcon&#039;&#039;&#039;  &amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;(RadarIcon)&amp;lt;/font&amp;gt; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( number unitDefID, string iconName ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitDefImage&#039;&#039;&#039;   &amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;(BuildPic)&amp;lt;/font&amp;gt; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( number unitDefID, luaTexture | string texFile ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
= Camera =&lt;br /&gt;
&#039;&#039;&#039;Spring.SetCameraState&#039;&#039;&#039;&lt;br /&gt;
  ( table camState, number camTime) -&amp;gt; nil | boolean&lt;br /&gt;
&amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;camState has the same format as the output of Spring.GetCameraState(). See [[Lua_camState]] for details about camState.&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetCameraTarget&#039;&#039;&#039;&lt;br /&gt;
  ( number x, number y, number z [,number transTime] ) -&amp;gt; nil&lt;br /&gt;
&amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;For Spring Engine XZ represents horizontal, from north west corner of map and Y vertical, from water level and rising.&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetCameraOffset&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( [number px = 0 [, number py = 0 [, number pz = 0&lt;br /&gt;
     [, number tx = 0 [, number ty = 0 [, number tz = 0]]]]]] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
= (Virtual-)FileSystem =&lt;br /&gt;
&#039;&#039;&#039;Spring.ExtractModArchiveFile&#039;&#039;&#039;&lt;br /&gt;
  ( string modfile ) -&amp;gt; boolean&lt;br /&gt;
&#039;&#039;&#039;Spring.CreateDir&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( number path ) -&amp;gt; nil | boolean&lt;br /&gt;
&lt;br /&gt;
= Engine Config =&lt;br /&gt;
&amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;The following functions read the engine configs saved in [[springrc]], a version-ed instance of these or a custom file supplied on the command line.&lt;br /&gt;
If &#039;&#039;*Overlay&#039;&#039; is &#039;&#039;true&#039;&#039;, the value will only be set in memory, and not be restored for the next game&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.GetConfigInt&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( string name [, number default [, boolean setInOverlay = false]] ) -&amp;gt; nil | number&lt;br /&gt;
&#039;&#039;&#039;Spring.SetConfigInt&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( string name, number value [, boolean useOverlay = false] ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.GetConfigString&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( string name [, string default [, boolean setInOverlay = false]] ) -&amp;gt; nil | string&lt;br /&gt;
&#039;&#039;&#039;Spring.SetConfigString&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(needs ModUICtrl)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( string name, string value [, boolean useOverlay = false] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
= World Primitives =&lt;br /&gt;
&amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;outdated! use opengl api instead!&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.AddWorldIcon&#039;&#039;&#039;&lt;br /&gt;
  ( number cmdID, number x, number y, number z ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.AddWorldText&#039;&#039;&#039;&lt;br /&gt;
  ( string &amp;quot;text&amp;quot;, number x, number y, number z ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.AddWorldUnit&#039;&#039;&#039;&lt;br /&gt;
  ( number unitDefID,&lt;br /&gt;
    number x, number y, number z,&lt;br /&gt;
    number team, number facing) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
= Sun  =&lt;br /&gt;
&#039;&#039;&#039;Spring.SetSunManualControl&#039;&#039;&#039;&lt;br /&gt;
  ( boolean setManualControl ) - &amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetSunParameters&#039;&#039;&#039;&lt;br /&gt;
  ( number dirX, number dirY, number dirZ, number dist, number startTime, number orbitTime ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetSunDirection&#039;&#039;&#039;&lt;br /&gt;
  ( number dirX, number dirY, number dirZ ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
= Misc =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.Restart&#039;&#039;&#039; {{new|0.79}}&lt;br /&gt;
  ( string commandline_args, string startscript )&lt;br /&gt;
    -&amp;gt; if this call returns, something went wrong&lt;br /&gt;
&amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;&#039;&#039;commandline_args&#039;&#039; are commandline arguments passed to spring executable&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;start-script is the CONTENT of the script.txt spring should use to start (if empty, no start-script is added, you can still point spring to your custom script.txt when you add the file-path to &#039;&#039;commandline_args&#039;&#039;&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetWMIcon&#039;&#039;&#039; {{new|83.0}}&lt;br /&gt;
  ( string iconFileName ) -&amp;gt; nil&lt;br /&gt;
&amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;Sets the icon for the process which is seen in the OS task-bar and other places (default: spring-logo).&amp;lt;br/&amp;gt;&lt;br /&gt;
Note: has to be 24bit or 32bit&amp;lt;br/&amp;gt;&lt;br /&gt;
Note: on windows, it has to be 32x32 pixels in size (recommended for cross-platform)&amp;lt;br/&amp;gt;&lt;br /&gt;
Note: &#039;&#039;*.bmp&#039;&#039; images have to be in BGR format (default for m$ ones).&amp;lt;br/&amp;gt;&lt;br /&gt;
Note: &#039;&#039;*.ico&#039;&#039; images are not supported.&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetWMCaption&#039;&#039;&#039; {{new|83.0}}&lt;br /&gt;
  ( string title [, string titleShort = title ] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;Sets the window &#039;&#039;title&#039;&#039; for the process (default: &amp;quot;Spring &amp;lt;version&amp;gt;&amp;quot;).&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;The &#039;&#039;shortTitle&#039;&#039; is displayed in the OS task-bar (default: &amp;quot;Spring &amp;lt;version&amp;gt;&amp;quot;).&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;&#039;&#039;&#039;NOTE:&#039;&#039;&#039; &#039;&#039;shortTitle&#039;&#039; is only ever possibly used under X11 (Linux &amp;amp; OS X), but not with QT (KDE) and never under Windows. See [http://www.gpwiki.org/index.php/SDL:Tutorials:Initializing_SDL_Libraries#About_the_icon_.28.22Icon_Title.22.29_parameter_on_different_window-managers this site] for more details.&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.ClearWatchdogTimer&#039;&#039;&#039; {{new|83.0}}&lt;br /&gt;
  ( [ string threadName = main ] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.GetClipboard&#039;&#039;&#039; {{new|98.0}}&lt;br /&gt;
  ( ) -&amp;gt; string text&lt;br /&gt;
&lt;br /&gt;
= Rendering =&lt;br /&gt;
&amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;NOTE: these (0.83+) lighting callouts only work when called from unsynced gadgets!&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.AddMapLight&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(requires MaxDynamicMapLights &amp;amp;gt; 0)&amp;lt;/font&amp;gt;&lt;br /&gt;
  (table lightParams) -&amp;gt; number lightHandle&lt;br /&gt;
&#039;&#039;&#039;Spring.AddModelLight&#039;&#039;&#039; &amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-weight:600&amp;quot;&amp;gt;(requires MaxDynamicModelLights &amp;amp;gt; 0)&amp;lt;/font&amp;gt;&lt;br /&gt;
  (table lightParams) -&amp;gt; number lightHandle&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UpdateMapLight&#039;&#039;&#039;&lt;br /&gt;
  (number lightHandle, table lightParams) -&amp;gt; boolean success&lt;br /&gt;
&#039;&#039;&#039;Spring.UpdateModelLight&#039;&#039;&#039;&lt;br /&gt;
  (number lightHandle, table lightParams) -&amp;gt; boolean success&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetMapLightTrackingState&#039;&#039;&#039;&lt;br /&gt;
  (number lightHandle, number unitOrProjectileID,&lt;br /&gt;
   boolean enableTracking, boolean unitOrProjectile) -&amp;gt; boolean success&lt;br /&gt;
&#039;&#039;&#039;Spring.SetModelLightTrackingState&#039;&#039;&#039;&lt;br /&gt;
  (number lightHandle, number unitOrProjectileID,&lt;br /&gt;
   boolean enableTracking, boolean unitOrProjectile) -&amp;gt; boolean success&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;lightParams&#039;&#039;&#039; is a table that should contain at least one of the following recognized key/value pairs:&lt;br /&gt;
&lt;br /&gt;
    lightParams = {&lt;br /&gt;
        position = {px, py, pz},&lt;br /&gt;
        direction = {dx, dy, dz},&lt;br /&gt;
        ambientColor = {red, green, blue},&lt;br /&gt;
        diffuseColor = {red, green, blue},&lt;br /&gt;
        specularColor = {red, green, blue},&lt;br /&gt;
        intensityWeight = {ambientWeight, diffuseWeight, specularWeight},&lt;br /&gt;
&lt;br /&gt;
        -- per-frame decay of ambientColor (spread over TTL frames)&lt;br /&gt;
        ambientDecayRate = {ambientRedDecay, ambientGreenDecay, ambientBlueDecay},&lt;br /&gt;
        -- per-frame decay of diffuseColor (spread over TTL frames)&lt;br /&gt;
        diffuseDecayRate = {diffuseRedDecay, diffuseGreenDecay, diffuseBlueDecay},&lt;br /&gt;
        -- per-frame decay of specularColor (spread over TTL frames)&lt;br /&gt;
        specularDecayRate = {specularRedDecay, specularGreenDecay, specularBlueDecay},&lt;br /&gt;
        -- *DecayType = 0.0 -&amp;gt; interpret *DecayRate values as linear, else as exponential&lt;br /&gt;
        decayFunctionType = {ambientDecayType, diffuseDecayType, specularDecayType},&lt;br /&gt;
&lt;br /&gt;
        radius = number elmos,&lt;br /&gt;
        fov = number degrees,&lt;br /&gt;
        ttl = number frames,&lt;br /&gt;
        priority = number,&lt;br /&gt;
        ignoreLOS = boolean,&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetMapSquareTexture&#039;&#039;&#039;&lt;br /&gt;
  (number texSqrX, number texSqrY, string luaTexName) -&amp;gt; boolean success&lt;br /&gt;
&lt;br /&gt;
[[category: Lua]]&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=Lua_SyncedCtrl&amp;diff=11772</id>
		<title>Lua SyncedCtrl</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=Lua_SyncedCtrl&amp;diff=11772"/>
		<updated>2014-06-20T19:38:26Z</updated>

		<summary type="html">&lt;p&gt;Knorke: /* Unit Control */ SetUnitMoveGoal: moveRaw&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Engine_Development|Development]] &amp;lt; [[Lua_Scripting|Lua Scripting]] &amp;lt; {{FULLPAGENAME}}&lt;br /&gt;
&lt;br /&gt;
= Game End =&lt;br /&gt;
&#039;&#039;&#039;Spring.KillTeam&#039;&#039;&#039; {{new|83.0}}&lt;br /&gt;
  ( number teamID ) -&amp;gt; nil&lt;br /&gt;
&amp;lt;span class=&amp;quot;note&amp;quot;&amp;gt;Will declare a team to be dead ( no further orders can be assigned to such teams&#039;s units ), Gaia team cannot be killed.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.GameOver&#039;&#039;&#039; {{new|83.0}}&lt;br /&gt;
  ( {number allyTeamID1, number allyTeamID2, ...} ) -&amp;gt; nil&lt;br /&gt;
&amp;lt;span class=&amp;quot;note&amp;quot;&amp;gt;Will declare game over, a list of winning allyteams can be passed, if undecided ( like when dropped from the host ) it should be empty ( no winner ), in the case of a draw with multiple winners, all should be listed&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= RulesParams =&lt;br /&gt;
&amp;lt;span class=warning&amp;gt;string values are new since 95.0&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitRulesParam&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, string paramName, number|string paramValue [, table &amp;lt;span class=note&amp;gt;losAccess&amp;lt;/span&amp;gt;] ) -&amp;gt; nil&lt;br /&gt;
   &amp;lt;span class=note&amp;gt;possible keys for the losAccess table are:&lt;br /&gt;
    `private` : only readable by the ally (default)&lt;br /&gt;
    `allied`  : readable by ally + ingame allied&lt;br /&gt;
    `inlos`   : readable if the unit is in LOS&lt;br /&gt;
    `inradar` : readable if the unit is in AirLOS&lt;br /&gt;
    `public`  : readable by all&lt;br /&gt;
   note: if one condition is fulfilled all beneath it are too (e.g. if an unit is in LOS it&amp;lt;br/&amp;gt;     can read params with `inradar=true` even if the param has `inlos=false`)&lt;br /&gt;
   note2: all GameRulesParam are public, TeamRulesParams can just be `private`,`allied`&amp;lt;br/&amp;gt;     and/or `public`&lt;br /&gt;
   note3: You can read RulesParams from &#039;&#039;&#039;any&#039;&#039;&#039; Lua enviroments! With those losAccess&amp;lt;br/&amp;gt;     policies you can limit their access.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetTeamRulesParam&#039;&#039;&#039;&lt;br /&gt;
  ( number teamID, string paramName, number|string paramValue [, table &amp;lt;span class=note&amp;gt;losAccess&amp;lt;/span&amp;gt;] ) -&amp;gt; nil&lt;br /&gt;
   &amp;lt;span class=note&amp;gt;see above for further documentation of losAccess&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetGameRulesParam&#039;&#039;&#039;&lt;br /&gt;
  ( string paramName, number|string paramValue [, table &amp;lt;span class=note&amp;gt;losAccess&amp;lt;/span&amp;gt;] ) -&amp;gt; nil&lt;br /&gt;
   &amp;lt;span class=note&amp;gt;see above for further documentation of losAccess&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Resources =&lt;br /&gt;
&#039;&#039;&#039;Spring.AddTeamResource&#039;&#039;&#039;&lt;br /&gt;
  ( number teamID, string &amp;quot;metal&amp;quot; | &amp;quot;energy&amp;quot;, number amount ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.UseTeamResource&#039;&#039;&#039;&lt;br /&gt;
  ( number teamID, &lt;br /&gt;
    string &amp;quot;metal&amp;quot; | &amp;quot;energy&amp;quot;,number amount |&lt;br /&gt;
    { metal = number amount, energy = number amount}&lt;br /&gt;
  ) -&amp;gt; nil | boolean hadEnough&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetTeamResource&#039;&#039;&#039;&lt;br /&gt;
  ( number teamID, string res, number amount ) -&amp;gt; nil&lt;br /&gt;
&amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;&lt;br /&gt;
  possible values for res are:&lt;br /&gt;
    &amp;quot;m&amp;quot;  = metal&lt;br /&gt;
    &amp;quot;e&amp;quot;  = energy&lt;br /&gt;
    &amp;quot;ms&amp;quot;  = metal storage&lt;br /&gt;
    &amp;quot;es&amp;quot;  = energy storage&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetTeamShareLevel&#039;&#039;&#039;&lt;br /&gt;
  ( number teamID, string &amp;quot;metal&amp;quot; | &amp;quot;energy&amp;quot;, number amount ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.ShareTeamResource&#039;&#039;&#039; &amp;lt;span class=note&amp;gt;0.82 and later&amp;lt;/span&amp;gt;&lt;br /&gt;
  ( number teamID_src, number teamID_recv, string &amp;quot;metal&amp;quot; | &amp;quot;energy&amp;quot;, number amount ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
= Teams =&lt;br /&gt;
&#039;&#039;&#039;Spring.SetAlly&#039;&#039;&#039; {{new|98.0}}&lt;br /&gt;
  ( number firstAllyTeamID, number secondAllyTeamID, boolean ally ) -&amp;gt; nil&lt;br /&gt;
&amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;&lt;br /&gt;
Changes the value of the (one-sided) alliance between: firstAllyTeamID -&amp;gt; secondAllyTeamID&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Unit Handling =&lt;br /&gt;
&#039;&#039;&#039;Spring.CreateUnit&#039;&#039;&#039; &amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;note: offmap positions are clamped! (you still can use MoveCtrl todo so)&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( string &amp;quot;defName&amp;quot; | number unitDefID,&lt;br /&gt;
    number x, number y, number z,&lt;br /&gt;
    (number facing | string &amp;quot;facing&amp;quot;),&lt;br /&gt;
    number teamID&lt;br /&gt;
    [, boolean build = false] &lt;br /&gt;
    [, boolean flattenGround = true]&lt;br /&gt;
    [, number unitID]&lt;br /&gt;
    [, number builderID]) -&amp;gt; number unitID | nil (meaning unit was not created)&lt;br /&gt;
&amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;&lt;br /&gt;
  possible values for facing are:&lt;br /&gt;
    &amp;quot;south&amp;quot; | &amp;quot;s&amp;quot; | 0&lt;br /&gt;
    &amp;quot;east&amp;quot;  | &amp;quot;e&amp;quot; | 1&lt;br /&gt;
    &amp;quot;north&amp;quot; | &amp;quot;n&amp;quot; | 2&lt;br /&gt;
    &amp;quot;west&amp;quot;  | &amp;quot;w&amp;quot; | 3&lt;br /&gt;
  if build is true the unit is created in &amp;quot;being built&amp;quot; state, with buildProgress = 0&lt;br /&gt;
  unitID and builderID are {{new|92.0}}, the former allowing to spawn a unit with&lt;br /&gt;
  a specific ID.&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.DestroyUnit&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID&lt;br /&gt;
    [, boolean selfd = false]&lt;br /&gt;
    [, boolean reclaimed = false]&lt;br /&gt;
    [, number attackerID ] ) -&amp;gt; nil&lt;br /&gt;
&amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;&lt;br /&gt;
 selfd := makes the unit act like it self-destructed&lt;br /&gt;
 reclaimed := don&#039;t show any DeathSequences, don&#039;t leave a wreckage.&lt;br /&gt;
   NOTE this does _not_ give back the resources to the team!&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.TransferUnit&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID,&lt;br /&gt;
    numer newTeamID&lt;br /&gt;
    [, boolean given = true ] ) -&amp;gt; nil&lt;br /&gt;
&amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;if given=false, the unit is captured&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Unit Control ==&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitCosts&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, { &lt;br /&gt;
     [ buildTime  = number amount ],&lt;br /&gt;
     [ metalCost  = number amount ],&lt;br /&gt;
     [ energyCost = number amount ]&lt;br /&gt;
   } ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitTooltip&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, string &amp;quot;tooltip&amp;quot; ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitHealth&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID,&lt;br /&gt;
    number health |&lt;br /&gt;
    { [ health   = number health ],&lt;br /&gt;
      [ capture  = number capture ],&lt;br /&gt;
      [ paralyze = number paralyze ],&lt;br /&gt;
      [ build    = number build ] }&lt;br /&gt;
  ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitMaxHealth&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, number maxHealth ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.AddUnitDamage&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, number damage&lt;br /&gt;
    [, number paralyze = 0 [, number attackerID = -1 [, number weaponID = -1&lt;br /&gt;
      [, number impulse_x [, number impulse_y [, number impulse_z ]]] ]]] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitStockpile&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID [, number stockpile [, number buildPercent ]]) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitExperience&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, number experience ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitFuel&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, number fuel ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitCrashing&#039;&#039;&#039; {{new|83.0}}&lt;br /&gt;
  ( number unitID, boolean crashing ) -&amp;gt; boolean success&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitLineage&#039;&#039;&#039; &amp;lt;span class=&amp;quot;warning&amp;quot;&amp;gt; Removed from version 83.0&amp;lt;/span&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
  ( number unitID, number teamID [, boolean isRoot] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitNeutral&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, boolean neutral ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitTarget&#039;&#039;&#039; &amp;lt;span class=&amp;quot;warning&amp;quot;&amp;gt;userTarget &amp;amp; sucess new in version 95.0&amp;lt;/span&amp;gt;&lt;br /&gt;
  ( number unitID,&lt;br /&gt;
    number enemyUnitID | number x, number y, number z,&lt;br /&gt;
    [ boolean dgun = false ], [ boolean userTarget = false ] ) -&amp;gt;  success&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitBlocking&#039;&#039;&#039; &amp;lt;span class=&amp;quot;warning&amp;quot;&amp;gt;crushable new in version 85.0&amp;lt;/span&amp;gt;&lt;br /&gt;
  ( number unitID, boolean blocking [, boolean collide [, boolean crushable]] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitBlocking&#039;&#039;&#039; {{new|95.0}} changed parameters:&lt;br /&gt;
  number unitID,&lt;br /&gt;
  boolean isBlocking,&lt;br /&gt;
  boolean isSolidObjectCollidable,&lt;br /&gt;
  boolean isProjectileCollidable,&lt;br /&gt;
  boolean isRaySegmentCollidable,&lt;br /&gt;
  boolean crushable,&lt;br /&gt;
  boolean blockEnemyPushing,&lt;br /&gt;
  boolean blockHeightChanges&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitMetalExtraction&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, number depth [,number range] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitBuildSpeed&#039;&#039;&#039;&lt;br /&gt;
  ( number builderID,&lt;br /&gt;
    number buildSpeed, [ number repairSpeed [, number reclaimSpeed&lt;br /&gt;
  [,number resurrectSpeed [, number captureSpeed [, number terraformSpeed ]] ]]] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitNanoPieces&#039;&#039;&#039; {{new|92.0}}&lt;br /&gt;
  ( number builderID, table pieces ) -&amp;gt; nil&lt;br /&gt;
This saves a lot of engine calls, by replacing:&lt;br /&gt;
function script.QueryNanoPiece() return currentpiece end&lt;br /&gt;
Use it!&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitArmored&#039;&#039;&#039; &amp;lt;span class=&amp;quot;warning&amp;quot;&amp;gt;armorMultiple new in version 0.83.x&amp;lt;/span&amp;gt;&lt;br /&gt;
  ( number unitID, boolean armored [, number armorMultiple] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitShieldState&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID [, number weaponID = -1] [, boolean enabled] [, number power] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitFlanking&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, string &amp;quot;mode&amp;quot;, number mode ) -&amp;gt; nil&lt;br /&gt;
  ( number unitID, string &amp;quot;moveFactor&amp;quot;, number factor) -&amp;gt; nil&lt;br /&gt;
  ( number unitID, string &amp;quot;minDamage&amp;quot;, number minDamage ) -&amp;gt; nil&lt;br /&gt;
  ( number unitID, string &amp;quot;mazDamage&amp;quot;, number maxDamage ) -&amp;gt; nil&lt;br /&gt;
  ( number unitID, string &amp;quot;dir&amp;quot;, number x, number y, number z) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitWeaponState&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, number weaponNum, table states ) -&amp;gt; nil&lt;br /&gt;
  ( number unitID, number weaponNum, string key, number value ) -&amp;gt; nil&lt;br /&gt;
  &amp;lt;span class=&amp;quot;note&amp;quot;&amp;gt;format of the states table:&lt;br /&gt;
    {&lt;br /&gt;
      [&amp;quot;reloadState&amp;quot; = number value,]&lt;br /&gt;
      [&amp;quot;reloadFrame&amp;quot; = number value,]   (synonym for reloadState!)&lt;br /&gt;
      [&amp;quot;reloadTime&amp;quot;  = number value,]&lt;br /&gt;
      [&amp;quot;accuracy&amp;quot;    = number value,]&lt;br /&gt;
      [&amp;quot;sprayAngle&amp;quot;  = number value,]&lt;br /&gt;
      [&amp;quot;range&amp;quot;       = number value,]&lt;br /&gt;
      [&amp;quot;projectileSpeed&amp;quot; = number value,]&lt;br /&gt;
      [&amp;quot;burst&amp;quot; = number value,]&lt;br /&gt;
      [&amp;quot;burstRate&amp;quot; = number value,]&lt;br /&gt;
      [&amp;quot;projectiles&amp;quot; = number value,]&lt;br /&gt;
      [&amp;quot;aimReady&amp;quot; = number value,] &amp;lt;span class=note&amp;gt;(&amp;lt;&amp;gt;0.0f := true)&amp;lt;/span&amp;gt;&lt;br /&gt;
    }&lt;br /&gt;
  &amp;lt;/span&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitCollisionVolumeData&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, number scaleX, number scaleY, number scaleZ,&lt;br /&gt;
    number offsetX, number offsetY, number offsetX,&lt;br /&gt;
    number vType, number tType, number Axis&lt;br /&gt;
  ) -&amp;gt; nil&lt;br /&gt;
  &amp;lt;span class=&amp;quot;note&amp;quot;&amp;gt;enum COLVOL_TYPES {&lt;br /&gt;
      COLVOL_TYPE_DISABLED = -1,&lt;br /&gt;
      COLVOL_TYPE_ELLIPSOID = 0,&lt;br /&gt;
      COLVOL_TYPE_CYLINDER,&lt;br /&gt;
      COLVOL_TYPE_BOX,&lt;br /&gt;
      COLVOL_TYPE_SPHERE,&lt;br /&gt;
      COLVOL_NUM_TYPES       // number of non-disabled collision volume types&lt;br /&gt;
    };&lt;br /&gt;
    enum COLVOL_TESTS {&lt;br /&gt;
      COLVOL_TEST_DISC = 0,&lt;br /&gt;
      COLVOL_TEST_CONT = 1,&lt;br /&gt;
      COLVOL_NUM_TESTS = 2   // number of tests&lt;br /&gt;
    };&lt;br /&gt;
    enum COLVOL_AXES {&lt;br /&gt;
      COLVOL_AXIS_X   = 0,&lt;br /&gt;
      COLVOL_AXIS_Y   = 1,&lt;br /&gt;
      COLVOL_AXIS_Z   = 2,&lt;br /&gt;
      COLVOL_NUM_AXES = 3    // number of collision volume axes&lt;br /&gt;
    };&lt;br /&gt;
  &amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitPieceCollisionVolumeData&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, number pieceIndex, boolean enable, &lt;br /&gt;
    number scaleX, number scaleY, number scaleZ,&lt;br /&gt;
    number offsetX, number offsetY, number offsetZ&lt;br /&gt;
    [, number volumeType [, number primaryAxis]]&lt;br /&gt;
  ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitTravel&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, number travel [, number travelPeriod] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitMoveGoal&#039;&#039;&#039;   &amp;lt;span class=&amp;quot;note&amp;quot;&amp;gt;used by default commands to get in build-,attackrange etc.&amp;lt;/span&amp;gt;&lt;br /&gt;
  (number unitID, number goalx, number goaly, number goalz &lt;br /&gt;
  [, number goalRadius [, number moveSpeed [, bool moveRaw ]]] )&lt;br /&gt;
{{new|98.0}} &amp;lt;span class=&amp;quot;note&amp;quot;&amp;gt;moveRaw: [http://springrts.com/mantis/view.php?id=4412 allow unit to dumbly move to a coordinate without calculating path.]&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitPhysics&#039;&#039;&#039; &amp;lt;span class=&amp;quot;warning&amp;quot;&amp;gt;drag new in version 95.0&amp;lt;/span&amp;gt;&lt;br /&gt;
  ( number unitID,&lt;br /&gt;
    number posx, number posy, number posz,&lt;br /&gt;
    number velx, number vely, number velz,&lt;br /&gt;
    number rotx, number roty, number rotz,&lt;br /&gt;
    number dragx, number dragy, number dragz,&lt;br /&gt;
  ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitPosition&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, number x, number z [, boolean alwaysAboveSea] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitDirection&#039;&#039;&#039; {{new|90.0}}&lt;br /&gt;
  ( number unitID, number x, number y, number z ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitVelocity&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, number velx, number vely, number velz ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitRotation&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, number rotx, number roty, number rotz ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.AddUnitImpulse&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, number x, number y, number z [, decayRate ] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.AddUnitSeismicPing&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, number pingSize ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.RemoveBuildingDecal&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitMidAndAimPos&#039;&#039;&#039; {{new|89.0}}&lt;br /&gt;
  ( number unitID, &lt;br /&gt;
    number mpx, number mpy, number mpz, &lt;br /&gt;
    number apx, number apy, number apz, &lt;br /&gt;
    [, boolean relative] ) -&amp;gt; boolean success&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;&lt;br /&gt;
mpx, mpy, mpz: new middle position of unit&lt;br /&gt;
&lt;br /&gt;
apx, apy, apz: new position that enemies aim at on this unit&lt;br /&gt;
&lt;br /&gt;
relative: are the new coordinates relative to world or unit coordinates?&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitRadiusAndHeight&#039;&#039;&#039; {{new|89.0}}&lt;br /&gt;
  ( number unitID, number radius, number height ) -&amp;gt; boolean success&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitWeaponFire&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, number weaponID ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitWeaponHoldFire&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, number weaponID ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
== Unit LOS ==&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitCloak&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID,&lt;br /&gt;
    boolean cloaked | number scriptCloak,&lt;br /&gt;
    [ number decloakDistance | boolean decloakAbs ] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;&lt;br /&gt;
  If the 2nd argument is a number, the value works like this:&lt;br /&gt;
   1:=normal cloak&lt;br /&gt;
   2:=for free cloak (cost no E)&lt;br /&gt;
   3:=for free + no decloaking (except the unit is stunned)&lt;br /&gt;
   4&amp;gt;=ultimative cloak (no ecost, no decloaking, no stunned decloak)&lt;br /&gt;
&lt;br /&gt;
  The decloak distance is only changed if the 3th argument is a number or a boolean.&lt;br /&gt;
   If the boolean is false it takes the default decloak distance for that unitdef,&lt;br /&gt;
   if the boolean is true it takes the absolute value of it.&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitSonarStealth&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, boolean sonarStealth ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitStealth&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, boolean stealth ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitAlwaysVisible&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, boolean alwaysVisible ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitLosMask&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, number allyTeam, number los | table losTypes ) -&amp;gt; nil&lt;br /&gt;
&amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;the 3th argument is either the bit-and combination of the following numbers:&lt;br /&gt;
  LOS_INLOS     = 1&lt;br /&gt;
  LOS_INRADAR   = 2&lt;br /&gt;
  LOS_PREVLOS   = 4&lt;br /&gt;
  LOS_CONTRADAR = 8&lt;br /&gt;
&amp;lt;/font&amp;gt;&amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;or a table of the following form:&lt;br /&gt;
  losTypes = {&lt;br /&gt;
    [los = boolean,]&lt;br /&gt;
    [radar = boolean,]&lt;br /&gt;
    [prevLos = boolean,]&lt;br /&gt;
    [contRadar = boolean,]&lt;br /&gt;
  }&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitLosState&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, number allyTeam, number los | table losTypes ) -&amp;gt; nil&lt;br /&gt;
  &amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;see above for more info on the arguments&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitSensorRadius&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, string type, number radius ) -&amp;gt; nil | number newRadius&lt;br /&gt;
  &amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;type can be:&lt;br /&gt;
  &amp;quot;los&amp;quot;,&amp;quot;airLos&amp;quot;,&amp;quot;radar&amp;quot;,&amp;quot;sonar&amp;quot;,&amp;quot;seismic&amp;quot;,&amp;quot;radarJammer&amp;quot;,&amp;quot;sonarJammer&amp;quot;&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetRadarErrorParams&#039;&#039;&#039; {{new|95.0}}&lt;br /&gt;
  (number allyTeamID, number allyteamErrorSize &lt;br /&gt;
  [, number baseErrorSize [, number baseErrorMult ]]) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitPosErrorParams&#039;&#039;&#039; {{new|95.0}}&lt;br /&gt;
  (number unitID, number posErrorVector.x, number posErrorVector.y, number posErrorVector.z,&lt;br /&gt;
  number posErrorDelta.x, number posErrorDelta.y, number posErrorDelta.z&lt;br /&gt;
  [ , number nextPosErrorUpdate]) --&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
== Unit Resourcing ==&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitResourcing&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID,&lt;br /&gt;
    string res, number amount |&lt;br /&gt;
    { res = number amount, ... }&lt;br /&gt;
  ) -&amp;gt; nil&lt;br /&gt;
&amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;&lt;br /&gt;
  possible values for res are: &amp;quot;[u|c][u|m][m|e]&amp;quot;&lt;br /&gt;
       unconditional | conditional&lt;br /&gt;
                 use | make&lt;br /&gt;
               metal | energy&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.AddUnitResource&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, string &amp;quot;m&amp;quot; | &amp;quot;e&amp;quot;, number amount ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UseUnitResource&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, string &amp;quot;m&amp;quot; | &amp;quot;e&amp;quot;, number amount ) -&amp;gt; nil | boolean okay&lt;br /&gt;
  ( number unitID, { [&amp;quot;m&amp;quot; | &amp;quot;metal&amp;quot; | &amp;quot;e&amp;quot; | &amp;quot;energy&amp;quot;] = amount, ... } ) -&amp;gt; nil | boolean okay&lt;br /&gt;
&lt;br /&gt;
= Feature Handling =&lt;br /&gt;
&#039;&#039;&#039;Spring.CreateFeature&#039;&#039;&#039;&lt;br /&gt;
  ( string &amp;quot;defName&amp;quot; | number featureDefID, &lt;br /&gt;
    number x, number y, number z&lt;br /&gt;
    [, number heading &lt;br /&gt;
    [, number AllyTeamID &lt;br /&gt;
    [, number featureID ]]] ) -&amp;gt; number featureID&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.DestroyFeature&#039;&#039;&#039;&lt;br /&gt;
  ( number featureID ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.TransferFeature&#039;&#039;&#039;&lt;br /&gt;
  ( number featureID, number teamID ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Feature Control ==&lt;br /&gt;
&#039;&#039;&#039;Spring.SetFeatureHealth&#039;&#039;&#039;&lt;br /&gt;
  ( number featureID, number health) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetFeatureReclaim&#039;&#039;&#039;&lt;br /&gt;
  ( number featureID, number reclaimLeft) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetFeatureResurrect&#039;&#039;&#039;&lt;br /&gt;
  ( number featureID, string &amp;quot;UnitDefName?&amp;quot; [, number facing | string &amp;quot;facing&amp;quot; ] ) -&amp;gt; nil&lt;br /&gt;
&amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;&lt;br /&gt;
  possible values for facing are:&lt;br /&gt;
    &amp;quot;south&amp;quot; | &amp;quot;s&amp;quot; | 0&lt;br /&gt;
    &amp;quot;east&amp;quot;  | &amp;quot;e&amp;quot; | 1&lt;br /&gt;
    &amp;quot;north&amp;quot; | &amp;quot;n&amp;quot; | 2&lt;br /&gt;
    &amp;quot;west&amp;quot;  | &amp;quot;w&amp;quot; | 3&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetFeaturePosition&#039;&#039;&#039;&lt;br /&gt;
  ( number featureID, number x, number y, number z [, boolean snapToGround]) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetFeatureDirection&#039;&#039;&#039;&lt;br /&gt;
  ( number featureID, number x, number y, number z ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetFeatureVelocity&#039;&#039;&#039; {{New|95.0}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetFeaturePhysics&#039;&#039;&#039; {{New|95.0}}&lt;br /&gt;
&lt;br /&gt;
(like their feature counterparts at [[Lua_SyncedCtrl#Unit_Control]])&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetFeatureNoSelect&#039;&#039;&#039;&lt;br /&gt;
  ( number featureID, boolean noSelect ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetFeatureAlwaysVisible&#039;&#039;&#039;&lt;br /&gt;
  ( number featureID, boolean enable ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetFeatureCollisionVolumeData&#039;&#039;&#039;&lt;br /&gt;
  ( number featureID, number scaleX, number scaleY, number scaleZ,&lt;br /&gt;
    number offsetX, number offsetY, number offsetX,&lt;br /&gt;
    number vType, number tType, number Axis&lt;br /&gt;
  ) -&amp;gt; nil&lt;br /&gt;
  &amp;lt;span class=note&amp;gt;check Spring.SetUnitCollisionVolumeData for further explanation of the arguments&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetFeatureMidAndAimPos&#039;&#039;&#039; {{new|89.0}}&lt;br /&gt;
  ( number unitID, &lt;br /&gt;
    number mpx, number mpy, number mpz, &lt;br /&gt;
    number apx, number apy, number apz, &lt;br /&gt;
    [, boolean relative] ) -&amp;gt; boolean success&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;span class=note&amp;gt;check Spring.SetUnitMidAndAimPos for further explanation of the arguments&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetFeatureRadiusAndHeight&#039;&#039;&#039; {{new|89.0}}&lt;br /&gt;
  ( number unitID, number radius, number height ) -&amp;gt; boolean success&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetFeatureBlocking&#039;&#039;&#039;&lt;br /&gt;
  (number featureID, boolean blocking, boolean collidable) --&amp;gt; boolean&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetFeatureBlocking&#039;&#039;&#039; {{new|95.0}} changed parameters:&lt;br /&gt;
  number featureID,&lt;br /&gt;
  boolean isBlocking,&lt;br /&gt;
  boolean isSolidObjectCollidable,&lt;br /&gt;
  boolean isProjectileCollidable,&lt;br /&gt;
  boolean isRaySegmentCollidable,&lt;br /&gt;
  boolean crushable,&lt;br /&gt;
  boolean blockEnemyPushing,&lt;br /&gt;
  boolean blockHeightChanges&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Lua to COB =&lt;br /&gt;
&#039;&#039;&#039;Spring.CallCOBScript&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, number funcID | string funcName, number retArgs, COBArg1, COBArg2, ... )&lt;br /&gt;
    -&amp;gt; nil | number returnValue, number retArg1, number retArg2, ...&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.CallCOBScriptCB&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;font style=&amp;quot;color:red;font-weight:600&amp;quot;&amp;gt;broken in 0.78.2.1; will be removed with the introduction of Lua as COB replacement&amp;lt;/font&amp;gt;&lt;br /&gt;
  ( number unitID, number funcID | string funcName, number retArgs, COBArg1, COBArg2, ... )&lt;br /&gt;
    -&amp;gt; nil | number returnValue, number CallbackData, number retArg1, number retArg2, ...&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.GetCOBScriptID&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, string funcName ) -&amp;gt; nil | number funcID&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class=&amp;quot;warning&amp;quot;&amp;gt;&amp;lt;b&amp;gt;Note: Don&#039;t use Spring.[Get|Set]UnitCOBValue in LUS just because you are familar with it since bos/cob, use the mighty LuaSpringAPI instead!&amp;lt;/b&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.GetUnitCOBValue&#039;&#039;&#039; &lt;br /&gt;
  ( number unitID [, boolean splitData=false], number COBValue&lt;br /&gt;
    [, number param1 [,number param2 [, number param3 [, number param4 ] ] ] ] )&lt;br /&gt;
  -&amp;gt; number result | number result1, number result2&lt;br /&gt;
  &amp;lt;span class=note&amp;gt;you find the possible values for `COBValue` in [[Lua_ConstCOB#Get.2FSet|Lua_ConstCOB]]&amp;lt;/span&amp;gt;&lt;br /&gt;
  &amp;lt;span class=note&amp;gt; also see [[Animation-CobConstants#Custom_Variables|Custom_Variables]]&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitCOBValue&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, number COBValue, number param1 [,number param2] ) -&amp;gt; nil&lt;br /&gt;
  &amp;lt;span class=note&amp;gt;you find the possible values for `COBValue` in [[Lua_ConstCOB#Get.2FSet|Lua_ConstCOB]]&amp;lt;/span&amp;gt;&lt;br /&gt;
  &amp;lt;span class=note&amp;gt; also see [[Animation-CobConstants#Custom_Variables|Custom_Variables]]&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Give Order =&lt;br /&gt;
&amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;options can also be a bitmask; e.g. 0 instead of an empty table (can avoid performance hit on table creation)&amp;lt;br&amp;gt;&lt;br /&gt;
see [[Lua CMDs]] for relevant constants&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.GiveOrderToUnit&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID,&lt;br /&gt;
    number cmdID,&lt;br /&gt;
    params = {number, etc...},&lt;br /&gt;
    options = {&amp;quot;alt&amp;quot;, &amp;quot;ctrl&amp;quot;, &amp;quot;shift&amp;quot;, &amp;quot;right&amp;quot;} ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.GiveOrderToUnitMap&#039;&#039;&#039;&lt;br /&gt;
  ( unitMap = { [unitID] = dontCare, etc... },&lt;br /&gt;
    number cmdID,&lt;br /&gt;
    params = {number, etc...},&lt;br /&gt;
    options = {&amp;quot;alt&amp;quot;, &amp;quot;ctrl&amp;quot;, &amp;quot;shift&amp;quot;, &amp;quot;right&amp;quot;} ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.GiveOrderToUnitArray&#039;&#039;&#039;&lt;br /&gt;
  ( unitArray = { [1] = unitID, etc... },&lt;br /&gt;
    number cmdID,&lt;br /&gt;
    params = {number, etc...},&lt;br /&gt;
    options = {&amp;quot;alt&amp;quot;, &amp;quot;ctrl&amp;quot;, &amp;quot;shift&amp;quot;, &amp;quot;right&amp;quot;} ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.GiveOrderArrayToUnitMap&#039;&#039;&#039;&lt;br /&gt;
  ( unitMap = { [number unitID] = dontCare, etc... },&lt;br /&gt;
    orderArray = {&lt;br /&gt;
      { number cmdID,&lt;br /&gt;
        {number, etc...},     &amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;params&amp;lt;/font&amp;gt;&lt;br /&gt;
        {&amp;quot;alt&amp;quot;, &amp;quot;ctrl&amp;quot;, &amp;quot;shift&amp;quot;, &amp;quot;right&amp;quot;}   &amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;options&amp;lt;/font&amp;gt;&lt;br /&gt;
      }, ..&lt;br /&gt;
    }&lt;br /&gt;
  ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.GiveOrderArrayToUnitArray&#039;&#039;&#039;&lt;br /&gt;
  ( unitArray = { [1] = number unitID, etc... },&lt;br /&gt;
    orderArray = {&lt;br /&gt;
      { number cmdID,&lt;br /&gt;
        {number, etc...},    &amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;params&amp;lt;/font&amp;gt;&lt;br /&gt;
        {&amp;quot;alt&amp;quot;, &amp;quot;ctrl&amp;quot;, &amp;quot;shift&amp;quot;, &amp;quot;right&amp;quot;}   &amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;options&amp;lt;/font&amp;gt;&lt;br /&gt;
      }, ..&lt;br /&gt;
    }&lt;br /&gt;
  ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
=Ground=&lt;br /&gt;
== Grass ==&lt;br /&gt;
&#039;&#039;&#039;Spring.AddGrass&#039;&#039;&#039;&lt;br /&gt;
  ( number x, number z ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.RemoveGrass&#039;&#039;&#039;&lt;br /&gt;
  ( number x, number z ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
== Heightmap ==&lt;br /&gt;
&amp;lt;span class=&amp;quot;note&amp;quot;&amp;gt;Note that x &amp;amp; z coords are in worldspace (Game.mapSizeX/Z), still the heightmap resolution is Game.squareSize.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.LevelHeightMap&#039;&#039;&#039;&lt;br /&gt;
  ( number x1, number z1 [, number x2, number z2], number height ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.AdjustHeightMap&#039;&#039;&#039; &amp;lt;span class=&amp;quot;note&amp;quot;&amp;gt;(heightmap[x][z] += height;)&amp;lt;/span&amp;gt;&lt;br /&gt;
  ( number x1, number z1 [, number x2, number z2], number height ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.RevertHeightMap&#039;&#039;&#039;&lt;br /&gt;
  ( number x1, number z1 [, number x2, number z2], number origFactor ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetHeightMapFunc&#039;&#039;&#039;&lt;br /&gt;
  ( lua_function [, arg1 ,[ arg2 [, ... ] ] ) -&amp;gt; nil | number absTotalHeightMapAmountChanged&lt;br /&gt;
&amp;lt;span class=&amp;quot;note&amp;quot;&amp;gt;Example code:&amp;lt;/span&amp;gt;&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
Spring.SetHeightMapFunc(function()&lt;br /&gt;
	for z=0,Game.mapSizeZ, Game.squareSize do&lt;br /&gt;
		for x=0,Game.mapSizeX, Game.squareSize do&lt;br /&gt;
			Spring.SetHeightMap( x, z, 200 + 20 * math.cos((x + z) / 90) )&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Spring.AddHeightMap&#039;&#039;&#039; &amp;lt;span class=&amp;quot;warning&amp;quot;&amp;gt;can only be called in SetHeightMapFunc()&amp;lt;/span&amp;gt; &lt;br /&gt;
  ( number x, number z, number height ) -&amp;gt; nil | number newHeight&lt;br /&gt;
&#039;&#039;&#039;Spring.SetHeightMap&#039;&#039;&#039; &amp;lt;span class=&amp;quot;warning&amp;quot;&amp;gt;can only be called in SetHeightMapFunc()&amp;lt;/span&amp;gt;&lt;br /&gt;
  ( number x, number z, number height [,number terraform = 1] ) -&amp;gt; nil | number absHeightDiff&lt;br /&gt;
&amp;lt;span class=&amp;quot;note&amp;quot;&amp;gt;the terraform argument is a scaling factor:&lt;br /&gt;
so if 0 nothing will be changed (the terraform starts) and if it is 1 the terraform will be finished.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.LevelSmoothMesh&#039;&#039;&#039;&lt;br /&gt;
  ( number x1, number z1 [, number x2, number z2], number height ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.AdjustSmoothMesh&#039;&#039;&#039;&lt;br /&gt;
  ( number x1, number z1 [, number x2, number z2], number height ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.RevertSmoothMesh&#039;&#039;&#039;&lt;br /&gt;
  ( number x1, number z1 [, number x2, number z2], number origFactor ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetSmoothMeshFunc&#039;&#039;&#039;&lt;br /&gt;
  ( lua_function [, arg1 ,[ arg2 [, ... ] ] ) -&amp;gt; nil | number absTotalHeightMapAmountChanged&lt;br /&gt;
&#039;&#039;&#039;Spring.AddSmoothMesh&#039;&#039;&#039; &amp;lt;span class=&amp;quot;warning&amp;quot;&amp;gt;can only be called in SetSmoothMeshFunc()&amp;lt;/span&amp;gt; &lt;br /&gt;
  ( number x, number z, number height ) -&amp;gt; nil | number newHeight&lt;br /&gt;
&#039;&#039;&#039;Spring.SetSmoothMesh&#039;&#039;&#039; &amp;lt;span class=&amp;quot;warning&amp;quot;&amp;gt;can only be called in SetSmoothMeshFunc()&amp;lt;/span&amp;gt;&lt;br /&gt;
  ( number x, number z, number height [,number terraform = 1] ) -&amp;gt; nil | number absHeightDiff&lt;br /&gt;
&lt;br /&gt;
== TerrainTypes ==&lt;br /&gt;
&#039;&#039;&#039;Spring.SetMapSquareTerrainType&#039;&#039;&#039;&lt;br /&gt;
  ( number x, number z, int newType ) -&amp;gt; nil | int oldType&lt;br /&gt;
&#039;&#039;&#039;Spring.SetTerrainTypeData&#039;&#039;&#039;&lt;br /&gt;
  ( int typeIndex&lt;br /&gt;
  [, number speedTanks = nil ]&lt;br /&gt;
  [, number speedKBOTs = nil ]&lt;br /&gt;
  [, number speedHovers = nil ]&lt;br /&gt;
  [, number speedShips = nil ] ) -&amp;gt; nil | boolean true&lt;br /&gt;
&lt;br /&gt;
== MetalAmount ==&lt;br /&gt;
&#039;&#039;&#039;Spring.SetMetalAmount&#039;&#039;&#039; {{new|83.0}}&lt;br /&gt;
  ( number x, number z, number metalAmount)&lt;br /&gt;
&amp;lt;span class=&amp;quot;note&amp;quot;&amp;gt;x &amp;amp; z coords are in worldspace/16&amp;lt;br&amp;gt;metalAmount must be between 0 and 255*maxMetal (with maxMetal from the .smd or mapinfo.lua)&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Command Descriptions =&lt;br /&gt;
&amp;lt;font color=&amp;quot;red&amp;quot; style=&amp;quot;font-size:120%; font-weight:600&amp;quot;&amp;gt;Doesn&#039;t work in unsynced code!&amp;lt;/font&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.EditUnitCmdDesc&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID, number cmdDescID, table cmdArray ) -&amp;gt; nil&lt;br /&gt;
&amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;&lt;br /&gt;
  structure of cmdArray:&lt;br /&gt;
  {&lt;br /&gt;
    [ id          = int ],&lt;br /&gt;
    [ type        = int ],&lt;br /&gt;
    [ name        = string ],&lt;br /&gt;
    [ action      = string ],&lt;br /&gt;
    [ tooltip     = string ],&lt;br /&gt;
    [ texture     = string ],&lt;br /&gt;
    [ cursor      = string ],&lt;br /&gt;
    [ hidden      = boolean ],&lt;br /&gt;
    [ disabled    = boolean ],&lt;br /&gt;
    [ showUnique  = boolean ],&lt;br /&gt;
    [ onlyTexture = boolean ],&lt;br /&gt;
    [ params      = { string = string, ... } ]&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.InsertUnitCmdDesc&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID [, number cmdDescID ] , table cmdArray ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.RemoveUnitCmdDesc&#039;&#039;&#039;&lt;br /&gt;
  ( number unitID [, number cmdDescID ] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
= Other =&lt;br /&gt;
&#039;&#039;&#039;Spring.SetNoPause&#039;&#039;&#039;&lt;br /&gt;
  ( boolean noPause ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetUnitToFeature&#039;&#039;&#039;&lt;br /&gt;
  ( boolean tofeature ) -&amp;gt; nil&lt;br /&gt;
&amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;&lt;br /&gt;
an ugly global switch that can be used to block units turning into features when they finish being built (like *A DT&#039;s do, which have the isFeature tag)&lt;br /&gt;
[http://springrts.com/phpbb/viewtopic.php?f=14&amp;amp;p=481521 thread]&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetExperienceGrade&#039;&#039;&#039;&lt;br /&gt;
  ( number expGrade&lt;br /&gt;
   &amp;lt;font color=#55ee99&amp;gt;[, number ExpPowerScale [, number ExpHealthScale [, number ExpReloadScale ]]]&amp;lt;/font&amp;gt; ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;font color=&amp;quot;#55ee99&amp;quot;&amp;gt;expGrade defines how often UnitExperience() will be called,&lt;br /&gt;
   it is based on the following equation:&lt;br /&gt;
     (int) [exp/(exp+1)] / expGrade&lt;br /&gt;
   If this integer differs from the one before the experience change&lt;br /&gt;
   it will call UnitExperience().&lt;br /&gt;
  Also those 3 last params are only available in .cheat&lt;br /&gt;
  &amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SpawnCEG&#039;&#039;&#039;&lt;br /&gt;
  ( string &amp;quot;cegname&amp;quot; | number cegID,&lt;br /&gt;
    number posX = 0, number posY = 0, number posZ = 0,&lt;br /&gt;
    number dirX = 0, number dirY = 0, number dirZ = 0,&lt;br /&gt;
    number radius = 0, number damage = 0&lt;br /&gt;
  ) -&amp;gt; nil | boolean success, cegID&lt;br /&gt;
&amp;lt;span class=&amp;quot;warning&amp;quot;&amp;gt;cegID new in 95.0&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Projectiles =&lt;br /&gt;
&#039;&#039;&#039;Spring.SpawnProjectile&#039;&#039;&#039;&lt;br /&gt;
  ( number weaponDefID, table projectileParams ) -&amp;gt; nil | number projectileID&lt;br /&gt;
  &amp;lt;span class=note&amp;gt;possible keys of projectileParams are:&lt;br /&gt;
    pos = {number x, number y, number z},&lt;br /&gt;
    end = {number x, number y, number z},&lt;br /&gt;
    speed = {number x, number y, number z},&lt;br /&gt;
    spread = {number x, number y, number z},&lt;br /&gt;
    error = {number x, number y, number z},&lt;br /&gt;
    owner = number,&lt;br /&gt;
    team = number,&lt;br /&gt;
    ttl = number,&lt;br /&gt;
    gravity = number,&lt;br /&gt;
    tracking = number,&lt;br /&gt;
    maxRange = number,&lt;br /&gt;
    startAlpha = number,&lt;br /&gt;
    endAlpha = number,&lt;br /&gt;
    model = string,&lt;br /&gt;
    cegTag = string,&lt;br /&gt;
  &amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetProjectileTarget&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class = &amp;quot;warning&amp;quot;&amp;gt;Pre 95.0:&amp;lt;/span&amp;gt;  ( number projectileID, &lt;br /&gt;
    [ number targetID, string targetTypeStr ] | [ number posX, number posY, number posZ ] ) &lt;br /&gt;
    -&amp;gt; nil | boolean validTarget&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span class = &amp;quot;warning&amp;quot;&amp;gt;Post 95.0:&amp;lt;/span&amp;gt;  ( number projectileID, &lt;br /&gt;
    [ number targetID [, number targetType]]  |  [number posX, number posY, number posZ]) &lt;br /&gt;
    --&amp;gt; nil | boolean validTarget&lt;br /&gt;
  &amp;lt;span class=note&amp;gt;targetTypeStr can be one of: &lt;br /&gt;
    &#039;u&#039; - unit&lt;br /&gt;
    &#039;f&#039; - feature&lt;br /&gt;
    &#039;p&#039; - projectile&lt;br /&gt;
  while targetTypeInt is one of:&lt;br /&gt;
    string.byte(&#039;g&#039;) := GROUND&lt;br /&gt;
    string.byte(&#039;u&#039;) := UNIT&lt;br /&gt;
    string.byte(&#039;f&#039;) := FEATURE&lt;br /&gt;
    string.byte(&#039;p&#039;) := PROJECTILE&lt;br /&gt;
  &amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetProjectileMoveControl&#039;&#039;&#039; &amp;lt;span class=note&amp;gt;(disables engine movecontrol, so lua can fully control the physics)&amp;lt;/span&amp;gt;&lt;br /&gt;
  ( number projID, boolean enable ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.SetProjectilePosition&#039;&#039;&#039;&lt;br /&gt;
  ( number projID [, number x = 0 [, number y = 0 [, number z = 0 ]]] ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.SetProjectileVelocity&#039;&#039;&#039;&lt;br /&gt;
  ( number projID [, number x = 0 [, number y = 0 [, number z = 0 ]]] ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.SetProjectileCollision&#039;&#039;&#039;&lt;br /&gt;
  ( number projID ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.SetProjectileGravity&#039;&#039;&#039; &lt;br /&gt;
  ( number projID [, number grav = 0] ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.SetProjectileSpinAngle&#039;&#039;&#039; {{new|95.0}} Deprecated&lt;br /&gt;
  ( number projID [, number spinAngle = 0] ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.SetProjectileSpinSpeed&#039;&#039;&#039; {{new|95.0}} Deprecated&lt;br /&gt;
  ( number projID [, number speed = 0] ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.SetProjectileSpinVec&#039;&#039;&#039; {{new|95.0}} Deprecated&lt;br /&gt;
  ( number projID [, number x = 0 [, number y = 0 [, number z = 0]]] ) -&amp;gt; nil&lt;br /&gt;
&#039;&#039;&#039;Spring.SetProjectileCEG&#039;&#039;&#039;&lt;br /&gt;
  ( number projID, string ceg_name ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetPieceProjectileParams&#039;&#039;&#039; {{new|95.0}} &lt;br /&gt;
  (number projectileID,&lt;br /&gt;
  [ number explosionFlags, [ number spinAngle, [ number spinSpeed,&lt;br /&gt;
  [ number spinVector.x, [ number spinVector.y, [ number spinVector.z ]]]]]]) --&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.SetProjectileAlwaysVisible&#039;&#039;&#039; {{new|95.0}} &lt;br /&gt;
    (number projectileID, boolean alwaysVisible) --&amp;gt; nil&lt;br /&gt;
[[category: Lua]]&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=Games&amp;diff=9053</id>
		<title>Games</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=Games&amp;diff=9053"/>
		<updated>2014-05-18T09:24:52Z</updated>

		<summary type="html">&lt;p&gt;Knorke: /* Open Source */ removed ST&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__There are a number of games made for the Spring Engine. Some of the more popular ones are listed below, sorted by their terms of use. &amp;lt;!--(/license schemes?)--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Open Source=&lt;br /&gt;
&#039;&#039;These games are all free to download and play and may be open to modifications, however, be sure to read the licenses before doing so.&#039;&#039;&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; width=&amp;quot;300px&amp;quot; | &amp;lt;h2&amp;gt;[http://zero-k.info/ Zero-K]&amp;lt;/h2&amp;gt;&lt;br /&gt;
([http://code.google.com/p/zero-k/source/browse/trunk/mods/zk/legal.txt GPL, PD])&lt;br /&gt;
| width=40 |&lt;br /&gt;
| align=&amp;quot;center&amp;quot; width=&amp;quot;300px&amp;quot; | &amp;lt;h2&amp;gt;&#039;&#039;&#039;[http://spring1944.org/ Spring: 1944]&#039;&#039;&#039;&amp;lt;/h2&amp;gt;([http://spring1944.svn.sourceforge.net/viewvc/spring1944/trunk/S44Main.sdd/docs/License.txt CC-BY-NC])&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | {{navimgx|xsize=300|ysize=225|image=Zero-k_image.jpg|link=http://zero-k.info/}}&lt;br /&gt;
|&lt;br /&gt;
| align=&amp;quot;center&amp;quot; |{{navimgx|xsize=300|ysize=225|image=S44_tigers.jpg|link=http://spring1944.org}}&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;justify&amp;quot; valign=&amp;quot;top&amp;quot; | Zero-K is a fast, competitive game with a focus on a streamlined economy and advanced interface that takes the focus off tedious tasks and back on the action. A huge roster of interesting, unique units and a variety of unit abilities provides tremendous tactical and strategic depth to the game. [http://zero-k.info Download link]&lt;br /&gt;
|&lt;br /&gt;
| align=&amp;quot;justify&amp;quot; valign=&amp;quot;top&amp;quot; | Spring:1944 is a WWII themed game with four fully functional sides (US, Germany, USSR, Britain), period-accurate units and strengths. Realism comes second only to creating a game that is fun and accessible to play.&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;lt;h2&amp;gt;[http://www.evolutionrts.info Evolution RTS]&amp;lt;/h2&amp;gt;([http://creativecommons.org/licenses/by-nc-nd/3.0/us/ CC-BY-NC-ND])&lt;br /&gt;
| width=40 |&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;lt;h2&amp;gt;[[Kernel Panic]]&amp;lt;/h2&amp;gt;([[Kernel_Panic#License:|FOSS, with only 2 FOSS maps]])&amp;lt;!-- Since you should be able to remove those, I wonâ€™t mark it as non-free. Other maps have non-free license or no license at all.) --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; valign=&amp;quot;top&amp;quot;| {{navimgx|xsize=300|ysize=188|image=Evoimg.jpg|link=http://www.evolutionrts.info}}&lt;br /&gt;
|&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | {{navimg|xsize=300|ysize=225|image=Kernel_Panic_3.4.jpg|link=Kernel Panic}}&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;justify&amp;quot; valign=&amp;quot;top&amp;quot; | A new war is brewing. A violent conflict, between the Six Colonies, each one convinced that it was in the right, each one sure of its own ability to defeat its enemies. But they need Generals. They need soldiers. They need you.&lt;br /&gt;
|&lt;br /&gt;
| align=&amp;quot;justify&amp;quot; valign=&amp;quot;top&amp;quot; | A game based around combat &#039;&#039;&#039;inside&#039;&#039;&#039; a computer, with 3 unique sides: the System, the Hacker and the Network waging war in a matrix of DOOM! No resource economy exists in KP, with the only constraints being time and space.&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;lt;h2&amp;gt;&#039;&#039;&#039;[http://notadota.com/ On The Edge]&#039;&#039;&#039;&amp;lt;/h2&amp;gt;  (GPL, [http://creativecommons.org/licenses/by-nc-sa/3.0/us/ CC-BY-NC-SA])&lt;br /&gt;
|&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;lt;h2&amp;gt;&#039;&#039;&#039;[http://www.moddb.com/games/conflict-terra Conflict Terra]&#039;&#039;&#039;&amp;lt;/h2&amp;gt;([http://code.google.com/p/conflictterra/source/browse/games/CT/License.txt FOSS])&amp;lt;!-- The sounds from EvoRTS were removed, so we&#039;re clean now. --&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; |{{navimgx|xsize=300|ysize=225|image=start3.jpg||link=http://notadota.com}}&lt;br /&gt;
|&lt;br /&gt;
| align=&amp;quot;center&amp;quot; |{{navimgx|xsize=300|ysize=225|image=CT_Hojos.png|link=http://www.moddb.com/games/conflict-terra}}&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;justify&amp;quot; valign=&amp;quot;top&amp;quot; | First Spring MOBA with unique pre-game hero setup. Under heavy development. How to setup working the game read on [http://springrts.com/phpbb/viewtopic.php?f=55&amp;amp;t=31476 On The Edge forum thread]&lt;br /&gt;
|&lt;br /&gt;
| align=&amp;quot;justify&amp;quot; valign=&amp;quot;top&amp;quot; | A unique game with heavy emphasis on mobility and featuring Spring&#039;s first major &amp;quot;collect and drop-off&amp;quot; economy, Conflict Terra boasts a distinctive art style.  Play as one of two factions in an ever-changing battlefield as you struggle to come out on top.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Proprietary=&lt;br /&gt;
&#039;&#039;These games may or may not be free to play. Modifying their content (i.e. the art assets) is not allowed without the game authors explicit permission, although the code is GPL and some games (P.U.R.E.) include large GPL-friendly content collections.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; width=&amp;quot;300px&amp;quot; | &amp;lt;h2&amp;gt;[http://springrts.com/phpbb/viewforum.php?f=46 Star Wars: Imperial Winter]&amp;lt;/h2&amp;gt;&lt;br /&gt;
| width=40 |&lt;br /&gt;
| align=&amp;quot;center&amp;quot; width=&amp;quot;300px&amp;quot; | &amp;lt;h2&amp;gt;[http://www.indiedb.com/games/the-cursed The Cursed]&amp;lt;/h2&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | {{navimgx|xsize=300|ysize=225|image=Imperial Winter assault.jpg|link=http://springrts.com/phpbb/viewforum.php?f=46}}&lt;br /&gt;
|&lt;br /&gt;
| align=&amp;quot;center&amp;quot; |{{navimgx|xsize=300|ysize=225|image=cursed_logo.jpg|link=http://www.indiedb.com/games/the-cursed}}&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;justify&amp;quot; valign=&amp;quot;top&amp;quot; | A Star Wars themed game set in the troubled post-Return of the Jedi era.&lt;br /&gt;
|&lt;br /&gt;
| align=&amp;quot;justify&amp;quot; valign=&amp;quot;top&amp;quot; |  The game is about bones, undead, demons, space marines and magic settled in a futuristic environment. It is a fresh   mixture of gameplay elements from many popular RTS games like Starcraft and C&amp;amp;C.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=TA-derived=&lt;br /&gt;
&#039;&#039;At least parts of these games are derived from data of the  Total Annihilation game (copyright Atari). As such, their distribution is potentially in breach of copyright laws and therefore not officially endorsed by the Spring RTS team.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; width=&amp;quot;300px&amp;quot; | &amp;lt;h2&amp;gt;[http://springrts.com/wiki/Balanced_Annihilation Balanced Annihilation]&amp;lt;/h2&amp;gt;&lt;br /&gt;
| width=40 |&lt;br /&gt;
| align=&amp;quot;center&amp;quot; width=&amp;quot;300px&amp;quot; |  &amp;lt;h2&amp;gt; [http://springfiles.com/spring/games/tech-annihilation-8 Tech Annihilation] &amp;lt;/h2&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | {{navimgx|xsize=300|ysize=225|image=BAScreenShot.jpg|link=http://springrts.com/phpbb/viewforum.php?f=44}}&lt;br /&gt;
|&lt;br /&gt;
| align=&amp;quot;center&amp;quot; |{{navimgx|xsize=300|ysize=200|image=Tech_Annihilation.png|link=http://springfiles.com/spring/games/tech-annihilation-8}}&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;justify&amp;quot; valign=&amp;quot;top&amp;quot; | &lt;br /&gt;
Balanced Annihilation (BA) is a mature game and new versions feature only minor balance tweaks.&lt;br /&gt;
&lt;br /&gt;
BA gameplay develops in stages of progressively heavier units with a growing economy. Many strategies are viable in BA, including focusing on map control, aggression, defense, air power, sea power, or mobility.&lt;br /&gt;
&lt;br /&gt;
|&lt;br /&gt;
| align=&amp;quot;justify&amp;quot; valign=&amp;quot;top&amp;quot; | This Game is bigger, greater and more epic! Tech your Commander from a tiny Commander to a Galactic Commander! (by &#039;&#039;[BoS]Senna&#039;&#039;, currently no homepage)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; width=&amp;quot;300px&amp;quot; | &amp;lt;h2&amp;gt;[http://springfiles.com/spring/games/nota-37 NOTA]&amp;lt;/h2&amp;gt;&lt;br /&gt;
| width=40 |&lt;br /&gt;
| align=&amp;quot;center&amp;quot; width=&amp;quot;300px&amp;quot; | &amp;lt;h2&amp;gt;[[XTA]]&amp;lt;/h2&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; |{{navimgx|xsize=300|ysize=225|image=Nota2nukes.jpg|link=http://springfiles.com/spring/games/nota-37}}&lt;br /&gt;
|&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | {{navimg|xsize=300|ysize=225|image=Screen508_s.jpg|link=XTA}}&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;justify&amp;quot; valign=&amp;quot;top&amp;quot; | Not Original Total Annihilation is a rethink of the Total Annihilation universe with a focus on strategic, base oriented gameplay. With its revised unit scale, huge battles erupt engaging hundreds of units and scores of unit types. NOTA&#039;s completely rethought air and sea gameplay forces participation in all elements and places the tide of conflict in your hands.&lt;br /&gt;
|&lt;br /&gt;
| align=&amp;quot;justify&amp;quot; valign=&amp;quot;top&amp;quot; | Originally developed as a Total Annihilation game by the Swedish Yankspankers, XTA is the Original Public Game released with first versions of Spring. Development of this game by the SYs has stopped a while ago, but it is still played and actively developed by the community.&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Installing Games in Spring=&lt;br /&gt;
Quite a few of the games listed above come with standalone installers, which makes things easy. Check their website to find out! &lt;br /&gt;
&lt;br /&gt;
In some cases however, the game will only distribute a game-file, for example &#039;&#039;BA750&#039;&#039;&#039;&#039;&#039;.sd7&#039;&#039;&#039; or &#039;&#039;XTA&#039;&#039;&#039;&#039;&#039;.sdz&#039;&#039;&#039;. For these games, you have to [[Download|install the stand-alone Spring-Engine]] first, and then place the game-file in the &#039;&#039;...\My Documents\My Games\Spring\Games\&#039;&#039; or &#039;&#039;...\Spring\games\&#039;&#039; folder (&#039;&#039;~/.spring/games/&#039;&#039; on Linux/Unix/Mac).&lt;br /&gt;
You may install multiple games in the same engine installation.&lt;br /&gt;
&lt;br /&gt;
To play a game, you also need a [[Maps|map]].&lt;br /&gt;
&lt;br /&gt;
Still not enough Games? There are [[Getting_Spring_Content_and_Links|some more]], not listed here or make your [[Game_and_Unit_development|own Game]]!&lt;br /&gt;
&lt;br /&gt;
[[Category: Games]]&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=Spring_Tanks&amp;diff=17320</id>
		<title>Spring Tanks</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=Spring_Tanks&amp;diff=17320"/>
		<updated>2014-05-18T05:17:57Z</updated>

		<summary type="html">&lt;p&gt;Knorke: {{deprecated}}&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{deprecated}}&lt;br /&gt;
&lt;br /&gt;
= About =&lt;br /&gt;
&#039;&#039;&#039;Spring Tanks&#039;&#039;&#039; started as an experiment.&lt;br /&gt;
&lt;br /&gt;
[http://springrts.com/media.php?tag=game%3A+Spring+Tanks Some screenshots] can seen be in the media section&lt;br /&gt;
&lt;br /&gt;
{{navimgx|xsize=200|ysize=140|image=Springtanks_TVicon.png|link=http://www.youtube.com/watch?v=xlgV64CEE7Q}}&lt;br /&gt;
[http://www.youtube.com/watch?v=xlgV64CEE7Q &#039;&#039;&#039;Click here for a video!&#039;&#039;&#039;]&lt;br /&gt;
&lt;br /&gt;
You can play it in both Single &amp;amp; Multiplayer. The Singleplayer is not so much fun because the AI is not very good.&lt;br /&gt;
&lt;br /&gt;
The lobbychannel is &#039;&#039;&#039;#springtanks&#039;&#039;&#039;  (type &#039;&#039;/join #springtanks&#039;&#039; into lobby chat)&lt;br /&gt;
&lt;br /&gt;
The forum is [http://springrts.com/phpbb/viewforum.php?f=68 here]&lt;br /&gt;
&lt;br /&gt;
= Gameplay Description =&lt;br /&gt;
Capture the Flag with Tanks. How cool is that?&lt;br /&gt;
[http://h-4.abload.de/img/springtanksctfcomic_jpgtbe.jpg  So cool that there is a comic about it.]&lt;br /&gt;
&lt;br /&gt;
Each player starts with a squad of tanks, a base and two flags.&lt;br /&gt;
&lt;br /&gt;
Outmanouver the enemy and pick up his flags by touching them with a unit and carry them to your base to score.&lt;br /&gt;
Defend your own flags.&lt;br /&gt;
&lt;br /&gt;
The player or team with the highest score after a set timelimit wins.&lt;br /&gt;
&lt;br /&gt;
One could say the gameplay is a strategy game mixed with elements from first person shooters and sports like football.&lt;br /&gt;
&lt;br /&gt;
== Squad System &amp;amp; Wave Respawn ==&lt;br /&gt;
Every 30 seconds all destroyed units are respawned.&lt;br /&gt;
&lt;br /&gt;
The respawn timer is shown as a countdown and progress bar in the top right corner.&lt;br /&gt;
You can not get more units than your initial squad.&lt;br /&gt;
&lt;br /&gt;
= The Units: =&lt;br /&gt;
[[Image:Knorke_Springtanks_startsquadwithnames.pngâ€Ž]]&lt;br /&gt;
&lt;br /&gt;
== Blitz - Car ==&lt;br /&gt;
The Blitz Car is unarmed and &#039;&#039;&#039;fragile&#039;&#039;&#039;.&lt;br /&gt;
With its high &#039;&#039;&#039;speed&#039;&#039;&#039; and good maneuverability it is perfect for sneaky flag capture runs and scouting.&lt;br /&gt;
&lt;br /&gt;
== TakTak - Medium Tank ==&lt;br /&gt;
This unit is the &#039;&#039;&#039;basis of your squad&#039;&#039;&#039;.&lt;br /&gt;
It is armed with an automatic dual cannon that offers a high rate of fire.&lt;br /&gt;
Armor and mobility are average.&lt;br /&gt;
&lt;br /&gt;
== Thulsa - Heavy Tank ==&lt;br /&gt;
A very cumbersome unit.&lt;br /&gt;
With the &#039;&#039;&#039;large cannon and heavy armor&#039;&#039;&#039; this tank dominates the battlefield.&lt;br /&gt;
Downside are the low speed and slow turret rotation.&lt;br /&gt;
One hit destroys a Blitz Car - if the Thulsa can catch it.&lt;br /&gt;
&lt;br /&gt;
== Flag ==&lt;br /&gt;
Drive near an enemy flag to &#039;&#039;&#039;pick it up&#039;&#039;&#039; then bring it to your Base to score a point.&lt;br /&gt;
If the flag carrier is destroyed, the flag falls to the ground. &lt;br /&gt;
There it can be picked up again or the flag owner can touch it to return it to his base.&lt;br /&gt;
Protect your flags!&lt;br /&gt;
Flags are indestructible.&lt;br /&gt;
&lt;br /&gt;
== Base ==&lt;br /&gt;
The base is a &#039;&#039;&#039;respawn point&#039;&#039;&#039; for destroyed units and flags.&lt;br /&gt;
You also have to bring enemy flags here to score a point.&lt;br /&gt;
The Base is indestructible.&lt;br /&gt;
&lt;br /&gt;
=The Maps=&lt;br /&gt;
Only the the listed maps are playable with Spring Tanks.&lt;br /&gt;
On other maps no units will be spawned at gamestart.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Desert Cliffs&#039;&#039;&#039; - 1v1&amp;lt;br&amp;gt;&lt;br /&gt;
http://springfiles.com/spring/spring-maps/desertcliffsv1&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Aquatic Divide&#039;&#039;&#039; - 1v1&amp;lt;br&amp;gt;&lt;br /&gt;
http://springfiles.com/spring/spring-maps/aquaticdividetnm05-v2&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Eye_Of_Horus_v2&#039;&#039;&#039; - 1v1, 3ffa, 4ffa, 2v2&amp;lt;br&amp;gt;&lt;br /&gt;
http://springfiles.com/spring/spring-maps/eye-horus-v2&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Saltrock Colony&#039;&#039;&#039; - 1v1, 3ffa&amp;lt;br&amp;gt;&lt;br /&gt;
http://springfiles.com/spring/spring-maps/saltrockcolonyv2&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Canyon Crossing&#039;&#039;&#039; - 1v1, 3ffa, 4ffa, 2v2&amp;lt;br&amp;gt;&lt;br /&gt;
http://springfiles.com/spring/spring-maps/canyon-crossing&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Into Battle&#039;&#039;&#039; - 1v1&amp;lt;br&amp;gt;&lt;br /&gt;
http://springfiles.com/spring/spring-maps/battle-v3&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Castles&#039;&#039;&#039; - 1v1, 3ffa, 4ffa, 2v2&amp;lt;br&amp;gt;&lt;br /&gt;
http://springfiles.com/spring/spring-maps/castles&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Mount Dustmore v3&#039;&#039;&#039; - 1v1, 3ffa, 4ffa, 2v2&amp;lt;br&amp;gt;&lt;br /&gt;
http://springfiles.com/spring/spring-maps/mountdustmorev3&lt;br /&gt;
&lt;br /&gt;
= Basic Gameplay Tips =&lt;br /&gt;
*Pay attention to the respawn timer:&lt;br /&gt;
If there are only few seconds left and you rush for the flag, chances are enemy units will respawn near you and destroy your flag carrier.&lt;br /&gt;
Sometimes it is better to wait until the enemy has left his respawn area and then go for an easy flag grab.&lt;br /&gt;
**Similiar, the timer can help you decide if you need to retreat to protect your flag or if the respawning reinforcements will clear the situation.&lt;br /&gt;
*When you play with the &amp;quot;place start position ingame&amp;quot; option, chose carefully.&lt;br /&gt;
**If your units respawn all the time in craters or in trees, you only got yourself to blame. So chose a spot with flat land, clear of obstacles.&lt;br /&gt;
**If a unit still gets stuck, you can selfdestruct it: select unit and press crtl+d to make it respawn in the next wave.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Battle Tactics =&lt;br /&gt;
*Thulsa Tanks have splash damage and kill a TakTak with 2 hits, only 1 hit is needed for a Blitz Car.&lt;br /&gt;
*A slowly retreating Thulsa Tank can kill a large number of TakTaks that attack in a line.&lt;br /&gt;
*If you need to kill a Thulsa with TakTaks, swarm it and do not get picked off one by one.&lt;br /&gt;
*Lure the enemy away from his base so that you can go for the flag with Blitz Cars from the flank or from the back.&lt;br /&gt;
*Pay attention to your attention: If a battle is lost and no advantage can be gained, do no bother with it.&lt;br /&gt;
Instead concentrate on the units that can make a difference.&lt;br /&gt;
&lt;br /&gt;
= Advice for Hosting =&lt;br /&gt;
*The modoption &amp;quot;gametimelimit&amp;quot; decides how long a game lasts. You can select from 1 to 90 minutes.&lt;br /&gt;
&lt;br /&gt;
*To spawn your own autohost, write this in private to a springie bot:&lt;br /&gt;
  !spawn mod=springtanks:stable,title=awesome game!,password=&lt;br /&gt;
&lt;br /&gt;
= Playing vs Single Player AI =&lt;br /&gt;
Spring Tanks has a build in Single Player menu.&amp;lt;br&amp;gt;&lt;br /&gt;
To open it:&amp;lt;br&amp;gt;&lt;br /&gt;
1) Start Spring.exe, select &lt;br /&gt;
*Mod: Spring Tanks &lt;br /&gt;
*Map: does not matter (smaller=loads faster but w/e)&lt;br /&gt;
&lt;br /&gt;
2) Click &amp;quot;Test the game&amp;quot;&lt;br /&gt;
&lt;br /&gt;
3) Now the Spring Tanks Single Player Menu should come up. &lt;br /&gt;
&lt;br /&gt;
4) Select one of the challenges and click &amp;quot;Start Game&amp;quot;&lt;br /&gt;
&lt;br /&gt;
5) Spring restarts and you can play!&lt;br /&gt;
&lt;br /&gt;
6) Can you find the easter egg after winning 3 challenges?&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;=&amp;gt;&#039;&#039;&#039; You can go back to the menu by pressing ESC.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Single Player by hosting a battle in a lobby:&#039;&#039;&#039;&lt;br /&gt;
*Dont. Try the pre setup matchups first.&lt;br /&gt;
*The only AI that knows how to play Spring Tanks is the &amp;quot;Borked Advancer&amp;quot; AI.&lt;br /&gt;
*Pay attention to what [http://springrts.com/wiki/Spring_Tanks#The_Maps maps] work.&lt;br /&gt;
&lt;br /&gt;
= Get the game =&lt;br /&gt;
Easiest way is to to join the Spring Tanks autohost with your existing spring engine install and whatever lobby you chose to use. The lobby will then download the game file.&lt;br /&gt;
==Manual download==&lt;br /&gt;
First of, the [http://springrts.com/wiki/Download Spring engine] must already be installed.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Game file:&#039;&#039;&#039; http://packages.springrts.com/builds/springtanks-RC6.1.sdz&lt;br /&gt;
&lt;br /&gt;
If you know how to use [http://springrts.com/wiki/Dev:LobbyDownloadSystems#Rapid rapid], the rapid tag is: &#039;&#039;&#039;springtanks:stable&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Mappack:&#039;&#039;&#039; [http://knorke.darkstars.co.uk/springtanks/SpringTanks_mappack2_unzip_to_mapfolder.zip download]&lt;br /&gt;
&lt;br /&gt;
Absolutely needed for single player!&lt;br /&gt;
&lt;br /&gt;
= Hotkeys =&lt;br /&gt;
hotkeys specific to Spring Tanks:&lt;br /&gt;
  v		select units carrying a flag&lt;br /&gt;
  b		send unit to home base&lt;br /&gt;
  esc		single player only: open/close the Spring Tanks single player menu&lt;br /&gt;
Usefull default hotkeys, regular Spring players will not need to read this.&lt;br /&gt;
Most important are:&lt;br /&gt;
  return/enter	chat&lt;br /&gt;
  tab		toggle complete map view (zooms out to show complete map)&lt;br /&gt;
  s		stop. selected unit stops shoting and moving.&lt;br /&gt;
  shift+clicking	make waypoints&lt;br /&gt;
  f		fight: while traveling to destination, unit will engage all enemies on its path&lt;br /&gt;
  a		attack / shot ground&lt;br /&gt;
  crtl+d		blew up selected unit (ie if stuck)&lt;br /&gt;
  c		cockpit view: controll the unit in (buggy) first person mode&lt;br /&gt;
  ctrl+z		select all units of the same type as current selection&lt;br /&gt;
  p		patrol. set up waypoints for a patrol route that the unit will circle on&lt;br /&gt;
  shif+esc	bring up exit menu&lt;br /&gt;
  F6		sound on/off&lt;br /&gt;
  pause		pause the game. its the key next to print &amp;amp; scroll lock.&lt;br /&gt;
&lt;br /&gt;
= Trouble? =&lt;br /&gt;
Such a little troublemaker!&lt;br /&gt;
&lt;br /&gt;
low fps? lol. should not use more cpu/gpu than any other spring game.&lt;br /&gt;
&lt;br /&gt;
If there is a ~1 seconde stutter at game start, that is because of the texture being loaded. Cant do much about it.&lt;br /&gt;
&lt;br /&gt;
If the game game crashes when starting a new game in Single Player, make sure you have the map. (next version will have a check)&lt;br /&gt;
&lt;br /&gt;
Some usefull commands to be entered in chat:&lt;br /&gt;
  /advshading 0	no reflections on units. can give large fps boost&lt;br /&gt;
  /advshading 1	turn reflections on units on&lt;br /&gt;
  /shadows 0	no shadows&lt;br /&gt;
  /shadows 1	full shadows&lt;br /&gt;
  /shadows 2	only shadows from units, no terrain shadows&lt;br /&gt;
  /water 0	most basic water graphics&lt;br /&gt;
&lt;br /&gt;
==Can&#039;t Fix==&lt;br /&gt;
Starting new games with Single player menu does not work on Mac OS.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= TL;DR =&lt;br /&gt;
Tanks. Capture The Flag. Get the map pack. glhf.&lt;br /&gt;
&lt;br /&gt;
Single Player: Read &#039;&#039;Playing vs AI&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=Credits &amp;amp; Making Of=&lt;br /&gt;
Credits: http://www.pastebin.com/Wpub9wWw&lt;br /&gt;
&lt;br /&gt;
==Used tools==&lt;br /&gt;
Wings 3D, notepad++, [[Upspring]], Irfanview, MS Paint, Audiacity, Fraps, Windows Movie Maker, 7zip, DXTbmp, VirtualDub&lt;br /&gt;
&lt;br /&gt;
=Status=&lt;br /&gt;
playing: &amp;lt;del&amp;gt;completly playable on latest stable engine version: 0.82.7.1&amp;lt;/del&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;del&amp;gt;needs fixing to work with newest Spring release 84.0 (will eventually be done)&amp;lt;del&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
development: {{forumlink|thread=26937|title=see forum:}} and http://springrts.com/mantis/view.php?id=4329&lt;br /&gt;
&lt;br /&gt;
paused due to other things being more interessting.&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=Animation-LuaCallouts&amp;diff=2044</id>
		<title>Animation-LuaCallouts</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=Animation-LuaCallouts&amp;diff=2044"/>
		<updated>2014-05-03T20:53:20Z</updated>

		<summary type="html">&lt;p&gt;Knorke: /* Localized functions for less typing */ some&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The new callouts are defined in the Spring.UnitScript table.&lt;br /&gt;
&lt;br /&gt;
Types for arguments are only shown where they&#039;re ambiguous. For a number of (common) arguments, the types are:&lt;br /&gt;
&lt;br /&gt;
* unitID: number&lt;br /&gt;
* piece: number&lt;br /&gt;
* axis: number (1 = x axis, 2 = y axis, 3 = z axis)&lt;br /&gt;
* destination: number ([[elmo]]s (linear), [[radian]]s (angular))&lt;br /&gt;
* speed: number ([[elmo]]s per second (linear), [[radian]]s per second (angular))&lt;br /&gt;
* accel/decel: number ([[radian]]s per second per frame)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Animation ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.SetPieceVisibility&#039;&#039;&#039; ( piece, boolean visible ) -&amp;gt; nil&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.Show&#039;&#039;&#039; ( piece ) -&amp;gt; nil&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.Hide&#039;&#039;&#039; ( piece ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
These may be used to show/hide pieces of the unit&#039;s model.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.Move&#039;&#039;&#039; ( piece, axis, destination[, speed][, updateMatrix]] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
Move piece along axis to the destination position. If speed is given, the piece isn&#039;t moved immediately, but will move there at the desired speed. The X axis is mirrored compared to BOS/COB scripts, to match the direction of the X axis in Spring world space. The 5th param was introduced in 95.0 and instantly updates the piece position matrix (rather than waiting for the next frame).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.Turn&#039;&#039;&#039; ( piece, axis, destination[, speed][, updateMatrix]] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
Turn piece around axis to the destination angle. If speed is given, the piece isn&#039;t rotated immediately, but will turn at the desired angular velocity. Angles are in radians.&lt;br /&gt;
Always uses the shortest angular towards destination degree, and if at exactly 180 degrees opposite, will go counter-clockwise. The 5th param was introduced in 95.0 and instantly updates the piece rotation matrix (rather than waiting for the next frame).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.Spin&#039;&#039;&#039; ( piece, axis, speed[, accel] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
Makes piece spin around axis at the desired angular velocity. If accel is given, the piece does not start at this velocity at once, but will accelerate to it. Both negative and positive angular velocities are supported. Accel should always be positive, even if speed is negative.&lt;br /&gt;
&lt;br /&gt;
Beware gimbal lock: http://en.wikipedia.org/wiki/Gimbal_lock&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.StopSpin&#039;&#039;&#039; ( piece, axis[, decel] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
Stops a piece from spinning around the given axis. If decel is given, the piece does not stop at once, but will decelerate to it. Decel should always be positive. This function is similar to Spin(piece, axis, 0, decel), however, StopSpin also frees up the animation record.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.IsInTurn&#039;&#039;&#039; (number piece, number axis) -&amp;gt; boolean&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.IsInMove&#039;&#039;&#039; (number piece, number axis) -&amp;gt; boolean&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.IsInSpin&#039;&#039;&#039; (number piece, number axis) -&amp;gt; boolean&lt;br /&gt;
&lt;br /&gt;
Returns true if such an animation exists, false otherwise.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.GetPieceTranslation&#039;&#039;&#039; ( piece ) -&amp;gt; number x, y, z&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.GetPieceRotation&#039;&#039;&#039; ( piece ) -&amp;gt; number x, y, z&lt;br /&gt;
&lt;br /&gt;
Get the current translation/rotation of a piece. The returned numbers match the values passed into Move and Turn.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.GetPiecePosDir&#039;&#039;&#039; ( piece ) -&amp;gt; number px, py, pz, dx, dy, dz&lt;br /&gt;
&lt;br /&gt;
Get the piece&#039;s position (px, py, pz) and direction (dx, dy, dz) in &#039;&#039;&#039;unit space&#039;&#039;&#039;. This is quite similar to &#039;&#039;Spring.GetUnitPiecePosDir&#039;&#039;, however that function returns in &#039;&#039;&#039;world space&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Threads ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.StartThread&#039;&#039;&#039; ( function fun, ... ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
Starts a new (animation) thread, which will execute the function &#039;fun&#039;. All arguments except the function to run are passed as-is as arguments to &#039;fun&#039;. [[Animation-CobThreads|COB-Threads]] has a decent description on COB threads, which are mimicked here in Lua using coroutines.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.SetSignalMask&#039;&#039;&#039; ( number mask ) -&amp;gt; nil&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.Signal&#039;&#039;&#039; ( number signal ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
These two support functions offer a powerful way to kill running threads. SetSignalMask assigns a mask to the currently running thread (any new threads started by this one will inherit the signal mask). Signal immediately stops all threads of this unit for which the bitwise and of mask and signal is not zero.&lt;br /&gt;
&lt;br /&gt;
[http://springrts.com/phpbb/viewtopic.php?f=14&amp;amp;t=26274&amp;amp;start=2| What signal will stop which threads?]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.WaitForMove&#039;&#039;&#039; ( piece, axis ) -&amp;gt; nil&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.WaitForTurn&#039;&#039;&#039; ( piece, axis ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
Waits until the piece has stopped moving along / turning around the axis. If the piece is not animating, this functions return at once. You can not wait for a spin, because a spin does never finish.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.Sleep&#039;&#039;&#039; ( number milliseconds ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
Waits a number of milliseconds before returning.&lt;br /&gt;
&lt;br /&gt;
== Effects ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.EmitSfx&#039;&#039;&#039; ( piece, number id ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
Emits a [[CEG]] effect or weapon from the given piece. The id is based on one of the effect or weapon ids defined in the units unitdef.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the piece has no geometry, then the sfx is emitted in the +z direction from the origin of the piece.&lt;br /&gt;
&lt;br /&gt;
If the piece has 1 vertex, the emit dir is the vector from the origin to the the position of the first vertex the emit position is the origin of the piece.&lt;br /&gt;
&lt;br /&gt;
If there is more than one vertex in the piece, then the emit vector is the vector pointing from v[0] to v[1], and the emit position is v[0].&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
--get the id of the CEG effects:&lt;br /&gt;
local smokecloud = SFX.CEG   --the first effect from the list in the unitdef&lt;br /&gt;
local smokecloud2 = SFX.CEG +1   --the second effect from the list in the unitdef&lt;br /&gt;
local fire = SFX.CEG +2   --the third effect from the list in the unitdef&lt;br /&gt;
--get the id of the emiter piece:&lt;br /&gt;
local turret = piece &amp;quot;turret&amp;quot;&lt;br /&gt;
EmitSfx(turret, smokecloud)   --emit the first effect&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.ShowFlare&#039;&#039;&#039; ( number piece ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
Same as COB&#039;s show _inside_ FireWeaponX.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.Explode&#039;&#039;&#039; ( piece, number flags ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
Explodes a piece, optionally creating a particle which flies off. Typically used inside Killed. Explode does not hide the piece by itself; if using it outside Killed you may want to Hide the piece immediately after. The flags may be any combination of:&lt;br /&gt;
* &#039;&#039;&#039;SFX.NONE&#039;&#039;&#039;: do nothing after creating a heatcloud. Other flags have no effect, except NO_HEATCLOUD. If that is given too, the call is a no-op.&lt;br /&gt;
* &#039;&#039;&#039;SFX.SHATTER&#039;&#039;&#039;: shatter the piece in many fragments. Only the NO_HEATCLOUD flag has any effect if this is present.&lt;br /&gt;
* &#039;&#039;&#039;SFX.EXPLODE&#039;&#039;&#039; | &#039;&#039;&#039;SFX.EXPLODE_ON_HIT&#039;&#039;&#039;: the piece that flies of should explode when it hits something.&lt;br /&gt;
* &#039;&#039;&#039;SFX.FALL&#039;&#039;&#039;: the piece should be affected by gravity (this is currently always forced on by Spring, to prevent pieces that float in air indefinitely).&lt;br /&gt;
* &#039;&#039;&#039;SFX.SMOKE&#039;&#039;&#039;: leave smoke trail.&lt;br /&gt;
* &#039;&#039;&#039;SFX.FIRE&#039;&#039;&#039;: the piece is on fire when it flies off.&lt;br /&gt;
* &#039;&#039;&#039;SFX.NO_CEG_TRAIL&#039;&#039;&#039;: disable a CEG trail, if present.&lt;br /&gt;
* &#039;&#039;&#039;SFX.NO_HEATCLOUD&#039;&#039;&#039;: suppress the heat cloud that&#039;s shown by default.&lt;br /&gt;
&lt;br /&gt;
== Other ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.AttachUnit&#039;&#039;&#039; ( piece, passengerID ) -&amp;gt; nil&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.DropUnit&#039;&#039;&#039; ( passengerID ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
Attaches or detaches another unit (a passenger, as this is designed for transports) to this unit. For AttachUnit, piece specifies the attachment point. Attaching to piece &amp;lt;code&amp;gt;-1&amp;lt;/code&amp;gt; makes the passenger unit enter a void state whereby it will never:&lt;br /&gt;
     &lt;br /&gt;
# take damage, even from Lua (but can be killed by Lua)&lt;br /&gt;
# be rendered through any engine path (nor their icons)&lt;br /&gt;
# be intersect-able by either synced or unsynced rays&lt;br /&gt;
# block any other objects from existing on top of them&lt;br /&gt;
# be selectable&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.GetUnitValue&#039;&#039;&#039; ( ... ) -&amp;gt; number | number, number&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.SetUnitValue&#039;&#039;&#039; ( ... ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
This may be used instead of COB&#039;s get and set codes. It is recommended however, to use dedicated Lua functions (e.g. Spring.GetUnitHealth(unitID) instead of GetUnitValue(4)): these functions should be considered a relic of the past.&lt;br /&gt;
&lt;br /&gt;
Note that these are identical to Spring.GetUnitCOBValue and Spring.SetUnitCOBValue (see also [[Lua_SyncedCtrl#Lua_to_COB]] for the signature of those functions), except that an unitID argument shouldn&#039;t be passed to the versions in the Spring.UnitScript table.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.GetLongestReloadTime&#039;&#039;&#039; ( unitID ) -&amp;gt; number reloadTime&lt;br /&gt;
&lt;br /&gt;
Returns max(reload time) of all the unit&#039;s weapons in milliseconds. This utility function exists to aid in porting BOS scripts, which have a SetMaxReloadTime call-in that is called immediately after Create.&lt;br /&gt;
&lt;br /&gt;
== Internal ==&lt;br /&gt;
&lt;br /&gt;
You generally shouldn&#039;t need any of the following call-outs, they are provided by the engine to allow the Lua framework to do it&#039;s work.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.CreateScript&#039;&#039;&#039; ( unitID, table callIns ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
This deletes the unit&#039;s current script (whether it&#039;s a COB or Lua script doesn&#039;t matter), and sets it up with a brand new Lua unit script, initially registering the call-ins given in the table as (string, function) pairs.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.UpdateCallIn&#039;&#039;&#039; ( unitID, string name[, function callIn] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
This updates a single call-in for the unit&#039;s current &#039;&#039;&#039;Lua&#039;&#039;&#039; unit script. If the unit does not currently have a Lua unit script, an error is raised. If the callIn argument is not given (or nil), the call-in with the given name is removed.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.CallAsUnit&#039;&#039;&#039; ( unitID, function fun, ... ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
As none of the call-outs takes a unitID, the engine needs to know the &#039;&#039;active unit&#039;&#039; when one of those is called. Using this function another function can be called with the active unit set arbitrarily.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.SetDeathScriptFinished&#039;&#039;&#039; ( [number wreckLevel] )&lt;br /&gt;
&lt;br /&gt;
Tells Spring the Killed script finished, and which wreckLevel to use. If wreckLevel is not given no wreck is created. May only be called after Killed has been called. DO NOT USE, the framework handles this transparently (it passes the return value of Killed into this function.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Localized functions for less typing ==&lt;br /&gt;
In unitscript enviroment some of the &#039;&#039;&#039;Spring.UnitScript.xxxxx()&#039;&#039;&#039; functions are already localized.&lt;br /&gt;
So unless doing anything special, you can save type:&lt;br /&gt;
  Show (piece)&lt;br /&gt;
instead of the longer:&lt;br /&gt;
  Spring.UnitScript.Show (piece)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Animation]]&lt;br /&gt;
[[Category:Lua]]&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=Animation-LuaCallouts&amp;diff=2043</id>
		<title>Animation-LuaCallouts</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=Animation-LuaCallouts&amp;diff=2043"/>
		<updated>2014-05-01T07:32:38Z</updated>

		<summary type="html">&lt;p&gt;Knorke: Localized functions for less typing&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The new callouts are defined in the Spring.UnitScript table.&lt;br /&gt;
&lt;br /&gt;
Types for arguments are only shown where they&#039;re ambiguous. For a number of (common) arguments, the types are:&lt;br /&gt;
&lt;br /&gt;
* unitID: number&lt;br /&gt;
* piece: number&lt;br /&gt;
* axis: number (1 = x axis, 2 = y axis, 3 = z axis)&lt;br /&gt;
* destination: number ([[elmo]]s (linear), [[radian]]s (angular))&lt;br /&gt;
* speed: number ([[elmo]]s per second (linear), [[radian]]s per second (angular))&lt;br /&gt;
* accel/decel: number ([[radian]]s per second per frame)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Animation ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.SetPieceVisibility&#039;&#039;&#039; ( piece, boolean visible ) -&amp;gt; nil&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.Show&#039;&#039;&#039; ( piece ) -&amp;gt; nil&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.Hide&#039;&#039;&#039; ( piece ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
These may be used to show/hide pieces of the unit&#039;s model.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.Move&#039;&#039;&#039; ( piece, axis, destination[, speed][, updateMatrix]] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
Move piece along axis to the destination position. If speed is given, the piece isn&#039;t moved immediately, but will move there at the desired speed. The X axis is mirrored compared to BOS/COB scripts, to match the direction of the X axis in Spring world space. The 5th param was introduced in 95.0 and instantly updates the piece position matrix (rather than waiting for the next frame).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.Turn&#039;&#039;&#039; ( piece, axis, destination[, speed][, updateMatrix]] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
Turn piece around axis to the destination angle. If speed is given, the piece isn&#039;t rotated immediately, but will turn at the desired angular velocity. Angles are in radians.&lt;br /&gt;
Always uses the shortest angular towards destination degree, and if at exactly 180 degrees opposite, will go counter-clockwise. The 5th param was introduced in 95.0 and instantly updates the piece rotation matrix (rather than waiting for the next frame).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.Spin&#039;&#039;&#039; ( piece, axis, speed[, accel] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
Makes piece spin around axis at the desired angular velocity. If accel is given, the piece does not start at this velocity at once, but will accelerate to it. Both negative and positive angular velocities are supported. Accel should always be positive, even if speed is negative.&lt;br /&gt;
&lt;br /&gt;
Beware gimbal lock: http://en.wikipedia.org/wiki/Gimbal_lock&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.StopSpin&#039;&#039;&#039; ( piece, axis[, decel] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
Stops a piece from spinning around the given axis. If decel is given, the piece does not stop at once, but will decelerate to it. Decel should always be positive. This function is similar to Spin(piece, axis, 0, decel), however, StopSpin also frees up the animation record.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.IsInTurn&#039;&#039;&#039; (number piece, number axis) -&amp;gt; boolean&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.IsInMove&#039;&#039;&#039; (number piece, number axis) -&amp;gt; boolean&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.IsInSpin&#039;&#039;&#039; (number piece, number axis) -&amp;gt; boolean&lt;br /&gt;
&lt;br /&gt;
Returns true if such an animation exists, false otherwise.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.GetPieceTranslation&#039;&#039;&#039; ( piece ) -&amp;gt; number x, y, z&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.GetPieceRotation&#039;&#039;&#039; ( piece ) -&amp;gt; number x, y, z&lt;br /&gt;
&lt;br /&gt;
Get the current translation/rotation of a piece. The returned numbers match the values passed into Move and Turn.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.GetPiecePosDir&#039;&#039;&#039; ( piece ) -&amp;gt; number px, py, pz, dx, dy, dz&lt;br /&gt;
&lt;br /&gt;
Get the piece&#039;s position (px, py, pz) and direction (dx, dy, dz) in &#039;&#039;&#039;unit space&#039;&#039;&#039;. This is quite similar to &#039;&#039;Spring.GetUnitPiecePosDir&#039;&#039;, however that function returns in &#039;&#039;&#039;world space&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Threads ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.StartThread&#039;&#039;&#039; ( function fun, ... ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
Starts a new (animation) thread, which will execute the function &#039;fun&#039;. All arguments except the function to run are passed as-is as arguments to &#039;fun&#039;. [[Animation-CobThreads|COB-Threads]] has a decent description on COB threads, which are mimicked here in Lua using coroutines.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.SetSignalMask&#039;&#039;&#039; ( number mask ) -&amp;gt; nil&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.Signal&#039;&#039;&#039; ( number signal ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
These two support functions offer a powerful way to kill running threads. SetSignalMask assigns a mask to the currently running thread (any new threads started by this one will inherit the signal mask). Signal immediately stops all threads of this unit for which the bitwise and of mask and signal is not zero.&lt;br /&gt;
&lt;br /&gt;
[http://springrts.com/phpbb/viewtopic.php?f=14&amp;amp;t=26274&amp;amp;start=2| What signal will stop which threads?]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.WaitForMove&#039;&#039;&#039; ( piece, axis ) -&amp;gt; nil&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.WaitForTurn&#039;&#039;&#039; ( piece, axis ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
Waits until the piece has stopped moving along / turning around the axis. If the piece is not animating, this functions return at once. You can not wait for a spin, because a spin does never finish.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.Sleep&#039;&#039;&#039; ( number milliseconds ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
Waits a number of milliseconds before returning.&lt;br /&gt;
&lt;br /&gt;
== Effects ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.EmitSfx&#039;&#039;&#039; ( piece, number id ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
Emits a [[CEG]] effect or weapon from the given piece. The id is based on one of the effect or weapon ids defined in the units unitdef.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the piece has no geometry, then the sfx is emitted in the +z direction from the origin of the piece.&lt;br /&gt;
&lt;br /&gt;
If the piece has 1 vertex, the emit dir is the vector from the origin to the the position of the first vertex the emit position is the origin of the piece.&lt;br /&gt;
&lt;br /&gt;
If there is more than one vertex in the piece, then the emit vector is the vector pointing from v[0] to v[1], and the emit position is v[0].&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
--get the id of the CEG effects:&lt;br /&gt;
local smokecloud = SFX.CEG   --the first effect from the list in the unitdef&lt;br /&gt;
local smokecloud2 = SFX.CEG +1   --the second effect from the list in the unitdef&lt;br /&gt;
local fire = SFX.CEG +2   --the third effect from the list in the unitdef&lt;br /&gt;
--get the id of the emiter piece:&lt;br /&gt;
local turret = piece &amp;quot;turret&amp;quot;&lt;br /&gt;
EmitSfx(turret, smokecloud)   --emit the first effect&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.ShowFlare&#039;&#039;&#039; ( number piece ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
Same as COB&#039;s show _inside_ FireWeaponX.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.Explode&#039;&#039;&#039; ( piece, number flags ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
Explodes a piece, optionally creating a particle which flies off. Typically used inside Killed. Explode does not hide the piece by itself; if using it outside Killed you may want to Hide the piece immediately after. The flags may be any combination of:&lt;br /&gt;
* &#039;&#039;&#039;SFX.NONE&#039;&#039;&#039;: do nothing after creating a heatcloud. Other flags have no effect, except NO_HEATCLOUD. If that is given too, the call is a no-op.&lt;br /&gt;
* &#039;&#039;&#039;SFX.SHATTER&#039;&#039;&#039;: shatter the piece in many fragments. Only the NO_HEATCLOUD flag has any effect if this is present.&lt;br /&gt;
* &#039;&#039;&#039;SFX.EXPLODE&#039;&#039;&#039; | &#039;&#039;&#039;SFX.EXPLODE_ON_HIT&#039;&#039;&#039;: the piece that flies of should explode when it hits something.&lt;br /&gt;
* &#039;&#039;&#039;SFX.FALL&#039;&#039;&#039;: the piece should be affected by gravity (this is currently always forced on by Spring, to prevent pieces that float in air indefinitely).&lt;br /&gt;
* &#039;&#039;&#039;SFX.SMOKE&#039;&#039;&#039;: leave smoke trail.&lt;br /&gt;
* &#039;&#039;&#039;SFX.FIRE&#039;&#039;&#039;: the piece is on fire when it flies off.&lt;br /&gt;
* &#039;&#039;&#039;SFX.NO_CEG_TRAIL&#039;&#039;&#039;: disable a CEG trail, if present.&lt;br /&gt;
* &#039;&#039;&#039;SFX.NO_HEATCLOUD&#039;&#039;&#039;: suppress the heat cloud that&#039;s shown by default.&lt;br /&gt;
&lt;br /&gt;
== Other ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.AttachUnit&#039;&#039;&#039; ( piece, passengerID ) -&amp;gt; nil&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.DropUnit&#039;&#039;&#039; ( passengerID ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
Attaches or detaches another unit (a passenger, as this is designed for transports) to this unit. For AttachUnit, piece specifies the attachment point. Attaching to piece &amp;lt;code&amp;gt;-1&amp;lt;/code&amp;gt; makes the passenger unit enter a void state whereby it will never:&lt;br /&gt;
     &lt;br /&gt;
# take damage, even from Lua (but can be killed by Lua)&lt;br /&gt;
# be rendered through any engine path (nor their icons)&lt;br /&gt;
# be intersect-able by either synced or unsynced rays&lt;br /&gt;
# block any other objects from existing on top of them&lt;br /&gt;
# be selectable&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.GetUnitValue&#039;&#039;&#039; ( ... ) -&amp;gt; number | number, number&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.SetUnitValue&#039;&#039;&#039; ( ... ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
This may be used instead of COB&#039;s get and set codes. It is recommended however, to use dedicated Lua functions (e.g. Spring.GetUnitHealth(unitID) instead of GetUnitValue(4)): these functions should be considered a relic of the past.&lt;br /&gt;
&lt;br /&gt;
Note that these are identical to Spring.GetUnitCOBValue and Spring.SetUnitCOBValue (see also [[Lua_SyncedCtrl#Lua_to_COB]] for the signature of those functions), except that an unitID argument shouldn&#039;t be passed to the versions in the Spring.UnitScript table.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.GetLongestReloadTime&#039;&#039;&#039; ( unitID ) -&amp;gt; number reloadTime&lt;br /&gt;
&lt;br /&gt;
Returns max(reload time) of all the unit&#039;s weapons in milliseconds. This utility function exists to aid in porting BOS scripts, which have a SetMaxReloadTime call-in that is called immediately after Create.&lt;br /&gt;
&lt;br /&gt;
== Internal ==&lt;br /&gt;
&lt;br /&gt;
You generally shouldn&#039;t need any of the following call-outs, they are provided by the engine to allow the Lua framework to do it&#039;s work.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.CreateScript&#039;&#039;&#039; ( unitID, table callIns ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
This deletes the unit&#039;s current script (whether it&#039;s a COB or Lua script doesn&#039;t matter), and sets it up with a brand new Lua unit script, initially registering the call-ins given in the table as (string, function) pairs.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.UpdateCallIn&#039;&#039;&#039; ( unitID, string name[, function callIn] ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
This updates a single call-in for the unit&#039;s current &#039;&#039;&#039;Lua&#039;&#039;&#039; unit script. If the unit does not currently have a Lua unit script, an error is raised. If the callIn argument is not given (or nil), the call-in with the given name is removed.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.CallAsUnit&#039;&#039;&#039; ( unitID, function fun, ... ) -&amp;gt; nil&lt;br /&gt;
&lt;br /&gt;
As none of the call-outs takes a unitID, the engine needs to know the &#039;&#039;active unit&#039;&#039; when one of those is called. Using this function another function can be called with the active unit set arbitrarily.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spring.UnitScript.SetDeathScriptFinished&#039;&#039;&#039; ( [number wreckLevel] )&lt;br /&gt;
&lt;br /&gt;
Tells Spring the Killed script finished, and which wreckLevel to use. If wreckLevel is not given no wreck is created. May only be called after Killed has been called. DO NOT USE, the framework handles this transparently (it passes the return value of Killed into this function.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Localized functions for less typing ==&lt;br /&gt;
In unitscript enviroment the &#039;&#039;&#039;Spring.UnitScript.xxxxx()&#039;&#039;&#039; functions are already localized.&lt;br /&gt;
So unless doing anything special, you can save type:&lt;br /&gt;
  Show (piece)&lt;br /&gt;
instead of the longer:&lt;br /&gt;
  Spring.UnitScript.Show (piece)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Animation]]&lt;br /&gt;
[[Category:Lua]]&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=Gamedev:Main&amp;diff=8281</id>
		<title>Gamedev:Main</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=Gamedev:Main&amp;diff=8281"/>
		<updated>2014-04-29T23:23:45Z</updated>

		<summary type="html">&lt;p&gt;Knorke: /* Engine Related */ add links: EngineChangelogForContentDevs and EngineSource_for_GameDevs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Engine_Development|Development]] &amp;lt; {{FULLPAGENAME}}&lt;br /&gt;
&lt;br /&gt;
= Game Development =&lt;br /&gt;
This information is meant to help newcomers learn how to develop their own games for the Spring Engine. If you are interested in creating maps for Spring, see [[Mapdev:Main]].&lt;br /&gt;
&lt;br /&gt;
= Templates &amp;amp; Examples =&lt;br /&gt;
* [[Gamedev:SpringABC|SpringABC]] - A hierarchical set of empty template games, without examples&lt;br /&gt;
* [[SpringTutorialGame|Spring Tutorial Game]] - A tutorial template game with full examples&lt;br /&gt;
* [[Gamedev:PublicRepos|Public Repos]] - Publicly readable Spring game code repositories&lt;br /&gt;
&lt;br /&gt;
= Technical Documentation =&lt;br /&gt;
; &#039;&#039;&#039;GameData&#039;&#039;&#039;&lt;br /&gt;
* [[Armordefs.lua]] - armor classes&lt;br /&gt;
* [[Icontypes.lua]] - strategic unit icons&lt;br /&gt;
* [[Modinfo.lua]] - game identifier file (name, version,...)&lt;br /&gt;
* [[Modrules.lua]] - Global game variables&lt;br /&gt;
* [[Movedefs.lua]] - MoveClasses for pathfinding&lt;br /&gt;
* [[Resources.lua]] - index file for textures&lt;br /&gt;
* [[Sidedata.lua]] - playable factions/races/sides&lt;br /&gt;
* [[Sounds.lua]] - index file for sounds&lt;br /&gt;
* [[Messages.lua]] - Team death messages {{new|95.0}}:deprecated&lt;br /&gt;
&lt;br /&gt;
; &#039;&#039;&#039;Definition Files&#039;&#039;&#039;&lt;br /&gt;
* [[Gamedev:UnitDefs]] - define the attributes of units&lt;br /&gt;
* [[Gamedev:WeaponDefs]] - define the attributes of weapons/projectiles&lt;br /&gt;
* [[Gamedev:FeatureDefs]] - define the attributes of static map features and wrecks&lt;br /&gt;
* [[CEG]] Particle effects (explosions etc)&lt;br /&gt;
&lt;br /&gt;
; &#039;&#039;&#039;Lua API &amp;amp; Libraries&#039;&#039;&#039; (excerpt)&lt;br /&gt;
* [[Lua_Scripting|Lua API Documentation]]&lt;br /&gt;
* [[LUPS]] - Lua Particle System&lt;br /&gt;
* [[Chili]] - A GUI Framework&lt;br /&gt;
* {{forumlink|topic=28341|title=ChangePiece}} - Switch piece geometry&lt;br /&gt;
&lt;br /&gt;
; &#039;&#039;&#039;Animation of units&#039;&#039;&#039;&lt;br /&gt;
Lua Animations&lt;br /&gt;
*[[Animation-LuaScripting]]&lt;br /&gt;
**[[Animation-LuaCallins]]&lt;br /&gt;
**[[Animation-LuaCallouts]]&lt;br /&gt;
**[[Animation-CobLuaDifferences]]&lt;br /&gt;
&lt;br /&gt;
COB Animations (Antiquated)&lt;br /&gt;
*[[Animation-CobOverview]]&lt;br /&gt;
**[[Animation-CobAnimation]]&lt;br /&gt;
**[[Animation-CobCallins]]&lt;br /&gt;
**[[Animation-CobConstants]]&lt;br /&gt;
**[[Animation-CobThreads]]&lt;br /&gt;
**[[Animation-CobHitByWeaponID]]&lt;br /&gt;
**[[Lua-LuaCOB]] - how to interface COB with LUA&lt;br /&gt;
**[[CEG_For_Units|Game Development:Calling basic CEGs from COB]]&lt;br /&gt;
**&amp;lt;strike&amp;gt;{{forumlink|topic=132943#132943|title=GPL COB Examples}}&amp;lt;/strike&amp;gt; - thread is gone&lt;br /&gt;
&lt;br /&gt;
; &#039;&#039;&#039;Models &amp;amp; Textures&#039;&#039;&#039;&lt;br /&gt;
* [[About_s3o|.s3o]]&lt;br /&gt;
* [[Assimp]]&lt;br /&gt;
* [[3DModels:Textures]]&lt;br /&gt;
&lt;br /&gt;
; &#039;&#039;&#039;Misc&#039;&#039;&#039;&lt;br /&gt;
* [[Gamedev:Archives]] - packing game/map&lt;br /&gt;
* [[Gamedev:Buildpics]]&lt;br /&gt;
* [[Gamedev:CollisionVolumes]]&lt;br /&gt;
* [[Gamedev:Glossary]]&lt;br /&gt;
* [[Gamedev:MouseCursors]]&lt;br /&gt;
* [[Gamedev:Sidepics]]&lt;br /&gt;
* [[Gamedev:Structure]]&lt;br /&gt;
* [[VirtualFileSystem]]&lt;br /&gt;
&lt;br /&gt;
= Tools =&lt;br /&gt;
== In-Game Tools ==&lt;br /&gt;
*[[ToolBox]] - A Collection of Game Development Tools&lt;br /&gt;
*[[Map Making: Feature Placer|Feature Placer]] - A Map Feature &amp;amp; NPC Unit Placement Tool&lt;br /&gt;
== External Tools ==&lt;br /&gt;
* [[Upspring]]&lt;br /&gt;
* [[Map,_Mod,_And_Unit_Development_Programs|Development Tools]]&lt;br /&gt;
&lt;br /&gt;
= Engine Related =&lt;br /&gt;
* [[Download_Testing]] - Test the compatibility of your game on upcoming versions of the Spring engine.&lt;br /&gt;
&lt;br /&gt;
* [[EngineChangelogForContentDevs]] - New engine versions sometimes require games to adjust. A list of common problems.&lt;br /&gt;
&lt;br /&gt;
* [[EngineSource_for_GameDevs]] - Notes about the engine source, from modding point of view.&lt;br /&gt;
&lt;br /&gt;
= Tutorials =&lt;br /&gt;
== Tips, Tricks &amp;amp; Testing ==&lt;br /&gt;
[[TestingYourGame|These tricks and commands]] are useful for testing or debugging.&lt;br /&gt;
&lt;br /&gt;
== Game Development Tutorials ==&lt;br /&gt;
*[[The Complete Guide To Making A Spring Game]] - A fairly comprehensive getting started tutorial.&lt;br /&gt;
*[http://springrts.com/phpbb/viewtopic.php?f=14&amp;amp;t=26409| Porting TA content to Spring]&lt;br /&gt;
*&amp;lt;strike&amp;gt;[[Simple Mod Tutorial|Simple Game Tutorial]]&amp;lt;/strike&amp;gt; - needs to be updated&lt;br /&gt;
&lt;br /&gt;
==Modelling Tutorials==&lt;br /&gt;
&#039;&#039;&#039;Wings3D&#039;&#039;&#039;&lt;br /&gt;
* [[3DModels:Wings3DTutorial]]&lt;br /&gt;
* [http://springrts.com/phpbb/viewtopic.php?t=10612 Wings UV Mapping Tutorial]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Blender&#039;&#039;&#039;&lt;br /&gt;
* [[TutorialBlenderWorkFlow|Blender Workflow Tutorial]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3DS Max&#039;&#039;&#039;&lt;br /&gt;
* [http://springrts.com/phpbb/viewtopic.php?t=10503 Runecrafter&#039;s 3DS Max UV Mapping Tutorial]&lt;br /&gt;
&lt;br /&gt;
==Texturing Tutorials==&lt;br /&gt;
* [http://springrts.com/phpbb/viewtopic.php?f=57&amp;amp;t=22392 DDS Textures:  How To]&lt;br /&gt;
* [http://springrts.com/phpbb/viewtopic.php?t=10947 Greeble Tutorial 1]&lt;br /&gt;
* [http://springrts.com/phpbb/viewtopic.php?f=9&amp;amp;t=12356 Greeble Tutorial 2]&lt;br /&gt;
&lt;br /&gt;
=Misc=&lt;br /&gt;
* [[Ren&#039;Py]]: a visual novel engine that can be used with Spring&lt;br /&gt;
* &amp;lt;strike&amp;gt;[http://answers.springlobby.info/ Q&amp;amp;A Site for the Spring Engine]&amp;lt;/strike&amp;gt; Currently down.&lt;br /&gt;
&lt;br /&gt;
[[Category:Game Dev]]&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=EngineSource_for_GameDevs&amp;diff=6345</id>
		<title>EngineSource for GameDevs</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=EngineSource_for_GameDevs&amp;diff=6345"/>
		<updated>2014-04-29T23:21:32Z</updated>

		<summary type="html">&lt;p&gt;Knorke: /* Intro */ bit clearer&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Intro==&lt;br /&gt;
During creation of a Spring game you will soon notice that not every detail is documented.&lt;br /&gt;
The most common things can be done without ever looking at the engine. But sometimes there are some specifique questions where one wants more details.&lt;br /&gt;
&lt;br /&gt;
Fortunately, the engine is open source and thus some things can be figured out by looking at it. Wait, isn&#039;t that like, super cryptic? Yes, scroll past those parts. A few things are comprehensible.&lt;br /&gt;
&lt;br /&gt;
==Downloading source and opening the files==&lt;br /&gt;
Download this https://github.com/spring/spring/zipball/master and unpack the zip file.&lt;br /&gt;
&lt;br /&gt;
==Text==&lt;br /&gt;
For example the code to load UnitDefs can be found here:&lt;br /&gt;
https://github.com/spring/spring/blob/develop/rts/Sim/Units/UnitDef.cpp&lt;br /&gt;
&lt;br /&gt;
Scroll down to about line 270:&amp;lt;br&amp;gt;&lt;br /&gt;
Notice how there are lines like for example this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;metalStorage = udTable.GetFloat(&amp;quot;metalStorage&amp;quot;, 0.0f);&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The word in double quotes (&amp;quot;metalStorage&amp;quot;) is the UnitDef tag as it is read from the unit file.&lt;br /&gt;
&lt;br /&gt;
If a tag can not be found in this file in this form, it is very likely that it does nothing and you can remove it from the unit file.&lt;br /&gt;
&lt;br /&gt;
GetFloat means that this tag is a float number.&lt;br /&gt;
The number, in this case 0.0f, is the default value that is used, when the tag can not be found in the unit file.&lt;br /&gt;
&lt;br /&gt;
Since the engine expects a number (eg 100.0) it is understandable that metalStorage = &amp;quot;a lot&amp;quot;, or metalStorage=false will not work.&lt;br /&gt;
&lt;br /&gt;
Beside &#039;&#039;&#039;GetFloat&#039;&#039;&#039; there are:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;GetBool&#039;&#039;&#039; - true or false&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;GetInt&#039;&#039;&#039; - an integer number&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;GetString&#039;&#039;&#039; - a string, that means a word eg a unit name or a file name&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;GetFloat3&#039;&#039;&#039; - 3 floats, for example coordinates in case of &amp;quot;modelCenterOffset&amp;quot; or a vector in case of &amp;quot;flareDropVector&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Searching text in files==&lt;br /&gt;
It is usefull to have an text editor that can search for text in multiple files at once, for example this one: http://notepad-plus-plus.org/&lt;br /&gt;
&lt;br /&gt;
==Interesting files==&lt;br /&gt;
Most things outside &amp;quot;Sim&amp;quot; folder are uninteresting.&lt;br /&gt;
&lt;br /&gt;
The files where XY&#039;&#039;&#039;defs&#039;&#039;&#039; get loaded:&lt;br /&gt;
&lt;br /&gt;
https://github.com/spring/spring/blob/develop/rts/Sim/Units/UnitDef.cpp&lt;br /&gt;
&lt;br /&gt;
https://github.com/spring/spring/blob/develop/rts/Sim/Weapons/WeaponDefHandler.cpp&lt;br /&gt;
&lt;br /&gt;
https://github.com/spring/spring/blob/develop/rts/Sim/Features/FeatureHandler.cpp&lt;br /&gt;
&lt;br /&gt;
https://github.com/spring/spring/blob/develop/rts/Sim/MoveTypes/MoveInfo.cpp&lt;br /&gt;
&lt;br /&gt;
Unit actions (damage, kill, experience,...):&amp;lt;br&amp;gt;&lt;br /&gt;
https://github.com/spring/spring/blob/develop/rts/Sim/Units/Unit.cpp&lt;br /&gt;
&lt;br /&gt;
[[Category:Game Dev]]&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=Lua:Main&amp;diff=10894</id>
		<title>Lua:Main</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=Lua:Main&amp;diff=10894"/>
		<updated>2014-04-24T20:10:02Z</updated>

		<summary type="html">&lt;p&gt;Knorke: /* Tutorials */ add Lua:Tutorial_GettingStarted&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Engine_Development|Development]] &amp;lt; {{FULLPAGENAME}}&lt;br /&gt;
&lt;br /&gt;
=Lua FAQ=&lt;br /&gt;
[[Lua_Beginners_FAQ]]&amp;lt;br&amp;gt;&lt;br /&gt;
[http://springrts.com/phpbb/viewtopic.php?f=23&amp;amp;t=15596 Forum topic with some basic information about gadgets]&amp;lt;br&amp;gt;&lt;br /&gt;
[http://springrts.com/phpbb/viewtopic.php?f=23&amp;amp;t=16223 Forum topic with a manual on Spring lua scripting]&lt;br /&gt;
&lt;br /&gt;
=Interfaces {{HeaderNotice|(last update: 95.0-dev)}}=&lt;br /&gt;
[[:Category:Lua]] (shows which interfaces are loaded by LuaUI,LuaRules,etc.)&amp;lt;br&amp;gt;&lt;br /&gt;
{{LuaInterfaces}}&lt;br /&gt;
&lt;br /&gt;
=Tutorials=&lt;br /&gt;
* [[Lua:Tutorial_GettingStarted|Getting Started]] (beginner guide)&lt;br /&gt;
&lt;br /&gt;
* [[LuaTutorials::InterCommunications]] (i.e. synced &amp;lt;-&amp;gt; unsynced communications)&lt;br /&gt;
&lt;br /&gt;
=Other useful information=&lt;br /&gt;
* [[Lua:Callins]]&lt;br /&gt;
* [[Lua_Performance | Lua performance tips]]&lt;br /&gt;
* [http://springrts.com/wiki/COB_Constants#Custom_Variables COB Custom Variables]&lt;br /&gt;
* [http://springrts.com/phpbb/viewtopic.php?f=12&amp;amp;t=19560 Font Drawing System]&lt;br /&gt;
* [[UI_commands]]&lt;br /&gt;
* [[Animation-LuaScripting | Unit animation scripting with Lua]]&lt;br /&gt;
* [[LUA ComonPitfalls]]&lt;br /&gt;
&lt;br /&gt;
=Official Lua documentation=&lt;br /&gt;
[http://www.lua.org/pil/ &#039;Programming in Lua&#039; book online]&amp;lt;br&amp;gt;&lt;br /&gt;
[http://www.lua.org/manual/5.1/ Lua 5.1 Reference manual]&amp;lt;br&amp;gt;&lt;br /&gt;
[http://lua-users.org/wiki/TutorialDirectory Lua tutorials]&lt;br /&gt;
[[Category: Lua]]&lt;br /&gt;
&lt;br /&gt;
=Widget Database=&lt;br /&gt;
[[WidgetDatabaseFAQ]]&amp;lt;br/&amp;gt;&lt;br /&gt;
[http://widgets.springrts.de/ Web-Interface]&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=Lua:Tutorial_GettingStarted&amp;diff=10913</id>
		<title>Lua:Tutorial GettingStarted</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=Lua:Tutorial_GettingStarted&amp;diff=10913"/>
		<updated>2014-04-24T20:08:21Z</updated>

		<summary type="html">&lt;p&gt;Knorke: copy over from User:Knorke/Sandbox1‎ into real page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Engine_Development|Development]] &amp;lt; [[Lua_Scripting|Lua Scripting]] &amp;lt; {{FULLPAGENAME}}&lt;br /&gt;
&lt;br /&gt;
==What this is==&lt;br /&gt;
This page explains how to get started making scripts for spring.&lt;br /&gt;
&lt;br /&gt;
==What this is not==&lt;br /&gt;
This page does not explains how to make scripts for spring.&lt;br /&gt;
&lt;br /&gt;
This page is not a Lua tutorial.&lt;br /&gt;
&lt;br /&gt;
==Requirements==&lt;br /&gt;
* having played spring game for some days&lt;br /&gt;
* text editor with synthax coloring&lt;br /&gt;
* copy of [[SpringTutorialGame]]&lt;br /&gt;
* [http://springfiles.com/spring/spring-maps/aliendesert some small map] because those load faster&lt;br /&gt;
* Spring set to [[Springsettings.cfg#Fullscreen|windowed mode]] for easier switching between editor/game&lt;br /&gt;
* a very bit familiar with programing (variables, functions, loops, arrays = enough)&lt;br /&gt;
* read through [[TestingYourGame|this tips page]] once&lt;br /&gt;
&lt;br /&gt;
==Wupget and friends==&lt;br /&gt;
In Spring games there are 3 kinds of Lua scripts.&lt;br /&gt;
Crude and simple explaination:&lt;br /&gt;
# gadgets: these are the &amp;quot;gameplay logic code.&amp;quot;&lt;br /&gt;
# widgets: these are for interface.&lt;br /&gt;
# unit scripts: animate units &amp;amp; controll their weapons.&lt;br /&gt;
&lt;br /&gt;
Making those 3 is not very different but widgets are the easiest to start with.&lt;br /&gt;
&lt;br /&gt;
There is also 4) functionality provided by the engine.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Also look at this:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
http://springrts.com/mediawiki/images/1/13/Gadgets_widgets_and_friends.png&lt;br /&gt;
&lt;br /&gt;
All 4 are in a constant fight against each other.&lt;br /&gt;
&lt;br /&gt;
==My first wupdget==&lt;br /&gt;
The [[SpringTutorialGame]] is simple and good for testing:&lt;br /&gt;
You can use any other game but some block player widgets or are very confusing.&lt;br /&gt;
&lt;br /&gt;
Create a txt file like this and there:&lt;br /&gt;
Spring\LuaUI\Widgets\myfirstwidget.lua&lt;br /&gt;
&lt;br /&gt;
and copypaste this text into it:&lt;br /&gt;
-----&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function widget:GetInfo()&lt;br /&gt;
  return {&lt;br /&gt;
    name      = &amp;quot;my first widget&amp;quot;,&lt;br /&gt;
    desc      = &amp;quot;this is so awesome&amp;quot;,&lt;br /&gt;
    author    = &amp;quot;horse 3000&amp;quot;,&lt;br /&gt;
    date      = &amp;quot;2009&amp;quot;,&lt;br /&gt;
    license   = &amp;quot;GNU GPL, v2 or later&amp;quot;,&lt;br /&gt;
    layer     = -10,&lt;br /&gt;
    enabled   = true&lt;br /&gt;
  }&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
-----&lt;br /&gt;
For now it does not matter what excactly this does but here you can put informations about your widget. &lt;br /&gt;
&lt;br /&gt;
What matters is that without such GetInfo() function Spring will not load the widget correctly.&lt;br /&gt;
(Since it takes up screen-space it will be left out when code is posted. Of course it must still be there.)&lt;br /&gt;
&lt;br /&gt;
Start spring.exe and press F11. The &amp;quot;widget menu&amp;quot; opens:&lt;br /&gt;
&lt;br /&gt;
http://springrts.com/mediawiki/images/8/80/Widget_F11menu.png&lt;br /&gt;
&lt;br /&gt;
It is likely already filled with some other widgets contained in the game.&lt;br /&gt;
Find your new widget in the list. Click on it to turn it on and off: The name in list should go green or red accordingly.&lt;br /&gt;
&lt;br /&gt;
If that works - congratulation: You made a new widget that does excactly nothing.&lt;br /&gt;
&lt;br /&gt;
=&amp;quot;Hello unit&amp;quot; wupdget=&lt;br /&gt;
Add the following at the end of myfirstwidget.lua:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function widget:UnitFinished(unitID, unitDefID, teamID)&lt;br /&gt;
	Spring.Echo (&amp;quot;a new unit was finished! It belongs to team &amp;quot; .. teamID)	&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
UnitFinished(...) is a [[Lua:Callins|callin function]] : Those are functions that the engine calls when certain events happen.&lt;br /&gt;
Captain Obvious has already figured out: This function gets called when a new unit is finished.&lt;br /&gt;
&lt;br /&gt;
Spring.Echo is used to output text to the chat/console.&lt;br /&gt;
So this widget should tell when a new unit is made.&lt;br /&gt;
&lt;br /&gt;
4)&lt;br /&gt;
Open the widget menu and disable then re-enable your widget: This will reload the widget.&lt;br /&gt;
Now build some units to test it.&lt;br /&gt;
&lt;br /&gt;
===Finding errors and infolog.txt===&lt;br /&gt;
For test add an error like this:&lt;br /&gt;
	Spring.Echo (100 + nil)&lt;br /&gt;
and reload the widget.&lt;br /&gt;
The widgets name is green but turns yellow as soon a unit is build: &amp;quot;nil&amp;quot; can not be used in math like that.&lt;br /&gt;
&lt;br /&gt;
The error is also displayed in chat and [[infolog.txt]]&lt;br /&gt;
In that logfile you can look up all errors even if they have disappeared from chat.&lt;br /&gt;
Fix the error, reload the widget and it is green again. Oha.&lt;br /&gt;
&lt;br /&gt;
FIXME: expand this&lt;br /&gt;
&lt;br /&gt;
===widget sees you and only you and your allies===&lt;br /&gt;
Even if there is a bot/other player building stuff, the widget will not notify on all  their new units if they are outside line of sight.&lt;br /&gt;
That is because widgets are limited in what they can &amp;quot;see.&amp;quot;&lt;br /&gt;
The widget only sees what what the player who is running the widget can see, too. This is to prevent cheating.&lt;br /&gt;
&lt;br /&gt;
==&amp;quot;Hello unit&amp;quot; 2 - with markers and advancement==&lt;br /&gt;
change the widget to this and guess what it does:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function widget:UnitFinished(unitID, unitDefID, teamID)&lt;br /&gt;
	local x,y,z = Spring.GetUnitPosition (unitID)&lt;br /&gt;
	Spring.MarkerAddPoint (x,y,z, &amp;quot;a new unit! id=&amp;quot; .. unitID)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It adds a marker point on every new unit!&lt;br /&gt;
Note how the unitID parameter from UnitFinished() is passed to GetUnitPosition()&lt;br /&gt;
&lt;br /&gt;
===unitIDs===&lt;br /&gt;
Previous paragraph featured &#039;&#039;unitID&#039;&#039; variable.&lt;br /&gt;
Every unit, feature or weapon projectile in spring has an ID number:&lt;br /&gt;
&lt;br /&gt;
http://springrts.com/mediawiki/images/3/3c/Units_features_projectiles.png&lt;br /&gt;
&lt;br /&gt;
There are never two units with the same unitID at the same time. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;#YOLO?&amp;lt;/pre&amp;gt;&lt;br /&gt;
No YOLO: when a unit is destroyed its unitID might be reused later for a different unit.&lt;br /&gt;
&lt;br /&gt;
=a boring counter widget=&lt;br /&gt;
A counter that is increased when units are made:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
local counter = 0&lt;br /&gt;
function widget:UnitFinished (unitID, unitDefID, teamID)	&lt;br /&gt;
	counter = counter +1&lt;br /&gt;
	Spring.Echo (&amp;quot;now there are &amp;quot; .. counter .. &amp;quot; units&amp;quot;)&lt;br /&gt;
	if counter &amp;gt; 10 then&lt;br /&gt;
		Spring.Echo (&amp;quot;wow, more than 10 units!&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[TestingYourGame#Lua|Reload the widget]] and note how the counter gets reseted. &lt;br /&gt;
That is how widgets roll: Their variables get cleared on reload.&lt;br /&gt;
&lt;br /&gt;
===boring counter widget with tables===&lt;br /&gt;
Imagine you want a counter that stores for each factory how many units it has already produced. One variable will not be enought here but an array can store multiple things.&lt;br /&gt;
&lt;br /&gt;
Arrays in Lua are tables. Read about tables: http://lua-users.org/wiki/TablesTutorial&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
local buildCount = {}&lt;br /&gt;
function widget:UnitFromFactory(unitID, unitDefID, unitTeam, factoryID, factoryDefID, userOrders)&lt;br /&gt;
	--read from table how many units this factory already built&lt;br /&gt;
	local n = buildCount[factoryID]&lt;br /&gt;
&lt;br /&gt;
	--was the entry empty?&lt;br /&gt;
	if n == nil then					&lt;br /&gt;
		n = 0 --if yes, start counting from 0&lt;br /&gt;
	end&lt;br /&gt;
	n = n +1 --increase n by 1 (best comment ever)&lt;br /&gt;
	Spring.Echo (&amp;quot;This was unit number &amp;quot; .. n .. &amp;quot; from factory &amp;quot; .. factoryID)&lt;br /&gt;
	--store new buildCount for this factory&lt;br /&gt;
	buildCount[factoryID] = n&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
UnitFromFactory is basically the same as UnitFinished, but has the usefull &#039;&#039;factoryID&#039;&#039; parameter.&lt;br /&gt;
&#039;&#039;&#039;Why the if n == nil?&#039;&#039;&#039;&lt;br /&gt;
In Lua everything not initialized is nil (=nothing) and nil can not be used in any math. &lt;br /&gt;
&lt;br /&gt;
(n = n +1  is a math)&lt;br /&gt;
&lt;br /&gt;
Btw a shorter version could be:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;buildCount[factoryID] = (buildCount[factoryID] or 0) + 1&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==I made enough &amp;quot;hello world&amp;quot; widgets. What now?==&lt;br /&gt;
On [[Lua_Scripting]] the most important are the pages under &#039;&#039;&#039;GameState&#039;&#039;&#039; and &#039;&#039;&#039;Client&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
See these [[TestingYourGame|pro-tips]] to make testing less frustrating.&lt;br /&gt;
&lt;br /&gt;
While widgets are initially easiest to make, soon there is a problem:&lt;br /&gt;
widgets are for interface stuff. &lt;br /&gt;
&lt;br /&gt;
That means widgets usually need to either...&lt;br /&gt;
* ...draw something on the screen. (for example the health of Commander)&lt;br /&gt;
and/or&lt;br /&gt;
* ...give orders to units. (for example make Commander automatically run away from danger)&lt;br /&gt;
&lt;br /&gt;
Both graphics and the whole order-system can be bit tricky for starters.&lt;br /&gt;
Without graphics and orders, the awesomeness potential of a widget is small.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Pro tip:&#039;&#039;&#039; gadgets can be awesome without either!&lt;br /&gt;
&lt;br /&gt;
==go go gadgets time!==&lt;br /&gt;
We learned widgets can only &amp;quot;look at&amp;quot; the gamestate or do things that players can do, for example ordering units to attack another unit.&lt;br /&gt;
&lt;br /&gt;
On the other hand gadgets are scripts that are able to alter the state of the game.&lt;br /&gt;
With gadgets it is possible to implent new game logic like jumpjets, drop pods, tech tree systems, etc.&lt;br /&gt;
&lt;br /&gt;
Unlike widgets, gadgets must be [[Gamedev:Structure#LuaRules.5C|included in a game or in a map.]]&lt;br /&gt;
&lt;br /&gt;
To do so it is best to unpack the game file into an [[Gamedev:Archives|.sdd archive]]&lt;br /&gt;
&lt;br /&gt;
Writing gadgets is similiar to widgets, except the getInfo() header and callin functions are prefixed with &amp;lt;code&amp;gt;gadget:xxx&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;widget:xxx&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===synced &amp;amp; unsynced===&lt;br /&gt;
Gadgets are split into a synced and into an unsynced part.&lt;br /&gt;
&lt;br /&gt;
In simple terms that means the synced part is usually for controlling the game logic.&lt;br /&gt;
The unsynced part is for drawig graphics.&lt;br /&gt;
&lt;br /&gt;
For example look at this lava tide gadget:&lt;br /&gt;
&lt;br /&gt;
http://springrts.com/mediawiki/images/3/33/Beachbuggysuicidecult_lava_sync_unsync.gif&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;synced&#039;&#039;&#039; part is responsible for &#039;&#039;damaging/destroying the units&#039;&#039; in the lava. It actually alters the gamestate.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;unsynced&#039;&#039;&#039; part is only for &#039;&#039;drawing&#039;&#039; the graphic of the lava. The graphic itself does not influence the gamestate in any way.&lt;br /&gt;
&lt;br /&gt;
In code it looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
if (gadgetHandler:IsSyncedCode()) then&lt;br /&gt;
  --synced code&lt;br /&gt;
  ..&lt;br /&gt;
  damage all units that are underneath the lava tide level&lt;br /&gt;
  ..&lt;br /&gt;
else&lt;br /&gt;
  --unsynced code&lt;br /&gt;
  ..&lt;br /&gt;
  drawing the lava with GL-api functions&lt;br /&gt;
  ..&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Of course that also means that some functions or callins can only be used in synced or unsynced part. For example the synced part can not draw anything and the unsynced part can not spawn units.&lt;br /&gt;
&lt;br /&gt;
Sometimes it is nessecary to transfer some data/information &amp;quot;across the sync-unsynced border&amp;quot; - but the scope of variables is only in the part they were declared in.&lt;br /&gt;
In lava-exampe that might be the current height of lava.&lt;br /&gt;
How this still works is explained here: [[LuaTutorials::InterCommunications]]&lt;br /&gt;
&lt;br /&gt;
==Look at more examples==&lt;br /&gt;
Common hint for learning spring Lua is: &#039;&#039;&amp;quot;Look at some examples in other games.&amp;quot;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
But a spring game usually has dozen of wupdgets and only a few are useful examples for beginners. Many scripts deal with some very specifique problem or are just way too long.&lt;br /&gt;
Or one has to be familiar with the game to even understand what the script even does.&lt;br /&gt;
Or if one wants to use the wupdget in ones own game, suddendly nothing works anymore because it depends on so many configs or other files.&lt;br /&gt;
&lt;br /&gt;
Two simple examples are:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Linked units&amp;quot; (hub dies, child-units explode too)&lt;br /&gt;
http://springrts.com/phpbb/viewtopic.php?f=23&amp;amp;t=25435&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Moveable metal extractor&amp;quot;&lt;br /&gt;
http://springrts.com/phpbb/viewtopic.php?f=14&amp;amp;t=26877&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
==Feedback? Questions?==&lt;br /&gt;
This page is open for feedback {{forumlink|topic=32047|title=in the forum.}}&lt;br /&gt;
&lt;br /&gt;
[[category: Lua]]&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=EvoGreenLitFAQ&amp;diff=6446</id>
		<title>EvoGreenLitFAQ</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=EvoGreenLitFAQ&amp;diff=6446"/>
		<updated>2014-04-24T13:21:13Z</updated>

		<summary type="html">&lt;p&gt;Knorke: /* Cannot start command: Downloading Engine 96.0: assign: The parameter is incorrect */ win xp into title&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;EvolutionRTS emergency FAQ&#039;&#039;&#039;&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Before you ask a question in chat, please see if it is already answered on this list.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==Playable at the moment?==&lt;br /&gt;
Looks like it!&lt;br /&gt;
&lt;br /&gt;
http://www.vemags.de/wp-content/uploads/2012/06/Status_LSA_gruen1.jpg&lt;br /&gt;
&lt;br /&gt;
There seem to be at least 1, often 2 and more team games running all the time.&lt;br /&gt;
&lt;br /&gt;
==Engine download stuck==&lt;br /&gt;
&lt;br /&gt;
First of all, make sure that your automatic windows updates are enabled. If you disabled them, then most likely you don&#039;t have the KB2533623 update that is necessary. Either reenable windows update or install KB2533623 separately if you&#039;re a power user.&lt;br /&gt;
&lt;br /&gt;
http://support.microsoft.com/kb/2533623&lt;br /&gt;
&lt;br /&gt;
Close the lobby and start it again.&lt;br /&gt;
&lt;br /&gt;
Look for common\EvolutionRTS\evo_data in your steam folder. If evo_data is not empty, copy everything in it into Documents\My games\Spring\&lt;br /&gt;
&lt;br /&gt;
==Downloads fail (because windows user name has special characters)==&lt;br /&gt;
http://i.imgur.com/6qZTQOZ.png&lt;br /&gt;
&lt;br /&gt;
If the lobby states it is downloading the engine but nothing happens:&lt;br /&gt;
&lt;br /&gt;
Check if your windows account name contains any &amp;quot;funny&amp;quot; characters or umlauts like Ã¶Ã¼Ã¤Ã´Ã¡ etc.&lt;br /&gt;
&lt;br /&gt;
As a workaround use a windows account name without such characters. This is will be fixed of course.&lt;br /&gt;
&lt;br /&gt;
==Singleplayer?==&lt;br /&gt;
&#039;&#039;&#039;Solution:&#039;&#039;&#039;  Create a multiplayer battleroom with the button at the bottom and make it private by giving it a password. The lobby will download the necessary files and once it&#039;s done, you can play. See below for adding bots.&lt;br /&gt;
&lt;br /&gt;
Or go to the Singleplayer tab and create a custom battle (&amp;lt;b&amp;gt;NOT&amp;lt;/b&amp;gt; launch game directly) with engine 96.0 and the latest version of Evolution RTS you can find in the list.&lt;br /&gt;
&lt;br /&gt;
==Windows XP: Cannot start command: Downloading Engine 96.0: assign: The parameter is incorrect==&lt;br /&gt;
&lt;br /&gt;
Are you on windows XP? Unfortunately the lobby does not work with Windows XP. You can use the Java Weblobby version by visiting http://www.weblobby.evolutionrts.info directly or you can try a different lobby: http://steamcommunity.com/app/291150/discussions/0/540738051772337468/&lt;br /&gt;
&lt;br /&gt;
==Automatic download of game files does not work==&lt;br /&gt;
NOTE: the GAME file, not the engine.&lt;br /&gt;
&lt;br /&gt;
Best idea is to wait a bit, the lobby should eventually download it.&lt;br /&gt;
If it &amp;lt;b&amp;gt;really absolutely&amp;lt;/b&amp;gt; does not work:&lt;br /&gt;
1. Go to http://packages.springrts.com/builds/&lt;br /&gt;
2. download the .sdz with the latest evolutionRTS version. (Currently that is 7.37 but check vs what is played in lobby)&lt;br /&gt;
3. Put the .sdz file into: Documents/My Games/Spring/games&lt;br /&gt;
Do not unzip it, just move it there. When you&#039;re done, close and reopen the lobby.&lt;br /&gt;
&lt;br /&gt;
As said, that is only for advanced users and should not be necessary.&lt;br /&gt;
&lt;br /&gt;
==AI does not work!==&lt;br /&gt;
The evolutionRTS AI is the &amp;quot;Survial Spawner AI.&amp;quot;&lt;br /&gt;
It spawns random enemies for you to shot at.&lt;br /&gt;
&lt;br /&gt;
The NullAI bot can also be used: It does &#039;&#039;nothing&#039;&#039; which is nice to try out the game without enemies.&lt;br /&gt;
&lt;br /&gt;
==Sandbox mode? I want to try the game without being rushed!==&lt;br /&gt;
Start a singleplayer game against the NullAI bot.&lt;br /&gt;
&lt;br /&gt;
==Missions?==&lt;br /&gt;
Not there yet.&lt;br /&gt;
&lt;br /&gt;
==It crashed!==&lt;br /&gt;
There is a logfile: [[Infolog.txt]]&lt;br /&gt;
&lt;br /&gt;
The page also explains how to find and share it. You can post it in forum, on steam or in chat.&lt;br /&gt;
&lt;br /&gt;
==Which maps should I play?==&lt;br /&gt;
Eye of Horus is a good map that works for team games, free-for-all, 1v1 and with bots.&lt;br /&gt;
&lt;br /&gt;
==Why so many problems?==&lt;br /&gt;
Surprised by so many players.&lt;br /&gt;
&lt;br /&gt;
==Hooray, I am ingame! How to play?==&lt;br /&gt;
http://www.wiki.evolutionrts.info/doku.php/evolution_rts:quick_start_guide&lt;br /&gt;
&lt;br /&gt;
Or just try out things :)&lt;br /&gt;
&lt;br /&gt;
==How to chat ingame?==&lt;br /&gt;
Press the RETURN key and type your message.&lt;br /&gt;
&lt;br /&gt;
==Graphics problems! / the game runs very bad!==&lt;br /&gt;
Some problems can probally be solved by the general spring-engine FAQ: [[FAQ:trouble]]&lt;br /&gt;
&lt;br /&gt;
==Cursor is painfully slow!==&lt;br /&gt;
Click Settings (the wrench) &amp;gt; Interface &amp;gt; Mouse Cursor &amp;gt; enable Hardware Cursor&lt;br /&gt;
&lt;br /&gt;
==As a player, how can I help?==&lt;br /&gt;
&lt;br /&gt;
1. &#039;&#039;&#039;If you have bugs to report&#039;&#039;&#039;: It is okay to do so in the steam forum: http://steamcommunity.com/app/291150&lt;br /&gt;
&lt;br /&gt;
(Or if you know how to use the google.code bugtracker: https://code.google.com/p/evolutionrts/issues/list )&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Give as much &#039;&#039;info&#039;&#039; as possible:&#039;&#039;&#039;&lt;br /&gt;
*Operation system&lt;br /&gt;
&lt;br /&gt;
*computer hardware (laptop or desktop, cpu, ram, graphics card,..)&lt;br /&gt;
&lt;br /&gt;
*This logfile: [[Infolog.txt]]&lt;br /&gt;
&lt;br /&gt;
*Lobby logfile: /Documents/My games/Spring/weblobby/&#039;&#039;&#039;weblobby.log&#039;&#039;&#039; , share via pastebin.com&lt;br /&gt;
&lt;br /&gt;
*Screenshots can be uploaded to imgur.com or similiar&lt;br /&gt;
&lt;br /&gt;
After a while check back on your post, devs might need more informations from you!&lt;br /&gt;
&lt;br /&gt;
Reporting bugs in chat is pretty much useless, there get overlooked there or forgotten.&lt;br /&gt;
&lt;br /&gt;
2. &#039;&#039;&#039;If you can play:&#039;&#039;&#039; help others players with their problems in chat.&lt;br /&gt;
&lt;br /&gt;
3. Be patient  :)&lt;br /&gt;
&lt;br /&gt;
==More Information About Common Bugs==&lt;br /&gt;
https://code.google.com/p/springweblobby/wiki/EvoSteamBugs&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=User:Knorke/Sandbox1&amp;diff=20867</id>
		<title>User:Knorke/Sandbox1</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=User:Knorke/Sandbox1&amp;diff=20867"/>
		<updated>2014-04-23T22:23:01Z</updated>

		<summary type="html">&lt;p&gt;Knorke: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==What this is==&lt;br /&gt;
This page explains how to get started making scripts for spring.&lt;br /&gt;
&lt;br /&gt;
==What this is not==&lt;br /&gt;
This page does not explains how to make scripts for spring.&lt;br /&gt;
&lt;br /&gt;
This page is not a Lua tutorial.&lt;br /&gt;
&lt;br /&gt;
==Requirements==&lt;br /&gt;
* having played spring game for some days&lt;br /&gt;
* text editor with synthax coloring&lt;br /&gt;
* copy of [[SpringTutorialGame]]&lt;br /&gt;
* [http://springfiles.com/spring/spring-maps/aliendesert some small map] because those load faster&lt;br /&gt;
* Spring set to [[Springsettings.cfg#Fullscreen|windowed mode]] for easier switching between editor/game&lt;br /&gt;
* a very bit familiar with programing (variables, functions, loops, arrays = enough)&lt;br /&gt;
* read through [[TestingYourGame|this tips page]] once&lt;br /&gt;
&lt;br /&gt;
==Wupget and friends==&lt;br /&gt;
In Spring games there are 3 kinds of Lua scripts.&lt;br /&gt;
Crude and simple explaination:&lt;br /&gt;
# gadgets: these are the &amp;quot;gameplay logic code.&amp;quot;&lt;br /&gt;
# widgets: these are for interface.&lt;br /&gt;
# unit scripts: animate units &amp;amp; controll their weapons.&lt;br /&gt;
&lt;br /&gt;
Making those 3 is not very different but widgets are the easiest to start with.&lt;br /&gt;
&lt;br /&gt;
There is also 4) functionality provided by the engine.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Also look at this:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
http://springrts.com/mediawiki/images/1/13/Gadgets_widgets_and_friends.png&lt;br /&gt;
&lt;br /&gt;
All 4 are in a constant fight against each other.&lt;br /&gt;
&lt;br /&gt;
==My first wupdget==&lt;br /&gt;
The [[SpringTutorialGame]] is simple and good for testing:&lt;br /&gt;
You can use any other game but some block player widgets or are very confusing.&lt;br /&gt;
&lt;br /&gt;
Create a txt file like this and there:&lt;br /&gt;
Spring\LuaUI\Widgets\myfirstwidget.lua&lt;br /&gt;
&lt;br /&gt;
and copypaste this text into it:&lt;br /&gt;
-----&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function widget:GetInfo()&lt;br /&gt;
  return {&lt;br /&gt;
    name      = &amp;quot;my first widget&amp;quot;,&lt;br /&gt;
    desc      = &amp;quot;this is so awesome&amp;quot;,&lt;br /&gt;
    author    = &amp;quot;horse 3000&amp;quot;,&lt;br /&gt;
    date      = &amp;quot;2009&amp;quot;,&lt;br /&gt;
    license   = &amp;quot;GNU GPL, v2 or later&amp;quot;,&lt;br /&gt;
    layer     = -10,&lt;br /&gt;
    enabled   = true&lt;br /&gt;
  }&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
-----&lt;br /&gt;
For now it does not matter what excactly this does but here you can put informations about your widget. &lt;br /&gt;
&lt;br /&gt;
What matters is that without such GetInfo() function Spring will not load the widget correctly.&lt;br /&gt;
(Since it takes up screen-space it will be left out when code is posted. Of course it must still be there.)&lt;br /&gt;
&lt;br /&gt;
Start spring.exe and press F11. The &amp;quot;widget menu&amp;quot; opens:&lt;br /&gt;
&lt;br /&gt;
http://springrts.com/mediawiki/images/8/80/Widget_F11menu.png&lt;br /&gt;
&lt;br /&gt;
It is likely already filled with some other widgets contained in the game.&lt;br /&gt;
Find your new widget in the list. Click on it to turn it on and off: The name in list should go green or red accordingly.&lt;br /&gt;
&lt;br /&gt;
If that works - congratulation: You made a new widget that does excactly nothing.&lt;br /&gt;
&lt;br /&gt;
=&amp;quot;Hello unit&amp;quot; wupdget=&lt;br /&gt;
Add the following at the end of myfirstwidget.lua:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function widget:UnitFinished(unitID, unitDefID, teamID)&lt;br /&gt;
	Spring.Echo (&amp;quot;a new unit was finished! It belongs to team &amp;quot; .. teamID)	&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
UnitFinished(...) is a [[Lua:Callins|callin function]] : Those are functions that the engine calls when certain events happen.&lt;br /&gt;
Captain Obvious has already figured out: This function gets called when a new unit is finished.&lt;br /&gt;
&lt;br /&gt;
Spring.Echo is used to output text to the chat/console.&lt;br /&gt;
So this widget should tell when a new unit is made.&lt;br /&gt;
&lt;br /&gt;
4)&lt;br /&gt;
Open the widget menu and disable then re-enable your widget: This will reload the widget.&lt;br /&gt;
Now build some units to test it.&lt;br /&gt;
&lt;br /&gt;
===Finding errors and infolog.txt===&lt;br /&gt;
For test add an error like this:&lt;br /&gt;
	Spring.Echo (100 + nil)&lt;br /&gt;
and reload the widget.&lt;br /&gt;
The widgets name is green but turns yellow as soon a unit is build: &amp;quot;nil&amp;quot; can not be used in math like that.&lt;br /&gt;
&lt;br /&gt;
The error is also displayed in chat and [[infolog.txt]]&lt;br /&gt;
In that logfile you can look up all errors even if they have disappeared from chat.&lt;br /&gt;
Fix the error, reload the widget and it is green again. Oha.&lt;br /&gt;
&lt;br /&gt;
FIXME: expand this&lt;br /&gt;
&lt;br /&gt;
===widget sees you and only you and your allies===&lt;br /&gt;
Even if there is a bot/other player building stuff, the widget will not notify on all  their new units if they are outside line of sight.&lt;br /&gt;
That is because widgets are limited in what they can &amp;quot;see.&amp;quot;&lt;br /&gt;
The widget only sees what what the player who is running the widget can see, too. This is to prevent cheating.&lt;br /&gt;
&lt;br /&gt;
==&amp;quot;Hello unit&amp;quot; 2 - with markers and advancement==&lt;br /&gt;
change the widget to this and guess what it does:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function widget:UnitFinished(unitID, unitDefID, teamID)&lt;br /&gt;
	local x,y,z = Spring.GetUnitPosition (unitID)&lt;br /&gt;
	Spring.MarkerAddPoint (x,y,z, &amp;quot;a new unit! id=&amp;quot; .. unitID)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It adds a marker point on every new unit!&lt;br /&gt;
Note how the unitID parameter from UnitFinished() is passed to GetUnitPosition()&lt;br /&gt;
&lt;br /&gt;
===unitIDs===&lt;br /&gt;
Previous paragraph featured &#039;&#039;unitID&#039;&#039; variable.&lt;br /&gt;
Every unit, feature or weapon projectile in spring has an ID number:&lt;br /&gt;
&lt;br /&gt;
http://springrts.com/mediawiki/images/3/3c/Units_features_projectiles.png&lt;br /&gt;
&lt;br /&gt;
There are never two units with the same unitID at the same time. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;#YOLO?&amp;lt;/pre&amp;gt;&lt;br /&gt;
No YOLO: when a unit is destroyed its unitID might be reused later for a different unit.&lt;br /&gt;
&lt;br /&gt;
=a boring counter widget=&lt;br /&gt;
A counter that is increased when units are made:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
local counter = 0&lt;br /&gt;
function widget:UnitFinished (unitID, unitDefID, teamID)	&lt;br /&gt;
	counter = counter +1&lt;br /&gt;
	Spring.Echo (&amp;quot;now there are &amp;quot; .. counter .. &amp;quot; units&amp;quot;)&lt;br /&gt;
	if counter &amp;gt; 10 then&lt;br /&gt;
		Spring.Echo (&amp;quot;wow, more than 10 units!&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[TestingYourGame#Lua|Reload the widget]] and note how the counter gets reseted. &lt;br /&gt;
That is how widgets roll: Their variables get cleared on reload.&lt;br /&gt;
&lt;br /&gt;
===boring counter widget with tables===&lt;br /&gt;
Imagine you want a counter that stores for each factory how many units it has already produced. One variable will not be enought here but an array can store multiple things.&lt;br /&gt;
&lt;br /&gt;
Arrays in Lua are tables. Read about tables: http://lua-users.org/wiki/TablesTutorial&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
local buildCount = {}&lt;br /&gt;
function widget:UnitFromFactory(unitID, unitDefID, unitTeam, factoryID, factoryDefID, userOrders)&lt;br /&gt;
	--read from table how many units this factory already built&lt;br /&gt;
	local n = buildCount[factoryID]&lt;br /&gt;
&lt;br /&gt;
	--was the entry empty?&lt;br /&gt;
	if n == nil then					&lt;br /&gt;
		n = 0 --if yes, start counting from 0&lt;br /&gt;
	end&lt;br /&gt;
	n = n +1 --increase n by 1 (best comment ever)&lt;br /&gt;
	Spring.Echo (&amp;quot;This was unit number &amp;quot; .. n .. &amp;quot; from factory &amp;quot; .. factoryID)&lt;br /&gt;
	--store new buildCount for this factory&lt;br /&gt;
	buildCount[factoryID] = n&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
UnitFromFactory is basically the same as UnitFinished, but has the usefull &#039;&#039;factoryID&#039;&#039; parameter.&lt;br /&gt;
&#039;&#039;&#039;Why the if n == nil?&#039;&#039;&#039;&lt;br /&gt;
In Lua everything not initialized is nil (=nothing) and nil can not be used in any math. &lt;br /&gt;
&lt;br /&gt;
(n = n +1  is a math)&lt;br /&gt;
&lt;br /&gt;
Btw a shorter version could be:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;buildCount[factoryID] = (buildCount[factoryID] or 0) + 1&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==I made enough &amp;quot;hello world&amp;quot; widgets. What now?==&lt;br /&gt;
On [[Lua_Scripting]] the most important are the pages under &#039;&#039;&#039;GameState&#039;&#039;&#039; and &#039;&#039;&#039;Client&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
See these [[TestingYourGame|pro-tips]] to make testing less frustrating.&lt;br /&gt;
&lt;br /&gt;
While widgets are initially easiest to make, soon there is a problem:&lt;br /&gt;
widgets are for interface stuff. &lt;br /&gt;
&lt;br /&gt;
That means widgets usually need to either...&lt;br /&gt;
* ...draw something on the screen. (for example the health of Commander)&lt;br /&gt;
and/or&lt;br /&gt;
* ...give orders to units. (for example make Commander automatically run away from danger)&lt;br /&gt;
&lt;br /&gt;
Both graphics and the whole order-system can be bit tricky for starters.&lt;br /&gt;
Without graphics and orders, the awesomeness potential of a widget is small.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Pro tip:&#039;&#039;&#039; gadgets can be awesome without either!&lt;br /&gt;
&lt;br /&gt;
==go go gadgets time!==&lt;br /&gt;
We learned widgets can only &amp;quot;look at&amp;quot; the gamestate or do things that players can do, for example ordering units to attack another unit.&lt;br /&gt;
&lt;br /&gt;
On the other hand gadgets are scripts that are able to alter the state of the game.&lt;br /&gt;
With gadgets it is possible to implent new game logic like jumpjets, drop pods, tech tree systems, etc.&lt;br /&gt;
&lt;br /&gt;
Unlike widgets, gadgets must be [[Gamedev:Structure#LuaRules.5C|included in a game or in a map.]]&lt;br /&gt;
&lt;br /&gt;
To do so it is best to unpack the game file into an [[Gamedev:Archives|.sdd archive]]&lt;br /&gt;
&lt;br /&gt;
Writing gadgets is similiar to widgets, except the getInfo() header and callin functions are prefixed with &amp;lt;code&amp;gt;gadget:xxx&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;widget:xxx&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===synced &amp;amp; unsynced===&lt;br /&gt;
Gadgets are split into a synced and into an unsynced part.&lt;br /&gt;
&lt;br /&gt;
In simple terms that means the synced part is usually for controlling the game logic.&lt;br /&gt;
The unsynced part is for drawig graphics.&lt;br /&gt;
&lt;br /&gt;
For example look at this lava tide gadget:&lt;br /&gt;
&lt;br /&gt;
http://springrts.com/mediawiki/images/3/33/Beachbuggysuicidecult_lava_sync_unsync.gif&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;synced&#039;&#039;&#039; part is responsible for &#039;&#039;damaging/destroying the units&#039;&#039; in the lava. It actually alters the gamestate.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;unsynced&#039;&#039;&#039; part is only for &#039;&#039;drawing&#039;&#039; the graphic of the lava. The graphic itself does not influence the gamestate in any way.&lt;br /&gt;
&lt;br /&gt;
In code it looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
if (gadgetHandler:IsSyncedCode()) then&lt;br /&gt;
  --synced code&lt;br /&gt;
  ..&lt;br /&gt;
  damage all units that are underneath the lava tide level&lt;br /&gt;
  ..&lt;br /&gt;
else&lt;br /&gt;
  --unsynced code&lt;br /&gt;
  ..&lt;br /&gt;
  drawing the lava with GL-api functions&lt;br /&gt;
  ..&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Of course that also means that some functions or callins can only be used in synced or unsynced part. For example the synced part can not draw anything and the unsynced part can not spawn units.&lt;br /&gt;
&lt;br /&gt;
Sometimes it is nessecary to transfer some data/information &amp;quot;across the sync-unsynced border&amp;quot; - but the scope of variables is only in the part they were declared in.&lt;br /&gt;
In lava-exampe that might be the current height of lava.&lt;br /&gt;
How this still works is explained here: [[LuaTutorials::InterCommunications]]&lt;br /&gt;
&lt;br /&gt;
==Look at more examples==&lt;br /&gt;
Common hint for learning spring Lua is: &#039;&#039;&amp;quot;Look at some examples in other games.&amp;quot;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
But a spring game usually has dozen of wupdgets and only a few are useful examples for beginners. Many scripts deal with some very specifique problem or are just way too long.&lt;br /&gt;
Or one has to be familiar with the game to even understand what the script even does.&lt;br /&gt;
Or if one wants to use the wupdget in ones own game, suddendly nothing works anymore because it depends on so many configs or other files.&lt;br /&gt;
&lt;br /&gt;
Two simple examples are:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Linked units&amp;quot; (hub dies, child-units explode too)&lt;br /&gt;
http://springrts.com/phpbb/viewtopic.php?f=23&amp;amp;t=25435&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Moveable metal extractor&amp;quot;&lt;br /&gt;
http://springrts.com/phpbb/viewtopic.php?f=14&amp;amp;t=26877&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
	<entry>
		<id>https://springrts-wiki.p2004a.com/mediawiki/index.php?title=User:Knorke/Sandbox1&amp;diff=20866</id>
		<title>User:Knorke/Sandbox1</title>
		<link rel="alternate" type="text/html" href="https://springrts-wiki.p2004a.com/mediawiki/index.php?title=User:Knorke/Sandbox1&amp;diff=20866"/>
		<updated>2014-04-23T13:16:50Z</updated>

		<summary type="html">&lt;p&gt;Knorke: /* go go gadgets time! */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==What this is==&lt;br /&gt;
This page explains how to get started making scripts for spring.&lt;br /&gt;
&lt;br /&gt;
==What this is not==&lt;br /&gt;
This page does not explains how to make scripts for spring.&lt;br /&gt;
&lt;br /&gt;
This page is not a Lua tutorial.&lt;br /&gt;
&lt;br /&gt;
==Requirements==&lt;br /&gt;
* having played spring game for some days&lt;br /&gt;
* text editor with synthax coloring&lt;br /&gt;
* copy of [[SpringTutorialGame]]&lt;br /&gt;
* some small map because those load faster&lt;br /&gt;
* Spring set to [[Springsettings.cfg#Fullscreen|windowed mode]] for easier switching between editor/game&lt;br /&gt;
* a very bit familiar with programing (variables, functions, loops, arrays = enough)&lt;br /&gt;
* read through [[TestingYourGame|this tips page]] once&lt;br /&gt;
&lt;br /&gt;
==Wupget and friends==&lt;br /&gt;
In Spring games there are 3 kinds of Lua scripts.&lt;br /&gt;
Crude and simple explaination:&lt;br /&gt;
# gadgets: these are the &amp;quot;gameplay logic code.&amp;quot;&lt;br /&gt;
# widgets: these are for interface.&lt;br /&gt;
# unit scripts: animate units &amp;amp; controll their weapons.&lt;br /&gt;
&lt;br /&gt;
Making those 3 is not very different but widgets are the easiest to start with.&lt;br /&gt;
&lt;br /&gt;
There is also 4) functionality provided by the engine.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Also look at this:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
http://springrts.com/mediawiki/images/1/13/Gadgets_widgets_and_friends.png&lt;br /&gt;
&lt;br /&gt;
All 4 are in a constant fight against each other.&lt;br /&gt;
&lt;br /&gt;
==My first wupdget==&lt;br /&gt;
The [[SpringTutorialGame]] is simple and good for testing:&lt;br /&gt;
You can use any other game but some block player widgets or are very confusing.&lt;br /&gt;
&lt;br /&gt;
Create a txt file like this and there:&lt;br /&gt;
Spring\LuaUI\Widgets\myfirstwidget.lua&lt;br /&gt;
&lt;br /&gt;
and copypaste this text into it:&lt;br /&gt;
-----&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function widget:GetInfo()&lt;br /&gt;
  return {&lt;br /&gt;
    name      = &amp;quot;my first widget&amp;quot;,&lt;br /&gt;
    desc      = &amp;quot;this is so awesome&amp;quot;,&lt;br /&gt;
    author    = &amp;quot;horse 3000&amp;quot;,&lt;br /&gt;
    date      = &amp;quot;2009&amp;quot;,&lt;br /&gt;
    license   = &amp;quot;GNU GPL, v2 or later&amp;quot;,&lt;br /&gt;
    layer     = -10,&lt;br /&gt;
    enabled   = true&lt;br /&gt;
  }&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
-----&lt;br /&gt;
For now it does not matter what excactly this does but here you can put informations about your widget. &lt;br /&gt;
&lt;br /&gt;
What matters is that without such GetInfo() function Spring will not load the widget correctly.&lt;br /&gt;
(Since it takes up screen-space it will be left out when code is posted. Of course it must still be there.)&lt;br /&gt;
&lt;br /&gt;
Start spring.exe and press F11. The &amp;quot;widget menu&amp;quot; opens:&lt;br /&gt;
&lt;br /&gt;
http://springrts.com/mediawiki/images/8/80/Widget_F11menu.png&lt;br /&gt;
&lt;br /&gt;
It is likely already filled with some other widgets contained in the game.&lt;br /&gt;
Find your new widget in the list. Click on it to turn it on and off: The name in list should go green or red accordingly.&lt;br /&gt;
&lt;br /&gt;
If that works - congratulation: You made a new widget that does excactly nothing.&lt;br /&gt;
&lt;br /&gt;
=&amp;quot;Hello unit&amp;quot; wupdget=&lt;br /&gt;
Add the following at the end of myfirstwidget.lua:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function widget:UnitFinished(unitID, unitDefID, teamID)&lt;br /&gt;
	Spring.Echo (&amp;quot;a new unit was finished! It belongs to team &amp;quot; .. teamID)	&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
UnitFinished(...) is a [[Lua:Callins|callin function]] : Those are functions that the engine calls when certain events happen.&lt;br /&gt;
Captain Obvious has already figured out: This function gets called when a new unit is finished.&lt;br /&gt;
&lt;br /&gt;
Spring.Echo is used to output text to the chat/console.&lt;br /&gt;
So this widget should tell when a new unit is made.&lt;br /&gt;
&lt;br /&gt;
4)&lt;br /&gt;
Open the widget menu and disable then re-enable your widget: This will reload the widget.&lt;br /&gt;
Now build some units to test it.&lt;br /&gt;
&lt;br /&gt;
===Finding errors and infolog.txt===&lt;br /&gt;
For test add an error like this:&lt;br /&gt;
	Spring.Echo (100 + nil)&lt;br /&gt;
and reload the widget.&lt;br /&gt;
The widgets name is green but turns yellow as soon a unit is build: &amp;quot;nil&amp;quot; can not be used in math like that.&lt;br /&gt;
&lt;br /&gt;
The error is also displayed in chat and [[infolog.txt]]&lt;br /&gt;
In that logfile you can look up all errors even if they have disappeared from chat.&lt;br /&gt;
Fix the error, reload the widget and it is green again. Oha.&lt;br /&gt;
&lt;br /&gt;
FIXME: expand this&lt;br /&gt;
&lt;br /&gt;
===widget sees you and only you and your allies===&lt;br /&gt;
Even if there is a bot/other player building stuff, the widget will not notify on all  their new units if they are outside line of sight.&lt;br /&gt;
That is because widgets are limited in what they can &amp;quot;see.&amp;quot;&lt;br /&gt;
The widget only sees what what the player who is running the widget can see, too. This is to prevent cheating.&lt;br /&gt;
&lt;br /&gt;
==&amp;quot;Hello unit&amp;quot; 2 - with markers and advancement==&lt;br /&gt;
change the widget to this and guess what it does:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
function widget:UnitFinished(unitID, unitDefID, teamID)&lt;br /&gt;
	local x,y,z = Spring.GetUnitPosition (unitID)&lt;br /&gt;
	Spring.MarkerAddPoint (x,y,z, &amp;quot;a new unit! id=&amp;quot; .. unitID)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It adds a marker point on every new unit!&lt;br /&gt;
Note how the unitID parameter from UnitFinished() is passed to GetUnitPosition()&lt;br /&gt;
&lt;br /&gt;
===unitIDs===&lt;br /&gt;
Previous paragraph featured &#039;&#039;unitID&#039;&#039; variable.&lt;br /&gt;
Every unit, feature or weapon projectile in spring has an ID number:&lt;br /&gt;
&lt;br /&gt;
http://springrts.com/mediawiki/images/3/3c/Units_features_projectiles.png&lt;br /&gt;
&lt;br /&gt;
There are never two units with the same unitID at the same time. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;#YOLO?&amp;lt;/pre&amp;gt;&lt;br /&gt;
No YOLO: when a unit is destroyed its unitID might be reused later for a different unit.&lt;br /&gt;
&lt;br /&gt;
=a boring counter widget=&lt;br /&gt;
A counter that is increased when units are made:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
local counter = 0&lt;br /&gt;
function widget:UnitFinished (unitID, unitDefID, teamID)	&lt;br /&gt;
	counter = counter +1&lt;br /&gt;
	Spring.Echo (&amp;quot;now there are &amp;quot; .. counter .. &amp;quot; units&amp;quot;)&lt;br /&gt;
	if counter &amp;gt; 10 then&lt;br /&gt;
		Spring.Echo (&amp;quot;wow, more than 10 units!&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[TestingYourGame#Lua|Reload the widget]] and note how the counter gets reseted. &lt;br /&gt;
That is how widgets roll: Their variables get cleared on reload.&lt;br /&gt;
&lt;br /&gt;
===boring counter widget with tables===&lt;br /&gt;
Imagine you want a counter that stores for each factory how many units it has already produced. One variable will not be enought here but an array can store multiple things.&lt;br /&gt;
&lt;br /&gt;
Arrays in Lua are tables. Read about tables: http://lua-users.org/wiki/TablesTutorial&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
local buildCount = {}&lt;br /&gt;
function widget:UnitFromFactory(unitID, unitDefID, unitTeam, factoryID, factoryDefID, userOrders)&lt;br /&gt;
	--read from table how many units this factory already built&lt;br /&gt;
	local n = buildCount[factoryID]&lt;br /&gt;
&lt;br /&gt;
	--was the entry empty?&lt;br /&gt;
	if n == nil then					&lt;br /&gt;
		n = 0 --if yes, start counting from 0&lt;br /&gt;
	end&lt;br /&gt;
	n = n +1 --increase n by 1 (best comment ever)&lt;br /&gt;
	Spring.Echo (&amp;quot;This was unit number &amp;quot; .. n .. &amp;quot; from factory &amp;quot; .. factoryID)&lt;br /&gt;
	--store new buildCount for this factory&lt;br /&gt;
	buildCount[factoryID] = n&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
UnitFromFactory is basically the same as UnitFinished, but has the usefull &#039;&#039;factoryID&#039;&#039; parameter.&lt;br /&gt;
&#039;&#039;&#039;Why the if n == nil?&#039;&#039;&#039;&lt;br /&gt;
In Lua everything not initialized is nil (=nothing) and nil can not be used in any math. &lt;br /&gt;
&lt;br /&gt;
(n = n +1  is a math)&lt;br /&gt;
&lt;br /&gt;
Btw a shorter version could be:&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;buildCount[factoryID] = (buildCount[factoryID] or 0) + 1&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==I made enough &amp;quot;hello world&amp;quot; widgets. What now?==&lt;br /&gt;
On [[Lua_Scripting]] the most important are the pages under &#039;&#039;&#039;GameState&#039;&#039;&#039; and &#039;&#039;&#039;Client&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
See these [[TestingYourGame|pro-tips]] to make testing less frustrating.&lt;br /&gt;
&lt;br /&gt;
While widgets are initially easiest to make, soon there is a problem:&lt;br /&gt;
widgets are for interface stuff. &lt;br /&gt;
&lt;br /&gt;
That means widgets usually need to either...&lt;br /&gt;
* ...draw something on the screen. (for example the health of Commander)&lt;br /&gt;
and/or&lt;br /&gt;
* ...give orders to units. (for example make Commander automatically run away from danger)&lt;br /&gt;
&lt;br /&gt;
Both graphics and the whole order-system can be bit tricky for starters.&lt;br /&gt;
Without graphics and orders, the awesomeness potential of a widget is small.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Pro tip:&#039;&#039;&#039; gadgets can be awesome without either!&lt;br /&gt;
&lt;br /&gt;
==go go gadgets time!==&lt;br /&gt;
We learned widgets can only &amp;quot;look at&amp;quot; the gamestate or do things that players can do, for example ordering units to attack another unit.&lt;br /&gt;
&lt;br /&gt;
On the other hand gadgets are scripts that are able to alter the state of the game.&lt;br /&gt;
With gadgets it is possible to implent new game logic like jumpjets, drop pods, tech tree systems, etc.&lt;br /&gt;
&lt;br /&gt;
Unlike widgets, gadgets must be [[Gamedev:Structure#LuaRules.5C|included in a game or in a map.]]&lt;br /&gt;
&lt;br /&gt;
To do so it is best to unpack the game file into an [[Gamedev:Archives|.sdd archive]]&lt;br /&gt;
&lt;br /&gt;
Writing gadgets is similiar to widgets, except the getInfo() header and callin functions are prefixed with &amp;lt;code&amp;gt;gadget:xxx&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;widget:xxx&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===synced &amp;amp; unsynced===&lt;br /&gt;
Gadgets are split into a synced and into an unsynced part.&lt;br /&gt;
&lt;br /&gt;
In simple terms that means the synced part is usually for controlling the game logic.&lt;br /&gt;
The unsynced part is for drawig graphics.&lt;br /&gt;
&lt;br /&gt;
For example look at this lava tide gadget:&lt;br /&gt;
&lt;br /&gt;
http://springrts.com/mediawiki/images/3/33/Beachbuggysuicidecult_lava_sync_unsync.gif&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;synced&#039;&#039;&#039; part is responsible for &#039;&#039;damaging/destroying the units&#039;&#039; in the lava. It actually alters the gamestate.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;unsynced&#039;&#039;&#039; part is only for &#039;&#039;drawing&#039;&#039; the graphic of the lava. The graphic itself does not influence the gamestate in any way.&lt;br /&gt;
&lt;br /&gt;
In code it looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
if (gadgetHandler:IsSyncedCode()) then&lt;br /&gt;
  --synced code&lt;br /&gt;
  ..&lt;br /&gt;
  damage all units that are underneath the lava tide level&lt;br /&gt;
  ..&lt;br /&gt;
else&lt;br /&gt;
  --unsynced code&lt;br /&gt;
  ..&lt;br /&gt;
  drawing the lava with GL-api functions&lt;br /&gt;
  ..&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Of course that also means that some functions or callins can only be used in synced or unsynced part. For example the synced part can not draw anything and the unsynced part can not spawn units.&lt;br /&gt;
&lt;br /&gt;
Sometimes it is nessecary to transfer some data/information &amp;quot;across the sync-unsynced border&amp;quot; - but the scope of variables is only in the part they were declared in.&lt;br /&gt;
In lava-exampe that might be the current height of lava.&lt;br /&gt;
How this still works is explained here: [[LuaTutorials::InterCommunications]]&lt;br /&gt;
&lt;br /&gt;
==Look at more examples==&lt;br /&gt;
Common hint for learning spring Lua is: &#039;&#039;&amp;quot;Look at some examples in other games.&amp;quot;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
But a spring game usually has dozen of wupdgets and only a few are useful examples for beginners. Many scripts deal with some very specifique problem or are just way too long.&lt;br /&gt;
Or one has to be familiar with the game to even understand what the script even does.&lt;br /&gt;
Or if one wants to use the wupdget in ones own game, suddendly nothing works anymore because it depends on so many configs or other files.&lt;br /&gt;
&lt;br /&gt;
Two simple examples are:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Linked units&amp;quot; (hub dies, child-units explode too)&lt;br /&gt;
http://springrts.com/phpbb/viewtopic.php?f=23&amp;amp;t=25435&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Moveable metal extractor&amp;quot;&lt;br /&gt;
http://springrts.com/phpbb/viewtopic.php?f=14&amp;amp;t=26877&lt;/div&gt;</summary>
		<author><name>Knorke</name></author>
	</entry>
</feed>