djcev.com

//

Git Repos / fte_dogmode / commit b57cc76

Commit: b57cc767e3517f4a408ec752ce850e563c66d7ca
Parent: 7839d54d6a272fbbb5b532feb8d9a97b76d3ddf4
Author: Cameron Vanderzanden, 2023-11-09 18:38
Committer: Cameron Vanderzanden, 2023-11-09 18:38

Commit Message

SlideMove, accel, and timer changes in pmove

First and most important: found the correct conditions for the
SlideMove; it now correctly handles creases and more edge cases
(still without using an array). The clues were all in Quake 1
and Quake 3's source. The current implementation should handle
everything Quake 1's FlyMove can.

I've also reworked player acceleration, notably split it into
two passes (which apparently helps with framerate dependence).
It changed the feel pretty significantly, it's faster now for
the same acceleration values (not sure what to make of that).

Last up I changed some of the movement timers into countdowns
that depend on 'input_timelength' instead of 'time'. This seems
to be a bit simpler to read & easier to understand, to keep
track of.

Change List

?File Add Del
M qc/client.qc +23 -20
M qc/csqc/csqc_defsclient.qc +2 -4
M qc/csqc/csqc_player.qc +6 -1
M qc/defs_constants.qc +17 -7
M qc/defs_misc.qc +3 -6
M qc/fteqcc.ini +2 -2
M qc/pmove.qc +400 -349

Diff qc/client.qc

diff --git a/qc/client.qc b/qc/client.qc
index b25d531..7ebb852 100644
--- a/qc/client.qc
+++ b/qc/client.qc
@@ -572,6 +572,9 @@ void() PlayerJump =
if (self.flags & FL_WATERJUMP)
return;

+ if (self.movetype == MOVETYPE_FLY || self.movetype == MOVETYPE_NOCLIP)
+ return;
+
if (self.waterlevel >= 2)
{
// pmove code predicts this
@@ -633,10 +636,6 @@ void() PlayerClimb =

void() WaterMove =
{
- // dprint (ftos(self.waterlevel));
- // if (self.movetype == MOVETYPE_NOCLIP)
- // return;
- // from Copper -- dumptruck_ds
if (self.movetype == MOVETYPE_NOCLIP)
{
self.air_finished = time + 120;
@@ -649,9 +648,11 @@ void() WaterMove =
if (self.waterlevel != 3)
{
if (self.air_finished < time)
- sound (self, CHAN_VOICE, "player/gasp2.wav", 1, ATTN_NORM);
+ sound (self, CHAN_VOICE, "player/gasp2.wav",
+ 1, ATTN_NORM);
else if (self.air_finished < time + 9)
- sound (self, CHAN_VOICE, "player/gasp1.wav", 1, ATTN_NORM);
+ sound (self, CHAN_VOICE, "player/gasp1.wav",
+ 1, ATTN_NORM);
self.air_finished = time + 12;
self.dmg = 2;
}
@@ -661,7 +662,8 @@ void() WaterMove =
if (self.pain_finished < time)
{
self.dmg = self.dmg + 2;
- if (self.dmg > 15) self.dmg = 10;
+ if (self.dmg > 15)
+ self.dmg = 10;
self.deathtype = "drowning";
T_Damage (self, world, world, self.dmg);
self.deathtype = "";
@@ -674,7 +676,8 @@ void() WaterMove =
if (self.flags & FL_INWATER)
{
// play leave water sound
- sound (self, CHAN_BODY, "misc/outwater.wav", 1, ATTN_NORM);
+ sound (self, CHAN_BODY, "misc/outwater.wav",
+ 1, ATTN_NORM);
self.flags = self.flags - FL_INWATER;
}
return;
@@ -712,19 +715,18 @@ void() WaterMove =

// player enter water sound
if (self.watertype == CONTENT_LAVA)
- sound (self, CHAN_BODY, "player/inlava.wav", 1, ATTN_NORM);
+ sound (self, CHAN_BODY, "player/inlava.wav",
+ 1, ATTN_NORM);
if (self.watertype == CONTENT_WATER)
- sound (self, CHAN_BODY, "player/inh2o.wav", 1, ATTN_NORM);
+ sound (self, CHAN_BODY, "player/inh2o.wav",
+ 1, ATTN_NORM);
if (self.watertype == CONTENT_SLIME)
- sound (self, CHAN_BODY, "player/slimbrn2.wav", 1, ATTN_NORM);
+ sound (self, CHAN_BODY, "player/slimbrn2.wav",
+ 1, ATTN_NORM);

self.flags = self.flags + FL_INWATER;
self.dmgtime = 0;
}
-
- if (! (self.flags & FL_WATERJUMP) )
- self.velocity -= 0.8 * self.waterlevel * frametime *
- self.velocity;
};

//======================================================================
@@ -885,8 +887,9 @@ void() PlayerPreThink =
self.flags = self.flags | FL_FLY;
}

- if (!self.boost_time && (self.teleport_time > time - 0.1))
- self.boost_time = time;
+ // TODO CEV
+ if (!self.groundboost_time && (self.teleport_time > time - 0.1))
+ self.groundboost_time = PM_GROUNDBOOST_WINDOW;
};

//======================================================================
@@ -1050,15 +1053,15 @@ void() CheckPowerups =
//======================================================================
void() PlayerPostThink =
{
+ // TODO CEV
+ self.SendFlags = FULLSEND;
+
// from Copper -- dumptruck_ds
if (self.movetype != MOVETYPE_NOCLIP)
{
self.flags = not(self.flags, FL_FLY);
}

- // TODO CEV
- self.SendFlags = FULLSEND;
-
if (self.view_ofs == '0 0 0')
// intermission or finale
return;

Return to the top of this page or return to the overview of this repo.

Diff qc/csqc/csqc_defsclient.qc

diff --git a/qc/csqc/csqc_defsclient.qc b/qc/csqc/csqc_defsclient.qc
index ed9344b..f75a756 100644
--- a/qc/csqc/csqc_defsclient.qc
+++ b/qc/csqc/csqc_defsclient.qc
@@ -117,11 +117,9 @@ float pmove_frame;
.float modelflags;

.float pmove_flags; // custom movement flags -- CEV
+.float nostick_time; // last time player stuck to the floor -- CEV
.float jump_time; // last time the player jumped -- CEV
-.float land_time; // last time the player landed onground -- CEV
-.vector primal_velocity; // velocity before engine physics -- CEV
-.float primal_speed; // speed before engine physics -- CEV
-.float boost_time; // time to simulate low friction -- CEV
+.float groundboost_time; // time to simulate low friction -- CEV
.void() customphysics;

.float ext_csqc; // Client Server Quake C HUD alive!

Return to the top of this page or return to the overview of this repo.

Diff qc/csqc/csqc_player.qc

diff --git a/qc/csqc/csqc_player.qc b/qc/csqc/csqc_player.qc
index a03259e..767e476 100644
--- a/qc/csqc/csqc_player.qc
+++ b/qc/csqc/csqc_player.qc
@@ -61,14 +61,19 @@ void(entity ent, float endframe) PlayerRunMovement =
pmove_frame = clientcommandframe;
if (!getinputstate(pmove_frame - 1))
{
+ #ifdef CSQC
+ dprint ("PlayerRunMovement: no-op if statement?\n");
+ #endif
// no-op ? -- CEV
}
return;
}

