addCpus command keeps crashing game


Recommended Posts

I'm trying to give tags a small per-turn upkeep cost by modifying the simunit.onStartTurn function, like so:

 

local oldOnStartTurn = simunit.onStartTurn
local tagUpkeepCost = 5

function simunit:onStartTurn( sim )
	local tagUpkeepCost = 5
	local player = sim:getCurrentPlayer()
	if player:isPC() then
		for _, unit in pairs( sim:getAllUnits() ) do 
			if unit:getTraits().isGuard and unit:getTraits().tagged then
				if player:getCpus( ) >= tagUpkeepCost then
					player:addCpus(-tagUpkeepCost);
				else
					unit:setTagged(true)
				end
			end
		end	
	end

	oldOnStartTurn( self, sim )
end

 

At the start of each agency turn this checks all guards for tags.  For each tagged guard it checks to see if the agency can pay the upkeep, then takes the PWR if it can or destroys the tag if it can't.

This is MOSTLY working - tags are removed properly - but the game keeps crashing whenever the addCpus function is called:

 

Jul 23 20:04:24 -- Sim returned:
BrokenStrats/tag_upkeep.lua:33: attempt to call method 'addCpus' (a nil value)

stack traceback:
	BrokenStrats/tag_upkeep.lua:33 in function 'onStartTurn'
	game/sim/simplayer.lua:510 in function 'onStartTurn'
	game/sim/pcplayer.lua:174 in function 'onStartTurn'
	game/sim/engine.lua:2068 in function 'endTurn'
	game/sim/aiplayer.lua:448 in function 'thinkHard'
	game/sim/engine.lua:2109 in function 'applyAction'
	game/client/states/state-game.lua:362 in function <game/client/states/state-game.lua:359>

Jul 23 20:04:24 -- PerformSync() - unverified build.
Jul 23 20:04:24 -- [LUA] HTTP 0: 0 bytes (Unspecified error.) 
Jul 23 20:04:32 --    TEXTURE: '+'      20628 = 408.91MB < 

 

It seems to like the getCpus function just fine, though, so I'm not sure what's going on.  Any ideas?

invisibleinc.txt

tag_upkeep.lua

Link to comment
Share on other sites

[facepalm] How did I miss THAT?  Okay, fixed.  Thanks.

But now I'm getting a different problem.  Power is being deducted appropriately, only when the agency has enough to spare.  But the tag is removed every turn even when the upkeep is payed.  Apparently the else clause is triggering when it isn't supposed to.

Link to comment
Share on other sites

I figured it out.  For some reason I thought the code would only work once at the start of the agency's turn instead of once per agency unit.  And agency units meant not only my agents but every device I had captured.  I had a high upkeep cost for testing purposes and kept paying it over and over until I couldn't afford the tag any more.

Is there a function for doing something once at the start of a given side's turn?

Link to comment
Share on other sites

It does that because you're editing simunit:onStartTurn(). This function is called for every unit in the game at turn start. This includes both player's turn start and corp's. Fix is simple: get rid of for loop, and replace every "unit" with "self". 

Link to comment
Share on other sites

Sounds about right, but I still need a way to ask the engine which side's turn it is and I haven't found it yet.  Without that it'll be checking for upkeep on both turns instead of just the agency's.

Link to comment
Share on other sites

Never mind.  I just remembered that the isPC and isNPC functions do that.

 

EDIT: No, wait, that doesn't work.  That just checks who's controlling the unit being checked at the time, which no longer works now that I'm not using the for loop any more.   @#$%.

Is there a function that does this, or do I need to jury rig something?

Link to comment
Share on other sites

Yeah, I just posted about that (probably while you were responding).  It doesn't work.  The upkeep check is being skipped entirely now, presumably because it thinks I'm asking for the controller of the current unit rather than the active player.  Here's the current code:

 

local oldOnStartTurn = simunit.onStartTurn
local tagUpkeepCost = .5

function simunit:onStartTurn( sim )
	local player = sim:getCurrentPlayer()

	if player:isPC()
	and self:getTraits().isGuard 
	and self:getTraits().tagged then
		if player:getCpus() >= tagUpkeepCost then
			player:addCPUs(-tagUpkeepCost)
		else
			self:setTagged("dissable")
		end
	end

	oldOnStartTurn( self, sim )
end

 

Link to comment
Share on other sites

1 hour ago, DGM said:

Yeah, I just posted about that (probably while you were responding).  It doesn't work.  The upkeep check is being skipped entirely now, presumably because it thinks I'm asking for the controller of the current unit rather than the active player.  Here's the current code:

 


local oldOnStartTurn = simunit.onStartTurn
local tagUpkeepCost = .5

