1#include "walljump.qh"
2
3#ifdef GAMEQC
4#ifdef CSQC
5REGISTER_MUTATOR(walljump, true);
6#elif defined(SVQC)
7REGISTER_MUTATOR(walljump, cvar("g_walljump"));
8#endif
9
10#define PHYS_WALLJUMP(s) 						STAT(WALLJUMP, s)
11#define PHYS_WALLJUMP_VELOCITY_Z_FACTOR(s) 		STAT(WALLJUMP_VELOCITY_Z_FACTOR, s)
12#define PHYS_WALLJUMP_VELOCITY_XY_FACTOR(s) 	STAT(WALLJUMP_VELOCITY_XY_FACTOR, s)
13#define PHYS_WALLJUMP_DELAY(s) 					STAT(WALLJUMP_DELAY, s)
14#define PHYS_WALLJUMP_FORCE(s) 					STAT(WALLJUMP_FORCE, s)
15
16vector PlayerTouchWall(entity this)
17{
18#define TRACE(newvec) \
19	tracebox (start, this.mins, this.maxs, (newvec), true, this); \
20	if (trace_fraction < 1 && vdist(this.origin - trace_endpos, <, dist) && trace_plane_normal_z < max_normal) \
21	if (!(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)) \
22		return trace_plane_normal;
23
24	float dist = 10, max_normal = 0.2, scaler = 100;
25	vector start = this.origin;
26	TRACE(start + v_forward * scaler)
27	TRACE(start - v_forward * scaler)
28	TRACE(start + v_right * scaler)
29	TRACE(start - v_right * scaler)
30#undef TRACE
31	return '0 0 0';
32}
33
34MUTATOR_HOOKFUNCTION(walljump, PlayerJump)
35{
36	entity player = M_ARGV(0, entity);
37
38	if(PHYS_WALLJUMP(player))
39	if(time - STAT(LASTWJ, player) > PHYS_WALLJUMP_DELAY(player)) // can't do this on client, as it's too stupid to obey counters
40	if(!IS_ONGROUND(player))
41	if(player.move_movetype != MOVETYPE_NONE && player.move_movetype != MOVETYPE_FOLLOW && player.move_movetype != MOVETYPE_FLY && player.move_movetype != MOVETYPE_NOCLIP)
42	if(!IS_JUMP_HELD(player))
43	if(!STAT(FROZEN, player))
44	if(!IS_DEAD(player))
45	{
46		vector plane_normal = PlayerTouchWall(player);
47
48		if(plane_normal != '0 0 0')
49		{
50			float wj_force = PHYS_WALLJUMP_FORCE(player);
51			float wj_xy_factor = PHYS_WALLJUMP_VELOCITY_XY_FACTOR(player);
52			float wj_z_factor = PHYS_WALLJUMP_VELOCITY_Z_FACTOR(player);
53			player.velocity_x += plane_normal_x * wj_force;
54			player.velocity_x /= wj_xy_factor;
55			player.velocity_y += plane_normal_y * wj_force;
56			player.velocity_y /= wj_xy_factor;
57			player.velocity_z = PHYS_JUMPVELOCITY(player) * wj_z_factor;
58			if(PHYS_INPUT_BUTTON_CROUCH(player)) player.velocity_z *= -1;
59
60#ifdef SVQC
61			STAT(LASTWJ, player) = time;
62			player.oldvelocity = player.velocity;
63			Send_Effect(EFFECT_SMOKE_RING, trace_endpos, plane_normal, 5);
64			PlayerSound(player, playersound_jump, CH_PLAYER, VOL_BASE, VOICETYPE_PLAYERSOUND);
65			animdecide_setaction(player, ANIMACTION_JUMP, true);
66#endif
67
68			M_ARGV(2, bool) = true; // multijump
69		}
70	}
71}
72
73#endif
74