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 localentity_t *localentity;
30 // true if the entity is alive (not freed)
31 static unsigned char *localentityactive;
32 // time the entity was freed
33 static float *localentityfreetime;
35 static cgphysentity_t *phys_entity;
36 static int phys_entities;
38 static float cg_gravity;
40 static void readvector(vec3_t v)
42 v[0] = CGVM_MSG_ReadFloat();
43 v[1] = CGVM_MSG_ReadFloat();
44 v[2] = CGVM_MSG_ReadFloat();
47 static localentity_t *entspawn(void)
51 bestfreetime = (float) (gametime + 100.0);
53 for (i = 0;i < MAX_LOCALENTITIES;i++)
55 if (!localentityactive[i] && bestfreetime > localentityfreetime[i])
57 bestfreetime = localentityfreetime[i];
59 if (bestfreetime < gametime)
65 memset(localentity + best, 0, sizeof(*localentity));
66 localentityactive[best] = true;
67 return localentity + best;
72 static void entremove(localentity_t *e)
75 i = (e - localentity) / sizeof(localentity_t);
76 if (i < 0 || i >= MAX_LOCALENTITIES)
77 return; // this should be an error
78 //memset(e, 0, sizeof(*e));
79 localentityactive[i] = false;
80 localentityfreetime[i] = (float)gametime + 1.0f;
83 static void phys_setupphysentities(void)
87 for (i = 0;i < MAX_LOCALENTITIES;i++)
89 if (localentityactive[i] && localentities[i].solid)
91 l = localentities + i;
97 static void phys_moveentities(void)
101 for (i = 0;i < MAX_LOCALENTITIES;i++)
103 if (localentityactive[i])
109 if (!localentityactive[i])
113 CGVM_Draw_Entity(&l->draw);
118 static void phys_updateentities(void)
120 phys_setupphysentities();
124 static void phys_update(localentity_t *e)
126 vec3_t impactpos, impactnormal, end;
128 float t, f, frac, bounce;
129 t = (float)frametime;
132 VectorMA(e->draw.angles, t, e->avelocity, e->draw.angles);
133 VectorMA(e->draw.origin, t, e->velocity, end);
134 frac = CGVM_TracePhysics(e->draw.origin, end, e->worldmins, e->worldmaxs, e->entitymins, e->entitymaxs, phys_entity, phys_entities, impactpos, impactnormal, &impactentnum);
135 VectorCopy(impactpos, e->draw.origin);
138 bounce = DotProduct(e->velocity, impactnormal) * -e->bouncescale;
139 VectorMA(e->velocity, bounce, impactnormal, e->velocity);
140 if (impactnormal[2] >= 0.7 && DotProduct(e->velocity, e->velocity) < 100*100)
142 VectorClear(e->velocity);
143 VectorClear(e->avelocity);
148 // FIXME: do some kind of touch code here if physentities get implemented
150 VectorCopy(impactpos, e->lastimpactorigin);
153 if (e->airfrictionscale)
155 if (DotProduct(e->velocity, e->velocity) < 10*10)
157 VectorClear(e->velocity);
158 VectorClear(e->avelocity);
162 f = 1 - (t * e->airfrictionscale);
165 VectorScale(e->velocity, f, e->velocity);
166 if (DotProduct(e->avelocity, e->avelocity) < 10*10)
168 VectorClear(e->avelocity);
172 VectorScale(e->avelocity, f, e->avelocity);
177 VectorClear(e->velocity);
178 VectorClear(e->avelocity);
183 e->velocity[2] += cg_gravity * e->gravityscale * t;
186 static void explosiondebris_framethink(localentity_t *self)
188 if (gametime > self->dietime)
190 self->draw.scale -= (float)(frametime * 3.0);
191 if (self->draw.scale < 0.05f)
200 static void gib_framethink(localentity_t *self)
202 if (gametime > self->dietime)
204 self->draw.scale -= (float)frametime * 3.0f;
205 if (self->draw.scale < 0.05f)
212 if (gametime > self->trailnexttime)
214 self->trailnexttime = gametime + 0.1f;
215 CGVM_BloodParticle(self->draw.origin, self->velocity);
221 static void gib_touchnetwork(localentity_t *self)
223 if (VectorDistance2(self->draw.origin, self->lastimpactorigin) >= 5*5)
224 CGVM_Stain(self->draw.origin, 64, 64, 24, 24, 48, 192, 48, 48, 48);
227 static void net_explosion(unsigned char num)
234 // need the time to know when the rubble should fade
236 // read the network data
239 for (i = 0;i < 40;i++)
245 VectorCopy(org, e->draw.origin);
246 e->draw.angles[0] = CGVM_RandomRange(0, 360);
247 e->draw.angles[1] = CGVM_RandomRange(0, 360);
248 e->draw.angles[2] = CGVM_RandomRange(0, 360);
249 VectorRandom(e->velocity);
250 VectorScale(e->velocity, 300, e->velocity);
251 e->velocity[2] -= (float)cg_gravity * 0.1f;
252 e->avelocity[0] = CGVM_RandomRange(0, 1440);
253 e->avelocity[1] = CGVM_RandomRange(0, 1440);
254 e->avelocity[2] = CGVM_RandomRange(0, 1440);
255 r = CGVM_RandomRange(0, 3);
257 e->draw.model = CGVM_Model("progs/rubble1.mdl");
259 e->draw.model = CGVM_Model("progs/rubble2.mdl");
261 e->draw.model = CGVM_Model("progs/rubble3.mdl");
266 e->draw.framelerp = 0;
268 VectorSet(e->worldmins, 0, 0, -8);
269 VectorSet(e->worldmaxs, 0, 0, -8);
270 VectorSet(e->entitymins, -8, -8, -8);
271 VectorSet(e->entitymaxs, 8, 8, 8);
272 e->bouncescale = 1.4f;
274 e->airfrictionscale = 1;
275 e->framethink = explosiondebris_framethink;
276 e->dietime = (float)time + 5.0f;
280 static void net_gibshower(unsigned char num)
283 float r, velocityscale;
287 // need the time to know when the gibs should fade
289 // read the network data
290 count = CGVM_MSG_ReadByte();
291 velocityscale = (float)(CGVM_MSG_ReadByte() * 100);
294 for (i = 0;i < count;i++)
300 VectorCopy(org, e->draw.origin);
301 e->draw.angles[0] = CGVM_RandomRange(0, 360);
302 e->draw.angles[1] = CGVM_RandomRange(0, 360);
303 e->draw.angles[2] = CGVM_RandomRange(0, 360);
304 VectorRandom(e->velocity);
305 VectorScale(e->velocity, velocityscale, e->velocity);
306 e->velocity[2] -= (float)(cg_gravity * 0.1);
307 e->avelocity[0] = CGVM_RandomRange(0, 1440);
308 e->avelocity[1] = CGVM_RandomRange(0, 1440);
309 e->avelocity[2] = CGVM_RandomRange(0, 1440);
310 r = CGVM_RandomRange(0, 3);
312 e->draw.model = CGVM_Model("progs/gib1.mdl");
314 e->draw.model = CGVM_Model("progs/gib2.mdl");
316 e->draw.model = CGVM_Model("progs/gib3.mdl");
321 e->draw.framelerp = 0;
323 VectorSet(e->worldmins, 0, 0, -8);
324 VectorSet(e->worldmaxs, 0, 0, -8);
325 VectorSet(e->entitymins, -8, -8, -8);
326 VectorSet(e->entitymaxs, 8, 8, 8);
327 e->bouncescale = 1.5;
329 e->airfrictionscale = 1;
330 e->framethink = gib_framethink;
331 e->touchnetwork = gib_touchnetwork;
332 e->dietime = (float)time + CGVM_RandomRange(3.0f, 5.0f);
339 localentity = CGVM_Malloc(sizeof(*localentity) * MAX_LOCALENTITIES);
340 localentityactive = CGVM_Malloc(sizeof(*localentityactive) * MAX_LOCALENTITIES);
341 localentityfreetime = CGVM_Malloc(sizeof(*localentityfreetime) * MAX_LOCALENTITIES);
342 phys_entity = CGVM_Malloc(sizeof(*phys_entity) * MAX_LOCALENTITIES);
343 CGVM_RegisterNetworkCode(1, net_explosion);
344 CGVM_RegisterNetworkCode(2, net_gibshower);
349 void CG_Frame(double time)
351 cg_gravity = -CGVM_GetCvarFloat("sv_gravity");
352 frametime = time - gametime;
354 phys_updateentities();