]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/common/mutators/mutator/dodging/sv_dodging.qc
i hate this code
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / mutators / mutator / dodging / sv_dodging.qc
index 8e90ef3534f169fb3d50fc036dab17fd8fbb71fd..cf1a33949f091abc2a47ae9d67740bd619aa8286 100644 (file)
@@ -3,7 +3,7 @@
 #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_NODOUBLETAP                autocvar_sv_dodging_frozen_doubletap
+#define PHYS_DODGING_FROZEN_DOUBLETAP          autocvar_sv_dodging_frozen_doubletap
 #define PHYS_DODGING_HEIGHT_THRESHOLD          autocvar_sv_dodging_height_threshold
 #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_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
+#define PHYS_DODGING_MAXSPEED                          autocvar_sv_dodging_maxspeed // TODO separate max air speed, fix frozen dodging
 
 // 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_MAXSPEED                          STAT(DODGING_MAXSPEED, this)
 #endif
 
-#ifdef CSQC
+#ifdef CSQC // FIXME this is an sv_ file, none of this will even be compiled
        #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
 
 
 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"))
 {
@@ -81,7 +75,6 @@ REGISTER_MUTATOR(dodging, true);
 // the jump part of the dodge cannot be ramped
 .float dodging_single_action;
 
-
 // these are used to store the last key press time for each of the keys..
 .float last_FORWARD_KEY_time;
 .float last_BACKWARD_KEY_time;
@@ -98,111 +91,130 @@ REGISTER_MUTATOR(dodging, true);
 // This is the velocity gain to be added over the ramp time.
 // It will decrease from frame to frame during dodging_action = 1
 // until it's 0.
-.float dodging_velocity_gain;
+//.float dodging_velocity_gain;
 
-#ifdef CSQC
+.float dodging_force_total;
+.float dodging_force_remaining;
+
+#ifdef CSQC // TODO what is this? 1) CSQC in sv_ file never even gets compiled 2) pressedkeys is only defined on server so this would be always 0
 .int pressedkeys;
 #endif
 
-// returns 1 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 && !(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY) && 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);
-#undef X
+
+// returns true if the player is close to a wall
+bool is_close_to_wall(entity this, float threshold)
+{
+       X(v_right);
+       X(-v_right);
+       X(v_forward);
+       X(-v_forward);
 
        return false;
 }
 
-bool check_close_to_ground(entity this, float threshold)
+bool is_close_to_ground(entity this, float threshold)
 {
-       return IS_ONGROUND(this) ? true : false;
+       if (IS_ONGROUND(this)) return true;
+       X(-v_up); // necessary for dodging down a slope using doubletap (using `+dodge` works anyway)
+
+       return false;
+}
+
+#undef X
+
+// 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);*/
 }
 
 bool PM_dodging_checkpressedkeys(entity this)
 {
-       if(!PHYS_DODGING)
+       // 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;
 
        bool frozen_dodging = (PHYS_FROZEN(this) && PHYS_DODGING_FROZEN(this));
-       bool frozen_no_doubletap = (frozen_dodging && !PHYS_DODGING_FROZEN_NODOUBLETAP);
+       bool frozen_no_doubletap = (frozen_dodging && !PHYS_DODGING_FROZEN_DOUBLETAP);
 
-       // 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;
+       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 (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;                                                                                          \
+                       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++);
+       X(y < 0, LEFT,          y--);
+       X(y > 0, RIGHT,         y++);
+       #undef X
+
+       if (!dodge_detected) return false;
 
        makevectors(this.angles);
 
        bool wall_dodge = false;
 
        if(!PHYS_DODGING_AIR)
-       if(!check_close_to_ground(this, PHYS_DODGING_HEIGHT_THRESHOLD))
+       if(!is_close_to_ground(this, PHYS_DODGING_HEIGHT_THRESHOLD))
        {
-               wall_dodge = check_close_to_wall(this, PHYS_DODGING_DISTANCE_THRESHOLD);
+               wall_dodge = (PHYS_DODGING_WALL && is_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;
+                       return false;
        }
 
        if(!wall_dodge && PHYS_DODGING_MAXSPEED && vdist(this.velocity, >, PHYS_DODGING_MAXSPEED))
                return false;
 
-       float tap_direction_x = 0;
-       float tap_direction_y = 0;
-       bool dodge_detected = false;
+       this.last_dodging_time = time;
 
-       #define X(COND,BTN,RESULT)                                                                                                                      \
-       if (this.movement_##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;                                                                                          \
-                               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++);
-       X(y < 0, LEFT,          y--);
-       X(y > 0, RIGHT,         y++);
-       #undef X
+       this.dodging_action = 1;
+       this.dodging_single_action = 1;
 
-       if (dodge_detected)
-       {
-               this.last_dodging_time = time;
+       //this.dodging_velocity_gain = PHYS_DODGING_HORIZ_SPEED;
+       this.dodging_force_total = determine_speed(this);
+       this.dodging_force_remaining = this.dodging_force_total;
 
-               this.dodging_action = 1;
-               this.dodging_single_action = 1;
+       this.dodging_direction.x = tap_direction_x;
+       this.dodging_direction.y = tap_direction_y;
 
-               this.dodging_velocity_gain = PHYS_DODGING_HORIZ_SPEED;
+       // normalize the dodging_direction vector.. (unlike UT99) XD
+       float length = sqrt(this.dodging_direction.x ** 2 + this.dodging_direction.y ** 2);
 
-               this.dodging_direction_x = tap_direction_x;
-               this.dodging_direction_y = tap_direction_y;
+       this.dodging_direction_x = this.dodging_direction_x / length;
+       this.dodging_direction_y = this.dodging_direction_y / length;
 
-               // normalize the dodging_direction vector.. (unlike UT99) XD
-               float length = this.dodging_direction_x * this.dodging_direction_x
-                                       + this.dodging_direction_y * this.dodging_direction_y;
-               length = sqrt(length);
-
-               this.dodging_direction_x = this.dodging_direction_x * 1.0 / length;
-               this.dodging_direction_y = this.dodging_direction_y * 1.0 / length;
-               return true;
-       }
-       return false;
+       return true;
 }
 
 void PM_dodging(entity this)
 {
-       if (!PHYS_DODGING)
-               return;
+       // can't use return value from PM_dodging_checkpressedkeys because they're called from different hooks
+       if (!this.dodging_action) return;
 
        // when swimming or dead, no dodging allowed..
        if (this.waterlevel >= WATERLEVEL_SWIMMING || IS_DEAD(this))
@@ -219,31 +231,35 @@ void PM_dodging(entity this)
        else
                makevectors(this.angles);
 
+       // fraction of the force to apply each frame
        // if we have e.g. 0.5 sec ramptime and a frametime of 0.25, then the ramp code
        // will be called ramp_time/frametime times = 2 times. so, we need to
        // add 0.5 * the total speed each frame until the dodge action is done..
        float common_factor = PHYS_DODGING_FRAMETIME / PHYS_DODGING_RAMP_TIME;
+       common_factor /= 2; // FIXME this is WRONG but this function is called twice per frame!!!
 
        // 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
+       //LOG_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;
+       float velocity_difference = this.dodging_velocity_gain - new_velocity_gain;*/
 
-       // ramp up dodging speed by adding some velocity each frame.. TODO: do it! :D
-       if (this.dodging_action == 1)
-       {
-               //disable jump key during dodge accel phase
-               if(this.movement_z > 0) { this.movement_z = 0; }
+       /*float velocity_increase = min(common_factor * this.dodging_force_total, this.dodging_force_remaining;
+       this.dodging_force_remaining -= velocity_increase;*/
 
-               this.velocity += ((this.dodging_direction_y * velocity_difference) * v_right)
-                                       + ((this.dodging_direction_x * velocity_difference) * v_forward);
+       /*this.velocity += ((this.dodging_direction_y * velocity_difference) * v_right)
+                               + ((this.dodging_direction_x * velocity_difference) * v_forward);
 
-               this.dodging_velocity_gain = this.dodging_velocity_gain - velocity_difference;
-       }
+       this.dodging_velocity_gain = this.dodging_velocity_gain - velocity_difference;*/
+
+       float velocity_increase = common_factor * this.dodging_force_total;
+       LOG_INFOF("time %f velocity_increase: %f\n", time, velocity_increase);
+       this.velocity += this.dodging_direction_x * velocity_increase * v_forward
+                      + this.dodging_direction_y * velocity_increase * v_right;
 
        // the up part of the dodge is a single shot action
        if (this.dodging_single_action == 1)
@@ -263,42 +279,42 @@ void PM_dodging(entity this)
        }
 
        // are we done with the dodging ramp yet?
-       if((this.dodging_action == 1) && ((time - this.last_dodging_time) > PHYS_DODGING_RAMP_TIME))
+       if((time - this.last_dodging_time) > PHYS_DODGING_RAMP_TIME)
        {
                // reset state so next dodge can be done correctly
                this.dodging_action = 0;
-               this.dodging_direction_x = 0;
-               this.dodging_direction_y = 0;
+               this.dodging_direction.x = 0;
+               this.dodging_direction.y = 0;
        }
 }
 
+#ifdef CSQC
 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));
        keys = BITSET(keys, KEY_ATCK,           PHYS_INPUT_BUTTON_ATCK(this));
        keys = BITSET(keys, KEY_ATCK2,          PHYS_INPUT_BUTTON_ATCK2(this));
        this.pressedkeys = keys;
-#endif
 }
+#endif
 
 MUTATOR_HOOKFUNCTION(dodging, PlayerPhysics)
 {
-    entity player = M_ARGV(0, entity);
+       entity player = M_ARGV(0, entity);
+       //LOG_INFOF("player %s, physics %f\n", player.netname, time);
 
-       // print("dodging_PlayerPhysics\n");
+#ifdef CSQC
        PM_dodging_GetPressedKeys(player);
+#endif
        PM_dodging(player);
 }
 
@@ -309,6 +325,7 @@ REPLICATE(cvar_cl_dodging_timeout, float, "cl_dodging_timeout");
 MUTATOR_HOOKFUNCTION(dodging, GetPressedKeys)
 {
        entity player = M_ARGV(0, entity);
+       //LOG_INFOF("player %s, keys %f\n", player.netname, time);
 
        PM_dodging_checkpressedkeys(player);
 }