]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/client/movetypes.qc
improved the shot origin adjuster:
[divverent/nexuiz.git] / data / qcsrc / client / movetypes.qc
1 .entity move_groundentity;
2 .float move_suspendedinair;
3 .float move_didgravity;
4
5 void _Movetype_CheckVelocity() // SV_CheckVelocity
6 {
7 }
8
9 float _Movetype_CheckWater() // SV_CheckWater
10 {
11         return FALSE;
12 }
13
14 void _Movetype_CheckWaterTransition() // SV_CheckWaterTransition
15 {
16 }
17
18 void _Movetype_Impact(entity oth) // SV_Impact
19 {
20         entity oldother, oldself;
21
22         oldself = self;
23         oldother = other;
24
25         if(self.move_touch)
26         {
27                 other = oth;
28
29                 self.move_touch();
30
31                 other = oldother;
32         }
33
34         if(oth.move_touch)
35         {
36                 other = self;
37                 self = oth;
38
39                 self.move_touch();
40
41                 self = oldself;
42                 other = oldother;
43         }
44 }
45
46 void _Movetype_LinkEdict_TouchAreaGrid() // SV_LinkEdict_TouchAreaGrid
47 {
48         entity e, oldself, oldother;
49
50         oldself = self;
51         oldother = other;
52
53         for(e = findradius(0.5 * (self.absmin + self.absmax), 0.5 * vlen(self.absmax - self.absmin)); e; e = e.chain)
54         {
55                 if(e.move_touch)
56                 if(boxesoverlap(e.absmin, e.absmax, oldself.absmin, oldself.absmax))
57                 {
58                         self = e;
59                         other = oldself;
60
61                         trace_allsolid = FALSE;
62                         trace_startsolid = FALSE;
63                         trace_fraction = 1;
64                         trace_inwater = FALSE;
65                         trace_inopen = TRUE;
66                         trace_endpos = e.origin;
67                         trace_plane_normal = '0 0 1';
68                         trace_plane_dist = 0;
69                         trace_ent = oldself;
70
71                         e.move_touch();
72                 }
73         }
74
75         other = oldother;
76         self = oldself;
77 }
78
79 void _Movetype_LinkEdict(float touch_triggers) // SV_LinkEdict
80 {
81         vector mi, ma;
82         if(self.solid == SOLID_BSP)
83         {
84                 // TODO set the absolute bbox
85                 mi = self.mins;
86                 ma = self.maxs;
87         }
88         else
89         {
90                 mi = self.mins;
91                 ma = self.maxs;
92         }
93         mi = mi + self.origin;
94         ma = ma + self.origin;
95
96         if(self.move_flags & FL_ITEM)
97         {
98                 mi_x -= 15;
99                 mi_y -= 15;
100                 mi_z -= 1;
101                 ma_x += 15;
102                 ma_y += 15;
103                 ma_z += 1;
104         }
105         else
106         {
107                 mi_x -= 1;
108                 mi_y -= 1;
109                 mi_z -= 1;
110                 ma_x += 1;
111                 ma_y += 1;
112                 ma_z += 1;
113         }
114
115         self.absmin = mi;
116         self.absmax = ma;
117
118         if(touch_triggers)
119                 _Movetype_LinkEdict_TouchAreaGrid();
120 }
121
122 float _Movetype_TestEntityPosition(vector ofs) // SV_TestEntityPosition
123 {
124         vector org;
125         float cont;
126         org = self.move_origin + ofs;
127         
128         cont = self.dphitcontentsmask;
129         self.dphitcontentsmask = DPCONTENTS_SOLID;
130         tracebox(self.move_origin, self.mins, self.maxs, self.move_origin, MOVE_NOMONSTERS, self);
131         self.dphitcontentsmask = cont;
132
133         if(trace_startsolid)
134                 return TRUE;
135
136         if(vlen(trace_endpos - self.move_origin) > 0.0001)
137                 self.move_origin = trace_endpos;
138         return FALSE;
139 }
140
141 float _Movetype_UnstickEntity() // SV_UnstickEntity
142 {
143         if(!_Movetype_TestEntityPosition('0 0 0'))
144                 return TRUE;
145         if(!_Movetype_TestEntityPosition('-1 0 0')) goto success;
146         if(!_Movetype_TestEntityPosition('1 0 0')) goto success;
147         if(!_Movetype_TestEntityPosition('0 -1 0')) goto success;
148         if(!_Movetype_TestEntityPosition('0 1 0')) goto success;
149         if(!_Movetype_TestEntityPosition('-1 -1 0')) goto success;
150         if(!_Movetype_TestEntityPosition('1 -1 0')) goto success;
151         if(!_Movetype_TestEntityPosition('-1 1 0')) goto success;
152         if(!_Movetype_TestEntityPosition('1 1 0')) goto success;
153         float i;
154         for(i = 1; i <= 17; ++i)
155         {
156                 if(!_Movetype_TestEntityPosition('0 0 -1' * i)) goto success;
157                 if(!_Movetype_TestEntityPosition('0 0 1' * i)) goto success;
158         }
159         dprint("Some entity is stuck\n");
160         return FALSE;
161 :success
162         dprint("Unstuck some entity\n");
163         _Movetype_LinkEdict(TRUE);
164         return TRUE;
165 }
166
167 vector _Movetype_ClipVelocity(vector vel, vector norm, float f) // SV_ClipVelocity
168 {
169         vel = vel - ((vel * norm) * norm) * f;
170
171         if(vel_x > -0.1 && vel_x < 0.1) vel_x = 0;
172         if(vel_y > -0.1 && vel_y < 0.1) vel_y = 0;
173         if(vel_z > -0.1 && vel_z < 0.1) vel_z = 0;
174
175         return vel;
176 }
177
178 void _Movetype_PushEntityTrace(vector push)
179 {
180         vector end;
181         float type;
182
183         end = self.move_origin + push;
184
185         if(self.move_movetype == MOVETYPE_FLYMISSILE)
186                 type = MOVE_MISSILE;
187         else if(self.solid == SOLID_TRIGGER || self.solid == SOLID_NOT)
188                 type = MOVE_NOMONSTERS;
189         else
190                 type = MOVE_NORMAL;
191
192         tracebox(self.move_origin, self.mins, self.maxs, end, type, self);
193 }
194
195 float _Movetype_PushEntity(vector push, float failonstartsolid) // SV_PushEntity
196 {
197         _Movetype_PushEntityTrace(push);
198
199         if(trace_startsolid && failonstartsolid)
200                 return trace_fraction;
201
202         self.move_origin = trace_endpos;
203
204         if(trace_fraction < 1)
205                 if(self.solid >= SOLID_TRIGGER && (!(self.move_flags & FL_ONGROUND) || (self.move_groundentity != trace_ent)))
206                         _Movetype_Impact(trace_ent);
207
208         return trace_fraction;
209 }
210
211 void _Movetype_Physics_Toss(float dt) // SV_Physics_Toss
212 {
213         if(self.move_flags & FL_ONGROUND)
214         {
215                 if(self.velocity_z >= 1/32)
216                         self.move_flags &~= FL_ONGROUND;
217                 else if(!self.move_groundentity)
218                         return;
219                 else if(self.move_suspendedinair && wasfreed(self.move_groundentity))
220                 {
221                         self.move_groundentity = world;
222                         return;
223                 }
224         }
225
226         self.move_suspendedinair = FALSE;
227
228         _Movetype_CheckVelocity();
229
230         if(self.move_movetype == MOVETYPE_BOUNCE || self.move_movetype == MOVETYPE_TOSS)
231         {
232                 self.move_didgravity = TRUE;
233                 if(self.gravity)
234                         self.move_velocity_z -= dt * self.gravity * getstatf(STAT_MOVEVARS_GRAVITY);
235                 else
236                         self.move_velocity_z -= dt * getstatf(STAT_MOVEVARS_GRAVITY);
237         }
238
239         self.move_angles = self.move_angles + self.move_avelocity * dt;
240
241         vector move;
242         move = self.move_velocity * dt;
243
244         _Movetype_PushEntity(move, TRUE);
245         if(wasfreed(self))
246                 return;
247         
248         if(trace_startsolid)
249         {
250                 _Movetype_UnstickEntity();
251                 _Movetype_PushEntity(move, FALSE);
252                 if(wasfreed(self))
253                         return;
254         }
255
256         if(trace_fraction < 1)
257         {
258                 if(self.move_movetype == MOVETYPE_BOUNCEMISSILE)
259                 {
260                         self.move_velocity = _Movetype_ClipVelocity(self.move_velocity, trace_plane_normal, 2.0);
261                         self.move_flags &~= FL_ONGROUND;
262                 }
263                 else if(self.move_movetype == MOVETYPE_BOUNCE)
264                 {
265                         float d, bouncefac, bouncestop;
266
267                         bouncefac = self.move_bounce_factor;     if(!bouncefac)  bouncefac = 0.5;
268                         bouncestop = self.move_bounce_stopspeed; if(!bouncestop) bouncestop = 60;
269
270                         self.move_velocity = _Movetype_ClipVelocity(self.move_velocity, trace_plane_normal, 1 + bouncefac);
271
272                         d = trace_plane_normal * self.move_velocity;
273                         if(trace_plane_normal_z > 0.7 && d < bouncestop && d > -bouncestop)
274                         {
275                                 self.move_flags |= FL_ONGROUND;
276                                 self.move_groundentity = trace_ent;
277                                 self.move_velocity = '0 0 0';
278                                 self.move_avelocity = '0 0 0';
279                         }
280                         else
281                                 self.move_flags &~= FL_ONGROUND;
282                 }
283                 else
284                 {
285                         self.move_velocity = _Movetype_ClipVelocity(self.move_velocity, trace_plane_normal, 1.0);
286                         if(trace_plane_normal_z > 0.7)
287                         {
288                                 self.move_flags |= FL_ONGROUND;
289                                 self.move_groundentity = trace_ent;
290                                 if(trace_ent.solid == SOLID_BSP)
291                                         self.move_suspendedinair = TRUE;
292                                 self.move_velocity = '0 0 0';
293                                 self.move_avelocity = '0 0 0';
294                         }
295                         else
296                                 self.move_flags &~= FL_ONGROUND;
297                 }
298         }
299
300         _Movetype_CheckWaterTransition();
301 }
302
303 void Movetype_Physics(float matchserver) // SV_Physics_Entity
304 {
305         float n, i, dt, movedt;
306
307         dt = time - self.move_time;
308
309         if(matchserver)
310         {
311                 movedt = ticrate;
312                 n = max(0, floor(dt / ticrate));
313                 dt -= n * ticrate;
314                 self.move_time += n * ticrate;
315         }
316         else
317         {
318                 movedt = dt;
319                 dt = 0;
320                 n = 1;
321                 self.move_time = time;
322         }
323
324         //self.move_didgravity = ((self.move_movetype == MOVETYPE_BOUNCE || self.move_movetype == MOVETYPE_TOSS) && !(self.move_flags & FL_ONGROUND));
325         // we use the field as set by the last run of this
326
327         for(i = 0; i < n; ++i)
328         {
329                 self.move_didgravity = FALSE;
330                 switch(self.move_movetype)
331                 {
332                         case MOVETYPE_PUSH:
333                         case MOVETYPE_FAKEPUSH:
334                                 error("SV_Physics_Pusher not implemented");
335                                 break;
336                         case MOVETYPE_NONE:
337                                 break;
338                         case MOVETYPE_FOLLOW:
339                                 error("SV_Physics_Follow not implemented");
340                                 break;
341                         case MOVETYPE_NOCLIP:
342                                 _Movetype_CheckWater();
343                                 self.move_origin = self.move_origin + ticrate * self.move_velocity;
344                                 self.move_angles = self.move_angles + ticrate * self.move_avelocity;
345                                 _Movetype_LinkEdict(FALSE);
346                                 break;
347                         case MOVETYPE_STEP:
348                                 error("SV_Physics_Step not implemented");
349                                 break;
350                         case MOVETYPE_WALK:
351                                 error("SV_Physics_Walk not implemented");
352                                 break;
353                         case MOVETYPE_TOSS:
354                         case MOVETYPE_BOUNCE:
355                         case MOVETYPE_BOUNCEMISSILE:
356                         case MOVETYPE_FLYMISSILE:
357                         case MOVETYPE_FLY:
358                                 _Movetype_Physics_Toss(movedt);
359                                 break;
360                 }
361         }
362
363         self.avelocity = self.move_avelocity;
364
365         if(dt > 0 && self.move_movetype != MOVETYPE_NONE)
366         {
367                 // now continue the move from move_time to time
368                 self.velocity = self.move_velocity;
369                 if(self.move_didgravity)
370                 {
371                         if(self.gravity)
372                                 self.velocity_z -= dt * self.gravity * getstatf(STAT_MOVEVARS_GRAVITY);
373                         else
374                                 self.velocity_z -= dt * getstatf(STAT_MOVEVARS_GRAVITY);
375                 }
376
377                 self.angles = self.move_angles + dt * self.avelocity;
378
379                 if(self.movetype != MOVETYPE_NOCLIP)
380                 {
381                         _Movetype_PushEntityTrace(dt * self.velocity);
382                         if(!trace_startsolid)
383                                 self.origin = trace_endpos;
384                 }
385                 else
386                         self.origin = self.move_origin + dt * self.velocity;
387         }
388         else
389         {
390                 self.velocity = self.move_velocity;
391                 self.angles = self.move_angles;
392                 self.origin = self.move_origin;
393         }
394
395         if(!wasfreed(self))
396                 setorigin(self, self.origin);
397 }