According to my tests, stuff moves across the screen. While a bit rough, it gets the job done (for now). This will put together a data structure that allows one to setup a way to move npc types around a zone. Currently, the data is not persistent and only loads the points when the zone is booted. Is there really a good reason to make persistent pathing points? Anyway, here is the code, hope it helps!
database structure:
Code:
CREATE TABLE path_points(
id int(11) NOT NULL auto_increment,
npctypeid int(11) NOT NULL default '0', //from table npc_types, using key (id)
zone varchar(16) NOT NULL default '', //short zone name
x float NOT NULL default '0',
y float NOT NULL default '0',
z float NOT NULL default '0',
MoveRate float NOT NULL default '0', //float representing how fast the critter needs to move
step int NOT NULL default '0', //what step in the linear sequence are we?
primary key (id)
);
insert into path_points(npctypeid,zone,x,y,z,MoveRate,step) values ('4057','misty',-200,-200,0,1.00,0);
insert into path_points(npctypeid,zone,x,y,z,MoveRate,step) values ('4057','misty',-100,-100,0,1.00,1);
Changes to zone.h
Code:
///////////////////////
//Malevolent:
//Data structure that contains information about a zone's pathing points
struct PathPoint {
float x;
float y;
float z;
int step;
float movement_increment; //float value to increase movement value by
int NPC_TypeID; //maybe make this an array of ints, so more than 1 npc can use a path?
};
Public:
LinkedList<PathPoint*> PathPointsList; //Malevolent: pathing points collection
Changes to zone.cpp
Code:
///////////////////////////////
//Malevolent: PathPoint, load data
bool Database::PopulateZonePathPoint(char* zone_name, LinkedList<PathPoint*> &PathPointsList, int32 repopdelay) {
//, LinkedList<PathPoint*> &PathPointsList, int32 repopdelay
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
MakeAnyLenString(&query, "SELECT x, y, z, zone, npctypeid, MoveRate FROM path_points WHERE zone='%s'", zone_name);
if (RunQuery(query, strlen(query), errbuf, &result))
{
delete[] query;
while(row = mysql_fetch_row(result))
{
PathPoint* pp = new PathPoint;
ZonePoint* zp = new ZonePoint;
pp->x = atof(row[0]); //x coordinate to move to
pp->y = atof(row[1]); //y coordinate to move to
pp->z = atof(row[2]); //z coordinate currently not used
pp->movement_increment = atof(row[5]); //movement incremental value (how far to move the critter)
pp->NPC_TypeID = atoi(row[4]); //the *npc_type* to move...todo: make it the spawn id
PathPointsList.Insert(pp);
}
mysql_free_result(result);
}
else
{
cerr << "Error in PopulateZonePathPoints query '" << query << "' " << errbuf << endl;
delete[] query;
return false;
}
return true;
}
Changes to npc.cpp
Code:
//////////////////////////////
//Malevolent:
//Walk npc to one of the pathpoints setup for it in db
void NPC::PathPointSendTo()
{
//Build list
LinkedListIterator<PathPoint*> iterator(zone->PathPointsList);
iterator.Reset();
while(iterator.MoreElements())
{
PathPoint* pp = iterator.GetData();
if (this->GetPathPointStep() == pp->step) /// are we on the right step?
if (this->GetNPCTypeID() == pp->NPC_TypeID) ///make sure that the npc matches
{
//todo: find a better way to get there--maybe add a flag to use different pathfinding techniques?
if (pp->x > this->GetX())
{
this->x_pos=this->GetX()+pp->movement_increment;
}
if (pp->y > this->GetY())
{
this->y_pos=this->GetY()+pp->movement_increment;
}
//what's a good way to check for optimal z coordinate?
this->z_pos=0;
//lastly, check to ensure that we haven't completed out objective
//and if so, then increase the step value
if ((pp->x < this->GetX()) && pp->y < this->GetY())
this->SetPathPointStep(this->GetPathPointStep()+1);
//Update spawn position. Don't use fale as it kills performance
SendPosUpdate(true);
//todo some way to reset the step counter (after respawn or after ticks, or maybe just let it loop, /shrug?)
} //end if
iterator.Advance();
}//end while
}
npc.cpp, within ::Process() right before the final return true;
Code:
//Malevolent
//Walk through the zone pathing points
//if the target is not engaged and if the movement timer says its ok
if(!this->IsEngaged()&&movement_timer->Check())
{
this->PathPointSendTo();
return true;
}
npc.cpp in npc::npc
Code:
SetPathPointStep(0); //always start out at step 0 for a new npc
npc.h
Code:
public:
void PathPointSendTo();
uint32 GetPathPointStep() { return PathPointStep; }
void SetPathPointStep(int step_value);
Protected:
uint32 PathPointStep;
--MV
(formerly known as ScotchTape)