Unit E-Stall Gadget

Unit E-Stall Gadget

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

Moderator: Moderators

Post Reply
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Unit E-Stall Gadget

Post by Argh »

Um, here's my first LUA script that I've been able to get working, based heavily on Licho's work for CA. It works, as-is, but I'd like some assistance getting it working exactly as I want it to (please see comments, below).

Code: Select all

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--
--  file:    unit_estall_disable.lua
--  brief:   disables Units during energy stall
--  author:  Argh
--
--  Copyright (C) 2007.
--  Licensed under the terms of the GNU GPL, v2 or later.  Based on GPL code written by Licho for CA mod.
--
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

function gadget:GetInfo()
  return {
    name      = "UnitEstall",
    desc      = "Deactivates Units during energy stall",
    author    = "Argh",
    date      = "30.7.2007",
    license   = "GNU GPL, v2 or later",
    layer     = 0,
    enabled   = true  --  loaded by default?
  }
end

--------------------------------------------------------------------------------
if (gadgetHandler:IsSyncedCode()) then
--------------------------------------------------------------------------------
--  SYNCED
--------------------------------------------------------------------------------

--Speed-ups

local insert            = table.insert
local GiveOrderToUnit	= Spring.GiveOrderToUnit
local GetUnitStates	= Spring.GetUnitStates
local GetUnitTeam		= Spring.GetUnitTeam
local GetUnitResources	= Spring.GetUnitResources

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

local units = {}
local disabledUnits = {}
local canShutDownDefs = {
-------------------------------
----------------------------------------insert your Units into this list here, just dummy code
	[ UnitDefNames['yourUnitName'].id ] = true,
----------------------------------------
--------------------------------
}

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

function gadget:Initialize()
  for _,unitID in ipairs(Spring.GetAllUnits()) do
    local unitDefID = Spring.GetUnitDefID(unitID)
		AddUnit(unitID, unitDefID)
	end
end


function AddUnit(unitID, unitDefID) 
  if (canShutDownDefs[unitDefID]) then
		units[unitID] = unitDefID
  end
end

function gadget:UnitCreated(unitID, unitDefID)
	AddUnit(unitID, unitDefID)
end

function gadget:UnitTaken(unitID, unitDefID)
	AddUnit(unitID, unitDefID)
end

function gadget:UnitDestroyed(unitID)
  units[unitID] = nil
end

function gadget:GameFrame(n)
  if ((n % 61) < 0.1) then
		local teamEnergy = {}
		local temp = Spring.GetTeamList() 
		for _,teamID in ipairs(temp) do 
			local eCur, eMax, eUse, eInc, _, _, _, eRec = Spring.GetTeamResources(teamID, "energy")
			teamEnergy[teamID] = eCur - eUse + eInc
		end 
		
		for unitID,unitDefID in pairs(units) do
			local _, _, _, eu =	GetUnitResources(unitID)

			local disabledUnitEnergyUse = disabledUnits[unitID] 
			if (disabledUnitEnergyUse~=nil) then -- we have disabled unit
				local unitTeamID = GetUnitTeam(unitID)
				if (disabledUnitEnergyUse < teamEnergy[unitTeamID]) then  -- we still have enough energy to reenable unit
					disabledUnits[unitID]=nil
					GiveOrderToUnit(unitID, CMD.ONOFF, { 1 }, { })    -- turns Units back ON and sends Activatesc() function call to COB
  					Spring.SetUnitHealth(unitID, { paralyze = -1})    -- turns Units back on again
					teamEnergy[unitTeamID] = teamEnergy[unitTeamID] - disabledUnitEnergyUse
				end
			else -- we have non-disabled unit
				if (eu == 0) then -- there is not enough energy to keep unit running (its energy use auto dropped to 0), we will disable it 
					if (GetUnitStates(unitID).active) then  -- only disable "active" unit
						GiveOrderToUnit(unitID, CMD.ONOFF, { 0 }, { })	-- turns Units OFF and sends Deactivatesc() function call to COB
  						Spring.SetUnitHealth(unitID, { paralyze = 1.0e9 })    -- turns Units off
						disabledUnits[unitID] = UnitDefs[unitDefID].energyUpkeep
					end				
				end
			end
		end
	end
