EQEmulator Forums

EQEmulator Forums (https://www.eqemulator.org/forums/index.php)
-   Archive::Development (https://www.eqemulator.org/forums/forumdisplay.php?f=621)
-   -   NPC Grid Pause Bug (https://www.eqemulator.org/forums/showthread.php?t=9385)

Scorpious2k 09-12-2003 01:29 AM

NPC Grid Pause Bug
 
There is a bug in 4.4 that will cause roaming NPCs, moving along a grid to stop at a waypoint. Here is the fix we have put in at the Scorpious2k server.

The problem is in MovAI.CPP. In Mob::AI_Process() you find the following performed almost immediately on entry:

Code:

        if (AIwalking_timer->Check())
        {
                timercompleted=true;
                AIwalking_timer->Disable();
        }

the timer is disabled and the LOCAL variable timercompleted is set to true to indicate that the pause time is up and it is time for the mob to move.

The problem is that, because of other considerations, it may not get to the part of the function that gets the new waypoint, resets the timer to the new pause time and starts moving it.

The next time (and subsequent times) it will find the timer disabled and the local variable reset... so the mob will no longer move.

I considered several possible solutions to this problem. The timer does have to be disabled so that can't be removed. Finally I came up with this:

Find the line

Code:

                        else if (roamer)
                              {

and add the line
AIwalking_timer->Enable();

so it looks like this

Code:

        else if (roamer)
        {
            AIwalking_timer->Enable();

that will re-enable the timer and let the process continue. So far, this has worked perfectly for us (been testing it for 2 days so it may not be perfect).

I hope this helps.[/i][/b]

tcsmyworld 09-12-2003 01:40 AM

With the timer still being in the MobAI.cpp tho , do you still have the first in - first out npc movement?
Or do the mobs all move about freely?
The only way I was able to get ALL mobs moving without first in - first out , was to move timer into Mob.h , but it didn't fix the whole problem.

Scorpious2k 09-12-2003 01:48 AM

I didn't look, but I'm sure its still FIFO. Since I use random or random-half pauses unless I absolutely have to stay at a waypoint for a fixed time, it would be hard to tell by watching them.

It might interest you too, that this seems to have reduced the lag from zones with moving mobs.

I was actually forced to find and fix this problem because it got in the way of making the boats work. We have come up with a way to do that and are in the process of implementing it.

I will post the how-to when we have enough done to make it worthwhile for the other server ops. Its complex, but not especially difficult. The explination will be long.

krich 09-12-2003 06:23 AM

Excellent work Scorp. I was working on this as well and you beat me to it. From your description sounds like I was on the right track anyways...

As an added bonus, your contribution will allow tcsmyworld to sleep at night now.

Regards,

krich

tcsmyworld 09-12-2003 06:56 AM

Thanks a ton scorpious2k :)
I threw in a small twist and wound up with exactly what i was looking for, move the timer into Mob.h and it lets each npc run on it's own timer , no first in - first out :)

Krich get ahold of me , on irc channel or PM me :idea:

krich 09-12-2003 07:19 AM

TCS,


I got your message, but am having problems with replying to the PM...not sure why. Anyway, the short answer is yes. I'll contact you later on.

Regards,

krich

Scorpious2k 09-16-2003 12:08 PM

ok, the celebration was a bit premature. yes it worked, but it was more of a band-aid than a cure. I wasn't happy with it, and felt it wasn't right. Timing pauses on npcs proved it. So I dug back in and ended up redoing a lot of the logic. It now works *perfectly*. But this is a major overhaul, not just a simple fix...

There were several problems. When spawned, the npc never paused at the first wp. The program logic actually assigned the pause time and started the timer at the time of the wp change. So the timer started at the time the npc started moving towards the next wp not when it got there. There were a few others, but who cares, right? All you want is the fix. :-)

this is for 4.4 (of course) here it is....

in mob.h add the declaration

Code:

        void        SetWaypointPause();
in mobAI.cpp Mob::AI_Process add this var at the top

Code:

        int16 gridno;
if you added the enable timer previously discussed, get rid of it
move the following from its position near the top

Code:

        if (AIwalking_timer->Check())
        {
                timercompleted=true;
                AIwalking_timer->Disable();
        }

to immediately after the else if (roamer) and add the line gridno = this->CastToNPC()->GetGrid(); so it looks like this

Code:

                else if (roamer)
                {
                                  if  (AIwalking_timer->Check())       
                                  {
                                  timercompleted=true;
                        AIwalking_timer->Disable();
                                  }
                       
                                  gridno = this->CastToNPC()->GetGrid();

at this point I should mention that I have been installing boats on the Scorpious2k server and changed the "rules" for boats. Any grid number from 1-49 is considered a boat in that it makes a single run along the grid from 1 to the end and then depops. the following code reflects that. if that causes problems for you, you will want to change it.

anway, replace the rest of Mob::AI_Process from this point down with the following so that starting at the else if (roamer) it looks like this

Code:

                                        else if (roamer)
                                        {
                                                if (AIwalking_timer->Check())        // this really belongs here not at the top
                                                {
                                                        timercompleted=true;
                                                        AIwalking_timer->Disable();
                                                }
                                               
                                                gridno = this->CastToNPC()->GetGrid();

                                                if (gridno > 0)
                                                {
                                                        if (timercompleted==true)       
                                                        {
                                                                if (gridno < 50 && cur_wp == max_wp)
                                                                {
                                                                        printf("Depoping Ship\n");
                                                                        this->CastToNPC()->Depop();
                                                                }
                                                                else
                                                                {
                                                                                timercompleted=false;
                                                                                char temp[100];
                                                                                parse->Event(7,this->GetNPCTypeID(), itoa(cur_wp,temp,10), this->CastToMob(), 0);
                                                                                CalculateNewWaypoint();
                                                                                SetAppearance(0, false);
                                                                }
                                                        }
                                                        else if (!(AIwalking_timer->Enabled())
                                                                && cur_wp_x == GetX() && cur_wp_y == GetY())
                                                        {
                                                                        SetWaypointPause();
                                                        }
               
                                                }
                                                        CalculateNewPosition(cur_wp_x, cur_wp_y, cur_wp_z, GetWalkspeed());
                                                }
                                                else if (!(GetGuardX() == 0 && GetGuardY() == 0 && GetGuardZ() == 0))
                                                {
                                                        if (!CalculateNewPosition(GetGuardX(), GetGuardY(), GetGuardZ(), GetWalkspeed()))
                                                        {
                                                                if (!GetTarget() || (GetTarget() && CalculateDistance(GetTarget()->GetX(),GetTarget()->GetY(),GetTarget()->GetZ()) >= 5) ) SetHeading(GetGuardHeading());
                                                                else { FaceTarget(GetTarget(), true);
                                                        }
                                                }
                                        }
                                }
                        }
                } // else if (AImovement_timer->Check())
        }