+ /*
if (getinputstate(pmove_frame - 1))
- // from CSQCTest; what is this doing? -- CEV;
+ // from CSQCTest; what is this doing? -- TODO CEV;
ent.pmove_flags |= PMF_JUMP_HELD;
+ */

while (pmove_frame <= endframe)
{

Return to the top of this page or return to the overview of this repo.

Diff qc/defs_constants.qc

diff --git a/qc/defs_constants.qc b/qc/defs_constants.qc
index 3836d86..491a3d2 100644
--- a/qc/defs_constants.qc
+++ b/qc/defs_constants.qc
@@ -2,13 +2,15 @@
CONSTANT VALS COLLECTED HERE
==============================================================================*/

+//
#define FULLSEND 0xffffff

-#define PM_AIRACCEL 8 // 10 in Q1; now 8
-#define PM_AIRACCELQ3 0.8 // 1.0 in Q3 ?; now 0.8
+// PMOVE constants
+#define PM_AIRACCEL 7.5 // 10 in Q1; now 8
+#define PM_AIRACCELQ3 0.75 // 1.0 in Q3 ?; now 0.8
#define PM_AIRACCELFWD 1.5 // 1 feels close to Q3 / CPM
#define PM_AIRACCELBACK 5 // Air stop speed in Q3?
-#define PM_AIRACCELTURN 150 // affects +fwd style turning radius
+#define PM_AIRACCELTURN 100 // affects +fwd style turning radius
#define PM_BOOSTACCEL 12 // 12 is fast, 10 is enough
#define PM_BOOSTFRICTION 4 // Q1 friction (4) is plenty low
#define PM_FRICTION 8 // 4 for Q1, 6 for Q3, 8 for CPM
@@ -18,28 +20,36 @@
#define PM_OVERCLIP 1.0f // Quake3's OVERCLIP is 1.001f
#define PM_STEPHEIGHT 18 // 18 for Q1, 22 for later games?
#define PM_WALLDIST_V '0 0 40' // min. distance from ground for wj
+#define PM_WATERACCEL 10 // water acceleration
+#define PM_WATERFRICTION 4 // friction in water

#define PM_JUMPSPEED 270 // standard jump Z velocity; 90 * 3
#define PM_DOUBLEJUMPSPEED 360 // 270 * 1.5 in CPM?; 360 = 90 * 4
-#define PM_TRIPLEJUMPSPEED 270 // 225 reduced Z velocity; 90 * 2.5
#define PM_TELEJUMPSPEED 360 // same as DOUBLEJUMPSPEED
#define PM_WALLJUMPFORCE 90 // amount of push away from wall
#define PM_WALLJUMPSPEED PM_JUMPSPEED // upward vel for walljumps
#define PM_MAXSPEED 320 // 320 always
#define PM_MAXAIRSPEED 30 // 30 for Q1 air control
#define PM_STOPSPEED 100
+#define PM_WATERMAXSPEED 224 // 320 * 0.7
#define PM_WATERSINKSPEED 60

-#define PM_JUMP_WINDOW 0.1 // minimum jump interval
#define PM_DOUBLEJUMP_WINDOW 0.4 // 2 jumps in this time is a double
#define PM_DOUBLEJUMP_COOLDOWN 0.4 //
-#define PM_TELEJUMP_WINDOW 0.4 // duration to allow a telejump
+#define PM_NOSTICK_WINDOW 0.3 // duration to perform onesided clips
+#define PM_TELEJUMP_WINDOW 0.4 // duration to perform a telejump
#define PM_WALLJUMP_WINDOW 0.2 // duration between walljumps
#define PM_WALLCLIP_WINDOW 0.25 //
-#define PM_BOOST_WINDOW 0.4 // groundboost duration
+#define PM_GROUNDBOOST_WINDOW 0.4 // groundboost duration

#define PM_JUMPPADADDHEIGHT 64 // not currently in use
#define PM_TELEDROP '0 0 -64' // drop teleporter exit to floor if
// floor is within this distance
#define PM_TELEEXITSPEED 400 // exit teleporters at this speed

+// water level
+#define WATERLEVEL_NONE 0
+#define WATERLEVEL_FEET 1
+#define WATERLEVEL_WAIST 2
+#define WATERLEVEL_EYES 3
+

Return to the top of this page or return to the overview of this repo.

Diff qc/defs_misc.qc

diff --git a/qc/defs_misc.qc b/qc/defs_misc.qc
index 4462a79..80a9bf1 100644
--- a/qc/defs_misc.qc
+++ b/qc/defs_misc.qc
@@ -300,17 +300,14 @@ float AS_TURRET = 5;
.float air_finished; // when time > air_finished, drown
.float bubble_count; // keeps track of the number of bubbles
.string deathtype; // keeps track of how the player died
-
.float pmove_flags; // custom movement flags -- CEV
+.float groundboost_time; // time to simulate low friction -- CEV
.float jump_time; // last time the player jumped -- CEV
-.float land_time; // last time the player landed -- CEV
-.vector primal_velocity; // velocity before engine physics -- CEV
-.float primal_speed; // speed before engine physics -- CEV
-.float boost_time; // time to simulate low friction -- CEV
+.float nostick_time; // time to not stick to the floor -- CEV
.void() customphysics;

float input_timelength; // from fteextensions.qc -- CEV
-vector input_angles; /* +x=DOWN */
+vector input_angles; // +x = DOWN
vector input_movevalues;
float input_buttons;
float input_impulse;

Return to the top of this page or return to the overview of this repo.

Diff qc/fteqcc.ini

diff --git a/qc/fteqcc.ini b/qc/fteqcc.ini
index 151ecc1..a002034 100644
--- a/qc/fteqcc.ini
+++ b/qc/fteqcc.ini
@@ -22,12 +22,12 @@ optimisation f default # This strips out the filenames of the p
# really old decompilers, but is nothing to the more recent ones.
optimisation u off # Removes the entries of unreferenced variables. Doesn't make a
# difference in well maintained code.
-optimisation r off # Optimises the pr_globals count by overlapping temporaries. In
+optimisation r on # Optimises the pr_globals count by overlapping temporaries. In
# QC, every multiplication, division or operation in general produces
# a temporary variable. This optimisation prevents excess, and in
# the case of Hexen2's gamecode, reduces the count by 50k. This
# is the most important optimisation, ever.
-optimisation a off # 5*6 actually emits an operation into the progs. This prevents
+optimisation a on # 5*6 actually emits an operation into the progs. This prevents
# that happening, effectivly making the compiler see 30
optimisation pf default # Strip out stuff wasted used in function calls and strings to the
# precache_file builtin (which is actually a stub in quake).

Return to the top of this page or return to the overview of this repo.

Diff qc/pmove.qc

diff --git a/qc/pmove.qc b/qc/pmove.qc
index 0dc8b6e..5fb8be3 100644
--- a/qc/pmove.qc
+++ b/qc/pmove.qc
@@ -2,39 +2,48 @@
// PMOVE
//==============================================================================

+// TODO: implement PMF_WINDMOVE / wind brush nostick timer
+// TODO: look into reworking the jump_time timer
+
.entity groundentity;
.vector groundnormal;

// pmove_flags
enumflags
{
- PMF_JUMP_HELD,
- PMF_RESERVED,
- PMF_ONGROUND,
- PMF_WALLJUMP,
- PMF_DOUBLEJUMPED,
- PMF_WATERJUMP
+ PMF_ONGROUND, // entity is on ground
+ PMF_STARTGROUND, // entity started the move on ground
+ PMF_JUMP_HELD, // player is holding the jump key
+ PMF_DOUBLEJUMPED, // entity has doublejumped
+ PMF_WALLJUMP, // entity has walljumped
+ PMF_WATERJUMP, // entity has waterjumped
+ PMF_WINDMOVE, // entity has been trigger_push'ed
+ PMF_NOSTICK // entity won't stick to the floor
};

+//======================================================================
+// PM_DoTouch
+// call when self has touched target (to run target's touch function)
//----------------------------------------------------------------------
-static void(entity tother) PM_DoTouch =
+static void(entity target) PM_DoTouch =
{
- if (tother.touch == __NULL__)
+ if (target.touch == __NULL__)
return;

- entity oself;
+ entity orig_self;

- oself = self;
+ orig_self = self;
other = self;
- self = tother;
+ self = target;
self.touch();
- self = oself;
+ self = orig_self;
};

//======================================================================
// PM_Nudge
//
// from the GPL2 CSQCTest code that comes with FTEQW
+// This isn't working correctly from what I can tell. Not sure why.
//----------------------------------------------------------------------
float() PM_Nudge =
{
@@ -78,53 +87,6 @@ float() PM_Nudge =
};

//======================================================================
-// PM_Rebound
-//
-// Alternative ClipVelocity that does ground checking.
-// For use with Eukara / Nuclide move.
-//----------------------------------------------------------------------
-#define STOP_EPSILON 0.125
-void(vector normal, float ob, float oneside) PM_Rebound =
-{
- local float backoff;
-
- backoff = self.velocity * normal;
-
- if (backoff < 0)
- backoff *= ob;
- else
- if (oneside)
- backoff *= -0.001;
- else
- backoff /= ob;
-
- self.velocity -= normal * backoff;
-
- if (self.velocity_x > -STOP_EPSILON && self.velocity_x < STOP_EPSILON)
- self.velocity_x = 0;
- if (self.velocity_y > -STOP_EPSILON && self.velocity_y < STOP_EPSILON)
- self.velocity_y = 0;
- if (self.velocity_z > -STOP_EPSILON && self.velocity_z < STOP_EPSILON)
- self.velocity_z = 0;
-
- if (normal_z > 0.7)
- {
- if (trace_ent.solid == SOLID_BSP)
- {
- self.groundentity = trace_ent;
- self.groundnormal = trace_plane_normal;
- self.pmove_flags |= PMF_ONGROUND;
- }
- }
- else
- {
- self.groundentity = __NULL__;
- self.groundnormal = __NULL__;
- self.pmove_flags &= ~PMF_ONGROUND;
- }
-};
-
-//======================================================================
// PM_NuclideMove
//
// Updates origin, moves the player through the world. Similar to Q3
@@ -137,12 +99,12 @@ void(vector normal, float ob, float oneside) PM_Rebound =
// This in turn appears to be based on a similar function in CSQCTest.
// -- CEV
//----------------------------------------------------------------------
-void(float dogravity, float onesided) PM_NuclideMove =
+void(float dogravity, float sticky, float dostep, float doskim) PM_NuclideMove =
{
- vector end, prev_plane, plane, start_o, start_v;
- float backoff, dostep, grav, stepsz, time_left;
- int i, start_onground;
- entity ent;
+ vector end, prev_plane, plane, start_v;
+ float backoff, grav, stepsize, time_left;
+ int i;
+ entity touched_ent;

if (dogravity)
{
@@ -156,13 +118,10 @@ void(float dogravity, float onesided) PM_NuclideMove =
self.velocity_z -= grav * 0.5;
}

- start_o = self.origin;
start_v = self.velocity;
- start_onground = (self.pmove_flags & PMF_ONGROUND);

- dostep = TRUE;
if (!(autocvar(pm_airstep, TRUE)) && !(self.pmove_flags & PMF_ONGROUND))
- // Borrowing FTE's pm_airstep cvar here. If false, don't
+ // Borrowing FTEQW's pm_airstep cvar here. If false, don't
// step up while in the air (changes stairs) -- CEV
dostep = FALSE;

@@ -197,12 +156,12 @@ void(float dogravity, float onesided) PM_NuclideMove =
self.origin = trace_endpos;

if (trace_fraction >= 1.0f)
- // made the whole move -- CEV
+ // no obstructions, made the whole move -- CEV
break;

- stepsz = 0;
+ stepsize = 0;
plane = trace_plane_normal;
- ent = trace_ent;
+ touched_ent = trace_ent;
time_left -= time_left * trace_fraction;

// integrated StepSlideMove -- CEV
@@ -220,7 +179,7 @@ void(float dogravity, float onesided) PM_NuclideMove =
{
// up move didn't hit anything
// second: move forward
- stepsz = trace_endpos_z - self.origin_z;
+ stepsize = trace_endpos_z - self.origin_z;
end = trace_endpos +
(self.velocity * time_left);
end_z = trace_endpos_z;
@@ -232,7 +191,7 @@ void(float dogravity, float onesided) PM_NuclideMove =
// forward move didn't hit anything
// third: move down
end = trace_endpos;
- end_z -= stepsz;
+ end_z -= stepsize;
tracebox (trace_endpos, self.mins,
self.maxs, end, FALSE, self);

@@ -241,13 +200,13 @@ void(float dogravity, float onesided) PM_NuclideMove =
{
// good ground, accept the move
// laugh at my 80 column term
- stepsz = trace_endpos_z -
+ stepsize = trace_endpos_z -
self.origin_z;
self.origin = trace_endpos;
time_left -= time_left *
trace_fraction;
plane = trace_plane_normal;
- ent = trace_ent;
+ touched_ent = trace_ent;
// don't attempt to step again
dostep = FALSE;
}
@@ -256,7 +215,7 @@ void(float dogravity, float onesided) PM_NuclideMove =
// down move didn't hit and/or
// it hit a plane too steep to
// be ground -- CEV
- stepsz = 0;
+ stepsize = 0;
}
}
else if (trace_plane_normal_z == 0)
@@ -266,40 +225,20 @@ void(float dogravity, float onesided) PM_NuclideMove =
// complex movement on stairs. note
// that we're not updating origin.
// -- CEV
- stepsz = 0;
+ stepsize = 0;
time_left -= time_left * trace_fraction;
plane = trace_plane_normal;
- ent = trace_ent;
+ touched_ent = trace_ent;
}
}
else
{
// up move hit something (the roof?)
// ignore the step attempt entirely -- CEV
- stepsz = 0;
+ stepsize = 0;
}
}