end


function gadget:AllowCommand(unitID, unitDefID, teamID, cmdID, cmdParams, cmdOptions)
	if (cmdID == CMD.ONOFF and disabledUnits[unitID]~=nil) then
    return false
  else 
		return true
	end
end
 
  
--------------------------------------------------------------------------------
--  END SYNCED
--------------------------------------------------------------------------------
end
Ok, so here's what's not quite perfect about the script:

1. I think running it every game frame is excessive. I understand that the code section here:

Code: Select all

function gadget:GameFrame(n)
  if ((n % 61) < 0.1) then
Is responsible for how often it runs, but I'm not sure what (n % 61) < 0.1) means here, and how to adjust it. I'd like to run this no more than once every 15 game frames (every SlowUpdate). Is there a way to do this?

2. I want to shut down everything that's defined in my list, if Energy goes below X level, not just a few things, based on where in the stack they are, and how much Energy is still present. This is because of Spring's stupid, "I can't go below zero" economy, which I've complained at length about elsewhere. Is there any way to do this? I can live with it waiting another SlowUpdate before getting whatever % of Units didn't qualify, but I want everything to come to a screeching halt until Energy levels rise above X level again, and stay there. The way that this script works now, only about 60-75% of the Units will shut down, even if I set up an incredibly-large Energy drain! That's unacceptable.

3. Having tested this script, it works great... unless you CTRL-Z all of the stunned Units. Then it results in massive slowdown and lots of hard-drive churning! I think this is because it's the code for replays again, recording all of the ON/OFF states as a "command" through the UI, and it's incredibly annoying. Is there any way to shut this off? I mean, I obviously must run this code synched... is there a way to tell the Replay recorder to ignore this "command" from the UI?

Um, that's about it. I'd imagine that fixing the timing's the easy one, but any help I can get for the other two issues would be much-appreciated.
User avatar
AF
AI Developer
Posts: 20687
Joined: 14 Sep 2004, 11:32

Post by AF »

Code: Select all

(n % 61) < 0.1
This makes no sense.

n being the game frame is a whole number, an integer.

If n was 60 then n%61 == 60
If n was 61 then n%61 == 0
If n was 62 then n%61 == 1


Its basically the remainder left over e.g. 5/2 == 2 remainder 1, 5%2 == 1

So basically that if condition can never be satisifed, you have found a bug.

Code: Select all

local canShutDownDefs = { 
------------------------------- 
----------------------------------------insert your Units into this list here, just dummy code 
   [ UnitDefNames['yourUnitName'].id ] = true, 
---------------------------------------- 
-------------------------------- 
}
Look at the other gadgets and youll see they load definition data from a seperate lua file in a configs directory that defines a table then returns it as if it were a function, then uses an include function to retrieve the table. Using that method seems cleaner than this one as it seperates the gadgets function code form its mod specific code.

Also as I seeit you want all units to stop when below a certain value. This gadget instead disables all untis of a certain type individually if they arent disabled already untill theres enough energy. Its just a matter fo identifying the calculation and the if statements that do this in GameUpdate and removing them and replacing with something else.

Basically

if(energystored < x and energyincome is negative)
disbale all units for 61 frames
else
enable them all
end
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

Code: Select all

(n % 61) < 0.1
Er, I didn't write that, and it works, so I dunno what to tell ya. % is the divisor symbol in LUA, eh? Does Spring start that count, n, over after X numbers of game frames? Or does it never restart? I'm very confused... can't we just say:

Code: Select all

function gadget:GameFrame(n)
if n / 60 == 1
To wait 60 frames? Or am I missing something basic here, about the way frames are counted? Can I do a for-->next, where for every 60 n, then we re-check?

As for the config... that's actually pretty straightforwards, I'll do it that way. I started with Licho's code, where he did it this way, though.
Kloot
Spring Developer
Posts: 1867
Joined: 08 Oct 2006, 16:58

