]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/warpzonelib/common.qc
handle traces correctly if starting inside a warpzone
[divverent/nexuiz.git] / data / qcsrc / warpzonelib / common.qc
1 void WarpZone_SetUp(entity e, vector my_org, vector my_ang, vector other_org, vector other_ang)
2 {
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;
11 }
12
13 .entity enemy;
14
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()
20 {
21         float s;
22         entity se;
23         float f;
24
25         tracebox('0 0 0', WarpZoneLib_BoxTouchesBrush_mins, WarpZoneLib_BoxTouchesBrush_maxs, '0 0 0', MOVE_NOMONSTERS, WarpZoneLib_BoxTouchesBrush_ignore);
26 #ifdef CSQC
27         if (trace_networkentity)
28         {
29                 dprint("hit a network ent, cannot continue WarpZoneLib_BoxTouchesBrush\n");
30                 // we cannot continue, as a player blocks us...
31                 // so, abort
32                 return 0;
33         }
34 #endif
35         if not(trace_ent)
36                 return 0;
37         if (trace_ent == WarpZoneLib_BoxTouchesBrush_ent)
38                 return 1;
39
40         se = trace_ent;
41         s = se.solid;
42         se.solid = SOLID_NOT;
43         f = WarpZoneLib_BoxTouchesBrush_Recurse();
44         se.solid = s;
45
46         return f;
47 }
48
49 float WarpZoneLib_BoxTouchesBrush(vector mi, vector ma, entity e, entity ig)
50 {
51     float f, s;
52
53     if not(e.modelindex)
54         return 1;
55
56     s = e.solid;
57     e.solid = SOLID_BSP;
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();
63     e.solid = s;
64
65     return f;
66 }
67
68 entity WarpZone_Find(vector mi, vector ma)
69 {
70         // if we are near any warpzone planes - MOVE AWAY (work around nearclip)
71         entity e;
72         for(e = world; (e = find(e, classname, "trigger_warpzone")); )
73                 if(WarpZoneLib_BoxTouchesBrush(mi, ma, e, world))
74                         return e;
75         return world;
76 }
77
78 void WarpZone_MakeAllSolid()
79 {
80         entity e;
81         for(e = world; (e = find(e, classname, "trigger_warpzone")); )
82                 e.solid = SOLID_BSP;
83 }
84
85 void WarpZone_MakeAllOther()
86 {
87         entity e;
88         for(e = world; (e = find(e, classname, "trigger_warpzone")); )
89                 e.solid = SOLID_TRIGGER;
90 }
91
92 void WarpZone_TraceBox(vector org, vector mi, vector ma, vector end, float nomonsters, entity forent)
93 {
94         float frac, sol;
95         vector o0, e0;
96         entity wz;
97         vector vf, vr, vu;
98         vf = v_forward;
99         vr = v_right;
100         vu = v_up;
101         // if starting in warpzone, first transform
102         wz = WarpZone_Find(org + mi, org + ma);
103         if(wz)
104         {
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);
110         }
111         WarpZone_MakeAllSolid();
112         o0 = org;
113         e0 = end;
114         sol = -1;
115         frac = 0;
116         for(;;)
117         {
118                 tracebox(org, mi, ma, end, nomonsters, forent);
119                 if(WarpZone_trace_callback)
120                         WarpZone_trace_callback(org, trace_endpos, end);
121                 if(sol < 0)
122                         sol = trace_startsolid;
123                 if(trace_fraction >= 1)
124                         break;
125                 frac = trace_fraction = frac + (1 - frac) * trace_fraction;
126                 if(trace_ent.classname != "trigger_warpzone")
127                         break;
128                 if(trace_ent == wz)
129                 {
130                         dprint("I transformed into the same zone again, wtf, aborting the trace\n");
131                         break;
132                 }
133                 wz = trace_ent;
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);
140         }
141         WarpZone_MakeAllOther();
142         trace_startsolid = sol;
143         WarpZone_trace_endpos = o0 + (e0 - o0) * trace_fraction;
144         v_forward = vf;
145         v_right = vr;
146         v_up = vu;
147 }
148
149 void WarpZone_TraceBox_ThroughZone(vector org, vector mi, vector ma, vector end, float nomonsters, entity forent, entity zone)
150 {
151         float frac, sol;
152         vector o0, e0;
153         entity wz;
154         vector vf, vr, vu;
155         vf = v_forward;
156         vr = v_right;
157         vu = v_up;
158         // if starting in warpzone, first transform
159         wz = WarpZone_Find(org + mi, org + ma);
160         if(wz)
161         {
162                 if(wz != zone)
163                 {
164                         // we are in ANOTHER warpzone. This is bad. Make a zero length trace and return.
165                         sol = 1;
166                         trace_fraction = 0;
167                         trace_endpos = org;
168                         goto fail;
169                 }
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);
175         }
176         WarpZone_MakeAllSolid();
177         o0 = org;
178         e0 = end;
179         sol = -1;
180         frac = 0;
181         for(;;)
182         {
183                 tracebox(org, mi, ma, end, nomonsters, forent);
184                 if(WarpZone_trace_callback)
185                         WarpZone_trace_callback(org, trace_endpos, end);
186                 if(sol < 0)
187                         sol = trace_startsolid;
188                 if(trace_fraction >= 1)
189                         break;
190                 frac = trace_fraction = frac + (1 - frac) * trace_fraction;
191                 if(trace_ent.classname != "trigger_warpzone")
192                         break;
193                 if(trace_ent != zone)
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                 // 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);
207         }
208         WarpZone_MakeAllOther();
209 :fail
210         trace_startsolid = sol;
211         WarpZone_trace_endpos = o0 + (e0 - o0) * trace_fraction;
212         v_forward = vf;
213         v_right = vr;
214         v_up = vu;
215 }
216
217 void WarpZone_TraceLine(vector org, vector end, float nomonsters, entity forent)
218 {
219         WarpZone_TraceBox(org, '0 0 0', '0 0 0', end, nomonsters, forent);
220 }
221
222 void WarpZone_TraceToss(entity e, entity forent)
223 {
224         float g, dt;
225         vector vf, vr, vu, v0, o0;
226         entity wz;
227         vf = v_forward;
228         vr = v_right;
229         vu = v_up;
230         // if starting in warpzone, first transform
231         wz = WarpZone_Find(e.origin + e.mins, e.origin + e.maxs);
232         if(wz)
233         {
234                 setorigin(e, WarpZone_TransformOrigin(wz, e.origin));
235                 e.velocity = WarpZone_TransformVelocity(wz, e.velocity);
236         }
237         WarpZone_MakeAllSolid();
238         g = cvar("sv_gravity") * e.gravity;
239         WarpZone_tracetoss_time = 0;
240         v0 = e.velocity;
241         o0 = e.origin;
242         for(;;)
243         {
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)
252                         break;
253                 if(trace_ent.classname != "trigger_warpzone")
254                         break;
255                 if(trace_ent == wz)
256                 {
257                         dprint("I transformed into the same zone again, wtf, aborting the trace\n");
258                         break;
259                 }
260                 wz = trace_ent;
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);
264         }
265         WarpZone_MakeAllOther();
266         v_forward = vf;
267         v_right = vr;
268         v_up = vu;
269         WarpZone_tracetoss_velocity = e.velocity;
270         e.velocity = v0;
271         e.origin = o0;
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;
274 }
275
276 void WarpZone_TrailParticles(entity own, float eff, vector org, vector end)
277 {
278         vector vf, vr, vu;
279         entity e;
280         vf = v_forward;
281         vr = v_right;
282         vu = v_up;
283         WarpZone_MakeAllSolid();
284         e = world;
285         for(;;)
286         {
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)
291                         break;
292                 if(trace_ent.classname != "trigger_warpzone")
293                         break;
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);
297                 if(trace_ent == e)
298                 {
299                         dprint("I transformed into the same zone again, wtf, aborting the trace\n");
300                         break;
301                 }
302                 e = trace_ent;
303         }
304         WarpZone_MakeAllOther();
305         v_forward = vf;
306         v_right = vr;
307         v_up = vu;
308 }
309
310 float WarpZone_PlaneDist(entity wz, vector v)
311 {
312         return (v - wz.warpzone_origin) * wz.warpzone_forward;
313 }
314
315 float WarpZone_TargetPlaneDist(entity wz, vector v)
316 {
317         return (v - wz.warpzone_targetorigin) * wz.warpzone_targetforward;
318 }
319
320 vector WarpZone_TransformOrigin(entity wz, vector v)
321 {
322         return wz.warpzone_shift + AnglesTransform_Apply(wz.warpzone_transform, v);
323 }
324
325 vector WarpZone_TransformVelocity(entity wz, vector v)
326 {
327         return AnglesTransform_Apply(wz.warpzone_transform, v);
328 }
329
330 vector WarpZone_TransformAngles(entity wz, vector v)
331 {
332         return AnglesTransform_ApplyToAngles(wz.warpzone_transform, v);
333 }
334
335 vector WarpZone_TransformVAngles(entity wz, vector ang)
336 {
337         float roll;
338
339         roll = ang_z;
340         ang_z = 0;
341
342         ang = AnglesTransform_ApplyToVAngles(wz.warpzone_transform, ang);
343         ang = AnglesTransform_Normalize(ang, TRUE);
344         ang = AnglesTransform_CancelRoll(ang);
345
346         ang_z = roll;
347         return ang;
348 }
349
350 vector WarpZone_UnTransformOrigin(entity wz, vector v)
351 {
352         return AnglesTransform_Apply(AnglesTransform_Invert(wz.warpzone_transform), v - wz.warpzone_shift);
353 }
354
355 vector WarpZone_UnTransformVelocity(entity wz, vector v)
356 {
357         return AnglesTransform_Apply(AnglesTransform_Invert(wz.warpzone_transform), v);
358 }
359
360 vector WarpZone_UnTransformAngles(entity wz, vector v)
361 {
362         return AnglesTransform_ApplyToAngles(AnglesTransform_Invert(wz.warpzone_transform), v);
363 }
364
365 vector WarpZone_UnTransformVAngles(entity wz, vector ang)
366 {
367         float roll;
368
369         roll = ang_z;
370         ang_z = 0;
371
372         ang = AnglesTransform_ApplyToVAngles(AnglesTransform_Invert(wz.warpzone_transform), ang);
373         ang = AnglesTransform_Normalize(ang, TRUE);
374         ang = AnglesTransform_CancelRoll(ang);
375
376         ang_z = roll;
377         return ang;
378 }
379
380 vector WarpZoneLib_NearestPointOnBox(vector mi, vector ma, vector org)
381 {
382         vector nearest;
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);
386         return nearest;
387 }
388
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)
393 {
394         vector org_new;
395         vector org0_new;
396         vector shift_new, transform_new;
397         vector shift_second, transform_second;
398         vector p;
399         entity e, e0;
400         entity wz;
401         if(rad <= 0)
402                 return;
403         e0 = findradius(org, rad);
404         wz = world;
405
406         for(e = e0; e; e = e.chain)
407         {
408                 p = WarpZoneLib_NearestPointOnBox(e.origin + e.mins, e.origin + e.maxs, org0);
409                 if(needlineofsight)
410                 {
411                         traceline(org, p, MOVE_NOMONSTERS, e);
412                         if(trace_fraction < 1)
413                                 continue;
414                 }
415                 if(!e.WarpZone_findradius_hit || vlen(e.WarpZone_findradius_dist) > vlen(org0 - p))
416                 {
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")
422                         {
423                                 e.WarpZone_findradius_next = wz;
424                                 wz = e;
425
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;
429                         }
430                         else
431                         {
432                                 e.warpzone_transform = transform;
433                                 e.warpzone_shift = shift;
434
435                                 e.WarpZone_findradius_hit = 1;
436                         }
437                 }
438         }
439         for(e = wz; e; e = e.WarpZone_findradius_next)
440         {
441                 org0_new = WarpZone_TransformOrigin(e, org);
442                 traceline(e.warpzone_targetorigin, org0_new, MOVE_NOMONSTERS, e);
443                 org_new = trace_endpos;
444
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(
450                         org_new,
451                         bound(0, rad - vlen(org_new - org0_new), rad - 8),
452                         org0_new,
453                         transform_new, shift_new,
454                         needlineofsight);
455                 e.WarpZone_findradius_hit = 0;
456                 e.enemy.WarpZone_findradius_hit = 0;
457         }
458 }
459 entity WarpZone_FindRadius(vector org, float rad, float needlineofsight)
460 {
461         entity e0, e;
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;
466         return e0;
467 }
468
469 void WarpZone_Accumulator_Clear(entity acc)
470 {
471         acc.warpzone_transform = '0 0 0';
472         acc.warpzone_shift = '0 0 0';
473 }
474 void WarpZone_Accumulator_AddTransform(entity acc, vector t, vector s)
475 {
476         vector tr, st;
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;
481 }
482 void WarpZone_Accumulator_Add(entity acc, entity wz)
483 {
484         vector t, st;
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;
489 }
490
491 .entity WarpZone_refsys;
492 void WarpZone_RefSys_GC()
493 {
494         // garbage collect unused reference systems
495         self.nextthink = time + 1;
496         if(self.owner.WarpZone_refsys != self)
497                 remove(self);
498 }
499 void WarpZone_RefSys_Add(entity me, entity wz)
500 {
501         if(me.WarpZone_refsys.owner != me)
502         {
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);
509         }
510         if(wz)
511                 WarpZone_Accumulator_Add(me.WarpZone_refsys, wz);
512 }
513 .vector WarpZone_refsys_incremental_shift;
514 .vector WarpZone_refsys_incremental_transform;
515 void WarpZone_RefSys_AddIncrementally(entity me, entity ref)
516 {
517         vector t, s;
518         if(me.WarpZone_refsys_incremental_transform == ref.WarpZone_refsys.warpzone_transform)
519         if(me.WarpZone_refsys_incremental_shift == ref.WarpZone_refsys.warpzone_shift)
520                 return;
521         if(me.WarpZone_refsys.owner != me)
522         {
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);
529         }
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;
536 }
537 void WarpZone_RefSys_BeginAddingIncrementally(entity me, entity ref)
538 {
539         me.WarpZone_refsys_incremental_shift = ref.WarpZone_refsys.warpzone_shift;
540         me.WarpZone_refsys_incremental_transform = ref.WarpZone_refsys.warpzone_transform;
541 }
542 vector WarpZone_RefSys_TransformOrigin(entity from, entity to, vector org)
543 {
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);
548         return org;
549 }
550 vector WarpZone_RefSys_TransformVelocity(entity from, entity to, vector vel)
551 {
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);
556         return vel;
557 }
558 vector WarpZone_RefSys_TransformAngles(entity from, entity to, vector ang)
559 {
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);
564         return ang;
565 }
566 vector WarpZone_RefSys_TransformVAngles(entity from, entity to, vector ang)
567 {
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);
572         return ang;
573 }
574 entity WarpZone_RefSys_SpawnSameRefSys(entity me)
575 {
576         entity e;
577         e = spawn();
578         if(me.WarpZone_refsys)
579         {
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;
587         }
588         return e;
589 }