- // Slide along the crease of previous plane and current plane
- // if previous plane is not the same as current plane AND
- // our velocity interacts with the current or previous plane
- // if those planes are an acute vertical angle -- CEV
- //
- // TODO CEV: this is *definitely* wrong, but it solves some
- // immediate problems
- if (prev_plane && prev_plane != plane &&
- (
- (!(self.velocity * prev_plane >= 0) &&
- prev_plane_z < 0) ||
- (!(self.velocity * plane >= 0) &&
- plane_z < 0)
- ))
- {
- end = crossproduct (prev_plane, plane);
- end = normalize (end);
- self.velocity = end * (end * self.velocity);
- }
-
// clip velocity to the saved plane
// integrated PM_Rebound aka PM_ClipVelocity -- CEV
backoff = self.velocity * plane;
@@ -307,19 +246,47 @@ void(float dogravity, float onesided) PM_NuclideMove =
if (backoff < 0)
backoff *= PM_OVERCLIP;
else
- if (onesided)
- backoff *= -0.001;
- else
+ if (sticky)
backoff /= PM_OVERCLIP;
+ else
+ backoff *= -0.001;

self.velocity -= plane * backoff;

+ // if velocity interacts with prev_plane then clip to it.
+ // I'm duplicating a little code here (ClipVelocity),
+ // hopefully the audience will forgive me. -- CEV
+ if (prev_plane && prev_plane != plane &&
+ self.velocity * prev_plane < 0)
+ {
+ backoff = self.velocity * prev_plane;
+
+ if (backoff < 0)
+ backoff *= PM_OVERCLIP;
+ else
+ if (sticky)
+ backoff /= PM_OVERCLIP;
+ else
+ backoff *= -0.001;
+
+ self.velocity -= prev_plane * backoff;
+
+ // Slide along the crease of previous plane and
+ // current plane if the two still interact -- CEV
+ if (self.velocity * plane < 0)
+ {
+ end = crossproduct (prev_plane, plane);
+ end = normalize (end);
+ self.velocity = end * (end * self.velocity);
+ }
+ }
+
// integrated ground check -- CEV
if (plane_z > 0.7)
{
- if (ent.solid == SOLID_BSP)
+ if (touched_ent.solid == SOLID_BSP)
{
- self.groundentity = ent;
+ self.groundentity = touched_ent;
self.groundnormal = plane;
self.pmove_flags |= PMF_ONGROUND;
}
@@ -332,24 +299,26 @@ void(float dogravity, float onesided) PM_NuclideMove =
}

