Page 1 of 1

Escort lost in limbo

Posted: Sat Apr 02, 2011 11:07 pm
by Flare
Good news: The injured seer is still alive after meeting Wrathroot.
Bad news: While still alive, the injured seer no longer exists.

I'm playing a Yeek Corruptor in an attempt to unlock the psionic class, although that goal has been delayed by side quests*. While in the Old Forest, an injured seer appeared and asked for help in reaching the portal. While normally seers are a welcome sight, this one happened to be wandering around on Wrathroot's level of the forest. Sure enough, the instant I left the seer's side Wrathroot appeared. Thinking quickly, I threw the Demon Plane spell on Wrathroot. After a short scuffle, I emerged victorious with a pile of loot at my feet. Then I noticed that the seer was gone. The quest was still active, and the team status bar said she was still alive at 24% health, but the seer wasn't where I left her. A thorough search of the forest turned up a heap of soon-to-be corpses, but no seer. Finally, I started a new character on cheat mode.

Using cheat mode, I forced an escort quest and set out to reproduce the limbo effect. The first monster I found was a cute little level 1 fox. "Ah, perfect!" I said, and dragged the newborn fox pup down into the flaming pits of hell.** There was small orange explosion, and I was alone on the demon plane. This was surprising, since the spell is supposed to end when the target dies. After waiting a few turns for something more to happen, I deactivated the spell. The escort had vanished, confirming the first bug, but now there was a second bug to confirm. A few casts of Demon Plane revealed a pattern. Trolls would take a single step, take 50 damage, and end the spell as planned, but foxes would leave me hanging around the demon plane without a partner.

Finally I took a close look at the Demon Plane talent and found a third bug - according to the talent description, the fires of the demon plane were supposed to dish out 30,000 damage per turn. The aforementioned troll only took 50.

It's pretty obvious what's going on in the third bug. The damage in the talent description factors in the insane god mode damage multiplier, while the damage from the lava floor doesn't. The code for the Demon Plane talent*** uses the line

Code: Select all

		local dam = self:combatTalentSpellDamage(t, 12, 140)
to control lava damage, while the description uses

Code: Select all

		The damage will increase with the Magic stat]]):format(damDesc(self, DamageType.FIRE, self:combatTalentSpellDamage(t, 12, 140)))
In the first block of code, the base damage before damage multipliers gets passed to the lava floor. The lava floor never uses the caster's damage multiplier. The second block calls damDesc(), which factors in damage multipliers. Since the damage is dealt by the floor rather than by the player's own hands, I think the un-multiplied version is correct and the talent description should be changed to reflect the spell.

The second bug was a little harder to track down, but I think this is it. Again, this is from the Demon Plane talent in Shadowflame.lua.

Code: Select all

			local x1, y1 = util.findFreeGrid(4, 6, 20, true, {[Map.ACTOR]=true})
			if x1 then
				self:move(x1, y1, true)
				game.level.map:particleEmitter(x1, y1, 1, "demon_teleport")
			end
			local x2, y2 = util.findFreeGrid(8, 6, 20, true, {[Map.ACTOR]=true})
			if x2 then
				target:move(x2, y2, true)
				game.level.map:particleEmitter(x2, y2, 1, "demon_teleport")
			end

			target:setTarget(self)
			target.demon_plane_trapper = self
			target.demon_plane_on_die = target.on_die
			target.on_die = function(...)
				target.demon_plane_trapper:forceUseTalent(self.T_DEMON_PLANE, {ignore_energy=true})
				if target.demon_plane_on_die then target.demon_plane_on_die(...) end
				target.on_die, target.demon_plane_on_die = target.demon_plane_on_die, nil
			end

			self.demon_plane_on_die = self.on_die
			self.on_die = function(...)
				self:forceUseTalent(self.T_DEMON_PLANE, {ignore_energy=true})
				if self.demon_plane_on_die then self.demon_plane_on_die(...) end
				self.on_die, self.demon_plane_on_die = self.demon_plane_on_die, nil
			end

			game.logPlayer(game.player, "#LIGHT_RED#You are taken to the demon plane!")
In plain English, this block of code goes through these steps.

1. Move the caster to the demon plane.
2. Move the target to the demon plane.
3. Give the target instructions.
4. Give the caster instructions.

Note the order here. First, the caster moves to the demon plane. The move command allows the possibility that the person moving might move onto dangerous terrain. The terrain in the demon plane might kill the caster on that first move, if the caster were heavily injured first. The same thing applies when the target moves to the demon plane - the automatic movement to the demon plane can kill a weak opponent, such as a level 1 fox.

Then we move on to steps 3 and 4. Among the instructions given to the target and the caster are orders that if either of them die, they should deactivate the Demon Plane spell. The problem is that this only applies if they die. It doesn't apply if they're already dead. If a small opponent dies during the movement to the demon plane, their death happens before they receive on_death commands, and they will not end the spell. It's not that far of a stretch to say that if the caster dies during the movement, the target will be probably be stuck there forever.

