mirror of
https://github.com/blendogames/thirtyflightsofloving.git
synced 2024-11-15 00:41:21 +00:00
243 lines
4.9 KiB
C
243 lines
4.9 KiB
C
|
|
||
|
#include "g_local.h"
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
float Lerp(float value1, float value2, float amount)
|
||
|
{
|
||
|
float delta = value2 - value1;
|
||
|
return value1 + amount * delta;
|
||
|
}
|
||
|
|
||
|
int civwalk_SetPathData(edict_t *self)
|
||
|
{
|
||
|
vec3_t v;
|
||
|
vec3_t facingVec;
|
||
|
|
||
|
VectorSubtract (self->s.origin, self->target_ent->s.origin, v);
|
||
|
self->moveinfo.distance = VectorLength(v);
|
||
|
|
||
|
//this is the 0-1 transition.
|
||
|
self->moveinfo.remaining_distance = 0;
|
||
|
|
||
|
//this is the step to increase each frame.
|
||
|
self->moveinfo.accel = self->speed / self->moveinfo.distance;
|
||
|
|
||
|
VectorCopy(self->s.origin, self->pos1 );
|
||
|
VectorCopy(self->target_ent->s.origin, self->pos2 );
|
||
|
|
||
|
//random path offset.
|
||
|
self->pos2[0] += -48 + random() * 96;
|
||
|
self->pos2[1] += -48 + random() * 96;
|
||
|
|
||
|
//turn to face the next path.
|
||
|
|
||
|
VectorSubtract (self->pos2, self->pos1, facingVec);
|
||
|
vectoangles(facingVec,facingVec);
|
||
|
self->s.angles[YAW] = facingVec[YAW];
|
||
|
|
||
|
if (self->target_ent->spawnflags & 1)
|
||
|
{
|
||
|
self->s.event = EV_OTHER_TELEPORT; //so the ent teleports over w/o interpolation.
|
||
|
|
||
|
self->moveinfo.remaining_distance = 1;
|
||
|
VectorCopy(self->pos2, self->s.origin);
|
||
|
VectorCopy(self->pos2, self->s.old_origin);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
void civwalk_think(edict_t *self)
|
||
|
{
|
||
|
vec3_t finalPos;
|
||
|
|
||
|
self->think = civwalk_think;
|
||
|
self->nextthink = level.time + FRAMETIME;
|
||
|
|
||
|
self->moveinfo.remaining_distance += self->moveinfo.accel;
|
||
|
if (self->moveinfo.remaining_distance >= 1)
|
||
|
{
|
||
|
if (!self->target_ent->target)
|
||
|
return;
|
||
|
|
||
|
//reached the path end. continue to next pathcorner.
|
||
|
self->target_ent = G_Find(NULL, FOFS(targetname), self->target_ent->target);
|
||
|
|
||
|
//no next target? then abort.
|
||
|
if (self->target_ent == NULL)
|
||
|
return;
|
||
|
|
||
|
if (civwalk_SetPathData(self) <= 0)
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//animation.
|
||
|
self->s.frame++;
|
||
|
if (self->s.frame >= self->startframe + self->framenumbers)
|
||
|
self->s.frame = self->startframe;
|
||
|
|
||
|
finalPos[0] = Lerp(self->pos1[0], self->pos2[0], self->moveinfo.remaining_distance);
|
||
|
finalPos[1] = Lerp(self->pos1[1], self->pos2[1], self->moveinfo.remaining_distance);
|
||
|
finalPos[2] = Lerp(self->pos1[2], self->pos2[2], self->moveinfo.remaining_distance);
|
||
|
|
||
|
VectorCopy(finalPos, self->s.origin);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
void SP_civwalker(edict_t *ent)
|
||
|
{
|
||
|
ent->s.modelindex = gi.modelindex ("models/monsters/npc/tris.md2");
|
||
|
|
||
|
ent->solid = SOLID_NOT;
|
||
|
ent->takedamage = DAMAGE_NO;
|
||
|
ent->movetype = MOVETYPE_NOCLIP;
|
||
|
|
||
|
ent->s.renderfx |= RF_MINLIGHT;
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//TODO: select random skin.
|
||
|
ent->s.skinnum = 13 + random() * 5;
|
||
|
|
||
|
|
||
|
//BC baboo
|
||
|
if (skill->value >= 2 )
|
||
|
{
|
||
|
ent->s.skinnum = 7;
|
||
|
}
|
||
|
|
||
|
//find target path.
|
||
|
ent->target_ent = G_Find(NULL, FOFS(targetname), ent->target);
|
||
|
civwalk_SetPathData(ent);
|
||
|
|
||
|
|
||
|
|
||
|
ent->think = civwalk_think;
|
||
|
ent->nextthink = level.time + FRAMETIME;
|
||
|
gi.linkentity (ent);
|
||
|
}
|
||
|
|
||
|
void civspawner_spawnOne(edict_t *ent)
|
||
|
{
|
||
|
edict_t *person;
|
||
|
vec3_t spawnpos;
|
||
|
vec3_t dest;
|
||
|
trace_t tr;
|
||
|
int width, height, length;
|
||
|
|
||
|
width = abs(ent->maxs[0] - ent->mins[0]);
|
||
|
length = abs(ent->maxs[1] - ent->mins[1]);
|
||
|
height = abs(ent->maxs[2] - ent->mins[2]);
|
||
|
|
||
|
|
||
|
//drop to ground.
|
||
|
spawnpos[0] = ent->mins[0] + random() * width;
|
||
|
spawnpos[1] = ent->mins[1] + random() * length;
|
||
|
spawnpos[2] = ent->maxs[2];
|
||
|
|
||
|
VectorSet( dest, spawnpos[0], spawnpos[1], spawnpos[2] - 4096 );
|
||
|
tr = gi.trace (
|
||
|
spawnpos,
|
||
|
vec3_origin,
|
||
|
vec3_origin,
|
||
|
dest, //dest
|
||
|
ent, //ignore
|
||
|
MASK_SOLID);//MASK_SOLID
|
||
|
|
||
|
//if in solid, then abort.
|
||
|
if ( tr.startsolid )
|
||
|
return;
|
||
|
|
||
|
person = G_Spawn();
|
||
|
|
||
|
//position.
|
||
|
spawnpos[2] = tr.endpos[2];
|
||
|
VectorCopy (spawnpos, person->s.origin);
|
||
|
VectorCopy (spawnpos, person->s.old_origin);
|
||
|
|
||
|
//target path.
|
||
|
person->target = ent->target;
|
||
|
|
||
|
//person animation.
|
||
|
person->startframe = ent->startframe;
|
||
|
person->framenumbers = ent->framenumbers;
|
||
|
person->s.frame = person->startframe + random() * person->framenumbers;
|
||
|
|
||
|
//random speed.
|
||
|
person->speed = ent->speed + random() * ent->random;
|
||
|
|
||
|
SP_civwalker( person );
|
||
|
}
|
||
|
|
||
|
void civspawner_DoSpawn(edict_t *ent)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
for ( i = 0 ; i < ent->count ; i++ )
|
||
|
{
|
||
|
civspawner_spawnOne(ent);
|
||
|
}
|
||
|
|
||
|
//remove this ent from world.
|
||
|
ent->think = G_FreeEdict;
|
||
|
ent->nextthink = level.time + FRAMETIME;
|
||
|
|
||
|
}
|
||
|
|
||
|
void use_civspawner(edict_t *self)
|
||
|
{
|
||
|
self->think = civspawner_DoSpawn;
|
||
|
self->nextthink = level.time + FRAMETIME;
|
||
|
}
|
||
|
|
||
|
void SP_func_civspawner(edict_t *self)
|
||
|
{
|
||
|
edict_t *pathent;
|
||
|
|
||
|
if (!self->target)
|
||
|
{
|
||
|
gi.dprintf ("func_civspawner without a target at %s\n", vtos(self->absmin));
|
||
|
G_FreeEdict (self);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
pathent = G_Find(NULL, FOFS(targetname), self->target);
|
||
|
if (pathent == NULL)
|
||
|
{
|
||
|
gi.dprintf ("func_civspawner can't find target %s\n", self->target);
|
||
|
G_FreeEdict (self);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (!self->speed)
|
||
|
self->speed = 5;
|
||
|
|
||
|
if (!self->count)
|
||
|
self->count = 20;
|
||
|
|
||
|
if (!self->startframe)
|
||
|
self->startframe = 59;
|
||
|
|
||
|
if (!self->framenumbers)
|
||
|
self->framenumbers = 10;
|
||
|
|
||
|
if (!self->random)
|
||
|
self->random = 15;
|
||
|
|
||
|
self->use = use_civspawner;
|
||
|
|
||
|
self->svflags = SVF_NOCLIENT;
|
||
|
self->solid = SOLID_NOT;
|
||
|
gi.setmodel (self, self->model);
|
||
|
|
||
|
if (!(self->spawnflags & 1))
|
||
|
{
|
||
|
self->think = civspawner_DoSpawn;
|
||
|
self->nextthink = level.time + 1;
|
||
|
}
|
||
|
}
|