Post by Kloot »

% is the modulo operator, so n % 61 will be 0 when n is 61, 1 when n is 62, etc. Thus n % 61 < 0.1 is only true if n is zero or an integer multiple of 61.
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

Ok, so you're basically saying that this only runs every 60 frames? That might explain some things!

Next off... what about the HD churn when lots of Units are being stunned by this? Any way to address this? Can I hide the ON/OFF state button, or do other things to prevent this from happening? I don't want, or care, if users can manually turn these things ON/OFF, frankly. And the amount of churn is directly related to how many Units are being stunned- and it only occurs when they're selected...
User avatar
AF
AI Developer
Posts: 20687
Joined: 14 Sep 2004, 11:32

Post by AF »

You seem to be the only person with that HD chug problem. Your HD is either ancient or it has a cr*ppy antivirus installed on it(you dont have several in operation do you?), or you've set a tiny page file, whereas it should be 3x your ram minimum, and at least 4096 for a hefty gaming PC minimum regardless of ram size.
User avatar
Neddie
Community Lead
Posts: 9406
Joined: 10 Apr 2006, 05:05

Post by Neddie »

Well, Argh, if you're tackling LUA, I have no excuse not to be doing the same.

I need to turn up my page file as well.
heze
Posts: 38
Joined: 28 Apr 2005, 23:32

Post by heze »

AF wrote:you've set a tiny page file, whereas it should be 3x your ram minimum, and at least 4096 for a hefty gaming PC minimum regardless of ram size.
Adding more swap space doesn't make swapping more efficient as far as I know. So depending what you run on your computer, you barely need a gig of swap. (I actually never have stuff in my swap file, 2G real mem).

Such a large swap file is only usable if someone runs programs worth of say 3G that aren't needed at all while playing so they can be swapped out to make room for Spring. That's a very rare situation and who has it, basically knows to have enough swap. :P

Or am I wrong?
User avatar
AF
AI Developer
Posts: 20687
Joined: 14 Sep 2004, 11:32

Post by AF »

It makes the entire swap algorithms setup mor efficient.

Look at metalmakers and storage and the metalmaker widget AI.

You dont need mass storage for it to work but the more storage capacity you have the more efficient the algorithm the more metal is produced.
User avatar
KDR_11k
Game Developer
Posts: 8293
Joined: 25 Jun 2006, 08:44

Post by KDR_11k »

Swapping becomes the most effective if you put the swap file on a ramdisk. Bizare but true.
User avatar
Argh
Posts: 10920
Joined: 21 Feb 2005, 03:38

Post by Argh »

I think I solved that, by installing a different AV. The only thing left is shutting down everything, but I can probably achieve the right result by jiggering the math check to make it higher than zero.
User avatar
AF
AI Developer
Posts: 20687
Joined: 14 Sep 2004, 11:32

Post by AF »

if you do that then for ever 61 frmes itll execute 60 times
Masure
Posts: 581
Joined: 30 Jan 2007, 15:23

Post by Masure »

Hi argh,

I tried your script but I got an error on line 14 on game start. Something like "assign an incorrect value to gadget (nil value)". I'm not a lua scripter, so I can't correct it myself.

I copy pasted all your script in LUA/Widgets/unit_estall_disable.lua
User avatar
Acidd_UK
Posts: 963
Joined: 23 Apr 2006, 02:15

Post by Acidd_UK »

KDR_11k wrote:Swapping becomes the most effective if you put the swap file on a ramdisk. Bizare but true.
It's not bizarre at all - the swap file is used when you run out of RAM, it's used to store memory pages that don't fit in main memory (RAM). As such, if you have spare RAM for a RAM drive, then you're better off using it as RAM, rather than as a RAM drive to store the swap file, because it's an unnecessary overhead.
User avatar
Snipawolf
Posts: 4357
Joined: 12 Dec 2005, 01:49

Post by Snipawolf »

Whoo, I may be able to use this on the third race.. Which is currently..

WAAAAAAYYYYYYYY off on the horizon -_____-
Post Reply

Return to “Lua Scripts”