Xonotic QuakeC
The free, fast arena FPS with crisp movement and a wide array of weapons
jumppads.qc File Reference
Include dependency graph for jumppads.qc:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

bool jumppad_push (entity this, entity targ, bool is_velocity_pad)
 spawnfunc (info_notnull)
 spawnfunc (target_position)
 spawnfunc (target_push)
 spawnfunc (trigger_push)
 spawnfunc (trigger_push_velocity)
void target_push_init (entity this)
void target_push_link (entity this)
bool target_push_send (entity this, entity to, float sf)
void target_push_use (entity this, entity actor, entity trigger)
vector trigger_push_calculatevelocity (vector org, entity tgt, float ht, entity pushed_entity)
void trigger_push_findtarget (entity this)
float trigger_push_get_push_time (entity this, vector endpos)
vector trigger_push_get_start_point (entity this)
void trigger_push_link (entity this)
float trigger_push_send (entity this, entity to, float sf)
bool trigger_push_test (entity this, entity item)
bool trigger_push_testorigin (entity tracetest_ent, entity targ, entity jp, vector org)
bool trigger_push_testorigin_for_item (entity tracetest_ent, entity item, vector org)
void trigger_push_touch (entity this, entity toucher)
void trigger_push_updatelink (entity this)
void trigger_push_use (entity this, entity actor, entity trigger)
vector trigger_push_velocity_calculatevelocity (entity this, vector org, entity tgt, float speed, float count, entity pushed_entity, bool already_pushed)
void trigger_push_velocity_link (entity this)
float trigger_push_velocity_send (entity this, entity to, float sf)
void trigger_push_velocity_think (entity this)
void trigger_push_velocity_touch (entity this, entity toucher)

Function Documentation

◆ jumppad_push()

bool jumppad_push ( entity this,
entity targ,
bool is_velocity_pad )

Definition at line 264 of file jumppads.qc.

