//////////////////////////////////////////////////////////////
// entmove.c - entity position and angle manipulation functions
// (c) oP group - jcl 2010
//////////////////////////////////////////////////////////////
#ifndef entmove_c
#define entmove_c
// macro for terminating prior function instances by the same entity
#define ENT_OVERRIDE(ent) if(!ent) return; ENTITY* old=me; me=ent; proc_kill(5); me=old
// rotate an entity relative to its own orientation
function ent_rotate(ENTITY* ent,speed_pan,speed_tilt,speed_roll)
{
ENT_OVERRIDE(ent);
while(speed_pan || speed_tilt || speed_roll) {
ang_rotate(ent.pan,vector(
speed_pan*time_step,
speed_tilt*time_step,
speed_roll*time_step));
wait(1);
}
}
// rotate an entity according to its skill1,2,3 values
action ent_rotor()
{
if (!my.skill1 && !my.skill2 && !my.skill3)
ent_rotate(me,2,0,0); // no skills -> just pan
else
ent_rotate(me,my.skill1,my.skill2,my.skill3);
}
//////////////////////////////////////////////////////////////////
// turn towards an absolute target angle with given angular speed
// use wait_for_my(ent_turnto) for determining when the angle is reached
function ent_turnto(ENTITY* ent,ANGLE* to,var aspeed)
{
ENT_OVERRIDE(ent);
// store the "to" angle for the wait loop - it could be a temporary vector!
ANGLE atarget;
vec_set(atarget,to);
while(aspeed) {
// calculate the difference between the current and the target angle
ANGLE adiff;
ang_diff(adiff,atarget,ent.pan);
// check if we're already there
if(vec_length(adiff) <= aspeed*time_step) {
vec_set(ent.pan,atarget);
return;
}
// scale the difference angle by the angular speed,
// and add it to the entity angle
vec_normalize(adiff,aspeed*time_step);
ang_add(ent.pan,adiff);
wait(1);
}
}
// turn towards a target position with given speed
// use wait_for_my(ent_turnto) for determining when the angle is reached
function ent_faceto(ENTITY* ent,VECTOR* pos,var aspeed)
{
if(!ent || !pos) return;
VECTOR* diff = vec_diff(NULL,pos,ent.x);
vec_to_angle(diff,diff);
ent_turnto(ent,diff,aspeed);
}
//////////////////////////////////////////////////////////////////
// move to an absolute position with given speed
// use wait_for_my(ent_moveto) for determining when the position is reached
function ent_moveto(ENTITY* ent,VECTOR* pos,var speed)
{
ENT_OVERRIDE(ent);
// store the "pos" vector for the wait loop - it could be a temporary vector!
VECTOR vpos;
vec_set(vpos,pos);
while(speed) {
// calculate the difference between the current and the target position
VECTOR diff;
vec_diff(diff,vpos,ent.x);
// check if we're already there
if(vec_length(diff) <= speed*time_step) {
vec_set(ent.x,vpos);
return;
}
// scale the difference vector by the speed,
// and add it to the entity position
vec_normalize(diff,speed*time_step);
vec_add(ent.x,diff);
wait(1);
}
}
// move to a relative position with given speed
// use wait_for_my(ent_moveto) for determining when the position is reached
function ent_moveby(ENTITY* ent,VECTOR* pos,var speed)
{
if(!ent || !pos) return;
ent_moveto(ent,vec_add(pos,my.x),speed);
}
//////////////////////////////////////////////////////////////////
// place an entity on the floor below
function ent_placefloor(ENTITY* ent)
{
// get the entity's feet distance
VECTOR vMin;
vec_for_min(vMin,ent);
vMin.z *= ent.scale_z;
// find the ground below the entity origin
ENTITY* old=me; me=ent;
c_trace(
vector(ent.x,ent.y,ent.z+10),
vector(ent.x,ent.y,ent.z-1000),
IGNORE_ME | IGNORE_PASSABLE | IGNORE_SPRITES);
me=old;
// place the lowest part (vMin.z) on the ground (hit.z)
if(HIT_TARGET) ent.z = hit.z-vMin.z;
}
// let an entity move along a closed path with given speed
function ent_movepath(ENTITY* ent,char* pathname,var speed,var mode)
{
ENT_OVERRIDE(ent);
var vLastPos[3],vDir[3];
vec_set(vLastPos,ent.x);
var dist = 0;
if (pathname) path_set(ent,pathname);
while(speed)
{
// place the entity along the path
path_spline(ent,ent.x,dist);
dist += speed*time_step;
// adjust the entity to the floor
if(mode&1)
ent_placefloor(ent);
// let the entity look ahead in movement direction
if(mode&2) {
vec_diff(vDir,ent.x,vLastPos);
vec_to_angle(ent.pan,vDir);
vec_set(vLastPos,ent.x);
}
wait(1);
}
}
#endif