// touch the saved entity -- CEV
- PM_DoTouch (ent);
+ PM_DoTouch (touched_ent);
+
+ // copied from Q1FlyMove, not sure this is necessary -- CEV
+ if ((self.velocity * start_v) <= 0)
+ {
+ self.velocity = '0 0 0';
+ break;
+ }

- // store plane for the crease check above
+ // store current plane for later -- CEV
prev_plane = plane;
}

// wallclip / wall skim timer check
- // in order: velocity is non-zero, we're within WALLCLIP_WINDOW,
- // we haven't just teleported, we're not waterjumping, we're not
- // in the ground boost state, and we lost speed during the move -- CEV
- if (self.velocity && self.jump_time > (time - PM_WALLCLIP_WINDOW) &&
- (self.teleport_time <= (time - 0.1)) &&
- (!(self.pmove_flags & PMF_WATERJUMP)) &&
- (self.boost_time <= time - PM_BOOST_WINDOW) &&
- (vlen(start_v) > vlen(self.velocity)))
+ // if doskim is true and velocity is non-zero and we lost speed
+ // during the move -- CEV
+ if (doskim && self.velocity && (vlen(start_v) > vlen(self.velocity)))
{
#ifdef SSQC
- dprint ("PM_NuclideMove: wallclip, restoring velocity...\n");
+ dprint ("PM_NuclideMove: wall skim, restoring velocity...\n");
#endif
// restore velocity, taking either the start Z or clipped Z
// depending on which is lower -- CEV
@@ -359,21 +328,22 @@ void(float dogravity, float onesided) PM_NuclideMove =
self.velocity = start_v;
}

- // final gravity check here
+ // final gravity check here -- CEV
if (dogravity)
self.velocity_z -= grav * 0.5;

- // manage the "boost" timer -- CEV
- if (!start_onground && self.pmove_flags & PMF_ONGROUND && stepsz)
+ // if stepsize is nonzero and we changed from inair to onground then
+ // we've airstepped -- CEV
+ if (stepsize && !(self.pmove_flags & PMF_STARTGROUND) &&
+ self.pmove_flags & PMF_ONGROUND)
{
- if (!self.boost_time &&
- self.boost_time <= time - PM_BOOST_WINDOW)
- self.boost_time = time;
+ // manage timers -- CEV
+ if (self.groundboost_time <= 0)
+ self.groundboost_time = PM_GROUNDBOOST_WINDOW;

// more debugging -- CEV
#ifdef SSQC
- dprint (sprintf("PM_NuclideMove: airstep: %g, %g\n", stepsz,
- self.origin_z - start_o_z));
+ dprint (sprintf("PM_NuclideMove: airstep: %g\n", stepsize));
#endif
}

@@ -387,29 +357,6 @@ void(float dogravity, float onesided) PM_NuclideMove =
};