265{
266 if (!isPushable(targ))
267 return false;
268
269 vector org = targ.origin;
270
272 org = (this.absmin + this.absmax) * 0.5;
273
274 bool already_pushed = false;
275 if(is_velocity_pad) // remember velocity jump pads
276 {
277 if(this == targ.last_pushed || (targ.last_pushed && !STAT(Q3COMPAT, targ))) // if q3compat is active overwrite last stored jump pad, otherwise ignore
278 {
279 already_pushed = true;
280 }
281 else
282 {
283 targ.last_pushed = this; // may be briefly out of sync between client and server if client prediction is toggled
284
285 #ifdef SVQC
287 this.nextthink = time;
288 #endif
289 }
290 }
291
292 if(this.enemy)
293 {
294 if(!is_velocity_pad)
295 {
296 targ.velocity = trigger_push_calculatevelocity(org, this.enemy, this.height, targ);
297 }
298 else
299 {
300 targ.velocity = trigger_push_velocity_calculatevelocity(this, org, this.enemy, this.speed, this.count, targ, already_pushed);
301 }
302 }
303 else if(this.target && this.target != "")
304 {
305 entity e;
307 for(e = NULL; (e = find(e, targetname, this.target)); )
308 {
309 if(e.cnt)
310 RandomSelection_AddEnt(e, e.cnt, 1);
311 else
312 RandomSelection_AddEnt(e, 1, 1);
313 }
314 if(!is_velocity_pad)
315 {
317 }
318 else
319 {
320 targ.velocity = trigger_push_velocity_calculatevelocity(this, org, RandomSelection_chosen_ent, this.speed, this.count, targ, already_pushed);
321 }
322 }
323 else
324 {
325 if(!is_velocity_pad)
326 {
327 targ.velocity = this.movedir;
328 }
329 else
330 {
331#ifdef SVQC
332 objerror (this, "Jumppad with no target");
333#endif
334 return false;
335 }
336 }
337
338 if(!is_velocity_pad) UNSET_ONGROUND(targ);
339
340#ifdef CSQC
341 if (targ.flags & FL_PROJECTILE)
342 {
343 targ.angles = vectoangles (targ.velocity);
344 switch(targ.move_movetype)
345 {
346 case MOVETYPE_FLY:
348 targ.gravity = 1;
349 break;
352 targ.gravity = 1;
353 break;
354 }
355 }
356#endif
357
358#ifdef SVQC
359 if (IS_PLAYER(targ))
360 {
361 // reset tracking of oldvelocity for impact damage (sudden velocity changes)
362 targ.oldvelocity = targ.velocity;
363
364 // prevent sound spam when a player hits the jumppad more than once
365 // or when a dead player gets stuck in the jumppad for some reason
366 if(!already_pushed && this.pushltime < time && !(IS_DEAD(targ) && targ.velocity == '0 0 0'))
367 {
368 if (Q3COMPAT_COMMON && this.classname == "target_push")
369 this.pushltime = time + 1.5;
370 else
371 {
372 // flash when activated
373 Send_Effect(EFFECT_JUMPPAD, targ.origin, targ.velocity, 1);
374 this.pushltime = time + 0.2;
375 }
376 _sound (targ, CH_TRIGGER, this.noise, VOL_BASE, ATTEN_NORM);
377 }
378
379 if(IS_REAL_CLIENT(targ) || IS_BOT_CLIENT(targ))
380 {
381 bool found = false;
382 for(int i = 0; i < targ.jumppadcount && i < NUM_JUMPPADSUSED; ++i)
383 if(targ.(jumppadsused[i]) == this)
384 found = true;
385 if(!found)
386 {
387 targ.(jumppadsused[targ.jumppadcount % NUM_JUMPPADSUSED]) = this;
388 targ.jumppadcount = targ.jumppadcount + 1;
389 }
390
391 if(IS_REAL_CLIENT(targ))
392 {
393 if(this.message)
394 centerprint(targ, this.message);
395 }
396 else
397 {
398 targ.lastteleporttime = time;
399 targ.lastteleport_origin = targ.origin;
400 }
401
402 if (!IS_DEAD(targ))
404 }
405 else
406 targ.jumppadcount = 1;
407
408 // reset tracking of who pushed you into a hazard (for kill credit)
409 targ.pushltime = 0;
410 targ.istypefrag = 0;
411 }
412
413 if(this.enemy.target)
414 SUB_UseTargets(this.enemy, targ, this);
415
416 if (targ.flags & FL_PROJECTILE)
417 {
418 targ.angles = vectoangles (targ.velocity);
419 targ.com_phys_gravity_factor = 1;
420 switch(targ.move_movetype)
421 {
422 case MOVETYPE_FLY:
424 targ.gravity = 1;
425 break;
428 targ.gravity = 1;
429 break;
430 }
432 }
433#endif
434
435 return true;
436}
void animdecide_setaction(entity e, float action, float restart)
const int ANIMACTION_JUMP
float height
Definition bobbing.qc:3
var entity(vector mins, vector maxs,.entity tofield) findbox_tofield_OrFallback
string message
Definition powerups.qc:19
float count
Definition powerups.qc:22
int spawnflags
Definition ammo.qh:15
#define IS_DEAD(s)
Definition player.qh:245
#define IS_PLAYER(s)
Definition player.qh:243
#define Q3COMPAT_COMMON
Definition stats.qh:368
const int FL_PROJECTILE
Definition constants.qh:85
string classname
float time
float nextthink
vector absmax
vector absmin
void UpdateCSQCProjectile(entity e)
float speed
Definition dynlight.qc:9
void Send_Effect(entity eff, vector eff_loc, vector eff_vel, int eff_cnt)
Definition all.qc:124
vector trigger_push_calculatevelocity(vector org, entity tgt, float ht, entity pushed_entity)
Definition jumppads.qc:32
void trigger_push_velocity_think(entity this)
Definition jumppads.qc:246
vector trigger_push_velocity_calculatevelocity(entity this, vector org, entity tgt, float speed, float count, entity pushed_entity, bool already_pushed)
Definition jumppads.qc:140
void SUB_UseTargets(entity this, entity actor, entity trigger)
Definition triggers.qc:344
const int NUM_JUMPPADSUSED
Definition jumppads.qh:27
float pushltime
Definition jumppads.qh:21
const int PUSH_STATIC
Definition jumppads.qh:6
#define STAT(...)
Definition stats.qh:82
vector movedir
Definition viewloc.qh:18
entity find(entity start,.string field, string match)
vector vectoangles(vector v)
void centerprint(string text,...)
void set_movetype(entity this, int mt)
Definition movetypes.qc:4
const int MOVETYPE_BOUNCEMISSILE
Definition movetypes.qh:140
#define UNSET_ONGROUND(s)
Definition movetypes.qh:18
const int MOVETYPE_FLY
Definition movetypes.qh:134
const int MOVETYPE_TOSS
Definition movetypes.qh:135
const int MOVETYPE_BOUNCE
Definition movetypes.qh:139
#define NULL
Definition post.qh:14
#define objerror
Definition pre.qh:8
ERASEABLE void RandomSelection_Init()
Definition random.qc:4
#define RandomSelection_AddEnt(e, weight, priority)
Definition random.qh:14
entity RandomSelection_chosen_ent
Definition random.qh:5
#define setthink(e, f)
vector
Definition self.qh:92
vector org
Definition self.qh:92
const int CH_TRIGGER
Definition sound.qh:12
const float VOL_BASE
Definition sound.qh:36
#define _sound(e, c, s, v, a)
Definition sound.qh:43
const float ATTEN_NORM
Definition sound.qh:30
string noise
Definition subs.qh:83
entity enemy
Definition sv_ctf.qh:153
bool isPushable(entity e)
Definition triggers.qc:3
string targetname
Definition triggers.qh:56
string target
Definition triggers.qh:55
#define IS_REAL_CLIENT(v)
Definition utils.qh:17
#define IS_BOT_CLIENT(v)
want: (IS_CLIENT(v) && !IS_REAL_CLIENT(v))
Definition utils.qh:15

References _sound, absmax, absmin, ANIMACTION_JUMP, animdecide_setaction(), ATTEN_NORM, centerprint(), CH_TRIGGER, classname, count, enemy, entity(), find(), FL_PROJECTILE, height, IS_BOT_CLIENT, IS_DEAD, IS_PLAYER, IS_REAL_CLIENT, isPushable(), message, movedir, MOVETYPE_BOUNCE, MOVETYPE_BOUNCEMISSILE, MOVETYPE_FLY, MOVETYPE_TOSS, nextthink, noise, NULL, NUM_JUMPPADSUSED, objerror, org, PUSH_STATIC, pushltime, Q3COMPAT_COMMON, RandomSelection_AddEnt, RandomSelection_chosen_ent, RandomSelection_Init(), Send_Effect(), set_movetype(), setthink, spawnflags, speed, STAT, SUB_UseTargets(), target, targetname, time, trigger_push_calculatevelocity(), trigger_push_velocity_calculatevelocity(), trigger_push_velocity_think(), UNSET_ONGROUND, UpdateCSQCProjectile(), vectoangles(), vector, and VOL_BASE.

Referenced by target_push_use(), trigger_push_touch(), and trigger_push_velocity_touch().

◆ spawnfunc() [1/5]

spawnfunc ( info_notnull )

Definition at line 937 of file jumppads.qc.

938{
939 target_push_init(this);
940}
void target_push_init(entity this)
Definition jumppads.qc:894

References target_push_init().

◆ spawnfunc() [2/5]

spawnfunc ( target_position )

Definition at line 941 of file jumppads.qc.

