Moving an NPC Script

I’ve got a simple script that moves an NPC to a location:

void main()
{
object oArea = GetArea(OBJECT_SELF);
vector vDestination = Vector(132.0, 133.0, 0.0); // x:132, y:133, z:0
location locTarget = Location(oArea, vDestination, 90.0);
ActionMoveToLocation(locTarget);
}

However what if I wanted to move the NPC from its current location dynamically? Meaning what if I wanted him to travel North or South without stopping or going to a particular spot? Is it possible to manipulate the x,y, and z coordinates dynamically by adding to one and leaving the others the same? If so what would be the syntax?

You can add vectors.

vector vPos = GetPosition(OBJECT_SELF);
vPos.x += 10.f;

location lDest = Location(GetArea(OBJECT_SELF), vPos, 0.f);

They can also be extracted from a location w/ GetPositionFromLocation()

Thanks guys. Still working the idea of marching Roman soldiers.

am interested. I’d like to look over (and perhaps tweak) whatever scheme you come up with … tho my head is stuck in other code for a couple weeks.

OK here’s an issue . . . the first IF statement worked so I made a Do Loop, however my Do Loop fails to move the NPC. The LocalInt “move” is established as “1” through a conversation which also fires off the script.

void main()
//{
//
// object oPC = GetPCSpeaker();
// if (GetLocalInt(oPC, “move”) != 1 )
// {
// vector vPos = GetPosition(OBJECT_SELF);
// vPos.x += 10.f;
// location lDest = Location(GetArea(OBJECT_SELF), vPos, 0.f);
// ActionMoveToLocation(lDest);
// }
//}

{

object oPC = GetPCSpeaker();
	do
	{
    vector vPos = GetPosition(OBJECT_SELF);
    vPos.x += 10.f;
	location lDest = Location(GetArea(OBJECT_SELF), vPos, 0.f);
    ActionMoveToLocation(lDest);		
	}
	 while (GetLocalInt(oPC, "move") != 1 );

}

Thanks and I’ll definitely let you know when I’ve got a rough draft. My idea is to try and get one NPC following orders through a usable item and then have the group (6 x 5) work off their spatial relationship with him. I’m trying to keep it as “clean” as possible to allow for as many people as possible.

the do/while loop is basically infinite – too many instructions. I believe you want something like this:

void MoveNorth(object oPC);
void MoveNorthEast(object oPC);
void MoveEast(object oPC);
void MoveSouthEast(object oPC);
void MoveSouth(object oPC);
void MoveSouthWest(object oPC);
void MoveWest(object oPC);
void MoveNorthWest(object oPC);


void main(int dir)
{
    object oPC = GetPCSpeaker();

    switch (dir)
    {
        case 0:
            MoveNorth(oPC);
            break;
        case 1:
            MoveNorthEast(oPC);
            break;
        case 2:
            MoveEast(oPC);
            break;
        case 3:
            MoveSouthEast(oPC);
            break;
        case 4:
            MoveSouth(oPC);
            break;
        case 5:
            MoveSouthWest(oPC);
            break;
        case 6:
            MoveWest(oPC);
            break;
        case 7:
            MoveNorthWest(oPC);
            break;
    }
}

void MoveNorth(object oPC)
{
}

void MoveNorthEast(object oPC)
{
}

void MoveEast(object oPC)
{
    if (GetLocalInt(oPC, "move"))
    {
        vector vPos = GetPosition(oPC);
        vPos.x += 10.f;
        location lDest = Location(GetArea(oPC), vPos, 0.f);
        lDest = CalcSafeLocation(oPC, lDest, 1.f, TRUE, FALSE);

        ClearAllActions();
        ActionMoveToLocation(lDest);

        DelayCommand(3.f, MoveEast(oPC)); // recurse
    }
}

void MoveSouthEast(object oPC)
{
}

void MoveSouth(object oPC)
{
}

void MoveSouthWest(object oPC)
{
}

void MoveWest(object oPC)
{
}

void MoveNorthWest(object oPC)
{
}

eventually I’d like to see a 3x3 gui-scene (9 buttons) w/ the center btn for stop.

I was thinking of that (infinite loop) last night. I’ll work on it a bit today and see how it goes. Thanks!

Using yours as a base I set up the following. However the Action Stack/Queue is still not clearing when from the ClearAllActions. What happens is that I tell the Test NPC to move North and she does. However when I tell her to move South, she moves South for a moment but then tries to move North and then tries to move South, etc. I moved a ClearAllActions to the beginning of each directional script but that was not helpful either.

void MoveNorth(object oNPC);
void MoveNorthEast(object oNPC);
void MoveEast(object oNPC);
void MoveSouthEast(object oNPC);
void MoveSouth(object oNPC);
void MoveSouthWest(object oNPC);
void MoveWest(object oNPC);
void MoveNorthWest(object oNPC);
void Halt(object oNPC);


void main(int dir)
{
    object oNPC = GetObjectByTag("nx2_merris");
	
    switch (dir)
    {
        case 0:
            MoveNorth(oNPC);
            break;
        case 1:
            MoveNorthEast(oNPC);
            break;
        case 2:
            MoveEast(oNPC);
            break;
        case 3:
            MoveSouthEast(oNPC);
            break;
        case 4:
            MoveSouth(oNPC);
            break;
        case 5:
            MoveSouthWest(oNPC);
            break;
        case 6:
            MoveWest(oNPC);
            break;
        case 7:
            MoveNorthWest(oNPC);
            break;
		case 8:
			Halt(oNPC);
			break;
    }
}

