djcev.com

//

Git Repos / fte_dogmode / commit 59d0c37

Commit: 59d0c37e1082d4559164e9b949313bcf26b4f36e
Parent: 347cc34a83e67b69ea1365775a58ae9991f16cb8
Author: Cameron Vanderzanden, 2024-09-17 12:58
Committer: Cameron Vanderzanden, 2024-09-17 12:58

Commit Message

Ice, improved stairs, other movement changes

Once again I don't fully remember all the changes I've made in this
commit.

Ice physics (low ground friction surfaces) have been implemented and
are triggered the same way they are in Quake 3 (through a q3bsp
surface flag). This means that Quake 3 maps with icy/slick floors
will work correctly. The acceleration is currently a bit different
than how it works in Quake 3 however. It would be a good idea to write
a new icy floor trigger volume entity for q1bsp maps.

Stairs have once again been improved; if you press jump in the frame
after you've stepped up then the expected jump flags will be set
but no Z velocity will be added. I think this is the missing piece
to make stairjumps more reliable. They certainly feel better now,
though that's subjective of course.

A few other minor changes are included here, of course.

The CSQC is still not feature complete with a vanilla engine. Headbob
and LG beam tracking the player origin are still missing at least.
I don't know when I'll get to fixing those problems.

Anyway stairs are pretty good now.

Change List

Diff qc/base_entities.qc

diff --git a/qc/base_entities.qc b/qc/base_entities.qc
index d832f0a..d63b3df 100644
--- a/qc/base_entities.qc
+++ b/qc/base_entities.qc
@@ -24,7 +24,7 @@ entity damage_attacker; // set by T_Damage

#if defined(CSQC) || defined(SSQC)
// int trace_endcontentsi; // TODO CEV fteextensions.qc
-// float trace_surfaceflags; // TODO CEV
+float trace_surfaceflagsf; // float form is deprecated
#endif

//======================================================================

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

Diff qc/base_monster.qc

diff --git a/qc/base_monster.qc b/qc/base_monster.qc
index e673415..867f6c8 100644
--- a/qc/base_monster.qc
+++ b/qc/base_monster.qc
@@ -916,8 +916,7 @@ void(float n) monster_update_total =

if (r == RANGE_NEAR)
{
- if (client.show_hostile < time && !ai_infront
- (client))
+ if (client.show_hostile < time && !(ai_infront(client)))
return FALSE;
}
else if (r == RANGE_MID)
@@ -925,7 +924,7 @@ void(float n) monster_update_total =
/*
if (client.show_hostile < time || !ai_infront (client))
*/
- if (!ai_infront(client))
+ if (!(ai_infront(client)))
return FALSE;
}

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

Diff qc/cl_entry.qc

diff --git a/qc/cl_entry.qc b/qc/cl_entry.qc
index 3307333..7ce9242 100644
--- a/qc/cl_entry.qc
+++ b/qc/cl_entry.qc
@@ -85,7 +85,7 @@ __used var float physics_mode = 2; // 0 = not run, 1 = DP, 2 = movetypes
#ifdef CSQC
float(string cmd) CSQC_ConsoleCommand;
// float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent;
-__used void() CSQC_Input_Frame;
+// __used void() CSQC_Input_Frame;
float(float save, float take, vector dir) CSQC_Parse_Damage;
void() CSQC_Parse_Event;
// void(string printmsg, float printlvl) CSQC_Parse_Print;
@@ -143,6 +143,7 @@ float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent =
// can edit the input_* globals in order to apply your own player
// inputs within csqc, which may allow you a convienient way to
// pass certain info to ssqc.
+#if 0
__used void() CSQC_Input_Frame =
{
if (serverkeyfloat(SERVERKEY_PAUSESTATE))
@@ -193,6 +194,7 @@ __used void() CSQC_Input_Frame =
}
}
};
+#endif

// This is linked to client dmg_take / dmg_save / dmg_inflictor fields
// returning TRUE will block the red flash damage stuff

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

Diff qc/cl_hud.qc

diff --git a/qc/cl_hud.qc b/qc/cl_hud.qc
index 26a5d6d..79075ce 100644
--- a/qc/cl_hud.qc
+++ b/qc/cl_hud.qc
@@ -266,7 +266,9 @@ void(vector pos, float value, float digit, float zerofill, float fontcol)
if (value < 0)
value = 0;
// Check max range against max digits
- else if (value > 999 && digit >= 3)
+ else if (value > 9999 && digit >= 4)
+ value = 9999;
+ else if (value > 999 && digit == 3)
value = 999;
else if (value > 99 && digit == 2)
value = 99;
@@ -916,7 +918,7 @@ void(vector pos) Hud_InputMonitor =
//----------------------------------------------------------------------
void(vector pos) Hud_Speedometer =
{
- Hud_DrawNoFont8 (pos, floor(view_pl.speed), 3, FALSE, HUDFONT_WHITE);
+ Hud_DrawNoFont8 (pos, floor(view_pl.speed), 4, FALSE, HUDFONT_WHITE);
};

//----------------------------------------------------------------------
@@ -1005,7 +1007,12 @@ void(vector virtsize, float showscores) CSQC_DrawHud =
pos_speedo_x = virtsize_x / 2.0;
pos_speedo_y = virtsize_y / 2.0;
pos_speedo_z = 0;
- Hud_Speedometer (pos_speedo - [8 * 1.5, -8]);
+ if (view_pl.speed > 999)
+ Hud_Speedometer (pos_speedo - [16, -8]);
+ else if (view_pl.speed > 99)
+ Hud_Speedometer (pos_speedo - [20, -8]);
+ else
+ Hud_Speedometer (pos_speedo - [24, -8]);

// Input Monitor TODO CEV
if (!cvar("crosshair"))

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

Diff qc/cshift.qc

