Request for Slow resistance

All development conversation and discussion takes place here

Moderator: Moderator

Message
Author
evouga
Wyrmic
Posts: 231
Joined: Tue Jul 06, 2010 1:03 am

Re: Request for Slow resistance

#16 Post by evouga »

Final Master wrote:At what point have slow effects gotten to any status of worry? What causes this now, and in general gameplay, is it any real threat outside of very specific instances?
The new custom bosses. The main aggravating factor is the fact that these can "cheat" and get talents at raw levels greater than 5: if talent levels are capped, there's probably no need to modify Slow.

Even "very specific instances" is too much when you are playing with one life.

tiger_eye
Perspiring Physicist
Posts: 889
Joined: Thu Feb 17, 2011 5:20 am

Re: Request for Slow resistance

#17 Post by tiger_eye »

Then as I said earlier, this is probably an issue with random uniques, not with slow. Tweak as needed. No need to use a greatmaul when a scalpel is called for. It is possible to disallow uniques from getting certain talents, and it should be possible to put a cap on talents that (may) need caps. I still don't view it as a particularly big deal: if you're around a unique that you know can slow by a lot, then you best be careful. In fact, you should always be careful :wink:

I'd like to point out that even if you're slowed by 90%, this doesn't mean enemies will get 10 free turns to attack you. Like everything else, slow is based off of game turns, so if you're slowed for 3 turns, then, at worst, they'll get 3 free shots at you. If you want to reduce the number of turns you'll be slowed, then increase your physical saves.

This is a very narrow issue. In hopes of actually making progress--and making it easy adjust things as appropriate--here are the only four talents (that I found, at least) that may be unfair for random unique npcs to have at high level:

"Glyph of Fatigue": slows by (20 + 7*tl)%. Lasts 5 turns.
"Congeal Time": slows (8*tl)%. Lasts 7 turns.
"Kinetic Leech": slows (10 + 3*tl)%. Lasts 4 turns.
Chronomancy speed control "Slow": slow amount depends on spell power, talent level, and paradox modifier. Potientially high. Lasts 5 turns.

Final Master
Sher'Tul
Posts: 1022
Joined: Fri May 21, 2010 8:16 pm
Location: Inside the minds of all
Contact:

Re: Request for Slow resistance

#18 Post by Final Master »

I would also like to point out - as these cases seem to be isolated to Far Portal bosses - you are asking for these. These are not npcs that will just spawn randomly without you going to, and purposely looking for, this kind of danger.

In other words, you are bringing this upon yourself willingly.
Final Master's Character Guides
Final Master's Guide to the Arena
Edge: Final Master... official Tome 4 (thread) necromancer.
Zonk: I'd rather be sick than on fire! :D

Hirumakai
Thalore
Posts: 192
Joined: Wed Aug 11, 2010 2:39 pm

Re: Request for Slow resistance

#19 Post by Hirumakai »

Well, technically, its not just the Far Portal bosses. Apparently the Vor Bastion (which was what triggered my initial post) can include an NPC with the glyph talents at level 8 (looked like random generation to me). Of course, that is not a critical path dungeon either.

Presumably adventurer parties can also get the class talents, although I don't know at what level (if any) they cap at. But you are correct, it is restricted to a small set of NPCs with class skills.

Also, could someone point me to the file(s) that contains the code that reduces the duration of slows based on save value? I'm curious how much I need to reduce most durations to 1 turn or less. :) My grep foo is apparently weak and can't seem to track down this connection.

Susramanian
Spiderkin
Posts: 454
Joined: Sat May 15, 2010 3:09 am

Re: Request for Slow resistance

#20 Post by Susramanian »

It's been suggested that saves reduce the duration of effects instead of just giving the player another chance to resist them completely. I wasn't aware that this duration-reducing mechanic had been implemented anywhere yet. If it has, then good!

evouga
Wyrmic
Posts: 231
Joined: Tue Jul 06, 2010 1:03 am

Re: Request for Slow resistance

#21 Post by evouga »

Final Master wrote:I would also like to point out - as these cases seem to be isolated to Far Portal bosses - you are asking for these. These are not npcs that will just spawn randomly without you going to, and purposely looking for, this kind of danger.

In other words, you are bringing this upon yourself willingly.
I believe adventuring parties can get these as well.

