this page contains various spring related scripts / projects i was working on. they might inspire you hopefully


more screenshots:


since there was no cross platform linux lobby client and the other linux client sucked (it is called springlobby). i decided to write one using qt from scratch:

two friends soon joined my effort and we got quite far with our project. we stopped working on it because:

  • the lobby protocol (xml like protocol) but much more fuzzy sucks
  • rewriting this would require also rewiring the server application
  • a rewrite of the server application was out of scope
  • i would have liked to rewrite this as a p2p project but i did not have enough time nor support

in the end it was a great experience and we found a few new interesting programming principles and i learned how to do async network programming (mentioned here: which is not hard to do but requires certain design decisions!


sourcecode see here:

spring map converter (without GL and X enforcement)

what is it?

texcompress code - generates mipmaps & compresses them using
the compressed_rgba_s3tc_dxt1_ext opengl standard


since i wanted to generate maps and convert them to the final format
without having to run a X instance using 3d drivers

see [6] for code.

spring random map generator

some time ago i tested how well random map generation is suited for rts games. my current results can be seen at [5]. i will finish my custom random procedural map generator soon and it will help to you to build maps with just a few clicks even if you never did that before. parts of the interface as the 'noise-view' can be seen on [5] already. more coming soon.

2009-07-05 work still going on

spring map downloader scripts

How to use?

tar xf springmaps-0.0.1.tar
cd springmaps-0.0.1

formulas for spring map making

size factors in spring for maps are given in 1x1 2x2 3x3 SpringUnits (short SU) ... and so on. meaning the size is represented in this 4 images which are calculated like this:

1 SU (spring unit) = 512 pixels (TextureMap -> meaning texture.png) Different images sizes have to be computed for every texture (meaning texture.png, height.png, metal.png, feature.png)

Compute the textures like this (consider a map with x*y SU):

texture.png   x*512   x   y*512      24-bit
height.png    x*64+1  x   y*64+1     8-bit grayscale, non-interlaced
metal.png     x*32+1  x   y*32+1     8-bit grayscale, non-interlaced
feature.png   x*64    x   y*64       8-bit/color RGB, non-interlaced

Water Height: Mapconv vs. Heightmap (copied from spring wiki)

The Problem: It has come up as a source of confusion as to what shade of grey in your heightmap is water level. The simple answer is that there isn't a simple answer, but don't worry it really isn't all that hard. It is determined by your height input parameters to mapconv (Does none of this make sense? You probably want to stop here, go back and read some of the tutorials. ) Note this assumes you have both 0% and 100% grey (black and white, respectively) on your heightmap, which should be the case (this maximises the range of greys you can play with for your heightmap)

the -x value in mapconv is the altitude (in elmos?) of a 100% white surface the -n value is the altitude of a 0% white surface To find the altitude of an intermediate shade of grey, do this, n+(y*(x-n)) = a or, simplified, y*x + (1-y)*n = a Where y is your value (in percent or in RGB value / 255) x and n are the parameters from mapconv and a is the altitude of that value The water level is always assumed to be 0 in mapconv, so anything with a negative a value will be underwater.

An Example

So to make 50% grey underwater, you could for example set your water line at 55% grey. Then, some values for mapconv that would work are: -x 82 -n -100 <- this would produce very low mountains -x 205 -n -250 <- this would probably be better

note on spring-lua scripting

Docu can be found here:

/usr/share/games/spring/docs/lua_ui_interface.txt which has been renamed to API.txt and can be found: /usr/share/games/spring/LuaUI/API.txt

start lua ui inside spring

Here is how to start the lua ui inside spring with the command shell:

 Added LuaUI v0.1 (with widget management code, somewhat experimental)
(requires the LuaUI setting to be on to be autoloaded,
"/luaui disable" to disable in-game
"/luaui reload" to load in-game
"/luaui reload fresh" to load in-game, but with fresh state)

start lua ui by default (in linux)

Enable it in ~/.springrc


And create a symlink like this:

ln -s /usr/share/games/spring/LuaUI ~/.spring/

If you want to develop you need of course read/write support so then copy the files rather symlinking them:

cp -r /usr/share/games/spring/LuaUI ~/.spring/

Be warned that if you copy all the files spring has it twice because LuaUI is loaded from two sources then:

41 $ cat /etc/spring/datadir



so overwriting will work but you might get some strange results because scripts are loaded twice with different scripts (if one is modified).

Better use your own scripts while not copying all LuaUI/ files.

directory structure

maybe this is not complete, but might give you an idea anyway:

first have a look here:

du -a /usr/share/games/spring/LuaUI/

in case you installed spring somewhere else, adapt your path as needed.


- /
- Sounds/
- Widgets/
- .../ (and others)

If you want to create a custom widget, you have to use the same directory strucutre. So do:

mkdir -p ~/.spring/LuaUI/Widgets touch ~/.spring/LuaUI/Widgets/cmd_firstscript.lua

how to add a custom lua script

First of all, there are three kind of lua scripts you can have:

  • a script that is started right on gamestart called: commander script
  • a script that is run from the gui (nearly all scripts are)
  • a script that is run from the ingame 'command line'

We will have a look at the third kind of script:


$ cat -n cmd_firstscript.lua
    1  --------------------------------------------------------------------------------
    2  -- first register this function in the F11 lua menu
    3  -- next try if it's working by typing a lua command spring understands
    4  --   /luaui lucmd Spring.Echo("it is working")
    5  -- you should see a line in the spring console that says the text from above
    6  --
    7  --------------------------------------------------------------------------------
    9  function widget:GetInfo()
   10    return {
   11      name      = "FLUX_LuaCmd",
   12      desc      = "Low level access to lua commands",
   13      author    = "qknight",
   14      date      = "Jan 2, 2008",
   15      license   = "GNU GPL, v2 or later",
   16      layer     = 1,     --  after the normal widgets
   17      enabled   = false  --  loaded by default?
   18    }
   19  end
   21  --------------------------------------------------------------------------------
   23  local function LuaCmd(cmd, line, words)
   24    local wc = #words
   26    local lua_call,err = loadstring(line)
   27    assert(lua_call,err)
   29    -- now we call what was given by string
   30    lua_call()
   32    return true
   33  end
   35  --------------------------------------------------------------------------------
   37  function widget:Initialize()
   38    widgetHandler:AddAction("luacmd", LuaCmd)
   39  end
   41  --------------------------------------------------------------------------------

Let's have a look at this script:

First note line 9 to 19 which helps the widget to recognize some script parameters. Adapt those in your own script first. Keep the 'name' uniq because else your script might be 'shadowed' by another script and you would keep wondering why the script doesn't work as you edit the file. This is because spring might use the other script only and your script is never run.

Next have a look at line 37 to 39, which registers the function 'luacmd' to the luaui environmen. You need this in order to access the script from within spring command line. Type:

/luaui luacmd Spring.Echo("hello world")

in spring. And you will get the "hello world" string in spring if everything is working. If not either LuaUI is disabled in the configuration -> if F11 shows a dialog for lua scripts it is enabled and this is not your problem. If you can find your script in the list invoced by F11 you have to check if it's green.

Also note that line 38 referes to the function on line 23, so whenever you want to register a function to /luaui in spring you have to use the code from line 37-39 and luaui will wrap the call to your registered script.

Another point to mention is on line 37:

   23  local function LuaCmd(cmd, line, words)
  • 'cmd' contains the command, in this case it's: luacmd
  • 'line' contains the rest of the command: example
    • "/luaui luacmd foo bar". line would contain: "foo bar" then.
  • and words contains how many words are in line, separated by ' '.

you can now bind a shortcut to your custom script

/bind a+g luaui luacmd Spring.Echo("hello") to call the luaui script with function flux on CTRL+G or ALT+G or *+G ;-)

