1 void WarpZone_SetUp(entity e, vector my_org, vector my_ang, vector other_org, vector other_ang)
3 e.warpzone_transform = AnglesTransform_Divide(other_ang, AnglesTransform_TurnDirectionFR(my_ang));
4 e.warpzone_shift = AnglesTransform_PrePostShift_GetPostShift(my_org, e.warpzone_transform, other_org);
5 e.warpzone_origin = my_org;
6 e.warpzone_targetorigin = other_org;
7 e.warpzone_angles = my_ang;
8 e.warpzone_targetangles = other_ang;
9 fixedmakevectors(my_ang); e.warpzone_forward = v_forward;
10 fixedmakevectors(other_ang); e.warpzone_targetforward = v_forward;
15 vector WarpZoneLib_BoxTouchesBrush_mins;
16 vector WarpZoneLib_BoxTouchesBrush_maxs;
17 entity WarpZoneLib_BoxTouchesBrush_ent;
18 entity WarpZoneLib_BoxTouchesBrush_ignore;
19 float WarpZoneLib_BoxTouchesBrush_Recurse()
25 tracebox('0 0 0', WarpZoneLib_BoxTouchesBrush_mins, WarpZoneLib_BoxTouchesBrush_maxs, '0 0 0', MOVE_NOMONSTERS, WarpZoneLib_BoxTouchesBrush_ignore);
27 if (trace_networkentity)
29 dprint("hit a network ent, cannot continue WarpZoneLib_BoxTouchesBrush\n");
30 // we cannot continue, as a player blocks us...
37 if (trace_ent == WarpZoneLib_BoxTouchesBrush_ent)
43 f = WarpZoneLib_BoxTouchesBrush_Recurse();
49 float WarpZoneLib_BoxTouchesBrush(vector mi, vector ma, entity e, entity ig)
58 WarpZoneLib_BoxTouchesBrush_mins = mi;
59 WarpZoneLib_BoxTouchesBrush_maxs = ma;
60 WarpZoneLib_BoxTouchesBrush_ent = e;
61 WarpZoneLib_BoxTouchesBrush_ignore = ig;
62 f = WarpZoneLib_BoxTouchesBrush_Recurse();
68 entity WarpZone_Find(vector mi, vector ma)
70 // if we are near any warpzone planes - MOVE AWAY (work around nearclip)
72 for(e = world; (e = find(e, classname, "trigger_warpzone")); )
73 if(WarpZoneLib_BoxTouchesBrush(mi, ma, e, world))
78 void WarpZone_MakeAllSolid()
81 for(e = world; (e = find(e, classname, "trigger_warpzone")); )
85 void WarpZone_MakeAllOther()
88 for(e = world; (e = find(e, classname, "trigger_warpzone")); )
89 e.solid = SOLID_TRIGGER;
92 void WarpZone_TraceBox(vector org, vector mi, vector ma, vector end, float nomonsters, entity forent)
101 // if starting in warpzone, first transform
102 wz = WarpZone_Find(org + mi, org + ma);
105 org = WarpZone_TransformOrigin(wz, trace_endpos);
106 end = WarpZone_TransformOrigin(wz, end);
107 WarpZone_trace_velocity = WarpZone_TransformVelocity(wz, WarpZone_trace_velocity);
108 WarpZone_trace_angles = WarpZone_TransformAngles(wz, WarpZone_trace_angles);
109 WarpZone_trace_v_angle = WarpZone_TransformVAngles(wz, WarpZone_trace_v_angle);
111 WarpZone_MakeAllSolid();
118 tracebox(org, mi, ma, end, nomonsters, forent);
119 if(WarpZone_trace_callback)
120 WarpZone_trace_callback(org, trace_endpos, end);
122 sol = trace_startsolid;
123 if(trace_fraction >= 1)
125 frac = trace_fraction = frac + (1 - frac) * trace_fraction;
126 if(trace_ent.classname != "trigger_warpzone")
130 dprint("I transformed into the same zone again, wtf, aborting the trace\n");
134 // we hit a warpzone... so, let's perform the trace after the warp again
135 org = WarpZone_TransformOrigin(wz, trace_endpos);
136 end = WarpZone_TransformOrigin(wz, end);
137 WarpZone_trace_velocity = WarpZone_TransformVelocity(wz, WarpZone_trace_velocity);
138 WarpZone_trace_angles = WarpZone_TransformAngles(wz, WarpZone_trace_angles);
139 WarpZone_trace_v_angle = WarpZone_TransformVAngles(wz, WarpZone_trace_v_angle);
141 WarpZone_MakeAllOther();
142 trace_startsolid = sol;
143 WarpZone_trace_endpos = o0 + (e0 - o0) * trace_fraction;
149 void WarpZone_TraceBox_ThroughZone(vector org, vector mi, vector ma, vector end, float nomonsters, entity forent, entity zone)
158 // if starting in warpzone, first transform
159 wz = WarpZone_Find(org + mi, org + ma);
164 // we are in ANOTHER warpzone. This is bad. Make a zero length trace and return.
170 org = WarpZone_TransformOrigin(wz, trace_endpos);
171 end = WarpZone_TransformOrigin(wz, end);
172 WarpZone_trace_velocity = WarpZone_TransformVelocity(wz, WarpZone_trace_velocity);
173 WarpZone_trace_angles = WarpZone_TransformAngles(wz, WarpZone_trace_angles);
174 WarpZone_trace_v_angle = WarpZone_TransformVAngles(wz, WarpZone_trace_v_angle);
176 WarpZone_MakeAllSolid();
183 tracebox(org, mi, ma, end, nomonsters, forent);
184 if(WarpZone_trace_callback)
185 WarpZone_trace_callback(org, trace_endpos, end);
187 sol = trace_startsolid;
188 if(trace_fraction >= 1)
190 frac = trace_fraction = frac + (1 - frac) * trace_fraction;
191 if(trace_ent.classname != "trigger_warpzone")
193 if(trace_ent != zone)
197 dprint("I transformed into the same zone again, wtf, aborting the trace\n");
201 // we hit a warpzone... so, let's perform the trace after the warp again
202 org = WarpZone_TransformOrigin(wz, trace_endpos);
203 end = WarpZone_TransformOrigin(wz, end);
204 WarpZone_trace_velocity = WarpZone_TransformVelocity(wz, WarpZone_trace_velocity);
205 WarpZone_trace_angles = WarpZone_TransformAngles(wz, WarpZone_trace_angles);
206 WarpZone_trace_v_angle = WarpZone_TransformVAngles(wz, WarpZone_trace_v_angle);
208 WarpZone_MakeAllOther();
210 trace_startsolid = sol;
211 WarpZone_trace_endpos = o0 + (e0 - o0) * trace_fraction;
217 void WarpZone_TraceLine(vector org, vector end, float nomonsters, entity forent)
219 WarpZone_TraceBox(org, '0 0 0', '0 0 0', end, nomonsters, forent);
222 void WarpZone_TraceToss(entity e, entity forent)
225 vector vf, vr, vu, v0, o0;
230 // if starting in warpzone, first transform
231 wz = WarpZone_Find(e.origin + e.mins, e.origin + e.maxs);
234 setorigin(e, WarpZone_TransformOrigin(wz, e.origin));
235 e.velocity = WarpZone_TransformVelocity(wz, e.velocity);
237 WarpZone_MakeAllSolid();
238 g = cvar("sv_gravity") * e.gravity;
239 WarpZone_tracetoss_time = 0;
244 tracetoss(e, forent);
245 if(WarpZone_trace_callback)
246 WarpZone_trace_callback(e.origin, trace_endpos, trace_endpos);
247 e.origin = trace_endpos;
248 dt = vlen(e.origin - o0) / vlen(e.velocity);
249 WarpZone_tracetoss_time += dt;
250 e.velocity_z -= WarpZone_tracetoss_time * g;
251 if(trace_fraction >= 1)
253 if(trace_ent.classname != "trigger_warpzone")
257 dprint("I transformed into the same zone again, wtf, aborting the trace\n");
261 // we hit a warpzone... so, let's perform the trace after the warp again
262 e.origin = WarpZone_TransformOrigin(wz, e.origin);
263 e.velocity = WarpZone_TransformVelocity(wz, e.velocity);
265 WarpZone_MakeAllOther();
269 WarpZone_tracetoss_velocity = e.velocity;
272 WarpZone_trace_endpos = e.origin + e.velocity * WarpZone_tracetoss_time;
273 WarpZone_trace_endpos_z -= 0.5 * g * WarpZone_tracetoss_time * WarpZone_tracetoss_time;
276 void WarpZone_TrailParticles(entity own, float eff, vector org, vector end)
283 WarpZone_MakeAllSolid();
287 traceline(org, end, MOVE_NOMONSTERS, world);
288 //print(vtos(org), " to ", vtos(trace_endpos), "\n");
289 trailparticles(own, eff, org, trace_endpos);
290 if(trace_fraction >= 1)
292 if(trace_ent.classname != "trigger_warpzone")
294 // we hit a warpzone... so, let's perform the trace after the warp again
295 org = WarpZone_TransformOrigin(trace_ent, trace_endpos);
296 end = WarpZone_TransformOrigin(trace_ent, end);
299 dprint("I transformed into the same zone again, wtf, aborting the trace\n");
304 WarpZone_MakeAllOther();
310 float WarpZone_PlaneDist(entity wz, vector v)
312 return (v - wz.warpzone_origin) * wz.warpzone_forward;
315 float WarpZone_TargetPlaneDist(entity wz, vector v)
317 return (v - wz.warpzone_targetorigin) * wz.warpzone_targetforward;
320 vector WarpZone_TransformOrigin(entity wz, vector v)
322 return wz.warpzone_shift + AnglesTransform_Apply(wz.warpzone_transform, v);
325 vector WarpZone_TransformVelocity(entity wz, vector v)
327 return AnglesTransform_Apply(wz.warpzone_transform, v);
330 vector WarpZone_TransformAngles(entity wz, vector v)
332 return AnglesTransform_ApplyToAngles(wz.warpzone_transform, v);
335 vector WarpZone_TransformVAngles(entity wz, vector ang)
342 ang = AnglesTransform_ApplyToVAngles(wz.warpzone_transform, ang);
343 ang = AnglesTransform_Normalize(ang, TRUE);
344 ang = AnglesTransform_CancelRoll(ang);
350 vector WarpZone_UnTransformOrigin(entity wz, vector v)
352 return AnglesTransform_Apply(AnglesTransform_Invert(wz.warpzone_transform), v - wz.warpzone_shift);
355 vector WarpZone_UnTransformVelocity(entity wz, vector v)
357 return AnglesTransform_Apply(AnglesTransform_Invert(wz.warpzone_transform), v);
360 vector WarpZone_UnTransformAngles(entity wz, vector v)
362 return AnglesTransform_ApplyToAngles(AnglesTransform_Invert(wz.warpzone_transform), v);
365 vector WarpZone_UnTransformVAngles(entity wz, vector ang)
372 ang = AnglesTransform_ApplyToVAngles(AnglesTransform_Invert(wz.warpzone_transform), ang);
373 ang = AnglesTransform_Normalize(ang, TRUE);
374 ang = AnglesTransform_CancelRoll(ang);
380 vector WarpZoneLib_NearestPointOnBox(vector mi, vector ma, vector org)
383 nearest_x = bound(mi_x, org_x, ma_x);
384 nearest_y = bound(mi_y, org_y, ma_y);
385 nearest_z = bound(mi_z, org_z, ma_z);
389 .float WarpZone_findradius_hit;
390 .entity WarpZone_findradius_next;
391 void WarpZone_FindRadius_Recurse(vector org, float rad, vector org0, vector transform, vector shift, float needlineofsight)
392 // blast origin of current search original blast origin how to untransform (victim to blast system)
396 vector shift_new, transform_new;
397 vector shift_second, transform_second;
403 e0 = findradius(org, rad);
406 for(e = e0; e; e = e.chain)
408 p = WarpZoneLib_NearestPointOnBox(e.origin + e.mins, e.origin + e.maxs, org0);
411 traceline(org, p, MOVE_NOMONSTERS, e);
412 if(trace_fraction < 1)
415 if(!e.WarpZone_findradius_hit || vlen(e.WarpZone_findradius_dist) > vlen(org0 - p))
417 e.WarpZone_findradius_nearest = p;
418 e.WarpZone_findradius_dist = org0 - p;
419 e.WarpZone_findradius_findorigin = org;
420 e.WarpZone_findradius_findradius = rad;
421 if(e.classname == "trigger_warpzone")
423 e.WarpZone_findradius_next = wz;
426 e.WarpZone_findradius_hit = 1;
427 e.enemy.WarpZone_findradius_dist = '0 0 0'; // we don't want to go through this zone ever again
428 e.enemy.WarpZone_findradius_hit = 1;
432 e.warpzone_transform = transform;
433 e.warpzone_shift = shift;
435 e.WarpZone_findradius_hit = 1;
439 for(e = wz; e; e = e.WarpZone_findradius_next)
441 org0_new = WarpZone_TransformOrigin(e, org);
442 traceline(e.warpzone_targetorigin, org0_new, MOVE_NOMONSTERS, e);
443 org_new = trace_endpos;
445 transform_second = AnglesTransform_Invert(e.warpzone_transform);
446 shift_second = AnglesTransform_PrePostShift_GetPostShift(e.warpzone_shift, transform_second, '0 0 0'); // invert the shift
447 transform_new = AnglesTransform_Multiply(transform, transform_second);
448 shift_new = AnglesTransform_Multiply_GetPostShift(transform, shift, transform_second, shift_second);
449 WarpZone_FindRadius_Recurse(
451 bound(0, rad - vlen(org_new - org0_new), rad - 8),
453 transform_new, shift_new,
455 e.WarpZone_findradius_hit = 0;
456 e.enemy.WarpZone_findradius_hit = 0;
459 entity WarpZone_FindRadius(vector org, float rad, float needlineofsight)
462 WarpZone_FindRadius_Recurse(org, rad, org, '0 0 0', '0 0 0', needlineofsight);
463 e0 = findchainfloat(WarpZone_findradius_hit, 1);
464 for(e = e0; e; e = e.chain)
465 e.WarpZone_findradius_hit = 0;
469 void WarpZone_Accumulator_Clear(entity acc)
471 acc.warpzone_transform = '0 0 0';
472 acc.warpzone_shift = '0 0 0';
474 void WarpZone_Accumulator_AddTransform(entity acc, vector t, vector s)
477 tr = AnglesTransform_Multiply(t, acc.warpzone_transform);
478 st = AnglesTransform_Multiply_GetPostShift(t, s, acc.warpzone_transform, acc.warpzone_shift);
479 acc.warpzone_transform = tr;
480 acc.warpzone_shift = st;
482 void WarpZone_Accumulator_Add(entity acc, entity wz)
485 t = AnglesTransform_Multiply(wz.warpzone_transform, acc.warpzone_transform);
486 st = AnglesTransform_Multiply_GetPostShift(wz.warpzone_transform, wz.warpzone_shift, acc.warpzone_transform, acc.warpzone_shift);
487 acc.warpzone_transform = t;
488 acc.warpzone_shift = st;
491 .entity WarpZone_refsys;
492 void WarpZone_RefSys_GC()
494 // garbage collect unused reference systems
495 self.nextthink = time + 1;
496 if(self.owner.WarpZone_refsys != self)
499 void WarpZone_RefSys_Add(entity me, entity wz)
501 if(me.WarpZone_refsys.owner != me)
503 me.WarpZone_refsys = spawn();
504 me.WarpZone_refsys.classname = "warpzone_refsys";
505 me.WarpZone_refsys.owner = me;
506 me.WarpZone_refsys.think = WarpZone_RefSys_GC;
507 me.WarpZone_refsys.nextthink = time + 1;
508 WarpZone_Accumulator_Clear(me.WarpZone_refsys);
511 WarpZone_Accumulator_Add(me.WarpZone_refsys, wz);
513 .vector WarpZone_refsys_incremental_shift;
514 .vector WarpZone_refsys_incremental_transform;
515 void WarpZone_RefSys_AddIncrementally(entity me, entity ref)
518 if(me.WarpZone_refsys_incremental_transform == ref.WarpZone_refsys.warpzone_transform)
519 if(me.WarpZone_refsys_incremental_shift == ref.WarpZone_refsys.warpzone_shift)
521 if(me.WarpZone_refsys.owner != me)
523 me.WarpZone_refsys = spawn();
524 me.WarpZone_refsys.classname = "warpzone_refsys";
525 me.WarpZone_refsys.owner = me;
526 me.WarpZone_refsys.think = WarpZone_RefSys_GC;
527 me.WarpZone_refsys.nextthink = time + 1;
528 WarpZone_Accumulator_Clear(me.WarpZone_refsys);
530 t = AnglesTransform_Invert(me.WarpZone_refsys_incremental_transform);
531 s = AnglesTransform_PrePostShift_GetPostShift(me.WarpZone_refsys_incremental_shift, t, '0 0 0');
532 WarpZone_Accumulator_AddTransform(me.WarpZone_refsys, t, s);
533 WarpZone_Accumulator_Add(me.WarpZone_refsys, ref);
534 me.WarpZone_refsys_incremental_shift = ref.WarpZone_refsys.warpzone_shift;
535 me.WarpZone_refsys_incremental_transform = ref.WarpZone_refsys.warpzone_transform;
537 void WarpZone_RefSys_BeginAddingIncrementally(entity me, entity ref)
539 me.WarpZone_refsys_incremental_shift = ref.WarpZone_refsys.warpzone_shift;
540 me.WarpZone_refsys_incremental_transform = ref.WarpZone_refsys.warpzone_transform;
542 vector WarpZone_RefSys_TransformOrigin(entity from, entity to, vector org)
544 if(from.WarpZone_refsys)
545 org = WarpZone_UnTransformOrigin(from.WarpZone_refsys, org);
546 if(to.WarpZone_refsys)
547 org = WarpZone_TransformOrigin(to.WarpZone_refsys, org);
550 vector WarpZone_RefSys_TransformVelocity(entity from, entity to, vector vel)
552 if(from.WarpZone_refsys)
553 vel = WarpZone_UnTransformVelocity(from.WarpZone_refsys, vel);
554 if(to.WarpZone_refsys)
555 vel = WarpZone_TransformVelocity(to.WarpZone_refsys, vel);
558 vector WarpZone_RefSys_TransformAngles(entity from, entity to, vector ang)
560 if(from.WarpZone_refsys)
561 ang = WarpZone_UnTransformAngles(from.WarpZone_refsys, ang);
562 if(to.WarpZone_refsys)
563 ang = WarpZone_TransformAngles(to.WarpZone_refsys, ang);
566 vector WarpZone_RefSys_TransformVAngles(entity from, entity to, vector ang)
568 if(from.WarpZone_refsys)
569 ang = WarpZone_UnTransformVAngles(from.WarpZone_refsys, ang);
570 if(to.WarpZone_refsys)
571 ang = WarpZone_TransformVAngles(to.WarpZone_refsys, ang);
574 entity WarpZone_RefSys_SpawnSameRefSys(entity me)
578 if(me.WarpZone_refsys)
580 e.WarpZone_refsys = spawn();
581 e.WarpZone_refsys.classname = "warpzone_refsys";
582 e.WarpZone_refsys.owner = e;
583 e.WarpZone_refsys.think = WarpZone_RefSys_GC;
584 e.WarpZone_refsys.nextthink = time + 1;
585 e.WarpZone_refsys.warpzone_shift = me.WarpZone_refsys.warpzone_shift;
586 e.WarpZone_refsys.warpzone_transform = me.WarpZone_refsys.warpzone_transform;