lukep
Sher'Tul Godslayer
Posts: 1712
Joined: Mon Mar 14, 2011 10:32 am
Location: Canada

Re: Request for Slow resistance

#22 Post by lukep »

Final Master wrote:I would also like to point out - as these cases seem to be isolated to Far Portal bosses - you are asking for these. These are not npcs that will just spawn randomly without you going to, and purposely looking for, this kind of danger.

In other words, you are bringing this upon yourself willingly.
Just because it is rare, isolated, and optional, doesn't mean that it isn't broken.
Some of my tools for helping make talents:
Melee Talent Creator
Annotated Talent Code (incomplete)

tiger_eye
Perspiring Physicist
Posts: 889
Joined: Thu Feb 17, 2011 5:20 am

Re: Request for Slow resistance

#23 Post by tiger_eye »

Search your output log for "Effect duration reduction". This may also be the `grep foo` technique that will provide the answer to your question :wink:

Have you ever wondered why some high level NPCs can appear to have negatively timed timed_effects (which promptly disappear)? Well, I think you're about to find out!

Hirumakai
Thalore
Posts: 192
Joined: Wed Aug 11, 2010 2:39 pm

Re: Request for Slow resistance

#24 Post by Hirumakai »

First, anyone know if spoiler tags work on this forum? And if so, whats the tag, I tried [spoiler][/spoiler] but that didn't work. I'd like to edit this post not to spam this thread with long sections.

Continuing on: The effect reduction is very interesting. So the updateEffectDuration() gets called once in the SLOW effect definition and modifies the duration.

From ActorTemporaryEffects.lua

Code: Select all

--- Adjusts timed effect durations based on rank and other things
function _M:updateEffectDuration(dur, what)
	-- Rank reduction: below elite = none; elite = 1, boss = 2, elite boss = 3
	local rankmod = 0
	if self.rank == 3 then rankmod = 25
	elseif self.rank == 3.5 then rankmod = 40
	elseif self.rank == 4 then rankmod = 45
	elseif self.rank == 5 then rankmod = 75
	end
	if rankmod <= 0 then return dur end

	print("Effect duration reduction <", dur)
	if what == "stun" then
		local p = self:combatPhysicalResist(), rankmod * (util.bound(self:combatPhysicalResist() * 3, 40, 115) / 100)
		dur = dur - math.ceil(dur * (p) / 100)
	elseif what == "pin" then
		local p = self:combatPhysicalResist(), rankmod * (util.bound(self:combatPhysicalResist() * 3, 40, 115) / 100)
		dur = dur - math.ceil(dur * (p) / 100)
	elseif what == "disarm" then
		local p = self:combatPhysicalResist(), rankmod * (util.bound(self:combatPhysicalResist() * 3, 40, 115) / 100)
		dur = dur - math.ceil(dur * (p) / 100)
	elseif what == "frozen" then
		local p = self:combatSpellResist(), rankmod * (util.bound(self:combatSpellResist() * 3, 40, 115) / 100)
		dur = dur - math.ceil(dur * (p) / 100)
	elseif what == "blind" then
		local p = self:combatMentalResist(), rankmod * (util.bound(self:combatMentalResist() * 3, 40, 115) / 100)
		dur = dur - math.ceil(dur * (p) / 100)
	elseif what == "silence" then
		local p = self:combatMentalResist(), rankmod * (util.bound(self:combatMentalResist() * 3, 40, 115) / 100)
		dur = dur - math.ceil(dur * (p) / 100)
	elseif what == "slow" then
		local p = self:combatPhysicalResist(), rankmod * (util.bound(self:combatPhysicalResist() * 3, 40, 115) / 100)
		dur = dur - math.ceil(dur * (p) / 100)
	elseif what == "confusion" then
		local p = self:combatMentalResist(), rankmod * (util.bound(self:combatMentalResist() * 3, 40, 115) / 100)
		dur = dur - math.ceil(dur * (p) / 100)
	end
	print("Effect duration reduction >", dur)
	return dur
end

So as far as I can tell, if you have a physical save of 100, the duration gets set to 0. Assuming you are not playing on insane, at which point your rank 0-ness makes you lose out. I'm not sure why there is a separate calculation when setting p, since I believe only the 1st value (the save) gets applied to the variable.