You can bind any lua command you want.

replacement for UnitFromFactory

Using factories with groups this script will place all none builder units in the same group as the factory but all others not (different to the standard where all units are placed in the same group). The advantage is that the builders won't be interrupted using the group.

joachim@Z3:~/.spring/LuaUI/Widgets 31 $ cat unit_factory_ungroup_guard.lua | sed -e 's/^/ /g'

--  file:    unit_factory_guard.lua
--  brief:   assigns new builder units to guard their source factory
--  author:  Dave Rodgers
--  Copyright (C) 2007.
--  Licensed under the terms of the GNU GPL, v2 or later.

function widget:GetInfo()
  return {
    name      = "FactoryGuardUnGroup",
    desc      = "Assigns new builders to assist their source factory, removes them from their factory group",
    author    = "trepan,qknight",
    date      = "Feb 28, 2007",
    license   = "GNU GPL, v2 or later",
    layer     = 0,
    enabled   = false  --  loaded by default?



local OrderUnit = Spring.GiveOrderToUnit

-- find out in which group the factID is (if in any)
-- also find out in which position the unitID has in the table
function SearchGroupForUnitID(unitID, unitIDsgroupID, unitIDPosition)
  groupList, count = Spring.GetGroupList()
  for g, c in pairs(groupList) do
    uTable = Spring.GetGroupUnits(g)
    uTable.n = nil
    --print('> Now searching for unit' .. unitID .. ' in Group' .. g)
    for uid,udid2 in pairs(uTable) do
      --print('> ', uid, udid2)
      if (udid2 == unitID) then
        unitIDsgroupID = g
        unitIDPosition = uid
        --print('> ' .. udid2 .. ' in group ' .. unitIDsgroupID .. ' on position ' .. unitIDPosition)
        return unitIDsgroupID, unitIDPosition;

function widget:UnitFromFactory(unitID, unitDefID, unitTeam,
                                factID, factDefID, userOrders)
  if (unitTeam ~= Spring.GetMyTeamID()) then
    return -- not my unit
  if (userOrders) then
    return -- already has user assigned orders
  local bd = UnitDefs[factDefID]
  if (not (bd and bd.isFactory)) then
    return -- not a factory
  -- can this unit assist?
  local ud = UnitDefs[unitDefID]
  if (ud and ud.builder and ud.canAssist) then

  local unitIDsgroupID = nil
  local unitIDPosition = nil

  unitIDsgroupID, unitIDPosition = SearchGroupForUnitID(unitID, unitIDsgroupID, unitIDPosition)

  if (unitIDsgroupID) then
    -- save current selection -> group
    local selUnits = Spring.GetSelectedUnits()

    -- remove builders from the factory group
    Spring.SendCommands({"group " .. unitIDsgroupID})
    local GroupUnitToRemove = Spring.GetSelectedUnits()

    --> remove unit

    Spring.SendCommands({"group " .. unitIDsgroupID .. " set"})

    -- restore old selection -> group

  -- set builders to guard/assist their factories
  local x, y, z = Spring.GetUnitPosition(factID)
  OrderUnit(unitID, CMD_MOVE,  { x + 100, y, z + 100 }, { "" })
  OrderUnit(unitID, CMD_MOVE,  { x + 100, y, z },       { "shift" })
  OrderUnit(unitID, CMD_GUARD, { factID },              { "shift" })


Powered by MediaWiki