Jump to content

The first hound wave often fails to spawn hounds


loganpea
  • Pending

The first hound wave can happen as early as the start of day 6, but at that time, it is very rare for a player (including the host) to actually receive hounds; they only get the warning.

attack_delays =
{
	intro 		= function() return TUNING.TOTAL_DAY_TIME * 5, math.random() * TUNING.TOTAL_DAY_TIME * 3 end,
	light 		= function() return TUNING.TOTAL_DAY_TIME * 5, math.random() * TUNING.TOTAL_DAY_TIME * 5 end,
	med 		= function() return TUNING.TOTAL_DAY_TIME * 7, math.random() * TUNING.TOTAL_DAY_TIME * 5 end,
	heavy 		= function() return TUNING.TOTAL_DAY_TIME * 9, math.random() * TUNING.TOTAL_DAY_TIME * 5 end,
	crazy 		= function() return TUNING.TOTAL_DAY_TIME * 11, math.random() * TUNING.TOTAL_DAY_TIME * 5 end,
},

New players and the host receive hound wave protection based on whether or not they "lived shorter than the minimum wave delay". What is supposed to happen is that they should receive exactly one hound, but that is not always the case.

for player, group in pairs(groupindex) do
	local attackdelaybase = _attackdelayfn()
	local playerAge = player.components.age:GetAge()

	-- amount of hounds relative to our age
	-- if we never saw a warning or have lived shorter than the minimum wave delay then don't spawn hounds to us
 	local playerInGame = GetTime() - player.components.age.spawntime
	local spawnsToRelease = (playerInGame > _warnduration and playerAge >= attackdelaybase) and CalcPlayerAttackSize(player) or 0

spawnsToRelease will sometimes equal 0 because playerAge is not greater or equal to attackdelaybase. My guess is that it ends up calling the attackdelaybase = _attackdelayfn() function again, which can potentially return a number greater than playerAge, which causes the variable to return 0. The problem here is that attackdelaybase is not synced with the current hound wave, and could be fixed by removing the math.random variance from the function in this case. This is supported by the fact that hounds fail to spawn more often closer to day 6.


Steps to Reproduce

Here are some debug commands from the file for easy access:
TheWorld.components.hounded:ForceNextWave()
c_announce(TheWorld.components.hounded:GetDebugString())

  • Like 2
  • Spooky 1



User Feedback


WAIT! So this happens with other people too?!?! I have only noticed this since I am playing with my character mod. I actually thought it was related to his coding.

If this is the case and this is a REGULAR bug, then please Klei fix this! I have felt so guilty for not finding what was causing this bug and even removed one of my character's abilities for it, because I thought it was the reason.

  • Like 1

Share this comment


Link to comment
Share on other sites

The problem seems to specifically be that players can easily have a little bit less age than the world, so if the attack delay variance ends up being very close to 0, player age can end up not being greater than the base attack delay, even if they're the first player to join.

One simple way to solve this would be to have the variance always have a minimum of a day or half a day guaranteed (or a specific amount to account for this), the rest of the variance random as usual. It'd be also more ideal to do it this way than to change the player age check, as you still want that consistent for actual cases of not wanting to spawn hounds on a player.

Something like this:

-- vanilla
attack_delays =
{
	intro 		= function() return TUNING.TOTAL_DAY_TIME * 5, math.random() * TUNING.TOTAL_DAY_TIME * 3 end,
	light 		= function() return TUNING.TOTAL_DAY_TIME * 5, math.random() * TUNING.TOTAL_DAY_TIME * 5 end,
	med 		= function() return TUNING.TOTAL_DAY_TIME * 7, math.random() * TUNING.TOTAL_DAY_TIME * 5 end,
	heavy 		= function() return TUNING.TOTAL_DAY_TIME * 9, math.random() * TUNING.TOTAL_DAY_TIME * 5 end,
	crazy 		= function() return TUNING.TOTAL_DAY_TIME * 11, math.random() * TUNING.TOTAL_DAY_TIME * 5 end,
},

-- tweaked
attack_delays =
{
	intro 		= function() return TUNING.TOTAL_DAY_TIME * 5, TUNING.TOTAL_DAY_TIME + math.random() * TUNING.TOTAL_DAY_TIME * 2 end,
	light 		= function() return TUNING.TOTAL_DAY_TIME * 5, TUNING.TOTAL_DAY_TIME + math.random() * TUNING.TOTAL_DAY_TIME * 4 end,
	med 		= function() return TUNING.TOTAL_DAY_TIME * 7, TUNING.TOTAL_DAY_TIME + math.random() * TUNING.TOTAL_DAY_TIME * 4 end,
	heavy 		= function() return TUNING.TOTAL_DAY_TIME * 9, TUNING.TOTAL_DAY_TIME + math.random() * TUNING.TOTAL_DAY_TIME * 4 end,
	crazy 		= function() return TUNING.TOTAL_DAY_TIME * 11, TUNING.TOTAL_DAY_TIME + math.random() * TUNING.TOTAL_DAY_TIME * 4 end,
},

The reason why more than just intro are being changed in this example is that delayed player spawns can be a thing for people that leave and rejoin a shard/server (those have other bugs, reported here, but regardless if they're fixed or not, it would be good to account for them if this is ever solved). Needless to say, the same should be done with the worm spawn data in cave.lua.

That said, attackdelaybase in GetDelayedPlayerWaveAmounts can actually be completely desynced, and it makes no sense that it uses the ongoing _attackdelayfn to determine it, instead of doing so based on the age of the specific player being processed. It's a delayed spawn that spawns things for that specific player, so that should be doing something similar to CalcPlayerAttackSize.

Share this comment


Link to comment
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

×
  • Create New...