Xonotic QuakeC
The free, fast arena FPS with crisp movement and a wide array of weapons
common.qc
Go to the documentation of this file.
1#include "common.qh"
2
4
5#ifdef CSQC
6 #include <client/items/items.qh>
7#elifdef SVQC
9#endif
10
12{
13 acc.warpzone_transform = '0 0 0';
14 acc.warpzone_shift = '0 0 0';
15}
17{
18 vector tr = AnglesTransform_Multiply(t, acc.warpzone_transform);
19 vector st = AnglesTransform_Multiply_GetPostShift(t, s, acc.warpzone_transform, acc.warpzone_shift);
20 acc.warpzone_transform = tr;
21 acc.warpzone_shift = st;
22}
23#define WarpZone_Accumulator_Add(acc, wz) \
24 WarpZone_Accumulator_AddTransform(acc, (wz).warpzone_transform, (wz).warpzone_shift)
26{
30 // yes, this probably can be done simpler... but this way is "obvious" :)
31}
32#define WarpZone_Accumulator_AddInverse(acc, wz) \
33 WarpZone_Accumulator_AddInverseTransform(acc, (wz).warpzone_transform, (wz).warpzone_shift)
34
36{
37 if (this.warpzone_fadestart
38 && vdist(org - this.origin - 0.5 * (this.mins + this.maxs), >, this.warpzone_fadeend + 400))
39 return org;
40 // don't transform if zone faded out (plus 400qu safety margin for typical speeds and latencies)
41 // unneeded on client, on server this helps a lot
42 vector vf = v_forward;
43 vector vr = v_right;
44 vector vu = v_up;
46 vf = WarpZone_TransformVelocity(this, vf);
47 vr = WarpZone_TransformVelocity(this, vr);
48 vu = WarpZone_TransformVelocity(this, vu);
50 v_forward = vf;
51 v_right = vr;
52 v_up = vu;
53 return org;
54}
55
56void WarpZone_SetUp(entity e, vector my_org, vector my_ang, vector other_org, vector other_ang)
57{
58 e.warpzone_transform = AnglesTransform_RightDivide(other_ang, AnglesTransform_TurnDirectionFR(my_ang));
59 // fix small representation errors so that math operations with 0 will be cheaper
60 if (fabs(e.warpzone_transform.x) <= 0.000000000001) e.warpzone_transform.x = 0;
61 if (fabs(e.warpzone_transform.y) <= 0.000000000001) e.warpzone_transform.y = 0;
62 if (fabs(e.warpzone_transform.z) <= 0.000000000001) e.warpzone_transform.z = 0;
63 e.warpzone_shift = AnglesTransform_PrePostShift_GetPostShift(my_org, e.warpzone_transform, other_org);
64 e.warpzone_origin = my_org;
65 e.warpzone_targetorigin = other_org;
66 e.warpzone_angles = my_ang;
67 e.warpzone_targetangles = other_ang;
68 vector forward, right, up;
69 FIXED_MAKE_VECTORS(my_ang, forward, right, up);
70 e.warpzone_forward = forward;
71 FIXED_MAKE_VECTORS(other_ang, forward, right, up);
72 e.warpzone_targetforward = forward;
74}
75
77{
78 // a fixed camera view
79 if (this.warpzone_fadestart
80 && vdist(org - this.origin - 0.5 * (this.mins + this.maxs), >, this.warpzone_fadeend + 400))
81 return org;
82 // don't transform if zone faded out (plus 400qu safety margin for typical speeds and latencies)
83 // unneeded on client, on server this helps a lot
86 return this.warpzone_origin;
87}
88
89void WarpZone_Camera_SetUp(entity e, vector my_org, vector my_ang) // we assume that e.oldorigin and e.avelocity point to view origin and direction
90{
91 e.warpzone_origin = my_org;
92 e.warpzone_angles = my_ang;
94}
95
97{
98 tracebox('0 0 0', mi, ma, '0 0 0', MOVE_NOMONSTERS, ig);
99#ifdef CSQC
101 {
102 LOG_TRACE("hit a network ent, cannot continue WarpZoneLib_BoxTouchesBrush");
103 // we cannot continue, as a player blocks us...
104 // so, abort
105 return 0;
106 }
107#endif
108 if (!trace_ent)
109 return 0;
110 if (trace_ent == e)
111 return 1;
112
113 entity se = trace_ent;
114 float s = se.solid;
115 se.solid = SOLID_NOT;
116 setorigin(se, se.origin); // unlink
117 float f = WarpZoneLib_BoxTouchesBrush_Recurse(mi, ma, e, ig);
118 se.solid = s;
119 setorigin(se, se.origin); // relink
120
121 return f;
122}
123
125{
126 // bones_was_here: TODO: when findbox_OrFallback() is available, use it to
127 // optimise this into a single non-recursive function that only calls tracebox once
128
129 if (!e.modelindex || e.warpzone_isboxy)
130 return 1;
131
132 // work around trigger_hurt on geit3ctf1 not being detected by tracebox
133 // bones_was_here: FIXME: WHY do these triggers only have supercontents == 128 ?!
134 if (Q3COMPAT_COMMON && ig != world)
135 ig.dphitcontentsmask |= 128;
136
137 float s = e.solid;
138 if (e.solid != SOLID_BSP)
139 {
140 e.solid = SOLID_BSP;
141 setorigin(e, e.origin); // update linking
142 }
143 float f = WarpZoneLib_BoxTouchesBrush_Recurse(mi, ma, e, ig);
144 if (e.solid != s) // if we needed to change .solid temporarily
145 {
146 e.solid = s; // restore it
147 setorigin(e, e.origin); // update linking
148 }
149
150 if (Q3COMPAT_COMMON && ig != world)
151 ig.dphitcontentsmask &= ~128;
152
153 return f;
154}
155
157{
158 // if we are near any warpzone planes - MOVE AWAY (work around nearclip)
160 IL_EACH(g_warpzones, WarpZoneLib_BoxTouchesBrush(mi, ma, it, NULL), return it);
161 return NULL;
162}
163
165{
167 IL_EACH(g_warpzones, true, it.solid = SOLID_BSP);
168}
169
171{
173 IL_EACH(g_warpzones, true, it.solid = SOLID_TRIGGER);
174}
175
182#define WarpZone_Trace_AddTransform(wz) \
183 WarpZone_Accumulator_Add(WarpZone_trace_transform, wz)
184
188{
189 WarpZone_trace_forent = forent;
193
194 bool nearby_warpzones = false;
195 // use tracebox if no warpzone is touching the box the entity would be traced through
197 {
198 vector boxmin = mi;
199 vector boxmax = ma;
200 #define CHOOSE_AXIS(axis) \
201 if (org.axis < end.axis) { boxmin.axis += org.axis; boxmax.axis += end.axis; } \
202 else { boxmin.axis += end.axis; boxmax.axis += org.axis; }
203 CHOOSE_AXIS(x);
204 CHOOSE_AXIS(y);
205 CHOOSE_AXIS(z);
206 #undef CHOOSE_AXIS
207 /* Above is equivalent to the following, but more efficient
208 * boxmin += vec_to_min(org, end);
209 * boxmax += vec_to_max(org, end);
210 */
211 IL_EACH(g_warpzones, boxesoverlap(it.absmin, it.absmax, boxmin, boxmax),
212 {
213 nearby_warpzones = true;
214 break;
215 });
216 }
217 if (!nearby_warpzones)
218 {
219 if (nomonsters == MOVE_NOTHING)
220 {
221 trace_endpos = end;
222 trace_fraction = 1;
223 }
224 else
225 tracebox(org, mi, ma, end, nomonsters, WarpZone_trace_forent);
226
227 if (cb)
228 cb(org, trace_endpos, end);
229 return;
230 }
231
232 vector vf = v_forward;
233 vector vr = v_right;
234 vector vu = v_up;
235
236 float nomonsters_adjusted;
237 switch (nomonsters)
238 {
239 case MOVE_WORLDONLY:
240 case MOVE_NOTHING:
241 nomonsters_adjusted = MOVE_NOMONSTERS;
242 break;
243 default:
244 nomonsters_adjusted = nomonsters;
245 break;
246 }
247 bool contents_hack = (WarpZone_trace_forent.dphitcontentsmask && !(WarpZone_trace_forent.dphitcontentsmask & DPCONTENTS_SOLID));
248 if (contents_hack)
250
251 // if starting in warpzone, first transform
252 entity wz = WarpZone_Find(org + mi, org + ma);
253 float sol;
254 if (wz)
255 {
258 if (zone && wz != zone)
259 {
260 // we are in ANOTHER warpzone. This is bad. Make a zero length trace and return.
261 sol = 1;
262 trace_fraction = 0;
264 goto fail;
265 }
268 end = WarpZone_TransformOrigin(wz, end);
269 }
271 sol = -1;
272 float frac = 0;
273 float i = 16;
274 for (;;)
275 {
276 if (--i < 1)
277 {
278 LOG_TRACE("Too many warpzones in sequence, aborting trace.");
279 trace_ent = NULL;
280 break;
281 }
282 tracebox(org, mi, ma, end, nomonsters_adjusted, WarpZone_trace_forent);
283 if (cb)
284 cb(org, trace_endpos, end);
285 if (sol < 0)
286 sol = trace_startsolid;
287
288 frac = trace_fraction = frac + (1 - frac) * trace_fraction;
289 if (trace_fraction >= 1)
290 break;
291 if (trace_ent.classname != "trigger_warpzone")
292 {
293 if (nomonsters == MOVE_NOTHING
294 || (nomonsters == MOVE_WORLDONLY && trace_ent)
295 || (contents_hack && (trace_dphitcontents & WarpZone_trace_forent.dphitcontentsmask) == DPCONTENTS_SOLID))
296 {
297 // continue the trace, ignoring this hit (we only care for warpzones)
298 org = trace_endpos + normalize(end - org);
299 continue;
300 // we cannot do an inverted trace here, as we do care for further warpzones inside that "solid" to be found
301 // otherwise, players could block entrances that way
302 }
303 break;
304 }
305 /*if (trace_ent == wz)
306 {
307 // FIXME can this check be removed? Do we really need it?
308 LOG_TRACE("I transformed into the same zone again, wtf, aborting the trace");
309 trace_ent = NULL;
310 break;
311 }*/
312 wz = trace_ent;
316 if (zone && wz != zone)
317 break;
319 // we hit a warpzone... so, let's perform the trace after the warp again
321 end = WarpZone_TransformOrigin(wz, end);
322
323 // we got warped, so let's step back a bit
324 tracebox(org, mi, ma, org + normalize(org - end) * 32, nomonsters_adjusted, WarpZone_trace_forent);
326 }
328LABEL(fail)
329 if (contents_hack)
331 trace_startsolid = sol;
332 v_forward = vf;
333 v_right = vr;
334 v_up = vu;
335}
336
339{
340 vector o0 = e.origin;
341 vector v0 = e.velocity;
342 float dt, i, g = PHYS_GRAVITY(NULL) * e.gravity;
343
344 WarpZone_trace_forent = forent;
350 {
351 tracetoss(e, WarpZone_trace_forent);
352 if (cb)
353 cb(e.origin, trace_endpos, trace_endpos);
354 dt = sqrt(vlen2(e.origin - o0) / vlen2(e.velocity));
356 e.velocity.z -= dt * g;
357 WarpZone_tracetoss_velocity = e.velocity;
358 e.velocity = v0;
359 return;
360 }
361
362 vector vf = v_forward;
363 vector vr = v_right;
364 vector vu = v_up;
365
366 // if starting in warpzone, first transform
367 entity wz = WarpZone_Find(e.origin + e.mins, e.origin + e.maxs);
368 if (wz)
369 {
372 if (zone && wz != zone)
373 {
374 // we are in ANOTHER warpzone. This is bad. Make a zero length trace and return.
375
377 trace_endpos = o0;
378 goto fail;
379 }
381 vector org = WarpZone_TransformOrigin(wz, e.origin);
382 setorigin(e, org);
383 e.velocity = WarpZone_TransformVelocity(wz, e.velocity);
384 }
386 i = 16;
387 for (;;)
388 {
389 if (--i < 1)
390 {
391 LOG_TRACE("Too many warpzones in sequence, aborting trace.");
392 trace_ent = NULL;
393 break;
394 }
395 tracetoss(e, WarpZone_trace_forent);
396 if (cb)
397 cb(e.origin, trace_endpos, trace_endpos);
398 dt = sqrt(vlen2(trace_endpos - e.origin) / vlen2(e.velocity));
400 e.origin = trace_endpos;
401 e.velocity.z -= dt * g;
402 if (trace_fraction >= 1)
403 break;
404 if (trace_ent.classname != "trigger_warpzone")
405 break;
406 if (trace_ent == wz)
407 {
408 // FIXME can this check be removed? Do we really need it?
409 LOG_TRACE("I transformed into the same zone again, wtf, aborting the trace");
410 trace_ent = NULL;
411 break;
412 }
413 wz = trace_ent;
417 if (zone && wz != zone)
418 break;
420 // we hit a warpzone... so, let's perform the trace after the warp again
421 e.origin = WarpZone_TransformOrigin(wz, e.origin);
422 e.velocity = WarpZone_TransformVelocity(wz, e.velocity);
423
424 // we got warped, so let's step back a bit
425 e.velocity = -e.velocity;
426 tracetoss(e, WarpZone_trace_forent);
427 dt = sqrt(vlen2(trace_endpos - e.origin) / vlen2(e.velocity));
429 e.origin = trace_endpos;
430 e.velocity = -e.velocity;
431 }
433LABEL(fail)
434 WarpZone_tracetoss_velocity = e.velocity;
435 v_forward = vf;
436 v_right = vr;
437 v_up = vu;
438 // restore old entity data (caller just uses trace_endpos, WarpZone_tracetoss_velocity and the transform)
439 e.velocity = v0;
440 e.origin = o0;
441}
442
449
456
460{
461 te_csqc_trace_callback_func(start, hit);
462}
463
464#ifdef CSQC
471
480#endif
481
483{
484 return (p - wz.warpzone_origin) * wz.warpzone_forward;
485}
486
488{
489 return (p - wz.warpzone_targetorigin) * wz.warpzone_targetforward;
490}
491
494{
495 return wz.warpzone_shift + AnglesTransform_Apply(wz.warpzone_transform, org);
496}
497
500{
501 return AnglesTransform_Apply(wz.warpzone_transform, vel);
502}
503
505{
506 return AnglesTransform_ApplyToAngles(wz.warpzone_transform, ang);
507}
508
510{
511#ifdef KEEP_ROLL
512 float roll = ang.z;
513 ang.z = 0;
514#endif
515
516 ang = AnglesTransform_ApplyToVAngles(wz.warpzone_transform, ang);
517#ifdef KEEP_ROLL
520 ang.z = roll;
521#else
523#endif
524 return ang;
525}
526
531{
532 return AnglesTransform_Apply(AnglesTransform_Invert(wz.warpzone_transform), org - wz.warpzone_shift);
533}
534
536{
537 return AnglesTransform_Apply(AnglesTransform_Invert(wz.warpzone_transform), vel);
538}
539
544
546{
547#ifdef KEEP_ROLL
548 float roll = ang.z;
549 ang.z = 0;
550#endif
551
553#ifdef KEEP_ROLL
556 ang.z = roll;
557#else
559#endif
560 return ang;
561}
562
563// FIXME: the nearest bounding box point can be unreachable via trace,
564// despite there actually being line of sight if only the trace was adjusted slightly
565#define WarpZoneLib_NearestPointOnBox(mi, ma, org) NearestPointOnBoundingBox(mi, ma, org)
566
573{
574 if (e.WarpZone_findradius_hit != WarpZone_FindRadius_Hit_UNSEEN) // also account for caching
575 return (e.WarpZone_findradius_hit == WarpZone_FindRadius_Hit_BAD); // either BAD or GOOD
576 if (is_pure(e))
577 return true;
578
579 string s = e.classname;
580 switch (s)
581 {
582 case "warpzone_refsys": // ignore, especially: do not overwrite the refsys parameters
583 case "weaponentity":
584 case "exteriorweaponentity":
585 case "sprite_waypoint":
586 case "waypoint":
587 case "spawnfunc":
588 case "weaponchild":
589 case "chatbubbleentity":
590 case "buff_model":
591 //case "net_linked": // actually some real entities are linked without classname, fail
592 case "":
593 return true;
594 }
595 if (startsWith(s, "target_"))
596 return true;
597 if (startsWith(s, "info_"))
598 return true;
599
600 return (cb && !cb(e));
601}
602
603.entity enemy;
611 vector org,
612 float rad,
614 vector org0,
616 vector transform,
617 vector shift)
618{
619 if (rad <= 0)
620 return;
621 entity wz = NULL;
622 FOREACH_ENTITY_RADIUS(org, rad, it.WarpZone_findradius_hit != WarpZone_FindRadius_Hit_BAD, // exclude entities we already know are bad
623 {
624 bool is_warpzone = (it.classname == "trigger_warpzone");
625 if (!is_warpzone // warpzones are never bad entities
626 && WarpZoneLib_BadEntity(it, _WarpZone_FindRadius_cond_cb))
627 {
628 it.WarpZone_findradius_hit = WarpZone_FindRadius_Hit_BAD;
629 it.WarpZone_findradius_next = _WarpZone_FindRadius_badents_first;
630 // use .WarpZone_findradius_next so that .chain isn't changed on entities not included in the returned list_first
631 _WarpZone_FindRadius_badents_first = it;
632 continue;
633 }
634
635 vector p = WarpZoneLib_NearestPointOnBox(it.origin + it.mins, it.origin + it.maxs, org0);
636 if (it.WarpZone_findradius_hit == WarpZone_FindRadius_Hit_GOOD && vlen2(it.WarpZone_findradius_dist) <= vlen2(org0 - p))
637 continue;
639 {
640 traceline(org, p, _WarpZone_FindRadius_nomonsters, it);
641 if (trace_fraction < 1)
642 continue;
643 }
644
645 it.WarpZone_findradius_nearest = p;
646 it.WarpZone_findradius_dist = org0 - p;
647 //it.WarpZone_findradius_findorigin = org;
648 //it.WarpZone_findradius_findradius = rad;
649 if (is_warpzone)
650 {
651 it.WarpZone_findradius_next = wz;
652 wz = it;
653 it.WarpZone_findradius_hit = WarpZone_FindRadius_Hit_GOOD;
654 it.enemy.WarpZone_findradius_dist = '0 0 0'; // we don't want to go through this zone ever again
655 it.enemy.WarpZone_findradius_hit = WarpZone_FindRadius_Hit_GOOD;
656 }
657 else // entity we'll include in the list
658 {
659 it.warpzone_transform = transform;
660 it.warpzone_shift = shift;
661 if (it.WarpZone_findradius_hit != WarpZone_FindRadius_Hit_GOOD) // add to good ents chain if not already in it
662 {
663 it.chain = _WarpZone_FindRadius_goodents_first; // fine to use .chain since FOREACH_ENTITY_RADIUS doesn't use it
665 it.WarpZone_findradius_hit = WarpZone_FindRadius_Hit_GOOD;
666 }
667 }
668 });
669 for (entity e = wz; e; e = e.WarpZone_findradius_next)
670 {
671 vector org0_new = WarpZone_TransformOrigin(e, org);
672 traceline(e.warpzone_targetorigin, org0_new, MOVE_NOMONSTERS, e);
673 vector org_new = trace_endpos;
674
676 org_new,
677 rad - max(8, vlen(org_new - org0_new)),
678 org0_new,
679 AnglesTransform_Multiply(e.warpzone_transform, transform), // new transform
680 AnglesTransform_Multiply_GetPostShift(e.warpzone_transform, e.warpzone_shift, transform, shift)); // new shift
681 e.WarpZone_findradius_hit = e.enemy.WarpZone_findradius_hit = WarpZone_FindRadius_Hit_UNSEEN;
682 }
683}
685{
686 bool nearby_warpzones = false;
687 // use FOREACH_ENTITY_RADIUS if no warpzone is touching the box of side 2 * rad and center org
688 // which includes the sphere of radius rad and center org
690 {
691 vector boxmin = vec3(org.x - rad, org.y - rad, org.z - rad);
692 vector boxmax = vec3(org.x + rad, org.y + rad, org.z + rad);
693 IL_EACH(g_warpzones, boxesoverlap(it.absmin, it.absmax, boxmin, boxmax),
694 {
695 nearby_warpzones = true;
696 break;
697 });
698 }
699
701 if (nearby_warpzones)
702 {
706 _WarpZone_FindRadius_Recurse(org, rad, org, '0 0 0', '0 0 0');
707 FOREACH_LIST(_WarpZone_FindRadius_goodents, chain, true, it.WarpZone_findradius_hit = WarpZone_FindRadius_Hit_UNSEEN);
708 FOREACH_LIST(_WarpZone_FindRadius_badents, WarpZone_findradius_next, true, it.WarpZone_findradius_hit = WarpZone_FindRadius_Hit_UNSEEN);
709 }
710 else // cheaper than _WarpZone_FindRadius_Recurse
712 {
713 vector p = NearestPointOnBoundingBox(it.origin + it.mins, it.origin + it.maxs, org);
714 if (nomonsters != MOVE_NOTHING)
715 {
716 traceline(org, p, nomonsters, it);
717 if (trace_fraction < 1)
718 continue;
719 }
720
721 it.chain = _WarpZone_FindRadius_goodents_first; // fine to use .chain since FOREACH_ENTITY_RADIUS doesn't use it
723 it.WarpZone_findradius_nearest = p;
724 it.WarpZone_findradius_dist = org - p;
725 WarpZone_Accumulator_Clear(it); // reset .warpzone_transform and .warpzone_shift
726 });
727
729}
730
732// called when an entity is deleted with delete() / remove()
733// or when a player disconnects
735void ONREMOVE(entity this)
736{
737 // remove WarpZone_refsys object attached to 'this'
738 if (this.WarpZone_refsys && this.WarpZone_refsys.owner == this)
739 delete(this.WarpZone_refsys);
740}
742{
743 if (me.WarpZone_refsys.owner == me)
744 return;
745 me.WarpZone_refsys = new(warpzone_refsys);
746 me.WarpZone_refsys.owner = me;
747 WarpZone_Accumulator_Clear(me.WarpZone_refsys);
748}
750{
751 if (!me.WarpZone_refsys)
752 return;
753 delete(me.WarpZone_refsys);
754 me.WarpZone_refsys = NULL;
755}
757{
758 if (t == '0 0 0' && s == '0 0 0')
759 return;
761 WarpZone_Accumulator_AddTransform(me.WarpZone_refsys, t, s);
762}
764{
765 if (t == '0 0 0' && s == '0 0 0')
766 return;
768 WarpZone_Accumulator_AddInverseTransform(me.WarpZone_refsys, t, s);
769}
773{
774 //vector t, s;
775 if (me.WarpZone_refsys_incremental_transform == ref.WarpZone_refsys.warpzone_transform
776 && me.WarpZone_refsys_incremental_shift == ref.WarpZone_refsys.warpzone_shift)
777 return;
778 WarpZone_Accumulator_AddInverseTransform(me.WarpZone_refsys, me.WarpZone_refsys_incremental_transform, me.WarpZone_refsys_incremental_shift);
779 WarpZone_Accumulator_Add(me.WarpZone_refsys, ref.WarpZone_refsys);
780 me.WarpZone_refsys_incremental_shift = ref.WarpZone_refsys.warpzone_shift;
781 me.WarpZone_refsys_incremental_transform = ref.WarpZone_refsys.warpzone_transform;
782}
784{
785 me.WarpZone_refsys_incremental_shift = ref.WarpZone_refsys.warpzone_shift;
786 me.WarpZone_refsys_incremental_transform = ref.WarpZone_refsys.warpzone_transform;
787}
788
792{
793 if (from.WarpZone_refsys)
794 org = WarpZone_UnTransformOrigin(from.WarpZone_refsys, org);
795 if (to.WarpZone_refsys)
796 org = WarpZone_TransformOrigin(to.WarpZone_refsys, org);
797 return org;
798}
799
801{
802 if (from.WarpZone_refsys)
803 vel = WarpZone_UnTransformVelocity(from.WarpZone_refsys, vel);
804 if (to.WarpZone_refsys)
805 vel = WarpZone_TransformVelocity(to.WarpZone_refsys, vel);
806 return vel;
807}
808
810{
811 if (from.WarpZone_refsys)
812 ang = WarpZone_UnTransformAngles(from.WarpZone_refsys, ang);
813 if (to.WarpZone_refsys)
814 ang = WarpZone_TransformAngles(to.WarpZone_refsys, ang);
815 return ang;
816}
817
819{
820 if (from.WarpZone_refsys)
821 ang = WarpZone_UnTransformVAngles(from.WarpZone_refsys, ang);
822 if (to.WarpZone_refsys)
823 ang = WarpZone_TransformVAngles(to.WarpZone_refsys, ang);
824 return ang;
825}
826
829{
830 if (from.WarpZone_refsys)
831 {
833 me.WarpZone_refsys.warpzone_shift = from.WarpZone_refsys.warpzone_shift;
834 me.WarpZone_refsys.warpzone_transform = from.WarpZone_refsys.warpzone_transform;
835 }
836 else
838}
839
843{
844 entity e = spawn();
846 return e;
847}
848
850{
851 vector emin = toucher.absmin, emax = toucher.absmax;
852 if (!Q3COMPAT_COMMON)
853 {
854 // Xonotic and Nexuiz maps assume triggers will be activated by adjacent players
855 // prior to sv_legacy_bbox_expand 0 DP always did this for SVQC and never for CSQC
856 emin -= '1 1 1';
857 emax += '1 1 1';
858 }
859
860 // if called from a touch func, we can assume the boxes do overlap
861 if (!touchfunc && !boxesoverlap(emin, emax, this.absmin, this.absmax)) // quick
862 return false;
863
864 return WarpZoneLib_BoxTouchesBrush(emin, emax, this, toucher); // accurate
865}
866
867
869{
870 const float eps = 1/16; // 0.0625
871 tracebox(e.origin, e.mins - '1 1 1' * eps, e.maxs + '1 1 1' * eps, e.origin + by, MOVE_WORLDONLY, e);
873 return;
874 if (trace_fraction < 1)
875 // hit something, adjust origin in the other direction...
876 setorigin(e, e.origin - by * (1 - trace_fraction));
877}
878
880{
881 vector o = e.origin;
882 traceline(o, o, MOVE_WORLDONLY, e);
884 return 0; // too stuck, giving up
885
886 tracebox(o, e.mins, e.maxs, o, MOVE_WORLDONLY, e);
887 if (!trace_startsolid)
888 return -1; // wasn't stuck
889
890 vector m0 = e.mins;
891 vector m1 = e.maxs;
892 e.mins = '0 0 0';
893 e.maxs = '0 0 0';
894 WarpZoneLib_MoveOutOfSolid_Expand(e, eX * m0.x); e.mins.x = m0.x;
895 WarpZoneLib_MoveOutOfSolid_Expand(e, eX * m1.x); e.maxs.x = m1.x;
896 WarpZoneLib_MoveOutOfSolid_Expand(e, eY * m0.y); e.mins.y = m0.y;
897 WarpZoneLib_MoveOutOfSolid_Expand(e, eY * m1.y); e.maxs.y = m1.y;
898 WarpZoneLib_MoveOutOfSolid_Expand(e, eZ * m0.z); e.mins.z = m0.z;
899 WarpZoneLib_MoveOutOfSolid_Expand(e, eZ * m1.z); e.maxs.z = m1.z;
900 setorigin(e, e.origin);
901
902 tracebox(e.origin, e.mins, e.maxs, e.origin, MOVE_WORLDONLY, e);
904 {
905 setorigin(e, o);
906 return 0; // can't fix
907 }
908
909 return 1; // was stuck but is fixed now
910}
vector AnglesTransform_ApplyToVAngles(vector transform, vector v)
vector AnglesTransform_Multiply_GetPostShift(vector t0, vector st0, vector t1, vector st1)
vector AnglesTransform_CancelRoll(vector t)
vector AnglesTransform_TurnDirectionFR(vector transform)
vector AnglesTransform_Apply(vector transform, vector v)
angles transforms angles in fixedmakevectors/fixedvectoangles space
vector AnglesTransform_Normalize(vector t, float minimize_roll)
vector AnglesTransform_Invert(vector transform)
vector AnglesTransform_RightDivide(vector to_transform, vector from_transform)
vector AnglesTransform_PrePostShift_GetPostShift(vector sf, vector t, vector st)
vector AnglesTransform_Multiply(vector t1, vector t2)
vector AnglesTransform_ApplyToAngles(vector transform, vector v)
#define FIXED_MAKE_VECTORS(angles, forward, right, up)
var entity(vector mins, vector maxs,.entity tofield) findbox_tofield_OrFallback
#define Q3COMPAT_COMMON
Definition stats.qh:370
#define LABEL(id)
Definition compiler.qh:34
vector v_up
const float MOVE_NOMONSTERS
float trace_dphitcontents
entity trace_ent
const float SOLID_TRIGGER
float DPCONTENTS_SOLID
vector mins
entity chain
const float SOLID_NOT
vector v_right
float trace_networkentity
vector trace_endpos
float trace_startsolid
vector maxs
float MOVE_WORLDONLY
vector absmax
vector v_forward
vector origin
float trace_fraction
vector absmin
const float SOLID_BSP
float PARTICLES_DRAWASTRAIL
#define spawn
v y
Definition ent_cs.qc:146
v z
Definition ent_cs.qc:146
v x
Definition ent_cs.qc:146
#define IL_EACH(this, cond, body)
#define FOREACH_LIST(list, next, cond, body)
Definition iter.qh:21
#define FOREACH_ENTITY_RADIUS(org, dist, cond, body)
Definition iter.qh:160
#define ACCUMULATE
Definition _all.inc:31
#define WarpZoneLib_NearestPointOnBox(mi, ma, org)
Definition common.qc:565
void WarpZone_RefSys_AddInverseTransform(entity me, vector t, vector s)
Definition common.qc:763
void WarpZone_SetUp(entity e, vector my_org, vector my_ang, vector other_org, vector other_ang)
Definition common.qc:56
entity WarpZone_SearchInRadius(vector org, float rad, float nomonsters, WarpZone_FindRadius_cond_callback_t cb)
Modified findradius aware of warpzones, that only includes entities that meet the "cb" criteria.
Definition common.qc:684
vector WarpZone_Camera_camera_transform(entity this, vector org, vector ang)
Definition common.qc:76
entity WarpZone_findradius_next
Definition common.qc:608
void WarpZone_TraceToss_ThroughZone(entity e, entity forent, entity zone, WarpZone_trace_callback_t cb)
Traces tossing e, shifting & transforming each time it goes through a warpzone.
Definition common.qc:338
void WarpZone_RefSys_Clear(entity me)
Definition common.qc:749
vector WarpZone_RefSys_TransformVelocity(entity from, entity to, vector vel)
Transform velocity vel in from's reference into to's reference.
Definition common.qc:800
entity WarpZone_Find(vector mi, vector ma)
Definition common.qc:156
float WarpZoneLib_BoxTouchesBrush(vector mi, vector ma, entity e, entity ig)
Definition common.qc:124
vector WarpZone_UnTransformVAngles(entity wz, vector ang)
Transforms v_angle ang backwards through warpzone wz, as the inverse of WarpZone_TransformVAngles.
Definition common.qc:545
float WarpZoneLib_BoxTouchesBrush_Recurse(vector mi, vector ma, entity e, entity ig)
Definition common.qc:96
const int WarpZone_FindRadius_Hit_GOOD
Definition common.qc:569
bool WarpZoneLib_ExactTrigger_Touch(entity this, entity toucher, bool touchfunc)
Definition common.qc:849
void WarpZone_Accumulator_Clear(entity acc)
Definition common.qc:11
void WarpZone_Trace_InitTransform()
Definition common.qc:176
void WarpZone_Camera_SetUp(entity e, vector my_org, vector my_ang)
Definition common.qc:89
void WarpZone_Accumulator_AddTransform(entity acc, vector t, vector s)
Definition common.qc:16
#define WarpZone_Trace_AddTransform(wz)
Definition common.qc:182
#define WarpZone_Accumulator_Add(acc, wz)
Definition common.qc:23
vector WarpZone_refsys_incremental_transform
Definition common.qc:771
vector WarpZone_UnTransformOrigin(entity wz, vector org)
Transforms origin org backwards through warpzone wz, as the inverse of WarpZone_TransformOrigin.
Definition common.qc:530
void WarpZone_TraceBox_ThroughZone(vector org, vector mi, vector ma, vector end, float nomonsters, entity forent, entity zone, WarpZone_trace_callback_t cb)
Traces a box from org to end, shifting & transforming each time it goes through a warpzone.
Definition common.qc:187
vector WarpZone_TransformVAngles(entity wz, vector ang)
Transforms v_angle ang across warpzone wz.
Definition common.qc:509
const int WarpZone_FindRadius_Hit_BAD
Definition common.qc:570
vector WarpZone_TransformOrigin(entity wz, vector org)
Transforms origin org across warpzone wz.
Definition common.qc:493
void WarpZone_TrailParticles_WithMultiplier(entity own, float eff, vector org, vector end, float f, int boxflags)
Definition common.qc:472
void WarpZone_RefSys_CheckCreate(entity me)
Definition common.qc:741
ACCUMULATE void ONREMOVE(entity this)
Definition common.qc:735
void WarpZone_RefSys_BeginAddingIncrementally(entity me, entity ref)
Definition common.qc:783
float WarpZone_TrailParticles_trace_callback_flags
Definition common.qc:466
void WarpZone_TrailParticles(entity own, float eff, vector org, vector end)
Definition common.qc:450
float WarpZone_TargetPlaneDist(entity wz, vector p)
Definition common.qc:487
void WarpZone_MakeAllOther()
Definition common.qc:170
entity WarpZone_TrailParticles_trace_callback_own
Definition common.qc:443
entity WarpZone_refsys
Definition common.qc:731
void WarpZone_RefSys_AddIncrementally(entity me, entity ref)
Definition common.qc:772
entity WarpZone_RefSys_SpawnSameRefSys(entity me)
Spawns an entity in the same warpzone reference as me, and sets up its reference.
Definition common.qc:842
float WarpZone_PlaneDist(entity wz, vector p)
Definition common.qc:482
vector WarpZone_UnTransformAngles(entity wz, vector ang)
Transforms angle ang backwards through warpzone wz, as the inverse of WarpZone_TransformAngles.
Definition common.qc:540
void _WarpZone_FindRadius_Recurse(vector org, float rad, vector org0, vector transform, vector shift)
Definition common.qc:609
vector WarpZone_refsys_incremental_shift
Definition common.qc:770
void WarpZone_RefSys_AddTransform(entity me, vector t, vector s)
Definition common.qc:756
void WarpZone_MakeAllSolid()
Definition common.qc:164
entity _WarpZone_FindRadius_badents_first
Definition common.qc:605
vector WarpZone_camera_transform(entity this, vector org, vector ang)
Definition common.qc:35
void WarpZone_TrailParticles_WithMultiplier_trace_callback(vector from, vector endpos, vector to)
Definition common.qc:467
vector WarpZone_TransformAngles(entity wz, vector ang)
Transforms angle v across warpzone wz.
Definition common.qc:504
vector WarpZone_RefSys_TransformOrigin(entity from, entity to, vector org)
Transform origin org in from's reference into to's reference.
Definition common.qc:791
float WarpZone_TrailParticles_trace_callback_f
Definition common.qc:465
void WarpZone_RefSys_Copy(entity me, entity from)
Copies the warpzone reference of from onto me.
Definition common.qc:828
int WarpZone_findradius_hit
Definition common.qc:567
vector WarpZone_UnTransformVelocity(entity wz, vector vel)
Transforms angle vel backwards through warpzone wz, as the inverse of WarpZone_TransformVelocity.
Definition common.qc:535
vector WarpZone_TransformVelocity(entity wz, vector vel)
Transforms velocity v across warpzone wz.
Definition common.qc:499
void WarpZone_Accumulator_AddInverseTransform(entity acc, vector t, vector s)
Definition common.qc:25
bool WarpZoneLib_BadEntity(entity e, WarpZone_FindRadius_cond_callback_t cb)
Blacklist of entities that WarpZone_FindRadius doesn't care about.
Definition common.qc:572
entity _WarpZone_FindRadius_goodents_first
Definition common.qc:604
void WarpZone_TrailParticles_trace_callback(vector from, vector endpos, vector to)
Definition common.qc:445
var WarpZone_FindRadius_cond_callback_t _WarpZone_FindRadius_cond_cb
Definition common.qc:607
#define CHOOSE_AXIS(axis)
void WarpZoneLib_MoveOutOfSolid_Expand(entity e, vector by)
Definition common.qc:868
float _WarpZone_FindRadius_nomonsters
Definition common.qc:606
float WarpZone_TrailParticles_trace_callback_eff
Definition common.qc:444
vector WarpZone_RefSys_TransformVAngles(entity from, entity to, vector ang)
Transform v_angle ang in from's reference into to's reference.
Definition common.qc:818
const int WarpZone_FindRadius_Hit_UNSEEN
Definition common.qc:568
vector WarpZone_RefSys_TransformAngles(entity from, entity to, vector ang)
Transform angle ang in from's reference into to's reference.
Definition common.qc:809
int WarpZoneLib_MoveOutOfSolid(entity e)
Definition common.qc:879
entity WarpZone_trace_firstzone
First warpzone hit by a trace (can differ from the requested zone in case of _ThroughZone,...
Definition common.qh:41
#define BITSET_ASSIGN(a, b)
Definition common.qh:122
float warpzone_fadestart
Definition common.qh:24
#define WarpZone_TraceLine_ThroughZone(org, end, nomonsters, forent, zone, cb)
Definition common.qh:47
vector warpzone_targetorigin
Definition common.qh:21
void(vector start, vector hit, vector end) WarpZone_trace_callback_t
Definition common.qh:37
float warpzone_fadeend
Definition common.qh:25
#define BITCLR_ASSIGN(a, b)
Definition common.qh:119
entity WarpZone_trace_lastzone
First warpzone hit by a trace (can differ from the requested zone in case of _ThroughZone,...
Definition common.qh:42
WarpZone_trace_callback_t te_csqc_trace_callback
Definition common.qh:38
vector warpzone_origin
Definition common.qh:18
vector WarpZone_tracetoss_velocity
Ending velocity of a tracetoss (post-transform).
Definition common.qh:43
entity WarpZone_trace_transform
Transform accumulator during a trace.
Definition common.qh:40
#define MOVE_NOTHING
Definition common.qh:35
IntrusiveList g_warpzones
Definition common.qh:6
float warpzone_warpzones_exist
Definition common.qh:12
vector warpzone_angles
Definition common.qh:19
float WarpZone_tracetoss_time
Duration of toss (approximate).
Definition common.qh:44
bool(entity e) WarpZone_FindRadius_cond_callback_t
Definition common.qh:67
var void te_csqc_trace_callback_func(vector start, vector hit)
entity WarpZone_trace_forent
Temp, callback is allowed to change it.
Definition common.qh:36
#define LOG_TRACE(...)
Definition log.qh:74
float vlen(vector v)
float sqrt(float f)
vector normalize(vector v)
float fabs(float f)
float max(float f,...)
#define PHYS_GRAVITY(s)
Definition movetypes.qh:54
#define is_pure(e)
Definition oo.qh:16
#define new_pure(class)
purely logical entities (not linked to the area grid)
Definition oo.qh:66
#define NULL
Definition post.qh:14
#define world
Definition post.qh:15
#define makevectors
Definition post.qh:21
#define setcamera_transform(e, f)
Definition self.qh:97
vector
Definition self.qh:96
vector org
Definition self.qh:96
entity entity toucher
Definition self.qh:76
vector vector ang
Definition self.qh:96
#define startsWith(haystack, needle)
Definition string.qh:234
if(frag_attacker.flagcarried)
Definition sv_ctf.qc:2319
entity enemy
Definition sv_ctf.qh:152
#define vlen2(v)
Definition vector.qh:4
const vector eY
Definition vector.qh:44
#define vdist(v, cmp, f)
Vector distance comparison, avoids sqrt().
Definition vector.qh:8
const vector eZ
Definition vector.qh:45
ERASEABLE vector NearestPointOnBoundingBox(vector mi, vector ma, vector org)
Definition vector.qh:200
ERASEABLE float boxesoverlap(vector m1, vector m2, vector m3, vector m4)
Requires that m2>m1 in all coordinates, and that m4>m3.
Definition vector.qh:72
const vector eX
Definition vector.qh:43
#define vec3(_x, _y, _z)
Definition vector.qh:100