diff --git a/qc/cshift.qc b/qc/cshift.qc
index ecaa123..059da86 100644
--- a/qc/cshift.qc
+++ b/qc/cshift.qc
@@ -42,7 +42,7 @@ void(vector ssize) csf_draw;
//----------------------------------------------------------------------
void(entity c, float d, vector col) csf_set_netsend =
{
- col = PM_TruncateVector (col);
+ col = PM_TruncateVectorToEighth (col);
WriteByte (MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte (MSG_MULTICAST, EVENT_CSHIFT_SET);
WriteShort (MSG_MULTICAST, col_x);

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

Diff qc/defs_const.qc

diff --git a/qc/defs_const.qc b/qc/defs_const.qc
index ac17fdd..2c78ab6 100644
--- a/qc/defs_const.qc
+++ b/qc/defs_const.qc
@@ -524,3 +524,36 @@ const int CONTENTBITS_BOXSOLID = CONTENTBIT_SOLID|0x00000002i |
const int CONTENTBITS_FLUID = CONTENTBIT_WATER | CONTENTBIT_SLIME |
CONTENTBIT_LAVA | CONTENTBIT_SKY;
#endif
+
+#if defined(CSQC) || defined(SSQC)
+// the following definitions are copied from dpextensions.qc -- CEV
+const float Q3SURFACEFLAG_NODAMAGE = 1;
+// low friction surface
+const float Q3SURFACEFLAG_SLICK = 2;
+// sky surface (also has NOIMPACT and NOMARKS set)
+const float Q3SURFACEFLAG_SKY = 4;
+// climbable surface
+const float Q3SURFACEFLAG_LADDER = 8;
+// projectiles should remove themselves on impact (this is set on sky)
+const float Q3SURFACEFLAG_NOIMPACT = 16;
+// projectiles should not leave marks, such as decals (this is set on sky)
+const float Q3SURFACEFLAG_NOMARKS = 32;
+// projectiles should do a fleshy effect (blood?) on impact
+const float Q3SURFACEFLAG_FLESH = 64;
+// compiler hint (not important to qc)
+const float Q3SURFACEFLAG_NODRAW = 128;
+// compiler hint (not important to qc)
+// const float Q3SURFACEFLAG_HINT = 256;
+// compiler hint (not important to qc)
+// const float Q3SURFACEFLAG_SKIP = 512;
+// compiler hint (not important to qc)
+// const float Q3SURFACEFLAG_NOLIGHTMAP = 1024;
+// compiler hint (not important to qc)
+// const float Q3SURFACEFLAG_POINTLIGHT = 2048;
+// walking on this surface should make metal step sounds
+const float Q3SURFACEFLAG_METALSTEPS = 4096;
+// walking on this surface should not make footstep sounds
+const float Q3SURFACEFLAG_NOSTEPS = 8192;
+// compiler hint (not important to qc)
+const float Q3SURFACEFLAG_NONSOLID = 16384;
+#endif

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

Diff qc/func/monster_spawner.qc

diff --git a/qc/func/monster_spawner.qc b/qc/func/monster_spawner.qc
index d0d70bc..b0049c3 100644
--- a/qc/func/monster_spawner.qc
+++ b/qc/func/monster_spawner.qc
@@ -235,7 +235,7 @@ Can only use default health, models and sounds.
//--------------------------------------------------------------
void() func_monster_spawner_think =
{
- dprint ("mobot thinking\n");
+ dprint ("func_monster_spawner_think: starting...\n");
// telefrag check thanks to ryanscissorhands for this code!
// -- dumptruck_ds
// findradius (vector origin, float radius in Quake units)
@@ -245,7 +245,8 @@ Can only use default health, models and sounds.
{
if (nearby.takedamage && nearby.solid != SOLID_CORPSE)
{
- dprint ("monster waiting to spawn\n");
+ dprint ("func_monster_spawner_think: "
+ "monster waiting to spawn\n");
// qss crash fix from paavohuhtala
// -- dumptruck_ds
self.think = func_monster_spawner_think;

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

Diff qc/monsters/ogre.qc

diff --git a/qc/monsters/ogre.qc b/qc/monsters/ogre.qc
index 2249e0a..ebe75c5 100644
--- a/qc/monsters/ogre.qc
+++ b/qc/monsters/ogre.qc
@@ -254,6 +254,8 @@ damage_mod(float) : "USE WITH CAUTION! Multiply all damage from this monster by
return TRUE;
}

+ enemy_range = ai_range (self.enemy);
+
if (enemy_range == RANGE_MELEE)
{
if (can_damage(self, self.enemy))

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

Diff qc/monsters/playerclient.qc

diff --git a/qc/monsters/playerclient.qc b/qc/monsters/playerclient.qc
index ed1f162..90533d0 100644
--- a/qc/monsters/playerclient.qc
+++ b/qc/monsters/playerclient.qc
@@ -637,8 +637,10 @@ $frame axattd1 axattd2 axattd3 axattd4 axattd5 axattd6
if (input_timelength <= 0)
break;

+ /*
if (i == clientcommandframe)
CSQC_Input_Frame ();
+ */

// see pmove.qc -- CEV
PM_Move (e);
@@ -1755,6 +1757,10 @@ $frame axattd1 axattd2 axattd3 axattd4 axattd5 axattd6
if (self.pm_flags & PMF_CROUCHED)
return;

+ // no steps when on a slick/icy surface
+ if (self.pm_flags & PMF_ONSLICK)
+ return;
+
// at least 200ms between steps
if (self.step_time >= time - 0.2)
return;
@@ -2651,13 +2657,28 @@ $frame axattd1 axattd2 axattd3 axattd4 axattd5 axattd6
if (self.deadflag)
return;

+ if (self.pm_flags & PMF_ONGROUND)
+ {
+ if (self.pm_flags & PMF_CROUCHED)
+ {
+ // TODO CEV
+ local vector l = getlight (self.origin);
+ /*
+ l = normalize (l);
+ */
+
+ dprint (sprintf("player_postthink: light %v, "
+ "level %g\n", l, vlen(l)));
+ }
+ }
+
// next block was in W_WeaponFrame -- CEV
if (time >= self.attack_finished)
{
if (self.impulse)
player_impulse ();

- if (self.button0)
+ if (input_buttons & PM_BTN_ATTACK)
{
player_superdamage_sound ();
player_attack ();

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 9ab2f11..8c16aa5 100644
--- a/qc/pmove.qc
+++ b/qc/pmove.qc
@@ -26,7 +26,7 @@ vector input_movevalues; // movement requested by client
#if defined(CSQC) || defined(SSQC)
// note: timers are expensive, require synch between server and client -- CEV
// .entity groundentity; // already defined in entvars_t
-.vector groundnormal;
+.vector groundnormal; // ground plane normal; NOT networked
.float pm_flags; // custom movement flags -- CEV
.float pm_timer; // crouchslide & jump timer -- CEV
.void() customphysics;
@@ -38,34 +38,41 @@ vector input_movevalues; // movement requested by client

#if defined(CSQC) || defined(SSQC)
// acceleration & friction
-const float PM_AIRACCEL = 8.0f; // 10 in Q1; speed gain reduced by
-const float PM_AIRACCELSCALE = 0.5f; // multiplying by this const
-const float PM_AIRACCELQ3 = 0.8f; // 1.0 in Q3 ?; now 0.8
-const float PM_AIRACCELFWD = 0.8f; // 1 feels close to Q3 / CPM
-const float PM_AIRACCELBACK = 5.0f; // Air stop speed in Q3? 5.0f?
-const float PM_AIRACCELBASE = 32.0f; // PM_MAXSPEED / 10.0
+const float PM_AIRACCELY = 70.0f; // (320 / 30) * 6.5625; 106.666 in Q1
+const float PM_AIRACCELXY = 1.0f; // for Q3 strafejumping; 1.0 in Q3
+const float PM_AIRACCELXFWD = 1.0f; // 1 feels close to Q3 / CPM
+const float PM_AIRACCELXBACK = 2.5f; // Air stop speed in Q3? 5.0f?
+const float PM_AIRACCELBASE = 32.0f; //
const float PM_AIRACCELTURN = 250.0f; // affects +fwd turning radius; 150.0f
-const float PM_GROUNDACCEL = 10.0f; // 10 is Q1, 15 is CPM
+const float PM_GROUNDACCEL = 10.0f; // 10 is Q1 & VQ3, 15 is CPM
const float PM_GROUNDFRICTION = 6.0f; // 4 for Q1, 6 for Q3, 8 for (old?) CPM
-const float PM_SLIDEACCEL = 1.0f; // crouchslide accel; 10; 8? 4?
+const float PM_SLIDEACCELY = 70.0f; //
+const float PM_SLIDEACCELXY = 1.0f; // crouchslide accel
const float PM_SLIDEFRICTION = 0.25f; // crouchslide friction; 1.0?
+const float PM_SURFACCELY = 106.666f; // (320 / 30) * 10.0
+const float PM_SURFACCELXY = 1.0f; //
const float PM_WATERACCEL = 10.0f; // water acceleration
const float PM_WATERFRICTION = 4.0f; // friction in water

// horizontal speeds (mostly)
const float PM_CROUCHSPEED = 120.0f; // ???
+const float PM_CROUCHAIRSPEED = 11.25f; // PM_CROUCHSPEED / 10.666
const float PM_MAXSPEED = 320.0f; // 320 always
-const float PM_MAXAIRSPEED = 30.0f; // 30 for Q1 air control
+const float PM_MAXAIRSPEED = 30.0f; // 30 for Q1 (PM_MAXSPEED / 10.666)
const float PM_MAXWISHSPEED = 400.0f; // 320, 400
-const float PM_RUNSPEED = 320.0f; // run speed override; 400.0 default
-const float PM_STOPSPEED = 100.0f;
-const float PM_WALKSPEED = 200.0f; // walk speed override
-const float PM_WATERMAXSPEED = 224.0f; // 320 * 0.7
+const float PM_RUNSPEED = 320.0f; // run speed; same as MAXSPEED
+const float PM_RUNAIRSPEED = 30.0f; // PM_RUNSPEED / 10.666
+const float PM_STOPSPEED = 100.0f; // used in friction calculations
+const float PM_WALKSPEED = 200.0f; // walk speed
+const float PM_WALKAIRSPEED = 18.75f; // PM_WALKSPEED / 10.666
+const float PM_WATERMAXSPEED = 224.0f; // id1 224; 320 * 0.7
const float PM_WATERSINKSPEED = 60.0f;

// vertical speeds (mostly)
const float PM_GRAVITY = 800.0f; // superseded by world_gravity global
-const float PM_CLIMBSPEED = 120.0f; // ladder & wall climbing
+const float PM_CLIMBSPEEDMIN = 45.0f; // min ladder & climbing speed
+const float PM_CLIMBSPEEDMAX = 160.0f; // max climbing speed; Rubicon2 160
+const float PM_CLIMBACCEL = 45.0f; // affected by CLIMBSCALE
const float PM_JUMPSPEED = 270.0f; // standard jump Z velocity; 90 * 3
const float PM_DOUBLEJUMPSPEED = 270.0f;// 270 * 1.5 in CPM
const float PM_STAIRJUMPSPEED = 360.0f; // 360 = 90 * 4
@@ -76,19 +83,24 @@ const float PM_WALLJUMPLIMIT = -180.f; // no walljump if Z vel below this
const float PM_WALLJUMPSPEED = 270.0f; // same as JUMPSPEED
const float PM_WALLJUMPDOUBLE = 360.0f; // same as STAIRJUMPSPEED

-// timing
+// timing (in seconds)
const float PM_CROUCHSLIDE_TIME = 1.0f; // crouchslide total duration
const float PM_DOUBLEJUMP_WINDOW = 0.4f;// 2 jumps in this time is a double
const float PM_TELEJUMP_WINDOW = 0.4f; // duration to perform a telejump
const float PM_WALLCLIP_WINDOW = 0.15f; // 0.4 - 0.25

+// button mapping (should be moved elsewhere, somewhere more global)
+const float PM_BTN_ATTACK = INPUT_BUTTON0;
+const float PM_BTN_DOWN = INPUT_BUTTON8;// crouch key
+const float PM_BTN_JUMP = INPUT_BUTTON2;// jump key
+const float PM_BTN_WALK = INPUT_BUTTON7;// walk key
+
// misc
-#define PM_MAXWISHMULT (PM_MAXWISHSPEED - PM_MAXSPEED) / PM_DOUBLEJUMP_WINDOW
-#define PM_MAXSTEPMULT PM_STEPHEIGHT / PM_DOUBLEJUMP_WINDOW
const float PM_CLIMBSCALE = 0.75; // scale XY vel by this while climbing
-const float PM_MAX_CLIP_PLANES = 3; // counting ground and self.velocity
+const float PM_EPSILONF = 0.125f; // 1.0 / 8.0; minimum float precision
+const float PM_MAX_CLIP_PLANES = 3; // counting ground
const float PM_MAXVELOCITY = 4095; // 32768 / 8.0; vel networked as short
-const float PM_OVERCLIP = 1.001f; // Q3 OVERCLIP is 1.001f, Q1 1.0f
+const float PM_OVERCLIP = 1.0f; // Q3 OVERCLIP is 1.001f, Q1 1.0f
const float PM_STEPHEIGHT = 18.0f; // 18 for Q1, 22 for later games?
const float PM_PLANE_FLAT = 1.0f; // flat horizontal
const float PM_PLANE_GROUND = 0.7f; // above this is ONGROUND
@@ -119,13 +131,14 @@ const vector PM_CROUCH_VIEWOFS = '0 0 8'; // Q3 crouch 0 0 12 -- CEV

// PM_SetOnGround flags; positive values are assumed to be SSQC entnums
const float PMG_BLANK = -1; // ignored
-const float PMG_TRACEGROUND = -2; // run a trace looking for ground
-const float PMG_NOGROUND = -3; // skip checks and clear ground flags
+const float PMG_MIDMOVE = -2; // called during DanceMove
+const float PMG_TRACEGROUND = -3; // run a trace looking for ground
+const float PMG_NOGROUND = -4; // skip checks and clear ground flags

// pmove_flags is used by the engine; FTE defines two constants:
// PMF_JUMP_HELD = 1, PMF_LADDER = 2. So those two constants should
// be first (and in that order) in our enum below. -- CEV
-// this is currently 19 flags; max flags for a float is 23 -- CEV
+// this is currently 18 flags; max flags for a float is 23 -- CEV
enumflags
{
PMF_JUMP_HELD, // player is holding the jump key
@@ -133,9 +146,11 @@ enumflags
PMF_ONGROUND, // entity is on ground
PMF_ONRAMP, // entity is on a ramp
PMF_ONSLOPE, // entity is on a steep slope
+ PMF_ONSLICK, // entity is on a slick (icy) surface
PMF_CROUCH_HELD, // player is holding the crouch key
PMF_CROUCHED, // entity is crouching
PMF_CROUCHSLIDE, // entity is crouch sliding
+ PMF_WALK_HELD, // player is holding the walk key
PMF_STEPPED, // entity has stepped up
PMF_AIRSTEPPED, // entity has airstepped
PMF_DOUBLEJUMPED, // entity has doublejumped
@@ -143,59 +158,79 @@ enumflags
PMF_WATERJUMPED, // entity has waterjumped
PMF_CLIMB, // entity is climbing
PMF_PUSHED, // entity moved by a trigger_push
- PMF_SLIDE_GRAVITY, // slidemove hint to apply gravity
- PMF_SLIDE_SKIM, // slidemove hint to skim/wallclip
- PMF_SLIDE_STEP, // slidemove hint to traverse steps
- PMF_SLIDE_STICKY // slidemove hint to stick to ground
+ PMF_SLIDE_STEP // slidemove hint to traverse steps
};

+// remove these flags when landing on ground -- CEV
+const float PM_ONGROUNDFLAGS = PMF_ONSLOPE | PMF_CLIMB | PMF_PUSHED |
+ PMF_WALLJUMPED;
+
+// remove these flags when landing on a steep slope -- CEV
+const float PM_ONSLOPEFLAGS = PMF_ONSLICK | PMF_ONRAMP | PMF_ONGROUND;
+
+// remove these flags when not on ground -- CEV
+const float PM_NOGROUNDFLAGS = PMF_ONGROUND | PMF_ONRAMP | PMF_ONSLICK |
+ PMF_ONSLOPE;
+
// don't transmit these flags from server to client -- CEV
-const float PM_SLIDEFLAGS = PMF_SLIDE_GRAVITY |
- PMF_SLIDE_SKIM | PMF_SLIDE_STEP | PMF_SLIDE_STICKY;
+const float PM_SLIDEFLAGS = PMF_SLIDE_STEP;
#endif

//======================================================================
// forward declarations
//======================================================================

-#ifdef SSQC
+#if 0
+vector(vector vel, vector normal, float overbounce) PM_ClipVelocity;
float(float maxspeed, float a, float c, float t) PM_MaxCircleGroundSpeed;
#endif

#if defined(CSQC) || defined (SSQC)
static void(entity ent) PM_DoTouch;
-vector(vector v) PM_TruncateVector;
+vector(vector v) PM_TruncateVectorToEighth;
void() PM_CheckVelocity;
float() PM_Nudge;
-vector(vector vel, vector normal, float overbounce) PM_ClipVelocity;
-void(float fl) PM_SetOnGround;
-void() PM_DanceMove;
+void(float pmg_flag) PM_SetOnGround;
+void() PM_SetNoClipFlags;
void() PM_CategorizePosition;
-void(float friction, float move_time) PM_Friction;
-void(vector dir, float wishspeed, float accel, float move_time) PM_Accelerate;
-void(vector dir, float wishspeed, float move_time) PM_AirAccelerate;
-void(vector dir, float wishspeed, float move_time) PM_AirControl;
+void() PM_DanceMove;
void() PM_CrouchStart;
void() PM_CrouchStop;
void() PM_CrouchSlideStart;
void() PM_CrouchSlideStop;
void() PM_Jump;
-void(float grounddist) PM_WallClimb;
+void() PM_WallClimb;
void() PM_WallJump;
void() PM_WallJumpCheck;
-float(float wishspeed) PM_GroundBoostWishSpeed;
-void(vector wishvel, float move_time) PM_WalkPreMove;
-void(vector wishvel, float move_time) PM_WalkAccelerate;
+void(vector wishvel, float scale, float move_time) PM_NoClipAccelerate;
void(vector wishvel, float move_time) PM_SwimPreMove;
void(vector wishvel, float move_time) PM_SwimAccelerate;
-void(vector wishvel, float scale, float move_time) PM_NoClipAccelerate;
+void(vector wishvel, float move_time) PM_WalkPreMove;
+void(vector wishvel, float move_time) PM_WalkAccelerate;
void(float move_time) PM_ManageTimer;
void(entity e) PM_Move;
#endif

//------------------------------------------------------------------------------

-#ifdef SSQC
+#if 0
+//----------------------------------------------------------------------
+// PM_ClipVelocity -- slide off the impacting surface -- CEV
+//----------------------------------------------------------------------
+vector(vector vel, vector normal, float overbounce) PM_ClipVelocity =
+{
+ // the same implementation used in Quake 3 -- CEV
+ local float backoff = vel * normal;
+
+ if (backoff < 0)
+ backoff *= overbounce;
+ else
+ backoff /= overbounce;
+
+ vel -= normal * backoff;
+ return vel;
+};
+
//----------------------------------------------------------------------
// PM_MaxCircleGroundSpeed
//
@@ -240,13 +275,13 @@ static void(entity ent) PM_DoTouch =
};

//----------------------------------------------------------------------
-// PM_TruncateVector - truncate a vector to network precision (short) -- CEV
+// PM_TruncateVector - truncate a vector to 0.125 precision -- CEV
//----------------------------------------------------------------------
-vector(vector v) PM_TruncateVector =
+vector(vector v) PM_TruncateVectorToEighth =
{
- v_x = (floor(v_x * 8 + (1.0 / 16))) * 0.125;
- v_y = (floor(v_y * 8 + (1.0 / 16))) * 0.125;
- v_z = (floor(v_z * 8 + (1.0 / 16))) * 0.125;
+ v_x = (floor(v_x * 8 + (1.0 / 16))) * PM_EPSILONF;
+ v_y = (floor(v_y * 8 + (1.0 / 16))) * PM_EPSILONF;
+ v_z = (floor(v_z * 8 + (1.0 / 16))) * PM_EPSILONF;

return v;
};
@@ -262,7 +297,7 @@ void() PM_CheckVelocity =
PM_MAXVELOCITY);
self.velocity_z = bound (-PM_MAXVELOCITY, self.velocity_z,
PM_MAXVELOCITY);
-}
+};

//----------------------------------------------------------------------
// PM_Nudge
@@ -280,7 +315,7 @@ float() PM_Nudge =
return TRUE;

// truncate to network accuracy
- org = PM_TruncateVector (org);
+ org = PM_TruncateVectorToEighth (org);

test = org;

@@ -310,42 +345,21 @@ float() PM_Nudge =
};

//----------------------------------------------------------------------
-// PM_ClipVelocity -- slide off the impacting surface -- CEV
-//----------------------------------------------------------------------
-vector(vector vel, vector normal, float overbounce) PM_ClipVelocity =
-{
- // the same implementation used in Quake 3 -- CEV
- local float backoff = vel * normal;
-
- if (backoff < 0)
- backoff *= overbounce;
- else
- backoff /= overbounce;
-
- vel -= normal * backoff;
- return vel;
-};
-
-//----------------------------------------------------------------------
// PM_SetOnGround -- manage ground flags and fields
// arguments in order are: ground entity, ground plane, ground trace
// end position, ground entity num (or PMG_* flag if negative) -- CEV
//----------------------------------------------------------------------
-void(float fl) PM_SetOnGround =
+void(float pmg_flag) PM_SetOnGround =
{
// flagged to skip checks and clear ONGROUND -- CEV
- if (fl == PMG_NOGROUND)
+ if (pmg_flag == PMG_NOGROUND)
goto PM_SetOnGround_NoGround;

- if (fl == PMG_TRACEGROUND)
+ if (pmg_flag == PMG_TRACEGROUND)
{
// do a trace to check for ground -- CEV
tracebox (self.origin, self.mins, self.maxs,
self.origin - '0 0 0.25', PM_MOVEFLAGS, self);
-
- #ifdef CSQC
- fl = trace_networkentity;
- #endif
}

// onground if we hit something & it faces upwards
@@ -362,8 +376,8 @@ void(float fl) PM_SetOnGround =
if (!(self.pm_flags & PMF_ONGROUND)) {
if (self.pm_flags & PMF_CROUCH_HELD) {
if (!(self.pm_flags & PMF_CROUCHSLIDE)) {
- if (self.conlevel == 0) {
- if (self.speed > PM_MAXSPEED)
+ if (self.conlevel < WATERLEVEL_WAIST) {
+ if (self.speed > PM_RUNSPEED)
{
PM_CrouchSlideStart ();
} } } } }
@@ -373,15 +387,23 @@ void(float fl) PM_SetOnGround =
self.groundnormal = trace_plane_normal;

// now manage flags -- CEV
- self.flags |= FL_ONGROUND;
- self.pm_flags |= PMF_ONGROUND;
+ if (pmg_flag != PMG_MIDMOVE)
+ {
+ self.flags |= FL_ONGROUND;
+ self.pm_flags |= PMF_ONGROUND;
+ }
+
if (self.groundnormal_z < PM_PLANE_FLAT)
self.pm_flags |= PMF_ONRAMP;
else if (self.pm_flags & PMF_ONRAMP)
self.pm_flags &= ~PMF_ONRAMP;
- self.pm_flags = self.pm_flags - (self.pm_flags &
- (PMF_ONSLOPE | PMF_CLIMB | PMF_PUSHED |
- PMF_WALLJUMPED));
+
+ if (trace_surfaceflagsf & Q3SURFACEFLAG_SLICK)
+ // on a slick/icy surface -- CEV
+ self.pm_flags |= PMF_ONSLICK;
+
+ self.pm_flags = self.pm_flags -
+ (self.pm_flags & PM_ONGROUNDFLAGS);
}
else if (trace_plane_normal_z > PM_PLANE_VERTICAL)
{
@@ -394,16 +416,13 @@ void(float fl) PM_SetOnGround =
// now do flags -- CEV
self.flags &= ~FL_ONGROUND;
self.pm_flags |= PMF_ONSLOPE;
- self.pm_flags = self.pm_flags - (self.pm_flags &
- (PMF_ONRAMP | PMF_ONGROUND));
+ self.pm_flags = self.pm_flags -
+ (self.pm_flags & PM_ONSLOPEFLAGS);
+ self.pm_timer = 0;

// don't crouchslide on a slope -- CEV
if (self.pm_flags & PMF_CROUCHSLIDE)
- {
- if (self.pm_timer < 0)
- self.pm_timer = 0;
PM_CrouchSlideStop ();
- }
}
else
{
@@ -413,7 +432,7 @@ void(float fl) PM_SetOnGround =

#ifdef CSQC
// don't smooth out steps when on a network ent -- CEV
- if (fl > 0 || trace_ent.velocity != '0 0 0')
+ if (trace_networkentity > 0 || trace_ent.velocity != '0 0 0')
view_step_disable = TRUE;
else if (view_step_disable)
view_step_disable = FALSE;
@@ -426,8 +445,8 @@ void(float fl) PM_SetOnGround =
self.groundentity = __NULL__;
self.groundnormal = '0 0 0';
self.flags &= ~FL_ONGROUND;
- self.pm_flags = self.pm_flags - (self.pm_flags &
- (PMF_ONSLOPE | PMF_ONRAMP | PMF_ONGROUND));
+ self.pm_flags = self.pm_flags -
+ (self.pm_flags & PM_NOGROUNDFLAGS);

// don't crouchslide in air -- CEV
if (self.pm_flags & PMF_CROUCHSLIDE)
@@ -445,6 +464,79 @@ void(float fl) PM_SetOnGround =
};

//----------------------------------------------------------------------
+void() PM_SetNoClipFlags =
+{
+ // noclip is never on ground
+ if (self.groundentity != __NULL__)
+ self.groundentity = __NULL__;
+ if (self.groundnormal != '0 0 0')
+ self.groundnormal = '0 0 0';
+ if (self.pm_flags & PMF_DOUBLEJUMPED)
+ self.pm_flags &= ~PMF_DOUBLEJUMPED;
+ if (self.pm_flags & PMF_WALLJUMPED)
+ self.pm_flags &= ~PMF_WALLJUMPED;
+ if (self.pm_flags & PMF_ONGROUND)
+ self.pm_flags &= ~PMF_ONGROUND;
+ if (self.flags & FL_ONGROUND)
+ self.flags &= ~FL_ONGROUND;
+ if (self.pm_flags & PMF_PUSHED)
+ self.pm_flags &= ~PMF_PUSHED;
+ if (self.pm_flags & PMF_CLIMB)
+ self.pm_flags &= ~PMF_CLIMB;
+
+ self.pm_timer = 0;
+};
+
+//----------------------------------------------------------------------
+// PM_CategorizePosition
+// Based on similarly-named function in the GPL2 purecsqc pmove.qc
+//----------------------------------------------------------------------
+void() PM_CategorizePosition =
+{
+ if (self.velocity_z > 180)
+ {
+ // if Z velocity is greater than 180 and we're not on a
+ // ramp or a steep slope then assume we're not onground
+ // (an optimization from Warsow / Warfork) -- CEV
+ if (self.pm_flags & PMF_ONRAMP)
+ PM_SetOnGround (PMG_TRACEGROUND);
+ else if (self.pm_flags & PMF_ONSLOPE)
+ PM_SetOnGround (PMG_TRACEGROUND);
+ else
+ PM_SetOnGround (PMG_NOGROUND);
+ }
+ else
+ {
+ // look for ground, manage flags & fields -- CEV
+ // setting onground here before the acceleration functions
+ // turns out to be faster (in my testing) than relying on
+ // DanceMove to correctly track ground state -- CEV
+ PM_SetOnGround (PMG_TRACEGROUND);
+ }
+
+ // set waterlevel and watertype -- CEV
+ base_entity_positioncontents (self);
+
+ // don't crouchslide in water -- CEV
+ if (self.pm_flags & PMF_CROUCHSLIDE) {
+ if (self.pm_flags & PMF_ONGROUND) {
+ if (self.conlevel >= WATERLEVEL_WAIST)
+ {
+ if (self.pm_timer < 0)
+ self.pm_timer = 0;
+ PM_CrouchSlideStop ();
+ } } }
+
+ // can't be waterjumping if we're on ground
+ if (self.pm_flags & PMF_WATERJUMPED) {
+ if (self.conlevel == WATERLEVEL_NONE || self.pm_flags & PMF_ONGROUND)
+ {
+ self.pm_flags &= ~PMF_WATERJUMPED;
+ self.flags &= ~FL_WATERJUMP;
+ } }
+};
+
+//----------------------------------------------------------------------
// PM_DanceMove
//
// Updates origin according to velocity, moves the player through the world.
@@ -461,7 +553,9 @@ void() PM_DanceMove =
{
local float grav = 0;

- if (self.pm_flags & PMF_SLIDE_GRAVITY)
+ if (self.conlevel < WATERLEVEL_WAIST) {
+ if (!(self.pm_flags & PMF_ONLADDER)) {
+ if (!(self.pm_flags & PMF_ONGROUND) || self.pm_flags & PMF_ONRAMP)
{
if (self.gravity)
grav = self.gravity;
@@ -472,7 +566,7 @@ void() PM_DanceMove =
// Half now, half later. Apparently affects framerate
// dependence. -- CEV
self.velocity_z -= grav * 0.5f;
- }
+ } } }

if (self.velocity == '0 0 0')
// we aren't moving so skip to clearing flags -- CEV
@@ -534,12 +628,16 @@ void() PM_DanceMove =
// requested, and we hit a vertical plane -- CEV
if (self.pm_flags & PMF_SLIDE_STEP) {
if (time_left > 0) {
- if (trace_plane_normal_z <= PM_PLANE_GROUND)
+ if (trace_plane_normal_z == PM_PLANE_VERTICAL)
{
// store the entity and plane normal from above in
// case we need to reject the step attempt -- CEV
local vector first_plane = trace_plane_normal;
local entity first_ent = trace_ent;
+ local float first_frac = trace_fraction;
+ #ifdef CSQC
+ local float first_net = trace_networkentity;
+ #endif
j = time_left;

// first: move up
@@ -569,43 +667,47 @@ void() PM_DanceMove =
// if we hit the same plane we're trying to step over
// and we made no progress in the move then reject
// the step attempt -- CEV
- if (trace_plane_normal == first_plane)
- if (self.origin_x - trace_endpos_x == 0)
- if (self.origin_y - trace_endpos_y == 0)
- goto PM_DanceMove_RejectStep;
+ if (trace_plane_normal == first_plane) {
+ if (fabs(self.origin_x - trace_endpos_x) < PM_EPSILONF)
+ if (fabs(self.origin_y - trace_endpos_y) < PM_EPSILONF)
+ goto PM_DanceMove_RejectStep;
+ }

if (trace_fraction < 1.0f)
- {
- if (trace_plane_normal_z <= PM_PLANE_GROUND) {
- if (trace_plane_normal_z != PM_PLANE_VERTICAL)
- {
- goto PM_DanceMove_RejectStep;
- } }
-
- if (trace_ent && trace_ent.touch)
+ if (trace_ent.touch)
touched_ent = trace_ent;
- }

local vector fwd_plane = trace_plane_normal;
j -= j * trace_fraction;

// third: move down
end = trace_endpos;
- end_z -= k;
+ end_z -= k + 1;
tracebox (trace_endpos, self.mins, self.maxs, end,
PM_MOVEFLAGS, self);

- if (trace_plane_normal_z <= PM_PLANE_GROUND)
- if (trace_fraction < 1.0f)
- goto PM_DanceMove_RejectStep;
- else if (trace_plane_normal == fwd_plane)
+ // When airborne and directing momentum into the
+ // intersection of a step and a wall the down move
+ // will sometimes hit nothing (trace_fraction 1
+ // plane normal '0 0 0'). We *do not* want to reject
+ // the step when this happens. -- CEV
+ if (trace_fraction == 1.0f)
+ {
+ if (trace_plane_normal_z != 0)
goto PM_DanceMove_RejectStep;
+ }
+ else if (trace_plane_normal_z <= PM_PLANE_GROUND)
+ {
+ // this is the expected and regular
+ // not-good-ground step rejection -- CEV
+ goto PM_DanceMove_RejectStep;
+ }

- if (!trace_allsolid)
+ if (trace_allsolid == FALSE)
{
// accept the stepped move. update time_left,
- // origin, touched_ent, store any planes
- // that interact, then update flags -- CEV
+ // origin, touched_ent, store any unique
+ // planes, then update flags -- CEV
time_left = j;
self.origin = trace_endpos;

@@ -631,7 +733,9 @@ void() PM_DanceMove =
self.pm_flags |= PMF_STEPPED;

if (!(self.pm_flags & PMF_ONGROUND))
- self.pm_flags |= PMF_AIRSTEPPED;
+ // this is nuts. for stairjumps. -- CEV
+ if (start_vel_z <= 0)
+ self.pm_flags |= PMF_AIRSTEPPED;
}
else
{
@@ -639,46 +743,26 @@ void() PM_DanceMove =
PM_DanceMove_RejectStep:
trace_plane_normal = first_plane;
touched_ent = trace_ent = first_ent;
+ trace_fraction = first_frac;
+ #ifdef CSQC
+ trace_networkentity = first_net;
+ #endif
}
} } }

- // we've found a ground plane so update (just a few)
- // flags and fields. the less we do here the better;
- // let PM_CategorizePosition and PM_SetOnGround handle
- // the rest at the start and end of PM_Move -- CEV
- if (trace_plane_normal_z > PM_PLANE_VERTICAL)
+ // we've found a ground plane so call PM_SetOnGround -- CEV
+ if (trace_plane_normal_z > PM_PLANE_GROUND)
{
- if (trace_plane_normal_z > PM_PLANE_GROUND)
+ #ifdef SSQC
+ // impact info (see player_postthink) -- CEV
+ if (!(self.pm_flags & PMF_ONGROUND)) {
+ if (self.velocity_z < self.jump_flag)
{
- self.groundnormal = trace_plane_normal;
-
- #ifdef SSQC
- // impact info (see player_postthink) -- CEV
- if (self.velocity_z < self.jump_flag)
- self.jump_flag = self.velocity_z;
- #endif
- }
+ self.jump_flag = self.velocity_z;
+ } }
+ #endif

- // setting the PMF_ONGROUND bit at this point will
- // introduce a ground friction frame -- CEV
- if (self.groundnormal_z <= PM_PLANE_GROUND)
- {
- self.pm_flags &= ~PMF_ONGROUND;
- self.pm_flags &= ~PMF_ONRAMP;
- self.pm_flags |= PMF_ONSLOPE;
- }
- else if (self.groundnormal_z < PM_PLANE_FLAT)
- {
- // self.pm_flags |= PMF_ONGROUND;
- self.pm_flags |= PMF_ONRAMP;
- self.pm_flags &= ~PMF_ONSLOPE;
- }
- else
- {
- // self.pm_flags |= PMF_ONGROUND;
- self.pm_flags &= ~PMF_ONRAMP;
- self.pm_flags &= ~PMF_ONSLOPE;
- }
+ PM_SetOnGround (PMG_MIDMOVE);
}

// clip to the plane if velocity interacts with it -- CEV
@@ -752,33 +836,43 @@ void() PM_DanceMove =
break;
}

- // the loop above doesn't clip to the ground plane; if SLIDE_STICKY
- // is set then make sure we do (for stairjumps) -- CEV
- if (self.pm_flags & PMF_SLIDE_STICKY) {
- if (self.groundnormal_z > PM_PLANE_GROUND)
- {
- k = self.velocity * self.groundnormal;
- self.velocity -= self.groundnormal * k;
- } }
-
- // if wall clipping / skimming was requested then restore velocity
- if (self.pm_flags & PMF_SLIDE_SKIM)
+ // if we're not onground and the timer is greater than
+ // PM_WALLCLIP_WINDOW (within 250ms of pressing jump)
+ // then restore velocity (to skim past walls) -- CEV
+ if (!(self.pm_flags & PMF_ONGROUND)) {
+ if (self.pm_timer > PM_WALLCLIP_WINDOW)
{
- j = self.velocity_z;
- k = start_vel_z;
+ j = start_vel_z;
+ k = self.velocity_z;
self.velocity = start_vel;
-
- if (self.pm_flags & PMF_ONSLOPE)
- self.velocity_z = min (j, k);
- else if (!(self.pm_flags & PMF_PUSHED))
- if (self.pm_flags & PMF_STEPPED)
- self.velocity_z = j;
- }
+ // need the min of vel_z so headbump doublejumps work -- CEV
+ if (fabs(j) > fabs(k))
+ self.velocity_z = k;
+ else
+ self.velocity_z = j;
+ } }