942{
943 target_push_init(this);
944}

References target_push_init().

◆ spawnfunc() [3/5]

spawnfunc ( target_push )

Definition at line 901 of file jumppads.qc.

902{
903 target_push_init(this); // normal push target behaviour can be combined with a legacy pusher?
904 this.use = target_push_use;
905
906 if(this.target && this.target != "") // Q3 or old style Nexuiz pusher
907 {
908 entity trigger_ent = findchain(target, this.targetname);
909 if (trigger_ent)
910 {
911 // apply size of its trigger entity so that it can be tested like a conventional
912 // trigger_push jumppad and spawn an usable box waypoyint
913 this.absmin = trigger_ent.absmin;
914 this.absmax = trigger_ent.absmax;
915 }
916 IL_PUSH(g_jumppads, this);
918 }
919 else // Q3 .angles and .speed pusher
920 {
921 if (!this.speed)
922 this.speed = 1000;
923 SetMovedir(this); // this clears .angles so it must be after target_push_init()
924 this.movedir *= this.speed;
925 }
926
927 if (!this.noise)
928 {
930 this.noise = "sound/misc/windfly.wav"; // Q3 mappers provide this, it's not in pak0
931 else
932 this.noise = "misc/jumppad.wav";
933 }
934 precache_sound (this.noise);
935}
const int INITPRIO_FINDTARGET
Definition constants.qh:96
#define use
ERASEABLE entity IL_PUSH(IntrusiveList this, entity it)
Push to tail.
void trigger_push_findtarget(entity this)
Definition jumppads.qc:753
void target_push_use(entity this, entity actor, entity trigger)
Definition jumppads.qc:879
#define Q3_TARGET_PUSH_JUMPPAD
Definition jumppads.qh:16
IntrusiveList g_jumppads
Definition jumppads.qh:18
string precache_sound(string sample)
void SetMovedir(entity this)
Definition subs.qc:540
void InitializeEntity(entity e, void(entity this) func, int order)
Definition world.qc:2209

References absmax, absmin, entity(), g_jumppads, IL_PUSH(), InitializeEntity(), INITPRIO_FINDTARGET, movedir, noise, precache_sound(), Q3_TARGET_PUSH_JUMPPAD, Q3COMPAT_COMMON, SetMovedir(), spawnflags, speed, target, target_push_init(), target_push_use(), targetname, trigger_push_findtarget(), and use.

◆ spawnfunc() [4/5]

spawnfunc ( trigger_push )

Definition at line 815 of file jumppads.qc.

816{
817 SetMovedir(this);
818
821 this.active = ACTIVE_ACTIVE;
822 this.use = trigger_push_use;
824
825 // normal push setup
826 if (!this.speed)
827 this.speed = 1000;
828 this.movedir = this.movedir * this.speed * 10;
829
830 if (!this.noise)
831 this.noise = "misc/jumppad.wav";
832 precache_sound (this.noise);
833
834 trigger_push_link(this); // link it now
835
836 IL_PUSH(g_jumppads, this);
837
838 // this must be called to spawn the teleport waypoints for bots
840}
float effects
const float EF_NODEPTHTEST
int active
Definition defs.qh:34
const int ACTIVE_ACTIVE
Definition defs.qh:37
void trigger_push_use(entity this, entity actor, entity trigger)
Definition jumppads.qc:6
void trigger_push_link(entity this)
Definition jumppads.qc:793
void trigger_push_touch(entity this, entity toucher)
Definition jumppads.qc:438
#define BITSET_ASSIGN(a, b)
Definition common.qh:104
#define settouch(e, f)
Definition self.qh:73
void WarpZoneLib_ExactTrigger_Init(entity this, bool unsetmodel)

References active, ACTIVE_ACTIVE, BITSET_ASSIGN, EF_NODEPTHTEST, effects, g_jumppads, IL_PUSH(), InitializeEntity(), INITPRIO_FINDTARGET, movedir, noise, precache_sound(), SetMovedir(), settouch, speed, trigger_push_findtarget(), trigger_push_link(), trigger_push_touch(), trigger_push_use(), use, and WarpZoneLib_ExactTrigger_Init().

◆ spawnfunc() [5/5]

spawnfunc ( trigger_push_velocity )

Definition at line 849 of file jumppads.qc.

850{
853 this.active = ACTIVE_ACTIVE;
854 this.use = trigger_push_use;
856
857 // normal push setup
858 if (!this.noise)
859 this.noise = "misc/jumppad.wav";
860 precache_sound (this.noise);
861
862 trigger_push_velocity_link(this); // link it now
863}
void trigger_push_velocity_link(entity this)
Definition jumppads.qc:798
void trigger_push_velocity_touch(entity this, entity toucher)
Definition jumppads.qc:461

References active, ACTIVE_ACTIVE, BITSET_ASSIGN, EF_NODEPTHTEST, effects, noise, precache_sound(), settouch, trigger_push_use(), trigger_push_velocity_link(), trigger_push_velocity_touch(), use, and WarpZoneLib_ExactTrigger_Init().

◆ target_push_init()

void target_push_init ( entity this)

Definition at line 894 of file jumppads.qc.

895{
896 this.mangle = this.angles;
897 setorigin(this, this.origin);
898 target_push_link(this);
899}
vector origin
ent angles
Definition ent_cs.qc:121
void target_push_link(entity this)
Definition jumppads.qc:887
vector mangle
Definition subs.qh:51

References angles, entity(), mangle, origin, and target_push_link().

Referenced by spawnfunc(), spawnfunc(), spawnfunc(), and spawnfunc().

◆ target_push_link()

void target_push_link ( entity this)

Definition at line 887 of file jumppads.qc.

