6 static double gametime, frametime;
9 typedef struct localentity_s
18 vec3_t lastimpactorigin; // updated by physics code, used by gib blood stains
20 float airfrictionscale;
22 void (*framethink)(struct localentity_s *e);
23 void (*touchnetwork)(struct localentity_s *self);
28 #define MAX_LOCALENTITIES 1024
29 static int numlocalentities;
30 static localentity_t *localentity;
31 // true if the entity is alive (not freed)
32 static unsigned char *localentityactive;
33 // time the entity was freed
34 static float *localentityfreetime;
36 static cgphysentity_t *phys_entity;
37 static int phys_entities;
39 static float cg_gravity;
41 static void readvector(vec3_t v)
43 v[0] = CGVM_MSG_ReadFloat();
44 v[1] = CGVM_MSG_ReadFloat();
45 v[2] = CGVM_MSG_ReadFloat();
48 static localentity_t *entspawn(void)
52 bestfreetime = (float) (gametime + 100.0);
54 for (i = 0;i < MAX_LOCALENTITIES;i++)
56 if (!localentityactive[i] && bestfreetime > localentityfreetime[i])
58 bestfreetime = localentityfreetime[i];
60 if (bestfreetime < gametime)
66 // update numlocalentities to include the newly allocated slot
67 numlocalentities = max(numlocalentities, best + 1);
68 memset(localentity + best, 0, sizeof(*localentity));
69 localentityactive[best] = true;
70 return localentity + best;
75 static void entremove(localentity_t *e)
78 i = (int)((e - localentity) / sizeof(localentity_t));
79 if (i < 0 || i >= numlocalentities)
80 return; // this should be an error
81 //memset(e, 0, sizeof(*e));
82 localentityactive[i] = false;
83 localentityfreetime[i] = (float)gametime + 1.0f;
84 // since an entity was removed, we may be able to reduce the number of
86 while (numlocalentities > 0 && !localentityactive[numlocalentities-1])
90 static void phys_setupphysentities(void)
94 for (i = 0;i < MAX_LOCALENTITIES;i++)
96 if (localentityactive[i] && localentities[i].solid)
98 l = localentities + i;
104 static void phys_moveentities(void)
108 for (i = 0;i < numlocalentities;i++)
110 if (localentityactive[i])
116 if (!localentityactive[i])
120 CGVM_Draw_Entity(&l->draw);
125 static void phys_updateentities(void)
127 phys_setupphysentities();
131 static void phys_update(localentity_t *e)
133 vec3_t impactpos, impactnormal, end;
135 float t, f, frac, bounce;
136 t = (float)frametime;
139 VectorMA(e->draw.angles, t, e->avelocity, e->draw.angles);
140 VectorMA(e->draw.origin, t, e->velocity, end);
141 frac = CGVM_TracePhysics(e->draw.origin, end, e->worldmins, e->worldmaxs, e->entitymins, e->entitymaxs, phys_entity, phys_entities, impactpos, impactnormal, &impactentnum);
142 VectorCopy(impactpos, e->draw.origin);
145 bounce = DotProduct(e->velocity, impactnormal) * -e->bouncescale;
146 VectorMA(e->velocity, bounce, impactnormal, e->velocity);
147 if (impactnormal[2] >= 0.7 && DotProduct(e->velocity, e->velocity) < 100*100)
149 VectorClear(e->velocity);
150 VectorClear(e->avelocity);
155 // FIXME: do some kind of touch code here if physentities get implemented
157 VectorCopy(impactpos, e->lastimpactorigin);
160 if (e->airfrictionscale)
162 if (DotProduct(e->velocity, e->velocity) < 10*10)
164 VectorClear(e->velocity);
165 VectorClear(e->avelocity);
169 f = 1 - (t * e->airfrictionscale);
172 VectorScale(e->velocity, f, e->velocity);
173 if (DotProduct(e->avelocity, e->avelocity) < 10*10)
175 VectorClear(e->avelocity);
179 VectorScale(e->avelocity, f, e->avelocity);
184 VectorClear(e->velocity);
185 VectorClear(e->avelocity);
190 e->velocity[2] += cg_gravity * e->gravityscale * t;
193 static void explosiondebris_framethink(localentity_t *self)
195 if (gametime > self->dietime)
197 self->draw.scale -= (float)(frametime * 3.0);
198 if (self->draw.scale < 0.05f)
207 static void gib_framethink(localentity_t *self)
209 if (gametime > self->dietime)
211 self->draw.scale -= (float)frametime * 3.0f;
212 if (self->draw.scale < 0.05f)
219 if (gametime > self->trailnexttime)
221 self->trailnexttime = gametime + 0.1f;
222 CGVM_BloodParticle(self->draw.origin, self->velocity);
228 static void gib_touchnetwork(localentity_t *self)
230 if (VectorDistance2(self->draw.origin, self->lastimpactorigin) >= 5*5)
231 CGVM_Stain(self->draw.origin, 64, 64, 24, 24, 48, 192, 48, 48, 48);
234 static void net_explosion(unsigned char num)
241 // need the time to know when the rubble should fade
243 // read the network data
246 for (i = 0;i < 40;i++)
252 VectorCopy(org, e->draw.origin);
253 e->draw.angles[0] = CGVM_RandomRange(0, 360);
254 e->draw.angles[1] = CGVM_RandomRange(0, 360);
255 e->draw.angles[2] = CGVM_RandomRange(0, 360);
256 VectorRandom(e->velocity);
257 VectorScale(e->velocity, 300, e->velocity);
258 e->velocity[2] -= (float)cg_gravity * 0.1f;
259 e->avelocity[0] = CGVM_RandomRange(0, 1440);
260 e->avelocity[1] = CGVM_RandomRange(0, 1440);
261 e->avelocity[2] = CGVM_RandomRange(0, 1440);
262 r = CGVM_RandomRange(0, 3);
264 e->draw.model = CGVM_Model("progs/rubble1.mdl");
266 e->draw.model = CGVM_Model("progs/rubble2.mdl");
268 e->draw.model = CGVM_Model("progs/rubble3.mdl");
273 e->draw.framelerp = 0;
275 VectorSet(e->worldmins, 0, 0, -8);
276 VectorSet(e->worldmaxs, 0, 0, -8);
277 VectorSet(e->entitymins, -8, -8, -8);
278 VectorSet(e->entitymaxs, 8, 8, 8);
279 e->bouncescale = 1.4f;
281 e->airfrictionscale = 1;
282 e->framethink = explosiondebris_framethink;
283 e->dietime = (float)time + 5.0f;
287 static void net_gibshower(unsigned char num)
290 float r, velocityscale;
294 // need the time to know when the gibs should fade
296 // read the network data
297 count = CGVM_MSG_ReadByte();
298 velocityscale = (float)(CGVM_MSG_ReadByte() * 100);
301 for (i = 0;i < count;i++)
307 VectorCopy(org, e->draw.origin);
308 e->draw.angles[0] = CGVM_RandomRange(0, 360);
309 e->draw.angles[1] = CGVM_RandomRange(0, 360);
310 e->draw.angles[2] = CGVM_RandomRange(0, 360);
311 VectorRandom(e->velocity);
312 VectorScale(e->velocity, velocityscale, e->velocity);
313 e->velocity[2] -= (float)(cg_gravity * 0.1);
314 e->avelocity[0] = CGVM_RandomRange(0, 1440);
315 e->avelocity[1] = CGVM_RandomRange(0, 1440);
316 e->avelocity[2] = CGVM_RandomRange(0, 1440);
317 r = CGVM_RandomRange(0, 3);
319 e->draw.model = CGVM_Model("progs/gib1.mdl");
321 e->draw.model = CGVM_Model("progs/gib2.mdl");
323 e->draw.model = CGVM_Model("progs/gib3.mdl");
328 e->draw.framelerp = 0;
330 VectorSet(e->worldmins, 0, 0, -8);
331 VectorSet(e->worldmaxs, 0, 0, -8);
332 VectorSet(e->entitymins, -8, -8, -8);
333 VectorSet(e->entitymaxs, 8, 8, 8);
334 e->bouncescale = 1.5;
336 e->airfrictionscale = 1;
337 e->framethink = gib_framethink;
338 e->touchnetwork = gib_touchnetwork;
339 e->dietime = (float)time + CGVM_RandomRange(3.0f, 5.0f);
346 numlocalentities = 0;
347 localentity = (localentity_t *)CGVM_Malloc(sizeof(*localentity) * MAX_LOCALENTITIES);
348 localentityactive = (unsigned char *)CGVM_Malloc(sizeof(*localentityactive) * MAX_LOCALENTITIES);
349 localentityfreetime = (float *)CGVM_Malloc(sizeof(*localentityfreetime) * MAX_LOCALENTITIES);
350 phys_entity = (cgphysentity_t *)CGVM_Malloc(sizeof(*phys_entity) * MAX_LOCALENTITIES);
351 CGVM_RegisterNetworkCode(1, net_explosion);
352 CGVM_RegisterNetworkCode(2, net_gibshower);
357 void CG_Frame(double time)
359 cg_gravity = -CGVM_GetCvarFloat("sv_gravity");
360 frametime = time - gametime;
362 phys_updateentities();