3 .float cvar_cl_dodging_timeout;
6 .float stat_dodging_timeout;
7 .float stat_dodging_delay;
8 .float stat_dodging_horiz_speed_frozen;
9 .float stat_dodging_frozen_nodoubletap;
10 .float stat_dodging_frozen;
11 .float stat_dodging_horiz_speed;
12 .float stat_dodging_height_threshold;
13 .float stat_dodging_distance_threshold;
14 .float stat_dodging_ramp_time;
15 .float stat_dodging_up_speed;
16 .float stat_dodging_wall;
20 // set to 1 to indicate dodging has started.. reset by physics hook after dodge has been done..
21 .float dodging_action;
23 // the jump part of the dodge cannot be ramped
24 .float dodging_single_action;
27 // these are used to store the last key press time for each of the keys..
28 .float last_FORWARD_KEY_time;
29 .float last_BACKWARD_KEY_time;
30 .float last_LEFT_KEY_time;
31 .float last_RIGHT_KEY_time;
33 // these store the movement direction at the time of the dodge action happening.
34 .float dodging_direction_x;
35 .float dodging_direction_y;
37 // this indicates the last time a dodge was executed. used to check if another one is allowed
38 // and to ramp up the dodge acceleration in the physics hook.
39 .float last_dodging_time;
41 // This is the velocity gain to be added over the ramp time.
42 // It will decrease from frame to frame during dodging_action = 1
44 .float dodging_velocity_gain;
51 void dodging_UpdateStats()
53 self.stat_dodging = PHYS_DODGING;
54 self.stat_dodging_delay = PHYS_DODGING_DELAY;
55 self.stat_dodging_timeout = PHYS_DODGING_TIMEOUT(self);
56 self.stat_dodging_horiz_speed_frozen = PHYS_DODGING_HORIZ_SPEED_FROZEN;
57 self.stat_dodging_frozen = PHYS_DODGING_FROZEN;
58 self.stat_dodging_frozen_nodoubletap = PHYS_DODGING_FROZEN_NODOUBLETAP;
59 self.stat_dodging_height_threshold = PHYS_DODGING_HEIGHT_THRESHOLD;
60 self.stat_dodging_distance_threshold = PHYS_DODGING_DISTANCE_THRESHOLD;
61 self.stat_dodging_ramp_time = PHYS_DODGING_RAMP_TIME;
62 self.stat_dodging_up_speed = PHYS_DODGING_UP_SPEED;
63 self.stat_dodging_wall = PHYS_DODGING_WALL;
66 void dodging_Initialize()
68 addstat(STAT_DODGING, AS_INT, stat_dodging);
69 addstat(STAT_DODGING_DELAY, AS_FLOAT, stat_dodging_delay);
70 addstat(STAT_DODGING_TIMEOUT, AS_FLOAT, cvar_cl_dodging_timeout); // we stat this, so it is updated on the client when updated on server (otherwise, chaos)
71 addstat(STAT_DODGING_FROZEN_NO_DOUBLETAP, AS_INT, stat_dodging_frozen_nodoubletap);
72 addstat(STAT_DODGING_HORIZ_SPEED_FROZEN, AS_FLOAT, stat_dodging_horiz_speed_frozen);
73 addstat(STAT_DODGING_FROZEN, AS_INT, stat_dodging_frozen);
74 addstat(STAT_DODGING_HORIZ_SPEED, AS_FLOAT, stat_dodging_horiz_speed);
75 addstat(STAT_DODGING_HEIGHT_THRESHOLD, AS_FLOAT, stat_dodging_height_threshold);
76 addstat(STAT_DODGING_DISTANCE_THRESHOLD, AS_FLOAT, stat_dodging_distance_threshold);
77 addstat(STAT_DODGING_RAMP_TIME, AS_FLOAT, stat_dodging_ramp_time);
78 addstat(STAT_DODGING_UP_SPEED, AS_FLOAT, stat_dodging_up_speed);
79 addstat(STAT_DODGING_WALL, AS_FLOAT, stat_dodging_wall);
84 // instantly updates pressed keys, for use with dodging (may be out of date, but we can't care)
85 void PM_dodging_updatepressedkeys()
87 if (PHYS_INPUT_MOVEVALUES(self)_x > 0) // get if movement keys are pressed
88 { // forward key pressed
89 self.pressedkeys |= KEY_FORWARD;
90 self.pressedkeys &= ~KEY_BACKWARD;
92 else if (PHYS_INPUT_MOVEVALUES(self)_x < 0)
93 { // backward key pressed
94 self.pressedkeys |= KEY_BACKWARD;
95 self.pressedkeys &= ~KEY_FORWARD;
99 self.pressedkeys &= ~KEY_FORWARD;
100 self.pressedkeys &= ~KEY_BACKWARD;
103 if (PHYS_INPUT_MOVEVALUES(self)_y > 0)
104 { // right key pressed
105 self.pressedkeys |= KEY_RIGHT;
106 self.pressedkeys &= ~KEY_LEFT;
108 else if (PHYS_INPUT_MOVEVALUES(self)_y < 0)
109 { // left key pressed
110 self.pressedkeys |= KEY_LEFT;
111 self.pressedkeys &= ~KEY_RIGHT;
115 self.pressedkeys &= ~KEY_RIGHT;
116 self.pressedkeys &= ~KEY_LEFT;
119 if (PHYS_INPUT_BUTTONS(self) & 2) // get if jump and crouch keys are pressed
120 self.pressedkeys |= KEY_JUMP;
122 self.pressedkeys &= ~KEY_JUMP;
123 if (PHYS_INPUT_BUTTONS(self) & 16)
124 self.pressedkeys |= KEY_CROUCH;
126 self.pressedkeys &= ~KEY_CROUCH;
128 if (PHYS_INPUT_BUTTONS(self) & 1)
129 self.pressedkeys |= KEY_ATCK;
131 self.pressedkeys &= ~KEY_ATCK;
132 if (PHYS_INPUT_BUTTONS(self) & 4)
133 self.pressedkeys |= KEY_ATCK2;
135 self.pressedkeys &= ~KEY_ATCK2;
139 // returns 1 if the player is close to a wall
140 float check_close_to_wall(float threshold)
142 if (PHYS_DODGING_WALL == 0) { return FALSE; }
147 trace_start = self.origin;
149 trace_end = self.origin + (1000*v_right);
150 tracebox(trace_start, self.mins, self.maxs, trace_end, TRUE, self);
151 if (trace_fraction < 1 && vlen (self.origin - trace_endpos) < threshold)
154 trace_end = self.origin - (1000*v_right);
155 tracebox(trace_start, self.mins, self.maxs, trace_end, TRUE, self);
156 if (trace_fraction < 1 && vlen (self.origin - trace_endpos) < threshold)
159 trace_end = self.origin + (1000*v_forward);
160 tracebox(trace_start, self.mins, self.maxs, trace_end, TRUE, self);
161 if (trace_fraction < 1 && vlen (self.origin - trace_endpos) < threshold)
164 trace_end = self.origin - (1000*v_forward);
165 tracebox(trace_start, self.mins, self.maxs, trace_end, TRUE, self);
166 if (trace_fraction < 1 && vlen (self.origin - trace_endpos) < threshold)
172 float check_close_to_ground(float threshold)
174 if (IS_ONGROUND(self))
180 void PM_dodging_checkpressedkeys()
182 if(!PHYS_DODGING) { return; }
185 float tap_direction_x;
186 float tap_direction_y;
191 float frozen_dodging, frozen_no_doubletap;
192 frozen_dodging = (PHYS_FROZEN(self) && PHYS_DODGING_FROZEN);
193 frozen_no_doubletap = (frozen_dodging && !PHYS_DODGING_FROZEN_NODOUBLETAP);
195 float dodge_detected = 0;
197 // first check if the last dodge is far enough back in time so we can dodge again
198 if ((time - self.last_dodging_time) < PHYS_DODGING_DELAY)
201 makevectors(PHYS_WORLD_ANGLES(self));
203 if (check_close_to_ground(PHYS_DODGING_HEIGHT_THRESHOLD) != 1
204 && check_close_to_wall(PHYS_DODGING_DISTANCE_THRESHOLD) != 1)
207 if (PHYS_INPUT_MOVEVALUES(self)_x > 0)
209 // is this a state change?
210 if (!(PHYS_DODGING_PRESSED_KEYS(self) & KEY_FORWARD) || frozen_no_doubletap)
212 if ((time - self.last_FORWARD_KEY_time) < PHYS_DODGING_TIMEOUT(self))
214 tap_direction_x = 1.0;
217 self.last_FORWARD_KEY_time = time;
221 if (PHYS_INPUT_MOVEVALUES(self)_x < 0)
223 // is this a state change?
224 if (!(PHYS_DODGING_PRESSED_KEYS(self) & KEY_BACKWARD) || frozen_no_doubletap)
226 tap_direction_x = -1.0;
227 if ((time - self.last_BACKWARD_KEY_time) < PHYS_DODGING_TIMEOUT(self))
231 self.last_BACKWARD_KEY_time = time;
235 if (PHYS_INPUT_MOVEVALUES(self)_y > 0)
237 // is this a state change?
238 if (!(PHYS_DODGING_PRESSED_KEYS(self) & KEY_RIGHT) || frozen_no_doubletap)
240 tap_direction_y = 1.0;
241 if ((time - self.last_RIGHT_KEY_time) < PHYS_DODGING_TIMEOUT(self))
245 self.last_RIGHT_KEY_time = time;
249 if (PHYS_INPUT_MOVEVALUES(self)_y < 0)
251 // is this a state change?
252 if (!(PHYS_DODGING_PRESSED_KEYS(self) & KEY_LEFT) || frozen_no_doubletap)
254 tap_direction_y = -1.0;
255 if ((time - self.last_LEFT_KEY_time) < PHYS_DODGING_TIMEOUT(self))
259 self.last_LEFT_KEY_time = time;
263 if (dodge_detected == 1)
265 self.last_dodging_time = time;
267 self.dodging_action = 1;
268 self.dodging_single_action = 1;
270 self.dodging_velocity_gain = PHYS_DODGING_HORIZ_SPEED;
272 self.dodging_direction_x = tap_direction_x;
273 self.dodging_direction_y = tap_direction_y;
275 // normalize the dodging_direction vector.. (unlike UT99) XD
276 length = self.dodging_direction_x * self.dodging_direction_x;
277 length = length + self.dodging_direction_y * self.dodging_direction_y;
278 length = sqrt(length);
280 self.dodging_direction_x = self.dodging_direction_x * 1.0/length;
281 self.dodging_direction_y = self.dodging_direction_y * 1.0/length;
285 PM_dodging_updatepressedkeys();
291 if(!PHYS_DODGING) { return; }
294 float new_velocity_gain;
295 float velocity_difference;
296 float clean_up_and_do_nothing;
297 float horiz_speed = PHYS_DODGING_HORIZ_SPEED;
300 dodging_UpdateStats();
303 if(PHYS_FROZEN(self))
304 horiz_speed = PHYS_DODGING_HORIZ_SPEED_FROZEN;
309 new_velocity_gain = 0;
310 clean_up_and_do_nothing = 0;
312 // when swimming, no dodging allowed..
313 if (self.waterlevel >= WATERLEVEL_SWIMMING)
314 clean_up_and_do_nothing = 1;
316 if (clean_up_and_do_nothing != 0)
318 self.dodging_action = 0;
319 self.dodging_direction_x = 0;
320 self.dodging_direction_y = 0;
324 // make sure v_up, v_right and v_forward are sane
325 makevectors(PHYS_WORLD_ANGLES(self));
327 // if we have e.g. 0.5 sec ramptime and a frametime of 0.25, then the ramp code
328 // will be called ramp_time/frametime times = 2 times. so, we need to
329 // add 0.5 * the total speed each frame until the dodge action is done..
330 common_factor = PHYS_DODGING_FRAMETIME / PHYS_DODGING_RAMP_TIME;
332 // if ramp time is smaller than frametime we get problems ;D
333 if (common_factor > 1)
336 new_velocity_gain = self.dodging_velocity_gain - (common_factor * horiz_speed);
337 if (new_velocity_gain < 0)
338 new_velocity_gain = 0;
340 velocity_difference = self.dodging_velocity_gain - new_velocity_gain;
342 // ramp up dodging speed by adding some velocity each frame.. TODO: do it! :D
343 if (self.dodging_action == 1)
345 //disable jump key during dodge accel phase
346 if(PHYS_INPUT_MOVEVALUES(self)_z > 0) { PHYS_INPUT_MOVEVALUES(self)_z = 0; }
350 + ((self.dodging_direction_y * velocity_difference) * v_right)
351 + ((self.dodging_direction_x * velocity_difference) * v_forward);
353 self.dodging_velocity_gain = self.dodging_velocity_gain - velocity_difference;
356 // the up part of the dodge is a single shot action
357 if (self.dodging_single_action == 1)
359 UNSET_ONGROUND(self);
363 + (PHYS_DODGING_UP_SPEED * v_up);
366 if (autocvar_sv_dodging_sound == 1)
367 PlayerSound(playersound_jump, CH_PLAYER, VOICETYPE_PLAYERSOUND);
369 animdecide_setaction(self, ANIMACTION_JUMP, TRUE);
372 self.dodging_single_action = 0;
375 // are we done with the dodging ramp yet?
376 if((self.dodging_action == 1) && ((time - self.last_dodging_time) > PHYS_DODGING_RAMP_TIME))
378 // reset state so next dodge can be done correctly
379 self.dodging_action = 0;
380 self.dodging_direction_x = 0;
381 self.dodging_direction_y = 0;
385 PM_dodging_checkpressedkeys();
391 MUTATOR_HOOKFUNCTION(dodging_GetCvars)
393 GetCvars_handleFloat(get_cvars_s, get_cvars_f, cvar_cl_dodging_timeout, "cl_dodging_timeout");
397 MUTATOR_HOOKFUNCTION(dodging_PlayerPhysics)
399 // print("dodging_PlayerPhysics\n");
405 MUTATOR_HOOKFUNCTION(dodging_GetPressedKeys)
407 PM_dodging_checkpressedkeys();
412 MUTATOR_DEFINITION(mutator_dodging)
414 // we need to be called before GetPressedKey does its thing so we can
415 // detect state changes and therefore dodging actions..
416 MUTATOR_HOOK(GetPressedKeys, dodging_GetPressedKeys, CBC_ORDER_ANY);
418 // in the physics hook we actually implement the dodge..
419 MUTATOR_HOOK(PlayerPhysics, dodging_PlayerPhysics, CBC_ORDER_ANY);
421 // get timeout information from the client, so the client can configure it..
422 MUTATOR_HOOK(GetCvars, dodging_GetCvars, CBC_ORDER_ANY);
424 // this just turns on the cvar.
427 g_dodging = cvar("g_dodging");
428 dodging_Initialize();
431 // this just turns off the cvar.
432 MUTATOR_ONROLLBACK_OR_REMOVE