in Mob::CalculateNewWaypoint remove

Code:

       
        //Declare time to wait on current WP
       
        if (cur_wp_pause == 0) {
                AIwalking_timer->Start(100);
        }
        else
        {
               
                switch (pausetype)
                {
                case 0: //Random Half
                        AIwalking_timer->Start((cur_wp_pause - rand()%cur_wp_pause/2)*1000);
                        break;
                case 1: //Full
                        AIwalking_timer->Start(cur_wp_pause*1000);
                        break;
                case 2: //Random Full
                        AIwalking_timer->Start((rand()%cur_wp_pause)*1000);
                        break;
                }
        }

and create a new function
Code:

void Mob::SetWaypointPause()
{
        //Declare time to wait on current WP
       
        if (cur_wp_pause == 0) {
                AIwalking_timer->Start(100);
        }
        else
        {
               
                switch (pausetype)
                {
                case 0: //Random Half
                        AIwalking_timer->Start((cur_wp_pause - rand()%cur_wp_pause/2)*1000);
                        break;
                case 1: //Full
                        AIwalking_timer->Start(cur_wp_pause*1000);
                        break;
                case 2: //Random Full
                        AIwalking_timer->Start((rand()%cur_wp_pause)*1000);
                        break;
                }
        }
}

That will fix the npc grid pause timing problems. It might be interesting to note that I use the fact that the timer is disabled to indicate that the npc is in transition between waypoints, so the previous "fix" will break it.

Finally in Mob::AssignWaypoints after the following
Code:

                        else { //Retrieve a waypoint
                                wplist * newwp = new wplist;
                                adverrorinfo = 7564;
                                Seperator sep(wpstruct, ' ', 4);
                                newwp->x        = atof(sep.arg[0]);
                                newwp->y        = atof(sep.arg[1]);
                                newwp->z        = atof(sep.arg[2]);
                                newwp->pause = atoi(sep.arg[3]);
                                newwp->index = i-2;
//                                printf("New Waypoint: X: %f - Y: %f - Z: %f - P: %d - Index: %d - MaxWp: %d\n", newwp->x, newwp->y, newwp->z, newwp->pause, newwp->index, max_wp);
                                if (newwp->x && newwp->y && newwp->z) {
                                        max_wp                = newwp->index;
                                        Waypoints.AddItem(newwp);
                                }
                        }

add the lines

Code:

                        UpdateWaypoint(0);
                        SetWaypointPause();

that fixes the problem with a new spawn not pausing in the first wp

<whew>

hope I didn't forget anything... I posted this in a hurry so I could get the info out. might even be useful in 5.0. [/b]

Merth 09-16-2003 02:10 PM

Holy crap that's a lot of work! Good job.

I don't believe the AI engine has changed at all in 0.5.0, so it may port directly. Unfortunately, I've got my hands tied up in too many other pieces of code at the moment. I'm going to make this a sticky to remind us to integrate it when the time comes.

Scorpious2k 09-17-2003 12:49 AM

Quote:

Originally Posted by MerthEQ
Holy crap that's a lot of work! Good job.

Thanks, I had a good day :-)


Quote:

Originally Posted by MerthEQ
I don't believe the AI engine has changed at all in 0.5.0, so it may port directly. Unfortunately, I've got my hands tied up in too many other pieces of code at the moment.

If it would help, I could get the changed version to you. If nothing has been done with it yet and it will port in easily, it might provide a starting base at least.

If you want to do this, there is one thing I'd like to do first. I have it set now so all grids numbered 1-49 are a "1 way 1 time" type. They simply follow the waypoints from 1 to the end and then depop. I'm using it for boats, but there could be other uses. So what I'd like to do is change it to a new wander type rather than have it based on the grid id.

Let me know about getting the code to you and about the new wander type. Always glad to help out on the project.

kathgar 11-23-2003 06:17 AM

merged in, by trump, love him

mangoo 11-23-2003 07:27 AM

omg ban kathgar for bumping!!!!


All times are GMT -4. The time now is 04:58 AM.

Powered by vBulletin®, Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.