413 lines
8.5 KiB
C
413 lines
8.5 KiB
C
|
|
#include "quakedef.h"
|
|
|
|
|
|
#define MELEE_DISTANCE 80
|
|
|
|
//range
|
|
#define RANGE_MELEE 0
|
|
#define RANGE_NEAR 1
|
|
#define RANGE_MID 2
|
|
#define RANGE_FAR 3
|
|
|
|
//gib types
|
|
#define GIB_ORGANIC 0
|
|
#define GIB_METALLIC 1
|
|
|
|
//monster ai flags
|
|
#define AI_STAND_GROUND 0x00000001
|
|
#define AI_TEMP_STAND_GROUND 0x00000002
|
|
#define AI_SOUND_TARGET 0x00000004
|
|
#define AI_LOST_SIGHT 0x00000008
|
|
#define AI_PURSUIT_LAST_SEEN 0x00000010
|
|
#define AI_PURSUE_NEXT 0x00000020
|
|
#define AI_PURSUE_TEMP 0x00000040
|
|
#define AI_HOLD_FRAME 0x00000080
|
|
#define AI_GOOD_GUY 0x00000100
|
|
#define AI_BRUTAL 0x00000200
|
|
#define AI_NOSTEP 0x00000400
|
|
#define AI_DUCKED 0x00000800
|
|
#define AI_COMBAT_POINT 0x00001000
|
|
#define AI_MEDIC 0x00002000
|
|
#define AI_RESURRECTING 0x00004000
|
|
|
|
//monster attack state
|
|
#define AS_STRAIGHT 1
|
|
#define AS_SLIDING 2
|
|
#define AS_MELEE 3
|
|
#define AS_MISSILE 4
|
|
|
|
|
|
void PF_changeyaw (void);
|
|
qboolean SV_StepDirection (edict_t *ent, float yaw, float dist);
|
|
float VectorLength( const vec3_t v );
|
|
float vectoyaw (vec3_t value1);
|
|
|
|
|
|
float changeyaw (float ideal, float speed, float current)
|
|
{
|
|
// edict_t *ent;
|
|
float move;
|
|
|
|
current = anglemod( current );
|
|
|
|
if (current == ideal)
|
|
return current;
|
|
|
|
move = ideal - current;
|
|
if (ideal > current)
|
|
{
|
|
if (move >= 180)
|
|
move = move - 360;
|
|
}
|
|
else
|
|
{
|
|
if (move <= -180)
|
|
move = move + 360;
|
|
}
|
|
|
|
if (move > 0)
|
|
{
|
|
if (move > speed)
|
|
move = speed;
|
|
}
|
|
else
|
|
{
|
|
if (move < -speed)
|
|
move = -speed;
|
|
}
|
|
|
|
return anglemod (current + move);
|
|
}
|
|
|
|
|
|
edict_t *NextClient (edict_t *edict)
|
|
{
|
|
int e;
|
|
edict_t *ent;
|
|
|
|
e = NUM_FOR_EDICT (edict); // Get the edictnum
|
|
|
|
while (1) // Loop until we get a return
|
|
{
|
|
e++; // Increase e with 1
|
|
|
|
if (e == sv.num_edicts) // If gone through all edict's
|
|
return sv.edicts; // then return
|
|
|
|
ent = EDICT_NUM (e); // Get the edict from the new edictnum
|
|
|
|
if (!ent->free) // If it exists
|
|
return ent; // then return it
|
|
}
|
|
}
|
|
|
|
qboolean Wisible (vec3_t v1, vec3_t v2, edict_t *ent, edict_t *enemy)
|
|
{
|
|
trace_t trace;
|
|
|
|
trace = SV_Move (v1, vec3_origin, vec3_origin, v2, true, ent);
|
|
|
|
if (trace.fraction == 1) // If the trace found its way to the enemy
|
|
return true; // Then the bot can see him
|
|
|
|
return false; // Otherwise he cant
|
|
}
|
|
|
|
void CalcAngles (vec3_t oldvector, vec3_t newvector)
|
|
{
|
|
float forward;
|
|
float yaw, pitch;
|
|
|
|
if (oldvector[1] == 0 && oldvector[0] == 0)
|
|
{
|
|
yaw = 0;
|
|
if (oldvector[2] > 0)
|
|
pitch = 90;
|
|
else
|
|
pitch = 270;
|
|
}
|
|
else
|
|
{
|
|
yaw = (int) (atan2(oldvector[1], oldvector[0]) * 180 / M_PI);
|
|
if (yaw < 0)
|
|
yaw += 360;
|
|
|
|
forward = sqrt (oldvector[0]*oldvector[0] + oldvector[1]*oldvector[1]);
|
|
pitch = (int) (atan2(oldvector[2], forward) * 180 / M_PI);
|
|
if (pitch < 0)
|
|
pitch += 360;
|
|
}
|
|
|
|
newvector[0] = pitch;
|
|
newvector[1] = yaw;
|
|
newvector[2] = 0;
|
|
}
|
|
|
|
|
|
void ai_move (edict_t *self, float dist)
|
|
{
|
|
SV_StepDirection (self, self->v.ideal_yaw, dist);
|
|
}
|
|
|
|
void ai_search (edict_t *self)
|
|
{
|
|
int oldself;
|
|
|
|
oldself = pr_global_struct->self;
|
|
pr_global_struct->self = EDICT_TO_PROG(self);
|
|
|
|
SV_MoveToGoal();
|
|
pr_global_struct->self = oldself;
|
|
}
|
|
|
|
int range (edict_t *self, edict_t *other)
|
|
{
|
|
vec3_t v;
|
|
float len;
|
|
|
|
VectorSubtract (self->v.origin, other->v.origin, v);
|
|
len = VectorLength (v);
|
|
if (len < MELEE_DISTANCE)
|
|
return RANGE_MELEE;
|
|
if (len < 500)
|
|
return RANGE_NEAR;
|
|
if (len < 1000)
|
|
return RANGE_MID;
|
|
return RANGE_FAR;
|
|
}
|
|
|
|
qboolean visible (edict_t *self, edict_t *other)
|
|
{
|
|
vec3_t spot1;
|
|
vec3_t spot2;
|
|
trace_t trace;
|
|
|
|
VectorCopy (self->v.origin, spot1);
|
|
spot1[2] += self->v.view_ofs[2];
|
|
VectorCopy (other->v.origin, spot2);
|
|
spot2[2] += self->v.view_ofs[2];
|
|
|
|
trace = SV_Move (spot1, vec3_origin, vec3_origin, spot2, true, self);
|
|
|
|
if (trace.fraction == 1.0)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
|
|
qboolean infront (edict_t *self, edict_t *other)
|
|
{
|
|
vec3_t vec;
|
|
float dot;
|
|
vec3_t forward;
|
|
|
|
AngleVectors (self->v.angles, forward, NULL, NULL);
|
|
VectorSubtract (other->v.origin, self->v.origin, vec);
|
|
VectorNormalize (vec);
|
|
dot = DotProduct (vec, forward);
|
|
|
|
if (dot > 0.3)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
entvars_t * V(int entity)
|
|
{
|
|
return &((EDICT_NUM(entity))->v);
|
|
}
|
|
|
|
int FindFieldOffset(char *field);
|
|
|
|
float GetFunctionValue(char *name, edict_t * ed)
|
|
{
|
|
static char oldname[200];
|
|
static int oldoffset;
|
|
eval_t *eval;
|
|
int offset;
|
|
|
|
if (!strcmp(name, oldname))
|
|
{
|
|
eval = GETEDICTFIELDVALUE(ed, oldoffset);
|
|
return eval->function;
|
|
}
|
|
|
|
offset = FindFieldOffset(name);
|
|
if(!offset)
|
|
return 0;
|
|
|
|
oldoffset = offset;
|
|
strcpy(oldname, name);
|
|
|
|
eval = GETEDICTFIELDVALUE(ed, offset);
|
|
|
|
return eval->function;
|
|
}
|
|
|
|
vec3_t * GetVectorValue(char *name, edict_t * ed)
|
|
{
|
|
static char oldname[200];
|
|
static int oldoffset;
|
|
eval_t *eval;
|
|
int offset;
|
|
|
|
if (!strcmp(name, oldname))
|
|
{
|
|
eval = GETEDICTFIELDVALUE(ed, oldoffset);
|
|
return &(eval->vector);
|
|
}
|
|
|
|
offset = FindFieldOffset(name);
|
|
if(!offset)
|
|
return 0;
|
|
|
|
oldoffset = offset;
|
|
strcpy(oldname, name);
|
|
|
|
eval = GETEDICTFIELDVALUE(ed, offset);
|
|
|
|
return &(eval->vector);
|
|
}
|
|
|
|
void HuntTarget (edict_t *self)
|
|
{
|
|
vec3_t vec;
|
|
|
|
self->v.goalentity = self->v.enemy;
|
|
|
|
/*
|
|
if (self->monsterinfo.aiflags & AI_STAND_GROUND)
|
|
self->monsterinfo.stand (self);
|
|
else
|
|
self->monsterinfo.run (self);*/
|
|
|
|
self->v.think = GetFunctionValue("th_run",self);
|
|
|
|
VectorSubtract (V(self->v.enemy)->origin, self->v.origin, vec);
|
|
self->v.ideal_yaw = vectoyaw(vec);
|
|
// wait a while before first attack
|
|
//if (!(self->monsterinfo.aiflags & AI_STAND_GROUND))
|
|
// AttackFinished (self, 1);
|
|
}
|
|
|
|
int IsClient(int self)
|
|
{
|
|
edict_t * ed;
|
|
|
|
if (!self || self>sv.max_edicts)
|
|
return false;
|
|
|
|
ed = EDICT_NUM(self);
|
|
|
|
return ((int)(ed->v.flags) & FL_CLIENT);
|
|
}
|
|
|
|
/*
|
|
void FoundTarget (edict_t *self)
|
|
{
|
|
// let other monsters see this monster for a while
|
|
if (IsClient(self->v.enemy))
|
|
{
|
|
pr_global_struct->
|
|
SetGlobal("sight_entity",EDICT_NUM(self));
|
|
level.sight_entity = self;
|
|
level.sight_entity_framenum = level.framenum;
|
|
level.sight_entity->light_level = 128;
|
|
}
|
|
|
|
self->show_hostile = level.time + 1; // wake up other monsters
|
|
|
|
//VectorCopy(V(self->enemy)->v.origin, self->monsterinfo.last_sighting);
|
|
//self->monsterinfo.trail_time = level.time;
|
|
|
|
if (!self->combattarget)
|
|
{
|
|
HuntTarget (self);
|
|
return;
|
|
}
|
|
|
|
self->goalentity = self->movetarget = G_PickTarget(self->combattarget);
|
|
if (!self->movetarget)
|
|
{
|
|
self->goalentity = self->movetarget = self->enemy;
|
|
HuntTarget (self);
|
|
gi.dprintf("%s at %s, combattarget %s not found\n", self->classname, vtos(self->s.origin), self->combattarget);
|
|
return;
|
|
}
|
|
|
|
// clear out our combattarget, these are a one shot deal
|
|
self->combattarget = NULL;
|
|
self->monsterinfo.aiflags |= AI_COMBAT_POINT;
|
|
|
|
// clear the targetname, that point is ours!
|
|
self->movetarget->targetname = NULL;
|
|
self->monsterinfo.pausetime = 0;
|
|
|
|
// run for it
|
|
self->monsterinfo.run (self);
|
|
}
|
|
*/
|
|
|
|
void AddNextThink(edict_t *self, float time)
|
|
{
|
|
self->v.nextthink = pr_global_struct->time + time;
|
|
}
|
|
|
|
|
|
#define DELEGATE -120
|
|
#define SUBREMOVE 13 //work?
|
|
|
|
void NexthinkRemove(edict_t *self, float time)
|
|
{
|
|
self->v.nextthink = pr_global_struct->time + time;
|
|
|
|
self->v.think = DELEGATE;
|
|
self->v.weapon = SUBREMOVE;
|
|
}
|
|
|
|
/*
|
|
void SV_Physics_Conveyor(edict_t *ent)
|
|
{
|
|
edict_t *player;
|
|
int i;
|
|
trace_t tr;
|
|
vec3_t v, move;
|
|
vec3_t point, end;
|
|
|
|
VectorScale(ent->v.movedir,10,v);
|
|
VectorScale(v,0.1,move);
|
|
for(i=0; i<sv.maxclients; i++)
|
|
{
|
|
player = sv_edict + 1 + i;
|
|
if(!player->inuse)
|
|
continue;
|
|
if(!player->groundentity)
|
|
continue;
|
|
if(player->groundentity != ent)
|
|
continue;
|
|
// Look below player; make sure he's on a conveyor
|
|
VectorCopy(player->s.origin,point);
|
|
point[2] += 1;
|
|
VectorCopy(point,end);
|
|
end[2] -= 256;
|
|
tr = trace (point, player->mins, player->maxs, end, player, MASK_SOLID);
|
|
// tr.ent HAS to be conveyor, but just in case we screwed something up:
|
|
if(tr.ent == ent)
|
|
{
|
|
if(tr.plane.normal[2] > 0) {
|
|
v[2] = ent->speed * sqrt(1.0 - tr.plane.normal[2]*tr.plane.normal[2]) /
|
|
tr.plane.normal[2];
|
|
if(DotProduct(ent->movedir,tr.plane.normal) > 0) {
|
|
// then we're moving down
|
|
v[2] = -v[2];
|
|
}
|
|
move[2] = v[2]*FRAMETIME;
|
|
}
|
|
VectorAdd(player->s.origin,move,end);
|
|
tr = gi.trace(player->s.origin,player->mins,player->maxs,end,player,player->clipmask);
|
|
VectorCopy(tr.endpos,player->s.origin);
|
|
gi.linkentity(player);
|
|
}
|
|
}
|
|
}*/
|