#include "sv_dodging.qh"
+#define PHYS_DODGING g_dodging
+#define PHYS_DODGING_DELAY autocvar_sv_dodging_delay
+#define PHYS_DODGING_DISTANCE_THRESHOLD autocvar_sv_dodging_wall_distance_threshold
+#define PHYS_DODGING_FROZEN_DOUBLETAP autocvar_sv_dodging_frozen_doubletap
+#define PHYS_DODGING_HEIGHT_THRESHOLD autocvar_sv_dodging_height_threshold // TODO not used - kill? (also below)
+#define PHYS_DODGING_HORIZ_SPEED autocvar_sv_dodging_horiz_speed
+#define PHYS_DODGING_HORIZ_SPEED_FROZEN autocvar_sv_dodging_horiz_speed_frozen
+#define PHYS_DODGING_RAMP_TIME autocvar_sv_dodging_ramp_time
+#define PHYS_DODGING_UP_SPEED autocvar_sv_dodging_up_speed
+#define PHYS_DODGING_WALL autocvar_sv_dodging_wall_dodging
+#define PHYS_DODGING_AIR autocvar_sv_dodging_air_dodging
+#define PHYS_DODGING_MAXSPEED autocvar_sv_dodging_maxspeed
+
+// we ran out of stats slots! TODO: re-enable this when prediction is available for dodging
+#if 0
#define PHYS_DODGING STAT(DODGING, this)
#define PHYS_DODGING_DELAY STAT(DODGING_DELAY, this)
#define PHYS_DODGING_DISTANCE_THRESHOLD STAT(DODGING_DISTANCE_THRESHOLD, this)
-#define PHYS_DODGING_FROZEN_NODOUBLETAP STAT(DODGING_FROZEN_NO_DOUBLETAP, this)
+#define PHYS_DODGING_FROZEN_DOUBLETAP STAT(DODGING_FROZEN_DOUBLETAP, this)
#define PHYS_DODGING_HEIGHT_THRESHOLD STAT(DODGING_HEIGHT_THRESHOLD, this)
#define PHYS_DODGING_HORIZ_SPEED STAT(DODGING_HORIZ_SPEED, this)
#define PHYS_DODGING_HORIZ_SPEED_FROZEN STAT(DODGING_HORIZ_SPEED_FROZEN, this)
#define PHYS_DODGING_UP_SPEED STAT(DODGING_UP_SPEED, this)
#define PHYS_DODGING_WALL STAT(DODGING_WALL, this)
#define PHYS_DODGING_AIR STAT(DODGING_AIR, this)
-#define PHYS_DODGING_PRESSED_KEYS(s) (s).pressedkeys
+#define PHYS_DODGING_MAXSPEED STAT(DODGING_MAXSPEED, this)
+#endif
#ifdef CSQC
#define PHYS_DODGING_FRAMETIME (1 / (frametime <= 0 ? 60 : frametime))
#define PHYS_DODGING_TIMEOUT(s) STAT(DODGING_TIMEOUT)
+ #define PHYS_DODGING_PRESSED_KEYS(s) (s).pressedkeys
#elif defined(SVQC)
#define PHYS_DODGING_FRAMETIME sys_frametime
- #define PHYS_DODGING_TIMEOUT(s) s.cvar_cl_dodging_timeout
+ #define PHYS_DODGING_TIMEOUT(s) CS(s).cvar_cl_dodging_timeout
+ #define PHYS_DODGING_PRESSED_KEYS(s) CS(s).pressedkeys
#endif
#ifdef SVQC
bool autocvar_sv_dodging_sound;
-// set to 1 to indicate dodging has started.. reset by physics hook after dodge has been done..
-.float dodging_action;
-
-// the jump part of the dodge cannot be ramped
-.float dodging_single_action;
-
#include <common/animdecide.qh>
#include <common/physics/player.qh>
-.float cvar_cl_dodging_timeout = _STAT(DODGING_TIMEOUT);
+.float cvar_cl_dodging_timeout;
REGISTER_MUTATOR(dodging, cvar("g_dodging"))
{
.int pressedkeys;
#endif
-// returns 1 if the player is close to a wall
+// returns true if the player is close to a wall
bool check_close_to_wall(entity this, float threshold)
{
if (PHYS_DODGING_WALL == 0) { return false; }
-#define X(OFFSET) \
- tracebox(this.origin, this.mins, this.maxs, this.origin + OFFSET, true, this); \
- if(trace_fraction < 1 && vdist(this.origin - trace_endpos, <, threshold)) \
+#define X(dir) \
+ tracebox(this.origin, this.mins, this.maxs, this.origin + threshold * dir, true, this); \
+ if (trace_fraction < 1 && !(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)) \
return true;
- X(1000*v_right);
- X(-1000*v_right);
- X(1000*v_forward);
- X(-1000*v_forward);
+
+ X(v_right);
+ X(-v_right);
+ X(v_forward);
+ X(-v_forward);
#undef X
return false;
return IS_ONGROUND(this) ? true : false;
}
-float PM_dodging_checkpressedkeys(entity this)
+bool PM_dodging_checkpressedkeys(entity this)
{
- if(!PHYS_DODGING)
- return false;
-
- float frozen_dodging = (PHYS_FROZEN(this) && PHYS_DODGING_FROZEN(this));
- float frozen_no_doubletap = (frozen_dodging && !PHYS_DODGING_FROZEN_NODOUBLETAP);
-
// first check if the last dodge is far enough back in time so we can dodge again
if ((time - this.last_dodging_time) < PHYS_DODGING_DELAY)
return false;
makevectors(this.angles);
+ bool wall_dodge = false;
+
if(!PHYS_DODGING_AIR)
- if (check_close_to_ground(this, PHYS_DODGING_HEIGHT_THRESHOLD) != 1
- && check_close_to_wall(this, PHYS_DODGING_DISTANCE_THRESHOLD) != 1)
- return true;
+ if(!check_close_to_ground(this, PHYS_DODGING_HEIGHT_THRESHOLD))
+ {
+ wall_dodge = check_close_to_wall(this, PHYS_DODGING_DISTANCE_THRESHOLD);
+ if(!wall_dodge) // we're not on the ground, and wall dodging isn't allowed, end it!
+ return true;
+ }
+
+ if(!wall_dodge && PHYS_DODGING_MAXSPEED && vdist(this.velocity, >, PHYS_DODGING_MAXSPEED))
+ return false;
+
+ bool frozen_dodging = (PHYS_FROZEN(this) && PHYS_DODGING_FROZEN(this));
+ bool frozen_no_doubletap = (frozen_dodging && !PHYS_DODGING_FROZEN_DOUBLETAP);
float tap_direction_x = 0;
float tap_direction_y = 0;
bool dodge_detected = false;
+ vector mymovement = PHYS_CS(this).movement;
#define X(COND,BTN,RESULT) \
- if (this.movement_##COND) \
+ if (mymovement_##COND) \
/* is this a state change? */ \
if(!(PHYS_DODGING_PRESSED_KEYS(this) & KEY_##BTN) || frozen_no_doubletap) { \
- tap_direction_##RESULT; \
- if ((time - this.last_##BTN##_KEY_time) < PHYS_DODGING_TIMEOUT(this) || frozen_no_doubletap) \
- dodge_detected = true; \
- this.last_##BTN##_KEY_time = time; \
+ tap_direction_##RESULT; \
+ if ((time - this.last_##BTN##_KEY_time) < PHYS_DODGING_TIMEOUT(this) || frozen_no_doubletap) \
+ dodge_detected = true; \
+ if(PHYS_INPUT_BUTTON_DODGE(this)) \
+ dodge_detected = true; \
+ this.last_##BTN##_KEY_time = time; \
}
X(x < 0, BACKWARD, x--);
X(x > 0, FORWARD, x++);
return false;
}
+// TODO use real cvars
+/*float autocvar_velocity_min = 200;
+float autocvar_velocity_max = 700;
+float autocvar_force_min = 50;
+float autocvar_force_max = 350;*/
+float determine_speed(entity player) {
+ float x = PHYS_FROZEN(player) ? PHYS_DODGING_HORIZ_SPEED_FROZEN : PHYS_DODGING_HORIZ_SPEED;
+ x = x; // unused
+ return x;
+
+ /*float horiz_vel = vlen(vec2(player.velocity));
+ // force min and max are inverted - the faster you are the wekaer dodging becomes
+ // TODO document cvars in cfg
+ return map_bound_ranges(horiz_vel, autocvar_velocity_min, autocvar_velocity_max, autocvar_force_max, autocvar_force_min);*/
+}
+
void PM_dodging(entity this)
{
- if (!PHYS_DODGING)
- return;
-
- if (IS_DEAD(this))
- return;
-
- // when swimming, no dodging allowed..
- if (this.waterlevel >= WATERLEVEL_SWIMMING)
+ // when swimming or dead, no dodging allowed..
+ if (this.waterlevel >= WATERLEVEL_SWIMMING || IS_DEAD(this))
{
this.dodging_action = 0;
this.dodging_direction_x = 0;
// if ramp time is smaller than frametime we get problems ;D
common_factor = min(common_factor, 1);
- float horiz_speed = PHYS_FROZEN(this) ? PHYS_DODGING_HORIZ_SPEED_FROZEN : PHYS_DODGING_HORIZ_SPEED;
+ float horiz_speed = determine_speed(this); // TODO kill this
+ //OG_INFOF("velocity %f -> force %f\n", vlen(vec2(this.velocity)), horiz_speed);
float new_velocity_gain = this.dodging_velocity_gain - (common_factor * horiz_speed);
new_velocity_gain = max(0, new_velocity_gain);
float velocity_difference = this.dodging_velocity_gain - new_velocity_gain;
- // ramp up dodging speed by adding some velocity each frame.. TODO: do it! :D
+ // ramp up dodging speed by adding some velocity each frame..
if (this.dodging_action == 1)
{
//disable jump key during dodge accel phase
- if(this.movement_z > 0) { this.movement_z = 0; }
+ if(PHYS_CS(this).movement.z > 0) { PHYS_CS(this).movement_z = 0; }
this.velocity += ((this.dodging_direction_y * velocity_difference) * v_right)
+ ((this.dodging_direction_x * velocity_difference) * v_forward);
void PM_dodging_GetPressedKeys(entity this)
{
#ifdef CSQC
- if(!PHYS_DODGING) { return; }
-
PM_dodging_checkpressedkeys(this);
int keys = this.pressedkeys;
- keys = BITSET(keys, KEY_FORWARD, this.movement.x > 0);
- keys = BITSET(keys, KEY_BACKWARD, this.movement.x < 0);
- keys = BITSET(keys, KEY_RIGHT, this.movement.y > 0);
- keys = BITSET(keys, KEY_LEFT, this.movement.y < 0);
+ keys = BITSET(keys, KEY_FORWARD, PHYS_CS(this).movement.x > 0);
+ keys = BITSET(keys, KEY_BACKWARD, PHYS_CS(this).movement.x < 0);
+ keys = BITSET(keys, KEY_RIGHT, PHYS_CS(this).movement.y > 0);
+ keys = BITSET(keys, KEY_LEFT, PHYS_CS(this).movement.y < 0);
keys = BITSET(keys, KEY_JUMP, PHYS_INPUT_BUTTON_JUMP(this));
keys = BITSET(keys, KEY_CROUCH, PHYS_INPUT_BUTTON_CROUCH(this));
MUTATOR_HOOKFUNCTION(dodging, PlayerPhysics)
{
- entity player = M_ARGV(0, entity);
+ entity player = M_ARGV(0, entity);
// print("dodging_PlayerPhysics\n");
PM_dodging_GetPressedKeys(player);