DGM

addCpus command keeps crashing game

Recommended Posts

DGM    13

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

Share this post


Link to post
Share on other sites
DGM    13

Just realized I stuck a semicolon at the end of the addCpus line.  Damned muscle memory.

However, the line still crashes the game even after removing that (and making no other changes).  New log, in case it matters: invisibleinc.txt

Share this post


Link to post
Share on other sites
DGM    13

[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.

Share this post


Link to post
Share on other sites
DGM    13

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?

Share this post


Link to post
Share on other sites
wodzu_93    23
Posted (edited)

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". 

Edited by wodzu_93

Share this post


Link to post
Share on other sites
DGM    13

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.

Share this post


Link to post
Share on other sites
DGM    13
Posted (edited)

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?

Edited by DGM

Share this post


Link to post
Share on other sites
DGM    13
Posted (edited)

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

 

Edited by DGM

Share this post


Link to post
Share on other sites
Cyberboy2000    368
Posted (edited)
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.

Edited by Cyberboy2000

Share this post


Link to post
Share on other sites
DGM    13
Posted (edited)

>> "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?

Edited by DGM

Share this post


Link to post
Share on other sites
Cyberboy2000    368
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.

Share this post


Link to post
Share on other sites
DGM    13

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.

Share this post


Link to post
Share on other sites
Cyberboy2000    368
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()} )

 

Share this post


Link to post
Share on other sites
DGM    13

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.

 

Share this post


Link to post
Share on other sites
Strelock    10

simengine is probably a sim that you want. So implicit arg "self" should be your sim.

Share this post


Link to post
Share on other sites
DGM    13
Posted (edited)

>> "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.

Edited by DGM

Share this post


Link to post
Share on other sites
DGM    13

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.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now