Include gmqcc binaries for Windows and Linux
[voretournament/voretournament.git] / data / qcsrc / warpzonelib / common.qc
1 void WarpZone_Accumulator_Clear(entity acc)
2 {
3         acc.warpzone_transform = '0 0 0';
4         acc.warpzone_shift = '0 0 0';
5 }
6 void WarpZone_Accumulator_AddTransform(entity acc, vector t, vector s)
7 {
8         vector tr, st;
9         tr = AnglesTransform_Multiply(t, acc.warpzone_transform);
10         st = AnglesTransform_Multiply_GetPostShift(t, s, acc.warpzone_transform, acc.warpzone_shift);
11         acc.warpzone_transform = tr;
12         acc.warpzone_shift = st;
13 }
14 void WarpZone_Accumulator_Add(entity acc, entity wz)
15 {
16         vector t, st;
17         t = AnglesTransform_Multiply(wz.warpzone_transform, acc.warpzone_transform);
18         st = AnglesTransform_Multiply_GetPostShift(wz.warpzone_transform, wz.warpzone_shift, acc.warpzone_transform, acc.warpzone_shift);
19         acc.warpzone_transform = t;
20         acc.warpzone_shift = st;
21 }
22
23 .vector(vector, vector) camera_transform;
24 var float autocvar_cl_warpzone_usetrace = 1;
25 vector WarpZone_camera_transform(vector org, vector ang)
26 {
27         vector vf, vr, vu;
28         vf = v_forward;
29         vr = v_right;
30         vu = v_up;
31         org = WarpZone_TransformOrigin(self, org);
32         vf = WarpZone_TransformVelocity(self, vf);
33         vr = WarpZone_TransformVelocity(self, vr);
34         vu = WarpZone_TransformVelocity(self, vu);
35         if(autocvar_cl_warpzone_usetrace)
36                 traceline(self.warpzone_targetorigin, org, MOVE_NOMONSTERS, world);
37         else
38                 trace_endpos = self.warpzone_targetorigin;
39         v_forward = vf;
40         v_right = vr;
41         v_up = vu;
42         return org;
43 }
44
45 void WarpZone_SetUp(entity e, vector my_org, vector my_ang, vector other_org, vector other_ang)
46 {
47         e.warpzone_transform = AnglesTransform_Divide(other_ang, AnglesTransform_TurnDirectionFR(my_ang));
48         e.warpzone_shift = AnglesTransform_PrePostShift_GetPostShift(my_org, e.warpzone_transform, other_org);
49         e.warpzone_origin = my_org;
50         e.warpzone_targetorigin = other_org;
51         e.warpzone_angles = my_ang;
52         e.warpzone_targetangles = other_ang;
53         fixedmakevectors(my_ang); e.warpzone_forward = v_forward;
54         fixedmakevectors(other_ang); e.warpzone_targetforward = v_forward;
55         e.camera_transform = WarpZone_camera_transform;
56 }
57
58 .entity enemy;
59
60 vector WarpZoneLib_BoxTouchesBrush_mins;
61 vector WarpZoneLib_BoxTouchesBrush_maxs;
62 entity WarpZoneLib_BoxTouchesBrush_ent;
63 entity WarpZoneLib_BoxTouchesBrush_ignore;
64 float WarpZoneLib_BoxTouchesBrush_Recurse()
65 {
66         float s;
67         entity se;
68         float f;
69
70         tracebox('0 0 0', WarpZoneLib_BoxTouchesBrush_mins, WarpZoneLib_BoxTouchesBrush_maxs, '0 0 0', MOVE_NOMONSTERS, WarpZoneLib_BoxTouchesBrush_ignore);
71 #ifdef CSQC
72         if (trace_networkentity)
73         {
74                 dprint("hit a network ent, cannot continue WarpZoneLib_BoxTouchesBrush\n");
75                 // we cannot continue, as a player blocks us...
76                 // so, abort
77                 return 0;
78         }
79 #endif
80         if not(trace_ent)
81                 return 0;
82         if (trace_ent == WarpZoneLib_BoxTouchesBrush_ent)
83                 return 1;
84
85         se = trace_ent;
86         s = se.solid;
87         se.solid = SOLID_NOT;
88         f = WarpZoneLib_BoxTouchesBrush_Recurse();
89         se.solid = s;
90
91         return f;
92 }
93
94 float WarpZoneLib_BoxTouchesBrush(vector mi, vector ma, entity e, entity ig)
95 {
96     float f, s;
97
98     if not(e.modelindex)
99         return 1;
100
101     s = e.solid;
102     e.solid = SOLID_BSP;
103     WarpZoneLib_BoxTouchesBrush_mins = mi;
104     WarpZoneLib_BoxTouchesBrush_maxs = ma;
105     WarpZoneLib_BoxTouchesBrush_ent = e;
106     WarpZoneLib_BoxTouchesBrush_ignore = ig;
107     f = WarpZoneLib_BoxTouchesBrush_Recurse();
108     e.solid = s;
109
110     return f;
111 }
112
113 entity WarpZone_Find(vector mi, vector ma)
114 {
115         // if we are near any warpzone planes - MOVE AWAY (work around nearclip)
116         entity e;
117         for(e = world; (e = find(e, classname, "trigger_warpzone")); )
118                 if(WarpZoneLib_BoxTouchesBrush(mi, ma, e, world))
119                         return e;
120         return world;
121 }
122
123 void WarpZone_MakeAllSolid()
124 {
125         entity e;
126         for(e = world; (e = find(e, classname, "trigger_warpzone")); )
127                 e.solid = SOLID_BSP;
128 }
129
130 void WarpZone_MakeAllOther()
131 {
132         entity e;
133         for(e = world; (e = find(e, classname, "trigger_warpzone")); )
134                 e.solid = SOLID_TRIGGER;
135 }
136
137 void WarpZone_Trace_InitTransform()
138 {
139         if(!WarpZone_trace_transform)
140         {
141                 WarpZone_trace_transform = spawn();
142                 WarpZone_trace_transform.classname = "warpzone_trace_transform";
143         }
144         WarpZone_Accumulator_Clear(WarpZone_trace_transform);
145 }
146 void WarpZone_Trace_AddTransform(entity wz)
147 {
148         WarpZone_Accumulator_Add(WarpZone_trace_transform, wz);
149 }
150
151 void WarpZone_TraceBox_ThroughZone(vector org, vector mi, vector ma, vector end, float nomonsters, entity forent, entity zone, WarpZone_trace_callback_t cb)
152 {
153         float frac, sol;
154         vector o0, e0;
155         entity wz;
156         vector vf, vr, vu;
157         vf = v_forward;
158         vr = v_right;
159         vu = v_up;
160         o0 = org;
161         e0 = end;
162         WarpZone_Trace_InitTransform();
163         // if starting in warpzone, first transform
164         wz = WarpZone_Find(org + mi, org + ma);
165         if(wz)
166         {
167                 if(zone && wz != zone)
168                 {
169                         // we are in ANOTHER warpzone. This is bad. Make a zero length trace and return.
170                         sol = 1;
171                         trace_fraction = 0;
172                         trace_endpos = org;
173                         goto fail;
174                 }
175                 WarpZone_Trace_AddTransform(wz);
176                 org = WarpZone_TransformOrigin(wz, trace_endpos);
177                 end = WarpZone_TransformOrigin(wz, end);
178         }
179         WarpZone_MakeAllSolid();
180         sol = -1;
181         frac = 0;
182         for(;;)
183         {
184                 tracebox(org, mi, ma, end, nomonsters, forent);
185                 if(cb)
186                         cb(org, trace_endpos, end);
187                 if(sol < 0)
188                         sol = trace_startsolid;
189
190                 frac = trace_fraction = frac + (1 - frac) * trace_fraction;
191                 if(trace_fraction >= 1)
192                         break;
193                 if(trace_ent.classname != "trigger_warpzone")
194                         break;
195                 if(trace_ent == wz)
196                 {
197                         dprint("I transformed into the same zone again, wtf, aborting the trace\n");
198                         break;
199                 }
200                 wz = trace_ent;
201                 if(zone && wz != zone)
202                         break;
203                 WarpZone_Trace_AddTransform(wz);
204                 // we hit a warpzone... so, let's perform the trace after the warp again
205                 org = WarpZone_TransformOrigin(wz, trace_endpos);
206                 end = WarpZone_TransformOrigin(wz, end);
207         }
208         WarpZone_MakeAllOther();
209 :fail
210         trace_startsolid = sol;
211         v_forward = vf;
212         v_right = vr;
213         v_up = vu;
214 }
215
216 void WarpZone_TraceBox(vector org, vector mi, vector ma, vector end, float nomonsters, entity forent)
217 {
218         WarpZone_TraceBox_ThroughZone(org, mi, ma, end, nomonsters, forent, world, WarpZone_trace_callback_t_null);
219 }
220
221 void WarpZone_TraceLine(vector org, vector end, float nomonsters, entity forent)
222 {
223         WarpZone_TraceBox(org, '0 0 0', '0 0 0', end, nomonsters, forent);
224 }
225
226 void WarpZone_TraceToss_ThroughZone(entity e, entity forent, entity zone, WarpZone_trace_callback_t cb)
227 {
228         float g, dt;
229         vector vf, vr, vu, v0, o0;
230         entity wz;
231
232         vf = v_forward;
233         vr = v_right;
234         vu = v_up;
235         o0 = e.origin;
236         v0 = e.velocity;
237         WarpZone_Trace_InitTransform();
238         // if starting in warpzone, first transform
239         wz = WarpZone_Find(e.origin + e.mins, e.origin + e.maxs);
240         if(wz)
241         {
242                 if(zone && wz != zone)
243                 {
244                         // we are in ANOTHER warpzone. This is bad. Make a zero length trace and return.
245
246                         WarpZone_tracetoss_time = 0;
247                         trace_endpos = o0;
248                         goto fail;
249                 }
250                 WarpZone_Trace_AddTransform(wz);
251                 setorigin(e, WarpZone_TransformOrigin(wz, e.origin));
252                 e.velocity = WarpZone_TransformVelocity(wz, e.velocity);
253         }
254         WarpZone_MakeAllSolid();
255         g = cvar("sv_gravity") * e.gravity;
256         WarpZone_tracetoss_time = 0;
257         for(;;)
258         {
259                 tracetoss(e, forent);
260                 if(cb)
261                         cb(e.origin, trace_endpos, trace_endpos);
262                 e.origin = trace_endpos;
263                 e.velocity_z -= WarpZone_tracetoss_time * g;
264                 dt = vlen(e.origin - o0) / vlen(e.velocity);
265                 WarpZone_tracetoss_time += dt;
266                 if(trace_fraction >= 1)
267                         break;
268                 if(trace_ent.classname != "trigger_warpzone")
269                         break;
270                 if(trace_ent == wz)
271                 {
272                         dprint("I transformed into the same zone again, wtf, aborting the trace\n");
273                         break;
274                 }
275                 wz = trace_ent;
276                 if(zone && wz != zone)
277                         break;
278                 WarpZone_Trace_AddTransform(wz);
279                 // we hit a warpzone... so, let's perform the trace after the warp again
280                 e.origin = WarpZone_TransformOrigin(wz, e.origin);
281                 e.velocity = WarpZone_TransformVelocity(wz, e.velocity);
282         }
283         WarpZone_MakeAllOther();
284 :fail
285         WarpZone_tracetoss_velocity = e.velocity;
286         v_forward = vf;
287         v_right = vr;
288         v_up = vu;
289         // restore old entity data (caller just uses trace_endpos, WarpZone_tracetoss_velocity and the transform)
290         e.velocity = v0;
291         e.origin = o0;
292 }
293
294 void WarpZone_TraceToss(entity e, entity forent)
295 {
296         WarpZone_TraceToss_ThroughZone(e, forent, world, WarpZone_trace_callback_t_null);
297 }
298
299 entity WarpZone_TrailParticles_trace_callback_own;
300 float WarpZone_TrailParticles_trace_callback_eff;
301 void WarpZone_TrailParticles_trace_callback(vector from, vector endpos, vector to)
302 {
303         trailparticles(WarpZone_TrailParticles_trace_callback_own, WarpZone_TrailParticles_trace_callback_eff, from, endpos);
304 }
305
306 void WarpZone_TrailParticles(entity own, float eff, vector org, vector end)
307 {
308         WarpZone_TrailParticles_trace_callback_own = own;
309         WarpZone_TrailParticles_trace_callback_eff = eff;
310         WarpZone_TraceBox_ThroughZone(org, '0 0 0', '0 0 0', end, MOVE_NOMONSTERS, world, world, WarpZone_TrailParticles_trace_callback);
311 }
312
313 float WarpZone_PlaneDist(entity wz, vector v)
314 {
315         return (v - wz.warpzone_origin) * wz.warpzone_forward;
316 }
317
318 float WarpZone_TargetPlaneDist(entity wz, vector v)
319 {
320         return (v - wz.warpzone_targetorigin) * wz.warpzone_targetforward;
321 }
322
323 vector WarpZone_TransformOrigin(entity wz, vector v)
324 {
325         return wz.warpzone_shift + AnglesTransform_Apply(wz.warpzone_transform, v);
326 }
327
328 vector WarpZone_TransformVelocity(entity wz, vector v)
329 {
330         return AnglesTransform_Apply(wz.warpzone_transform, v);
331 }
332
333 vector WarpZone_TransformAngles(entity wz, vector v)
334 {
335         return AnglesTransform_ApplyToAngles(wz.warpzone_transform, v);
336 }
337
338 vector WarpZone_TransformVAngles(entity wz, vector ang)
339 {
340 #ifdef KEEP_ROLL
341         float roll;
342         roll = ang_z;
343         ang_z = 0;
344 #endif
345
346         ang = AnglesTransform_ApplyToVAngles(wz.warpzone_transform, ang);
347
348 #ifdef KEEP_ROLL
349         ang = AnglesTransform_Normalize(ang, TRUE);
350         ang = AnglesTransform_CancelRoll(ang);
351         ang_z = roll;
352 #else
353         ang = AnglesTransform_Normalize(ang, FALSE);
354 #endif
355
356         return ang;
357 }
358
359 vector WarpZone_UnTransformOrigin(entity wz, vector v)
360 {
361         return AnglesTransform_Apply(AnglesTransform_Invert(wz.warpzone_transform), v - wz.warpzone_shift);
362 }
363
364 vector WarpZone_UnTransformVelocity(entity wz, vector v)
365 {
366         return AnglesTransform_Apply(AnglesTransform_Invert(wz.warpzone_transform), v);
367 }
368
369 vector WarpZone_UnTransformAngles(entity wz, vector v)
370 {
371         return AnglesTransform_ApplyToAngles(AnglesTransform_Invert(wz.warpzone_transform), v);
372 }
373
374 vector WarpZone_UnTransformVAngles(entity wz, vector ang)
375 {
376         float roll;
377
378         roll = ang_z;
379         ang_z = 0;
380
381         ang = AnglesTransform_ApplyToVAngles(AnglesTransform_Invert(wz.warpzone_transform), ang);
382         ang = AnglesTransform_Normalize(ang, TRUE);
383         ang = AnglesTransform_CancelRoll(ang);
384
385         ang_z = roll;
386         return ang;
387 }
388
389 vector WarpZoneLib_NearestPointOnBox(vector mi, vector ma, vector org)
390 {
391         vector nearest;
392         nearest_x = bound(mi_x, org_x, ma_x);
393         nearest_y = bound(mi_y, org_y, ma_y);
394         nearest_z = bound(mi_z, org_z, ma_z);
395         return nearest;
396 }
397
398 .float WarpZone_findradius_hit;
399 .entity WarpZone_findradius_next;
400 void WarpZone_FindRadius_Recurse(vector org, float rad,        vector org0,               vector transform, vector shift, float needlineofsight)
401 //                               blast origin of current search   original blast origin   how to untransform (victim to blast system)
402 {
403         vector org_new;
404         vector org0_new;
405         vector shift_new, transform_new;
406         vector p;
407         entity e, e0;
408         entity wz;
409         if(rad <= 0)
410                 return;
411         e0 = findradius(org, rad);
412         wz = world;
413
414         for(e = e0; e; e = e.chain)
415         {
416                 p = WarpZoneLib_NearestPointOnBox(e.origin + e.mins, e.origin + e.maxs, org0);
417                 if(needlineofsight)
418                 {
419                         traceline(org, p, MOVE_NOMONSTERS, e);
420                         if(trace_fraction < 1)
421                                 continue;
422                 }
423                 if(!e.WarpZone_findradius_hit || vlen(e.WarpZone_findradius_dist) > vlen(org0 - p))
424                 {
425                         e.WarpZone_findradius_nearest = p;
426                         e.WarpZone_findradius_dist = org0 - p;
427                         e.WarpZone_findradius_findorigin = org;
428                         e.WarpZone_findradius_findradius = rad;
429                         if(e.classname == "warpzone_refsys")
430                         {
431                                 // ignore, especially: do not overwrite the refsys parameters
432                         }
433                         else if(e.classname == "trigger_warpzone")
434                         {
435                                 e.WarpZone_findradius_next = wz;
436                                 wz = e;
437                                 e.WarpZone_findradius_hit = 1;
438                                 e.enemy.WarpZone_findradius_dist = '0 0 0'; // we don't want to go through this zone ever again
439                                 e.enemy.WarpZone_findradius_hit = 1;
440                         }
441                         else
442                         {
443                                 e.warpzone_transform = transform;
444                                 e.warpzone_shift = shift;
445                                 e.WarpZone_findradius_hit = 1;
446                         }
447                 }
448         }
449         for(e = wz; e; e = e.WarpZone_findradius_next)
450         {
451                 org0_new = WarpZone_TransformOrigin(e, org);
452                 traceline(e.warpzone_targetorigin, org0_new, MOVE_NOMONSTERS, e);
453                 org_new = trace_endpos;
454
455                 transform_new = AnglesTransform_Multiply(e.warpzone_transform, transform);
456                 shift_new = AnglesTransform_Multiply_GetPostShift(e.warpzone_transform, e.warpzone_shift, transform, shift);
457                 WarpZone_FindRadius_Recurse(
458                         org_new,
459                         bound(0, rad - vlen(org_new - org0_new), rad - 8),
460                         org0_new,
461                         transform_new, shift_new,
462                         needlineofsight);
463                 e.WarpZone_findradius_hit = 0;
464                 e.enemy.WarpZone_findradius_hit = 0;
465         }
466 }
467 entity WarpZone_FindRadius(vector org, float rad, float needlineofsight)
468 {
469         entity e0, e;
470         WarpZone_FindRadius_Recurse(org, rad, org, '0 0 0', '0 0 0', needlineofsight);
471         e0 = findchainfloat(WarpZone_findradius_hit, 1);
472         for(e = e0; e; e = e.chain)
473                 e.WarpZone_findradius_hit = 0;
474         return e0;
475 }
476
477 .entity WarpZone_refsys;
478 void WarpZone_RefSys_GC()
479 {
480         // garbage collect unused reference systems
481         self.nextthink = time + 1;
482         if(self.owner.WarpZone_refsys != self)
483                 remove(self);
484 }
485 void WarpZone_RefSys_Add(entity me, entity wz)
486 {
487         if(me.WarpZone_refsys.owner != me)
488         {
489                 me.WarpZone_refsys = spawn();
490                 me.WarpZone_refsys.classname = "warpzone_refsys";
491                 me.WarpZone_refsys.owner = me;
492                 me.WarpZone_refsys.think = WarpZone_RefSys_GC;
493                 me.WarpZone_refsys.nextthink = time + 1;
494                 WarpZone_Accumulator_Clear(me.WarpZone_refsys);
495         }
496         if(wz)
497                 WarpZone_Accumulator_Add(me.WarpZone_refsys, wz);
498 }
499 .vector WarpZone_refsys_incremental_shift;
500 .vector WarpZone_refsys_incremental_transform;
501 void WarpZone_RefSys_AddIncrementally(entity me, entity ref)
502 {
503         vector t, s;
504         if(me.WarpZone_refsys_incremental_transform == ref.WarpZone_refsys.warpzone_transform)
505         if(me.WarpZone_refsys_incremental_shift == ref.WarpZone_refsys.warpzone_shift)
506                 return;
507         if(me.WarpZone_refsys.owner != me)
508         {
509                 me.WarpZone_refsys = spawn();
510                 me.WarpZone_refsys.classname = "warpzone_refsys";
511                 me.WarpZone_refsys.owner = me;
512                 me.WarpZone_refsys.think = WarpZone_RefSys_GC;
513                 me.WarpZone_refsys.nextthink = time + 1;
514                 WarpZone_Accumulator_Clear(me.WarpZone_refsys);
515         }
516         t = AnglesTransform_Invert(me.WarpZone_refsys_incremental_transform);
517         s = AnglesTransform_PrePostShift_GetPostShift(me.WarpZone_refsys_incremental_shift, t, '0 0 0');
518         WarpZone_Accumulator_AddTransform(me.WarpZone_refsys, t, s);
519         WarpZone_Accumulator_Add(me.WarpZone_refsys, ref);
520         me.WarpZone_refsys_incremental_shift = ref.WarpZone_refsys.warpzone_shift;
521         me.WarpZone_refsys_incremental_transform = ref.WarpZone_refsys.warpzone_transform;
522 }
523 void WarpZone_RefSys_BeginAddingIncrementally(entity me, entity ref)
524 {
525         me.WarpZone_refsys_incremental_shift = ref.WarpZone_refsys.warpzone_shift;
526         me.WarpZone_refsys_incremental_transform = ref.WarpZone_refsys.warpzone_transform;
527 }
528 vector WarpZone_RefSys_TransformOrigin(entity from, entity to, vector org)
529 {
530         if(from.WarpZone_refsys)
531                 org = WarpZone_UnTransformOrigin(from.WarpZone_refsys, org);
532         if(to.WarpZone_refsys)
533                 org = WarpZone_TransformOrigin(to.WarpZone_refsys, org);
534         return org;
535 }
536 vector WarpZone_RefSys_TransformVelocity(entity from, entity to, vector vel)
537 {
538         if(from.WarpZone_refsys)
539                 vel = WarpZone_UnTransformVelocity(from.WarpZone_refsys, vel);
540         if(to.WarpZone_refsys)
541                 vel = WarpZone_TransformVelocity(to.WarpZone_refsys, vel);
542         return vel;
543 }
544 vector WarpZone_RefSys_TransformAngles(entity from, entity to, vector ang)
545 {
546         if(from.WarpZone_refsys)
547                 ang = WarpZone_UnTransformAngles(from.WarpZone_refsys, ang);
548         if(to.WarpZone_refsys)
549                 ang = WarpZone_TransformAngles(to.WarpZone_refsys, ang);
550         return ang;
551 }
552 vector WarpZone_RefSys_TransformVAngles(entity from, entity to, vector ang)
553 {
554         if(from.WarpZone_refsys)
555                 ang = WarpZone_UnTransformVAngles(from.WarpZone_refsys, ang);
556         if(to.WarpZone_refsys)
557                 ang = WarpZone_TransformVAngles(to.WarpZone_refsys, ang);
558         return ang;
559 }
560 entity WarpZone_RefSys_SpawnSameRefSys(entity me)
561 {
562         entity e;
563         e = spawn();
564         if(me.WarpZone_refsys)
565         {
566                 e.WarpZone_refsys = spawn();
567                 e.WarpZone_refsys.classname = "warpzone_refsys";
568                 e.WarpZone_refsys.owner = e;
569                 e.WarpZone_refsys.think = WarpZone_RefSys_GC;
570                 e.WarpZone_refsys.nextthink = time + 1;
571                 e.WarpZone_refsys.warpzone_shift = me.WarpZone_refsys.warpzone_shift;
572                 e.WarpZone_refsys.warpzone_transform = me.WarpZone_refsys.warpzone_transform;
573         }
574         return e;
575 }