Here are all the vital snippets. Like I said though, it'll take a good bit of adaption, but this contains everything you need to get fear working. With it a feared creature will flee in a random direction, avoiding walls, cliffs and pits.
Code:
void Mob::CalculateNewFearpoint()
{
int loop = 0;
float ranx, rany, ranz;
curfp = false;
while (loop < 100) //Max 100 tries
{
int ran = 250 - (loop*2);
loop++;
ranx = GetX()+rand()%ran-rand()%ran;
rany = GetY()+rand()%ran-rand()%ran;
ranz = FindGroundZ(ranx,rany);
if (ranz == -999999)
continue;
float fdist = ranz - GetZ();
if (fdist >= -12 && fdist <= 12 && CheckCoordLosNoZLeaps(GetX(),GetY(),GetZ(),ranx,rany,ranz))
{
curfp = true;
break;
}
}
if (curfp)
{
fear_walkto_x = ranx;
fear_walkto_y = rany;
fear_walkto_z = ranz;
}
else //Break fear
{
BuffFadeByEffect(SE_Fear);
}
}
Code:
float Mob::FindGroundZ(float new_x, float new_y, float z_offset)
{
float ret = -999999;
if (zone->map != 0)
{
NodeRef pnode = zone->map->SeekNode( zone->map->GetRoot(), new_x, new_y );
if (pnode != NODE_NONE)
{
VERTEX me;
me.x = new_x;
me.y = new_y;
me.z = z_pos+z_offset;
VERTEX hit;
FACE *onhit;
float best_z = zone->map->FindBestZ(pnode, me, &hit, &onhit);
if (best_z != -999999)
{
ret = best_z;
}
}
}
return ret;
}
Code:
bool Entity::CheckCoordLosNoZLeaps(float cur_x, float cur_y, float cur_z, float trg_x, float trg_y, float trg_z, float perwalk)
{
if(zone->map == NULL) {
return(true);
}
VERTEX myloc;
VERTEX oloc;
VERTEX hit;
myloc.x = cur_x;
myloc.y = cur_y;
myloc.z = cur_z+5;
oloc.x = trg_x;
oloc.y = trg_y;
oloc.z = trg_z+5;
if (myloc.x == oloc.x && myloc.y == oloc.y && myloc.z == oloc.z)
return true;
FACE *onhit;
if (!zone->map->LineIntersectsZoneNoZLeaps(myloc,oloc,perwalk,&hit,&onhit))
return true;
return false;
}
Code:
bool Map::LineIntersectsZoneNoZLeaps(VERTEX start, VERTEX end, float step_mag, VERTEX *result, FACE **on) {
float z = -999999;
VERTEX step;
VERTEX cur;
cur.x = start.x;
cur.y = start.y;
cur.z = start.z;
step.x = end.x - start.x;
step.y = end.y - start.y;
step.z = end.z - start.z;
float factor = step_mag / sqrt(step.x*step.x + step.y*step.y + step.z*step.z);
step.x *= factor;
step.y *= factor;
step.z *= factor;
int steps = 0;
if (step.x > 0 && step.x < 0.001f)
step.x = 0.001f;
if (step.y > 0 && step.y < 0.001f)
step.y = 0.001f;
if (step.z > 0 && step.z < 0.001f)
step.z = 0.001f;
if (step.x < 0 && step.x > -0.001f)
step.x = -0.001f;
if (step.y < 0 && step.y > -0.001f)
step.y = -0.001f;
if (step.z < 0 && step.z > -0.001f)
step.z = -0.001f;
NodeRef cnode, lnode;
lnode = NULL;
int i = 0;
//while we are not past end
//always do this once, even if start == end.
while(cur.x != end.x || cur.y != end.y || cur.z != end.z)
{
steps++;
cnode = SeekNode(GetRoot(), cur.x, cur.y);
if (cnode == NODE_NONE)
{
return(true);
}
VERTEX me;
me.x = cur.x;
me.y = cur.y;
me.z = cur.z;
VERTEX hit;
FACE *onhit;
float best_z = zone->map->FindBestZ(cnode, me, &hit, &onhit);
float diff = best_z-z;
diff *= sign(diff);
if (z == -999999 || best_z == -999999 || diff < 12.0)
z = best_z;
else
return(true);
//look at current location
if(cnode != NODE_NONE && cnode != lnode) {
if(LineIntersectsNode(cnode, start, end, result, on))
{
return(true);
}
lnode = cnode;
}
//move 1 step
if (cur.x != end.x)
cur.x += step.x;
if (cur.y != end.y)
cur.y += step.y;
if (cur.z != end.z)
cur.z += step.z;
//watch for end conditions
if ( (cur.x > end.x && end.x >= start.x) || (cur.x < end.x && end.x <= start.x) || (step.x == 0) ) {
cur.x = end.x;
}
if ( (cur.y > end.y && end.y >= start.y) || (cur.y < end.y && end.y <= start.y) || (step.y == 0) ) {
cur.y = end.y;
}
if ( (cur.z > end.z && end.z >= start.z) || (cur.z < end.z && end.z < start.z) || (step.z == 0) ) {
cur.z = end.z;
}
}
//walked entire line and didnt run into anything...
return(false);
}