1 #include "multijump.qh"
6 #include <server/antilag.qh>
8 #include <common/physics/player.qh>
12 REGISTER_MUTATOR(multijump, autocvar_g_multijump);
14 REGISTER_MUTATOR(multijump, true);
17 #define PHYS_MULTIJUMP(s) STAT(MULTIJUMP, s)
18 #define PHYS_MULTIJUMP_SPEED(s) STAT(MULTIJUMP_SPEED, s)
19 #define PHYS_MULTIJUMP_ADD(s) STAT(MULTIJUMP_ADD, s)
20 #define PHYS_MULTIJUMP_MAXSPEED(s) STAT(MULTIJUMP_MAXSPEED, s)
21 #define PHYS_MULTIJUMP_DODGING(s) STAT(MULTIJUMP_DODGING, s)
22 #define PHYS_MULTIJUMP_COUNT(s) STAT(MULTIJUMP_COUNT, s)
24 .bool multijump_ready;
27 bool cvar_cl_multijump;
28 bool autocvar_cl_multijump = true;
30 #define PHYS_MULTIJUMP_CLIENT(s) autocvar_cl_multijump
32 .bool cvar_cl_multijump;
34 #define PHYS_MULTIJUMP_CLIENT(s) CS(s).cvar_cl_multijump
37 MUTATOR_HOOKFUNCTION(multijump, PlayerPhysics)
39 entity player = M_ARGV(0, entity);
42 player.multijump_count = PHYS_MULTIJUMP_COUNT(player);
44 if(!PHYS_MULTIJUMP(player)) { return; }
46 if(IS_ONGROUND(player))
47 player.multijump_count = 0;
50 MUTATOR_HOOKFUNCTION(multijump, PlayerJump)
52 entity player = M_ARGV(0, entity);
54 if(!PHYS_MULTIJUMP(player)) { return; }
56 int client_multijump = PHYS_MULTIJUMP_CLIENT(player);
57 if(client_multijump > 1)
60 if (!IS_JUMP_HELD(player) && !IS_ONGROUND(player) && client_multijump) // jump button pressed this frame and we are in midair
61 player.multijump_ready = true; // this is necessary to check that we released the jump button and pressed it again
63 player.multijump_ready = false;
65 int phys_multijump = PHYS_MULTIJUMP(player);
67 if(!M_ARGV(2, bool) && player.multijump_ready && (PHYS_MULTIJUMP_COUNT(player) < phys_multijump || phys_multijump == -1) && player.velocity_z > PHYS_MULTIJUMP_SPEED(player) &&
68 (!PHYS_MULTIJUMP_MAXSPEED(player) || vdist(player.velocity, <=, PHYS_MULTIJUMP_MAXSPEED(player))))
70 if (PHYS_MULTIJUMP(player))
72 if (!PHYS_MULTIJUMP_ADD(player)) // in this case we make the z velocity == jumpvelocity
74 if (player.velocity_z < PHYS_JUMPVELOCITY(player))
76 M_ARGV(2, bool) = true;
77 player.velocity_z = 0;
81 M_ARGV(2, bool) = true;
85 if(PHYS_MULTIJUMP_DODGING(player))
86 if(PHYS_CS(player).movement_x != 0 || PHYS_CS(player).movement_y != 0) // don't remove all speed if player isnt pressing any movement keys
89 vector wishvel, wishdir;
93 vlen(vec2(player.velocity)), // current xy speed
94 vlen(vec2(antilag_takebackavgvelocity(player, max(player.lastteleporttime + sys_frametime, time - 0.25), time))) // average xy topspeed over the last 0.25 secs
97 curspeed = vlen(vec2(player.velocity));
100 makevectors(player.v_angle_y * '0 1 0');
101 wishvel = v_forward * PHYS_CS(player).movement_x + v_right * PHYS_CS(player).movement_y;
102 wishdir = normalize(wishvel);
104 player.velocity_x = wishdir_x * curspeed; // allow "dodging" at a multijump
105 player.velocity_y = wishdir_y * curspeed;
106 // keep velocity_z unchanged!
108 if (PHYS_MULTIJUMP(player) > 0)
110 player.multijump_count += 1;
114 player.multijump_ready = false; // require releasing and pressing the jump button again for the next jump
118 REPLICATE(cvar_cl_multijump, bool, "cl_multijump");
122 MUTATOR_HOOKFUNCTION(multijump, BuildMutatorsString)
124 M_ARGV(0, string) = strcat(M_ARGV(0, string), ":multijump");
127 MUTATOR_HOOKFUNCTION(multijump, BuildMutatorsPrettyString)
129 M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Multi jump");