//----------------------------------------------------------------------
-void(float friction) PM_Friction =
-{
- float control, newspeed, speed;
-
- speed = vlen(self.velocity);
-
- if (speed < 1)
- {
- self.velocity = '0 0 0';
- return;
- }
-
- // calculate what their new speed should be
- control = speed < PM_STOPSPEED ? PM_STOPSPEED : speed;
- newspeed = speed - control * friction * input_timelength;
-
- // and slow them
- if (newspeed < 0)
- newspeed = 0;
- self.velocity = self.velocity * (newspeed / speed);
-};
-
-//----------------------------------------------------------------------
void(entity ground_e, vector ground_v, int docheck) PM_SetOnground =
{
// look for ground with tracebox if requested
@@ -444,17 +391,12 @@ void(entity ground_e, vector ground_v, int docheck) PM_SetOnground =
if (self.groundnormal != __NULL__)
{
// on ground
- if (!(self.pmove_flags & PMF_ONGROUND))
- // transitioning from in-air to onground
- self.land_time = time;
self.pmove_flags |= PMF_ONGROUND;
self.pmove_flags &= ~PMF_WALLJUMP;
}
else
{
// not on ground
- if (self.pmove_flags & PMF_ONGROUND)
- self.land_time = 0;
self.pmove_flags &= ~PMF_ONGROUND;
}

@@ -470,10 +412,10 @@ void(entity ground_e, vector ground_v, int docheck) PM_SetOnground =
//----------------------------------------------------------------------
void() PM_CategorizePosition =
{
- vector p;
- float pc;
+ vector point;
+ float contents;

- if (self.movetype == MOVETYPE_NOCLIP)
+ if (self.movetype == MOVETYPE_NOCLIP || self.movetype == MOVETYPE_FLY)
// noclip is never on ground
PM_SetOnground (__NULL__, __NULL__, FALSE);
else
@@ -482,104 +424,148 @@ void() PM_CategorizePosition =

// clear doublejumped if outside of DOUBLEJUMP_COOLDOWN
if ((self.pmove_flags & PMF_DOUBLEJUMPED)
- && self.jump_time < (time - PM_DOUBLEJUMP_COOLDOWN))
+ && self.jump_time <= (time - PM_DOUBLEJUMP_COOLDOWN))
{
- // #ifdef SSQC
- // dprint ("PM_Categorize: clear FL_DOUBLEJUMPED\n");
- // #endif
self.pmove_flags &= ~PMF_DOUBLEJUMPED;
}

+ // zero out groundboost timer if it's gone negative -- CEV
+ if (self.groundboost_time < 0)
+ self.groundboost_time = 0;
+
+ // PMF_NOSTICK if within nostick_time, otherwise clear -- CEV
+ if (self.nostick_time > 0)
+ {
+ self.pmove_flags |= PMF_NOSTICK;
+ }
+ else
+ {
+ self.nostick_time = 0;
+ self.pmove_flags &= ~PMF_NOSTICK;
+ }
+
// check water levels
- p = self.origin;
- p_z = self.origin_z + self.mins_z + 1;
- pc = pointcontents (p);
- if (pc < CONTENT_SOLID)
+ point = self.origin;
+ point_z = self.origin_z + self.mins_z + 1;
+ contents = pointcontents (point);
+ if (contents < CONTENT_SOLID)
{
- self.watertype = pc;
- p_z = self.origin_z + (self.mins_z + self.maxs_z) * 0.5;
- if (pointcontents(p) < CONTENT_SOLID)
+ self.watertype = contents;
+ point_z = self.origin_z + (self.mins_z + self.maxs_z) * 0.5;
+ if (pointcontents(point) < CONTENT_SOLID)
{
- p_z = self.origin_z + self.maxs_z;
- if (pointcontents(p) < CONTENT_SOLID)
- self.waterlevel = 3;
+ point_z = self.origin_z + self.maxs_z;
+ if (pointcontents(point) < CONTENT_SOLID)
+ self.waterlevel = WATERLEVEL_EYES;
else
- self.waterlevel = 2;
+ self.waterlevel = WATERLEVEL_WAIST;
}
else
{
- self.waterlevel = 1;
+ self.waterlevel = WATERLEVEL_FEET;
}
}
else
{
self.watertype = CONTENT_EMPTY;
- self.waterlevel = 0;
+ self.waterlevel = WATERLEVEL_NONE;
}
};

+//======================================================================
+// PM_Friction
+// Ground friction
//----------------------------------------------------------------------
-void(vector wishdir, float wishspeed, float accel) PM_Accelerate =
+void(float friction, float move_time) PM_Friction =
{
- float addspeed, accelspeed, curspeed;
+ float control, newspeed, speed;

- curspeed = self.velocity * wishdir;
- addspeed = wishspeed - curspeed;
+ speed = vlen (self.velocity);

- if (addspeed <= 0)
+ if (speed < 1)
+ {
+ self.velocity = '0 0 0';
return;
+ }
+
+ // calculate what their new speed should be
+ control = speed < PM_STOPSPEED ? PM_STOPSPEED : speed;
+ newspeed = speed - control * friction * move_time;

- accelspeed = accel * input_timelength * wishspeed;
- if (accelspeed > addspeed) accelspeed = addspeed;
+ // and slow them
+ if (newspeed < 0)
+ newspeed = 0;

- self.velocity = self.velocity + accelspeed * wishdir;
+ self.velocity = self.velocity * (newspeed / speed);
};

+//======================================================================
+// PM_Accelerate
+// Ground acceleration & Quake 3 style air acceleration -- CEV
//----------------------------------------------------------------------
-void(vector wishvel, float wishspeed, float accel) PM_Q1AirAccelerate =
+void(vector wishdir, float wishspeed, float accel, float move_time)
+ PM_Accelerate =
{
- float addspeed, wishspd, accelspeed, currentspeed;
+ float newspeed, speed;

- currentspeed = self.velocity * wishvel;
+ speed = wishspeed - (self.velocity * wishdir);
+
+ if (speed <= 0)
+ return;
+
+ newspeed = accel * move_time * wishspeed;
+ if (newspeed > speed)
+ newspeed = speed;
+
+ self.velocity += newspeed * wishdir;
+};
+
+//======================================================================
+// PM_AirAccelerate
+// Quake 1 style air acceleration -- CEV
+//----------------------------------------------------------------------
+void(vector wishvel, float wishspeed, float accel, float move_time)
+ PM_AirAccelerate =
+{
+ float newspeed, speed, wishspd;

- wishvel = normalize (wishvel);
wishspd = vlen (wishvel);
- if (wishspd > PM_MAXAIRSPEED) wishspd = PM_MAXAIRSPEED;
+ wishvel = normalize (wishvel);
+ if (wishspd > PM_MAXAIRSPEED)
+ wishspd = PM_MAXAIRSPEED;
+ speed = self.velocity * wishvel;
+ speed = wishspd - speed;

- addspeed = wishspd - currentspeed;
- if (addspeed <= 0)
+ if (speed <= 0)
return;

- accelspeed = accel * input_timelength * wishspeed;
- if (accelspeed > addspeed) accelspeed = addspeed;
-
- self.velocity = self.velocity + accelspeed * wishvel;
+ newspeed = accel * move_time * wishspeed;
+ if (newspeed > speed)
+ newspeed = speed;
+ self.velocity += newspeed * wishvel;
};

