]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/mutators/mutator_dodging.qc
DODGING: reset dodging direction component when any checks fail
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / mutators / mutator_dodging.qc
index 93d5da3e9085a5f91479faa311fe17227f634b44..c51ca01db2f1cb4696ed0f594a66705e9ef78783 100644 (file)
@@ -1,9 +1,13 @@
 
+.float cvar_cl_dodging_timeout;
+
+
 // 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;
 .float last_LEFT_KEY_time;
 .float last_RIGHT_KEY_time;
+.float last_JUMP_KEY_time;
 
 // these store the movement direction at the time of the dodge action happening.
 .float dodging_direction_x;
 // 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;
+
 void dodging_Initialize() {
+       // print("dodging_Initialize\n");
+
        self.last_FORWARD_KEY_time = 0;
        self.last_BACKWARD_KEY_time = 0;
        self.last_RIGHT_KEY_time = 0;
        self.last_LEFT_KEY_time = 0;
+       self.last_JUMP_KEY_time = 0;
        self.last_dodging_time = 0;
        self.dodging_action = 0;
+       self.dodging_single_action = 0;
        self.dodging_direction_x = 0;
        self.dodging_direction_y = 0;
 }
 
+MUTATOR_HOOKFUNCTION(dodging_GetCvars) {
+       GetCvars_handleFloat(get_cvars_s, get_cvars_f, cvar_cl_dodging_timeout, "cl_dodging_timeout");
+       return 0;
+}
+
 MUTATOR_HOOKFUNCTION(dodging_PlayerPhysics) {
-       // print("physics hook\n");
+       // print("dodging_PlayerPhysics\n");
+
+       float common_factor;
+
+       float clean_up_and_do_nothing;
+
+       clean_up_and_do_nothing = 0;
+
        if (g_dodging == 0)
+               clean_up_and_do_nothing = 1;
+
+       // when swimming, no dodging allowed..
+       if (self.waterlevel >= WATERLEVEL_SWIMMING)
+               clean_up_and_do_nothing = 1;
+
+       if (clean_up_and_do_nothing != 0) {
+               self.dodging_action = 0;
+               self.dodging_direction_x = 0;
+               self.dodging_direction_y = 0;
                return 0;
+       }
 
-       // ramp up dodging speed by adding some velocity each frame..
+       // make sure v_up, v_right and v_forward are sane
+       makevectors(self.angles);
+
+       // 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..
+       common_factor = sys_frametime / cvar("sv_dodging_ramp_time");
+
+       // if ramp time is smaller than frametime we get problems ;D
+       if (common_factor > 1) 
+               common_factor = 1;
+
+
+       // ramp up dodging speed by adding some velocity each frame.. TODO: do it! :D
        if (self.dodging_action == 1) {
-               self.velocity = self.velocity + self.dodging_direction_y * (cvar("sv_dodging_horiz_speed") * v_right) + self.dodging_direction_x * (cvar("sv_dodging_horiz_speed") * v_forward) + (cvar("sv_dodging_up_speed") * v_up);
-               self.dodging_action = 0;
+               //disable jump key during dodge accel phase
+               if (self.movement_z > 0) self.movement_z = 0;
+
+               self.velocity = 
+                         self.velocity 
+                       + (common_factor * (self.dodging_direction_y * cvar("sv_dodging_horiz_speed")) * v_right) 
+                       + (common_factor * (self.dodging_direction_x * cvar("sv_dodging_horiz_speed")) * v_forward);
+       }
+
+       // the up part of the dodge is a single shot action
+       if (self.dodging_single_action == 1) {
+               self.velocity = 
+                         self.velocity 
+                       + (cvar("sv_dodging_up_speed") * v_up);
+
+               if (cvar("sv_dodging_sound") == 1)
+                       PlayerSound(playersound_jump, CHAN_PLAYER, VOICETYPE_PLAYERSOUND);
+
+               setanim(self, self.anim_jump, TRUE, FALSE, TRUE);
+
+               self.dodging_single_action = 0;
        }
 
        // are we done with the dodging ramp yet?
        if((self.dodging_action == 1) && ((time - self.last_dodging_time) > cvar("sv_dodging_ramp_time")))
+       {
+               // reset state so next dodge can be done correctly
                self.dodging_action = 0;
+               self.dodging_direction_x = 0;
+               self.dodging_direction_y = 0;
+       }
+
+       return 0;
+}
+
+
+// returns 1 if the player is close to a wall
+float check_close_to_wall(float threshold) {
+       if (cvar("sv_dodging_wall_dodging") == 0)
+               return 0;
+
+       vector trace_start;
+       vector trace_end;
+
+       trace_start = self.origin;
+
+       trace_end = self.origin + (1000*v_right);
+       tracebox(trace_start, self.mins, self.maxs, trace_end, TRUE, self);
+       if (trace_fraction < 1 && vlen (self.origin - trace_endpos) < threshold)
+               return 1;
+
+       trace_end = self.origin - (1000*v_right);
+       tracebox(trace_start, self.mins, self.maxs, trace_end, TRUE, self);
+       if (trace_fraction < 1 && vlen (self.origin - trace_endpos) < threshold)
+               return 1;
+
+       trace_end = self.origin + (1000*v_forward);
+       tracebox(trace_start, self.mins, self.maxs, trace_end, TRUE, self);
+       if (trace_fraction < 1 && vlen (self.origin - trace_endpos) < threshold)
+               return 1;
+
+       trace_end = self.origin - (1000*v_forward);
+       tracebox(trace_start, self.mins, self.maxs, trace_end, TRUE, self);
+       if (trace_fraction < 1 && vlen (self.origin - trace_endpos) < threshold)
+               return 1;
+
+       return 0;
+}
+
+float check_close_to_ground(float threshold) {
+       vector trace_start;
+       vector trace_end;
+
+       // determine height above ground is below a threshold
+       trace_start = self.origin;
+       trace_end = self.origin - (1000*v_up);
+
+       tracebox(trace_start, self.mins, self.maxs, trace_end, TRUE, self);
+
+       // check if the trace hit anything at all
+       if (trace_fraction > 1)
+               return 0;
+
+       if(self.origin_z - trace_endpos_z < threshold) 
+               return 1;
 
        return 0;
 }
 
