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