]> icculus.org git repositories - divverent/darkplaces.git/blob - cgame.c
Forgot to apply Vic's axial patch for r_light.c, here it is.
[divverent/darkplaces.git] / cgame.c
1
2 #include <string.h>
3 #include "cgame_api.h"
4 #include "cg_math.h"
5
6
7 #ifndef NULL
8 #define NULL ((void *)0)
9 #endif
10
11 static double gametime, frametime;
12
13 struct localentity_s;
14 typedef struct localentity_s
15 {
16         int active; // true if the entity is alive (not freed)
17         float freetime; // time this entity was freed
18         float dietime;
19         vec3_t velocity;
20         vec3_t avelocity;
21         vec3_t worldmins;
22         vec3_t worldmaxs;
23         vec3_t entitymins;
24         vec3_t entitymaxs;
25         vec3_t lastimpactorigin; // updated by physics code, used by gib blood stains
26         float bouncescale;
27         float airfrictionscale;
28         float gravityscale;
29         void (*framethink)(struct localentity_s *e);
30         void (*touchnetwork)(struct localentity_s *self);
31         cgdrawentity_t draw;
32 }
33 localentity_t;
34
35 #define MAX_LOCALENTITIES 1024
36 static localentity_t *localentity;
37
38 static cgphysentity_t *phys_entity;
39 static int phys_entities;
40
41 static float cg_gravity;
42
43 static void readvector(vec3_t v)
44 {
45         v[0] = CGVM_MSG_ReadFloat();
46         v[1] = CGVM_MSG_ReadFloat();
47         v[2] = CGVM_MSG_ReadFloat();
48 }
49
50 static localentity_t *entspawn(void)
51 {
52         int i;
53         localentity_t *l;
54         for (i = 0;i < MAX_LOCALENTITIES;i++)
55         {
56                 l = localentity + i;
57                 if (!l->active && l->freetime < gametime)
58                 {
59                         memset(l, 0, sizeof(*l));
60                         l->active = true;
61                         return l;
62                 }
63         }
64         for (i = 0;i < MAX_LOCALENTITIES;i++)
65         {
66                 l = localentity + i;
67                 if (!l->active)
68                 {
69                         memset(l, 0, sizeof(*l));
70                         l->active = true;
71                         return l;
72                 }
73         }
74         return NULL;
75 }
76
77 static void entremove(localentity_t *e)
78 {
79         memset(e, 0, sizeof(*e));
80         e->freetime = (float)gametime + 1.0f;
81 }
82
83 static void phys_setupphysentities(void)
84 {
85         phys_entities = 0;
86         /*
87         for (i = 0;i < MAX_LOCALENTITIES;i++)
88         {
89                 l = localentities + i;
90                 if (l->active && l->solid)
91                 {
92                 }
93         }
94         */
95 }
96
97 static void phys_moveentities(void)
98 {
99         int i;
100         localentity_t *l;
101         for (i = 0;i < MAX_LOCALENTITIES;i++)
102         {
103                 l = localentity + i;
104                 if (l->active)
105                 {
106                         if (l->framethink)
107                                 l->framethink(l);
108                         if (l->active && l->draw.model)
109                                 CGVM_Draw_Entity(&l->draw);
110                 }
111         }
112 }
113
114 static void phys_updateentities(void)
115 {
116         phys_setupphysentities();
117         phys_moveentities();
118 }
119
120 static void phys_update(localentity_t *e)
121 {
122         vec3_t impactpos, impactnormal, end;
123         int impactentnum;
124         float t, f, frac, bounce;
125         t = (float)frametime;
126         if (t == 0)
127                 return;
128         VectorMA(e->draw.angles, t, e->avelocity, e->draw.angles);
129         VectorMA(e->draw.origin, t, e->velocity, end);
130         frac = CGVM_TracePhysics(e->draw.origin, end, e->worldmins, e->worldmaxs, e->entitymins, e->entitymaxs, phys_entity, phys_entities, impactpos, impactnormal, &impactentnum);
131         VectorCopy(impactpos, e->draw.origin);
132         if (frac < 1)
133         {
134                 bounce = DotProduct(e->velocity, impactnormal) * -e->bouncescale;
135                 VectorMA(e->velocity, bounce, impactnormal, e->velocity);
136                 if (impactnormal[2] >= 0.7 && DotProduct(e->velocity, e->velocity) < 100*100)
137                 {
138                         VectorClear(e->velocity);
139                         VectorClear(e->avelocity);
140                 }
141
142                 if (e->touchnetwork)
143                         e->touchnetwork(e);
144                 // FIXME: do some kind of touch code here if physentities get implemented
145
146                 VectorCopy(impactpos, e->lastimpactorigin);
147         }
148
149         if (e->airfrictionscale)
150         {
151                 if (DotProduct(e->velocity, e->velocity) < 10*10)
152                 {
153                         VectorClear(e->velocity);
154                         VectorClear(e->avelocity);
155                 }
156                 else
157                 {
158                         f = 1 - (t * e->airfrictionscale);
159                         if (f > 0)
160                         {
161                                 VectorScale(e->velocity, f, e->velocity);
162                                 if (DotProduct(e->avelocity, e->avelocity) < 10*10)
163                                 {
164                                         VectorClear(e->avelocity);
165                                 }
166                                 else
167                                 {
168                                         VectorScale(e->avelocity, f, e->avelocity);
169                                 }
170                         }
171                         else
172                         {
173                                 VectorClear(e->velocity);
174                                 VectorClear(e->avelocity);
175                         }
176                 }
177         }
178         if (e->gravityscale)
179                 e->velocity[2] += cg_gravity * e->gravityscale * t;
180 }
181
182 static void explosiondebris_framethink(localentity_t *self)
183 {
184         if (gametime > self->dietime)
185         {
186                 self->draw.scale -= (float)(frametime * 3.0);
187                 if (self->draw.scale < 0.05f)
188                 {
189                         entremove(self);
190                         return;
191                 }
192         }
193         phys_update(self);
194 }
195
196 static void gib_framethink(localentity_t *self)
197 {
198         if (gametime > self->dietime)
199         {
200                 self->draw.scale -= (float)frametime * 3.0f;
201                 if (self->draw.scale < 0.05f)
202                 {
203                         entremove(self);
204                         return;
205                 }
206         }
207         /*
208         if (gametime > self->trailnexttime)
209         {
210                 self->trailnexttime = gametime + 0.1f;
211                 CGVM_BloodParticle(self->draw.origin, self->velocity);
212         }
213         */
214         phys_update(self);
215 }
216
217 static void gib_touchnetwork(localentity_t *self)
218 {
219         if (VectorDistance2(self->draw.origin, self->lastimpactorigin) >= 5*5)
220                 CGVM_Stain(self->draw.origin, 64, 64, 24, 24, 48, 192, 48, 48, 48);
221 }
222
223 static void net_explosion(unsigned char num)
224 {
225         int i;
226         float r;
227         vec3_t org;
228         double time;
229         localentity_t *e;
230         // need the time to know when the rubble should fade
231         time = CGVM_Time();
232         // read the network data
233         readvector(org);
234
235         for (i = 0;i < 40;i++)
236         {
237                 e = entspawn();
238                 if (!e)
239                         return;
240
241                 VectorCopy(org, e->draw.origin);
242                 e->draw.angles[0] = CGVM_RandomRange(0, 360);
243                 e->draw.angles[1] = CGVM_RandomRange(0, 360);
244                 e->draw.angles[2] = CGVM_RandomRange(0, 360);
245                 VectorRandom(e->velocity);
246                 VectorScale(e->velocity, 300, e->velocity);
247                 e->velocity[2] -= (float)cg_gravity * 0.1f;
248                 e->avelocity[0] = CGVM_RandomRange(0, 1440);
249                 e->avelocity[1] = CGVM_RandomRange(0, 1440);
250                 e->avelocity[2] = CGVM_RandomRange(0, 1440);
251                 r = CGVM_RandomRange(0, 3);
252                 if (r < 1)
253                         e->draw.model = CGVM_Model("progs/rubble1.mdl");
254                 else if (r < 2)
255                         e->draw.model = CGVM_Model("progs/rubble2.mdl");
256                 else
257                         e->draw.model = CGVM_Model("progs/rubble3.mdl");
258                 e->draw.alpha = 1;
259                 e->draw.scale = 1;
260                 e->draw.frame1 = 0;
261                 e->draw.frame2 = 0;
262                 e->draw.framelerp = 0;
263                 e->draw.skinnum = 5;
264                 VectorSet(e->worldmins, 0, 0, -8);
265                 VectorSet(e->worldmaxs, 0, 0, -8);
266                 VectorSet(e->entitymins, -8, -8, -8);
267                 VectorSet(e->entitymaxs, 8, 8, 8);
268                 e->bouncescale = 1.4f;
269                 e->gravityscale = 1;
270                 e->airfrictionscale = 1;
271                 e->framethink = explosiondebris_framethink;
272                 e->dietime = (float)time + 5.0f;
273         }
274 }
275
276 static void net_gibshower(unsigned char num)
277 {
278         int i, count;
279         float r, velocityscale;
280         vec3_t org;
281         double time;
282         localentity_t *e;
283         // need the time to know when the gibs should fade
284         time = CGVM_Time();
285         // read the network data
286         count = CGVM_MSG_ReadByte();
287         velocityscale = (float)(CGVM_MSG_ReadByte() * 100);
288         readvector(org);
289
290         for (i = 0;i < count;i++)
291         {
292                 e = entspawn();
293                 if (!e)
294                         return;
295
296                 VectorCopy(org, e->draw.origin);
297                 e->draw.angles[0] = CGVM_RandomRange(0, 360);
298                 e->draw.angles[1] = CGVM_RandomRange(0, 360);
299                 e->draw.angles[2] = CGVM_RandomRange(0, 360);
300                 VectorRandom(e->velocity);
301                 VectorScale(e->velocity, velocityscale, e->velocity);
302                 e->velocity[2] -= (float)(cg_gravity * 0.1);
303                 e->avelocity[0] = CGVM_RandomRange(0, 1440);
304                 e->avelocity[1] = CGVM_RandomRange(0, 1440);
305                 e->avelocity[2] = CGVM_RandomRange(0, 1440);
306                 r = CGVM_RandomRange(0, 3);
307                 if (r < 1)
308                         e->draw.model = CGVM_Model("progs/gib1.mdl");
309                 else if (r < 2)
310                         e->draw.model = CGVM_Model("progs/gib2.mdl");
311                 else
312                         e->draw.model = CGVM_Model("progs/gib3.mdl");
313                 e->draw.alpha = 1;
314                 e->draw.scale = 1;
315                 e->draw.frame1 = 0;
316                 e->draw.frame2 = 0;
317                 e->draw.framelerp = 0;
318                 e->draw.skinnum = 0;
319                 VectorSet(e->worldmins, 0, 0, -8);
320                 VectorSet(e->worldmaxs, 0, 0, -8);
321                 VectorSet(e->entitymins, -8, -8, -8);
322                 VectorSet(e->entitymaxs, 8, 8, 8);
323                 e->bouncescale = 1.5;
324                 e->gravityscale = 1;
325                 e->airfrictionscale = 1;
326                 e->framethink = gib_framethink;
327                 e->touchnetwork = gib_touchnetwork;
328                 e->dietime = (float)time + CGVM_RandomRange(3.0f, 5.0f);
329         }
330 }
331
332 // called by engine
333 void CG_Init(void)
334 {
335         localentity = CGVM_Malloc(sizeof(localentity_t) * MAX_LOCALENTITIES);
336         phys_entity = CGVM_Malloc(sizeof(cgphysentity_t) * MAX_LOCALENTITIES);
337         CGVM_RegisterNetworkCode(1, net_explosion);
338         CGVM_RegisterNetworkCode(2, net_gibshower);
339         gametime = 0;
340 }
341
342 // called by engine
343 void CG_Frame(double time)
344 {
345         cg_gravity = -CGVM_GetCvarFloat("sv_gravity");
346         frametime = time - gametime;
347         gametime = time;
348         phys_updateentities();
349 }
350