Turns out the effect was in fact reduced to 2 rounds for Valen. Although the slow was apparently worse than I thought, -0.928. So I guess it was only supposed to be a loss of 1 or 2 turns (like an old style 1 or 2 turn stun).

Code: Select all

[LOG]	Valen Sky triggers a trap (glyph of fatigue)!
[LOG]	Valen Sky slows down.
addTmpVal	table: 0A76E668	global_speed	-0.928	 :=: 	1	4022	mult0
Effect duration reduction <	5
Effect duration reduction >	2
Anyways, even with a duration of 0, it will stick around until the next actTurn(), which in turn calls timedEffects(), since there's no checking on positive durations at the setting the effect up stage. So there's always some effect (for example in the case of stunned, it checks if you're stunned for talent cooldowns before removing effects). However, looking through Valen's death log, I noticed something - several characters acted many times after Valen hit the trap - up to 7. And had that particular one had 3 different talent infusions come off cooldown, on different turns. (See the code section at the end).

So this got me thinking, -- who calls actTurn() and thus removes the effect? The only place in the entire lua code that calls actTurn is act(). act() calls it in a loop to catch up (as far as I can tell).

From Actor.lua:

Code: Select all

-- We compute turns at "default" speed, and only fire some actions when chaning turn
	local actturn = math.floor(game.turn / (game.zone.wilderness and 1000 or 10))
	if not self.last_act_turn then self.last_act_turn = actturn - 1 end
	for i = 1, actturn - self.last_act_turn do self:actTurn() end
	self.last_act_turn = actturn
And act() only gets called when you have sufficient energy to act.

From GameEnergyBased.lua:

Code: Select all

	local arr = self.entities
	for i, e in pairs(arr) do
		e = arr[i]
		if e and e.act and e.energy then
			if e.energy.value < self.energy_to_act then
				e.energy.value = (e.energy.value or 0) + self.energy_per_tick * (e.energy.mod or 1) * (e.global_speed or 1)
			end
			if e.energy.value >= self.energy_to_act then
				e.energy.used = false
				e:act(self)
			end
		end
	end
So this -0.928 slow was something akin to an 10-11 round old style stun, because it wouldn't be removed until Valen had sufficient energy to act. Actually worse, since he doesn't even get his natural health regen. Oddly enough, this also implies positive effects could be drawn out longer than they should in game turns with a low global speed.

Appendix 1:
I found the same Orc cryomancer (id# 39105) acted 7 times from when the trap hit, until Valen Sky died. With no other actions from Valen. I've included a list of its AI decisions here, which show it choices, as well as the various talents and infusions recharging.

Code: Select all

orc cryomancer	39105	dumb ai talents can use	Attack	T_ATTACK
dumb ai uses	T_ATTACK

orc cryomancer	39105	dumb ai talents can use	Attack	T_ATTACK
dumb ai uses	T_ATTACK

orc cryomancer	39105	dumb ai talents can use	Attack	T_ATTACK
orc cryomancer	39105	dumb ai talents can use	Phase Door	T_PHASE_DOOR
dumb ai uses	T_ATTACK

orc cryomancer	39105	dumb ai talents can use	Freeze	T_FREEZE
orc cryomancer	39105	dumb ai talents can use	Attack	T_ATTACK
orc cryomancer	39105	dumb ai talents can use	Phase Door	T_PHASE_DOOR
dumb ai uses	T_ATTACK

orc cryomancer	39105	dumb ai talents can use	Freeze	T_FREEZE
orc cryomancer	39105	dumb ai talents can use	Attack	T_ATTACK
orc cryomancer	39105	dumb ai talents can use	Phase Door	T_PHASE_DOOR
dumb ai uses	T_FREEZE

orc cryomancer	39105	dumb ai talents can use	Rune: Controlled Phase Door	T_RUNE:_CONTROLLED_PHASE_DOOR_1
orc cryomancer	39105	dumb ai talents can use	Attack	T_ATTACK
orc cryomancer	39105	dumb ai talents can use	Phase Door	T_PHASE_DOOR
dumb ai uses	T_RUNE:_CONTROLLED_PHASE_DOOR_1

orc cryomancer	39105	dumb ai talents can use	Phase Door	T_PHASE_DOOR
dumb ai uses	T_PHASE_DOOR

Edit: Removed duplicate code sections...

Hedrachi
Uruivellas
Posts: 606
Joined: Tue May 11, 2010 8:58 pm
Location: Ore uh gun, USA

Re: Request for Slow resistance

#25 Post by Hedrachi »

Hirumakai wrote:First, anyone know if spoiler tags work on this forum?
About the closest to a spoiler tag for the purposes you're describing would be to upload whatever wall of text you don't want to spam us with as an attachment (using the tool below the "post a reply/post a new topic" box. But, this is the devel forum, and spam would be something like including Monty Python's Camelot song from Holy Grail as comments in the code you post; posting code which is intended to be useful isn't spam.
Having satellite internet is a lot like relying on the processes described in those RFC's for your internet. Except, instead of needing to worry about statues interrupting your connection, this time you worry about the weather. I have satellite internet. Fun, no?

Hirumakai
Thalore
Posts: 192
Joined: Wed Aug 11, 2010 2:39 pm

Re: Request for Slow resistance

#26 Post by Hirumakai »

I'd like to throw an idea out there.

Currently, the way turns and speed is handled, a severely slowed creature will have several turns pass without any of the "turn" effects processing, such as Thunderstorm, Gloom, or timed effects expiring. When its turn finally comes up, they will all get processed at once (this could result in multiple thunderstorm damage effects occurring in the space of a single turn for example). This does not seem like ideal behavior.

So irregardless of whether slow gets capped or not, it strikes me that the code should do the right thing, even in the case of extreme slows.

The actTurn() function (from Actor.lua in /games/modules/tome/class/) could be called from within the tick function (in /game/engines/default/engine/GameEnergyBase.lua), possibly by an overrided definition of it if the GameEnergyBased.lua needs to be generic and not module specific? Although this might require a separate "true time/energy" counter for each actor? This would then require the actTurn() loop be removed from act().

From what I understand, running them at the correct time versus all at once playing catch up shouldn't slow the game down any, and at worst, adds a counter to each actor. It then means on turn effects occur at the correct time, preventing say a player from moving out of range of a slowed Boss's Thunderstorm towards the end of a severe slow.

Thoughts? Are there code reasons why this couldn't be done? If tick isn't overridable, perhaps a rewrite of act(), to handle both the act() and actTurn() functionality with if statements?

tiger_eye
Perspiring Physicist
Posts: 889
Joined: Thu Feb 17, 2011 5:20 am

Re: Request for Slow resistance

#27 Post by tiger_eye »

Thank you Hirumakai for taking a close look at the code and clarifying how speeds and actions work. It is a bit more nuanced than I thought. I agree with your last post, so let me try to explain it differently to see if I understand (and maybe help others better understand this as well).

Let me be clear that this post and your previous post are not specifically about the slow effect--it is deeper than that. Nor are we suggesting to change how speeds work--we just want speeds to work as currently intended. The issue is that even though many things are based off of the game clock (such as life regeneration, runic and infusion saturations, talent cooldowns, and other timed effects), these things do not update with the game clock: they only update when "act()" is called for the given actor. If several game turns pass before "act()" is called, then all the previously missed game turns are updated in that last "act()" call. Hence, if you are slowed by 90% for 3 turns, then 10 turns will pass. This is unfair and unintended. Let me show this with a diagram:

Note: 1 game turn happens every 10 ticks. An actor needs 10 energy to act. The actor in this example is slowed by 71%, so energy is regained slowly.

Code: Select all

Turn   0                   1                   2                   3                   4
Ticks  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0
Energy * 0 0 0 1 1 1 2 2 2 2 3 3 3 4 4 4 4 5 5 5 6 6 6 6 7 7 7 8 8 8 8 9 9 9 *
      /|\                                                                   /|\
       |                                                                     |
     act(), last_act_turn = 0                                              act()
The first "act()" call was done during turn 0, and the second "act()" call was done during turn 3. "actTurn()" for turns 1 and 2 was not called during turns 1 and 2. Instead, the second "act()" call during turn 3 called "actTurn()" for turns 1, 2, and 3. Any timed effect (such as slow) that was supposed to expire during turn 1 or turn 2 did not actually do so; instead, it expired in turn 3. (Note: effects like regeneration were also put on hold until turn 3).

Below is a diagrammatic representation of a proposed fix. Simply put, if there is about to be a new game turn and "actTurn()" hasn't been called for a given actor this game turn, then force "actTurn()" to be called for this game turn.

Code: Select all

Turn   0                   1                   2                   3                   4
Ticks  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0
Energy * 0 0 0 1 1 1 2 2 2 2 3 3 3 4 4 4 4 5 5 5 6 6 6 6 7 7 7 8 8 8 8 9 9 9 *
      /|\                                    /|\                 /|\        /|\
       |                                      |                   |          |
     act()                           actTurn(), turn 1   actTurn(), turn 2  act()
This should actually be pretty easy to do. In fact, I almost posted a patch to fix this... but, well, there may be other nuances I am not yet aware of, and I don't want to be responsible for any nuanced, difficult bugs :wink:

evouga
Wyrmic
Posts: 231
Joined: Tue Jul 06, 2010 1:03 am

Re: Request for Slow resistance

#28 Post by evouga »

Why is everything packaged together in one actTurn() call? Why doesn't each effect have its own timer?

For instance, suppose I activate regeneration on tick 0.0, then get slowed by a monster on tick 0.6. Instead of trying to package everything together on a per-turn basis I would update things asynchronously on a timeline that looks like this:

0.0: Regeneration activated
0.6: Slow activated
1.0: Regeneration adds health
2.0: Regeneration adds health
3.0: Regeneration adds health and deactivates
3.6: Slow deactivates

Hirumakai
Thalore
Posts: 192
Joined: Wed Aug 11, 2010 2:39 pm

Re: Request for Slow resistance

#29 Post by Hirumakai »

So I was fighting a Farportal Spire Dragon boss and stepped out about 75% through the fight, and suddenly went from full health and shields to dead. This is over 2400 hp in a single turn with most resists above 50%. I look through the log and see:

Code: Select all

Tactical choice:	disable	T_GLYPH_OF_FATIGUE
[LOG]	Silelle the spire dragon casts Glyph of Fatigue.

Code: Select all

addTmpVal	table: 0E0D7870	global_speed	-1.019	 :=: 	1	6786	mult0
Effect duration reduction <	5
Effect duration reduction >	1
Given the character has 78 physical resist, the effect duration dropping to 1 turn looks about right. The fact that the spire dragon got 4 rounds of action without any actions on the character part is not. The character is still alive, although only thanks to the Blood of Life.

Tiger_eye, I was wondering if the patch you had been considering has gone beyond the consideration stage? Having a negative global speed which would then never wear off strikes me as a bug, and at least the fix you propose seems easy to implement without too much additional overhead.

I admit Evouga's suggestion of individual timers might be nice, but I don't know how much slow down it would involve if every effect had its own timer. Perhaps not much.

tiger_eye
Perspiring Physicist
Posts: 889
Joined: Thu Feb 17, 2011 5:20 am

Re: Request for Slow resistance

#30 Post by tiger_eye »

Hirumakai wrote:Tiger_eye, I was wondering if the patch you had been considering has gone beyond the consideration stage?
Heh, yeah okay. I suppose if one says "it's easy", then the onus is on them to do it :wink: . I attached a simple patch to (basically) do the simple fix I illustrated above. I call "act()" at the end of the turn instead of "actTurn()", so things like sustains can be disabled properly if the given resource is drained. The actor still needs enough energy to act for T_AUTOMATIC_STEALTH to activate T_STEALTH. NPCs weren't overlooked, either: "Actor:act()" is now called before "enoughEnergy()".

I haven't verified this works correctly and without bugs (what could possibly go wrong :P ?), so another set of eyes to look over these changes is always appreciated.
Hirumakai wrote:Having a negative global speed which would then never wear off strikes me as a bug
Yeah, I agree it's a bug. I seem to recall listing which talents can accomplish this feat in a previous post. I'll look into tweaking those next.
EDIT: attached separate patch to fix "Glyph of Fatigue" and "Kinetic Leech"
Attachments
slow_talent_fix.txt
(2.18 KiB) Downloaded 274 times
game_turn_actions2.txt
(3.74 KiB) Downloaded 332 times

Post Reply