void MoveNorth(object oNPC)
{
        ClearAllActions();
    	object oPC = GetPCSpeaker();
	    if (GetLocalInt(oPC, "move") != 1 )
    {
        vector vPos = GetPosition(oNPC);
        vPos.y += 10.f;
        location lDest = Location(GetArea(oNPC), vPos, 90.f);
        lDest = CalcSafeLocation(oNPC, lDest, 1.f, TRUE, FALSE);

        ClearAllActions();
        ActionMoveToLocation(lDest);
		
        DelayCommand(3.f, MoveNorth(oNPC)); // recurse
    }
}

void MoveNorthEast(object oNPC)
{
}

void MoveEast(object oNPC)
{
        ClearAllActions();
    	object oPC = GetPCSpeaker();
	    if (GetLocalInt(oPC, "move") != 1 )
    {
        vector vPos = GetPosition(oNPC);
        vPos.x += 10.f;
        location lDest = Location(GetArea(oNPC), vPos, 0.f);
        lDest = CalcSafeLocation(oNPC, lDest, 1.f, TRUE, FALSE);

        ClearAllActions();
        ActionMoveToLocation(lDest);

        DelayCommand(3.f, MoveEast(oNPC)); // recurse
    }
}

void MoveSouthEast(object oNPC)
{
}

void MoveSouth(object oNPC)
{
		ClearAllActions();

    	object oPC = GetPCSpeaker();
	    if (GetLocalInt(oPC, "move") != 1 )
    {	
		
        vector vPos = GetPosition(oNPC);
        vPos.y -= 10.f;
        location lDest = Location(GetArea(oNPC), vPos, 270.f);
        lDest = CalcSafeLocation(oNPC, lDest, 1.f, TRUE, FALSE);

		ClearAllActions();
        ActionMoveToLocation(lDest);
		
        DelayCommand(3.f, MoveSouth(oNPC)); // recurse
    }
}

void MoveSouthWest(object oNPC)
{
}

void MoveWest(object oNPC)
{
        ClearAllActions();
    	object oPC = GetPCSpeaker();
	    if (GetLocalInt(oPC, "move") != 1 )
    {
        vector vPos = GetPosition(oNPC);
        vPos.x -= 10.f;
        location lDest = Location(GetArea(oNPC), vPos, 180.f);
        lDest = CalcSafeLocation(oNPC, lDest, 1.f, TRUE, FALSE);

        ClearAllActions();
        ActionMoveToLocation(lDest);

        DelayCommand(3.f, MoveWest(oNPC)); // recurse
    }
}

void MoveNorthWest(object oNPC)
{
}
void Halt(object oNPC)
{
        vector vPos = GetPosition(oNPC);
        vPos.x = 0.f;
        vPos.y = 0.f;
        location lDest = Location(GetArea(oNPC), vPos, 0.f);
        lDest = CalcSafeLocation(oNPC, lDest, 1.f, TRUE, FALSE);

        ClearAllActions();

}

part of it could be that ClearAllActions() doesn’t seem to stop the walker pronto – creature continues to dest.

 
regardless, I think it’d help if direction-constants are used for each state:

something like this,

const int DIR_STOP      = -1;
const int DIR_NORTH     =  0;
const int DIR_NORTHEAST =  1;
const int DIR_EAST      =  2;
const int DIR_SOUTHEAST =  3;
const int DIR_SOUTH     =  4;
const int DIR_SOUTHWEST =  5;
const int DIR_WEST      =  6;
const int DIR_NORTHWEST =  7;

Set the local “move” to which state you call as current… because a problem is that since the check to move in any direction is the same condition (at present), you’re ending up with multiple Move*() calls recursing simultaneously. eg, to stop recursion of other states –

    case 0:
        SetLocalInt(oNPC, "move", DIR_NORTH);
        MoveNorth(oNPC);
        break;
void MoveNorth(object oNPC)
{
    // blah blah

    if (GetLocalInt(oNPC, "move") == DIR_NORTH)
    {
        // blah blah blah recurse only if DIR_NORTH
    }
}

 
 
ps. To format code in the forum use
[code]

[/code]

1 Like

I wonder if your recursive delayed command is still running? I think you need a way to kill all recursive calls before issuing new orders.

3 Likes

note: #include ‘ginc_group’ has Formations …

- some of the functions are a bit bugged (not bad tho). They might give ya functions/ideas that could be useful

Thanks kevL_s. I’ll take a look as I’ve had little success after messing around with a couple of possibilities.

I think Danaan Tactics had some work on tactical AI for the group. Not sure if that is any help though.

1 Like

I looked at it already and I think I need a “clean” script rather than pulling out. I’m thinking about setting up each movement as a separate script and doing a AssignCommand(,ClearAllActions) to begin it and see how that goes . . . however I will have to wait until my laptop is fixed.

In your script, I’d probably get rid of the first ClearAllActions, and I’d store the move variable on the oNPC so you don’t need to keep calling GetPCSpeaker.

honestly i’d move the vars for various objects out to a script-variables. But at present i’m unclear on the distinctions between oPC, oNPC, and OBJECT_SELF … so am not trying to optimize anything … just rapid firing a machine gun at a wall to show Sawdust what sort of damage can be done /jk

1 Like

LOL . . . already seen that . . . literally and figuratively.

1 Like