+#include <string.h>
#include "cgame_api.h"
#include "cg_math.h"
-
-#ifndef NULL
-#define NULL ((void *)0)
-#endif
-
static double gametime, frametime;
struct localentity_s;
typedef struct localentity_s
{
- int active; // true if the entity is alive (not freed)
- float freetime; // time this entity was freed
float dietime;
vec3_t velocity;
vec3_t avelocity;
vec3_t worldmaxs;
vec3_t entitymins;
vec3_t entitymaxs;
+ vec3_t lastimpactorigin; // updated by physics code, used by gib blood stains
float bouncescale;
float airfrictionscale;
float gravityscale;
void (*framethink)(struct localentity_s *e);
- //int solid;
- //void (*touch)(struct localentity_s *self, struct localentity_s *other);
- //void (*touchnetwork)(struct *localentity_s *self);
+ void (*touchnetwork)(struct localentity_s *self);
cgdrawentity_t draw;
}
localentity_t;
#define MAX_LOCALENTITIES 1024
static localentity_t *localentity;
+// true if the entity is alive (not freed)
+static unsigned char *localentityactive;
+// time the entity was freed
+static float *localentityfreetime;
static cgphysentity_t *phys_entity;
static int phys_entities;
static localentity_t *entspawn(void)
{
- int i;
- localentity_t *l;
+ int i, best;
+ float bestfreetime;
+ bestfreetime = (float) (gametime + 100.0);
+ best = -1;
for (i = 0;i < MAX_LOCALENTITIES;i++)
{
- l = localentity + i;
- if (!l->active && l->freetime < gametime)
+ if (!localentityactive[i] && bestfreetime > localentityfreetime[i])
{
- memset(l, 0, sizeof(*l));
- l->active = true;
- return l;
+ bestfreetime = localentityfreetime[i];
+ best = i;
+ if (bestfreetime < gametime)
+ break;
}
}
- for (i = 0;i < MAX_LOCALENTITIES;i++)
+ if (best >= 0)
{
- l = localentity + i;
- if (!l->active)
- {
- memset(l, 0, sizeof(*l));
- l->active = true;
- return l;
- }
+ memset(localentity + best, 0, sizeof(*localentity));
+ localentityactive[best] = true;
+ return localentity + best;
}
return NULL;
}
static void entremove(localentity_t *e)
{
- memset(e, 0, sizeof(*e));
- e->freetime = gametime + 1;
+ int i;
+ i = (e - localentity) / sizeof(localentity_t);
+ if (i < 0 || i >= MAX_LOCALENTITIES)
+ return; // this should be an error
+ //memset(e, 0, sizeof(*e));
+ localentityactive[i] = false;
+ localentityfreetime[i] = (float)gametime + 1.0f;
}
static void phys_setupphysentities(void)
/*
for (i = 0;i < MAX_LOCALENTITIES;i++)
{
- l = localentities + i;
- if (l->active && l->solid)
+ if (localentityactive[i] && localentities[i].solid)
{
+ l = localentities + i;
}
}
*/
localentity_t *l;
for (i = 0;i < MAX_LOCALENTITIES;i++)
{
- l = localentity + i;
- if (l->active)
+ if (localentityactive[i])
{
+ l = localentity + i;
if (l->framethink)
+ {
l->framethink(l);
- if (l->active && l->draw.model)
+ if (!localentityactive[i])
+ continue;
+ }
+ if (l->draw.model)
CGVM_Draw_Entity(&l->draw);
}
}
vec3_t impactpos, impactnormal, end;
int impactentnum;
float t, f, frac, bounce;
- t = frametime;
+ t = (float)frametime;
if (t == 0)
return;
VectorMA(e->draw.angles, t, e->avelocity, e->draw.angles);
{
bounce = DotProduct(e->velocity, impactnormal) * -e->bouncescale;
VectorMA(e->velocity, bounce, impactnormal, e->velocity);
- // FIXME: do some kind of touch code here if physentities get implemented
-
if (impactnormal[2] >= 0.7 && DotProduct(e->velocity, e->velocity) < 100*100)
{
VectorClear(e->velocity);
VectorClear(e->avelocity);
}
+
+ if (e->touchnetwork)
+ e->touchnetwork(e);
+ // FIXME: do some kind of touch code here if physentities get implemented
+
+ VectorCopy(impactpos, e->lastimpactorigin);
}
if (e->airfrictionscale)
{
if (gametime > self->dietime)
{
- self->draw.scale -= frametime * 3;
+ self->draw.scale -= (float)(frametime * 3.0);
if (self->draw.scale < 0.05f)
{
entremove(self);
phys_update(self);
}
+static void gib_framethink(localentity_t *self)
+{
+ if (gametime > self->dietime)
+ {
+ self->draw.scale -= (float)frametime * 3.0f;
+ if (self->draw.scale < 0.05f)
+ {
+ entremove(self);
+ return;
+ }
+ }
+ /*
+ if (gametime > self->trailnexttime)
+ {
+ self->trailnexttime = gametime + 0.1f;
+ CGVM_BloodParticle(self->draw.origin, self->velocity);
+ }
+ */
+ phys_update(self);
+}
+
+static void gib_touchnetwork(localentity_t *self)
+{
+ if (VectorDistance2(self->draw.origin, self->lastimpactorigin) >= 5*5)
+ CGVM_Stain(self->draw.origin, 64, 64, 24, 24, 48, 192, 48, 48, 48);
+}
+
static void net_explosion(unsigned char num)
{
int i;
e->draw.angles[2] = CGVM_RandomRange(0, 360);
VectorRandom(e->velocity);
VectorScale(e->velocity, 300, e->velocity);
- e->velocity[2] -= cg_gravity * 0.1;
+ e->velocity[2] -= (float)cg_gravity * 0.1f;
e->avelocity[0] = CGVM_RandomRange(0, 1440);
e->avelocity[1] = CGVM_RandomRange(0, 1440);
e->avelocity[2] = CGVM_RandomRange(0, 1440);
VectorSet(e->worldmaxs, 0, 0, -8);
VectorSet(e->entitymins, -8, -8, -8);
VectorSet(e->entitymaxs, 8, 8, 8);
- e->bouncescale = 1.4;
+ e->bouncescale = 1.4f;
e->gravityscale = 1;
e->airfrictionscale = 1;
e->framethink = explosiondebris_framethink;
- e->dietime = time + 5;
+ e->dietime = (float)time + 5.0f;
+ }
+}
+
+static void net_gibshower(unsigned char num)
+{
+ int i, count;
+ float r, velocityscale;
+ vec3_t org;
+ double time;
+ localentity_t *e;
+ // need the time to know when the gibs should fade
+ time = CGVM_Time();
+ // read the network data
+ count = CGVM_MSG_ReadByte();
+ velocityscale = (float)(CGVM_MSG_ReadByte() * 100);
+ readvector(org);
+
+ for (i = 0;i < count;i++)
+ {
+ e = entspawn();
+ if (!e)
+ return;
+
+ VectorCopy(org, e->draw.origin);
+ e->draw.angles[0] = CGVM_RandomRange(0, 360);
+ e->draw.angles[1] = CGVM_RandomRange(0, 360);
+ e->draw.angles[2] = CGVM_RandomRange(0, 360);
+ VectorRandom(e->velocity);
+ VectorScale(e->velocity, velocityscale, e->velocity);
+ e->velocity[2] -= (float)(cg_gravity * 0.1);
+ e->avelocity[0] = CGVM_RandomRange(0, 1440);
+ e->avelocity[1] = CGVM_RandomRange(0, 1440);
+ e->avelocity[2] = CGVM_RandomRange(0, 1440);
+ r = CGVM_RandomRange(0, 3);
+ if (r < 1)
+ e->draw.model = CGVM_Model("progs/gib1.mdl");
+ else if (r < 2)
+ e->draw.model = CGVM_Model("progs/gib2.mdl");
+ else
+ e->draw.model = CGVM_Model("progs/gib3.mdl");
+ e->draw.alpha = 1;
+ e->draw.scale = 1;
+ e->draw.frame1 = 0;
+ e->draw.frame2 = 0;
+ e->draw.framelerp = 0;
+ e->draw.skinnum = 0;
+ VectorSet(e->worldmins, 0, 0, -8);
+ VectorSet(e->worldmaxs, 0, 0, -8);
+ VectorSet(e->entitymins, -8, -8, -8);
+ VectorSet(e->entitymaxs, 8, 8, 8);
+ e->bouncescale = 1.5;
+ e->gravityscale = 1;
+ e->airfrictionscale = 1;
+ e->framethink = gib_framethink;
+ e->touchnetwork = gib_touchnetwork;
+ e->dietime = (float)time + CGVM_RandomRange(3.0f, 5.0f);
}
}
// called by engine
void CG_Init(void)
{
- localentity = CGVM_Malloc(sizeof(localentity_t) * MAX_LOCALENTITIES);
- phys_entity = CGVM_Malloc(sizeof(cgphysentity_t) * MAX_LOCALENTITIES);
+ localentity = CGVM_Malloc(sizeof(*localentity) * MAX_LOCALENTITIES);
+ localentityactive = CGVM_Malloc(sizeof(*localentityactive) * MAX_LOCALENTITIES);
+ localentityfreetime = CGVM_Malloc(sizeof(*localentityfreetime) * MAX_LOCALENTITIES);
+ phys_entity = CGVM_Malloc(sizeof(*phys_entity) * MAX_LOCALENTITIES);
CGVM_RegisterNetworkCode(1, net_explosion);
+ CGVM_RegisterNetworkCode(2, net_gibshower);
gametime = 0;
}