function simunit:onStartTurn( sim )
	local player = sim:getCurrentPlayer()

	if player:isPC()
	and self:getTraits().isGuard 
	and self:getTraits().tagged then
		if player:getCpus() >= tagUpkeepCost then
			player:addCPUs(-tagUpkeepCost)
		else
			self:setTagged("dissable")
		end
	end

	oldOnStartTurn( self, sim )
end

 

That... looks like it should work. You sure you haven't missed something different like an include? If not I think I have to try it for myself.

Edit: Nevermind, I just realized what the problem is. onStartTurn is only called for units whose turn it currently is. Use a for loop like in your original post and replace simplayer.onStartTurn instead of simunit.onStartTurn.

Link to comment
Share on other sites

>> "Use a for loop like in your original post and replace simplayer.onStartTurn instead of simunit.onStartTurn."

And with that (and a little debugging) it's finally working.  Yeesh.  That took way longer than I was expecting, but at least I know how to set up once-per-turn effects now.  Thanks for your patience, guys.

One more question.  Testing revealed that the upkeep was being paid before Power Drip kicked in, resulting in tags being lost unnecessarily at low power.  I should probably address this, which means I need to learn how the engine handles the ordering of such things.  What section(s) of the code deal with this?

Link to comment
Share on other sites

28 minutes ago, DGM said:

>> "Use a for loop like in your original post and replace simplayer.onStartTurn instead of simunit.onStartTurn."

And with that (and a little debugging) it's finally working.  Yeesh.  That took way longer than I was expecting, but at least I know how to set up once-per-turn effects now.  Thanks for your patience, guys.

One more question.  Testing revealed that the upkeep was being paid before Power Drip kicked in, resulting in tags being lost unnecessarily at low power.  I should probably address this, which means I need to learn how the engine handles the ordering of such things.  What section(s) of the code deal with this?

Programs use TRG_START_TURN to check for new turns. I wouldn't recommend changing the timing of the trigger, because there is too much that depends on it, however if you replace simengine.endTurn instead you can make endTurn and thus the trigger be called before your code.

Link to comment
Share on other sites

Sorry for the delayed reply, but I've been sick.

 

>> "if you replace simengine.endTurn instead you can make endTurn and thus the trigger be called before your code."

 

Wouldn't that cause the upkeep to be checked AFTER the tags have already revealed the guard paths?  The idea is to check after things like generator programs and portable servers go off, but before the tags perform their function.

Link to comment
Share on other sites

8 hours ago, DGM said:

Sorry for the delayed reply, but I've been sick.

 

>> "if you replace simengine.endTurn instead you can make endTurn and thus the trigger be called before your code."

 

Wouldn't that cause the upkeep to be checked AFTER the tags have already revealed the guard paths?  The idea is to check after things like generator programs and portable servers go off, but before the tags perform their function.

I don't think that could happen, the effects of tags are not dependent on triggers as far as I know (and it's also completely separate from the observed effect), but just in case you can use this code to force an update:

sim():dispatchEvent( simdefs.EV_UNIT_GOALS_UPDATED, {unitID = unit:getID()} )

 

Link to comment
Share on other sites

I'm trying to implement this, but there's a complication.  I need the sim object and it isn't passed to the simengine:endTurn function through the parameters.  I'm trying to get at it like so:

 

function simengine:endTurn()

	oldEndTurn( self )

	local playerUnits = simplayer._units
	local sim = playerUnits[1].getSim()

.
.
.
end

 

...But I'm getting a crash on the "local sim" line:

 

Jul 29 17:06:11 -- Sim returned:
BrokenStrats/tag_changes.lua:37: attempt to index local 'playerUnits' (a nil value)

stack traceback:
	BrokenStrats/tag_changes.lua:37 in function 'endTurn'
	game/sim/simactions.lua:474 in function '?'
	game/sim/engine.lua:2100 in function 'applyAction'
	game/client/states/state-game.lua:362 in function <game/client/states/state-game.lua:359>

 

The term "sim" is used in so many places that even a grep tool isn't helping me find an easier way to do this.

 

Link to comment
Share on other sites

>> "So implicit arg "self" should be your sim."

That works, thanks.

Unfortunately, I was right about the timing.  Tags are still reporting the guard paths before getting destroyed.

 

EDIT: Before anyone suggests it, I tried setting patrolObserved to false right after removing the tag.  Doesn't work.

Link to comment
Share on other sites

Nevermind.  I moved the call to oldEndTurn from the beginning of the function to the end and it seems to be acting properly now.  I still don't fully understand how the timing is working here - I expected upkeep to be checked when the player ended his turn - but it's finally doing what I want so I'm not going to complain.

Thanks yet again, guys.

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

Please be aware that the content of this thread may be outdated and no longer applicable.