// final gravity check here -- CEV
- if (self.pm_flags & PMF_SLIDE_GRAVITY)
+ if (grav)
self.velocity_z -= grav * 0.5f;

+ // clip to the ground plane under certain complex conditions
+ // (this is done to recreate / simulate Q3/CPM stair behavior) -- CEV
+ if (self.pm_timer > 0) {
+ if (self.velocity_z) {
+ if (self.groundnormal_z > PM_PLANE_GROUND) {
+ if (!(self.pm_flags & PMF_CROUCH_HELD)) {
+ if (!(self.pm_flags & PMF_WALK_HELD)) {
+ if (!(self.pm_flags & PMF_DOUBLEJUMPED))
+ {
+ #if 0
+ dprint (sprintf("PM_DanceMove: glue %f\n", self.origin_z));
+ #endif
+
+ k = self.velocity * self.groundnormal;
+ self.velocity -= self.groundnormal * k;
+ } } } } } }
+
#if 0
if (i > 0)
dprint (sprintf("PM_DanceMove: move complete, "
@@ -792,248 +886,65 @@ void() PM_DanceMove =
};

//----------------------------------------------------------------------
-// PM_CategorizePosition
-// Based on similarly-named function in the GPL2 purecsqc pmove.qc
-//----------------------------------------------------------------------
-void() PM_CategorizePosition =
+void() PM_CrouchStart =
{
- if (self.movetype == MOVETYPE_NOCLIP || self.movetype == MOVETYPE_FLY)
- {
- // noclip is never on ground
- if (self.groundentity != __NULL__)
- self.groundentity = __NULL__;
- if (self.groundnormal != '0 0 0')
- self.groundnormal = '0 0 0';
- if (self.pm_flags & PMF_DOUBLEJUMPED)
- self.pm_flags &= ~PMF_DOUBLEJUMPED;
- if (self.pm_flags & PMF_WALLJUMPED)
- self.pm_flags &= ~PMF_WALLJUMPED;
- if (self.pm_flags & PMF_ONGROUND)
- self.pm_flags &= ~PMF_ONGROUND;
- if (self.flags & FL_ONGROUND)
- self.flags &= ~FL_ONGROUND;
- if (self.pm_flags & PMF_PUSHED)
- self.pm_flags &= ~PMF_PUSHED;
- if (self.pm_flags & PMF_CLIMB)
- self.pm_flags &= ~PMF_CLIMB;
+ // crouch
+ self.pm_flags |= PMF_CROUCHED;
+ // self.pm_flags |= PMF_CROUCH_HELD;
+ setsize (self, PM_CROUCH_MIN, PM_CROUCH_MAX);
+ self.view_ofs = PM_CROUCH_VIEWOFS;

- self.pm_timer = 0;
- }
- else if (self.velocity_z > 180)
- {
- // if Z velocity is greater than 180 and we're not on a
- // ramp or a steep slope then assume we're not onground
- // (an optimization from Warsow / Warfork) -- CEV
- if (self.pm_flags & PMF_ONRAMP)
- PM_SetOnGround (PMG_TRACEGROUND);
- else if (self.pm_flags & PMF_ONSLOPE)
- PM_SetOnGround (PMG_TRACEGROUND);
- else
- PM_SetOnGround (PMG_NOGROUND);
- }
- else
+ #ifdef CSQC
+ // smooth crouching -- CEV
+ if (self.entnum == player_localentnum)
{
- // look for ground, manage flags & fields -- CEV
- // setting onground here before the acceleration functions
- // turns out to be faster (in my testing) than relying on
- // DanceMove to correctly track ground state -- CEV
- PM_SetOnGround (PMG_TRACEGROUND);
+ view_offset_old = PM_STAND_VIEWOFS_z;
+ view_offset_finished = time + PLAYER_CROUCH_SMOOTH;
}
+ #endif
+};

- // set waterlevel and watertype -- CEV
- base_entity_positioncontents (self);
+//----------------------------------------------------------------------
+void() PM_CrouchStop =
+{
+ // uncrouch if we're clear to stand
+ tracebox (self.origin, PM_STAND_MIN, PM_STAND_MAX, self.origin,
+ PM_MOVEFLAGS, self);

- // don't crouchslide in water -- CEV
- if (self.pm_flags & PMF_CROUCHSLIDE) {
- if (self.pm_flags & PMF_ONGROUND) {
- if (self.conlevel > WATERLEVEL_NONE)
+ if (trace_startsolid == FALSE) {
+ if (trace_allsolid == FALSE)
{
- if (self.pm_timer < 0)
- self.pm_timer = 0;
- PM_CrouchSlideStop ();
- } } }
+ self.pm_flags &= ~PMF_CROUCHED;
+ setsize (self, PM_STAND_MIN, PM_STAND_MAX);
+ self.view_ofs = PM_STAND_VIEWOFS;

- // can't be waterjumping if we're on ground
- if (self.pm_flags & PMF_WATERJUMPED)
- {
- if (self.conlevel == WATERLEVEL_NONE ||
- self.pm_flags & PMF_ONGROUND)
+ #ifdef CSQC
+ // smooth crouching -- CEV
+ if (self.entnum == player_localentnum)
{
- self.pm_flags &= ~PMF_WATERJUMPED;
- self.flags &= ~FL_WATERJUMP;
+ view_offset_old = PM_CROUCH_VIEWOFS_z;
+ view_offset_finished = time + PLAYER_CROUCH_SMOOTH;
}
- }
+ #endif
+ } }
};