//======================================================================
// PM_AirControl
-// CPM-like Air Control. Based on Xonotic and an old experiment. -- CEV
+// CPM / Painkiller-like Air Control. Based on Xonotic sources. -- CEV
//----------------------------------------------------------------------
-void(vector wishdir, float wishspeed, float accel) PM_AirControl =
+void(vector wishdir, float wishspeed, float move_time) PM_AirControl =
{
- local float dot, xyspeed, zspeed;
+ local float speed, zspeed;

zspeed = self.velocity_z;
self.velocity_z = 0;

- PM_Accelerate (wishdir, wishspeed, accel);
-
- xyspeed = vlen (self.velocity);
+ speed = vlen (self.velocity);
self.velocity = normalize (self.velocity);
- dot = self.velocity * wishdir;

- if (dot > 0)
+ if ((self.velocity * wishdir) > 0)
{
- self.velocity = normalize (self.velocity * xyspeed +
+ self.velocity = normalize (self.velocity * speed +
wishdir * PM_AIRACCELTURN);
}

- self.velocity = self.velocity * xyspeed;
+ self.velocity *= speed;
self.velocity_z = zspeed;
};

@@ -598,12 +584,6 @@ void() PM_Jump =
if (self.pmove_flags & PMF_JUMP_HELD)
return;

- // don't let the player jump more often than JUMP_WINDOW -- CEV
- /*
- if ((self.jump_time) && (self.jump_time > time - PM_JUMP_WINDOW))
- return;
- */
-
// make sure we get at least jumpspeed upwards from
// the ground plane by clamping it first.
if (self.groundnormal && (self.velocity * self.groundnormal < 0))
@@ -620,25 +600,33 @@ void() PM_Jump =
if (self.velocity_z < 0)
self.velocity_z = 0;

- // teleport jumps; allow a larger (+0.2) window to account for
- // time to travel thru teleporter. -- CEV
if ((self.jump_time > time - PM_TELEJUMP_WINDOW) &&
(self.teleport_time > time - (PM_TELEJUMP_WINDOW + 0.2)))
{
+ // a teleport jump: allow a larger (+0.2) window to
+ // account for time to travel thru teleporter -- CEV
#ifdef SSQC
- dprint ("PM_Jump: telejump ");
- dprint (ftos(self.velocity_z));
- dprint (", ");
+ dprint (sprintf("PM_Jump: telejump %g, ", self.velocity_z));
#endif
- self.velocity_z += PM_TELEJUMPSPEED;
+
if !(self.pmove_flags & PMF_DOUBLEJUMPED)
self.pmove_flags |= PMF_DOUBLEJUMPED;
+
+ // set the nostick timer whenever we doublejump -- CEV
+ if (self.nostick_time <= 0)
+ self.nostick_time = PM_NOSTICK_WINDOW;
+
+ if (self.groundnormal && self.groundnormal_z == 1)
+ self.velocity_z = 0;
+
+ self.pmove_flags |= PMF_NOSTICK;
+
+ self.velocity_z += PM_TELEJUMPSPEED;
}
- // A doublejump is two jumps within 400ms, usually +50% Z velocity.
else if (self.jump_time > (time - PM_DOUBLEJUMP_WINDOW))
{
- if (self.boost_time && self.boost_time >
- (time - PM_BOOST_WINDOW))
+ // A doublejump is two jumps within 400ms -- CEV
+ if (self.groundboost_time > 0)
{
#ifdef SSQC
dprint ("PM_Jump: stairjump ");
@@ -650,49 +638,48 @@ void() PM_Jump =
dprint ("PM_Jump: doublejump ");
#endif
}
+
#ifdef SSQC
- dprint (ftos(self.velocity_z));
- dprint (", ");
+ dprint (sprintf("%g, ", self.velocity_z));
#endif
- if (self.pmove_flags & PMF_DOUBLEJUMPED)
- {
- self.velocity_z += PM_TRIPLEJUMPSPEED;
- }
- else
- {
- self.velocity_z += PM_DOUBLEJUMPSPEED;
+
+ if (!(self.pmove_flags & PMF_DOUBLEJUMPED))
self.pmove_flags |= PMF_DOUBLEJUMPED;
- }
+
+ // set the nostick timer whenever we doublejump -- CEV
+ if (self.nostick_time <= 0)
+ self.nostick_time = PM_NOSTICK_WINDOW;
+
+ if (self.groundnormal && self.groundnormal_z == 1)
+ self.velocity_z = 0;
+
+ self.pmove_flags |= PMF_NOSTICK;
+
+ self.velocity_z += PM_DOUBLEJUMPSPEED;
}
- // normal jump
else
{
+ // normal jump
#ifdef SSQC
- dprint ("PM_Jump: jump ");
- dprint (ftos(self.velocity_z));
- dprint (", ");
+ dprint (sprintf("PM_Jump: jump %g, ", self.velocity_z));
#endif
+
self.velocity_z += PM_JUMPSPEED;
}

// report Z velocity
#ifdef SSQC
- dprint (ftos(self.velocity_z));
- dprint ("\n");
+ dprint (sprintf("%g\n", self.velocity_z));
#endif

// clear flags
PM_SetOnground (__NULL__, __NULL__, FALSE);
self.pmove_flags |= PMF_JUMP_HELD;
+
// timers
self.jump_time = time;
- if (self.boost_time)
- {
- // #ifdef SSQC
- // dprint ("PM_Jump: clearing boost_time\n");
- // #endif
- self.boost_time = 0;
- }
+ if (self.groundboost_time > 0)
+ self.groundboost_time = 0;
};

//----------------------------------------------------------------------
@@ -784,64 +771,71 @@ void() PM_WaterJump =
}
};

