onblockwscript behaviour

O Ilusionista

Captain 100K
I recently replaced an "antiwall" animation script on my projectiles with an onblockwscript solution, which simply switches the projectile to another animation, nothing more.

It works very well, but I noticed that onblockwscript (and onblockoscript and onblockpscript as well) have a peculiar behavior: they are events that fire if the entity is blocked by a wall, but are not fired if the entity is already inside a wall.

This video demonstrates this behavior:

I remember having the same problem with "onmovez" scripts and projectiles that would leave the level's maximum zone if they were already created outside the maximum zone, and at the time I had to force this with an update script.

Is this the expected behavior for this type of event, or is it a version 3.0 issue? (I haven't tested it in V4.)

edit: a little more info
In the first video, the wall in front of the entity is low, so the engine moves the entity onto it. But in the video below, the wall is high (6000px), and when the engine detects an entity is inside a high wall, it is automatically removed.

It appears this behavior is triggered before the onblockwscript is triggered.

EDIT2: once I add an animation script, the arrow isn't stuck anymore (althought it doesn't jump back anymore too)
 
Last edited:
Wall logic is way, WAY too complex to explain fully in one post - it's a whole tangle of math and virtual geometric shapes. I'll try to give you a quick once over. Basically, if you spawn something in a wall, it's already too late to be "blocked" by the wall.

See this logic - this is how we decide to fire the on block wall script. But the wall has to be "below" you.
C:
if(self->modeldata.move_config_flags & MOVE_CONFIG_SUBJECT_TO_WALL)
{
    int hit = 0;

    if(xdir && (wall = checkwall_below(x, self->position.z, T_MAX_CHECK_ALTITUDE)) >= 0 && level->walls[wall].height > self->position.y)
    {
        xdir = 0;
        if ( self->falling && (self->modeldata.hitwalltype < 0 || (self->modeldata.hitwalltype >= 0 && level->walls[wall].type == self->modeldata.hitwalltype)) ) hit |= 1;
        execute_onblockw_script(self, &level->walls[wall], PLANE_X, wall);
    }
    if(zdir && (wall = checkwall_below(self->position.x, z, T_MAX_CHECK_ALTITUDE)) >= 0 && level->walls[wall].height > self->position.y)
    {
        zdir = 0;
        if ( self->falling && (self->modeldata.hitwalltype < 0 || (self->modeldata.hitwalltype >= 0 && level->walls[wall].type == self->modeldata.hitwalltype)) ) hit |= 1;
        execute_onblockw_script(self, &level->walls[wall], PLANE_Z, wall);
    }

    if ( hit && !self->hitwall && validanim(self, ANI_HITWALL) ) ent_set_anim(self, ANI_HITWALL, 0);
    if ( hit && !self->hitwall ) self->hitwall = 1;
}

Uses this checkwall function...

C:
// get a highest wall below this altitude
int checkwall_below(float x, float z, float a)
{
    float maxa;
    int i, ind;

    if(level == NULL)
    {
        return -1;
    }

    maxa = 0;
    ind = -1;
    for(i = 0; i < level->numwalls; i++)
    {
        if(testwall(i, x, z) && level->walls[i].height <= a && level->walls[i].height > maxa)
        {
            maxa = level->walls[i].height;
            ind = i;
        }
    }

    return ind;
}

Which is itself dependent on a test wall function...

C:
/*
Calculates the coef relative to the bottom left point. This is done by figuring out how far the entity is from
the bottom of the platform and multiplying the result by the difference of the bottom left point and the top
left point divided by depth of the platform. The same is done for the right side, and checks to see if they are
within the bottom/top and the left/right area.
*/
int testwall(int wall, float x, float z)
{
    float coef1, coef2;

    //if(wall >= level->numwalls || wall < 0) return 0;
    if(z <= level->walls[wall].z && z >= level->walls[wall].z - level->walls[wall].depth)
    {
        coef1 = (level->walls[wall].z - z) * ((level->walls[wall].upperleft - level->walls[wall].lowerleft) / level->walls[wall].depth);
        coef2 = (level->walls[wall].z - z) * ((level->walls[wall].upperright - level->walls[wall].lowerright) / level->walls[wall].depth);
        if(x >= level->walls[wall].x + level->walls[wall].lowerleft + coef1 && x <= level->walls[wall].x + level->walls[wall].lowerright + coef2)
        {
            return 1;
        }
    }

    return 0;
}

All that said, what's likely happening in your first example is the wall script IS firing - but it's firing continuously, so your arrow is playing the first frame of that animation every update. I would put in a log trace to see.

In your second example, it's the same thing that happened to Valis in PM. Entities get shunted straight out of existence, so the wall script doesn't matter any more. I'd have to really dig around to see how the engine decides when and how much to shunt, and I'm kind of busy with something else (for you actually) to be doing those kinds of unit tests at the moment. Sorry.

DC
 
In your second example, it's the same thing that happened to Valis in PM. Entities get shunted straight out of existence, so the wall script doesn't matter any more. I'd have to really dig around to see how the engine decides when and how much to shunt, and I'm kind of busy with something else (for you actually) to be doing those kinds of unit tests at the moment. Sorry.
Thanks for the explanation, no need to worry, I think I have the value noted somewhere, I will look for it later.

All that said, what's likely happening in your first example is the wall script IS firing - but it's firing continuously, so your arrow is playing the first frame of that animation every update. I would put in a log trace to see.
Probably, because if I add an animationscript to force the change upon wall detection, the new animation is fired, but the jumpframe is ignored
 
All that said, what's likely happening in your first example is the wall script IS firing - but it's firing continuously, so your arrow is playing the first frame of that animation every update. I would put in a log trace to see.
Looks like it is playing all the frames (it has 2) as once I move the jumpframe from frame 0 to frame 1, it works
 
Back
Top Bottom