Xonotic QuakeC
The free, fast arena FPS with crisp movement and a wide array of weapons
server.qc
Go to the documentation of this file.
1#include "server.qh"
2
3#include "common.qh"
4#ifdef SVQC
5 #include <common/constants.qh>
6 #include <common/net_linked.qh>
9 #include <common/util.qh>
10 #include <common/weapons/_all.qh>
11 #include <common/stats.qh>
12 #include <server/utils.qh>
14#endif
15
16#ifdef SVQC
18#endif
19
20#ifdef WARPZONELIB_KEEPDEBUG
21 #define WARPZONELIB_REMOVEHACK
22#endif
23
24// for think function
29
30// for all entities
35
36#define WarpZone_StoreProjectileData(e_) MACRO_BEGIN \
37 entity e = e_; \
38 e.warpzone_oldorigin = e.origin; \
39 e.warpzone_oldvelocity = e.velocity; \
40 e.warpzone_oldangles = e.angles; \
41MACRO_END
42
43void WarpZone_TeleportPlayer(entity teleporter, entity player, vector to, vector to_angles, vector to_velocity)
44{
45#ifdef SVQC
46 player.lastteleport_origin = player.origin;
47 player.lastteleporttime = time;
48#endif
49 setorigin(player, to); // NOTE: this also aborts the move, when this is called by touch
50 player.angles = to_angles;
51#ifdef SVQC
52 player.oldorigin = to; // for DP's unsticking
53 player.fixangle = true;
54 if (IS_BOT_CLIENT(player))
55 {
56 // FIXME find a way to smooth view's angles change for bots too
57 player.v_angle = player.angles;
58 bot_aim_reset(player);
59 }
60#endif
61 player.velocity = to_velocity;
62
63 BITXOR_ASSIGN(player.effects, EF_TELEPORT_BIT);
64
65 if (IS_PLAYER(player))
66 BITCLR_ASSIGN(player.flags, FL_ONGROUND);
67
69}
70
71#ifdef SVQC
73{
74 WriteHeader(MSG_ENTITY, ENT_CLIENT_WARPZONE_TELEPORTED);
75 WriteVector(MSG_ENTITY, this.angles);
76 return true;
77}
78#endif
79
80float WarpZone_Teleport(entity wz, entity player, float f0, float f1)
81{
82 vector o0, a0, v0, o1, a1, v1, o10;
83
84 o0 = player.origin + player.view_ofs;
85 v0 = player.velocity;
86 a0 = player.angles;
87
88 o10 = o1 = WarpZone_TransformOrigin(wz, o0);
89 v1 = WarpZone_TransformVelocity(wz, v0);
90 if (!IS_NOT_A_CLIENT(player))
92 else
93 a1 = WarpZone_TransformAngles(wz, a0);
94
95 if (f0 != 0 || f1 != 0)
96 {
97 // retry last move but behind the warpzone!
98 // we must first go back as far as we can, then forward again, to not cause double touch events!
99
100 tracebox(o1 - player.view_ofs + v1 * frametime * f1, player.mins, player.maxs, o1 - player.view_ofs + v1 * frametime * f0, MOVE_WORLDONLY, player);
101 {
102 entity own = player.owner;
103 player.owner = NULL;
104 tracebox(trace_endpos, player.mins, player.maxs, o1 - player.view_ofs + v1 * frametime * f1, MOVE_NORMAL, player); // this should get us through the warpzone
105 player.owner = own;
106 }
107 o1 = trace_endpos + player.view_ofs;
108
109 float d, dv, md;
110 md = max(vlen(player.mins), vlen(player.maxs));
111 d = WarpZone_TargetPlaneDist(wz, o1);
112 dv = WarpZone_TargetPlaneDist(wz, v1);
113 if (d < 0)
114 o1 -= v1 * (d / dv);
115 }
116
117 // put them out of solid
118 tracebox(o1 - player.view_ofs, player.mins, player.maxs, o1 - player.view_ofs, MOVE_NOMONSTERS, player);
120 {
121 setorigin(player, o1 - player.view_ofs);
122 if (WarpZoneLib_MoveOutOfSolid(player))
123 {
124 o1 = player.origin + player.view_ofs;
125 setorigin(player, o0 - player.view_ofs);
126 }
127 else
128 {
129 LOG_INFO("would have to put player in solid, won't do that");
130 setorigin(player, o0 - player.view_ofs);
131 return 0;
132 }
133 }
134
135 // do the teleport
136 WarpZone_RefSys_Add(player, wz);
137 WarpZone_TeleportPlayer(wz, player, o1 - player.view_ofs, a1, v1);
139 player.warpzone_teleport_time = time;
140 player.warpzone_teleport_finishtime = time;
141 player.warpzone_teleport_zone = wz;
142
143#ifdef SVQC
144 // prevent further teleports back
145 float dt = (v1 != '0 0 0') ? (o1 - o10) * v1 * (1 / (v1 * v1)) : 0;
146 if (dt < PHYS_INPUT_FRAMETIME)
147 player.warpzone_teleport_finishtime += PHYS_INPUT_FRAMETIME - dt;
148#endif
149
150#ifndef WARPZONE_USE_FIXANGLE
151 #ifdef SVQC
152 if (IS_VEHICLE(player) && player.owner)
153 player = player.owner; // hax
154 if (IS_PLAYER(player))
155 {
156 // instead of fixangle, send the transform to the client for smoother operation
157 player.fixangle = false;
158
159 entity ts = new(warpzone_teleported);
160 setmodel(ts, MDL_Null);
162 ts.SendFlags = 0xFFFFFF;
163 ts.drawonlytoclient = player;
164 setthink(ts, SUB_Remove);
165 ts.nextthink = time + 1;
166 ts.owner = player;
167 ts.enemy = wz;
168 ts.effects = EF_NODEPTHTEST;
169 ts.angles = wz.warpzone_transform;
170 }
171 #elifdef CSQC
172 setproperty(VF_CL_VIEWANGLES, WarpZone_TransformVAngles(wz, getpropertyvec(VF_CL_VIEWANGLES)));
173 //if (checkextension("DP_CSQC_ROTATEMOVES"))
174 //CL_RotateMoves(wz.warpzone_transform);
175 #endif
176#endif
177
178 return 1;
179}
180
182{
183 if (toucher.classname == "trigger_warpzone")
184 return;
185
186 if (time <= toucher.warpzone_teleport_finishtime) // already teleported this frame
187 return;
188
189 // FIXME needs a better check to know what is safe to teleport and what not
190 if (toucher.move_movetype == MOVETYPE_NONE || toucher.move_movetype == MOVETYPE_FOLLOW || toucher.tag_entity)
191 return;
192
193 if (WarpZone_PlaneDist(this, toucher.origin + toucher.view_ofs) >= 0) // wrong side of the trigger_warpzone (don't teleport yet)
194 return;
195
197
198 float f;
199 // number of frames we need to go back:
200 // dist = 16*sqrt(2) qu
201 // dist ~ 24 qu
202 // 24 qu = v*t
203 // 24 qu = v*frametime*n
204 // n = 24 qu/(v*frametime)
205 // for clients go only one frame though, may be too irritating otherwise
206 // but max 0.25 sec = 0.25/frametime frames
207 // 24/(0.25/frametime)
208 // 96*frametime
209 float d = 24 + max(vlen(toucher.mins), vlen(toucher.maxs));
211 f = -d / bound(frametime * d * 1, frametime * vlen(toucher.velocity), d);
212 else
213 f = -1;
214 if (WarpZone_Teleport(this, toucher, f, 0))
215 {
216#ifdef SVQC
217 SUB_UseTargets_SkipTargets(this, toucher, toucher, BIT(1) | BIT(3)); // use toucher too?
218 SUB_UseTargets_SkipTargets(this.enemy, toucher, toucher, BIT(1) | BIT(2)); // use toucher too?
219#endif
220 }
221 else
222 LOG_TRACE("WARPZONE FAIL AHAHAHAHAH))");
223}
224
225#ifdef SVQC
226bool WarpZone_Send(entity this, entity to, int sf)
227{
228 WriteHeader(MSG_ENTITY, ENT_CLIENT_WARPZONE);
229
230 // we must send this flag for clientside to match properly too
231 sf = 0;
232 if (this.warpzone_isboxy)
233 BITSET_ASSIGN(sf, 1);
234 if (this.warpzone_fadestart)
235 BITSET_ASSIGN(sf, 2);
236 if (this.origin != '0 0 0')
237 BITSET_ASSIGN(sf, 4);
239
240 // we need THESE to render the warpzone (and cull properly)...
241 if (sf & 4)
242 WriteVector(MSG_ENTITY, this.origin);
243
245 WriteVector(MSG_ENTITY, this.mins);
246 WriteVector(MSG_ENTITY, this.maxs);
247 WriteByte(MSG_ENTITY, bound(1, this.scale * 16, 255));
248
249 // we need THESE to calculate the proper transform
250 WriteVector(MSG_ENTITY, this.warpzone_origin);
251 WriteVector(MSG_ENTITY, this.warpzone_angles);
252 WriteVector(MSG_ENTITY, this.warpzone_targetorigin);
253 WriteVector(MSG_ENTITY, this.warpzone_targetangles);
254
255 if (sf & 2)
256 {
259 }
260
261 return true;
262}
263
264bool WarpZone_Camera_Send(entity this, entity to, int sf)
265{
266 sf = 0;
267 WriteHeader(MSG_ENTITY, ENT_CLIENT_WARPZONE_CAMERA);
268
269 if (this.warpzone_fadestart)
270 BITSET_ASSIGN(sf, 2);
271 if (this.origin != '0 0 0')
272 BITSET_ASSIGN(sf, 4);
274
275 // we need THESE to render the warpzone (and cull properly)...
276 if (sf & 4)
277 WriteVector(MSG_ENTITY, this.origin);
278
280 WriteVector(MSG_ENTITY, this.mins);
281 WriteVector(MSG_ENTITY, this.maxs);
282 WriteByte(MSG_ENTITY, bound(1, this.scale * 16, 255));
283
284 // we need THESE to calculate the proper transform
285 WriteVector(MSG_ENTITY, this.enemy.origin);
286 WriteVector(MSG_ENTITY, this.enemy.angles);
287
288 if (sf & 2)
289 {
292 }
293
294 return true;
295}
296
297#ifdef WARPZONELIB_KEEPDEBUG
298float WarpZone_CheckProjectileImpact(entity player)
299{
300 vector o0 = player.origin + player.view_ofs;
301 vector v0 = player.velocity;
302
303 // if we teleported shortly before, abort
304 if (time <= player.warpzone_teleport_finishtime + 0.1)
305 return 0;
306
307 // if player hit a warpzone, abort
308 entity wz = WarpZone_Find(o0 + player.mins, o0 + player.maxs);
309 if (!wz)
310 return 0;
311
312#ifdef WARPZONELIB_REMOVEHACK
313 LOG_INFO("impactfilter found something - and it no longer gets handled correctly - please tell divVerent whether anything behaves broken now");
314#else
315 LOG_INFO("impactfilter found something - and it even gets handled correctly - please tell divVerent that this code apparently gets triggered again");
316#endif
317 LOG_INFO("Entity type: ", player.classname);
318 LOG_INFO("Origin: ", vtos(player.origin));
319 LOG_INFO("Velocity: ", vtos(player.velocity));
320
321#ifdef WARPZONELIB_REMOVEHACK
322 return 0;
323#else
324 // retry previous move
325 setorigin(player, player.warpzone_oldorigin);
326 player.velocity = player.warpzone_oldvelocity;
327 if (WarpZone_Teleport(wz, player, 0, 1))
328 {
329 SUB_UseTargets_SkipTargets(wz, player, player, BIT(1) | BIT(3));
330 SUB_UseTargets_SkipTargets(wz.enemy, player, player, BIT(1) | BIT(2));
331 }
332 else
333 {
334 setorigin(player, o0 - player.view_ofs);
335 player.velocity = v0;
336 }
337
338 return +1;
339#endif
340}
341#endif
342#endif
343
345{
346 if (toucher.classname == "trigger_warpzone")
347 return true;
348
349 // no further impacts if we teleported this frame!
350 // this is because even if we did teleport, the engine still may raise
351 // touch events for the previous location
352 // engine now aborts moves on teleport, so this SHOULD not happen any more
353 // but if this is called from TouchAreaGrid of the projectile moving,
354 // then this won't do
355 if (time == this.warpzone_teleport_time)
356 return true;
357
358#ifdef SVQC
359#ifdef WARPZONELIB_KEEPDEBUG
360 // this SEEMS to not happen at the moment, but if it did, it would be more reliable
361 {
362 float save_dpstartcontents;
363 float save_dphitcontents;
364 float save_dphitq3surfaceflags;
365 string save_dphittexturename;
366 float save_allsolid;
367 float save_startsolid;
368 float save_fraction;
369 vector save_endpos;
370 vector save_plane_normal;
371 float save_plane_dist;
372 entity save_ent;
373 float save_inopen;
374 float save_inwater;
375 save_dpstartcontents = trace_dpstartcontents;
376 save_dphitcontents = trace_dphitcontents;
377 save_dphitq3surfaceflags = trace_dphitq3surfaceflags;
378 save_dphittexturename = trace_dphittexturename;
379 save_allsolid = trace_allsolid;
380 save_startsolid = trace_startsolid;
381 save_fraction = trace_fraction;
382 save_endpos = trace_endpos;
383 save_plane_normal = trace_plane_normal;
384 save_plane_dist = trace_plane_dist;
385 save_ent = trace_ent;
386 save_inopen = trace_inopen;
387 save_inwater = trace_inwater;
388 float f = WarpZone_CheckProjectileImpact(this);
389 if (f) return (f > 0);
390 trace_dpstartcontents = save_dpstartcontents;
391 trace_dphitcontents = save_dphitcontents;
392 trace_dphitq3surfaceflags = save_dphitq3surfaceflags;
393 trace_dphittexturename = save_dphittexturename;
394 trace_allsolid = save_allsolid;
395 trace_startsolid = save_startsolid;
396 trace_fraction = save_fraction;
397 trace_endpos = save_endpos;
398 trace_plane_normal = save_plane_normal;
399 trace_plane_dist = save_plane_dist;
400 trace_ent = save_ent;
401 trace_inopen = save_inopen;
402 trace_inwater = save_inwater;
403 }
404#endif
405
407 return true;
408#endif
409
410 return false;
411}
412
413#ifdef SVQC
414
416{
417 if (this.killtarget != "")
418 {
419 this.aiment = find(NULL, targetname, this.killtarget);
420 if (this.aiment == NULL)
421 {
422 error("Warp zone with nonexisting killtarget");
423 return;
424 }
425 this.killtarget = string_null;
426 }
427}
428
430{
431 if (this.target == "")
432 {
433 error("Warp zone position with no target");
434 return;
435 }
436 this.enemy = find(NULL, targetname, this.target);
437 if (this.enemy == NULL)
438 {
439 error("Warp zone position with nonexisting target");
440 return;
441 }
442 if (this.enemy.aiment)
443 {
444 // already is positioned
445 error("Warp zone position targeting already oriented warpzone");
446 return;
447 }
448 this.enemy.aiment = this;
449}
450
452{
453 if (this.warpzone_save_origin != this.origin
454 || this.warpzone_save_angles != this.angles
455 || this.warpzone_save_eorigin != this.enemy.origin
456 || this.warpzone_save_eangles != this.enemy.angles)
457 {
458 WarpZone_Camera_SetUp(this, this.enemy.origin, this.enemy.angles);
459 this.warpzone_save_origin = this.origin;
460 this.warpzone_save_angles = this.angles;
461 this.warpzone_save_eorigin = this.enemy.origin;
462 this.warpzone_save_eangles = this.enemy.angles;
463 }
464 this.nextthink = time;
465}
466
468{
469 entity e;
470 float i;
471 if (this.target == "")
472 {
473 error("Camera with no target");
474 return;
475 }
476 this.enemy = NULL;
477 for (e = NULL, i = 0; (e = find(e, targetname, this.target)); )
478 if (random() * ++i < 1)
479 this.enemy = e;
480 if (this.enemy == NULL)
481 {
482 error("Camera with nonexisting target");
483 return;
484 }
486 WarpZone_Camera_SetUp(this, this.enemy.origin, this.enemy.angles);
487 this.SendFlags = 0xFFFFFF;
488 if (this.spawnflags & 1)
489 {
491 this.nextthink = time;
492 }
493 else
494 this.nextthink = 0;
495}
496
498{
499 vector org, ang, norm, point;
500 float area;
501 vector tri, a, b, c, n;
502 float i_s, i_t, n_t;
503 string tex;
504
505 org = this.origin;
506 if (org == '0 0 0')
507 org = 0.5 * (this.mins + this.maxs);
508
509 norm = point = '0 0 0';
510 area = 0;
511 for (i_s = 0; ; ++i_s)
512 {
513 tex = getsurfacetexture(this, i_s);
514 if (!tex)
515 break; // this is beyond the last one
516 if (tex == "textures/common/trigger" || tex == "trigger")
517 continue;
518 n_t = getsurfacenumtriangles(this, i_s);
519 for (i_t = 0; i_t < n_t; ++i_t)
520 {
521 tri = getsurfacetriangle(this, i_s, i_t);
522 a = getsurfacepoint(this, i_s, tri.x);
523 b = getsurfacepoint(this, i_s, tri.y);
524 c = getsurfacepoint(this, i_s, tri.z);
525 n = cross(c - a, b - a);
526 area += vlen(n);
527 norm += n;
528 point += vlen(n) * (a + b + c);
529 }
530 }
531 if (area > 0)
532 {
533 norm *= 1 / area;
534 point *= 1 / (3 * area);
535 if (vdist(norm, <, 0.99))
536 {
537 LOG_INFO("trigger_warpzone near ", vtos(this.aiment.origin), " is nonplanar. BEWARE.");
538 area = 0; // no autofixing in this case
539 }
540 norm = normalize(norm);
541 }
542
543 ang = '0 0 0';
544 if (this.aiment)
545 {
546 org = this.aiment.origin;
547 ang = this.aiment.angles;
548 if (area > 0)
549 {
550 org -= ((org - point) * norm) * norm; // project to plane
551 vector forward, right, up;
552 MAKE_VECTORS(ang, forward, right, up);
553 if (norm * forward < 0)
554 {
555 LOG_INFO("Position target of trigger_warpzone near ", vtos(this.aiment.origin), " points into trigger_warpzone. BEWARE.");
556 norm = -1 * norm;
557 }
558 ang = vectoangles2(norm, up); // keep rotation, but turn exactly against plane
559 ang.x = -ang.x;
560 if (norm * forward < 0.99)
561 LOG_INFO("trigger_warpzone near ", vtos(this.aiment.origin), " has been turned to match plane orientation (", vtos(this.aiment.angles), " -> ", vtos(ang));
562 if (vdist(org - this.aiment.origin, >, 0.5))
563 LOG_INFO("trigger_warpzone near ", vtos(this.aiment.origin), " has been moved to match the plane (", vtos(this.aiment.origin), " -> ", vtos(org), ").");
564 }
565 }
566 else if (area > 0)
567 {
568 org = point;
569 ang = vectoangles(norm);
570 ang.x = -ang.x;
571 }
572 else
573 error("cannot infer origin/angles for this warpzone, please use a killtarget or a trigger_warpzone_position");
574
575 this.warpzone_origin = org;
576 this.warpzone_angles = ang;
577}
578
580{
581 if (this.enemy)
582 this.enemy.enemy = NULL;
583 this.enemy = NULL;
584}
585
587{
588 if (this.enemy)
589 return;
590
591 // this way only one of the two ents needs to target
592 if (this.target != "")
593 {
595 this.enemy = this; // so the if (!e.enemy) check also skips this, saves one IF
596
597 int i;
598 entity e, e2 = NULL;
599 for (e = NULL, i = 0; (e = find(e, targetname, this.target)); )
600 if (!e.enemy)
601 if (e.classname == this.classname) // possibly non-warpzones may use the same targetname!
602 if (random() * ++i < 1)
603 e2 = e;
604 if (!e2)
605 {
606 this.enemy = NULL;
607 error("Warpzone with non-existing target");
608 return;
609 }
610 this.enemy = e2;
611 e2.enemy = this;
612 }
613}
614
615void WarpZone_Think(entity this);
617{
618 if (!this.enemy || this.enemy.enemy != this)
619 {
620 error("Invalid warp zone detected. Killed.");
621 return;
622 }
623
625 WarpZone_SetUp(this, this.warpzone_origin, this.warpzone_angles, this.enemy.warpzone_origin, this.enemy.warpzone_angles);
627 this.SendFlags = 0xFFFFFF;
628 if (this.spawnflags & 1)
629 {
631 this.nextthink = time;
632 }
633 else
634 this.nextthink = 0;
635}
636
638//entity warpzone_first;
642spawnfunc(misc_warpzone_position)
643{
644 // "target", "angles", "origin"
647}
648spawnfunc(trigger_warpzone_position)
649{
650 spawnfunc_misc_warpzone_position(this);
651}
652spawnfunc(trigger_warpzone)
653{
654 // warp zone entities must have:
655 // "killtarget" pointing to a target_position with a direction arrow
656 // that points AWAY from the warp zone, and that is inside
657 // the warp zone trigger
658 // "target" pointing to an identical warp zone at another place in
659 // the map, with another killtarget to designate its
660 // orientation
661
662 if (!this.scale)
663 this.scale = this.modelscale;
664 if (!this.scale)
665 this.scale = 1;
666
668
670 this.SendFlags = 0xFFFFFF;
673 warpzone_first = this;
674
675 IL_PUSH(g_warpzones, this);
676}
677spawnfunc(func_camera)
678{
679 if (!this.scale)
680 this.scale = this.modelscale;
681 if (!this.scale)
682 this.scale = 1;
683 if (this.model != "")
684 {
685 precache_model(this.model);
686 _setmodel(this, this.model); // no precision needed
687 }
688 setorigin(this, this.origin);
689 if (this.scale)
690 setsize(this, this.mins * this.scale, this.maxs * this.scale);
691 else
692 setsize(this, this.mins, this.maxs);
693 if (!this.solid)
694 this.solid = SOLID_BSP;
695 else if (this.solid < 0)
696 this.solid = SOLID_NOT;
698 this.SendFlags = 0xFFFFFF;
701}
703{
704 for (entity e = warpzone_first; e; e = e.warpzone_next)
706 for (entity e = warpzone_first; e; e = e.warpzone_next)
708 for (entity e = warpzone_camera_first; e; e = e.warpzone_next)
710 for (entity e = warpzone_first; e; e = e.warpzone_next)
712}
713
715{
716 if (this.warpzone_save_origin != this.origin
717 || this.warpzone_save_angles != this.angles
718 || this.warpzone_save_eorigin != this.enemy.origin
719 || this.warpzone_save_eangles != this.enemy.angles)
720 {
725 this.warpzone_save_origin = this.origin;
726 this.warpzone_save_angles = this.angles;
727 this.warpzone_save_eorigin = this.enemy.origin;
728 this.warpzone_save_eangles = this.enemy.angles;
729 }
730 this.nextthink = time;
731}
732
734{
736 {
738 for (entity e = warpzone_first; e; e = e.warpzone_next)
740 for (entity e = warpzone_position_first; e; e = e.warpzone_next)
742 for (entity e = warpzone_first; e; e = e.warpzone_next)
746 }
747
750
751 FOREACH_CLIENT(true,
752 {
754 WarpZone_StoreProjectileData(it); // TODO: not actually needed
755
756 if (IS_OBSERVER(it) || it.solid == SOLID_NOT)
757 {
758 // warpzones
760 {
761 entity e = WarpZone_Find(it.origin + it.mins, it.origin + it.maxs);
762 if (e)
763 if (WarpZoneLib_ExactTrigger_Touch(e, it, false))
764 if (WarpZone_PlaneDist(e, it.origin + it.view_ofs) <= 0)
765 WarpZone_Teleport(e, it, -1, 0); // NOT triggering targets by this!
766 }
767
768 // teleporters
769 if (it.teleportable)
770 {
771 entity ent = Teleport_Find(it.origin + it.mins, it.origin + it.maxs);
772 if (ent && WarpZoneLib_ExactTrigger_Touch(ent, it, false))
773 Simple_TeleportPlayer(ent, it); // NOT triggering targets by this!
774 }
775 }
776 });
777}
778
781{
782 FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it) && checkpvs(it.origin + it.view_ofs, ent), return true);
783 return false;
784}
786{
787 // NOTE: this matches for target, not targetname, but of course
788 // targetname must be set too on the other entities
789 for (entity e = warpzone_first; e; e = e.warpzone_next)
790 e.warpzone_reconnecting = ((this.target == "" || e.target == this.target) && !((this.spawnflags & 1) && (visible_to_some_client(e) || visible_to_some_client(e.enemy))));
791 for (entity e = warpzone_camera_first; e; e = e.warpzone_next)
792 e.warpzone_reconnecting = ((this.target == "" || e.target == this.target) && !((this.spawnflags & 1) && visible_to_some_client(e)));
793 for (entity e = warpzone_first; e; e = e.warpzone_next)
794 if (e.warpzone_reconnecting)
796 for (entity e = warpzone_first; e; e = e.warpzone_next)
797 if (e.warpzone_reconnecting)
799 for (entity e = warpzone_camera_first; e; e = e.warpzone_next)
800 if (e.warpzone_reconnecting)
802 for (entity e = warpzone_first; e; e = e.warpzone_next)
803 if (e.warpzone_reconnecting || e.enemy.warpzone_reconnecting)
805}
806
807spawnfunc(trigger_warpzone_reconnect)
808{
810}
811
812spawnfunc(target_warpzone_reconnect)
813{
814 spawnfunc_trigger_warpzone_reconnect(this); // both names make sense here :(
815}
816
818{
819#ifndef WARPZONE_DONT_FIX_VANGLE
820 if (IS_REAL_CLIENT(this))
821 if (this.v_angle.z <= 360) // if not already adjusted
822 if (time - CS(this).ping * 0.001 < this.warpzone_teleport_time)
823 {
825 this.v_angle_z += 720; // mark as adjusted
826 }
827#endif
828}
829
830#endif
void bot_aim_reset(entity this)
Definition aim.qc:134
#define BIT(n)
Only ever assign into the first 24 bits in QC (so max is BIT(23)).
Definition bits.qh:8
var entity(vector mins, vector maxs,.entity tofield) findbox_tofield_OrFallback
float ping
Definition main.qh:169
int spawnflags
Definition ammo.qh:15
#define setmodel(this, m)
Definition model.qh:26
#define IS_NOT_A_CLIENT(s)
Definition player.qh:243
#define PHYS_INPUT_FRAMETIME
Definition player.qh:254
vector v_angle
Definition player.qh:236
#define PHYS_INPUT_ANGLES(s)
Definition player.qh:249
#define IS_PLAYER(s)
Definition player.qh:242
const int FL_ONGROUND
Definition constants.qh:78
const float MOVE_NOMONSTERS
float trace_dphitcontents
const float VF_CL_VIEWANGLES
entity trace_ent
float modelindex
float frametime
const float MOVE_NORMAL
vector mins
float trace_dpstartcontents
const float SOLID_NOT
string trace_dphittexturename
float effects
float time
vector trace_endpos
float checkpvs(vector viewpos, entity viewee)
float trace_startsolid
vector maxs
float nextthink
float trace_inopen
float MOVE_WORLDONLY
float trace_dphitq3surfaceflags
const float EF_NODEPTHTEST
vector origin
float trace_fraction
float solid
float trace_allsolid
const float SOLID_BSP
vector trace_plane_normal
float trace_plane_dist
float trace_inwater
#define use
const int EF_TELEPORT_BIT
void SUB_Remove(entity this)
Remove entity.
Definition defer.qh:12
#define MAKE_VECTORS(angles, forward, right, up)
Same as the makevectors builtin but uses the provided locals instead of the v_* globals.
ent angles
Definition ent_cs.qc:146
model
Definition ent_cs.qc:164
WriteByte(chan, ent.angles.y/DEC_FACTOR)
ERASEABLE entity IL_PUSH(IntrusiveList this, entity it)
Push to tail.
#define IL_EACH(this, cond, body)
int SendFlags
Definition net.qh:159
const int MSG_ENTITY
Definition net.qh:156
#define WriteHeader(to, id)
Definition net.qh:265
void WarpZone_Touch(entity this, entity toucher)
Definition server.qc:181
void WarpZone_SetUp(entity e, vector my_org, vector my_ang, vector other_org, vector other_ang)
Definition common.qc:60
void WarpZone_RefSys_Add(entity me, entity wz)
Definition common.qc:705
entity WarpZone_Find(vector mi, vector ma)
Definition common.qc:158
bool WarpZoneLib_ExactTrigger_Touch(entity this, entity toucher, bool touchfunc)
Definition common.qc:789
float WarpZone_PlaneDist(entity wz, vector v)
Definition common.qc:476
void WarpZone_Camera_SetUp(entity e, vector my_org, vector my_ang)
Definition common.qc:89
vector WarpZone_TransformVAngles(entity wz, vector ang)
Definition common.qc:501
vector WarpZone_TransformVelocity(entity wz, vector v)
Definition common.qc:491
vector WarpZone_TransformAngles(entity wz, vector v)
Definition common.qc:496
vector WarpZone_TransformOrigin(entity wz, vector v)
Definition common.qc:486
float WarpZone_TargetPlaneDist(entity wz, vector v)
Definition common.qc:481
int WarpZoneLib_MoveOutOfSolid(entity e)
Definition common.qc:822
#define EXACTTRIGGER_TOUCH(e, t)
Definition common.qh:118
#define BITSET_ASSIGN(a, b)
Definition common.qh:107
float warpzone_fadestart
Definition common.qh:24
float warpzone_cameras_exist
Definition common.qh:13
vector warpzone_targetorigin
Definition common.qh:20
float warpzone_fadeend
Definition common.qh:25
#define BITCLR_ASSIGN(a, b)
Definition common.qh:104
vector warpzone_origin
Definition common.qh:17
float warpzone_isboxy
Definition common.qh:15
vector warpzone_targetangles
Definition common.qh:21
IntrusiveList g_warpzones
Definition common.qh:6
float warpzone_warpzones_exist
Definition common.qh:12
vector warpzone_angles
Definition common.qh:18
#define BITXOR_ASSIGN(a, b)
Definition common.qh:110
#define LOG_INFO(...)
Definition log.qh:62
#define LOG_TRACE(...)
Definition log.qh:74
float bound(float min, float value, float max)
entity find(entity start,.string field, string match)
float random(void)
float vlen(vector v)
void WriteShort(float data, float dest, float desto)
vector vectoangles(vector v)
string vtos(vector v)
vector normalize(vector v)
float max(float f,...)
float modelscale
Definition models.qh:3
const int MOVETYPE_NONE
Definition movetypes.qh:129
const int MOVETYPE_FOLLOW
Definition movetypes.qh:141
entity aiment
Definition movetypes.qh:90
string string_null
Definition nil.qh:9
f1
Definition all.inc:566
#define NULL
Definition post.qh:14
#define error
Definition pre.qh:6
float scale
Definition projectile.qc:14
#define setSendEntity(e, f)
#define setthink(e, f)
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 settouch(e, f)
Definition self.qh:77
IntrusiveList g_projectiles
Definition common.qh:58
float warpzone_initialized
Definition server.qc:637
void WarpZone_Think(entity this)
Definition server.qc:714
void WarpZone_InitStep_FindOriginTarget(entity this)
Definition server.qc:415
vector warpzone_oldvelocity
Definition server.qc:31
vector warpzone_save_eangles
Definition server.qc:28
void WarpZone_StartFrame()
Definition server.qc:733
bool WarpZone_Camera_Send(entity this, entity to, int sf)
Definition server.qc:264
bool WarpZone_Teleported_Send(entity this, entity to, int sf)
Definition server.qc:72
entity warpzone_teleport_zone
Definition server.qc:34
void WarpZone_TeleportPlayer(entity teleporter, entity player, vector to, vector to_angles, vector to_velocity)
Definition server.qc:43
float WarpZone_Projectile_Touch(entity this, entity toucher)
Definition server.qc:344
vector warpzone_oldangles
Definition server.qc:31
entity warpzone_position_first
Definition server.qc:639
entity warpzone_camera_first
Definition server.qc:640
vector warpzone_save_origin
Definition server.qc:25
float warpzone_teleport_time
Definition server.qc:32
float warpzone_teleport_finishtime
Definition server.qc:33
vector warpzone_save_angles
Definition server.qc:26
void WarpZoneCamera_InitStep_FindTarget(entity this)
Definition server.qc:467
vector warpzone_save_eorigin
Definition server.qc:27
void WarpZones_Reconnect()
Definition server.qc:702
void WarpZoneCamera_Think(entity this)
Definition server.qc:451
entity warpzone_next
Definition server.qc:641
bool visible_to_some_client(entity ent)
Definition server.qc:780
#define WarpZone_StoreProjectileData(e_)
Definition server.qc:36
float warpzone_reconnecting
Definition server.qc:779
void WarpZone_InitStep_FindTarget(entity this)
Definition server.qc:586
void WarpZone_InitStep_UpdateTransform(entity this)
Definition server.qc:497
float WarpZone_Teleport(entity wz, entity player, float f0, float f1)
Definition server.qc:80
void WarpZone_InitStep_ClearTarget(entity this)
Definition server.qc:579
void WarpZonePosition_InitStep_FindTarget(entity this)
Definition server.qc:429
bool autocvar_sv_warpzone_allow_selftarget
Definition server.qc:17
void WarpZone_PlayerPhysics_FixVAngle(entity this)
Definition server.qc:817
vector warpzone_oldorigin
Definition server.qc:31
void WarpZone_InitStep_FinalizeTransform(entity this)
Definition server.qc:616
void WarpZone_Touch(entity this, entity toucher)
Definition server.qc:181
void trigger_warpzone_reconnect_use(entity this, entity actor, entity trigger)
Definition server.qc:785
bool WarpZone_Send(entity this, entity to, int sf)
Definition server.qc:226
bool WarpZone_Projectile_Touch_ImpactFilter_Callback(entity this, entity toucher)
Definition common.qc:150
void WarpZone_PostInitialize_Callback()
Definition main.qc:518
entity warpzone_first
Definition server.qh:4
#define spawnfunc(id)
Definition spawnfunc.qh:107
ClientState CS(Client this)
Definition state.qh:47
string killtarget
Definition subs.qh:48
entity enemy
Definition sv_ctf.qh:152
entity Simple_TeleportPlayer(entity teleporter, entity player)
void WarpZone_PostTeleportPlayer_Callback(entity pl)
entity Teleport_Find(vector mi, vector ma)
void SUB_UseTargets_SkipTargets(entity this, entity actor, entity trigger, int skiptargets)
Definition triggers.qc:346
string targetname
Definition triggers.qh:56
string target
Definition triggers.qh:55
void WarpZoneLib_ExactTrigger_Init(entity this, bool unsetmodel)
Definition util_server.qc:8
#define IS_OBSERVER(v)
Definition utils.qh:11
#define IS_REAL_CLIENT(v)
Definition utils.qh:17
#define FOREACH_CLIENT(cond, body)
Definition utils.qh:52
#define IS_VEHICLE(v)
Definition utils.qh:24
#define IS_BOT_CLIENT(v)
want: (IS_CLIENT(v) && !IS_REAL_CLIENT(v))
Definition utils.qh:15
#define vdist(v, cmp, f)
Vector distance comparison, avoids sqrt().
Definition vector.qh:8
#define cross(a, b)
Definition vector.qh:25