888{
890 Net_LinkEntity(this, false, 0, target_push_send);
891 //this.SendFlags |= 1; // update
892}
bool target_push_send(entity this, entity to, float sf)
Definition jumppads.qc:866
void Net_LinkEntity(entity e, bool docull, float dt, bool(entity this, entity to, int sendflags) sendfunc)
Definition net.qh:123

References BITSET_ASSIGN, EF_NODEPTHTEST, effects, entity(), Net_LinkEntity(), and target_push_send().

Referenced by target_push_init().

◆ target_push_send()

bool target_push_send ( entity this,
entity to,
float sf )

Definition at line 866 of file jumppads.qc.

867{
868 WriteHeader(MSG_ENTITY, ENT_CLIENT_TARGET_PUSH);
869
870 WriteByte(MSG_ENTITY, this.cnt);
872 WriteVector(MSG_ENTITY, this.origin);
873
874 WriteAngleVector(MSG_ENTITY, this.angles);
875
876 return true;
877}
float cnt
Definition powerups.qc:24
const int MSG_ENTITY
Definition net.qh:115
#define WriteHeader(to, id)
Definition net.qh:221
void WriteString(string data, float dest, float desto)
void WriteByte(float data, float dest, float desto)

References angles, cnt, entity(), MSG_ENTITY, origin, targetname, WriteByte(), WriteHeader, and WriteString().

Referenced by target_push_link().

◆ target_push_use()

void target_push_use ( entity this,
entity actor,
entity trigger )

Definition at line 879 of file jumppads.qc.

880{
881 if(trigger.classname == "trigger_push" || trigger == this)
882 return; // WTF, why is this a thing
883
884 jumppad_push(this, actor, false);
885}
bool jumppad_push(entity this, entity targ, bool is_velocity_pad)
Definition jumppads.qc:264

References entity(), and jumppad_push().

Referenced by spawnfunc().

◆ trigger_push_calculatevelocity()

vector trigger_push_calculatevelocity ( vector org,
entity tgt,
float ht,
entity pushed_entity )

Definition at line 32 of file jumppads.qc.

33{
34 float grav, sdist, zdist, vs, vz, jumpheight;
35 vector sdir, torg;
36
37 torg = tgt.origin + (tgt.mins + tgt.maxs) * 0.5;
38
39 grav = PHYS_GRAVITY(NULL);
40 if(pushed_entity && pushed_entity.gravity)
41 grav *= pushed_entity.gravity;
42
43 // Q3 has frametime-dependent gravity, but its trigger_push velocity calculation doesn't account for that.
44 // This discrepancy can be simulated accurately which ensures that all entities will arrive
45 // where they would in Q3 with gravity 800 at 125fps, even if entity-specific gravity is applied.
46 // This can be hard-coded because we don't support the Q3 world.gravity field at this time.
47 // See physicsCPMA.cfg for maths and test results.
49 grav /= 750/800; // exact float, unlike 800/750
50
51 zdist = torg.z - org.z;
52 sdist = vlen(torg - org - zdist * '0 0 1');
53 sdir = normalize(torg - org - zdist * '0 0 1');
54
55 // how high do we need to push the player?
56 jumpheight = fabs(ht);
57 if(zdist > 0)
58 jumpheight = jumpheight + zdist;
59
60 /*
61 STOP.
62
63 You will not understand the following equations anyway...
64 But here is what I did to get them.
65
66 I used the functions
67
68 s(t) = t * vs
69 z(t) = t * vz - 1/2 grav t^2
70
71 and solved for:
72
73 s(ti) = sdist
74 z(ti) = zdist
75 max(z, ti) = jumpheight
76
77 From these three equations, you will find the three parameters vs, vz
78 and ti.
79 */
80
81 // push them so high...
82 vz = sqrt(fabs(2 * grav * jumpheight)); // NOTE: sqrt(positive)!
83
84 // we start with downwards velocity only if it's a downjump and the jump apex should be outside the jump!
85 if(ht < 0)
86 if(zdist < 0)
87 vz = -vz;
88
89 vector solution;
90 solution = solve_quadratic(0.5 * grav, -vz, zdist); // equation "z(ti) = zdist"
91 // ALWAYS solvable because jumpheight >= zdist
92 if(!solution.z)
93 solution_y = solution.x; // just in case it is not solvable due to roundoff errors, assume two equal solutions at their center (this is mainly for the usual case with ht == 0)
94 if(zdist == 0)
95 solution_x = solution.y; // solution_x is 0 in this case, so don't use it, but rather use solution_y (which will be sqrt(0.5 * jumpheight / grav), actually)
96
97 float flighttime;
98 if(zdist < 0)
99 {
100 // down-jump
101 if(ht < 0)
102 {
103 // almost straight line type
104 // jump apex is before the jump
105 // we must take the larger one
106 flighttime = solution.y;
107 }
108 else
109 {
110 // regular jump
111 // jump apex is during the jump
112 // we must take the larger one too
113 flighttime = solution.y;
114 }
115 }
116 else
117 {
118 // up-jump
119 if(ht < 0)
120 {
121 // almost straight line type
122 // jump apex is after the jump
123 // we must take the smaller one
124 flighttime = solution.x;
125 }
126 else
127 {
128 // regular jump
129 // jump apex is during the jump
130 // we must take the larger one
131 flighttime = solution.y;
132 }
133 }
134 vs = sdist / flighttime;
135
136 // finally calculate the velocity
137 return sdir * vs + '0 0 1' * vz;
138}
ERASEABLE vector solve_quadratic(float a, float b, float c)
ax^2 + bx + c = 0
Definition math.qh:304
float vlen(vector v)
float sqrt(float f)
vector normalize(vector v)
float fabs(float f)
#define PHYS_GRAVITY(s)
Definition movetypes.qh:53

References entity(), fabs(), normalize(), NULL, org, PHYS_GRAVITY, Q3COMPAT_COMMON, solve_quadratic(), sqrt(), trigger_push_calculatevelocity(), vector, and vlen().