//----------------------------------------------------------------------
-// PM_Friction -- standard ground friction -- CEV
+// PM_CrouchSlideStart
+// Crouchslide behavior is based on Rapha's Quake Champions movement
+// tutorial found here: https://www.youtube.com/watch?v=95spyl1LRTc&t=1039s
+// because I've never played QC (or Q4). Please note that it doesn't
+// work exactly as described in that video. -- CEV
//----------------------------------------------------------------------
-void(float friction, float move_time) PM_Friction =
+void() PM_CrouchSlideStart =
{
- local float control, newspeed, speed1;
-
- speed1 = vlen (self.velocity);
-
- if (speed1 < 1)
- {
- self.velocity = '0 0 0';
- }
- else
- {
- // calculate what their new speed should be
- control = speed1 < PM_STOPSPEED ? PM_STOPSPEED : speed1;
- newspeed = speed1 - control * friction * move_time;
-
- // and slow them
- if (newspeed <= 0)
- self.velocity = '0 0 0';
- else
- self.velocity *= newspeed / speed1;
- }
-};
-
-//----------------------------------------------------------------------
-// PM_Accelerate -- ground acceleration & strafejumping -- CEV
-//----------------------------------------------------------------------
-void(vector dir, float wishspeed, float accel, float move_time) PM_Accelerate =
-{
- local float speed1 = wishspeed - (self.velocity * dir);
-
- if (speed1 > 0)
- {
- local float newspeed = accel * move_time * wishspeed;
-
- if (newspeed > speed1)
- newspeed = speed1;
-
- self.velocity += newspeed * dir;
- }
-};
-
-//----------------------------------------------------------------------
-// PM_AirAccelerate -- Quake 1 style air acceleration -- CEV
-//----------------------------------------------------------------------
-void(vector dir, float wishspeed, float move_time) PM_AirAccelerate =
-{
- local float newspeed, speed1, zspeed;
-
- zspeed = self.velocity_z;
- self.velocity_z = dir_z = 0;
- newspeed = min (wishspeed, PM_MAXAIRSPEED);
- speed1 = self.velocity * dir;
- speed1 = newspeed - speed1;
-
- if (speed1 > 0)
- {
- newspeed = min (PM_AIRACCEL * move_time * wishspeed, speed1);
-
- // below is an attempt to separate turning radius
- // from acceleration (re-using a lot of variables) -- CEV
- dir = self.velocity + newspeed * dir;
- newspeed = vlen (dir);
- speed1 = vlen (self.velocity);
-
- if (newspeed > speed1)
- {
- // we've gained speed; reduce -- CEV
- newspeed = (newspeed - speed1) * PM_AIRACCELSCALE;
- newspeed += speed1;
- // now apply the new speed -- CEV
- self.velocity = normalize (dir);
- self.velocity *= newspeed;
- }
- else
- {
- self.velocity = dir;
- }
- }
-
- self.velocity_z = zspeed;
-};
-
-//----------------------------------------------------------------------
-// PM_AirControl -- CPM / Nexuiz / PK / Warsow / Xonotic air control -- CEV
-//----------------------------------------------------------------------
-void(vector dir, float wishspeed, float move_time) PM_AirControl =
-{
- local float dot, speed1, turn, zspeed;
-
- zspeed = self.velocity_z;
- self.velocity_z = 0;
-
- speed1 = vlen (self.velocity);
- self.velocity = normalize (self.velocity);
-
- dot = self.velocity * dir;
-
- if (dot > 0)
- {
- turn = PM_AIRACCELBASE * bound (0, wishspeed / PM_MAXSPEED, 1);
- turn *= PM_AIRACCELTURN * dot * dot * move_time;
- self.velocity = self.velocity * speed1 + dir * turn;
- self.velocity = normalize (self.velocity);
- }
-
- self.velocity *= speed1;
- self.velocity_z = zspeed;
-};
-
-//----------------------------------------------------------------------
-void() PM_CrouchStart =
-{
- // crouch
- self.pm_flags |= PMF_CROUCHED;
- // self.pm_flags |= PMF_CROUCH_HELD;
- setsize (self, PM_CROUCH_MIN, PM_CROUCH_MAX);
- self.view_ofs = PM_CROUCH_VIEWOFS;
-
- #ifdef CSQC
- // smooth crouching -- CEV
- if (self.entnum == player_localentnum)
- {
- view_offset_old = PM_STAND_VIEWOFS_z;
- view_offset_finished = time + PLAYER_CROUCH_SMOOTH;
- }
- #endif
-};
-
-//----------------------------------------------------------------------
-void() PM_CrouchStop =
-{
- // uncrouch if we're clear to stand
- tracebox (self.origin, PM_STAND_MIN, PM_STAND_MAX, self.origin,
- PM_MOVEFLAGS, self);
- if (!trace_startsolid && !trace_allsolid)
- {
- self.pm_flags &= ~PMF_CROUCHED;
- setsize (self, PM_STAND_MIN, PM_STAND_MAX);
- self.view_ofs = PM_STAND_VIEWOFS;
-
- #ifdef CSQC
- // smooth crouching -- CEV
- if (self.entnum == player_localentnum)
- {
- view_offset_old = PM_CROUCH_VIEWOFS_z;
- view_offset_finished = time + PLAYER_CROUCH_SMOOTH;
- }
- #endif
- }
-};
-
-//----------------------------------------------------------------------
-// PM_CrouchSlideStart
-// Crouchslide behavior is based on Rapha's Quake Champions movement
-// tutorial found here: https://www.youtube.com/watch?v=95spyl1LRTc&t=1039s
-// because I've never played QC (or Q4). Please note that it doesn't
-// work exactly as described in that video. -- CEV
-//----------------------------------------------------------------------
-void() PM_CrouchSlideStart =
-{
- if (self.pm_timer >= 0)
+ if (self.pm_timer >= 0)
{
#ifdef SSQC
+ #if 0
sound (self, CHAN_AUTO, "player/slidestart.ogg",
0.4, ATTN_FEET);
+ #endif
sound (self, CHAN_SLIDE, "player/slide.ogg",
0.2, ATTN_FEET);
#endif
@@ -1076,7 +987,7 @@ void() PM_Jump =
#endif

// make sure we get at least jumpspeed upwards from the ground
- // plane by clamping it first. necessary for rampjumps. -- CEV
+ // plane by clipping velocity to it. necessary for rampjumps. -- CEV
if (self.groundnormal_z > PM_PLANE_GROUND)
if (self.velocity * self.groundnormal < 0)
self.velocity -= self.groundnormal *
@@ -1126,11 +1037,30 @@ void() PM_Jump =
wav = sprintf ("player/jump0%g.ogg", r2 + 1);
#endif

- // do an additive jump on non-flat ground -- CEV
if (self.pm_flags & PMF_ONRAMP)
+ {
+ // do an additive jump on non-flat ground -- CEV
self.velocity_z += PM_JUMPSPEED;
+ }
else
- self.velocity_z = PM_JUMPSPEED;
+ {
+ // ignore the jump input if the player has stepped
+ // up within the last frame (for CPM stairjumps)
+ // -- CEV
+ if (self.pm_flags & PMF_AIRSTEPPED)
+ self.velocity_z = PM_JUMPSPEED;
+ else if (self.pm_flags & PMF_CROUCH_HELD)
+ self.velocity_z = PM_JUMPSPEED;
+ else if (self.pm_flags & PMF_WALK_HELD)
+ self.velocity_z = PM_JUMPSPEED;
+ else if (!(self.pm_flags & PMF_STEPPED))
+ self.velocity_z = PM_JUMPSPEED;
+ #if 0
+ else
+ dprint (sprintf("PM_Jump: eating jump; %f\n",
+ self.origin_z));
+ #endif
+ }
}

// manage flags -- CEV
@@ -1154,22 +1084,30 @@ void() PM_Jump =
//----------------------------------------------------------------------
// PM_WallClimb -- climbing; checks performed in PM_WallJumpCheck -- CEV
//----------------------------------------------------------------------
-void(float grounddist) PM_WallClimb =
+void() PM_WallClimb =
{
// accelerate upwards toward a vertical ledge -- CEV
+ local float grav;
local float zspeed = self.velocity_z;
- if (grounddist == 0)
- grounddist = 1;
+
+ // counteract gravity with additional Z velocity -- CEV
+ if (self.gravity)
+ grav = self.gravity;
+ else
+ grav = 1.0f;
+ grav *= world_gravity * input_timelength;
+ zspeed += grav + PM_CLIMBACCEL;
+
self.velocity *= PM_CLIMBSCALE;
- self.velocity_z = bound (PM_CLIMBSPEED * 0.5f,
- zspeed + (64.0f / grounddist) * PM_CLIMBSPEED,
- PM_CLIMBSPEED * 2.0f);
+ self.velocity_z = bound (PM_CLIMBSPEEDMIN, zspeed, PM_CLIMBSPEEDMAX);

+ // reset pm_timer so we don't stick to the floor -- CEV
self.pm_flags |= PMF_CLIMB;
+ self.pm_flags |= PMF_JUMP_HELD;
+ self.pm_timer = 0;

#if 0
- dprint (sprintf("PM_WallJumpCheck: climb, vel_z %g, "
- "grounddist %g\n", self.velocity_z, grounddist));
+ dprint (sprintf("PM_WallClimb: vel_z %g\n", self.velocity_z));
#endif
};

@@ -1191,7 +1129,7 @@ void() PM_WallJump =
// walljump from that floor/wall you fell from now but you
// won't gain horizontal speed. (found this while attempting
// to circlejump over the center gap in CPM22) -- CEV
- // if (self.velocity_z > 0)
+ if (self.velocity_z > 0)
self.velocity += trace_plane_normal * PM_WALLJUMPFORCE;

if (self.pm_timer > 0)
@@ -1215,7 +1153,7 @@ void() PM_WallJump =
// manage flags & fields -- CEV
self.pm_flags |= PMF_JUMP_HELD;
self.pm_flags |= PMF_WALLJUMPED;
- self.pm_timer = PM_DOUBLEJUMP_WINDOW;
+ self.pm_timer = 0;

// server-side stuff
#ifdef SSQC
@@ -1230,15 +1168,11 @@ void() PM_WallJump =
//----------------------------------------------------------------------
void() PM_WallJumpCheck =
{
- // are we in water, waterjumping, walljumping & climbing,
- // or falling too fast? -- CEV
+ // are we in water, waterjumping, or falling too fast? -- CEV
if (self.conlevel > WATERLEVEL_NONE)
return;
if (self.pm_flags & PMF_WATERJUMPED)
return;
- if (self.pm_flags & PMF_WALLJUMPED)
- if (self.pm_flags & PMF_CLIMB)
- return;
if (self.velocity_z < PM_WALLJUMPLIMIT)
return;

@@ -1247,7 +1181,8 @@ void() PM_WallJumpCheck =
PM_MOVEFLAGS, self);
local float grounddist = self.origin_z - trace_endpos_z;
if (grounddist <= PM_WALLJUMPGROUND)
- return;
+ if (trace_plane_normal_z > PM_PLANE_GROUND)
+ return;

local float i, checks;
local vector start, end;
@@ -1296,7 +1231,7 @@ void() PM_WallJumpCheck =
// in order: we hit something and it's vaguely vertical -- CEV
if (trace_fraction < 1.0f) {
if (trace_plane_normal_z <= PM_PLANE_GROUND) {
- if (trace_plane_normal_z >= 0)
+ if (trace_plane_normal_z >= PM_PLANE_VERTICAL)
{
if (!(self.pm_flags & PMF_JUMP_HELD)) {
if (!(self.pm_flags & PMF_WALLJUMPED)) {
@@ -1310,7 +1245,7 @@ void() PM_WallJumpCheck =

if (i == 0) {
if (self.pm_flags & PMF_JUMP_HELD) {
- if (self.speed <= PM_MAXSPEED) {
+ if (self.speed <= PM_RUNSPEED) {
if (fabs(self.velocity_z) < 90.0f) {
if (grounddist > 42)
{
@@ -1347,10 +1282,7 @@ void() PM_WallJumpCheck =
if (trace_plane_normal_z >
PM_PLANE_GROUND)
{
- grounddist = trace_endpos_z -
- (self.origin_z +
- self.mins_z);
- PM_WallClimb (grounddist);
+ PM_WallClimb ();
break;
}
}
@@ -1370,10 +1302,7 @@ void() PM_WallJumpCheck =
if (trace_plane_normal_z >
PM_PLANE_GROUND)
{
- grounddist = trace_endpos_z -
- (self.origin_z +
- self.mins_z);
- PM_WallClimb (grounddist);
+ PM_WallClimb ();
break;
}
}
@@ -1388,185 +1317,50 @@ void() PM_WallJumpCheck =
};

//----------------------------------------------------------------------
-// PM_GroundBoostWishSpeed
-// scale wishspeed up based on the time remaining to doublejump -- CEV
+// PM_NoClipAccelerate -- for flying / noclip; not for swimming -- CEV
//----------------------------------------------------------------------
-float(float wishspeed) PM_GroundBoostWishSpeed =
+void(vector wishvel, float scale, float move_time) PM_NoClipAccelerate =
{
- // broke this up into multiple lines to improve readability -- CEV
- local float wishnew;
-
- wishnew = (PM_DOUBLEJUMP_WINDOW - self.pm_timer) * PM_MAXWISHMULT;
- wishnew = bound (PM_MAXSPEED, PM_MAXSPEED + wishnew, PM_MAXWISHSPEED);
+ local vector wishdir;
+ local float newspeed, speed1, temp, wishspeed;

- return min (wishspeed, wishnew);
-};
+ if (input_buttons & PM_BTN_JUMP)
+ // smartjump
+ wishvel_z = max (PM_MAXSPEED, wishvel_z);
+ else if (input_buttons & PM_BTN_DOWN)
+ // smartcrouch
+ wishvel_z = min (-PM_MAXSPEED, wishvel_z);

-//----------------------------------------------------------------------
-// PM_WalkPreMove -- Check for crouching, jumping, ladders -- CEV
-//----------------------------------------------------------------------
-void(vector wishvel, float move_time) PM_WalkPreMove =
-{
- if (self.pm_flags & PMF_ONLADDER)
- {
- // ladder physics
- self.velocity *= PM_CLIMBSCALE;
+ wishspeed = vlen (wishvel) * scale;
+ wishdir = normalize (wishvel);

- if (input_buttons & INPUT_BUTTON2 || input_movevalues_z > 0)
- {
- // PlayerClimb -- johnfitz
- self.velocity_z = PM_CLIMBSPEED;
- }
- else if (input_buttons & INPUT_BUTTON8 || input_movevalues_z<0)
- {
- // PlayerClimbDown -- CEV
- self.velocity_z = -PM_CLIMBSPEED;
- }
- else
- {
- self.flags |= FL_JUMPRELEASED;
- self.pm_flags &= ~PMF_JUMP_HELD;
- self.velocity_z = 0;
- }
+ // inline PM_Friction -- CEV
+ speed1 = vlen (self.velocity);

- self.pm_flags &= ~PMF_ONGROUND;
+ if (speed1 < PM_EPSILONF)
+ {
+ self.velocity = '0 0 0';
}
else
{
- if (input_buttons & INPUT_BUTTON2)
- {
- // +jump was pressed
- if (self.pm_flags & PMF_ONGROUND)
- // normal jump
- PM_Jump ();
- else if (world_walljump)
- // walljump
- PM_WallJumpCheck ();
- }
+ // calculate what their new speed should be & slow them
+ temp = speed1 < PM_STOPSPEED ? PM_STOPSPEED : speed1;
+ newspeed = speed1 - temp * PM_GROUNDFRICTION * move_time;
+ if (newspeed <= 0)
+ self.velocity = '0 0 0';
else
- {
- self.flags |= FL_JUMPRELEASED;
- self.pm_flags &= ~PMF_JUMP_HELD;
- }
-
- if (input_buttons & INPUT_BUTTON8 &&
- !(self.pm_flags & PMF_CROUCHED))
- {
- PM_CrouchStart ();
- }
- else if (!(input_buttons & INPUT_BUTTON8) &&
- self.pm_flags & PMF_CROUCHED)
- {
- PM_CrouchStop ();
- }
+ self.velocity *= newspeed / speed1;
}
-};
-
-//----------------------------------------------------------------------
-// PM_WalkAccelerate -- accel & friction for MOVETYPE_WALK -- CEV
-//----------------------------------------------------------------------
-void(vector wishvel, float mt) PM_WalkAccelerate =
-{
- local vector dir = normalize (wishvel);
- local float wish = vlen (wishvel);
-
- // Test ONGROUND after we might've called PM_Jump to avoid a ground
- // friction frame. Probably has unintended consequences. -- CEV
- if (self.pm_flags & PMF_ONGROUND)
- {
- if (self.pm_flags & PMF_CROUCHSLIDE && self.conlevel == 0)
- {
- // movement while crouchsliding -- CEV
- wish = min (wish, PM_MAXSPEED);
- PM_Friction (PM_SLIDEFRICTION, mt);

- if (wishvel != '0 0 0') {
- if (input_movevalues_x == 0)
- {
- PM_AirAccelerate (dir, wish, mt);
- }
- else if (input_movevalues_y == 0)
- {
- local float a1 = 0;
+ // inline PM_Accelerate -- CEV
+ speed1 = wishspeed - (self.velocity * wishdir);

- if (wishvel * self.velocity < 0)
- a1 = PM_AIRACCELBACK;
- else
- a1 = PM_AIRACCELFWD;
- PM_Accelerate (dir, wish, a1, mt);
- PM_AirControl (dir, wish, mt);
- }
- else
- {
- PM_Accelerate (dir, wish, PM_SLIDEACCEL, mt);
- } }
- }
- else
- {
- // movement while onground -- CEV
- PM_Friction (PM_GROUNDFRICTION, mt);
-
- if (wishvel != '0 0 0')
- {
- if (self.pm_flags & PMF_CROUCHED)
- wish = min (wish, PM_CROUCHSPEED);
- else if (self.pm_timer > 0)
- wish = PM_GroundBoostWishSpeed (wish);
- else
- wish = min (wish, PM_MAXSPEED);
-
- PM_Accelerate (dir, wish, PM_GROUNDACCEL, mt);
- }
- }
- }
- else if (self.pm_flags & PMF_ONSLOPE)
- {
- // TODO CEV steep slope acceleration (surfing?)
- // do Q3 air accel (strafejumping) for now -- CEV
- if (wishvel != '0 0 0')
- {
- wish = min (wish, PM_MAXSPEED);
- PM_Accelerate (dir, wish, PM_AIRACCELQ3, mt);
- }
- }
- else if (wishvel != '0 0 0')
+ if (speed1 > 0)
{
- // movement in the air -- CEV
- wish = min (wish, PM_MAXSPEED);
-
- if (input_movevalues_x == 0)
- {
- // sideways the air, so Q1 air accel -- CEV
- PM_AirAccelerate (dir, wish, mt);
- }
- else if (input_movevalues_y == 0)
- {
- local float a2 = 0;
-
- // CPM / Painkiller style air control -- CEV
- if (wishvel * self.velocity < 0)
- // against original velocity; we're slowing down
- a2 = PM_AIRACCELBACK;
- else
- // we're with original velocity - gaining speed
- a2 = PM_AIRACCELFWD;
-
- PM_Accelerate (dir, wish, a2, mt);
- PM_AirControl (dir, wish, mt);
- }
- else
- {
- // X and Y movement in the air: strafejumping -- CEV
- PM_Accelerate (dir, wish, PM_AIRACCELQ3, mt);
- }
+ newspeed = PM_GROUNDACCEL * move_time * wishspeed;
+ newspeed = min (newspeed, speed1);
+ self.velocity += newspeed * wishdir;
}
-
- #if 0
- dprint (sprintf("PM_WalkAccelerate: velocity %v, speed %g, "
- "wvel %v, wspeed %g\n",
- self.velocity, vlen ([self.velocity_x, self.velocity_y, 0]),
- wishvel, wish));
- #endif
};

//----------------------------------------------------------------------
@@ -1623,6 +1417,12 @@ void(vector wishvel, float move_time) PM_SwimPreMove =
0.6, ATTN_NORM);
} } }
#endif
+
+ if (self.pm_flags & PMF_STEPPED)
+ {
+ self.pm_flags &= ~PMF_STEPPED;
+ self.pm_flags &= ~PMF_AIRSTEPPED;
+ }
};

//----------------------------------------------------------------------
@@ -1631,63 +1431,412 @@ void(vector wishvel, float move_time) PM_SwimPreMove =
void(vector wishvel, float move_time) PM_SwimAccelerate =
{
local vector wishdir;
- local float wishspeed;
+ local float newspeed, speed1, temp, wishspeed;

if (!(self.pm_flags & PMF_WATERJUMPED))
{
- if (input_buttons & INPUT_BUTTON2)
- {
+ if (input_buttons & PM_BTN_JUMP)
// smartjump
wishvel_z = max (PM_MAXSPEED, wishvel_z);
- }
- else if (input_buttons & INPUT_BUTTON8)
- {
+ else if (input_buttons & PM_BTN_DOWN)
// smartcrouch
// self.pm_flags |= PMF_CROUCH_HELD;
wishvel_z = min (-PM_MAXSPEED, wishvel_z);
- }
else if (input_movevalues == '0 0 0')
- {
// drift towards bottom -- CEV
wishvel_z -= PM_WATERSINKSPEED;
- }
}

wishspeed = vlen (wishvel);
- if (wishspeed > PM_WATERMAXSPEED)
- wishspeed = PM_WATERMAXSPEED;
+ wishspeed = min (wishspeed, PM_WATERMAXSPEED);
wishdir = normalize (wishvel);

- // water friction; reuse PM_Friction with a special constant -- CEV
+ // inline PM_Friction -- CEV
if (!(self.pm_flags & PMF_WATERJUMPED))
- PM_Friction (PM_WATERFRICTION, move_time);
+ {
+ speed1 = vlen (self.velocity);
+
+ if (speed1 < PM_EPSILONF)
+ {
+ self.velocity = '0 0 0';
+ }
+ else
+ {
+ // calculate what their new speed should be & slow them
+ temp = speed1 < PM_STOPSPEED ? PM_STOPSPEED : speed1;
+ newspeed = speed1 - temp * PM_WATERFRICTION * move_time;
+ if (newspeed <= 0)
+ self.velocity = '0 0 0';
+ else
+ self.velocity *= newspeed / speed1;
+ }
+ }
+
+ // inline PM_Accelerate -- CEV
+ speed1 = wishspeed - (self.velocity * wishdir);
+
+ if (speed1 > 0)
+ {
+ newspeed = PM_WATERACCEL * move_time * wishspeed;
+ newspeed = min (newspeed, speed1);
+ self.velocity += newspeed * wishdir;
+ }

- // accelerate; reuse PM_Accelerate with a special constant -- CEV
- PM_Accelerate (wishdir, wishspeed, PM_WATERACCEL, move_time);
};

//----------------------------------------------------------------------
-// PM_NoClipAccelerate -- for flying / noclip; not for swimming -- CEV
+// PM_WalkPreMove -- Check for crouching, jumping, ladders -- CEV
//----------------------------------------------------------------------
-void(vector wishvel, float scale, float move_time) PM_NoClipAccelerate =
+void(vector wishvel, float move_time) PM_WalkPreMove =
{
- local float wishspeed;
+ if (self.pm_flags & PMF_ONLADDER)
+ {
+ // ladder physics
+ local float zspeed = fabs(self.velocity_z) + PM_CLIMBACCEL;
+ self.velocity *= PM_CLIMBSCALE;
+ self.speed = vlen ([self.velocity_x, self.velocity_y, 0]);

- if (input_buttons & INPUT_BUTTON2)
- // smartjump
- wishvel_z = max (PM_MAXSPEED, wishvel_z);
- else if (input_buttons & INPUT_BUTTON8)
- // smartcrouch
- wishvel_z = min (-PM_MAXSPEED, wishvel_z);
+ if (input_buttons & PM_BTN_JUMP || input_movevalues_z > 0)
+ {
+ // PlayerClimb -- johnfitz
+ self.velocity_z = bound (PM_CLIMBSPEEDMIN, zspeed,
+ PM_CLIMBSPEEDMAX);
+ }
+ else if (input_buttons & PM_BTN_DOWN || input_movevalues_z < 0)
+ {
+ // PlayerClimbDown -- CEV
+ self.velocity_z = bound (-PM_CLIMBSPEEDMAX, -zspeed,
+ -PM_CLIMBSPEEDMIN);
+ }
+ else
+ {
+ self.flags |= FL_JUMPRELEASED;
+ self.pm_flags &= ~PMF_JUMP_HELD;
+ self.velocity_z = 0;
+ }

- wishspeed = vlen (wishvel) * scale;
- wishvel = normalize (wishvel);
+ if (self.pm_flags & PMF_ONGROUND)
+ PM_SetOnGround (PMG_NOGROUND);
+
+ self.pm_timer = 0;
+
+ return;
+ }
+
+ if (input_buttons & PM_BTN_JUMP)
+ {
+ // +jump was pressed
+ if (self.pm_flags & PMF_ONGROUND)
+ PM_Jump ();
+ else if (world_walljump)
+ PM_WallJumpCheck ();
+ }
+ else
+ {
+ self.flags |= FL_JUMPRELEASED;
+ self.pm_flags &= ~PMF_JUMP_HELD;
+ }
+
+ if (input_buttons & PM_BTN_DOWN && !(self.pm_flags & PMF_CROUCHED))
+ {
+ PM_CrouchStart ();
+ }
+ else if (!(input_buttons & PM_BTN_DOWN) && self.pm_flags & PMF_CROUCHED)
+ {
+ PM_CrouchStop ();
+ }

- PM_Friction (PM_GROUNDFRICTION, move_time);
- PM_Accelerate (wishvel, wishspeed, PM_GROUNDACCEL, move_time);
+ if (self.pm_flags & PMF_STEPPED)
+ {
+ self.pm_flags &= ~PMF_STEPPED;
+ self.pm_flags &= ~PMF_AIRSTEPPED;
+ }
};

//----------------------------------------------------------------------
+// PM_WalkAccelerate -- accel & friction for MOVETYPE_WALK -- CEV
+//----------------------------------------------------------------------
+void(vector wishvel, float move_time) PM_WalkAccelerate =
+{
+ local float accel, friction, speed1, temp, wishyaw, wishspeed;
+ local vector wishdir = normalize (wishvel);
+
+ accel = friction = wishyaw = 0;
+ wishspeed = vlen (wishvel);
+
+ // determine the user's requested movement direction / angle.
+ // inspired by IsMoveInDirection from Nexuiz / Xonotic; this
+ // is slow and could be improved -- CEV
+ if (wishspeed)
+ {
+ // work out the requested movement direction -- CEV
+ #if 1
+ // vectoyaw ignores the Z component of its input -- CEV
+ wishyaw -= vectoyaw (input_movevalues);
+ wishyaw = fabs (wishyaw - 360.0f * rint(wishyaw / 360.0f));
+
+ // we don't care about 180 (backward) wishyaw; we'll test
+ // the dotproduct of wishvel and self.velocity later to
+ // determine if we're slowing down or speeding up -- CEV
+ if (wishyaw == 180)
+ wishyaw = 0;
+ #else
+ if (input_movevalues_x)
+ if (input_movevalues_y)
+ wishyaw = 45.0f;
+ else
+ wishyaw = 0;
+ else
+ wishyaw = 90.0f;
+ #endif
+
+ if (wishyaw == 0)
+ {
+ // test if the player is looking perpendicular to the
+ // direction they're moving in (+/- 30 degrees); if
+ // that's the case then alter wishyaw so the checks
+ // below will do Q1 air accel -- CEV
+ temp = input_angles_y - vectoyaw(self.velocity);
+ temp = fabs (temp - 360.0f * rint(temp / 360.0f));
+
+ if (temp > 60.0f)
+ if (temp < 120.0f)
+ wishyaw = 90.0f;
+ }
+ }
+
+ // priority and sequence of these checks is important -- CEV
+ if (self.pm_flags & PMF_ONGROUND)
+ {
+ if (self.pm_flags & PMF_ONSLICK)
+ {
+ // ice physics; friction remains 0 -- CEV
+ wishspeed = min (wishspeed, PM_MAXSPEED);
+
+ if (wishspeed) {
+ if (wishyaw == 90)
+ {
+ // Q1 air accel -- CEV
+ accel = PM_AIRACCELY;
+ wishspeed = min (wishspeed, PM_RUNAIRSPEED);
+ }
+ else if (wishyaw == 0)
+ {
+ // CPM / Painkiller style control -- CEV
+ if (wishvel * self.velocity < 0)
+ accel = PM_AIRACCELXBACK;
+ else
+ accel = PM_AIRACCELXFWD;
+ }
+ else
+ {
+ // regular ground accel -- CEV
+ accel = PM_AIRACCELXY;
+ } }
+ }
+ else if (self.pm_flags & PMF_CROUCHSLIDE)
+ {
+ // movement while crouchsliding -- CEV
+ wishspeed = min (wishspeed, PM_CROUCHSPEED);
+
+ // water level adds extra friction -- CEV
+ friction = PM_SLIDEFRICTION + self.conlevel;
+
+ if (wishspeed) {
+ if (wishyaw == 90)
+ {
+ // Q1 air accel -- CEV
+ // same behavior as when in the air -- CEV
+ accel = PM_SLIDEACCELY;
+ wishspeed = min (wishspeed, PM_MAXAIRSPEED);
+ }
+ else if (wishyaw == 0)
+ {
+ // CPM / Painkiller style control -- CEV
+ if (wishvel * self.velocity < 0)
+ accel = PM_AIRACCELXBACK;
+ else
+ accel = PM_AIRACCELXFWD;
+ }
+ else
+ {
+ // regular ground accel -- CEV
+ accel = PM_SLIDEACCELXY;
+ } }
+ }
+ else
+ {
+ // movement onground -- CEV
+ if (self.pm_flags & PMF_STEPPED)
+ // changing the friction constant is sketchy;
+ // it might help with navigating stairs -- CEV
+ friction = PM_GROUNDFRICTION * 0.1f;
+ else
+ friction = PM_GROUNDFRICTION;
+
+ if (wishspeed)
+ {
+ if (self.pm_flags & PMF_CROUCHED)
+ temp = PM_CROUCHSPEED;
+ else if (self.pm_flags & PMF_WALK_HELD)
+ temp = PM_WALKSPEED;
+ else if (self.pm_timer > 0)
+ temp = PM_MAXWISHSPEED;
+ else
+ temp = PM_RUNSPEED;
+
+ if (self.pm_timer > 0)
+ // go directly to PM_MAXWISHSPEED
+ // for stairjumps -- CEV
+ wishspeed = temp;
+ else
+ wishspeed = min (wishspeed, temp);
+
+ if (self.pm_flags & PMF_STEPPED)
+ accel = PM_GROUNDACCEL * 0.1f;
+ else
+ accel = PM_GROUNDACCEL;
+ }
+ }
+ }
+ else if (self.pm_flags & PMF_ONSLOPE)
+ {
+ // movement while surfing -- CEV
+ if (wishspeed)
+ {
+ if (wishyaw == 45 || wishyaw == 135)
+ {
+ // regular ground accel / strafejumping -- CEV
+ accel = PM_SURFACCELXY;
+ wishspeed = min (wishspeed, PM_MAXSPEED);
+ }
+ else
+ {
+ // Q1 style air accel -- CEV
+ accel = PM_SURFACCELY;
+ wishspeed = min (wishspeed, PM_MAXAIRSPEED);
+ }
+ }
+ }
+ else if (wishspeed)
+ {
+ // movement in the air -- CEV
+ if (wishyaw == 90)
+ {
+ // Q1 air accel -- CEV
+ accel = PM_AIRACCELY;
+
+ if (self.pm_flags & PMF_CROUCHED)
+ // temp = PM_CROUCHAIRSPEED;
+ temp = PM_RUNAIRSPEED;
+ else if (self.pm_flags & PMF_WALK_HELD)
+ temp = PM_WALKAIRSPEED;
+ else
+ temp = PM_RUNAIRSPEED;
+
+ wishspeed = min (wishspeed, temp);
+ }
+ else
+ {
+ if (self.pm_flags & PMF_CROUCHED)
+ temp = PM_CROUCHSPEED;
+ else if (self.pm_flags & PMF_WALK_HELD)
+ temp = PM_WALKSPEED;
+ else
+ temp = PM_MAXSPEED;
+
+ wishspeed = min (wishspeed, temp);
+
+ if (wishyaw == 0)
+ {
+ // CPM / Painkiller style air control -- CEV
+ if (wishvel * self.velocity < 0)
+ accel = PM_AIRACCELXBACK;
+ else
+ accel = PM_AIRACCELXFWD;
+ }
+ else
+ {
+ // X and Y in the air: strafejumping -- CEV
+ accel = PM_AIRACCELXY;
+ }
+ }
+ }
+
+ // inline PM_Friction -- CEV
+ if (friction > 0)
+ {
+ speed1 = vlen ([self.velocity_x, self.velocity_y, 0]);
+
+ if (speed1 < PM_EPSILONF)
+ {
+ self.velocity = '0 0 0';
+ }
+ else
+ {
+ // calculate what their new speed should be & slow them
+ if (self.pm_timer > 0)
+ temp = speed1;
+ else if (speed1 < PM_STOPSPEED)
+ temp = PM_STOPSPEED;
+ else
+ temp = speed1;
+ temp = speed1 - temp * friction * move_time;
+ if (temp <= 0)
+ self.velocity = '0 0 0';
+ else
+ self.velocity *= temp / speed1;
+ }
+ }
+
+ // inline PM_Accelerate -- CEV
+ if (accel > 0)
+ {
+ speed1 = wishspeed - (self.velocity * wishdir);
+
+ if (speed1 > 0)
+ {
+ // borrow / re-use the accel var -- CEV
+ accel = accel * move_time * wishspeed;
+ accel = min (accel, speed1);
+ self.velocity += accel * wishdir;
+ }
+ }
+
+ // inline PM_AirControl -- CEV
+ if (wishyaw == 0 || wishyaw == 180)
+ {
+ // borrow the friction var to hold Z speed -- CEV
+ friction = self.velocity_z;
+ self.velocity_z = 0;
+
+ speed1 = vlen (self.velocity);
+ self.velocity = normalize (self.velocity);
+ // borrow the accel var to hold dotproduct -- CEV
+ accel = self.velocity * wishdir;
+
+ if (accel > 0)
+ {
+ temp = PM_AIRACCELBASE;
+ temp *= bound (0, wishspeed / PM_MAXAIRSPEED, 1);
+ temp *= PM_AIRACCELTURN * accel * accel * move_time;
+ self.velocity = self.velocity * speed1 + wishdir * temp;
+ self.velocity = normalize (self.velocity);
+ }
+
+ self.velocity *= speed1;
+ self.velocity_z = friction;
+ }
+
+ #if 0
+ dprint (sprintf("PM_WalkAccelerate: velocity %v, speed %g, "
+ "wvel %v, wspeed %g\n",
+ self.velocity, vlen ([self.velocity_x, self.velocity_y, 0]),
+ wishvel, wish));
+ #endif
+}
+
+//----------------------------------------------------------------------
// PM_ManageTimer -- pos when jumping, neg when crouchsliding -- CEV
//----------------------------------------------------------------------
void(float move_time) PM_ManageTimer =
@@ -1721,20 +1870,6 @@ void(float move_time) PM_ManageTimer =
if (self.pm_timer <= 0)
self.pm_flags &= ~PMF_DOUBLEJUMPED;
}
-
- if (self.pm_flags & PMF_AIRSTEPPED)
- {
- if (self.pm_timer <= 0)
- self.pm_flags &= ~PMF_AIRSTEPPED;
- }
-
- /*
- if (self.pm_flags & PMF_STEPPED)
- {
- if (self.pm_timer <= 0)
- self.pm_flags &= ~PMF_STEPPED;
- }
- */
};

//----------------------------------------------------------------------
@@ -1759,14 +1894,14 @@ void(entity e) PM_Move =
PM_Nudge ();

if (self.velocity != '0 0 0')
- self.velocity = PM_TruncateVector (self.velocity);
+ self.velocity = PM_TruncateVectorToEighth (self.velocity);

- // clear JUMP_HELD if it's set and the user isn't pressing BUTTON2
- if (!(input_buttons & INPUT_BUTTON2))
+ // clear JUMP_HELD if it's set and the user isn't pressing jump
+ if (!(input_buttons & PM_BTN_JUMP))
self.pm_flags &= ~PMF_JUMP_HELD;

// crouch key, crouchsliding -- CEV
- if (input_buttons & INPUT_BUTTON8)
+ if (input_buttons & PM_BTN_DOWN)
{
self.pm_flags |= PMF_CROUCH_HELD;
}
@@ -1777,8 +1912,11 @@ void(entity e) PM_Move =
PM_CrouchSlideStop ();
}

- // figure out the properties of the player's position -- CEV
- PM_CategorizePosition ();
+ // walk key, walking -- CEV
+ if (input_buttons & PM_BTN_WALK)
+ self.pm_flags |= PMF_WALK_HELD;
+ else
+ self.pm_flags &= ~PMF_WALK_HELD;

local vector wishvel;
local float half_time = input_timelength * 0.5;
@@ -1786,6 +1924,9 @@ void(entity e) PM_Move =

if (self.movetype == MOVETYPE_WALK)
{
+ // figure out the properties of the player's position -- CEV
+ PM_CategorizePosition ();
+
// split acceleration in two to improve responsiveness -- CEV
if (self.conlevel >= WATERLEVEL_WAIST)
{
@@ -1807,74 +1948,26 @@ void(entity e) PM_Move =
wishvel_z = 0;
PM_WalkPreMove (wishvel, half_time);
PM_WalkAccelerate (wishvel, half_time);
-
- // WalkPreMove calls Jump which might change pmove
- // flags so do our feature checks afterwards -- CEV
-
- // stick to the ground if we've jumped and haven't
- // yet doublejumped
- if (!(self.pm_flags & PMF_DOUBLEJUMPED)) {
- if (!(self.pm_flags & PMF_WALLJUMPED)) {
- if (!(self.pm_flags & PMF_CROUCHSLIDE)) {
- if (!(self.pm_flags & PMF_CLIMB)) {
- if (!(self.pm_flags & PMF_PUSHED))
- {
- if (self.pm_flags & PMF_STEPPED)
- {
- // consume the step event -- CEV
- self.pm_flags &= ~PMF_STEPPED;
- self.pm_flags |= PMF_SLIDE_STICKY;
- }
- else if (self.pm_timer > 0)
- {
- self.pm_flags |= PMF_SLIDE_STICKY;
- }
- else if (input_buttons & INPUT_BUTTON2)
- {
- self.pm_flags |= PMF_SLIDE_STICKY;
- }
- } } } } }
-
- // apply gravity when in the air or on a ramp -- CEV
- if (!(self.pm_flags & PMF_ONGROUND))
- self.pm_flags |= PMF_SLIDE_GRAVITY;
- else if (self.pm_flags & PMF_ONRAMP)
- self.pm_flags |= PMF_SLIDE_GRAVITY;
-
- // skim / wallclipping checks -- CEV
- if (!(self.pm_flags & PMF_ONGROUND)) {
- if (!(self.pm_flags & PMF_CLIMB)) {
- if (self.pm_timer > PM_WALLCLIP_WINDOW)
- {
- self.pm_flags |= PMF_SLIDE_SKIM;
- } } }
-
- if (self.pm_flags & PMF_ONLADDER)
- {
- // feature set for ladders -- CEV
- self.pm_flags &= ~PMF_SLIDE_GRAVITY;
- self.pm_flags &= ~PMF_SLIDE_SKIM;
- self.pm_flags &= ~PMF_SLIDE_STICKY;
- }
}

// timers (part 1) -- CEV
PM_ManageTimer (half_time);

- // step if nostep is false...
- if (world_nostep == FALSE)
+ // step if nostep is false and we're not on a ladder...
+ if (world_nostep == FALSE) {
+ if (!(self.pm_flags & PMF_ONLADDER))
{
// ... and either airstep is true or we're onground
if (world_airstep == TRUE)
self.pm_flags |= PMF_SLIDE_STEP;
else if (self.pm_flags & PMF_ONGROUND)
self.pm_flags |= PMF_SLIDE_STEP;
- }
+ } }

- // Do the move. Bounce, Rock, Skate, Roll -- CEV
if (self.velocity != '0 0 0')
PM_CheckVelocity ();

+ // Do the move. Bounce, Rock, Skate, Roll -- CEV
PM_DanceMove ();

// second pass at acceleration; note that a touch function
@@ -1890,10 +1983,14 @@ void(entity e) PM_Move =
// clear ladder flag -- CEV
if (self.pm_flags & PMF_ONLADDER)
self.pm_flags &= ~PMF_ONLADDER;
+
+ touchtriggers ();
+ base_entity_positioncontents (self);
}
else if (self.movetype == MOVETYPE_FLY)
{
// split acceleration in two to improve responsiveness -- CEV
+ PM_SetNoClipFlags ();
makevectors (input_angles);
wishvel = v_forward * input_movevalues_x;
wishvel += v_right * input_movevalues_y;
@@ -1910,10 +2007,6 @@ void(entity e) PM_Move =
self.pm_flags |= PMF_SLIDE_STEP;
}

- // clear stepped flag after doing slide feature checks -- CEV
- if (self.pm_flags & PMF_STEPPED)
- self.pm_flags &= ~PMF_STEPPED;
-
if (self.velocity != '0 0 0')
PM_CheckVelocity ();

@@ -1921,11 +2014,15 @@ void(entity e) PM_Move =

// note that the v_ vectors may have changed in the move -- CEV
PM_NoClipAccelerate (wishvel, 1.0f, half_time);
+
+ touchtriggers ();
+ base_entity_positioncontents (self);
}
else if (self.movetype == MOVETYPE_NOCLIP)
{
// noclip is a debugging feature, no need to
// worry about acceleration consistency -- CEV
+ PM_SetNoClipFlags ();
makevectors (input_angles);
wishvel = v_forward * input_movevalues_x;
wishvel += v_right * input_movevalues_y;
@@ -1935,17 +2032,13 @@ void(entity e) PM_Move =
self.origin += self.velocity * input_timelength;
}