+//======================================================================
+// PM_WalkAccelerate
+//
+// Handle acceleration for MOVETYPE_WALK entities (players).
+// Modifies velocity. -- CEV
//----------------------------------------------------------------------
-int() PM_WalkAccelerate =
+void(float premove, float mt) PM_WalkAccelerate =
{
- vector forward, right, up;
vector wishvel, wishdir, wishang;
float wishspeed;
- int onesided;
-
- onesided = FALSE;

makevectors (input_angles);

- forward = v_forward;
- right = v_right;
- up = v_up;
-
- forward_z = 0;
- right_z = 0;
- forward = normalize (forward);
- right = normalize (right);
-
- wishvel = forward * input_movevalues_x + right * input_movevalues_y;
- if (self.movetype != MOVETYPE_WALK)
- wishvel_z = input_movevalues_z;
-
- wishspeed = vlen (wishvel);
- wishdir = normalize (wishvel);
+ wishvel = v_forward * input_movevalues_x;
+ wishvel += v_right * input_movevalues_y;
+ wishvel += v_up * input_movevalues_z;
+ wishspeed = vlen ([wishvel_x, wishvel_y, 0]);
+ wishdir = normalize ([wishvel_x, wishvel_y, 0]);

if (wishspeed > PM_MAXSPEED)
wishspeed = PM_MAXSPEED;

- if (input_buttons & 2)
- // +jump was pressed
+ if (premove)
+ {
+ if (input_buttons & 2)
+ {
+ // +jump was pressed
+ if (self.pmove_flags & PMF_ONGROUND)
+ PM_Jump ();
+ // else
+ // PM_WallJump (right);
+ }
+
if (self.pmove_flags & PMF_ONGROUND)
- PM_Jump ();
- // else
- // PM_WallJump (right);
+ self.pmove_flags |= PMF_STARTGROUND;
+ else
+ self.pmove_flags &= ~PMF_STARTGROUND;
+ }

- if (self.pmove_flags & PMF_ONGROUND)
+ // Test STARTGROUND (the ONGROUND status post jump) to avoid
+ // a ground friction frame when chaining jumps together.
+ // Probably has unintended consequences. -- CEV
+ if (self.pmove_flags & PMF_STARTGROUND)
{
- if (self.boost_time > (time - PM_BOOST_WINDOW))
+ // we're on ground so apply friction and pick an
+ // acceleration value -- CEV
+ if (self.groundboost_time > 0)
{
- PM_Friction (PM_BOOSTFRICTION);
- PM_Accelerate (wishdir, wishspeed, PM_BOOSTACCEL);
+ PM_Friction (PM_BOOSTFRICTION, mt);
+ PM_Accelerate (wishdir, wishspeed, PM_BOOSTACCEL, mt);
}
else
{
- PM_Friction (PM_FRICTION);
- PM_Accelerate (wishdir, wishspeed, PM_GROUNDACCEL);
+ PM_Friction (PM_FRICTION, mt);
+ PM_Accelerate (wishdir, wishspeed, PM_GROUNDACCEL, mt);
}
}
else
{
- // Quake 3 strafejumping if requesting both X and Y
- // -- CEV
if (input_movevalues_x && input_movevalues_y)
{
- PM_Accelerate (wishdir, wishspeed, PM_AIRACCELQ3);
+ // we're in the air and the player is requesting both
+ // forward/back and sideways movement, so pick the Q3
+ // air accel value -- CEV
+ PM_Accelerate (wishdir, wishspeed, PM_AIRACCELQ3, mt);
}
else
{
@@ -851,72 +845,108 @@ int() PM_WalkAccelerate =

// calculate the difference between the angle
// we're currently moving and the angle the
- // user is requesting to move
+ // user is requesting to move -- CEV
wishang = vectoangles (wishdir) -
- vectoangles (self.velocity);
+ vectoangles (self.velocity);
wishang_y = anglemod (wishang_y);

// limit wishang_y to a range of 0-180 (roughly)
if (wishang_y >= 180)
wishang_y = fabs (wishang_y - 360);

- /*
- #ifdef SSQC
- dprint ("PM_WalkAccelerate: wishang_y ");
- dprint (ftos(wishang_y));
- dprint ("\n");
- #endif
- */
-
- // Q1 air control when requesting movement within
- // 45 to 135 degrees of current movement -- CEV
if ((wishang_y > 45) && (wishang_y < 135) &&
- self.primal_speed >= 180)
+ vlen ([self.velocity_x, self.velocity_y, 0])
+ >= 180)
{
- PM_Q1AirAccelerate (wishvel, wishspeed,
- PM_AIRACCEL);
+ // Q1 air control when requesting movement
+ // within 45 to 135 degrees of current
+ // movement -- CEV
+ PM_AirAccelerate (wishvel, wishspeed,
+ PM_AIRACCEL, mt);
}
- // +direction style air control otherwise -- CEV
else
{
+ // +direction style air control -- CEV
if (wishang_y >= 135)
- // we're slowing down / stopping
- PM_AirControl (wishdir, wishspeed,
- PM_AIRACCELBACK);
+ // we're slowing down
+ PM_Accelerate (wishdir, wishspeed,
+ PM_AIRACCELBACK, mt);
else
- PM_AirControl (wishdir, wishspeed,
- PM_AIRACCELFWD);
+ // we're gaining speed
+ PM_Accelerate (wishdir, wishspeed,
+ PM_AIRACCELFWD, mt);
+
+ PM_AirControl (wishdir, wishspeed, mt);
}
}
}
- return onesided;
+
+ if (!premove)
+ self.pmove_flags &= ~PMF_STARTGROUND;
+};
+
+//======================================================================
+// PM_SwimAccelerate
+// Largely copied from id Software's WaterMove. Works like NoClipAccelerate.
+//----------------------------------------------------------------------
+void(float move_time) PM_SwimAccelerate =
+{
+ vector wishdir;
+ float wishspeed;
+
+ makevectors (input_angles);
+
+ wishdir = v_forward * input_movevalues_x;
+ wishdir += v_right * input_movevalues_y;
+ wishdir += v_up * input_movevalues_z;
+
+ if (input_buttons & 2)
+ // smartjump
+ wishdir_z = max (PM_MAXSPEED, wishdir_z);
+ else if (!input_movevalues)
+ // drift towards bottom; value copied from WinQuake -- CEV
+ wishdir_z -= PM_WATERSINKSPEED;
+
+ wishspeed = vlen (wishdir);
+ if (wishspeed > PM_WATERMAXSPEED)
+ wishspeed = PM_WATERMAXSPEED;
+ // value copied from WinQuake (id Software's) SV_WaterMove -- CEV
+ // wishspeed *= 0.7;
+ wishdir = normalize (wishdir);
+
+ // water friction; reuse PM_Friction with a special constant -- CEV
+ if (!(self.pmove_flags & PMF_WATERJUMP))
+ PM_Friction (PM_WATERFRICTION, move_time);
+
+ PM_Accelerate (wishdir, wishspeed, PM_WATERACCEL, move_time);
};