Referenced by jumppad_push(), trigger_push_calculatevelocity(), trigger_push_get_push_time(), trigger_push_test(), trigger_push_velocity_calculatevelocity(), W_Nexball_Attack2(), and W_Porto_Fail().

◆ trigger_push_findtarget()

void trigger_push_findtarget ( entity this)

Definition at line 753 of file jumppads.qc.

754{
755 trigger_push_test(this, NULL);
756}
bool trigger_push_test(entity this, entity item)
Definition jumppads.qc:579

References entity(), NULL, and trigger_push_test().

Referenced by spawnfunc(), and spawnfunc().

◆ trigger_push_get_push_time()

float trigger_push_get_push_time ( entity this,
vector endpos )

Definition at line 541 of file jumppads.qc.

542{
544
545 float grav = PHYS_GRAVITY(NULL);
546
547 entity t = this.enemy;
548 if (t)
549 {
550 entity e = spawn();
551 setsize(e, PL_MIN_CONST, PL_MAX_CONST);
554 vector v2 = trigger_push_calculatevelocity(endpos, t, this.height, e);
555 delete(e);
556 return (v.z + v2.z) / grav;
557 }
558 else if (!(this.target && this.target != ""))
559 {
560 if (!this.team)
561 {
562 vector v = this.movedir;
563
564 float t = v.z / grav;
565 float jump_height = 1/2 * grav * (t ** 2);
566 float remaining_height = org.z + jump_height - endpos.z;
567 float v2_z = sqrt(2 * grav * remaining_height);
568
569 return (v.z + v2_z) / grav;
570 }
571 }
572 return 0;
573}
int team
Definition main.qh:188
const vector PL_MIN_CONST
Definition constants.qh:56
const vector PL_MAX_CONST
Definition constants.qh:55
float DPCONTENTS_BOTCLIP
float DPCONTENTS_SOLID
float DPCONTENTS_BODY
float DPCONTENTS_PLAYERCLIP
#define spawn
vector trigger_push_get_start_point(entity this)
Definition jumppads.qc:533

References DPCONTENTS_BODY, DPCONTENTS_BOTCLIP, DPCONTENTS_PLAYERCLIP, DPCONTENTS_SOLID, enemy, entity(), height, movedir, NULL, org, PHYS_GRAVITY, PL_MAX_CONST, PL_MIN_CONST, spawn, sqrt(), target, team, trigger_push_calculatevelocity(), trigger_push_get_start_point(), and vector.

Referenced by waypoint_addlink_for_custom_jumppad().

◆ trigger_push_get_start_point()

vector trigger_push_get_start_point ( entity this)

Definition at line 533 of file jumppads.qc.

534{
535 // calculate a typical start point for the jump
536 vector org = (this.absmin + this.absmax) * 0.5;
537 org.z = this.absmax.z - PL_MIN_CONST.z - 7;
538 return org;
539}

References absmax, absmin, entity(), org, PL_MIN_CONST, and vector.

Referenced by trigger_push_get_push_time(), and trigger_push_test().

◆ trigger_push_link()

void trigger_push_link ( entity this)

Definition at line 793 of file jumppads.qc.

794{
796}
float trigger_push_send(entity this, entity to, float sf)
Definition jumppads.qc:759
void trigger_link(entity this, bool(entity this, entity to, int sendflags) sendfunc)
Definition triggers.qc:104

References entity(), trigger_link(), and trigger_push_send().

Referenced by spawnfunc().

◆ trigger_push_send()

float trigger_push_send ( entity this,
entity to,
float sf )

Definition at line 759 of file jumppads.qc.

760{
761 WriteHeader(MSG_ENTITY, ENT_CLIENT_TRIGGER_PUSH);
762
764 WriteInt24_t(MSG_ENTITY, this.spawnflags);
767
768 trigger_common_write(this, true);
769
770 return true;
771}
void WriteCoord(float data, float dest, float desto)
void trigger_common_write(entity this, bool withtarget)
Definition triggers.qc:110

References active, entity(), height, MSG_ENTITY, spawnflags, team, trigger_common_write(), WriteByte(), WriteCoord(), and WriteHeader.

Referenced by trigger_push_link().

◆ trigger_push_test()

bool trigger_push_test ( entity this,
entity item )

Definition at line 579 of file jumppads.qc.

