ZScript TryMove and CheckMove put monster in walls

Ask about ACS, DECORATE, ZScript, or any other scripting questions here!

Moderator: GZDoom Developers

Forum rules
Before asking on how to use a ZDoom feature, read the ZDoom wiki first. If you still don't understand how to use a feature, then ask here.

ZScript TryMove and CheckMove put monster in walls

Postby peewee_RotA » Fri Sep 03, 2021 6:49 am

In ZScript I have some of the monsters in Hexen able to teleport away on a hit. An inventory has a ModifyDamage override that calls another function to do this. I've tried combinations of CheckMove, TryMove, and then a combination of both with the TeleportMove as the actual move call. In every case the monster thinks that outside of the walls is valid and teleports out there sometimes.

Here's the code I have:
Code: Select allExpand view
void DoLightningLeaderTakeDamage(int damage, Name damageType, Actor inflictor, Actor source)
    {
        //don't teleport on death
        if (Owner.Health - damage < 0)
            return;

        if (!IsTimedOutExpired())
            return;
        SetTimeout();
       
        int moveTries = 0;
        Vector2 newPos;
        let oldPos = Owner.Pos;

        while (moveTries >= 0 && moveTries < 10)
        {
            moveTries++;

            newPos.x = random(-LIGHTNINGBOSS_TELEPORT_DIST, LIGHTNINGBOSS_TELEPORT_DIST) + Owner.Pos.X;
            newPos.y = random(-LIGHTNINGBOSS_TELEPORT_DIST, LIGHTNINGBOSS_TELEPORT_DIST) + Owner.Pos.Y;

            if (Owner.TryMove(newPos, 1, true))
            {
                let mo = Spawn("LightningLeaderFx1");
                if (mo)
                    mo.SetOrigin(oldPos + (0,0,28), false);

                moveTries = -1;
            }
        }
    }


It finds random positions and does a try move. If it works it exits the loop and creates an effect. It retries on a failure a few times and then ultimately exits if it fails too many times.

Has anyone ran into this before? I just want to know if it is a safe move position.

These two methods don't have a whole lot of documentation, and I had to go into the C++ code to figure out what the dropoff field does in TryMove (apparently 1 is yes, and 2 is yes sometimes but the logic is really complex and confusing)
peewee_RotA
 
Joined: 07 Feb 2014

Re: ZScript TryMove and CheckMove put monster in walls

Postby Player701 » Fri Sep 03, 2021 7:16 am

Try to use the same combination of checks as I suggested here. Upd: You should first change the position of the monster or they won't work. Reset to the original position on fail.
User avatar
Player701
 
 
 
Joined: 13 May 2009
Location: Russia
Discord: Player701#8214
Operating System: Windows 10/8.1/8/201x 64-bit
OS Test Version: No (Using Stable Public Version)
Graphics Processor: nVidia with Vulkan support

Re: ZScript TryMove and CheckMove put monster in walls

Postby peewee_RotA » Fri Sep 03, 2021 3:38 pm

That's genius! I'll give it a shot.
peewee_RotA
 
Joined: 07 Feb 2014

Re: ZScript TryMove and CheckMove put monster in walls

Postby peewee_RotA » Sat Sep 04, 2021 4:47 pm

Did some more testing and I think it's a Hexen issue. The outside sectors are valid after it teleports, they have floors, and appear to have heights and all that. After doing more digging, there is another problem. Rotating and moving walls in hexen have extra sectors so they can be lit. Meaning a monster that is required to be defeated could end up in a valid space in these extra rooms. So I had to make it so that it is not just a valid landing space, but a valid flight path and angle.

Meaning I run a linetrace to the new position. If the trace hits something it is a fail.

In the end the position has to be valid and a hitscan style trace has to be possible between the original spot and new spot. I do this line trace before the move and check and just hold onto its value.

Code: Select allExpand view
while (moveTries >= 0 && moveTries < 10)
        {
            moveTries++;

            newPos.x = random(-LIGHTNINGBOSS_TELEPORT_DIST, LIGHTNINGBOSS_TELEPORT_DIST) + Owner.Pos.X;
            newPos.y = random(-LIGHTNINGBOSS_TELEPORT_DIST, LIGHTNINGBOSS_TELEPORT_DIST) + Owner.Pos.Y;
            newPos.Z = Owner.Pos.Z;

            let vecOffset = newPos - oldPos;
            let vecLen = vecOffset.Length();
            let vecAngle = VectorAngle(vecOffset.x, vecOffset.y);
            let newPitch = VectorAngle(vecLen, vecOffset.Z);

            bool traceFail = Owner.LineTrace(vecAngle, vecLen, newPitch);

            Owner.SetOrigin(newPos, false);
            newPos.z = Owner.CurSector.NextLowestFloorAt(Owner.pos.x, Owner.pos.y, Owner.pos.z, Owner.pos.z, FFCF_NOPORTALS);

            Owner.SetZ(newPos.z);

            if (traceFail || !Owner.TestMobjLocation() || Owner.height > (Owner.ceilingz - Owner.floorz) || !Owner.CheckMove(Owner.Pos.XY))
            {
                //Move unsuccessful, move back
                Owner.SetOrigin(oldPos, false);
            }
            else
            {
                //Move Successful, spawn lightning and exit
                let mo = Spawn("LightningLeaderFx1");
                if (mo)
                    mo.SetOrigin(oldPos + (0,0,28), false);
               
                moveTries = -1;
            }
        }
peewee_RotA
 
Joined: 07 Feb 2014

Re: ZScript TryMove and CheckMove put monster in walls

Postby peewee_RotA » Sat Sep 04, 2021 4:56 pm

Last note. The Stalker (sea creature) already does a thing where it goes invisible, walks around, and then reappears. Anyone trying to do what I am doing should ignore this approach, set their monster invisible & invincible, let it walks around a second, and then set it visible again. Achieves the exact same effect with none of the fuss.
peewee_RotA
 
Joined: 07 Feb 2014


Return to Scripting

Who is online

Users browsing this forum: No registered users and 0 guests