7 #define NULL ((void *)0)
10 static double gametime, frametime;
13 typedef struct localentity_s
15 int active; // true if the entity is alive (not freed)
16 float freetime; // time this entity was freed
24 vec3_t lastimpactorigin; // updated by physics code, used by gib blood stains
26 float airfrictionscale;
28 void (*framethink)(struct localentity_s *e);
30 //void (*touch)(struct localentity_s *self, struct localentity_s *other);
31 void (*touchnetwork)(struct localentity_s *self);
36 #define MAX_LOCALENTITIES 1024
37 static localentity_t *localentity;
39 static cgphysentity_t *phys_entity;
40 static int phys_entities;
42 static float cg_gravity;
44 static void readvector(vec3_t v)
46 v[0] = CGVM_MSG_ReadFloat();
47 v[1] = CGVM_MSG_ReadFloat();
48 v[2] = CGVM_MSG_ReadFloat();
51 static localentity_t *entspawn(void)
55 for (i = 0;i < MAX_LOCALENTITIES;i++)
58 if (!l->active && l->freetime < gametime)
60 memset(l, 0, sizeof(*l));
65 for (i = 0;i < MAX_LOCALENTITIES;i++)
70 memset(l, 0, sizeof(*l));
78 static void entremove(localentity_t *e)
80 memset(e, 0, sizeof(*e));
81 e->freetime = (float)gametime + 1.0f;
84 static void phys_setupphysentities(void)
88 for (i = 0;i < MAX_LOCALENTITIES;i++)
90 l = localentities + i;
91 if (l->active && l->solid)
98 static void phys_moveentities(void)
102 for (i = 0;i < MAX_LOCALENTITIES;i++)
109 if (l->active && l->draw.model)
110 CGVM_Draw_Entity(&l->draw);
115 static void phys_updateentities(void)
117 phys_setupphysentities();
121 static void phys_update(localentity_t *e)
123 vec3_t impactpos, impactnormal, end;
125 float t, f, frac, bounce;
126 t = (float)frametime;
129 VectorMA(e->draw.angles, t, e->avelocity, e->draw.angles);
130 VectorMA(e->draw.origin, t, e->velocity, end);
131 frac = CGVM_TracePhysics(e->draw.origin, end, e->worldmins, e->worldmaxs, e->entitymins, e->entitymaxs, phys_entity, phys_entities, impactpos, impactnormal, &impactentnum);
132 VectorCopy(impactpos, e->draw.origin);
135 bounce = DotProduct(e->velocity, impactnormal) * -e->bouncescale;
136 VectorMA(e->velocity, bounce, impactnormal, e->velocity);
137 if (impactnormal[2] >= 0.7 && DotProduct(e->velocity, e->velocity) < 100*100)
139 VectorClear(e->velocity);
140 VectorClear(e->avelocity);
145 // FIXME: do some kind of touch code here if physentities get implemented
147 VectorCopy(impactpos, e->lastimpactorigin);
150 if (e->airfrictionscale)
152 if (DotProduct(e->velocity, e->velocity) < 10*10)
154 VectorClear(e->velocity);
155 VectorClear(e->avelocity);
159 f = 1 - (t * e->airfrictionscale);
162 VectorScale(e->velocity, f, e->velocity);
163 if (DotProduct(e->avelocity, e->avelocity) < 10*10)
165 VectorClear(e->avelocity);
169 VectorScale(e->avelocity, f, e->avelocity);
174 VectorClear(e->velocity);
175 VectorClear(e->avelocity);
180 e->velocity[2] += cg_gravity * e->gravityscale * t;
183 static void explosiondebris_framethink(localentity_t *self)
185 if (gametime > self->dietime)
187 self->draw.scale -= frametime * 3;
188 if (self->draw.scale < 0.05f)
197 static void gib_framethink(localentity_t *self)
199 if (gametime > self->dietime)
201 self->draw.scale -= (float)frametime * 3.0f;
202 if (self->draw.scale < 0.05f)
209 if (gametime > self->trailnexttime)
211 self->trailnexttime = gametime + 0.1f;
212 CGVM_BloodParticle(self->draw.origin, self->velocity);
218 static void gib_touchnetwork(localentity_t *self)
220 if (VectorDistance2(self->draw.origin, self->lastimpactorigin) >= 5*5)
221 CGVM_Stain(self->draw.origin, 64, 64, 24, 24, 48, 192, 48, 48, 48);
224 static void net_explosion(unsigned char num)
231 // need the time to know when the rubble should fade
233 // read the network data
236 for (i = 0;i < 40;i++)
242 VectorCopy(org, e->draw.origin);
243 e->draw.angles[0] = CGVM_RandomRange(0, 360);
244 e->draw.angles[1] = CGVM_RandomRange(0, 360);
245 e->draw.angles[2] = CGVM_RandomRange(0, 360);
246 VectorRandom(e->velocity);
247 VectorScale(e->velocity, 300, e->velocity);
248 e->velocity[2] -= (float)cg_gravity * 0.1f;
249 e->avelocity[0] = CGVM_RandomRange(0, 1440);
250 e->avelocity[1] = CGVM_RandomRange(0, 1440);
251 e->avelocity[2] = CGVM_RandomRange(0, 1440);
252 r = CGVM_RandomRange(0, 3);
254 e->draw.model = CGVM_Model("progs/rubble1.mdl");
256 e->draw.model = CGVM_Model("progs/rubble2.mdl");
258 e->draw.model = CGVM_Model("progs/rubble3.mdl");
263 e->draw.framelerp = 0;
265 VectorSet(e->worldmins, 0, 0, -8);
266 VectorSet(e->worldmaxs, 0, 0, -8);
267 VectorSet(e->entitymins, -8, -8, -8);
268 VectorSet(e->entitymaxs, 8, 8, 8);
269 e->bouncescale = 1.4f;
271 e->airfrictionscale = 1;
272 e->framethink = explosiondebris_framethink;
273 e->dietime = (float)time + 5.0f;
277 static void net_gibshower(unsigned char num)
280 float r, velocityscale;
284 // need the time to know when the gibs should fade
286 // read the network data
287 count = CGVM_MSG_ReadByte();
288 velocityscale = CGVM_MSG_ReadByte() * 100;
291 for (i = 0;i < count;i++)
297 VectorCopy(org, e->draw.origin);
298 e->draw.angles[0] = CGVM_RandomRange(0, 360);
299 e->draw.angles[1] = CGVM_RandomRange(0, 360);
300 e->draw.angles[2] = CGVM_RandomRange(0, 360);
301 VectorRandom(e->velocity);
302 VectorScale(e->velocity, velocityscale, e->velocity);
303 e->velocity[2] -= cg_gravity * 0.1;
304 e->avelocity[0] = CGVM_RandomRange(0, 1440);
305 e->avelocity[1] = CGVM_RandomRange(0, 1440);
306 e->avelocity[2] = CGVM_RandomRange(0, 1440);
307 r = CGVM_RandomRange(0, 3);
309 e->draw.model = CGVM_Model("progs/gib1.mdl");
311 e->draw.model = CGVM_Model("progs/gib2.mdl");
313 e->draw.model = CGVM_Model("progs/gib3.mdl");
318 e->draw.framelerp = 0;
320 VectorSet(e->worldmins, 0, 0, -8);
321 VectorSet(e->worldmaxs, 0, 0, -8);
322 VectorSet(e->entitymins, -8, -8, -8);
323 VectorSet(e->entitymaxs, 8, 8, 8);
324 e->bouncescale = 1.5;
326 e->airfrictionscale = 1;
327 e->framethink = gib_framethink;
328 e->touchnetwork = gib_touchnetwork;
329 e->dietime = (float)time + CGVM_RandomRange(3.0f, 5.0f);
336 localentity = CGVM_Malloc(sizeof(localentity_t) * MAX_LOCALENTITIES);
337 phys_entity = CGVM_Malloc(sizeof(cgphysentity_t) * MAX_LOCALENTITIES);
338 CGVM_RegisterNetworkCode(1, net_explosion);
339 CGVM_RegisterNetworkCode(2, net_gibshower);
344 void CG_Frame(double time)
346 cg_gravity = -CGVM_GetCvarFloat("sv_gravity");
347 frametime = time - gametime;
349 phys_updateentities();