There are probably several fixes to this. The first one I would try would be to reverse the order - first give the actors their instructions, then move them. If that turns out to have potential errors, then maybe an is-dead test would fix it.

The original problem has me beat. I looked through several file mentioning escort quests, but none of them had anything on moving the escort when the player goes to another level. My next guess is that the level map doesn't save the existence of an escort when the player switches levels, but I have no idea where to look for something like that. Cheat mode has nothing that can summon an existing actor. If nothing else comes up, I'm going to leave the level and hope that that terminates the quest, allowing cheat mode to give me another one. If that doesn't work, the seer will just have to remain lost in limbo.

UPDATE: Going down a level spawned the injured seer on that level. The seer headed out to where the recall portal would have been, had we been on the previous level. Unfortunately, that spot happened to be on the far side of lake Nur, and the seer drowned on the way.

*I reached the halfling ruins at level 10 and realized that killing Subject Z would prevent me from getting the arena quest. So I used the Rod of Recall to skip that fight. Neither the problem nor the solution seems like intended behavior, but they cancel each other out quite nicely.

**In hindsight, this might not have been a very nice thing to do.

***http://svn.net-core.org/repos/t-engine4 ... wflame.lua

Re: Escort lost in limbo

Posted: Mon Apr 04, 2011 6:21 pm
by Flare
Following up on the Demon Plane spell has uncovered a few more bugs. All of these are in b21.

First, casting Demon Plane on yourself throws the game into an infinite loop of level generation and bug reports. The only way to escape from this is to force quit ToME.

Second, using Demon Plane on Subject Z prevents the yeek wayist from granting the quest reward, or even speaking to the player. This might be related to the lost escort bug.

Thirdly, deactivating Flame of Urh'Rok does not stop lava from healing you. Cast Flame of Uhr'Rok once, and the demon plane is forever more your friend. The code's not being obvious here - did this get fixed in b23?

Penultimately, lava in the demon plane (at least, the spell's version of the demon plane) doesn't burn if you rest on it. I don't know if this is intentional - maybe the actor is standing on a rock or something? Anyway, there's code in demon-plane-spell/grids.lua to burn an actor when the actor moves, but standing doesn't trigger it. Changing on_move to on_stand should fix it.

http://svn.net-core.org/repos/t-engine4 ... /grids.lua

Code: Select all

	on_move = function(self, x, y, who)
		local DT = engine.DamageType
		local dam = DT:get(DT.DEMONFIRE).projector(self, x, y, DT.DEMONFIRE, game.level.demonfire_dam or 1)
		if dam > 0 then game.logPlayer(who, "The lava burns you!")
		elseif dam < 0 then game.logPlayer(who, "The lava heals you!") end
	end,
Oddly enough, lava in the real demon plane is entirely harmless. (Maybe the lava in the real demon plane could deal a very small amount of damage, like 3/turn? But I digress.)

Finally, canceling Demon Plane without a target spits up a nil pointer report.

Re: Escort lost in limbo

Posted: Tue Apr 05, 2011 9:56 pm
by darkgod
Oh very good analysis! that's great thanks!

I'm still checking out the escort one but I fixed the others.
Many thanks, this is a complex spell, but ultimately fun I hope :)

Re: Escort lost in limbo

Posted: Tue Apr 05, 2011 10:15 pm
by darkgod
Ok fixed escorts :)
The escort was removed by Game:leaveLevel()

Re: Escort lost in limbo

Posted: Sun Apr 10, 2011 1:48 am
by Hedrachi
*bumpity for similar kind of bug*
But yeah. I've noticed on a few occasions, escorts or Norgan will suddenly "see" something on the opposite side of the map that they're on and just mindlessly zerg the thing and stop at absolutely nothing until either you die, it dies, or its target dies. Generally tends to ignore foes it finds on its way to the target, except to do physical attacks from running into it when the foe is in its way. Case in point: Lost rogue, Old Forest 3: There is a long, backwards-L shaped path going along the southern part of the level to the southeastern tip, then heading north til the exit about halfway up. There was a northward-leading path from the entrance (and rogue) to the rest of the level. There was a white ant on the path to the exit, and the rogue just mindlessly zerged it as best as it could, which meant it just ran into the tree-wall for about 500 turns while I explored the level and (eventually) found the ant, which had also targeted the rogue and was similarly just sitting there only moving one tile and back. By this time, everything else had been cleared, so soon as the ant died, about as many turns as would be needed to get from the start point to the recall portal passed and the escort quest completed. With Norgan, this is a little more dangerous, as he tends to ignore leash range unless you set it to 1, and even this is dangerous. Ended up facing a wall of white worm masses in Escape from Reknor 2 while Norgan shamelessly "hid" behind me because he was so intent on killing something on the other side of the level, even to the point of ignorning the worms (and eventually orcs) when I switched places with him to try and get away from the things.

Also, if escorts could use infusions and runes too, would make the quests MUCH easier.