Script to avoid Stuck NPC

O Ilusionista

Captain 100K
I'm writing some code to prevent the NPC from getting stuck off-screen in levels that have walls.
Since they are set to be "subject to screen," that's the only scenario where they could end up off-screen.
So, I created code to grab P1's position (since P1 is always on-screen—it's a single-player mode) and direction, then teleport the NPC to P1's location and switch to the respawn animation, which acts like a teleport.

I'm calling this function during both the NPC's walk and run states, but unfortunately, nothing happens.
even if I use killentity or try to log a message, nothing happens, which means that something is wrong on the logic but I can't pinpoint what.

The code is identifying cases where the NPC is off-screen—both beyond the screen boundaries and before the screen starts—because I am reusing another function that already works.

C-like:
void isOffScreenNPC(){
// Check if the NPC is stuck offscreen and teleport it to P1 position
// Douglas Baldan / O Ilusionista - 16.08.2026
void self = getlocalvar("self");
int  XPos  = openborvariant("xpos");
int selfx = getentityproperty(self, "x");
int Screenwidth = openborvariant("hResolution"); // Get screen width
int P1 = getplayerproperty(0, "entity");
int P1X = getentityproperty(P1, "x"); //Get X location and add adjustment.
int P1Y = getentityproperty(P1, "y"); //Get X location and add adjustment.
int P1Z = getentityproperty(P1, "z"); //Get X location and add adjustment.
int P1D = getentityproperty(P1, "direction"); //Get X location and add adjustment.

    if (selfx > XPos + Screenwidth){
        return 1;
        if (P1){
            changeentityproperty(self, "position", P1X, P1Z,P1Y);
            changeentityproperty(self, "direction", P1D);
            changeentityproperty(self, "animation",openborconstant("ANI_RESPAWN"));
        } // beyond camera pos
    if (selfx < XPos){
        return 2;
        if (P1){
            changeentityproperty(self, "position", P1X, P1Z,P1Y);
            changeentityproperty(self, "direction", P1D);
            changeentityproperty(self, "animation",openborconstant("ANI_RESPAWN"));
        } // before camera pos
    }
    }
}
 
Thanks @Kratus for the fix - it was my mistake of using "return" before the position change.

Here is the fixed vesion:

C-like:
void isOffScreenNPC(){
// Check if the NPC is stuck offscreen and teleport it to P1 position
// Douglas Baldan / O Ilusionista - 16.08.2026
// Thanks Kratus
void self = getlocalvar("self");
int  XPos  = openborvariant("xpos");
int selfx = getentityproperty(self, "x");
int Screenwidth = openborvariant("hresolution"); // Get screen width
int P1 = getplayerproperty(0, "entity");
int P1X = getentityproperty(P1, "x"); //Get X location and add adjustment.
int P1Y = getentityproperty(P1, "y"); //Get X location and add adjustment.
int P1Z = getentityproperty(P1, "z"); //Get X location and add adjustment.
int P1D = getentityproperty(P1, "direction"); //Get X location and add adjustment.

    if (selfx > XPos + Screenwidth){
        if (P1){
            changeentityproperty(self, "position", P1X, P1Z,P1Y);
            changeentityproperty(self, "direction", P1D);
            changeentityproperty(self, "animation",openborconstant("ANI_RESPAWN"));
            } // beyond camera pos
            return 1;
    } else if (selfx < XPos){
        if (P1){
            changeentityproperty(self, "position", P1X, P1Z,P1Y);
            changeentityproperty(self, "direction", P1D);
            changeentityproperty(self, "animation",openborconstant("ANI_RESPAWN"));
            } // before camera pos
            return 2;
        }
}
 
Last edited:
Thanks @Kratus for the fix - it was my mistake of using "return" before the position change.

Here is the fixed vesion:

C-like:
void isOffScreenNPC(){
// Check if the NPC is stuck offscreen and teleport it to P1 position
// Douglas Baldan / O Ilusionista - 16.08.2026
void self = getlocalvar("self");
int  XPos  = openborvariant("xpos");
int selfx = getentityproperty(self, "x");
int Screenwidth = openborvariant("hresolution"); // Get screen width
int P1 = getplayerproperty(0, "entity");
int P1X = getentityproperty(P1, "x"); //Get X location and add adjustment.
int P1Y = getentityproperty(P1, "y"); //Get X location and add adjustment.
int P1Z = getentityproperty(P1, "z"); //Get X location and add adjustment.
int P1D = getentityproperty(P1, "direction"); //Get X location and add adjustment.

    if (selfx > XPos + Screenwidth){
        if (P1){
            changeentityproperty(self, "position", P1X, P1Z,P1Y);
            changeentityproperty(self, "direction", P1D);
            changeentityproperty(self, "animation",openborconstant("ANI_RESPAWN"));
        } // beyond camera pos
        return 1;
    if (selfx < XPos){
        if (P1){
            changeentityproperty(self, "position", P1X, P1Z,P1Y);
            changeentityproperty(self, "direction", P1D);
            changeentityproperty(self, "animation",openborconstant("ANI_RESPAWN"));
        } // before camera pos
        return 2;
    }
    }
}
Will this script help with enemies as well that may run or walk off screen and never come back, causing you not to be able to progress in a level? If so where would I place this script exactly?
 
Will this script help with enemies as well that may run or walk off screen and never come back, causing you not to be able to progress in a level? If so where would I place this script exactly?
Yes but it would look weird if you use it like that. In my case, my respawn animation for NPC and players has a teleport effect, so it won't look weird.

This is something I use for enemies: if they are stuck outside the screen, the engine will just kill them and call it a day

C-like:
void offScreenKill(){
// Check if an entity is offscreen and kill it
// Douglas Baldan / O Ilusionista - 07.05.2021
void self = getlocalvar("self");
int  XPos  = openborvariant("xpos");
int selfx = getentityproperty(self, "x");
int Screenwidth = openborvariant("hResolution"); // Get screen width
int stageT = getglobalvar("stageType");

if (stageT != "noOffscreenKill"){
    if (selfx > XPos + Screenwidth) { // beyond camera pos
        killentity(self);
    } else if (selfx < XPos){  // before camera pos
        killentity(self);
        }
    }
}

I use it as an animtionscript and just call it in the enemies walk animation:
@cmd offScreenKill
 
ok well I don't want the weird teleport enemies to me. lol. I gotta figure out what is causing my enemies to sometime walk pass my player and never comeback causing me to not progress. I'm new to this whole stage building thing and I think that's my main problem of what's causing them to leave and not comeback.
 
I'll check and see that I have that implemented on all of them. I know I've put that on most of them but it seems to happen with the sprinting enemies with running attacks.
If they have subject_to_screen 1 on their header, the only way for them to be able to move outside the screen is stuck behind a wall while you move (like in my case)
 
Keeping enemies from going too far offscreen is doable. There are 2 ways (at least) to do it:
1. Placing a pair of invisible huge block offscreen, one to the left and the other to the right. The one on the right could be removed with script if needed to allow progressing.
2. Using enemy puller which slowly pulls any enemy going offscreen to the screen. Enemies which shouldn't be pulled could use certain flag to exclude them from the puller.
 
Back
Top Bottom