Persistent build spacing
Posted: 07 Sep 2011, 01:02
Hi everyone,
I had some free time and decided to program a Lua widget that keeps track of the last chosen build spacing for each building. Next time we request to build the same building, the last chosen build spacing for that building will be automatically restored for us. As well, build spacing settings are stored in a separate file for each game once the game is over, so we can keep build spacing settings for every game. Finally, the widget allows to use the mouse well + shift for changing build spacing... nice logitech mouses have wheels that can turn pretty fast My 4th and 5th mouse buttons are not recognized in my Spring under Ubuntu, so this does the trick.
Well, with no more delay, here you are the source code:
This is my first experience with Lua, so I'm open to suggestions. It is not my first programming experience, though... I've already programmed in Java, C++, C, Perl, PASCAL, BASIC, Logo, LISP, Prolog, and other languages that I don't even recall.
Things that I don't like about this widget:
- it assumes build spacing is set to 0 upon game start, then simply catches key and mouse events that trigger a change in build spacing in order to keep a build spacing counter up to date. Failing to catch some of those keystrokes will result in a strange behavior. It would be nicer to be able to catch buildspacing inc/dec commands, or even nicer to be able to read/write the buildspacing variable inside the spring engine!! However, I did not find a way of doing so, so each one must modify the script for ensuring that every key/mouse event modifying build spacing is caught and properly treated, depending on your own configurations (uikeys.txt and widgets).
- finally, the build spacing settings are stored upon game over; however, if the player exits by pressing ESC + QUIT then the settings are not recorded. A callin function catching the game exiting should be used instead, but I neither found such feature.
So, enjoy this widget and Spring forever!!
DrHash
I had some free time and decided to program a Lua widget that keeps track of the last chosen build spacing for each building. Next time we request to build the same building, the last chosen build spacing for that building will be automatically restored for us. As well, build spacing settings are stored in a separate file for each game once the game is over, so we can keep build spacing settings for every game. Finally, the widget allows to use the mouse well + shift for changing build spacing... nice logitech mouses have wheels that can turn pretty fast My 4th and 5th mouse buttons are not recognized in my Spring under Ubuntu, so this does the trick.
Well, with no more delay, here you are the source code:
Code: Select all
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--
-- file: gui_persistent_build_spacing.lua
-- brief: Recalls last build spacing set for each building and game, and allows to modify build spacing with mouse wheel + shift
-- author: DrHash
-- version: 1.00
--
-- Copyright (C) 2011.
-- Licensed under the terms of the GNU GPL, v3 or later.
--
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
function widget:GetInfo()
return {
name = "Persistent Build Spacing",
desc = "Recalls last build spacing set for each building and game, and allows to modify build spacing with mouse wheel + shift",
author = "DrHash",
date = "Sep 6, 2011",
license = "GNU GPL, v3 or later",
layer = 0,
enabled = true -- loaded by default?
}
end
local buildSpacingTable = {}
local defaultBuildSpacing = 0
local currentBuildSpacing = 0
local lastActiveCommandId = nil
local currentBuildingCode = nil
local GetActiveCommand = Spring.GetActiveCommand
local Echo = Spring.Echo
local SendCommands = Spring.SendCommands
local pathToSave = "LuaUI/Widgets/BuildSpacing/" -- where to store build spacing presets
local filename
function LoadBuildSpacingTable(file)
local buildCode, buildSpacing, i, j
local line = file:read()
while (line) do
i, j = string.find(line, ", ")
if (not i) then break end
buildCode = string.sub(line, 1, i - 1)
buildSpacing = tonumber(string.sub(line, j + 1))
buildSpacingTable[buildCode] = buildSpacing
line = file:read()
end
end
local function SaveBuildSpacingTable(file)
local buildCode, buildSpacing
for buildCode, buildSpacing in pairs(buildSpacingTable) do
file:write(buildCode .. ", " .. buildSpacing .. "\n")
end
end
-- Load last saved build spacing table for current game, if present
function widget:Initialize()
-- if Spring.GetSpectatingState() or Spring.IsReplay() then
-- Echo("Persistent Build Spacing widget widget disabled for spectators")
-- widgetHandler:RemoveWidget()
-- end
Spring.CreateDir(pathToSave)
local modShortName = Game.modShortName
filename = (pathToSave .. modShortName .. ".txt")
local file = io.open(filename,'r')
if file then
Echo("Build spacing table detected for " .. modShortName .. " - loading...")
LoadBuildSpacingTable(file)
file:close()
end
end
-- Upon game over, save the build spacing table; however, if you exit the game with ESC + QUIT, build spacing will not be stored!!
-- Is there some alternative callin function??
function widget:GameOver()
local file = io.open(filename,'w')
if file then
Echo("Saving build spacing table to " .. filename);
SaveBuildSpacingTable(file)
file:close()
end
end
-- Keep track of a build spacing increment
function noticeBuildSpacingInc()
currentBuildSpacing = currentBuildSpacing + 1
if (currentBuildingCode) then
buildSpacingTable[currentBuildingCode] = currentBuildSpacing
end
end
-- Keep track of a build spacing decrement
function noticeBuildSpacingDec()
if (currentBuildSpacing > 0) then
currentBuildSpacing = currentBuildSpacing - 1
if (currentBuildingCode) then
buildSpacingTable[currentBuildingCode] = currentBuildSpacing
end
end
end
-- Allow mouse wheel + shift to change build spacing
function widget:MouseWheel(up, value)
local alt,ctrl,meta,shift = Spring.GetModKeyState()
if (shift) then
if (up) then
Spring.SendCommands("buildspacing dec")
noticeBuildSpacingDec()
else
Spring.SendCommands("buildspacing inc")
noticeBuildSpacingInc()
end
return true
end
return false
end
-- Sets build spacing as stored for the current selected building, or to the default spacing in case none defined
function setBuildSpacing()
local storedBuildSpacing = buildSpacingTable[currentBuildingCode]
if (not storedBuildSpacing) then
buildSpacingTable[currentBuildingCode] = defaultBuildSpacing
storedBuildSpacing = defaultBuildSpacing
end
while (storedBuildSpacing > currentBuildSpacing) do
Spring.SendCommands("buildspacing inc")
currentBuildSpacing = currentBuildSpacing + 1
end
while (storedBuildSpacing < currentBuildSpacing) do
Spring.SendCommands("buildspacing dec")
currentBuildSpacing = currentBuildSpacing - 1
end
end
-- Resets build spacing to the predefined value for the last building that has been chosen to build
-- but allows to manually modify build spacing afterwards, and the new build spacing will be recalled later
function widget:DrawScreen()
local _, currentActiveCommandId, _, currentActiveCommandName = GetActiveCommand()
-- currentActiveCommandId >= 0 for commands other than those that build buildings
if (not currentActiveCommandId) or (currentActiveCommandId >= 0) or (currentActiveCommandId == lastActiveCommandId) then
return
end
lastActiveCommandId = currentActiveCommandId
currentBuildingCode = currentActiveCommandName
setBuildSpacing()
end
-- This keeps build spacing counter up to date upon pressing mouse buttons 4 or 5
-- Note build spacing is modified by those buttons when widget gui_buildspacing.lua is active (it is by default as for BA version 7.50)
-- If you use these buttons for other purposes, remove or comment this function
--[[
function widget:MousePress(mx, my, button)
if (button == 4) then
noticeBuildSpacingInc()
elseif (button == 5) then
noticeBuildSpacingDec()
end
return false
end
--]]
--Uncomment the remaining code if you also use keys for changing build spacing
--If you use other keys than Z or X, simply replace KEYSYMS.Z and KEYSYMS.X by the corresponding key codes
--[[
include("keysym.h.lua")
function widget:KeyPress(key, modifier, isRepeat)
if (key == KEYSYMS.Z) then
noticeBuildSpacingInc()
elseif (key == KEYSYM.X) then
noticeBuildSpacingDec()
end
end
--]]
Things that I don't like about this widget:
- it assumes build spacing is set to 0 upon game start, then simply catches key and mouse events that trigger a change in build spacing in order to keep a build spacing counter up to date. Failing to catch some of those keystrokes will result in a strange behavior. It would be nicer to be able to catch buildspacing inc/dec commands, or even nicer to be able to read/write the buildspacing variable inside the spring engine!! However, I did not find a way of doing so, so each one must modify the script for ensuring that every key/mouse event modifying build spacing is caught and properly treated, depending on your own configurations (uikeys.txt and widgets).
- finally, the build spacing settings are stored upon game over; however, if the player exits by pressing ESC + QUIT then the settings are not recorded. A callin function catching the game exiting should be used instead, but I neither found such feature.
So, enjoy this widget and Spring forever!!
DrHash