- if (self.movetype != MOVETYPE_NOCLIP)
- touchtriggers ();
-
- PM_CategorizePosition ();
-
if (self.velocity != '0 0 0')
{
PM_CheckVelocity ();
- self.velocity = PM_TruncateVector (self.velocity);
+ self.velocity = PM_TruncateVectorToEighth (self.velocity);
}

+ self.speed = vlen ([self.velocity_x, self.velocity_y, 0]);
setorigin (self, self.origin);
self.oldorigin = self.origin;

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

Diff qc/sv_entry.qc

diff --git a/qc/sv_entry.qc b/qc/sv_entry.qc
index 182f46e..f672ae2 100644
--- a/qc/sv_entry.qc
+++ b/qc/sv_entry.qc
@@ -825,6 +825,9 @@ void() PlayerPreThink =
// call prethink on the player after double checking classtype -- CEV
if (self.classtype == CT_PLAYER)
player_prethink ();
+ else
+ dprint (sprintf("PlayerPreThink: called for a %s!\n",
+ self.classname));
};

//----------------------------------------------------------------------

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

Diff qc/triggers/push.qc

diff --git a/qc/triggers/push.qc b/qc/triggers/push.qc
index 5e14848..d422258 100644
--- a/qc/triggers/push.qc
+++ b/qc/triggers/push.qc
@@ -389,7 +389,11 @@ vector(float a, float b, float c) solve_quadratic =
else
other.velocity = self.speed * self.movedir * 10;
}
+ #if defined(CSQC)
+ else if (other.classtype == CT_PLAYER)
+ #elif defined(SSQC)
else if (other.health > 0)
+ #endif
{
if (self.state == TRIGGER_PUSH_STATE_TARGETED)
other.velocity = self.movedir;
@@ -401,6 +405,7 @@ vector(float a, float b, float c) solve_quadratic =
// signal pmove that player has touched a
// push brush -- CEV
other.pm_flags |= PMF_PUSHED;
+ other.pm_timer = 0;

#ifdef SSQC
// carry on with normal push sound behavior

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

Diff qc/world.qc

diff --git a/qc/world.qc b/qc/world.qc
index 395f845..549b886 100644
--- a/qc/world.qc
+++ b/qc/world.qc
@@ -36,7 +36,6 @@ nosave float *world_sounds; // via Spike fun times! nosave=noclobber
#if defined(CSQC) || defined(SSQC)
float world_airstep; // latched cvars, reset on world spawn
float world_bigcoords;
-float world_clrun;
float world_gravity;
float world_maxvelocity;
float world_nostep;
@@ -85,7 +84,6 @@ void() world_latched_cvars =
{
world_airstep = autocvar (pm_airstep, TRUE);
world_bigcoords = autocvar (sv_bigcoords, FALSE);
- world_clrun = autocvar (cl_run, FALSE);
world_gravity = autocvar (sv_gravity, 800.0);
world_maxvelocity = autocvar (sv_maxvelocity, 10000.0);
world_nostep = autocvar (pm_nostep, FALSE);
@@ -397,9 +395,11 @@ float(entity e, vector offset) world_surface_type =
traceline (e.origin, e.origin + offset, 0, e);
surfnum = getsurfacenearpoint (trace_ent, trace_endpos);
tex = getsurfacetexture (trace_ent, surfnum);
+ #if 0
dprint (sprintf("world_surface_type: trace ent %s, "
"surface id %g, texture %s\n",
trace_ent.classname, surfnum, tex));
+ #endif
}
else
{
@@ -408,9 +408,11 @@ float(entity e, vector offset) world_surface_type =
surfnum = getsurfacenearpoint (e.groundentity,
e.origin + offset);
tex = getsurfacetexture (e.groundentity, surfnum);
+ #if 0
dprint (sprintf("world_surface_type: ground ent %s, "
"surface id %g, texture %s\n",
e.groundentity.classname, surfnum, tex));
+ #endif
}

switch (known_release)

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