+
 MUTATOR_HOOKFUNCTION(dodging_GetPressedKeys) {
-       float length;
-       //print("dodging_hook\n");
+       // print("dodging_PlayerPhysics\n");
 
+       float length;
+       float dodge_detected;
        if (g_dodging == 0)
                return 0;
 
-       self.dodging_direction_x = 0;
-       self.dodging_direction_y = 0;
-       if (self.movement_x > 0) // get if movement keys are pressed
-   {       // forward key pressed
-       if (!(self.pressedkeys & KEY_FORWARD)) {        // is this a state change?
-                       if (
-                               ((time - self.last_FORWARD_KEY_time) < self.cvar_cl_dodging_timeout) &&
-                               (self.lastflags & FL_ONGROUND) &&
-                               ((time - self.last_dodging_time) > cvar("sv_dodging_delay"))
-                       ) { // are we allowed to dodge?
-                               self.dodging_action = 1;
-                               self.dodging_direction_x = 1;
-                               self.last_dodging_time = time;
+       dodge_detected = 0;
+
+       // no dodging and jumping at the same time..
+       if (self.BUTTON_JUMP)
+               return 0;
+
+       // first check if the last dodge is far enough back in time so we can dodge again
+       if ((time - self.last_dodging_time) < cvar("sv_dodging_delay"))
+               return 0;
+
+       if (check_close_to_ground(cvar("sv_dodging_height_threshold")) != 1 
+               && check_close_to_wall(cvar("sv_dodging_wall_distance_threshold")) != 1)
+               return 0;
+
+       // remember last jump key time, so we can check in dodging code, if it
+       // was pressed between the two dodges..
+       if (self.BUTTON_JUMP)
+               self.last_JUMP_KEY_time = time;
+
+       if (self.movement_x > 0) {
+               // is this a state change?
+               if (!(self.pressedkeys & KEY_FORWARD)) {
+                       if ((time - self.last_FORWARD_KEY_time) < self.cvar_cl_dodging_timeout) { 
+                               dodge_detected = 1;
+                               self.dodging_direction_x = 1.0;
                        }
                        self.last_FORWARD_KEY_time = time;
                }
        }
 
-       if (self.movement_x < 0) // get if movement keys are pressed
-   {       // forward key pressed
-       if (!(self.pressedkeys & KEY_BACKWARD)) {        // is this a state change?
-                       if (
-                               ((time - self.last_BACKWARD_KEY_time) < self.cvar_cl_dodging_timeout) &&
-                               (self.lastflags & FL_ONGROUND) &&
-                               ((time - self.last_dodging_time) > cvar("sv_dodging_delay"))
-                       ) { // are we allowed to dodge?
-                               self.dodging_action = 1;
-                               self.dodging_direction_x = -1;
-                               self.last_dodging_time = time;
+       if (self.movement_x < 0) {
+               // is this a state change?
+               if (!(self.pressedkeys & KEY_BACKWARD)) {
+                       if ((time - self.last_BACKWARD_KEY_time) < self.cvar_cl_dodging_timeout)        { 
+                               dodge_detected = 1;
+                               self.dodging_direction_x = -1.0;
                        }
                        self.last_BACKWARD_KEY_time = time;
                }
        }
 
-       // normalize the dodging_direction vector.. 
-       length += self.dodging_direction_x * self.dodging_direction_x;
-       length += self.dodging_direction_y * self.dodging_direction_y;
-       length = sqrt(length);
+       if (self.movement_y > 0) {
+               // is this a state change?
+               if (!(self.pressedkeys & KEY_RIGHT)) {
+                       if ((time - self.last_RIGHT_KEY_time) < self.cvar_cl_dodging_timeout)   { 
+                               dodge_detected = 1;
+                               self.dodging_direction_y = 1.0;
+                       }
+                       self.last_RIGHT_KEY_time = time;
+               }
+       }
+
+       if (self.movement_y < 0) {
+               // is this a state change?
+               if (!(self.pressedkeys & KEY_LEFT)) {
+                       if ((time - self.last_LEFT_KEY_time) < self.cvar_cl_dodging_timeout)    { 
+                               dodge_detected = 1;
+                               self.dodging_direction_y = -1.0;
+                       }
+                       self.last_LEFT_KEY_time = time;
+               }
+       }
 
-       self.dodging_direction_x *= 1/length;
-       self.dodging_direction_y *= 1/length;
+
+
+       if (dodge_detected == 1) {
+               // If the player pressed JUMP between the two taps, disallow dodging,
+               // cause he obviously wants to jump instead
+               if ((time - self.last_JUMP_KEY_time) < self.cvar_cl_dodging_timeout)
+                       return 0;
+
+               self.last_dodging_time = time;
+
+               self.dodging_action = 1;
+               self.dodging_single_action = 1;
+
+               // normalize the dodging_direction vector.. (unlike UT99) XD
+               length = length + self.dodging_direction_x * self.dodging_direction_x;
+               length = length + self.dodging_direction_y * self.dodging_direction_y;
+               length = sqrt(length);
+
+               self.dodging_direction_x = self.dodging_direction_x * 1.0/length;
+               self.dodging_direction_y = self.dodging_direction_y * 1.0/length;
+       }
 
        return 0;
 }
@@ -106,18 +276,21 @@ MUTATOR_DEFINITION(dodging)
        // in the physics hook we actually implement the dodge..
        MUTATOR_HOOK(PlayerPhysics, dodging_PlayerPhysics, CBC_ORDER_ANY);
 
-       // this just turns on the cvar. TODO: implement :D
+       // get timeout information from the client, so the client can configure it..
+       MUTATOR_HOOK(GetCvars, dodging_GetCvars, CBC_ORDER_ANY);
+
+       // this just turns on the cvar.
        MUTATOR_ONADD
        {
                g_dodging = 1;
                dodging_Initialize();
        }
 
-       // this just turns off the cvar. TODO: implement :D
+       // this just turns off the cvar.
        MUTATOR_ONREMOVE
        {        
                g_dodging = 0;
        }
 
        return 0;
-}
\ No newline at end of file
+}