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 e.warpzone_shift = AnglesTransform_PrePostShift_GetPostShift(my_org, e.warpzone_transform, other_org);
60 e.warpzone_origin = my_org;
61 e.warpzone_targetorigin = other_org;
62 e.warpzone_angles = my_ang;
63 e.warpzone_targetangles = other_ang;
64 vector forward, right, up;
65 FIXED_MAKE_VECTORS(my_ang, forward, right, up);
66 e.warpzone_forward = forward;
67 FIXED_MAKE_VECTORS(other_ang, forward, right, up);
68 e.warpzone_targetforward = forward;
70}
71
73{
74 // a fixed camera view
75 if (this.warpzone_fadestart
76 && vdist(org - this.origin - 0.5 * (this.mins + this.maxs), >, this.warpzone_fadeend + 400))
77 return org;
78 // don't transform if zone faded out (plus 400qu safety margin for typical speeds and latencies)
79 // unneeded on client, on server this helps a lot
82 return this.warpzone_origin;
83}
84
85void 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
86{
87 e.warpzone_origin = my_org;
88 e.warpzone_angles = my_ang;
90}
91
93{
94 tracebox('0 0 0', mi, ma, '0 0 0', MOVE_NOMONSTERS, ig);
95#ifdef CSQC
97 {
98 LOG_TRACE("hit a network ent, cannot continue WarpZoneLib_BoxTouchesBrush");
99 // we cannot continue, as a player blocks us...
100 // so, abort
101 return 0;
102 }
103#endif
104 if (!trace_ent)
105 return 0;
106 if (trace_ent == e)
107 return 1;
108
109 entity se = trace_ent;
110 float s = se.solid;
111 se.solid = SOLID_NOT;
112 setorigin(se, se.origin); // unlink
113 float f = WarpZoneLib_BoxTouchesBrush_Recurse(mi, ma, e, ig);
114 se.solid = s;
115 setorigin(se, se.origin); // relink
116
117 return f;
118}
119
121{
122 // bones_was_here: TODO: when findbox_OrFallback() is available, use it to
123 // optimise this into a single non-recursive function that only calls tracebox once
124
125 if (!e.modelindex || e.warpzone_isboxy)
126 return 1;
127
128 // work around trigger_hurt on geit3ctf1 not being detected by tracebox
129 // bones_was_here: FIXME: WHY do these triggers only have supercontents == 128 ?!
130 if (Q3COMPAT_COMMON && ig != world)
131 ig.dphitcontentsmask |= 128;
132
133 float s = e.solid;
134 if (e.solid != SOLID_BSP)
135 {
136 e.solid = SOLID_BSP;
137 setorigin(e, e.origin); // update linking
138 }
139 float f = WarpZoneLib_BoxTouchesBrush_Recurse(mi, ma, e, ig);
140 if (e.solid != s) // if we needed to change .solid temporarily
141 {
142 e.solid = s; // restore it
143 setorigin(e, e.origin); // update linking
144 }
145
146 if (Q3COMPAT_COMMON && ig != world)
147 ig.dphitcontentsmask &= ~128;
148
149 return f;
150}
151
153{
154 // if we are near any warpzone planes - MOVE AWAY (work around nearclip)
156 IL_EACH(g_warpzones, WarpZoneLib_BoxTouchesBrush(mi, ma, it, NULL), return it);
157 return NULL;
158}
159
161{
163 IL_EACH(g_warpzones, true, it.solid = SOLID_BSP);
164}
165
167{
169 IL_EACH(g_warpzones, true, it.solid = SOLID_TRIGGER);
170}
171
178#define WarpZone_Trace_AddTransform(wz) \
179 WarpZone_Accumulator_Add(WarpZone_trace_transform, wz)
180
184{
185 WarpZone_trace_forent = forent;
189
190 bool nearby_warpzones = false;
191 // use tracebox if no warpzone is touching the box the entity would be traced through
193 {
194 vector boxmin = mi;
195 vector boxmax = ma;
196 #define CHOOSE_AXIS(axis) \
197 if (org.axis < end.axis) { boxmin.axis += org.axis; boxmax.axis += end.axis; } \
198 else { boxmin.axis += end.axis; boxmax.axis += org.axis; }
199 CHOOSE_AXIS(x);
200 CHOOSE_AXIS(y);
201 CHOOSE_AXIS(z);
202 #undef CHOOSE_AXIS
203 /* Above is equivalent to the following, but more efficient
204 * boxmin += vec_to_min(org, end);
205 * boxmax += vec_to_max(org, end);
206 */
207 IL_EACH(g_warpzones, boxesoverlap(it.absmin, it.absmax, boxmin, boxmax),
208 {
209 nearby_warpzones = true;
210 break;
211 });
212 }
213 if (!nearby_warpzones)
214 {
215 if (nomonsters == MOVE_NOTHING)
216 {
217 trace_endpos = end;
218 trace_fraction = 1;
219 }
220 else
221 tracebox(org, mi, ma, end, nomonsters, WarpZone_trace_forent);
222
223 if (cb)
224 cb(org, trace_endpos, end);
225 return;
226 }
227
228 vector vf = v_forward;
229 vector vr = v_right;
230 vector vu = v_up;
231
232 float nomonsters_adjusted;
233 switch (nomonsters)
234 {
235 case MOVE_WORLDONLY:
236 case MOVE_NOTHING:
237 nomonsters_adjusted = MOVE_NOMONSTERS;
238 break;
239 default:
240 nomonsters_adjusted = nomonsters;
241 break;
242 }
243 bool contents_hack = (WarpZone_trace_forent.dphitcontentsmask && !(WarpZone_trace_forent.dphitcontentsmask & DPCONTENTS_SOLID));
244 if (contents_hack)
246
247 // if starting in warpzone, first transform
248 entity wz = WarpZone_Find(org + mi, org + ma);
249 float sol;
250 if (wz)
251 {
254 if (zone && wz != zone)
255 {
256 // we are in ANOTHER warpzone. This is bad. Make a zero length trace and return.
257 sol = 1;
258 trace_fraction = 0;
260 goto fail;
261 }
264 end = WarpZone_TransformOrigin(wz, end);
265 }
267 sol = -1;
268 float frac = 0;
269 float i = 16;
270 for (;;)
271 {
272 if (--i < 1)
273 {
274 LOG_TRACE("Too many warpzones in sequence, aborting trace.");
275 trace_ent = NULL;
276 break;
277 }
278 tracebox(org, mi, ma, end, nomonsters_adjusted, WarpZone_trace_forent);
279 if (cb)
280 cb(org, trace_endpos, end);
281 if (sol < 0)
282 sol = trace_startsolid;
283
284 frac = trace_fraction = frac + (1 - frac) * trace_fraction;
285 if (trace_fraction >= 1)
286 break;
287 if (trace_ent.classname != "trigger_warpzone")
288 {
289 if (nomonsters == MOVE_NOTHING
290 || (nomonsters == MOVE_WORLDONLY && trace_ent)
291 || (contents_hack && (trace_dphitcontents & WarpZone_trace_forent.dphitcontentsmask) == DPCONTENTS_SOLID))
292 {
293 // continue the trace, ignoring this hit (we only care for warpzones)
294 org = trace_endpos + normalize(end - org);
295 continue;
296 // we cannot do an inverted trace here, as we do care for further warpzones inside that "solid" to be found
297 // otherwise, players could block entrances that way
298 }
299 break;
300 }
301 /*if (trace_ent == wz)
302 {
303 // FIXME can this check be removed? Do we really need it?
304 LOG_TRACE("I transformed into the same zone again, wtf, aborting the trace");
305 trace_ent = NULL;
306 break;
307 }*/
308 wz = trace_ent;
312 if (zone && wz != zone)
313 break;
315 // we hit a warpzone... so, let's perform the trace after the warp again
317 end = WarpZone_TransformOrigin(wz, end);
318
319 // we got warped, so let's step back a bit
320 tracebox(org, mi, ma, org + normalize(org - end) * 32, nomonsters_adjusted, WarpZone_trace_forent);
322 }
324LABEL(fail)
325 if (contents_hack)
327 trace_startsolid = sol;
328 v_forward = vf;
329 v_right = vr;
330 v_up = vu;
331}
332
335{
336 vector o0 = e.origin;
337 vector v0 = e.velocity;
338 float dt, i, g = PHYS_GRAVITY(NULL) * e.gravity;
339
340 WarpZone_trace_forent = forent;
346 {
347 tracetoss(e, WarpZone_trace_forent);
348 if (cb)
349 cb(e.origin, trace_endpos, trace_endpos);
350 dt = sqrt(vlen2(e.origin - o0) / vlen2(e.velocity));
352 e.velocity.z -= dt * g;
353 WarpZone_tracetoss_velocity = e.velocity;
354 e.velocity = v0;
355 return;
356 }
357
358 vector vf = v_forward;
359 vector vr = v_right;
360 vector vu = v_up;
361
362 // if starting in warpzone, first transform
363 entity wz = WarpZone_Find(e.origin + e.mins, e.origin + e.maxs);
364 if (wz)
365 {
368 if (zone && wz != zone)
369 {
370 // we are in ANOTHER warpzone. This is bad. Make a zero length trace and return.
371
373 trace_endpos = o0;
374 goto fail;
375 }
377 vector org = WarpZone_TransformOrigin(wz, e.origin);
378 setorigin(e, org);
379 e.velocity = WarpZone_TransformVelocity(wz, e.velocity);
380 }
382 i = 16;
383 for (;;)
384 {
385 if (--i < 1)
386 {
387 LOG_TRACE("Too many warpzones in sequence, aborting trace.");
388 trace_ent = NULL;
389 break;
390 }
391 tracetoss(e, WarpZone_trace_forent);
392 if (cb)
393 cb(e.origin, trace_endpos, trace_endpos);
394 dt = sqrt(vlen2(trace_endpos - e.origin) / vlen2(e.velocity));
396 e.origin = trace_endpos;
397 e.velocity.z -= dt * g;
398 if (trace_fraction >= 1)
399 break;
400 if (trace_ent.classname != "trigger_warpzone")
401 break;
402 if (trace_ent == wz)
403 {
404 // FIXME can this check be removed? Do we really need it?
405 LOG_TRACE("I transformed into the same zone again, wtf, aborting the trace");
406 trace_ent = NULL;
407 break;
408 }
409 wz = trace_ent;
413 if (zone && wz != zone)
414 break;
416 // we hit a warpzone... so, let's perform the trace after the warp again
417 e.origin = WarpZone_TransformOrigin(wz, e.origin);
418 e.velocity = WarpZone_TransformVelocity(wz, e.velocity);
419
420 // we got warped, so let's step back a bit
421 e.velocity = -e.velocity;
422 tracetoss(e, WarpZone_trace_forent);
423 dt = sqrt(vlen2(trace_endpos - e.origin) / vlen2(e.velocity));
425 e.origin = trace_endpos;
426 e.velocity = -e.velocity;
427 }
429LABEL(fail)
430 WarpZone_tracetoss_velocity = e.velocity;
431 v_forward = vf;
432 v_right = vr;
433 v_up = vu;
434 // restore old entity data (caller just uses trace_endpos, WarpZone_tracetoss_velocity and the transform)
435 e.velocity = v0;
436 e.origin = o0;
437}
438
445
452
456{
457 te_csqc_trace_callback_func(start, hit);
458}
459
460#ifdef CSQC
467
476#endif
477
479{
480 return (p - wz.warpzone_origin) * wz.warpzone_forward;
481}
482
484{
485 return (p - wz.warpzone_targetorigin) * wz.warpzone_targetforward;
486}
487
490{
491 return wz.warpzone_shift + AnglesTransform_Apply(wz.warpzone_transform, org);
492}
493
496{
497 return AnglesTransform_Apply(wz.warpzone_transform, vel);
498}
499
501{
502 return AnglesTransform_ApplyToAngles(wz.warpzone_transform, ang);
503}
504
506{
507#ifdef KEEP_ROLL
508 float roll = ang.z;
509 ang.z = 0;
510#endif
511
512 ang = AnglesTransform_ApplyToVAngles(wz.warpzone_transform, ang);
513#ifdef KEEP_ROLL
516 ang.z = roll;
517#else
519#endif
520 return ang;
521}
522
527{
528 return AnglesTransform_Apply(AnglesTransform_Invert(wz.warpzone_transform), org - wz.warpzone_shift);
529}
530
532{
533 return AnglesTransform_Apply(AnglesTransform_Invert(wz.warpzone_transform), vel);
534}
535
540
542{
543#ifdef KEEP_ROLL
544 float roll = ang.z;
545 ang.z = 0;
546#endif
547
549#ifdef KEEP_ROLL
552 ang.z = roll;
553#else
555#endif
556 return ang;
557}
558
559// FIXME: the nearest bounding box point can be unreachable via trace,
560// despite there actually being line of sight if only the trace was adjusted slightly
561#define WarpZoneLib_NearestPointOnBox(mi, ma, org) NearestPointOnBoundingBox(mi, ma, org)
562
569{
570 if (e.WarpZone_findradius_hit != WarpZone_FindRadius_Hit_UNSEEN) // also account for caching
571 return (e.WarpZone_findradius_hit == WarpZone_FindRadius_Hit_BAD); // either BAD or GOOD
572 if (is_pure(e))
573 return true;
574
575 string s = e.classname;
576 switch (s)
577 {
578 case "warpzone_refsys": // ignore, especially: do not overwrite the refsys parameters
579 case "weaponentity":
580 case "exteriorweaponentity":
581 case "sprite_waypoint":
582 case "waypoint":
583 case "spawnfunc":
584 case "weaponchild":
585 case "chatbubbleentity":
586 case "buff_model":
587 //case "net_linked": // actually some real entities are linked without classname, fail
588 case "":
589 return true;
590 }
591 if (startsWith(s, "target_"))
592 return true;
593 if (startsWith(s, "info_"))
594 return true;
595
596 return (cb && !cb(e));
597}
598
599.entity enemy;
607 vector org,
608 float rad,
610 vector org0,
612 vector transform,
613 vector shift)
614{
615 if (rad <= 0)
616 return;
617 entity wz = NULL;
618 FOREACH_ENTITY_RADIUS(org, rad, it.WarpZone_findradius_hit != WarpZone_FindRadius_Hit_BAD, // exclude entities we already know are bad
619 {
620 bool is_warpzone = (it.classname == "trigger_warpzone");
621 if (!is_warpzone // warpzones are never bad entities
622 && WarpZoneLib_BadEntity(it, _WarpZone_FindRadius_cond_cb))
623 {
624 it.WarpZone_findradius_hit = WarpZone_FindRadius_Hit_BAD;
625 it.WarpZone_findradius_next = _WarpZone_FindRadius_badents_first;
626 // use .WarpZone_findradius_next so that .chain isn't changed on entities not included in the returned list_first
627 _WarpZone_FindRadius_badents_first = it;
628 continue;
629 }
630
631 vector p = WarpZoneLib_NearestPointOnBox(it.origin + it.mins, it.origin + it.maxs, org0);
632 if (it.WarpZone_findradius_hit == WarpZone_FindRadius_Hit_GOOD && vlen2(it.WarpZone_findradius_dist) <= vlen2(org0 - p))
633 continue;
635 {
636 traceline(org, p, _WarpZone_FindRadius_nomonsters, it);
637 if (trace_fraction < 1)
638 continue;
639 }
640
641 it.WarpZone_findradius_nearest = p;
642 it.WarpZone_findradius_dist = org0 - p;
643 //it.WarpZone_findradius_findorigin = org;
644 //it.WarpZone_findradius_findradius = rad;
645 if (is_warpzone)
646 {
647 it.WarpZone_findradius_next = wz;
648 wz = it;
649 it.WarpZone_findradius_hit = WarpZone_FindRadius_Hit_GOOD;
650 it.enemy.WarpZone_findradius_dist = '0 0 0'; // we don't want to go through this zone ever again
651 it.enemy.WarpZone_findradius_hit = WarpZone_FindRadius_Hit_GOOD;
652 }
653 else // entity we'll include in the list
654 {
655 it.warpzone_transform = transform;
656 it.warpzone_shift = shift;
657 if (it.WarpZone_findradius_hit != WarpZone_FindRadius_Hit_GOOD) // add to good ents chain if not already in it
658 {
659 it.chain = _WarpZone_FindRadius_goodents_first; // fine to use .chain since FOREACH_ENTITY_RADIUS doesn't use it
661 it.WarpZone_findradius_hit = WarpZone_FindRadius_Hit_GOOD;
662 }
663 }
664 });
665 for (entity e = wz; e; e = e.WarpZone_findradius_next)
666 {
667 vector org0_new = WarpZone_TransformOrigin(e, org);
668 traceline(e.warpzone_targetorigin, org0_new, MOVE_NOMONSTERS, e);
669 vector org_new = trace_endpos;
670
672 org_new,
673 rad - max(8, vlen(org_new - org0_new)),
674 org0_new,
675 AnglesTransform_Multiply(e.warpzone_transform, transform), // new transform
676 AnglesTransform_Multiply_GetPostShift(e.warpzone_transform, e.warpzone_shift, transform, shift)); // new shift
677 e.WarpZone_findradius_hit = e.enemy.WarpZone_findradius_hit = WarpZone_FindRadius_Hit_UNSEEN;
678 }
679}
681{
682 bool nearby_warpzones = false;
683 // use FOREACH_ENTITY_RADIUS if no warpzone is touching the box of side 2 * rad and center org
684 // which includes the sphere of radius rad and center org
686 {
687 vector boxmin = vec3(org.x - rad, org.y - rad, org.z - rad);
688 vector boxmax = vec3(org.x + rad, org.y + rad, org.z + rad);
689 IL_EACH(g_warpzones, boxesoverlap(it.absmin, it.absmax, boxmin, boxmax),
690 {
691 nearby_warpzones = true;
692 break;
693 });
694 }
695
697 if (nearby_warpzones)
698 {
702 _WarpZone_FindRadius_Recurse(org, rad, org, '0 0 0', '0 0 0');
703 FOREACH_LIST(_WarpZone_FindRadius_goodents, chain, true, it.WarpZone_findradius_hit = WarpZone_FindRadius_Hit_UNSEEN);
704 FOREACH_LIST(_WarpZone_FindRadius_badents, WarpZone_findradius_next, true, it.WarpZone_findradius_hit = WarpZone_FindRadius_Hit_UNSEEN);
705 }
706 else // cheaper than _WarpZone_FindRadius_Recurse
708 {
709 vector p = NearestPointOnBoundingBox(it.origin + it.mins, it.origin + it.maxs, org);
710 if (nomonsters != MOVE_NOTHING)
711 {
712 traceline(org, p, nomonsters, it);
713 if (trace_fraction < 1)
714 continue;
715 }
716
717 it.chain = _WarpZone_FindRadius_goodents_first; // fine to use .chain since FOREACH_ENTITY_RADIUS doesn't use it
719 it.WarpZone_findradius_nearest = p;
720 it.WarpZone_findradius_dist = org - p;
721 WarpZone_Accumulator_Clear(it); // reset .warpzone_transform and .warpzone_shift
722 });
723
725}
726
728// called when an entity is deleted with delete() / remove()
729// or when a player disconnects
731void ONREMOVE(entity this)
732{
733 // remove WarpZone_refsys object attached to 'this'
734 if (this.WarpZone_refsys && this.WarpZone_refsys.owner == this)
735 delete(this.WarpZone_refsys);
736}
738{
739 if (me.WarpZone_refsys.owner == me)
740 return;
741 me.WarpZone_refsys = new(warpzone_refsys);
742 me.WarpZone_refsys.owner = me;
743 WarpZone_Accumulator_Clear(me.WarpZone_refsys);
744}
746{
747 if (!me.WarpZone_refsys)
748 return;
749 delete(me.WarpZone_refsys);
750 me.WarpZone_refsys = NULL;
751}
753{
754 if (t == '0 0 0' && s == '0 0 0')
755 return;
757 WarpZone_Accumulator_AddTransform(me.WarpZone_refsys, t, s);
758}
760{
761 if (t == '0 0 0' && s == '0 0 0')
762 return;
764 WarpZone_Accumulator_AddInverseTransform(me.WarpZone_refsys, t, s);
765}
769{
770 //vector t, s;
771 if (me.WarpZone_refsys_incremental_transform == ref.WarpZone_refsys.warpzone_transform
772 && me.WarpZone_refsys_incremental_shift == ref.WarpZone_refsys.warpzone_shift)
773 return;
774 WarpZone_Accumulator_AddInverseTransform(me.WarpZone_refsys, me.WarpZone_refsys_incremental_transform, me.WarpZone_refsys_incremental_shift);
775 WarpZone_Accumulator_Add(me.WarpZone_refsys, ref.WarpZone_refsys);
776 me.WarpZone_refsys_incremental_shift = ref.WarpZone_refsys.warpzone_shift;
777 me.WarpZone_refsys_incremental_transform = ref.WarpZone_refsys.warpzone_transform;
778}
780{
781 me.WarpZone_refsys_incremental_shift = ref.WarpZone_refsys.warpzone_shift;
782 me.WarpZone_refsys_incremental_transform = ref.WarpZone_refsys.warpzone_transform;
783}
784
788{
789 if (from.WarpZone_refsys)
790 org = WarpZone_UnTransformOrigin(from.WarpZone_refsys, org);
791 if (to.WarpZone_refsys)
792 org = WarpZone_TransformOrigin(to.WarpZone_refsys, org);
793 return org;
794}
795
797{
798 if (from.WarpZone_refsys)
799 vel = WarpZone_UnTransformVelocity(from.WarpZone_refsys, vel);
800 if (to.WarpZone_refsys)
801 vel = WarpZone_TransformVelocity(to.WarpZone_refsys, vel);
802 return vel;
803}
804
806{
807 if (from.WarpZone_refsys)
808 ang = WarpZone_UnTransformAngles(from.WarpZone_refsys, ang);
809 if (to.WarpZone_refsys)
810 ang = WarpZone_TransformAngles(to.WarpZone_refsys, ang);
811 return ang;
812}
813
815{
816 if (from.WarpZone_refsys)
817 ang = WarpZone_UnTransformVAngles(from.WarpZone_refsys, ang);
818 if (to.WarpZone_refsys)
819 ang = WarpZone_TransformVAngles(to.WarpZone_refsys, ang);
820 return ang;
821}
822
825{
826 if (from.WarpZone_refsys)
827 {
829 me.WarpZone_refsys.warpzone_shift = from.WarpZone_refsys.warpzone_shift;
830 me.WarpZone_refsys.warpzone_transform = from.WarpZone_refsys.warpzone_transform;
831 }
832 else
834}
835
839{
840 entity e = spawn();
842 return e;
843}
844
846{
847 vector emin = toucher.absmin, emax = toucher.absmax;
848 if (!Q3COMPAT_COMMON)
849 {
850 // Xonotic and Nexuiz maps assume triggers will be activated by adjacent players
851 // prior to sv_legacy_bbox_expand 0 DP always did this for SVQC and never for CSQC
852 emin -= '1 1 1';
853 emax += '1 1 1';
854 }
855
856 // if called from a touch func, we can assume the boxes do overlap
857 if (!touchfunc && !boxesoverlap(emin, emax, this.absmin, this.absmax)) // quick
858 return false;
859
860 return WarpZoneLib_BoxTouchesBrush(emin, emax, this, toucher); // accurate
861}
862
863
865{
866 const float eps = 1/16; // 0.0625
867 tracebox(e.origin, e.mins - '1 1 1' * eps, e.maxs + '1 1 1' * eps, e.origin + by, MOVE_WORLDONLY, e);
869 return;
870 if (trace_fraction < 1)
871 // hit something, adjust origin in the other direction...
872 setorigin(e, e.origin - by * (1 - trace_fraction));
873}
874
876{
877 vector o = e.origin;
878 traceline(o, o, MOVE_WORLDONLY, e);
880 return 0; // too stuck, giving up
881
882 tracebox(o, e.mins, e.maxs, o, MOVE_WORLDONLY, e);
883 if (!trace_startsolid)
884 return -1; // wasn't stuck
885
886 vector m0 = e.mins;
887 vector m1 = e.maxs;
888 e.mins = '0 0 0';
889 e.maxs = '0 0 0';
890 WarpZoneLib_MoveOutOfSolid_Expand(e, eX * m0.x); e.mins.x = m0.x;
891 WarpZoneLib_MoveOutOfSolid_Expand(e, eX * m1.x); e.maxs.x = m1.x;
892 WarpZoneLib_MoveOutOfSolid_Expand(e, eY * m0.y); e.mins.y = m0.y;
893 WarpZoneLib_MoveOutOfSolid_Expand(e, eY * m1.y); e.maxs.y = m1.y;
894 WarpZoneLib_MoveOutOfSolid_Expand(e, eZ * m0.z); e.mins.z = m0.z;
895 WarpZoneLib_MoveOutOfSolid_Expand(e, eZ * m1.z); e.maxs.z = m1.z;
896 setorigin(e, e.origin);
897
898 tracebox(e.origin, e.mins, e.maxs, e.origin, MOVE_WORLDONLY, e);
900 {
901 setorigin(e, o);
902 return 0; // can't fix
903 }
904
905 return 1; // was stuck but is fixed now
906}
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:561
void WarpZone_RefSys_AddInverseTransform(entity me, vector t, vector s)
Definition common.qc:759
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:680
vector WarpZone_Camera_camera_transform(entity this, vector org, vector ang)
Definition common.qc:72
entity WarpZone_findradius_next
Definition common.qc:604
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:334
void WarpZone_RefSys_Clear(entity me)
Definition common.qc:745
vector WarpZone_RefSys_TransformVelocity(entity from, entity to, vector vel)
Transform velocity vel in from's reference into to's reference.
Definition common.qc:796
entity WarpZone_Find(vector mi, vector ma)
Definition common.qc:152
float WarpZoneLib_BoxTouchesBrush(vector mi, vector ma, entity e, entity ig)
Definition common.qc:120
vector WarpZone_UnTransformVAngles(entity wz, vector ang)
Transforms v_angle ang backwards through warpzone wz, as the inverse of WarpZone_TransformVAngles.
Definition common.qc:541
float WarpZoneLib_BoxTouchesBrush_Recurse(vector mi, vector ma, entity e, entity ig)
Definition common.qc:92
const int WarpZone_FindRadius_Hit_GOOD
Definition common.qc:565
bool WarpZoneLib_ExactTrigger_Touch(entity this, entity toucher, bool touchfunc)
Definition common.qc:845
void WarpZone_Accumulator_Clear(entity acc)
Definition common.qc:11
void WarpZone_Trace_InitTransform()
Definition common.qc:172
void WarpZone_Camera_SetUp(entity e, vector my_org, vector my_ang)
Definition common.qc:85
void WarpZone_Accumulator_AddTransform(entity acc, vector t, vector s)
Definition common.qc:16
#define WarpZone_Trace_AddTransform(wz)
Definition common.qc:178
#define WarpZone_Accumulator_Add(acc, wz)
Definition common.qc:23
vector WarpZone_refsys_incremental_transform
Definition common.qc:767
vector WarpZone_UnTransformOrigin(entity wz, vector org)
Transforms origin org backwards through warpzone wz, as the inverse of WarpZone_TransformOrigin.
Definition common.qc:526
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:183
vector WarpZone_TransformVAngles(entity wz, vector ang)
Transforms v_angle ang across warpzone wz.
Definition common.qc:505
const int WarpZone_FindRadius_Hit_BAD
Definition common.qc:566
vector WarpZone_TransformOrigin(entity wz, vector org)
Transforms origin org across warpzone wz.
Definition common.qc:489
void WarpZone_TrailParticles_WithMultiplier(entity own, float eff, vector org, vector end, float f, int boxflags)
Definition common.qc:468
void WarpZone_RefSys_CheckCreate(entity me)
Definition common.qc:737
ACCUMULATE void ONREMOVE(entity this)
Definition common.qc:731
void WarpZone_RefSys_BeginAddingIncrementally(entity me, entity ref)
Definition common.qc:779
float WarpZone_TrailParticles_trace_callback_flags
Definition common.qc:462
void WarpZone_TrailParticles(entity own, float eff, vector org, vector end)
Definition common.qc:446
float WarpZone_TargetPlaneDist(entity wz, vector p)
Definition common.qc:483
void WarpZone_MakeAllOther()
Definition common.qc:166
entity WarpZone_TrailParticles_trace_callback_own
Definition common.qc:439
entity WarpZone_refsys
Definition common.qc:727
void WarpZone_RefSys_AddIncrementally(entity me, entity ref)
Definition common.qc:768
entity WarpZone_RefSys_SpawnSameRefSys(entity me)
Spawns an entity in the same warpzone reference as me, and sets up its reference.
Definition common.qc:838
float WarpZone_PlaneDist(entity wz, vector p)
Definition common.qc:478
vector WarpZone_UnTransformAngles(entity wz, vector ang)
Transforms angle ang backwards through warpzone wz, as the inverse of WarpZone_TransformAngles.
Definition common.qc:536
void _WarpZone_FindRadius_Recurse(vector org, float rad, vector org0, vector transform, vector shift)
Definition common.qc:605
vector WarpZone_refsys_incremental_shift
Definition common.qc:766
void WarpZone_RefSys_AddTransform(entity me, vector t, vector s)
Definition common.qc:752
void WarpZone_MakeAllSolid()
Definition common.qc:160
entity _WarpZone_FindRadius_badents_first
Definition common.qc:601
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:463
vector WarpZone_TransformAngles(entity wz, vector ang)
Transforms angle v across warpzone wz.
Definition common.qc:500
vector WarpZone_RefSys_TransformOrigin(entity from, entity to, vector org)
Transform origin org in from's reference into to's reference.
Definition common.qc:787
float WarpZone_TrailParticles_trace_callback_f
Definition common.qc:461
void WarpZone_RefSys_Copy(entity me, entity from)
Copies the warpzone reference of from onto me.
Definition common.qc:824
int WarpZone_findradius_hit
Definition common.qc:563
vector WarpZone_UnTransformVelocity(entity wz, vector vel)
Transforms angle vel backwards through warpzone wz, as the inverse of WarpZone_TransformVelocity.
Definition common.qc:531
vector WarpZone_TransformVelocity(entity wz, vector vel)
Transforms velocity v across warpzone wz.
Definition common.qc:495
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:568
entity _WarpZone_FindRadius_goodents_first
Definition common.qc:600
void WarpZone_TrailParticles_trace_callback(vector from, vector endpos, vector to)
Definition common.qc:441
var WarpZone_FindRadius_cond_callback_t _WarpZone_FindRadius_cond_cb
Definition common.qc:603
#define CHOOSE_AXIS(axis)
void WarpZoneLib_MoveOutOfSolid_Expand(entity e, vector by)
Definition common.qc:864
float _WarpZone_FindRadius_nomonsters
Definition common.qc:602
float WarpZone_TrailParticles_trace_callback_eff
Definition common.qc:440
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:814
const int WarpZone_FindRadius_Hit_UNSEEN
Definition common.qc:564
vector WarpZone_RefSys_TransformAngles(entity from, entity to, vector ang)
Transform angle ang in from's reference into to's reference.
Definition common.qc:805
int WarpZoneLib_MoveOutOfSolid(entity e)
Definition common.qc:875
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 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