+//======================================================================
+// PM_NoClipAccelerate
+//
+// Basic acceleration for flying / noclipping players. Not suitable for
+// swimming. -- CEV
//----------------------------------------------------------------------
-void(float scale) PM_NoClipAccelerate =
+void(float scale, float move_time) PM_NoClipAccelerate =
{
vector wishdir;
float wishspeed;

makevectors (input_angles);

- wishdir = v_forward * input_movevalues_x +
- v_right * input_movevalues_y +
- v_up * input_movevalues_z;
+ wishdir = v_forward * input_movevalues_x;
+ wishdir += v_right * input_movevalues_y;
+ wishdir += v_up * input_movevalues_z;

+ // smartjump
if (input_buttons & 2)
- // should be water:100, slime:80, lava:50, but lets
- // just bake smartjump in here instead (we don't have
- // the client's cl_upspeed value in ssqc though).
wishdir_z = max (PM_MAXSPEED, wishdir_z);
- else if (wishdir == '0 0 0' && scale < 1)
- wishdir_z = -PM_WATERSINKSPEED;

wishspeed = vlen (wishdir) * scale;
wishdir = normalize (wishdir);

- PM_Friction (PM_FRICTION);
- PM_Accelerate (wishdir, wishspeed, PM_GROUNDACCEL);
+ PM_Friction (PM_FRICTION, move_time);
+ PM_Accelerate (wishdir, wishspeed, PM_GROUNDACCEL, move_time);
};

//======================================================================
@@ -925,11 +955,9 @@ void(float scale) PM_NoClipAccelerate =
void(entity target) PM_Move =
{
entity oldself;
- float dogravity, onesided;

oldself = self;
self = target;
- onesided = FALSE;

PM_Nudge ();

@@ -939,19 +967,6 @@ void(entity target) PM_Move =
PM_CategorizePosition ();
PM_WaterJump ();

- // save velocity + speed here -- CEV
- self.primal_velocity = self.velocity;
- self.primal_speed = vlen ([self.velocity_x, self.velocity_y, 0]);
-
- if (self.boost_time && self.boost_time <= time - PM_BOOST_WINDOW)
- {
- // Clear the boost timer if it's set
- // #ifdef SSQC
- // dprint ("PM_Move: clearing boost_time\n");
- // #endif
- self.boost_time = 0;
- }
-
if (input_timelength < 0)
{
dprint (sprintf("PM_Move: returning, input_timelength: %g\n",
@@ -963,52 +978,87 @@ void(entity target) PM_Move =
switch (self.movetype)
{
case MOVETYPE_WALK:
- if (self.waterlevel >= 2)
+ local float dogravity, doskim, dostep, sticky;
+
+ dostep = TRUE;
+ doskim = TRUE;
+ sticky = FALSE;
+
+ // split the acceleration in two to reduce
+ // framerate dependence. -- CEV
+ if (self.waterlevel >= WATERLEVEL_WAIST)
{
- PM_NoClipAccelerate (0.7);
- // water friction
- self.velocity -= 0.8 * self.waterlevel *
- input_timelength * self.velocity;
+ // no gravity, steps, or velocity-restoring
+ // behavior underwater -- CEV
+ dogravity = FALSE;
+ doskim = FALSE;
+ dostep = FALSE;
+ sticky = FALSE;
+ // swim acceleration
+ PM_SwimAccelerate (input_timelength * 0.5f);
}
else
{
- onesided = PM_WalkAccelerate ();
- }
+ PM_WalkAccelerate (TRUE,
+ input_timelength * 0.5f);

- // onesided if outside DOUBLEJUMP_WINDOW time
- if (self.jump_time <= (time - PM_DOUBLEJUMP_WINDOW))
- onesided = TRUE;
+ // WalkAccelerate calls Jump which might
+ // alter pmove_flags -- CEV
+ if (self.pmove_flags & PMF_NOSTICK)
+ sticky = FALSE;
+ else
+ sticky = TRUE;

- // don't stick to the floor when stepping up if we've
- // doublejumped recently
- if (self.pmove_flags & PMF_DOUBLEJUMPED)
- onesided = TRUE;
+ dogravity = !(self.pmove_flags & PMF_ONGROUND);
+ // apply gravity when we're on a ramp
+ if (self.groundnormal && self.groundnormal_z <1)
+ dogravity = TRUE;

- // don't stick to the floor when jumping out of water
- if ((self.pmove_flags & PMF_WATERJUMP) ||
- (self.pmove_flags & PMF_WALLJUMP))
- onesided = TRUE;
+ if ((self.jump_time <=
+ (time - PM_WALLCLIP_WINDOW)) ||
+ (self.teleport_time > (time - 0.1)) ||
+ (self.groundboost_time > 0) ||
+ (self.pmove_flags & PMF_WATERJUMP))
+ doskim = FALSE;

- if (self.boost_time >= (time - PM_BOOST_WINDOW))
- onesided = TRUE;
+ }
+
+ // timers (part 1) -- CEV
+ if (self.groundboost_time > 0)
+ self.groundboost_time -= input_timelength *0.5f;
+ if (self.nostick_time > 0)
+ self.nostick_time -= input_timelength * 0.5f;
+
+ // do the move
+ PM_NuclideMove (dogravity, sticky, dostep, doskim);

- // apply gravity when in the air
- dogravity = !(self.pmove_flags & PMF_ONGROUND);
+ // second pass at acceleration
+ if (self.waterlevel >= 2)
+ PM_SwimAccelerate (input_timelength * 0.5f);
+ else
+ PM_WalkAccelerate (FALSE,
+ input_timelength * 0.5f);

- // apply gravity when we're on a ramp
- if (self.groundnormal && self.groundnormal_z < 1)
- dogravity = TRUE;
+ // timers (part 2) -- CEV
+ if (self.groundboost_time > 0)
+ self.groundboost_time -= input_timelength *0.5f;
+ if (self.nostick_time > 0)
+ self.nostick_time -= input_timelength * 0.5f;

- PM_NuclideMove (dogravity, onesided);
break;

case MOVETYPE_FLY:
- PM_NoClipAccelerate (1.0);
- PM_NuclideMove (FALSE, TRUE);
+ // split the acceleration in two to reduce
+ // framerate dependence. -- CEV
+ PM_NoClipAccelerate (1.0f, input_timelength * 0.5f);
+ PM_NuclideMove (FALSE, TRUE, TRUE, FALSE);
+ PM_NoClipAccelerate (1.0f, input_timelength * 0.5f);
break;

case MOVETYPE_NOCLIP:
- PM_NoClipAccelerate (1.0);
+ // noclip is a debugging feature, no need to
+ // worry about consistency. -- CEV
+ PM_NoClipAccelerate (1.0f, input_timelength);
self.origin += self.velocity * input_timelength;
break;

@@ -1031,6 +1081,7 @@ void(entity target) PM_Move =
// PM_ClipVelocity
//----------------------------------------------------------------------
#if 0
+#define STOP_EPSILON 0.125
vector(vector vel, vector normal, float ob, float oneside) PM_ClipVelocity =
{
local float backoff;

Return to the top of this page or return to the overview of this repo.