580{
581#ifdef SVQC
583#endif
584
585 if (this.target)
586 {
587 int n = 0;
588#ifdef SVQC
589 vector vel = '0 0 0';
590#endif
591 for(entity t = NULL; (t = find(t, targetname, this.target)); )
592 {
593 ++n;
594#ifdef SVQC
595 if(t.move_movetype != MOVETYPE_NONE)
596 continue;
597
598 // bots can't tell teamed jumppads from normal ones
599 if (this.team)
600 continue;
601
602 entity e = spawn();
603 setsize(e, PL_MIN_CONST, PL_MAX_CONST);
605 e.velocity = trigger_push_calculatevelocity(org, t, this.height, e);
606
607 vel = e.velocity;
608 vector best_target = '0 0 0';
609 vector best_org = '0 0 0';
610 vector best_vel = '0 0 0';
611 bool valid_best_target = false;
612 if (item)
613 {
615 {
616 delete(e);
617 return false;
618 }
619 }
620 else
621 {
622 // optimization: if horizontal velocity is 0 then target is not good since the trajectory
623 // will definitely go back to the jumppad (horizontal velocity of best_vel can't be 0 anyway)
624 if ((e.velocity.x != 0 || e.velocity.y != 0)
625 && trigger_push_testorigin(e, t, this, org))
626 {
627 best_target = trace_endpos;
628 best_org = org;
629 best_vel = e.velocity;
630 valid_best_target = true;
631 }
632 }
633
634 vector new_org;
635 vector dist = t.origin - org;
636 if (dist.x || dist.y) // if not perfectly vertical
637 {
638 // test trajectory with different starting points, sometimes the trajectory
639 // starting from the jumppad origin can't reach the real destination
640 // and destination waypoint ends up near the jumppad itself
641 vector flatdir = normalize(dist - eZ * dist.z);
642 vector ofs = flatdir * 0.5 * min(fabs(this.absmax.x - this.absmin.x), fabs(this.absmax.y - this.absmin.y));
643 new_org = org + ofs;
644
645 LABEL(new_test)
646 e.velocity = trigger_push_calculatevelocity(new_org, t, this.height, e);
647 if (item)
648 {
649 if (!trigger_push_testorigin_for_item(e, item, new_org))
650 {
651 delete(e);
652 return false;
653 }
654 }
655 else
656 {
657 vel = e.velocity;
658 if (vdist(vec2(e.velocity), <, autocvar_sv_maxspeed))
659 e.velocity = autocvar_sv_maxspeed * flatdir;
660 if (trigger_push_testorigin(e, t, this, new_org) && (!valid_best_target || trace_endpos.z > best_target.z + 50))
661 {
662 best_target = trace_endpos;
663 best_org = new_org;
664 best_vel = vel;
665 valid_best_target = true;
666 }
667 }
668 if (ofs && new_org != org - ofs)
669 {
670 new_org = org - ofs;
671 goto new_test;
672 }
673 }
674
675 if (item)
676 {
677 delete(e);
678 return true;
679 }
680
681 if (valid_best_target)
682 {
683 if (!(boxesoverlap(this.absmin, this.absmax + eZ * 50, best_target + PL_MIN_CONST, best_target + PL_MAX_CONST)))
684 {
685 float velxy = vlen(vec2(best_vel));
686 float cost = vlen(vec2(t.origin - best_org)) / velxy;
687 if(velxy < autocvar_sv_maxspeed)
688 velxy = autocvar_sv_maxspeed;
689 cost += vlen(vec2(best_target - t.origin)) / velxy;
690 waypoint_spawnforteleporter(this, best_target, cost, e);
691 }
692 }
693 delete(e);
694#endif
695 }
696
697 if(item)
698 return false;
699
700 if(!n)
701 {
702 // no dest!
703#ifdef SVQC
704 objerror (this, "Jumppad with nonexistant target");
705#endif
706 return false;
707 }
708 else if(n == 1)
709 {
710 // exactly one dest - bots love that
711 if (!this.team)
712 this.enemy = find(NULL, targetname, this.target);
713 else // bots can't tell teamed jumppads from normal ones
714 this.enemy = NULL;
715 }
716 else
717 {
718 // have to use random selection every single time
719 this.enemy = NULL;
720 }
721
722 }
723#ifdef SVQC
724 else
725 {
726 if (!this.team)
727 {
728 entity e = spawn();
729 setsize(e, PL_MIN_CONST, PL_MAX_CONST);
731 setorigin(e, org);
732 e.velocity = this.movedir;
733 tracetoss(e, e);
734 if (item)
735 {
736 bool r = (trace_ent == item);
737 delete(e);
738 return r;
739 }
742 delete(e);
743 }
744 else if (item)
745 return false;
746 }
747
748 defer(this, 0.1, trigger_push_updatelink);
749#endif
750 return true;
751}
void waypoint_spawnforteleporter(entity e, vector destination, float timetaken, entity tracetest_ent)
float autocvar_sv_maxspeed
Definition player.qh:53
#define LABEL(id)
Definition compiler.qh:34
entity trace_ent
vector trace_endpos
void defer(entity this, float fdelay, void(entity) func)
Execute func() after time + fdelay.
Definition defer.qh:29
bool trigger_push_testorigin(entity tracetest_ent, entity targ, entity jp, vector org)
Definition jumppads.qc:477
bool trigger_push_testorigin_for_item(entity tracetest_ent, entity item, vector org)
Definition jumppads.qc:513
void trigger_push_updatelink(entity this)
Definition jumppads.qc:788
float min(float f,...)
const int MOVETYPE_NONE
Definition movetypes.qh:129
#define vdist(v, cmp, f)
Vector distance comparison, avoids sqrt()
Definition vector.qh:8
const vector eZ
Definition vector.qh:46
ERASEABLE float boxesoverlap(vector m1, vector m2, vector m3, vector m4)
requires that m2>m1 in all coordinates, and that m4>m3
Definition vector.qh:73
#define vec2(...)
Definition vector.qh:90

References absmax, absmin, autocvar_sv_maxspeed, boxesoverlap(), defer(), DPCONTENTS_BODY, DPCONTENTS_BOTCLIP, DPCONTENTS_PLAYERCLIP, DPCONTENTS_SOLID, enemy, entity(), eZ, fabs(), find(), height, LABEL, min(), movedir, MOVETYPE_NONE, normalize(), NULL, objerror, org, PL_MAX_CONST, PL_MIN_CONST, spawn, target, targetname, team, trace_endpos, trace_ent, trigger_push_calculatevelocity(), trigger_push_get_start_point(), trigger_push_testorigin(), trigger_push_testorigin_for_item(), trigger_push_updatelink(), vdist, vec2, vector, vlen(), and waypoint_spawnforteleporter().

Referenced by trigger_push_findtarget().

◆ trigger_push_testorigin()

bool trigger_push_testorigin ( entity tracetest_ent,
entity targ,
entity jp,
vector org )

Definition at line 477 of file jumppads.qc.

478{
479 setorigin(tracetest_ent, org);
480 tracetoss(tracetest_ent, tracetest_ent);
482 return false;
483
484 if (!jp.height)
485 {
486 // since tracetoss starting from jumppad's origin often fails when target
487 // is very close to real destination, start it directly from target's
488 // origin instead
489 vector ofs = '0 0 0';
490 if (vdist(vec2(tracetest_ent.velocity), <, autocvar_sv_maxspeed))
491 ofs = stepheightvec;
492
493 tracetest_ent.velocity.z = 0;
494 setorigin(tracetest_ent, targ.origin + ofs);
495 tracetoss(tracetest_ent, tracetest_ent);
496 if (trace_startsolid && ofs.z)
497 {
498 setorigin(tracetest_ent, targ.origin + ofs * 0.5);
499 tracetoss(tracetest_ent, tracetest_ent);
500 if (trace_startsolid && ofs.z)
501 {
502 setorigin(tracetest_ent, targ.origin);
503 tracetoss(tracetest_ent, tracetest_ent);
505 return false;
506 }
507 }
508 }
509 tracebox(trace_endpos, tracetest_ent.mins, tracetest_ent.maxs, trace_endpos - eZ * 1500, true, tracetest_ent);
510 return true;
511}
float trace_startsolid
vector stepheightvec
Definition navigation.qh:11

References autocvar_sv_maxspeed, entity(), eZ, org, stepheightvec, trace_endpos, trace_startsolid, vdist, vec2, and vector.

Referenced by trigger_push_test().

◆ trigger_push_testorigin_for_item()

bool trigger_push_testorigin_for_item ( entity tracetest_ent,
entity item,
vector org )

Definition at line 513 of file jumppads.qc.

514{
515 setorigin(tracetest_ent, org);
516 tracetoss(tracetest_ent, tracetest_ent);
517
519 return false;
520 if (trace_ent == item)
521 return true;
522
523 tracebox(trace_endpos, tracetest_ent.mins, tracetest_ent.maxs, trace_endpos - eZ * 1500, true, tracetest_ent);
524
525 if (trace_ent == item)
526 return true;
527
528 return false;
529}

References entity(), eZ, org, trace_endpos, trace_ent, trace_startsolid, and vector.

Referenced by trigger_push_test().

◆ trigger_push_touch()

void trigger_push_touch ( entity this,
entity toucher )

Definition at line 438 of file jumppads.qc.

439{
440 if (this.active == ACTIVE_NOT)
441 return;
442
443 if(this.team)
444 if(((this.spawnflags & INVERT_TEAMS) == 0) == (DIFF_TEAM(this, toucher)))
445 return;
446
448
449 noref bool success = jumppad_push(this, toucher, false);
450
451#ifdef SVQC
452 if (success && (this.spawnflags & PUSH_ONCE))
453 {
454 settouch(this, func_null);
455 setthink(this, SUB_Remove);
456 this.nextthink = time;
457 }
458#endif
459}
void SUB_Remove(entity this)
Remove entity.
Definition defer.qh:13
const int ACTIVE_NOT
Definition defs.qh:36
const int INVERT_TEAMS
Definition defs.qh:10
const int PUSH_ONCE
Definition jumppads.qh:4
#define EXACTTRIGGER_TOUCH(e, t)
Definition common.qh:115
var void func_null()
entity entity toucher
Definition self.qh:72
#define DIFF_TEAM(a, b)
Definition teams.qh:242

References active, ACTIVE_NOT, DIFF_TEAM, entity(), EXACTTRIGGER_TOUCH, func_null(), INVERT_TEAMS, jumppad_push(), nextthink, PUSH_ONCE, setthink, settouch, spawnflags, SUB_Remove(), team, time, and toucher.

Referenced by spawnfunc().

◆ trigger_push_updatelink()

void trigger_push_updatelink ( entity this)

Definition at line 788 of file jumppads.qc.

789{
791}
const int SF_TRIGGER_INIT
Definition defs.qh:22
int SendFlags
Definition net.qh:118

References entity(), SendFlags, and SF_TRIGGER_INIT.

Referenced by trigger_push_test().

◆ trigger_push_use()

void trigger_push_use ( entity this,
entity actor,
entity trigger )

Definition at line 6 of file jumppads.qc.

7{
8 if(teamplay)
9 {
10 this.team = actor.team;
12 }
13}
const int SF_TRIGGER_UPDATE
Definition defs.qh:23
bool teamplay
Definition teams.qh:59

References entity(), SendFlags, SF_TRIGGER_UPDATE, team, and teamplay.

Referenced by spawnfunc(), and spawnfunc().

◆ trigger_push_velocity_calculatevelocity()

vector trigger_push_velocity_calculatevelocity ( entity this,
vector org,
entity tgt,
float speed,
float count,
entity pushed_entity,
bool already_pushed )

Definition at line 140 of file jumppads.qc.

141{
142 bool is_playerdir_xy = boolean(this.spawnflags & PUSH_VELOCITY_PLAYERDIR_XY);
143 bool is_add_xy = boolean(this.spawnflags & PUSH_VELOCITY_ADD_XY);
144 bool is_playerdir_z = boolean(this.spawnflags & PUSH_VELOCITY_PLAYERDIR_Z);
145 bool is_add_z = boolean(this.spawnflags & PUSH_VELOCITY_ADD_Z);
146 bool is_bidirectional_xy = boolean(this.spawnflags & PUSH_VELOCITY_BIDIRECTIONAL_XY);
147 bool is_bidirectional_z = boolean(this.spawnflags & PUSH_VELOCITY_BIDIRECTIONAL_Z);
148 bool is_clamp_negative_adds = boolean(this.spawnflags & PUSH_VELOCITY_CLAMP_NEGATIVE_ADDS);
149
150 vector sdir = normalize(vec2(pushed_entity.velocity));
151 float zdir = pushed_entity.velocity.z;
152 if(zdir != 0) zdir = copysign(1, zdir);
153
154 vector vs_tgt = '0 0 0';
155 float vz_tgt = 0;
156 if (!is_playerdir_xy || !is_playerdir_z)
157 {
158 vector vel_tgt = trigger_push_calculatevelocity(org, tgt, 0, pushed_entity);
159 vs_tgt = vec2(vel_tgt);
160 vz_tgt = vel_tgt.z;
161
162 // bidirectional jump pads do not play nicely with xonotic's jump pad targets
163 if (is_bidirectional_xy)
164 {
165 if (normalize(vs_tgt) * sdir < 0)
166 {
167 vs_tgt *= -1;
168 }
169 }
170
171 if (is_bidirectional_z)
172 {
173 if (signbit(vz_tgt) != signbit(zdir))
174 {
175 vz_tgt *= -1;
176 }
177 }
178 }
179
180 vector vs;
181 if (is_playerdir_xy)
182 {
183 vs = sdir * speed;
184 }
185 else
186 {
187 vs = vs_tgt;
188 }
189
190 float vz;
191 if (is_playerdir_z)
192 {
193 vz = zdir * count;
194 }
195 else
196 {
197 vz = vz_tgt;
198 }
199
200 if (is_add_xy)
201 {
202 vector vs_add = vec2(pushed_entity.velocity);
203 if (already_pushed)
204 {
205 vs = vs_add;
206 }
207 else
208 {
209 vs += vs_add;
210
211 if (is_clamp_negative_adds)
212 {
213 if ((normalize(vs) * sdir) < 0)
214 {
215 vs = '0 0 0';
216 }
217 }
218 }
219 }
220
221 if (is_add_z)
222 {
223 float vz_add = pushed_entity.velocity.z;
224 if (already_pushed)
225 {
226 vz = vz_add;
227 }
228 else
229 {
230 vz += vz_add;
231
232 if (is_clamp_negative_adds)
233 {
234 if (signbit(vz) != signbit(zdir))
235 {
236 vz = 0;
237 }
238 }
239 }
240 }
241
242 return vs + '0 0 1' * vz;
243}
#define boolean(value)
Definition bool.qh:9
#define PUSH_VELOCITY_PLAYERDIR_Z
Definition jumppads.qh:10
#define PUSH_VELOCITY_ADD_Z
Definition jumppads.qh:11
#define PUSH_VELOCITY_PLAYERDIR_XY
Definition jumppads.qh:8
#define PUSH_VELOCITY_CLAMP_NEGATIVE_ADDS
Definition jumppads.qh:14
#define PUSH_VELOCITY_BIDIRECTIONAL_XY
Definition jumppads.qh:12
#define PUSH_VELOCITY_BIDIRECTIONAL_Z
Definition jumppads.qh:13
#define PUSH_VELOCITY_ADD_XY
Definition jumppads.qh:9
bool signbit(float e)
Definition mathlib.qc:43
float copysign(float e, float f)
Definition mathlib.qc:225

References boolean, copysign(), count, entity(), normalize(), org, PUSH_VELOCITY_ADD_XY, PUSH_VELOCITY_ADD_Z, PUSH_VELOCITY_BIDIRECTIONAL_XY, PUSH_VELOCITY_BIDIRECTIONAL_Z, PUSH_VELOCITY_CLAMP_NEGATIVE_ADDS, PUSH_VELOCITY_PLAYERDIR_XY, PUSH_VELOCITY_PLAYERDIR_Z, signbit(), spawnflags, speed, trigger_push_calculatevelocity(), vec2, and vector.

Referenced by jumppad_push().

◆ trigger_push_velocity_link()

void trigger_push_velocity_link ( entity this)

Definition at line 798 of file jumppads.qc.

799{
801}
float trigger_push_velocity_send(entity this, entity to, float sf)
Definition jumppads.qc:773

References entity(), trigger_link(), and trigger_push_velocity_send().

Referenced by spawnfunc().

◆ trigger_push_velocity_send()

float trigger_push_velocity_send ( entity this,
entity to,
float sf )

Definition at line 773 of file jumppads.qc.

774{
775 WriteHeader(MSG_ENTITY, ENT_CLIENT_TRIGGER_PUSH_VELOCITY);
776
778 WriteInt24_t(MSG_ENTITY, this.spawnflags);
782
783 trigger_common_write(this, true);
784
785 return true;
786}

References active, count, entity(), MSG_ENTITY, spawnflags, speed, team, trigger_common_write(), WriteByte(), WriteCoord(), and WriteHeader.

Referenced by trigger_push_velocity_link().

◆ trigger_push_velocity_think()

void trigger_push_velocity_think ( entity this)

Definition at line 246 of file jumppads.qc.

247{
248 bool found = false;
249 IL_EACH(g_moveables, it.last_pushed == this,
250 {
251 if(!WarpZoneLib_ExactTrigger_Touch(this, it, false))
252 it.last_pushed = NULL;
253 else
254 found = true;
255 });
256
257 if(found)
258 this.nextthink = time;
259 else
260 setthink(this, func_null);
261}
#define IL_EACH(this, cond, body)
IntrusiveList g_moveables
Definition world.qh:157

References entity(), func_null(), g_moveables, IL_EACH, nextthink, setthink, and time.

Referenced by jumppad_push().

◆ trigger_push_velocity_touch()

void trigger_push_velocity_touch ( entity this,
entity toucher )

Definition at line 461 of file jumppads.qc.

462{
463 if (this.active == ACTIVE_NOT)
464 return;
465
466 if(this.team && DIFF_TEAM(this, toucher))
467 return;
468
470
471 jumppad_push(this, toucher, true);
472}

References active, ACTIVE_NOT, DIFF_TEAM, entity(), EXACTTRIGGER_TOUCH, jumppad_push(), team, and toucher.

Referenced by spawnfunc().