djcev.com

//

Git Repos / fte_dogmode / commit ebb8d53

Commit: ebb8d538e43fa70c7719b4f30c744ac0ffebfa84
Parent: c91b0a03e51febbe3ae9af98b63ad8c03f6fce02
Author: Cameron Vanderzanden, 2024-07-03 07:20
Committer: Cameron Vanderzanden, 2024-07-03 07:20

Commit Message

pmove changes and fixes, improved climbing

This is mostly changes to various parts of pmove.

Some network transmission code has changed and several fields
(velocity and the timers) are now truncated to support transmission
over the network as a short. Classtype is also now transmitted as a
short (instead of a full 32bit float).

The slidemove has changed significantly. It now uses a pair
of pointers to implement something like Quake 3's velocity
clipping loops. It also no longer tracks onground state;
PM_CategorizePosition is now called both before and after the
move instead. Some of the post-loop checks and features have
been moved around or removed. It's different and hopefully
not much slower than the previous version.

The acceleration functions have also changed. PM_WalkAccelerate
now calls individual acceleration functions (the classics
PM_Accelerate, PM_AirAccelerate, etc) instead of inlining them.
It also no longer has a special case for having landed onground
between the first and second acceleration pass. The high
level accel functions (SwimAccelerate WalkAccelerate etc)
now generate their own wishvel & wishspeed each time they're
called (may undo this change in the near future, need to test
if it would save time).

A maxvelocity check has been added. The range of each axis
of the velocity vector is +/- 4095. (4096 * 8 is 32768,
the precision of a short).

Climbing has changed a little bit, it's now only one flag and
scales its Z speed with distance from the edge the player is
climbing to. Seems OK, haven't played with it much.

A very confounding bug resulted in a 90ups speed gain after
jumping a frame or two after dropping off a ledge has been
fixed. It turns out the player could walk off the ground
they're standing on and then jump off that ground (now wall)
behind them. (fixed in PM_WallJump by not bouncing off the
wall plane when Z velocity is negative, allowing the player
to still do this - jump off the ground/wall - but not gain
speed from it).

I'm sure there's more changes I'm forgetting here.

Change List

Diff qc/base_entities.qc

diff --git a/qc/base_entities.qc b/qc/base_entities.qc
index af21e8e..bf01003 100644
--- a/qc/base_entities.qc
+++ b/qc/base_entities.qc
@@ -22,7 +22,10 @@ entity damage_attacker; // set by T_Damage
// string lastnameused; // targetname last used to trigger
#endif

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

//======================================================================
// fields
@@ -61,6 +64,10 @@ entity damage_attacker; // set by T_Damage
.float prevstate; // previous entity state
.void() olduse; // previous use function

+/*
+.int hitcontentsmaski; // FTE surface impact mask
+*/
+
.string mdl; // object stuff
.string message2; // func_laser & trigger_heal
.string noise4; // noise & noise1-3 defined in entvars_t
@@ -125,6 +132,7 @@ float() base_entity_parsemapdata;
#if defined(CSQC) || defined(SSQC)
void(entity e) base_entity_aligntoground;
void(entity e, entity p, float maxspeed) base_entity_push;
+// int(entity e, vector pos) base_entity_tracecontents;
void(entity e) base_entity_positioncontents;
#endif
#ifdef SSQC
@@ -356,11 +364,28 @@ void() noclass;
};

//--------------------------------------------------------------
+ // Nuclide's PMoveCustom_Contents function -- CEV
+ //--------------------------------------------------------------
+ /*
+ int(entity e, vector pos) base_entity_tracecontents =
+ {
+ local int ohitcontents = e.hitcontentsmaski;
+ e.hitcontentsmaski = -1;
+ traceline (pos, pos, MOVE_EVERYTHING, e);
+ e.hitcontentsmaski = ohitcontents;
+ return trace_endcontentsi;
+ };
+ */
+
+ //--------------------------------------------------------------
// Set waterlevel and watertype; based on checks from purecsqc's
// pmove.qc. Called by both monsters and players. -- CEV
//--------------------------------------------------------------
void(entity e) base_entity_positioncontents =
{
+ /*
+ local int contents = 0;
+ */
local vector v = e.origin;
#ifdef SSQC
local float oldtype = e.contype;
@@ -369,6 +394,19 @@ void() noclass;
// check contents at e's feet + 1
v_z = e.origin_z + e.mins_z + 1;
e.contype = pointcontents (v);
+
+ /*
+ contents = base_entity_tracecontents (e,v);
+ if (contents & CONTENTBIT_WATER)
+ e.contype = CONTENT_WATER;
+ else if (contents & CONTENTBIT_SLIME)
+ e.contype = CONTENT_SLIME;
+ else if (contents & CONTENTBIT_LAVA)
+ e.contype = CONTENT_LAVA;
+ else
+ e.contype = CONTENT_EMPTY;
+ */
+
if (e.contype < CONTENT_SOLID)
{
if (e.classtype == CT_PLAYER)
@@ -378,9 +416,13 @@ void() noclass;
{
v_z = e.origin_z + e.maxs_z;
if (pointcontents(v) < CONTENT_SOLID)
+ {
e.conlevel = WATERLEVEL_EYES;
+ }
else
+ {
e.conlevel = WATERLEVEL_WAIST;
+ }
}
else
{
@@ -395,9 +437,13 @@ void() noclass;
{
v_z = e.origin_z + e.maxs_z;
if (pointcontents(v) < CONTENT_SOLID)
+ {
e.conlevel = WATERLEVEL_EYES;
+ }
else
+ {
e.conlevel = WATERLEVEL_FEET;
+ }
}
else
{

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

Diff qc/base_func.qc

diff --git a/qc/base_func.qc b/qc/base_func.qc
index a3c25b5..be30ca6 100644
--- a/qc/base_func.qc
+++ b/qc/base_func.qc
@@ -172,7 +172,7 @@ strip void() base_func;
//--------------------------------------------------------------
float(entity to, float netflags) base_func_netsend =
{
- WriteFloat (MSG_ENTITY, self.classtype);
+ WriteShort (MSG_ENTITY, self.classtype);
WriteFloat (MSG_ENTITY, netflags);

if (netflags & BASE_FUNC_NET_MODEL)

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 8019589..ad201af 100644
--- a/qc/cl_entry.qc
+++ b/qc/cl_entry.qc
@@ -90,6 +90,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;
float(float save, float take, vector dir) CSQC_Parse_Damage;
void() CSQC_Parse_Event;
// void(string printmsg, float printlvl) CSQC_Parse_Print;
@@ -143,6 +144,61 @@ float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent =
};
*/

+// Called just before each time clientcommandframe is updated. You
+// 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.
+__used void() CSQC_Input_Frame =
+{
+ if (serverkeyfloat(SERVERKEY_PAUSESTATE))
+ return;
+
+ if (intermission == TRUE)
+ return;
+
+ // rework user input, copying something like QuakeSpasm's always run
+ // feature here. This turns the +speed button into a hold-to-walk
+ // button when cl_run is 0 (when FTE's always run setting is on).
+ // -- CEV
+ if (world_clrun == FALSE)
+ {
+ local float m;
+
+ // we care about x and y, not so much z -- CEV
+ if (input_movevalues_x)
+ {
+ m = fabs (input_movevalues_x);
+ if (m > 400.0f)
+ input_movevalues_x = PM_WALKSPEED *
+ (input_movevalues_x / m);
+ else if (m == 400.0f)
+ input_movevalues_x = PM_RUNSPEED *
+ (input_movevalues_x / m);
+ /*
+ else if (m != 0)
+ input_movevalues_x = PM_RUNSPEED *
+ (input_movevalues_x / m);
+ */
+ }
+
+ if (input_movevalues_y)
+ {
+ m = fabs (input_movevalues_y);
+ if (m > 400.0f)
+ input_movevalues_y = PM_WALKSPEED *
+ (input_movevalues_y / m);
+ else if (m == 400.0f)
+ input_movevalues_y = PM_RUNSPEED *
+ (input_movevalues_y / m);
+ /*
+ else if (m != 0)
+ input_movevalues_y = PM_RUNSPEED *
+ (input_movevalues_y / m);
+ */
+ }
+ }
+};
+
// This is linked to client dmg_take / dmg_save / dmg_inflictor fields
// returning TRUE will block the red flash damage stuff
float(float save, float take, vector dir) CSQC_Parse_Damage =
@@ -409,7 +465,7 @@ float() CSQC_Parse_TempEntity =
//----------------------------------------------------------------------
void(float isnew) CSQC_Ent_Update =
{
- local float type = ReadFloat ();
+ local float type = ReadShort ();

if (self.classtype && self.classtype != type)
{

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 0b280d5..26a5d6d 100644
--- a/qc/cl_hud.qc
+++ b/qc/cl_hud.qc
@@ -916,8 +916,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), 3, FALSE, HUDFONT_WHITE);
};

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

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 b8d808b..ecaa123 100644
--- a/qc/cshift.qc
+++ b/qc/cshift.qc
@@ -42,6 +42,7 @@ void(vector ssize) csf_draw;
//----------------------------------------------------------------------
void(entity c, float d, vector col) csf_set_netsend =
{
+ col = PM_TruncateVector (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_builtins.qc

diff --git a/qc/defs_builtins.qc b/qc/defs_builtins.qc
index b17448e..30a0093 100644
--- a/qc/defs_builtins.qc
+++ b/qc/defs_builtins.qc
@@ -836,12 +836,6 @@ float(string str) tokenize_console = #514;
string(string fmt, ...) sprintf = #627;
#endif

-#if defined(CSQC) || defined(SSQC)
-// Part of FTE_QC_CROSSPRODUCT -- copied from fteextensions.qc -- CEV
-// Small helper function to calculate the crossproduct of two vectors.
-vector(vector v1, vector v2) crossproduct = #0:crossproduct;
-#endif
-
#ifdef SSQC
// Writes all 4 bytes of a 32bit integer without truncating to a float
// first before converting back to an int (unlike WriteLong does, but

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 58d8b6c..de6bb9b 100644
--- a/qc/defs_const.qc
+++ b/qc/defs_const.qc
@@ -122,13 +122,6 @@ const float SERVERFLAGS_RUNE2 = 64; //
const float SERVERFLAGS_RUNE3 = 128; //
const float SERVERFLAGS_RUNE4 = 256; //

-const float CONTENT_EMPTY = -1; // values returned by pointcontents ()
-const float CONTENT_SOLID = -2;
-const float CONTENT_WATER = -3;
-const float CONTENT_SLIME = -4;
-const float CONTENT_LAVA = -5;
-const float CONTENT_SKY = -6;
-
const vector VEC_ORIGIN = '0 0 0'; // origin & null vector value

const vector VEC_HULL_MIN = '-16 -16 -24';
@@ -492,3 +485,42 @@ const float RSES_NOROTATE = 2;
const float RSES_NOTRAILS = 4;
const float RSES_NOLIGHTS = 8;
#endif
+
+#if defined(CSQC) || defined(SSQC)
+// values returned by pointcontents ()
+const float CONTENT_EMPTY = -1;
+const float CONTENT_SOLID = -2;
+const float CONTENT_WATER = -3;
+const float CONTENT_SLIME = -4;
+const float CONTENT_LAVA = -5;
+const float CONTENT_SKY = -6;
+
+// trace_endcontentsi values
+const int CONTENTBIT_NONE = 0x00000000i;
+const int CONTENTBIT_SOLID = 0x00000001i;
+const int CONTENTBIT_LAVA = 0x00000008i;
+const int CONTENTBIT_SLIME = 0x00000010i;
+const int CONTENTBIT_WATER = 0x00000020i;
+// Content bit used for .skin=CONTENT_LADDER entities.
+const int CONTENTBIT_FTELADDER = 0x00004000i;
+const int CONTENTBIT_PLAYERCLIP = 0x00010000i;
+const int CONTENTBIT_MONSTERCLIP = 0x00020000i;
+// Content bit for collisions against SOLID_BBOX/SOLID_SLIDEBOX entities.
+const int CONTENTBIT_BODY = 0x02000000i;
+// Content bit that indicates collisions against SOLID_CORPSE entities.
+const int CONTENTBIT_CORPSE = 0x04000000i;
+// Content bit specific to q2bsp (conflicts with q3bsp contents so use with
+// caution).
+const int CONTENTBIT_Q2LADDER = 0x20000000i;
+// Content bit somewhat specific to q1bsp (aliases to NODROP in q3bsp),
+// but you should probably check surfaceflags&SURF_SKY as well for q2+q3bsp too.
+const int CONTENTBIT_SKY = 0x80000000i;
+// Bits that traceline would normally consider solid */
+const int CONTENTBITS_POINTSOLID = CONTENTBIT_SOLID | 0x00000002i |
+ CONTENTBIT_BODY;
+// Bits that tracebox would normally consider solid
+const int CONTENTBITS_BOXSOLID = CONTENTBIT_SOLID|0x00000002i |
+ CONTENTBIT_BODY | CONTENTBIT_PLAYERCLIP;
+const int CONTENTBITS_FLUID = CONTENTBIT_WATER | CONTENTBIT_SLIME |
+ CONTENTBIT_LAVA | CONTENTBIT_SKY;
+#endif

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

Diff qc/func/togglewall.qc

diff --git a/qc/func/togglewall.qc b/qc/func/togglewall.qc
index 2834cd9..c4d22c0 100644
--- a/qc/func/togglewall.qc
+++ b/qc/func/togglewall.qc
@@ -104,7 +104,7 @@ TOGGLEWALL_START_OFF wall doesn't block until triggered.
//--------------------------------------------------------------
float(entity to, float netflags) func_togglewall_netsend =
{
- WriteFloat (MSG_ENTITY, self.classtype);
+ WriteShort (MSG_ENTITY, self.classtype);
WriteFloat (MSG_ENTITY, netflags);

if (netflags & TOGGLEWALL_NET_MODEL)

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

Diff qc/misc/explobox.qc

diff --git a/qc/misc/explobox.qc b/qc/misc/explobox.qc
index f19a2e4..21ae888 100644
--- a/qc/misc/explobox.qc
+++ b/qc/misc/explobox.qc
@@ -82,7 +82,7 @@ void() misc_explobox2;
//--------------------------------------------------------------
float(entity to, float netflags) base_explobox_netsend =
{
- WriteFloat (MSG_ENTITY, self.classtype);
+ WriteShort (MSG_ENTITY, self.classtype);
WriteFloat (MSG_ENTITY, netflags);

if (netflags & MISC_EXPLOBOX_NET_ORIGIN)

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

Diff qc/misc/model.qc

diff --git a/qc/misc/model.qc b/qc/misc/model.qc
index 0a50130..c85f012 100644
--- a/qc/misc/model.qc
+++ b/qc/misc/model.qc
@@ -136,7 +136,7 @@ void() misc_model;
//--------------------------------------------------------------
float(entity to, float netflags) base_misc_model_netsend =
{
- WriteFloat (MSG_ENTITY, self.classtype);
+ WriteShort (MSG_ENTITY, self.classtype);
WriteFloat (MSG_ENTITY, netflags);

if (netflags & MISC_MODEL_NET_ORIGIN)

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 fd23160..c7b827c 100644
--- a/qc/monsters/playerclient.qc
+++ b/qc/monsters/playerclient.qc
@@ -308,7 +308,7 @@ $frame axattd1 axattd2 axattd3 axattd4 axattd5 axattd6
newframe = ReadByte ();

if (netflags & PLAYER_NET_MODEL)
- self.modelindex = ReadFloat ();
+ self.modelindex = ReadShort ();

if (netflags & PLAYER_NET_ORIGIN)
{
@@ -323,16 +323,17 @@ $frame axattd1 axattd2 axattd3 axattd4 axattd5 axattd6

if (netflags & PLAYER_NET_ANGLES)
{
- self.angles_x = ReadShort () * (360 / 32767);
- self.angles_y = ReadShort () * (360 / 32767);
- self.angles_z = ReadShort () * (360 / 32767);
+ self.angles_x = ReadAngle ();
+ self.angles_y = ReadAngle ();
+ self.angles_z = ReadAngle ();
}

if (netflags & PLAYER_NET_VELOCITY)
{
- self.velocity_x = ReadCoord ();
- self.velocity_y = ReadCoord ();
- self.velocity_z = ReadCoord ();
+ self.velocity_x = ReadShort() * 0.125;
+ self.velocity_y = ReadShort() * 0.125;
+ self.velocity_z = ReadShort() * 0.125;
+ self.speed = vlen ([self.velocity_x,self.velocity_y,0]);
}

if (netflags & PLAYER_NET_FLAGS)
@@ -343,8 +344,12 @@ $frame axattd1 axattd2 axattd3 axattd4 axattd5 axattd6

if (netflags & PLAYER_NET_TIMERS)
{
- self.crouchslide_timer = ReadFloat ();
- self.doublejump_timer = ReadFloat ();
+ /*
+ local float cst1 = ReadShort() * 0.125;
+ local float djt1 = ReadShort() * 0.125;
+ */
+ self.crouchslide_timer = ReadShort() * 0.125;
+ self.doublejump_timer = ReadShort() * 0.125;
}

if (netflags & PLAYER_NET_EFFECTS)
@@ -389,10 +394,7 @@ $frame axattd1 axattd2 axattd3 axattd4 axattd5 axattd6
{
PM_CrouchStop ();
}
- self.pmove_flags = newmoveflags;
- }
- else
- {
+
self.pmove_flags = newmoveflags;
}

@@ -605,13 +607,16 @@ $frame axattd1 axattd2 axattd3 axattd4 axattd5 axattd6
if (input_timelength <= 0)
continue;

+ if (i == clientcommandframe)
+ CSQC_Input_Frame ();
+
// see pmove.qc -- CEV
PM_Move (e);
}

// add anything that was applied after (for low packet
// rate protocols)
- input_angles = view_angles;
+ // input_angles = view_angles;
};

//--------------------------------------------------------------
@@ -629,14 +634,14 @@ $frame axattd1 axattd2 axattd3 axattd4 axattd5 axattd6
//--------------------------------------------------------------
float(entity to, float netflags) player_netsend =
{
- WriteFloat (MSG_ENTITY, self.classtype);
+ WriteShort (MSG_ENTITY, self.classtype);
WriteFloat (MSG_ENTITY, netflags);

if (netflags & PLAYER_NET_FRAME)
WriteByte (MSG_ENTITY, self.frame);

if (netflags & PLAYER_NET_MODEL)
- WriteFloat (MSG_ENTITY, self.modelindex);
+ WriteShort (MSG_ENTITY, self.modelindex);

if (netflags & PLAYER_NET_ORIGIN)
{
@@ -652,28 +657,31 @@ $frame axattd1 axattd2 axattd3 axattd4 axattd5 axattd6

if (netflags & PLAYER_NET_ANGLES)
{
- WriteShort (MSG_ENTITY, self.angles_x * (32767 / 360));
- WriteShort (MSG_ENTITY, self.angles_y * (32767 / 360));
- WriteShort (MSG_ENTITY, self.angles_z * (32767 / 360));
+ WriteAngle (MSG_ENTITY, self.angles_x);
+ WriteAngle (MSG_ENTITY, self.angles_y);
+ WriteAngle (MSG_ENTITY, self.angles_z);
}

if (netflags & PLAYER_NET_VELOCITY)
{
- WriteCoord (MSG_ENTITY, self.velocity_x);
- WriteCoord (MSG_ENTITY, self.velocity_y);
- WriteCoord (MSG_ENTITY, self.velocity_z);
+ WriteShort (MSG_ENTITY, floor(self.velocity_x * 8));
+ WriteShort (MSG_ENTITY, floor(self.velocity_y * 8));
+ WriteShort (MSG_ENTITY, floor(self.velocity_z * 8));
}

if (netflags & PLAYER_NET_FLAGS)
{
WriteFloat (MSG_ENTITY, self.flags);
- WriteFloat (MSG_ENTITY, self.pmove_flags);
+ WriteFloat (MSG_ENTITY, self.pmove_flags -
+ (self.pmove_flags & PM_OMITFLAGS));
}

if (netflags & PLAYER_NET_TIMERS)
{
- WriteFloat (MSG_ENTITY, self.crouchslide_timer);
- WriteFloat (MSG_ENTITY, self.doublejump_timer);
+ WriteShort (MSG_ENTITY,
+ floor(self.crouchslide_timer * 8 + (1.0 / 16)));
+ WriteShort (MSG_ENTITY,
+ floor(self.doublejump_timer * 8 + (1.0 / 16)));
}

if (netflags & PLAYER_NET_EFFECTS)
@@ -1819,12 +1827,6 @@ $frame axattd1 axattd2 axattd3 axattd4 axattd5 axattd6
}
}

- // TODO CEV
- if (self.pmove_flags & PMF_AIRSTEPPED)
- {
- self.pmove_flags &= ~PMF_AIRSTEPPED;
- }
-
sound (self, CHAN_FEET, wav, vol, ATTN_FEET);
self.cnt++;
self.step_time = time;
@@ -2621,10 +2623,6 @@ $frame axattd1 axattd2 axattd3 axattd4 axattd5 axattd6
// intermission or finale
return;

- if (self.pmove_flags & PMF_AIRSTEPPED)
- if (self.step_time <= time - 0.4)
- self.pmove_flags &= ~PMF_AIRSTEPPED;
-
if (self.deadflag)
return;

@@ -2642,8 +2640,7 @@ $frame axattd1 axattd2 axattd3 axattd4 axattd5 axattd6
}

// check to see if player landed and play landing sound
- if ((self.jump_flag < -300) && (self.flags & FL_ONGROUND) &&
- (self.health > 0))
+ if (self.jump_flag < -300 && self.health > 0)
{
if (self.contype == CONTENT_WATER)
sound (self, CHAN_BODY, "player/h2ojump.wav",
@@ -2663,9 +2660,6 @@ $frame axattd1 axattd2 axattd3 axattd4 axattd5 axattd6
self.jump_flag = 0;
}

- if (!(self.flags & FL_ONGROUND))
- self.jump_flag = self.velocity_z;
-
// dumptruck_ds -- self replaces item_megahealth_rot in items.qc
if (self.health > self.max_health)
{

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 d5b93d6..6bd0f28 100644
--- a/qc/pmove.qc
+++ b/qc/pmove.qc
@@ -4,6 +4,8 @@

// TODO CEV: improved player unstick function
// TODO CEV: varied sounds (different jump sounds)
+// TODO CEV: bug where client and server disagree on vertical height
+// when stepping up onto a tall object (40 units? 42?)

//======================================================================
// globals
@@ -22,11 +24,10 @@ vector input_movevalues; // movement requested by client
// fields
//======================================================================

-#if defined(CSQC) || defined (SSQC)
+#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;
-.float grounddistance; // distance from ground
.float pmove_flags; // custom movement flags -- CEV
.float crouchslide_timer; // crouchslide countdown timer
.float doublejump_timer; // time in which a player can doublejump
@@ -37,12 +38,12 @@ vector input_movevalues; // movement requested by client
// pmove constants (could be reworked as cvars, would add overhead) -- CEV
//======================================================================

-#if defined(CSQC) || defined (SSQC)
+#if defined(CSQC) || defined(SSQC)
// acceleration & friction
-const float PM_AIRACCEL = 7.5f; // 10 in Q1; speed gain reduced by
-const float PM_AIRACCELSCALE = 0.3f; // multiplying by this const
-const float PM_AIRACCELQ3 = 1.0f; // 1.0 in Q3 ?; now 0.8
-const float PM_AIRACCELFWD = 1.0f; // 1 feels close to Q3 / CPM
+const float PM_AIRACCEL = 8.0f; // 10 in Q1; speed gain reduced by
+const float PM_AIRACCELSCALE = 0.25f; // multiplying by this const
+const float PM_AIRACCELQ3 = 0.8f; // 1.0 in Q3 ?; now 0.8 / 0.9
+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_AIRACCELTURN = 250.0f; // affects +fwd turning radius; 150.0f
@@ -54,13 +55,12 @@ const float PM_WATERACCEL = 10.0f; // water acceleration
const float PM_WATERFRICTION = 4.0f; // friction in water

// horizontal speeds (mostly)
-const float PM_BOOSTWISHSPEED = 380.0f; // 320, 400
const float PM_CROUCHSPEED = 120.0f; // ???
const float PM_MAXSPEED = 320.0f; // 320 always
const float PM_MAXAIRSPEED = 30.0f; // 30 for Q1 air control
+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_TELEEXITSPEED = 400.0f; // exit teleporters at this speed
const float PM_WALKSPEED = 200.0f; // walk speed override
const float PM_WATERMAXSPEED = 224.0f; // 320 * 0.7
const float PM_WATERSINKSPEED = 60.0f;
@@ -70,13 +70,11 @@ const float PM_GRAVITY = 800.0f; // superseded by world_gravity global
const float PM_CLIMBSPEED = 120.0f; // ladder & wall climbing
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_SHORTJUMPSPEED = 180.0f; // 180 = 90 * 2
-const float PM_SHORTJUMPTHRESH = 340.0f;// shortjump when horiz speed under this
const float PM_STAIRJUMPSPEED = 360.0f; // 360 = 90 * 4
const float PM_TELEJUMPSPEED = 360.0f; // same as STAIRJUMPSPEED
const float PM_WALLJUMPFORCE = 90.0f; // push away from wall
-const float PM_WALLJUMPGROUND = 28.0f; // distance from ground to allow WJ (36)
-const float PM_WALLJUMPLIMIT = -225.f; // no walljump if Z vel below this
+const float PM_WALLJUMPGROUND = 28.0f; // distance from ground to allow WJ
+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

@@ -84,15 +82,19 @@ const float PM_WALLJUMPDOUBLE = 360.0f; // same as STAIRJUMPSPEED
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_WALLJUMP_WINDOW = 0.3f; // dj timer < this to walljump
-const float PM_WALLCLIP_WINDOW = 0.25f; //
+const float PM_WALLCLIP_WINDOW = 0.15f; // 0.4 - 0.25

// misc
+#define PM_MAXWISHMULT (PM_MAXWISHSPEED - PM_MAXSPEED) / PM_DOUBLEJUMP_WINDOW
const float PM_CLIMBSCALE = 0.75; // scale XY vel by this while climbing
-const float PM_MAX_CLIP_PLANES = 5;
-const float PM_OVERCLIP = 1.0f; // Quake3's OVERCLIP is 1.001f
+const float PM_MAX_CLIP_PLANES = 4; // counting ground and self.velocity
+const float PM_MAXVELOCITY = 4095; // 32768 / 8.0; vel networked as short
+const float PM_OVERCLIP = 1.0f; // Q3 OVERCLIP is 1.001f, Q1 1.0f
const float PM_ONESIDEDCLIP = -0.1f; // -0.001, -0.01, -0.1
const float PM_STEPHEIGHT = 18.0f; // 18 for Q1, 22 for later games?
+const float PM_PLANE_FLAT = 1.0f;
+const float PM_PLANE_GROUND = 0.7f;
+const float PM_PLANE_VERTICAL = 0.0f;
const vector PM_TELEDROP = '0 0 -64'; // drop teleporter exit to floor if
#if defined(SSQC) // floor is within this distance
const float PM_MOVEFLAGS = MOVE_LAGGED;
@@ -117,6 +119,11 @@ const vector PM_CROUCH_MAX = '16 16 16'; // Q3 crouch MAX_z is 16 -- CEV
const vector PM_STAND_VIEWOFS = '0 0 22'; // Q3 default 0 0 26 -- CEV
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
+
// 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
@@ -130,19 +137,24 @@ enumflags
PMF_CROUCH_HELD, // player is holding the crouch key
PMF_CROUCHED, // entity is crouching
PMF_CROUCHSLIDE, // entity is crouch sliding
+ PMF_STEPPED, // entity has stepped up
+ PMF_AIRSTEPPED, // entity has airstepped
PMF_DOUBLEJUMPED, // entity has doublejumped
PMF_WALLJUMPED, // entity has walljumped
- PMF_CLIMB1, // entity is climbing (state 1)
- PMF_CLIMB2, // entity is climbing (state 2)
PMF_WATERJUMPED, // entity has waterjumped
+ PMF_CLIMB, // entity is climbing
+ PMF_PUSHED, // entity moved by a trigger_push
PMF_PRE_MOVE, // hint that origin hasn't updated yet
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_AIRSTEPPED, // entity has airstepped
- PMF_PUSHED // entity moved by a trigger_push
+ PMF_SLIDE_STICKY // slidemove hint to stick to ground
};
+
+// don't transmit these flags from server to client -- CEV
+const float PM_OMITFLAGS = PMF_JUMP_HELD | PMF_STARTGROUND | PMF_CROUCH_HELD |
+ PMF_PRE_MOVE | PMF_SLIDE_GRAVITY | PMF_SLIDE_SKIM |
+ PMF_SLIDE_STEP | PMF_SLIDE_STICKY;
#endif

//======================================================================
@@ -155,25 +167,27 @@ float(float maxspeed, float a, float c, float t) PM_MaxCircleGroundSpeed;

#if defined(CSQC) || defined (SSQC)
static void(entity ent) PM_DoTouch;
+vector(vector v) PM_TruncateVector;
+void() PM_CheckVelocity;
float() PM_Nudge;
vector(vector vel, vector normal) PM_ClipVelocity;
+void(entity e, vector plane, vector pos, float frac, float fl) PM_SetOnGround;
void() PM_DanceMove;
void() PM_CategorizePosition;
void(float friction, float move_time) PM_Friction;
-void(vector wishdir, float wishspeed, float accel, float move_time)
- PM_Accelerate;
-void(vector wishvel, float wishspeed, float accel, float move_time)
- PM_AirAccelerate;
-void(vector wishdir, float wishspeed, float move_time) PM_AirControl;
+void(vector dir, float wishspeed, float accel, float move_time) PM_Accelerate;
+void(vector vel, vector dir, float wishspeed, float move_time) PM_AirAccelerate;
+void(vector dir, float wishspeed, float move_time) PM_AirControl;
void() PM_CrouchStart;
void() PM_CrouchStop;
void() PM_CrouchSlideStart;
void() PM_CrouchSlideStop;
-void(vector wishdir) PM_Jump;
+void() PM_Jump;
void() PM_WallJump;
-void(vector wishvel, float move_time) PM_WalkAccelerate;
-void(vector wishvel, float move_time) PM_SwimAccelerate;
-void(vector wishvel, float scale, float move_time) PM_NoClipAccelerate;
+float(float wishspeed) PM_GroundBoostWishSpeed;
+void(float move_time) PM_WalkAccelerate;
+void(float move_time) PM_SwimAccelerate;
+void(float scale, float move_time) PM_NoClipAccelerate;
void(float move_time) PM_ManageTimers;
void(entity e) PM_Move;
#endif
@@ -208,20 +222,55 @@ float(float maxspeed, float a, float f, float t) PM_MaxCircleGroundSpeed =
//----------------------------------------------------------------------
static void(entity ent) PM_DoTouch =
{
- if (ent && ent.touch != __NULL__)
+ if (ent.touch != __NULL__)
{
- local entity stemp = self;
- local entity otemp = other;
-
- other = self;
- self = ent;
- self.touch ();
- self = stemp;
- other = otemp;
+ if (ent.touch != sub_null)
+ {
+ local entity stemp = self;
+ local entity otemp = other;
+
+ other = self;
+ self = ent;
+ self.touch ();
+ self = stemp;
+ other = otemp;
+ }
}
};

//----------------------------------------------------------------------
+// PM_TruncateVector - truncate a vector to network precision
+//----------------------------------------------------------------------
+vector(vector v) PM_TruncateVector =
+{
+ 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;
+
+ return v;
+};
+
+//----------------------------------------------------------------------
+// PM_CheckVelocity - bound self.velocity to server maximums -- CEV
+//----------------------------------------------------------------------
+void() PM_CheckVelocity =
+{
+ // could use bound here, this might be faster? -- CEV
+ if (self.velocity_x > PM_MAXVELOCITY)
+ self.velocity_x = PM_MAXVELOCITY;
+ if (self.velocity_x < -PM_MAXVELOCITY)
+ self.velocity_x = -PM_MAXVELOCITY;
+ if (self.velocity_y > PM_MAXVELOCITY)
+ self.velocity_y = PM_MAXVELOCITY;
+ if (self.velocity_y < -PM_MAXVELOCITY)
+ self.velocity_y = -PM_MAXVELOCITY;
+ if (self.velocity_z > PM_MAXVELOCITY)
+ self.velocity_z = PM_MAXVELOCITY;
+ if (self.velocity_z < -PM_MAXVELOCITY)
+ self.velocity_z = -PM_MAXVELOCITY;
+}
+
+//----------------------------------------------------------------------
// PM_Nudge
// from the GPL2 CSQCTest code that comes with FTEQW; is called often
// to nudge player origin due to float/network precision errors -- CEV
@@ -243,9 +292,7 @@ float() PM_Nudge =
return TRUE;

// truncate to network accuracy
- org_x = floor (org_x * 8 + (1.0 / 16)) * 0.125;
- org_y = floor (org_y * 8 + (1.0 / 16)) * 0.125;
- org_z = floor (org_z * 8 + (1.0 / 16)) * 0.125;
+ org = PM_TruncateVector (org);

test = org;

@@ -275,7 +322,7 @@ float() PM_Nudge =
};

//----------------------------------------------------------------------
-// PM_ClipVelocity -- slide off the impacting surface
+// PM_ClipVelocity -- slide off the impacting surface -- CEV
//----------------------------------------------------------------------
vector(vector vel, vector normal) PM_ClipVelocity =
{
@@ -286,7 +333,7 @@ vector(vector vel, vector normal) PM_ClipVelocity =
if (backoff < 0)
backoff *= PM_OVERCLIP;
else
- if (normal_z > 0.7)
+ if (normal_z > PM_PLANE_GROUND)
// only stick to the floor if flagged to do so -- CEV
if (self.pmove_flags & PMF_SLIDE_STICKY)
backoff /= PM_OVERCLIP;
@@ -300,6 +347,134 @@ vector(vector vel, vector normal) PM_ClipVelocity =
};

//----------------------------------------------------------------------
+// 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(entity g, vector plane, vector pos, float frac, float fl) PM_SetOnGround =
+{
+ // flagged to skip checks and clear ONGROUND -- CEV
+ if (fl == PMG_NOGROUND)
+ goto PM_SetOnGround_NoGround;
+
+ if (fl == PMG_TRACEGROUND)
+ {
+ // do a trace to check for ground -- CEV
+ if (!(self.pmove_flags & PMF_DOUBLEJUMPED))
+ {
+ // TODO CEV clean up this next check somehow
+ if (self.pmove_flags & PMF_STEPPED ||
+ self.pmove_flags & PMF_AIRSTEPPED ||
+ (self.doublejump_timer > 0 &&
+ self.doublejump_timer < 0.35))
+ {
+ // trace farther down to find a floor
+ // if we're setting up to stairjump;
+ // this is really aggressive -- CEV
+ tracebox (self.origin, self.mins, self.maxs,
+ self.origin - [0, 0, 4],
+ PM_MOVEFLAGS, self);
+ }
+ else
+ {
+ goto PM_SetOnGround_SmallTrace;
+ }
+ }
+ else
+ {
+ PM_SetOnGround_SmallTrace:
+ // '0 0 1' works well too -- CEV
+ tracebox (self.origin, self.mins, self.maxs,
+ self.origin - '0 0 0.250', PM_MOVEFLAGS, self);
+ }
+
+ g = trace_ent;
+ plane = trace_plane_normal;
+ pos = trace_endpos;
+ frac = trace_fraction;
+ #ifdef CSQC
+ fl = trace_networkentity;
+ #endif
+ }
+
+ // onground if we hit something & it faces upwards
+ if (frac < 1.0f && plane_z > PM_PLANE_GROUND)
+ {
+ // on ground -- CEV
+
+ // ranger likes the floor. keep in mind the requested end
+ // position in the tracebox at the start of this func -- CEV
+ if (self.origin != pos)
+ {
+ if (plane_z >= PM_PLANE_FLAT)
+ {
+ #if defined(CSQC)
+ if (fl <= 0)
+ #elif defined(SSQC)
+ if (g.velocity == '0 0 0')
+ #endif
+ {
+ setorigin (self, pos);
+ }
+ }
+ }
+
+ // start crouchsliding if: we just landed, we're holding
+ // crouch, we aren't already sliding, we're not in water,
+ // and we're going faster than run speed -- CEV
+ if (!(self.pmove_flags & PMF_ONGROUND)) {
+ if (self.pmove_flags & PMF_CROUCH_HELD) {
+ if (!(self.pmove_flags & PMF_CROUCHSLIDE)) {
+ if (self.conlevel == 0) {
+ if (self.speed > PM_MAXSPEED)
+ {
+ PM_CrouchSlideStart ();
+ } } } } }
+
+ // set groundentity if it changed -- CEV
+ if (self.groundentity != g)
+ self.groundentity = g;
+
+ // store groundnormal for later -- CEV
+ self.groundnormal = plane;
+
+ #ifdef CSQC
+ // don't smooth out steps when on a networked ent -- CEV
+ if (fl > 0)
+ view_step_disable = TRUE;
+ else if (view_step_disable)
+ view_step_disable = FALSE;
+ #endif
+
+ // set these pmove flags if not set -- CEV
+ if (!(self.flags & FL_ONGROUND))
+ self.flags |= FL_ONGROUND;
+ if (!(self.pmove_flags & PMF_ONGROUND))
+ self.pmove_flags |= PMF_ONGROUND;
+
+ // clear these pmove flags if set -- CEV
+ if (self.pmove_flags & PMF_CLIMB)
+ self.pmove_flags &= ~PMF_CLIMB;
+ if (self.pmove_flags & PMF_PUSHED)
+ self.pmove_flags &= ~PMF_PUSHED;
+ if (self.pmove_flags & PMF_WALLJUMPED)
+ self.pmove_flags &= ~PMF_WALLJUMPED;
+ }
+ else
+ {
+ // not on ground, clear pmove flags & fields -- CEV
+ PM_SetOnGround_NoGround:
+ if (self.groundentity != __NULL__)
+ self.groundentity = __NULL__;
+ self.groundnormal = __NULL__;
+ if (self.flags & FL_ONGROUND)
+ self.flags &= ~FL_ONGROUND;
+ if (self.pmove_flags & PMF_ONGROUND)
+ self.pmove_flags &= ~PMF_ONGROUND;
+ }
+};
+
+//----------------------------------------------------------------------
// PM_DanceMove
//
// Updates origin according to velocity, moves the player through the world.
@@ -314,14 +489,7 @@ vector(vector vel, vector normal) PM_ClipVelocity =
//----------------------------------------------------------------------
void() PM_DanceMove =
{
- local vector end, plane1, plane2, start_vel;
- local float f, grav, i, stepsize, time_left;
- local entity touched_ent;
-
- // silence some FTEQCC warnings -- CEV
- end = plane1 = plane2 = '0 0 0';
- f = grav = i = stepsize = 0;
- time_left = input_timelength;
+ local float grav = 0;

if (self.pmove_flags & PMF_SLIDE_GRAVITY)
{
@@ -330,28 +498,32 @@ void() PM_DanceMove =
else
grav = 1.0;
// world_gravity is set in worldspawn() -- CEV
- grav *= world_gravity * time_left;
+ grav *= world_gravity * input_timelength;
// Half now, half later. Apparently affects framerate
// dependence. -- CEV
- self.velocity_z -= grav * 0.5;
+ self.velocity_z -= grav * 0.5f;
}

- start_vel = self.velocity;
+ if (self.velocity == '0 0 0')
+ // we aren't moving so skip to clearing flags -- CEV
+ goto PM_DanceMove_ClearFlags;

- // Borrowing FTEQW's pm_airstep cvar here. If false, don't step up
- // while in the air (changes stairs) -- CEV
- if (!(world_airstep) && !(self.pmove_flags & PMF_ONGROUND))
- self.pmove_flags &= ~PMF_SLIDE_STEP;
+ // declare and initialize variables -- CEV
+ local vector end, plane1, plane2, norm_vel, start_vel;
+ local float i, j, k, maxstep, stepz, time_left;
+ local entity touched_ent;
+ local vector *jp = __NULL__;
+ local vector *kp = __NULL__;

- // no stepping. useful for testing -- CEV
- if (world_nostep)
- self.pmove_flags &= ~PMF_SLIDE_STEP;
+ end = plane1 = plane2 = '0 0 0';
+ i = j = k = maxstep = stepz = 0;
+ time_left = input_timelength;
+ start_vel = self.velocity;
+ norm_vel = normalize (self.velocity);

- // we need to bounce off surfaces (in order to slide along them),
- // so we need at 2 attempts -- comment from the Nuclide SDK
- // I've changed this to a larger number of attempts (from 3 to 5)
- // to accommodate more complex plane interactions -- CEV
- for (i = 5; time_left > 0 && i; i--)
+ // attempt at most 4 moves, stopping early if time_left runs out,
+ // clipping velocity as we go -- CEV
+ for (i = 0; time_left > 0 && i < 4; i++)
{
// set our destination & test the move -- CEV
end = self.origin + (self.velocity * time_left);
@@ -363,19 +535,22 @@ void() PM_DanceMove =
// self is in something else; attempt to nudge out
if (PM_Nudge())
continue;
- #if defined(CSQC)
else
+ #if defined(CSQC)
break;
#elif defined(SSQC)
- else
setorigin (self, self.oldorigin);
+ #endif

// nah, we're stuck. don't build up falling damage
// but allow sideways acceleration -- CEV
+ #if defined(CSQC)
+ dprint ("PM_DanceMove: client player entity stuck!\n");
+ #elif defined(SSQC)
dprint ("PM_DanceMove: server player entity stuck!\n");
self.velocity_z = 0;
- break;
#endif
+ break;
}

// accept the move -- CEV
@@ -392,48 +567,55 @@ void() PM_DanceMove =
// integrated StepSlideMove from Nuclide / CSQCTest
// only attempt to step if there's time left, stepping was
// requested, and we hit a vertical plane -- CEV
- if (self.pmove_flags & PMF_SLIDE_STEP && time_left > 0 &&
- trace_plane_normal_z == 0)
+ if (self.pmove_flags & PMF_SLIDE_STEP) {
+ if (time_left > 0) {
+ if (trace_plane_normal_z == PM_PLANE_VERTICAL)
{
// store the entity and plane normal from above
// and set up a vec to track velocity changes in
// case we need to reject the step attempt -- CEV
- local entity first_ent = trace_ent;
+ #ifdef CSQC
+ local float first_net = trace_networkentity;
+ #endif
local vector first_plane = trace_plane_normal;
- local vector new_vel = self.velocity;
- f = time_left;
+ local entity first_ent = trace_ent;
+ j = time_left;

// first: move up
trace_endpos_z += PM_STEPHEIGHT;
tracebox (self.origin, self.mins, self.maxs,
trace_endpos, PM_MOVEFLAGS, self);

- if (trace_fraction < 1.0f)
- {
- // clip velocity to the roof plane but
- // don't reduce time_left (f) by the
- // roof fraction -- CEV
- new_vel = PM_ClipVelocity (new_vel,
- trace_plane_normal);
+ local vector roof_plane = trace_plane_normal;

- if (trace_ent && trace_ent.touch)
+ if (trace_fraction < 1.0f)
+ if (trace_ent.touch)
touched_ent = trace_ent;
- }

// second: move forward
- stepsize = trace_endpos_z - self.origin_z;
- end = trace_endpos + (new_vel * f);
+ stepz = trace_endpos_z - self.origin_z;
+ end = trace_endpos + (self.velocity * j);
end_z = trace_endpos_z;
tracebox (trace_endpos, self.mins, self.maxs, end,
PM_MOVEFLAGS, self);

- // reject the step if forward move ends in a solid
- // in practice this never executes -- CEV
if (trace_allsolid || trace_startsolid)
+ {
+ // reject the step if forward move ends in a
+ // solid; in practice this never hits -- CEV
+ goto PM_DanceMove_RejectStep;
+ }
+ else if (trace_plane_normal == first_plane)
+ {
+ // we hit the same plane we're trying to step
+ // over so reject the step attempt. we might
+ // manage to step on the next iteration of
+ // the loop (wallrunning up stairs) -- CEV
goto PM_DanceMove_RejectStep;
+ }

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

if (trace_fraction < 1.0f)
if (trace_ent && trace_ent.touch)
@@ -441,7 +623,7 @@ void() PM_DanceMove =

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

@@ -451,240 +633,183 @@ void() PM_DanceMove =
// a solid. again, never executes -- CEV
goto PM_DanceMove_RejectStep;
}
- else if (trace_endpos_z - self.origin_z <= 0)
+ else if (trace_plane_normal_z > PM_PLANE_GROUND)
{
- // what am I even doing with this check -- CEV
- if (fwd_plane != first_plane &&
- self.velocity * fwd_plane < 0)
+ // update time_left, stepsize, origin,
+ // velocity & touched_ent -- CEV
+ time_left = j;
+ stepz = trace_endpos_z - self.origin_z;
+ self.origin = trace_endpos;
+
+ if (trace_ent.touch)
+ touched_ent = trace_ent;
+
+ // store roof_plane and fwd_plane if we
+ // might clip velocity to them later -- CEV
+ if (roof_plane != plane1) {
+ if (roof_plane != plane2) {
+ if (self.velocity * roof_plane < 0)
{
plane2 = plane1;
- plane1 = fwd_plane;
- }
- goto PM_DanceMove_RejectStep;
- }
- else if (trace_fraction < 1.0f &&
- trace_plane_normal_z > 0.7f)
- {
- // we're clear to update time_left, stepsize,
- // origin, velocity & touched_ent -- CEV
- time_left = f;
- stepsize = trace_endpos_z - self.origin_z;
- self.origin = trace_endpos;
+ plane1 = roof_plane;
+ } } }

- // the ClipVelocity calls below will handle
- // trace_plane_normal and fwd_plane -- CEV
- if (new_vel * fwd_plane < 0)
+ if (fwd_plane != plane1) {
+ if (fwd_plane != plane2) {
+ if (self.velocity * fwd_plane < 0)
{
plane2 = plane1;
plane1 = fwd_plane;
- }
+ } } }

- self.velocity = new_vel;
+ if (maxstep < stepz)
+ maxstep = stepz;

- if (trace_ent && trace_ent.touch)
- touched_ent = trace_ent;
+ self.pmove_flags |= PMF_STEPPED;
+
+ if (!(self.pmove_flags & PMF_ONGROUND))
+ self.pmove_flags |= PMF_AIRSTEPPED;
}
else
{
- // discard the step attempt
+ // discard the step attempt -- CEV
PM_DanceMove_RejectStep:
+ #ifdef CSQC
+ trace_networkentity = first_net;
+ #endif
touched_ent = trace_ent = first_ent;
trace_plane_normal = first_plane;
- stepsize = 0;
+ stepz = 0;
}
- }
+ } } }

- // do the ground check before we might stop the loop -- CEV
- if (trace_plane_normal_z > 0.7)
+ // 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_GROUND)
{
- if (self.groundentity != touched_ent)
- {
- self.groundentity = touched_ent;
- #ifdef SSQC
- // before clipping velocity - CEV
+ #ifdef CSQC
+ // need to update this right away for client step
+ // smoothing / view interpolation -- CEV
+ if (trace_networkentity)
+ view_step_disable = TRUE;
+ else if (view_step_disable)
+ view_step_disable = FALSE;
+ #endif
+
+ #ifdef SSQC
+ // store impact info (see player_postthink) -- CEV
+ if (self.velocity_z < self.jump_flag)
self.jump_flag = self.velocity_z;
- #endif
- }
- self.groundnormal = trace_plane_normal;
- self.flags |= FL_ONGROUND;
- self.pmove_flags |= PMF_ONGROUND;
- }
- else
- {
- if (self.groundentity != __NULL__)
- {
- self.groundentity = __NULL__;
- self.groundnormal = __NULL__;
- }
- self.flags &= ~FL_ONGROUND;
- self.pmove_flags &= ~PMF_ONGROUND;
+ #endif
}

// from Q3 source: "if this is the same plane we hit
// before, nudge velocity out along it, which fixes
// some epsilon issues with non-axial planes" -- CEV
- if (plane1 && trace_plane_normal * plane1 > 0.99)
- self.velocity += trace_plane_normal;
-
- if (plane2 && trace_plane_normal * plane2 > 0.99)
- self.velocity += trace_plane_normal;
+ for (j = 0; j < PM_MAX_CLIP_PLANES; j++)
+ {
+ // no arrays were harmed in this loop -- CEV
+ if (j == 0) { jp = &self.groundnormal; }
+ else if (j == 1) { jp = &norm_vel; }
+ else if (j == 2) { jp = &plane1; }
+ else if (j == 3) { jp = &plane2; }
+
+ if (*jp)
+ if (trace_plane_normal * *jp > 0.99f)
+ self.velocity += trace_plane_normal;
+ }

// clip velocity to the plane -- CEV
- self.velocity = PM_ClipVelocity (self.velocity,
+ // TODO CEV
+ // if (self.velocity * norm_vel > 0)
+ self.velocity = PM_ClipVelocity (self.velocity,
trace_plane_normal);

- // if velocity interacts with plane1 then clip to it.
- if (plane1 != trace_plane_normal && self.velocity * plane1 < 0)
+ // loop over stored planes clipping velocity as needed;
+ // this block may look familiar, it's similar to the
+ // strategy used in Quake3's SlideMove -- CEV
+ for (j = 0; j < PM_MAX_CLIP_PLANES; j++)
{
- self.velocity = PM_ClipVelocity (self.velocity, plane1);
+ // again, not using arrays here -- CEV
+ if (j == 0) { jp = &self.groundnormal; }
+ else if (j == 1) { jp = &norm_vel; }
+ else if (j == 2) { jp = &plane1; }
+ else if (j == 3) { jp = &plane2; }

- // slide along the crease if necessary -- CEV
- if (self.velocity * trace_plane_normal < 0)
- {
- end = crossproduct (plane1, trace_plane_normal);
- end = normalize (end);
- self.velocity = end * (end * self.velocity);
- }
+ // test if plane interacts & is not current plane
+ if (*jp == trace_plane_normal) { continue; }
+ if (self.velocity * *jp >= 0) { continue; }

- // an optimization from Quake 3 -- CEV
- if (plane2 && plane2 != trace_plane_normal &&
- plane2 != plane1 && self.velocity * plane2 < 0)
- {
- // stop if we interact with three planes -- CEV
- dprint ("PM_DanceMove: position A1\n");
- goto PM_DanceMove_Stop;
- }
- }
+ // clip to the plane -- CEV
+ self.velocity = PM_ClipVelocity (self.velocity, *jp);

- // uplicating the block above but checking plane2 instead
- // of plane1. We're storing two planes so we might as well
- // check both -- CEV
- if (plane2 != trace_plane_normal && self.velocity * plane2 < 0)
- {
- self.velocity = PM_ClipVelocity (self.velocity, plane2);
+ // test if move goes back into the first plane -- CEV
+ if (self.velocity * trace_plane_normal >= 0)
+ continue;

- if (self.velocity * trace_plane_normal < 0)
- {
- end = crossproduct (plane2, trace_plane_normal);
- end = normalize (end);
- self.velocity = end * (end * self.velocity);
- }
+ // slide along crease ("><" is crossproduct) -- CEV
+ end = trace_plane_normal >< *jp;
+ end = normalize (end);
+ self.velocity = end * (end * self.velocity);

- if (plane1 && plane1 != trace_plane_normal &&
- plane2 != plane1 && self.velocity * plane1 < 0)
+ // see if we enter a third plane -- CEV
+ for (k = 0; k < PM_MAX_CLIP_PLANES; k++)
{
- dprint ("PM_DanceMove: position B1\n");
- goto PM_DanceMove_Stop;
+ if (k == 0) { kp = &self.groundnormal; }
+ else if (k == 1) { kp = &norm_vel; }
+ else if (k == 2) { kp = &plane1; }
+ else if (k == 3) { kp = &plane2; }
+
+ if (k == j) { continue; }
+ if (*kp == trace_plane_normal) { continue; }
+ if (self.velocity * *kp >= 0) { continue; }
+
+ // stop when 3 planes interact -- CEV
+ self.velocity = '0 0 0';
+ break;
}
- }

- // an optimization from Quake 1 -- CEV
- if (self.velocity * start_vel <= 0)
- {
- // we've turned against original velocity so zero
- // out vel, touch any ents, and stop the loop
- dprint ("PM_DanceMove: position Z\n");
- PM_DanceMove_Stop:
- self.velocity = '0 0 0';
- PM_DoTouch (touched_ent);
- break;
+ if (self.velocity == '0 0 0') { break; }
}

- // store current plane and plane1 for subsequent loops -- CEV
+ // store current plane and plane1 for the next pass -- CEV
plane2 = plane1;
plane1 = trace_plane_normal;

- // touch the saved entity last in case doing so overwrites
- // trace_plane_normal -- CEV
+ // touch last in case doing so alters trace_plane_normal -- CEV
PM_DoTouch (touched_ent);
- }
-
- // a final call to setorigin to update links -- CEV
- setorigin (self, self.origin);

- // wallclip / wall skim timer check
- // if doskim is true and velocity is non-zero and we lost speed
- // during the move then restore velocity -- CEV
- if ((self.pmove_flags & PMF_SLIDE_SKIM) && self.velocity)
- {
- local float speedloss = vlen([start_vel_x, start_vel_y, 0]) -
- vlen([self.velocity_x, self.velocity_y, 0]);
+ if (self.velocity == '0 0 0') { break; }
+ }

- if (speedloss > 0)
- {
- if (self.pmove_flags & PMF_DOUBLEJUMPED)
- {
- #ifdef SSQC
- dprint (sprintf("PM_DanceMove: "
- "double skim Z vel %g, loss %g\n",
- self.velocity_z, speedloss));
- #endif
+ #if 0
+ if (i > 0)
+ dprint (sprintf("PM_DanceMove: move complete, "
+ "i %g, time_left %g, velocity_z %g\n",
+ i, time_left, self.velocity_z));
+ #endif

- if (speedloss <= PM_RUNSPEED)
- {
- self.velocity = start_vel;
- self.velocity_z = min (start_vel_z,
- self.velocity_z);
- }
- }
- else if (self.pmove_flags & PMF_SLIDE_STICKY)
- {
- self.velocity = [start_vel_x, start_vel_y,
- min (start_vel_z, self.velocity_z)];
- }
- else
- {
+ // if wallclipping / wall skimming was requested and we did not
+ // step during the move and we lost speed then restore velocity -- CEV
+ if (self.pmove_flags & PMF_SLIDE_SKIM)
+ if (maxstep == 0)
+ if (vlen(start_vel) > vlen(self.velocity))
self.velocity = start_vel;
- }
- }
- }

// final gravity check here -- CEV
if (self.pmove_flags & PMF_SLIDE_GRAVITY)
- self.velocity_z -= grav * 0.5;
-
- if (self.pmove_flags & PMF_ONGROUND &&
- self.pmove_flags & PMF_SLIDE_STEP)
- {
- if (stepsize == 0)
- stepsize = self.origin_z - self.oldorigin_z;
-
- // if stepsize is nonzero and we changed from inair to
- // onground then we've airstepped. -- CEV
- if (stepsize > 0)
- {
- if (!(self.pmove_flags & PMF_STARTGROUND))
- {
- // improve stairjumps by mercilessly gluing
- // the player to the floor when their z vel
- // is positive, the jump timer isn't running,
- // the ground is flat horizontal, and we
- // weren't recently pushed -- CEV
- if (self.velocity_z > 0 &&
- self.doublejump_timer == 0 &&
- self.groundnormal_z == 1 &&
- !(self.pmove_flags & PMF_PUSHED) &&
- !(self.pmove_flags & PMF_WATERJUMPED))
- {
- self.velocity_z = 0;
- }
-
- #ifdef SSQC
- // for later (see player_postthink) -- CEV
- self.pmove_flags |= PMF_AIRSTEPPED;
- #endif
- }
- }
- }
+ self.velocity_z -= grav * 0.5f;

+ PM_DanceMove_ClearFlags:
// clear slide hint flags -- CEV
self.pmove_flags = self.pmove_flags - (self.pmove_flags &
(PMF_SLIDE_GRAVITY | PMF_SLIDE_SKIM | PMF_SLIDE_STEP |
PMF_SLIDE_STICKY));

- // clear push brush flag -- CEV
- if (self.groundentity && self.pmove_flags & PMF_PUSHED)
- self.pmove_flags &= ~PMF_PUSHED;
+ // a final call to setorigin to update links -- CEV
+ setorigin (self, self.origin);
};

//----------------------------------------------------------------------
@@ -698,9 +823,8 @@ void() PM_CategorizePosition =
// noclip is never on ground
if (self.groundentity != __NULL__)
self.groundentity = __NULL__;
- self.groundnormal = __NULL__;
- // use a large value for distance when no groundentity -- CEV
- self.grounddistance = 32767;
+ if (self.groundnormal != __NULL__)
+ self.groundnormal = __NULL__;
if (self.pmove_flags & PMF_DOUBLEJUMPED)
self.pmove_flags &= ~PMF_DOUBLEJUMPED;
if (self.pmove_flags & PMF_WALLJUMPED)
@@ -711,211 +835,148 @@ void() PM_CategorizePosition =
self.flags &= ~FL_ONGROUND;
if (self.pmove_flags & PMF_PUSHED)
self.pmove_flags &= ~PMF_PUSHED;
- if (self.pmove_flags & PMF_CLIMB1)
- self.pmove_flags &= ~PMF_CLIMB1;
- if (self.pmove_flags & PMF_CLIMB2)
- self.pmove_flags &= ~PMF_CLIMB2;
+ if (self.pmove_flags & PMF_CLIMB)
+ self.pmove_flags &= ~PMF_CLIMB;
}
else
{
- // do a trace to check for ground
- tracebox (self.origin, self.mins, self.maxs,
- self.origin - '0 0 1024', PM_MOVEFLAGS, self);
-
- self.grounddistance = self.origin_z - trace_endpos_z;
-
- // only onground if we're within one unit & it faces upwards
- if (self.grounddistance <= 1 && trace_plane_normal_z > 0.7f)
- {
- // on ground
- if (!(self.pmove_flags & PMF_ONGROUND) &&
- self.pmove_flags & PMF_CROUCH_HELD &&
- !(self.pmove_flags & PMF_CROUCHSLIDE) &&
- self.velocity * trace_plane_normal < 0 &&
- self.speed > PM_MAXSPEED)
- {
- // start crouchsliding if: we just landed,
- // we're holding crouch, we aren't already
- // sliding, we hit the ground with some force,
- // and we're going faster than run speed -- CEV
- PM_CrouchSlideStart ();
- }
-
- if (self.groundentity != trace_ent)
- {
- #ifdef SSQC
- if (self.groundentity == __NULL__)
- self.jump_flag = self.velocity_z;
- #endif
- self.groundentity = trace_ent;
- }
-
- self.groundnormal = trace_plane_normal;
-
- #ifdef CSQC
- // don't smooth out steps when on a networked ent -- CEV
- if (trace_networkentity)
- view_step_disable = TRUE;
- else if (view_step_disable)
- view_step_disable = FALSE;
- #endif
-
- if (!(self.flags & FL_ONGROUND))
- self.flags |= FL_ONGROUND;
- if (!(self.pmove_flags & PMF_ONGROUND))
- self.pmove_flags |= PMF_ONGROUND;
-
- if (self.pmove_flags & PMF_WALLJUMPED)
- self.pmove_flags &= ~PMF_WALLJUMPED;
-
- if (self.pmove_flags & PMF_PUSHED)
- self.pmove_flags &= ~PMF_PUSHED;
-
- if (self.pmove_flags & PMF_CLIMB1)
- self.pmove_flags &= ~PMF_CLIMB1;
- if (self.pmove_flags & PMF_CLIMB2)
- self.pmove_flags &= ~PMF_CLIMB2;
- }
- else
- {
- // not on ground
- if (self.groundentity != __NULL__)
- self.groundentity = __NULL__;
- if (self.groundnormal)
- self.groundnormal = __NULL__;
- if (self.grounddistance < 32767)
- self.grounddistance = 32767;
- if (self.flags & FL_ONGROUND)
- self.flags &= ~FL_ONGROUND;
- if (self.pmove_flags & PMF_ONGROUND)
- self.pmove_flags &= ~PMF_ONGROUND;
- }
+ // 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 (world, '0 0 0', '0 0 0', 0, PMG_TRACEGROUND);
}

// set waterlevel and watertype -- CEV
base_entity_positioncontents (self);

// don't crouchslide in water -- CEV
- if (self.pmove_flags & PMF_CROUCHSLIDE &&
- self.conlevel > WATERLEVEL_NONE)
- {
- // self.crouchslide_timer = 0;
- self.pmove_flags &= ~PMF_CROUCHSLIDE;
- }
+ if (self.pmove_flags & PMF_CROUCHSLIDE)
+ if (self.conlevel > WATERLEVEL_NONE)
+ self.pmove_flags &= ~PMF_CROUCHSLIDE;

// can't be waterjumping if we're on ground
- if (self.pmove_flags & PMF_WATERJUMPED &&
- (self.conlevel == WATERLEVEL_NONE ||
- self.pmove_flags & PMF_ONGROUND))
+ if (self.conlevel == WATERLEVEL_NONE || self.pmove_flags & PMF_ONGROUND)
{
- #ifdef SSQC
- dprint ("PM_CategorizePosition: clearing FL_WATERJUMP\n");
- #endif
- self.pmove_flags &= ~PMF_WATERJUMPED;
- self.flags &= ~FL_WATERJUMP;
+ if (self.pmove_flags & PMF_WATERJUMPED)
+ {
+ self.pmove_flags &= ~PMF_WATERJUMPED;
+ self.flags &= ~FL_WATERJUMP;
+ }
}
};

//----------------------------------------------------------------------
-// PM_Friction
-// Ground friction
+// PM_Friction -- standard ground friction -- CEV
//----------------------------------------------------------------------
void(float friction, float move_time) PM_Friction =
{
- float control, newspeed, speed;
+ local float control, newspeed, speed1;

- speed = vlen (self.velocity);
+ speed1 = vlen (self.velocity);

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

- // calculate what their new speed should be
- control = speed < PM_STOPSPEED ? PM_STOPSPEED : speed;
- newspeed = speed - control * friction * move_time;
-
- // and slow them
- if (newspeed < 0)
- newspeed = 0;
-
- self.velocity = self.velocity * (newspeed / speed);
+ // and slow them
+ if (newspeed <= 0)
+ self.velocity = '0 0 0';
+ else
+ self.velocity *= newspeed / speed1;
+ }
};

//----------------------------------------------------------------------
-// PM_Accelerate
-// Ground acceleration & Quake 3 style air acceleration -- CEV
+// PM_Accelerate -- ground acceleration & strafejumping -- CEV
//----------------------------------------------------------------------
-void(vector wishdir, float wishspeed, float accel, float move_time)
- PM_Accelerate =
+void(vector dir, float wishspeed, float accel, float move_time) PM_Accelerate =
{
- float newspeed, speed;
+ local float speed1 = wishspeed - (self.velocity * dir);

- speed = wishspeed - (self.velocity * wishdir);
-
- if (speed <= 0)
- return;
+ if (speed1 > 0)
+ {
+ local float newspeed = accel * move_time * wishspeed;

- newspeed = accel * move_time * wishspeed;
- if (newspeed > speed)
- newspeed = speed;
+ if (newspeed > speed1)
+ newspeed = speed1;

- self.velocity += newspeed * wishdir;
+ self.velocity += newspeed * dir;
+ }
};

//----------------------------------------------------------------------
-// PM_AirAccelerate
-// Quake 1 style air acceleration -- CEV
+// PM_AirAccelerate -- Quake 1 style air acceleration -- CEV
//----------------------------------------------------------------------
-void(vector wishvel, float wishspeed, float accel, float move_time)
+void(vector vel, vector dir, float wishspeed, float move_time)
PM_AirAccelerate =
{
- float newspeed, speed, wishspd;
+ local float newspeed, speed1, zspeed;

- // need to ignore Z velocity -- CEV
- wishvel = [wishvel_x, wishvel_y, 0];
- wishspd = vlen (wishvel);
- wishvel = normalize (wishvel);
- if (wishspd > PM_MAXAIRSPEED)
- wishspd = PM_MAXAIRSPEED;
- speed = self.velocity * wishvel;
- speed = wishspd - speed;
+ zspeed = self.velocity_z;
+ self.velocity_z = vel_z = dir_z = 0;
+ newspeed = min (vlen (vel), PM_MAXAIRSPEED);
+ speed1 = self.velocity * dir;
+ speed1 = newspeed - speed1;

- if (speed <= 0)
- return;
+ 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);

- newspeed = accel * move_time * wishspeed;
- if (newspeed > speed)
- newspeed = speed;
- self.velocity += newspeed * wishvel;
+ 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 / Painkiller-like Air Control. Based on Xonotic sources. -- CEV
+// PM_AirControl -- CPM / Nexuiz / PK / Warsow / Xonotic air control -- CEV
//----------------------------------------------------------------------
-void(vector wishdir, float wishspeed, float move_time) PM_AirControl =
+void(vector dir, float wishspeed, float move_time) PM_AirControl =
{
- local float dot, speed, turn, zspeed;
+ local float dot, speed1, turn, zspeed;

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

- speed = vlen (self.velocity);
+ speed1 = vlen (self.velocity);
self.velocity = normalize (self.velocity);

- dot = self.velocity * wishdir;
+ 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 = normalize (self.velocity * speed +
- wishdir * turn);
+ self.velocity = self.velocity * speed1 + dir * turn;
+ self.velocity = normalize (self.velocity);
}

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

@@ -939,10 +1000,6 @@ void() PM_CrouchStart =
}
*/
#endif
-
- #if 0
- self.SendFlags |= PLAYER_NET_SIZE | PLAYER_NET_FLAGS;
- #endif
};

//----------------------------------------------------------------------
@@ -968,17 +1025,13 @@ void() PM_CrouchStop =
}
*/
#endif
-
- #if 0
- self.SendFlags |= PLAYER_NET_SIZE | PLAYER_NET_FLAGS;
- #endif
}
};

//----------------------------------------------------------------------
// PM_CrouchSlideStart
-// Crouchslide behaviour is based on Rapha's Quake Champions movement
-// tutorial found here: https://www.youtube.com/watch?v=95spyl1LRTc&t=1623s
+// 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
//----------------------------------------------------------------------
@@ -1016,11 +1069,12 @@ void() PM_CrouchSlideStop =
//----------------------------------------------------------------------
// PM_Jump
//----------------------------------------------------------------------
-void(vector wishdir) PM_Jump =
+void() PM_Jump =
{
// are we already waterjumping, or is jump being held?
- if (self.pmove_flags & PMF_WATERJUMPED ||
- self.pmove_flags & PMF_JUMP_HELD)
+ if (self.pmove_flags & PMF_WATERJUMPED)
+ return;
+ if (self.pmove_flags & PMF_JUMP_HELD)
return;

#ifdef SSQC
@@ -1028,15 +1082,13 @@ void(vector wishdir) PM_Jump =
local float vol = 0;
#endif

- // make sure we get at least jumpspeed upwards from
- // the ground plane by clamping it first.
- if (self.groundnormal && (self.velocity * self.groundnormal < 0))
- {
- self.velocity -= self.groundnormal *
- (self.velocity * self.groundnormal);
- }
+ // make sure we get at least jumpspeed upwards from the ground
+ // plane by clamping it first. necessary for rampjumps. -- CEV
+ if (self.groundnormal)
+ if (self.velocity * self.groundnormal < 0)
+ self.velocity -= self.groundnormal *
+ (self.velocity * self.groundnormal);

- // make sure we get at least the indicated jump speed
// this changes the behavior of downward ramps -- CEV
if (self.velocity_z < 0)
self.velocity_z = 0;
@@ -1050,7 +1102,8 @@ void(vector wishdir) PM_Jump =
// account for time to travel thru teleporter -- CEV
// non-additive jump, though it shouldn't matter -- CEV
self.velocity_z = PM_TELEJUMPSPEED;
- else if (self.groundnormal && self.groundnormal_z == 1)
+ else if (self.groundnormal &&
+ self.groundnormal_z >= PM_PLANE_FLAT)
// don't do additive stairjumps on flat ground -- CEV
self.velocity_z = PM_STAIRJUMPSPEED;
else
@@ -1066,19 +1119,6 @@ void(vector wishdir) PM_Jump =
// set the doublejump flag -- CEV
self.pmove_flags |= PMF_DOUBLEJUMPED;
}
- else if (input_movevalues_y && input_movevalues_x == 0 &&
- self.speed <= PM_SHORTJUMPTHRESH)
- {
- // short fast sideways jump - a dodge -- CEV
- #ifdef SSQC
- local float r1 = rint (random() * 3);
- vol = 0.2;
- wav = sprintf ("player/jump0%g.ogg", r1 + 1);
- #endif
-
- self.velocity = wishdir * 400;
- self.velocity_z = PM_SHORTJUMPSPEED;
- }
else
{
// normal jump
@@ -1089,19 +1129,14 @@ void(vector wishdir) PM_Jump =
#endif

// do an additive jump on non-flat ground -- CEV
- if (self.groundnormal && self.groundnormal_z == 1)
+ if (self.groundnormal_z >= PM_PLANE_FLAT)
self.velocity_z = PM_JUMPSPEED;
- else if (self.groundentity.velocity)
- self.velocity_z += PM_JUMPSPEED;
else
self.velocity_z += PM_JUMPSPEED;
}

// manage flags -- CEV
- self.groundentity = __NULL__;
- self.groundnormal = __NULL__;
- self.pmove_flags &= ~PMF_ONGROUND;
- self.flags &= ~FL_ONGROUND;
+ PM_SetOnGround (world, '0 0 0', '0 0 0', 0, PMG_NOGROUND);
self.pmove_flags |= PMF_JUMP_HELD;

if (self.pmove_flags & PMF_CROUCHSLIDE)
@@ -1123,27 +1158,26 @@ void(vector wishdir) PM_Jump =
//----------------------------------------------------------------------
void() PM_WallJump =
{
- // are we in water, already waterjumping, already walljumping,
- // or is jump being held?
- if (self.conlevel > WATERLEVEL_NONE ||
- self.pmove_flags & PMF_WATERJUMPED ||
- self.pmove_flags & PMF_WALLJUMPED)
- {
+ // are we in water, waterjumping, walljumping,
+ // or falling too fast? -- CEV
+ if (self.conlevel > WATERLEVEL_NONE)
+ return;
+ if (self.pmove_flags & PMF_WATERJUMPED)
+ return;
+ if (self.pmove_flags & PMF_WALLJUMPED)
return;
- }
-
if (self.velocity_z < PM_WALLJUMPLIMIT)
- // falling too fast to walljump -- CEV
return;

- // ground distance is set in PM_CategorizePosition -- CEV
- if (self.grounddistance <= 32)
- // within 32 units of the floor, abort -- CEV
+ // are we within 32 units of the floor? -- CEV
+ tracebox (self.origin, self.mins, self.maxs, self.origin - '0 0 64',
+ PM_MOVEFLAGS, self);
+ local float grounddist = self.origin_z - trace_endpos_z;
+ if (grounddist <= PM_WALLJUMPGROUND)
return;

local float i;
local float dot = 0;
- local float dist = 0;
local vector start, end;
start = end = self.origin;

@@ -1182,24 +1216,24 @@ void() PM_WallJump =
vlen(self.origin - trace_endpos)));
#endif

- // in order: we hit something, that something is vaguely
- // vertical, and that something is within 20 (units?) -- CEV
- if (trace_fraction < 1.0f &&
- trace_plane_normal_z <= 0.7f &&
- trace_plane_normal_z >= 0)
- // vlen(self.origin - trace_endpos) <= 20)
+ // 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)
{
dot = self.velocity * trace_plane_normal;
- if (dot >= 0 && (!(self.pmove_flags & PMF_JUMP_HELD)))
+ if (!(self.pmove_flags & PMF_JUMP_HELD) && dot >= 0)
{
- // moving away from the wall -- CEV
+ // moving away from the wall, not holding
+ // jump, and haven't walljumped -- CEV
self.pmove_flags |= PMF_WALLJUMPED;
break;
}
- else if (i == 0 && self.pmove_flags & PMF_JUMP_HELD &&
- self.speed <= PM_MAXSPEED &&
- fabs(self.velocity_z) < 90.0f &&
- self.grounddistance > 42)
+ else if (i == 0) {
+ if (self.pmove_flags & PMF_JUMP_HELD) {
+ if (self.speed <= PM_MAXSPEED) {
+ if (fabs(self.velocity_z) < 90.0f) {
+ if (grounddist > 42)
{
// holding jump and moving *into* the wall
// at a rate below MAXSPEED with a low Z
@@ -1231,13 +1265,13 @@ void() PM_WallJump =
MOVE_NOMONSTERS | PM_MOVEFLAGS,
self);

- if (trace_plane_normal_z > 0.7f)
+ if (trace_plane_normal_z >
+ PM_PLANE_GROUND)
{
- dist = trace_endpos_z -
+ grounddist = trace_endpos_z -
(self.origin_z +
self.mins_z);
- self.pmove_flags |= PMF_CLIMB1;
- self.pmove_flags &= ~PMF_CLIMB2;
+ self.pmove_flags |= PMF_CLIMB;
break;
}
}
@@ -1254,50 +1288,40 @@ void() PM_WallJump =
MOVE_NOMONSTERS | PM_MOVEFLAGS,
self);

- if (trace_plane_normal_z > 0.7f)
+ if (trace_plane_normal_z >
+ PM_PLANE_GROUND)
{
- dist = trace_endpos_z -
+ grounddist = trace_endpos_z -
(self.origin_z +
self.mins_z);
- self.pmove_flags &= ~PMF_CLIMB1;
- self.pmove_flags |= PMF_CLIMB2;
+ self.pmove_flags |= PMF_CLIMB;
break;
}
}

start = self.origin;
- }
- }
+ } } } } }
+ } } }

// player can't hold on to thin air -- CEV
- if (self.pmove_flags & PMF_CLIMB1)
- self.pmove_flags &= ~PMF_CLIMB1;
- if (self.pmove_flags & PMF_CLIMB2)
- self.pmove_flags &= ~PMF_CLIMB2;
+ if (self.pmove_flags & PMF_CLIMB)
+ self.pmove_flags &= ~PMF_CLIMB;
}

- if (self.pmove_flags & PMF_CLIMB1)
+ if (self.pmove_flags & PMF_CLIMB)
{
- // climb up to a near edge
+ // accelerate upwards toward a vertical ledge -- CEV
local float zspeed = self.velocity_z;
+ if (grounddist == 0)
+ grounddist = 1;
self.velocity *= PM_CLIMBSCALE;
- self.velocity_z = bound (PM_CLIMBSPEED,
- zspeed + PM_CLIMBSPEED, PM_CLIMBSPEED * 2);
- #ifdef SSQC
- dprint (sprintf("PM_WallJump: climb offset 1, i %g, vel_z %g, "
- "dist %g\n", i, self.velocity_z, dist));
- #endif
- }
- else if (self.pmove_flags & PMF_CLIMB2)
- {
- // climb to an edge farther away
- local float zspeed2 = self.velocity_z;
- self.velocity *= PM_CLIMBSCALE;
- self.velocity_z = bound (PM_CLIMBSPEED * 0.5,
- zspeed2 + PM_CLIMBSPEED, PM_CLIMBSPEED);
- #ifdef SSQC
- dprint (sprintf("PM_WallJump: climb offset 2, i %g, vel_z %g, "
- "dist %g\n", i, self.velocity_z, dist));
+ self.velocity_z = bound (PM_CLIMBSPEED * 0.5f,
+ zspeed + (64.0f / grounddist) * PM_CLIMBSPEED,
+ PM_CLIMBSPEED * 2.0f);
+
+ #if 0
+ dprint (sprintf("PM_WallJump: climb, vel_z %g, "
+ "grounddist %g\n", self.velocity_z, grounddist));
#endif
}
else if (self.pmove_flags & PMF_WALLJUMPED)
@@ -1307,14 +1331,20 @@ void() PM_WallJump =
local string wav = "";
#endif

- // walljump; bounce off the wall plane -- CEV
- self.velocity_z = 0;
- self.velocity += trace_plane_normal * PM_WALLJUMPFORCE;
+ // bounce off the wall plane if Z velocity is positive -- CEV
+ // if we bounce off the wall plane when Z vel is negative it
+ // introduces a scenario where a player can fall off a ledge
+ // and then (for just a frame or two) jump off the wall
+ // behind them to gain additional XY speed. You can still
+ // 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)
+ self.velocity += trace_plane_normal * PM_WALLJUMPFORCE;

if (self.doublejump_timer > 0)
{
#ifdef SSQC
- // dprint ("PM_WallJump: wall double ");
vol = 0.9;
wav = "player/plyrjmp8.wav";
#endif
@@ -1323,7 +1353,6 @@ void() PM_WallJump =
else
{
#ifdef SSQC
- // dprint ("PM_WallJump: walljump ");
local float r = rint (random() * 3);
vol = 0.2;
wav = sprintf ("player/jump0%g.ogg", r + 1);
@@ -1337,7 +1366,6 @@ void() PM_WallJump =

// server-side stuff
#ifdef SSQC
- // dprint (sprintf("i %g, normalspeed %g\n", i, dot));
player_footstep ();
if (wav != "")
sound (self, CHAN_BODY, wav, vol, ATTN_NORM);
@@ -1346,18 +1374,28 @@ void() PM_WallJump =
};

//----------------------------------------------------------------------
-// PM_WalkAccelerate
-// Handle accel & friction for MOVETYPE_WALK entities (players). -- CEV
+// PM_GroundBoostWishSpeed
+// scale wishspeed up based on the time remaining to doublejump -- CEV
//----------------------------------------------------------------------
-void(vector wishvel, float move_time) PM_WalkAccelerate =
+float(float wishspeed) PM_GroundBoostWishSpeed =
{
- local float accel, friction, newspeed, speed1, temp, wishspeed;
- local vector wishdir;
+ // broke this up into multiple lines to improve readability -- CEV
+ local float wishnew;

- accel = friction = temp = 0;
+ wishnew = ((self.doublejump_timer - PM_DOUBLEJUMP_WINDOW) * -1) *
+ PM_MAXWISHMULT;
+ wishnew = bound (PM_MAXSPEED, PM_MAXSPEED + wishnew, PM_MAXWISHSPEED);

- wishspeed = vlen (wishvel);
- wishdir = normalize (wishvel);
+ return min (wishspeed, wishnew);
+};
+
+//----------------------------------------------------------------------
+// PM_WalkAccelerate -- accel & friction for MOVETYPE_WALK -- CEV
+//----------------------------------------------------------------------
+void(float mt) PM_WalkAccelerate =
+{
+ // only yaw matters here -- CEV
+ makevectors (input_angles_y * '0 1 0');

if (self.pmove_flags & PMF_PRE_MOVE)
{
@@ -1395,7 +1433,7 @@ void(vector wishvel, float move_time) PM_WalkAccelerate =
// +jump was pressed
if (self.pmove_flags & PMF_ONGROUND)
// normal jump
- PM_Jump (wishdir);
+ PM_Jump ();
else if (world_walljump)
// walljump
PM_WallJump ();
@@ -1424,308 +1462,119 @@ void(vector wishvel, float move_time) PM_WalkAccelerate =
self.pmove_flags &= ~PMF_STARTGROUND;
}

+ local vector vel;
+ vel = v_forward * input_movevalues_x + v_right * input_movevalues_y;
+ vel_z = 0;
+ local float wish = vlen (vel);
+ local vector dir = normalize (vel);
+
// 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)
{
- // we're on ground so pick accel and friction values -- CEV
if (self.pmove_flags & PMF_CROUCHSLIDE && self.conlevel == 0)
{
- wishspeed = min (wishspeed, PM_MAXSPEED);
+ wish = min (wish, PM_MAXSPEED);
+ PM_Friction (PM_SLIDEFRICTION, mt);

+ if (vel != '0 0 0') {
if (input_movevalues_x == 0)
{
- accel = -1;
- friction = PM_SLIDEFRICTION;
+ PM_AirAccelerate (vel, dir, wish, mt);
}
else
{
+ local float a1 = 0;
+
if (input_movevalues_y == 0)
{
- if (wishvel * self.velocity < 0)
- accel = PM_AIRACCELBACK;
+ if (vel * self.velocity < 0)
+ a1 = PM_AIRACCELBACK;
else
- accel = PM_AIRACCELFWD;
- friction = -1;
+ a1 = PM_AIRACCELFWD;
+ PM_Accelerate (dir, wish, a1, mt);
+ PM_AirControl (dir, wish, mt);
}
else
{
- accel = PM_SLIDEACCEL;
- friction = PM_SLIDEFRICTION;
+ a1 = PM_SLIDEACCEL;
+ PM_Accelerate (dir, wish, a1, mt);
}
- }
+ } }
}
else
{
- accel = PM_GROUNDACCEL;
- friction = PM_GROUNDFRICTION;
-
- if (self.pmove_flags & PMF_CROUCHED)
- wishspeed = min (wishspeed, PM_CROUCHSPEED);
- else if (self.doublejump_timer > 0)
- // scale wishspeed up linearly based on the
- // remaining time to doublejump -- CEV
- wishspeed = min (wishspeed,
- bound (PM_MAXSPEED, PM_MAXSPEED +
- ((self.doublejump_timer -
- PM_DOUBLEJUMP_WINDOW) * -1)
- * 150, PM_BOOSTWISHSPEED));
- else
- wishspeed = min (wishspeed, PM_MAXSPEED);
- }
- }
- else if (self.pmove_flags & PMF_ONGROUND)
- {
- if (self.pmove_flags & PMF_CROUCH_HELD &&
- self.conlevel == 0 &&
- self.velocity * self.groundnormal < 0 &&
- self.speed > PM_MAXSPEED)
- {
- // We've just landed, the player is holding crouch,
- // we hit the ground with some force, and we're
- // moving faster than default run speed so start
- // crouchsliding -- CEV
- PM_CrouchSlideStart ();
- wishspeed = min (wishspeed, PM_MAXSPEED);
+ PM_Friction (PM_GROUNDFRICTION, mt);

- if (input_movevalues_x == 0)
- {
- accel = -1;
- friction = PM_SLIDEFRICTION;
- }
- else
+ if (vel != '0 0 0')
{
- if (input_movevalues_y == 0)
- {
- if (wishvel * self.velocity < 0)
- accel = PM_AIRACCELBACK;
- else
- accel = PM_AIRACCELFWD;
-
- friction = -1;
- }
+ if (self.pmove_flags & PMF_CROUCHED)
+ wish = min (wish, PM_CROUCHSPEED);
+ else if (self.doublejump_timer > 0)
+ wish = PM_GroundBoostWishSpeed (wish);
else
- {
- accel = PM_SLIDEACCEL;
- friction = PM_SLIDEFRICTION;
- }
- }
- }
- else
- {
- // we're in the second acceleration pass and we've just
- // landed. For this one-half acceleration frame set
- // friction to zero and accel to AIRACCELQ3. This
- // moment is particularly noticeable on stairs. -- CEV
- accel = PM_AIRACCELQ3;
- friction = 0;
-
- // rewrite user input to direct movement along current
- // velocity in the half-frame after we've just landed.
- // will only rewrite when neither +fwd or +back is
- // pressed. the neverending quest to improve stairs.
- // -- CEV
- if (input_movevalues_y && input_movevalues_x == 0)
- {
- input_movevalues_x = fabs (input_movevalues_y);
-
- // we've altered input movevalues so rework
- // wishvel; start by ensuring v_ globals are
- // correct
- makevectors ([0, input_angles_y, 0]);
- wishvel = v_forward * input_movevalues_x;
- wishvel += v_right * input_movevalues_y;
- // is wishvel now against self.velocity?
- if (wishvel * self.velocity < 0)
- {
- // then movevalues_x should be negative
- input_movevalues_x = -input_movevalues_x;
- wishvel = v_forward * input_movevalues_x;
- wishvel += v_right * input_movevalues_y;
- }
- wishspeed = vlen (wishvel);
- wishdir = normalize (wishvel);
- }
+ wish = min (wish, PM_MAXSPEED);

- if (self.doublejump_timer > 0)
- // scale wishspeed up linearly based on the
- // remaining time to doublejump -- CEV
- wishspeed = min (wishspeed,
- bound (PM_MAXSPEED, PM_MAXSPEED +
- ((self.doublejump_timer -
- PM_DOUBLEJUMP_WINDOW) * -1)
- * 150, PM_BOOSTWISHSPEED));
- else
- wishspeed = min (wishspeed, PM_MAXSPEED);
- }
- }
- else if (input_movevalues_x == 0)
- {
- // Q1 air accel when requesting sideways movement in the air
- // flag a check below with this -1 -- CEV
- wishspeed = min (wishspeed, PM_MAXSPEED);
- accel = -1;
- }
- else
- {
- wishspeed = min (wishspeed, PM_MAXSPEED);
-
- if (input_movevalues_y == 0)
- {
- // Painkiller style air control
- if (wishvel * self.velocity < 0)
- // against original velocity; we're slowing down
- accel = PM_AIRACCELBACK;
- else
- // we're with original velocity - gaining speed
- accel = PM_AIRACCELFWD;
-
- // borrow the friction var to flag a conditional below
- friction = -1;
- }
- else
- {
- // we're in the air and the player is requesting both
- // forward/back and sideways movement, so pick the Q3
- // air accel value -- CEV
- accel = PM_AIRACCELQ3;
+ PM_Accelerate (dir, wish, PM_GROUNDACCEL, mt);
+ }
}
}
-
- // I've duplicated a fair amount of code below, inlining the various
- // acceleration functions to hopefully improve performance -- CEV
-
- // apply friction (ground or otherwise)
- if (friction > 0)
+ else if (vel != '0 0 0')
{
- // inline PM_Friction
- speed1 = vlen (self.velocity);
+ wish = min (wish, PM_MAXSPEED);

- if (speed1 < 1)
+ if (input_movevalues_x == 0)
{
- self.velocity = '0 0 0';
+ // sideways movement in the air, so Q1 air accel -- CEV
+ PM_AirAccelerate (vel, dir, wish, mt);
}
- else
+ else if (input_movevalues_y == 0)
{
- // calculate what their new speed should be
- temp = speed1 < PM_STOPSPEED ? PM_STOPSPEED : speed1;
- newspeed = speed1 - temp * friction * move_time;
+ local float a3 = 0;

- // and slow them
- if (newspeed <= 0)
- {
- newspeed = 0;
- self.velocity = '0 0 0';
- }
+ // CPM / Painkiller style air control -- CEV
+ if (vel * self.velocity < 0)
+ // against original velocity; we're slowing down
+ a3 = PM_AIRACCELBACK;
else
- {
- self.velocity *= newspeed / speed1;
- }
- }
- }
-
- if (accel == -1)
- {
- // Quake 1 sideways air acceleration; inline PM_AirAccelerate
- temp = self.velocity_z;
- self.velocity_z = wishvel_z = wishdir_z = 0;
- newspeed = vlen (wishvel);
- // we've already normalized wishvel as wishdir above, no
- // need to do it again -- CEV
- // wishvel = normalize (wishvel);
- if (newspeed > PM_MAXAIRSPEED)
- newspeed = PM_MAXAIRSPEED;
- speed1 = self.velocity * wishdir;
- speed1 = newspeed - speed1;
-
- if (speed1 > 0)
- {
- newspeed = PM_AIRACCEL * move_time * wishspeed;
-
- if (newspeed > speed1)
- newspeed = speed1;
-
- // below is an attempt to separate turning radius
- // from acceleration. -- CEV
-
- // re-using a lot of variables here
- wishdir = self.velocity + newspeed * wishdir;
- newspeed = vlen (wishdir);
- speed1 = vlen (self.velocity);
+ // we're with original velocity - gaining speed
+ a3 = PM_AIRACCELFWD;

- 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 (wishdir);
- self.velocity *= newspeed;
- }
- else
- {
- self.velocity = wishdir;
- }
+ PM_Accelerate (dir, wish, a3, mt);
+ PM_AirControl (dir, wish, mt);
}
-
- self.velocity_z = temp;
- }
- else if (accel > 0)
- {
- // ground & Quake 3 style acceleration; inline PM_Accelerate
- speed1 = wishspeed - (self.velocity * wishdir);
-
- if (speed1 > 0)
+ else
{
- newspeed = accel * move_time * wishspeed;
- if (newspeed > speed1)
- newspeed = speed1;
-
- self.velocity += newspeed * wishdir;
+ // X and Y movement in the air: strafejumping -- CEV
+ PM_Accelerate (dir, wish, PM_AIRACCELQ3, mt);
}
}

- // CPM & PK-style air control, needs to happen after PM_Accelerate
- // based on code from Nexuiz & Xonotic
- if (friction == -1)
- {
- // inline PM_AirControl
- temp = self.velocity_z;
- self.velocity_z = 0;
-
- speed1 = vlen (self.velocity);
- self.velocity = normalize (self.velocity);
-
- // reuse the friction float for dotproduct -- CEV
- friction = self.velocity * wishdir;
-
- // reuse the accel var for turning -- CEV
- accel = PM_AIRACCELBASE * bound (0, wishspeed / PM_MAXSPEED, 1);
- accel *= PM_AIRACCELTURN * friction * friction * move_time;
-
- if (friction > 0)
- {
- self.velocity = normalize (self.velocity * speed1 +
- wishdir * accel);
- }
-
- self.velocity *= speed1;
- self.velocity_z = temp;
- }
+ #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]),
+ vel, wish));
+ #endif

if (!(self.pmove_flags & PMF_PRE_MOVE))
- self.pmove_flags &= ~PMF_STARTGROUND;
+ if (self.pmove_flags & PMF_STARTGROUND)
+ self.pmove_flags &= ~PMF_STARTGROUND;
};

//----------------------------------------------------------------------
// PM_SwimAccelerate
// Largely copied from id Software's WaterMove. Works like NoClipAccelerate.
//----------------------------------------------------------------------
-void(vector wishvel, float move_time) PM_SwimAccelerate =
+void(float move_time) PM_SwimAccelerate =
{
local float wishspeed;
+ local vector wishvel;
+
+ makevectors (input_angles);
+ wishvel = v_forward * input_movevalues_x +
+ v_right * input_movevalues_y + v_up * input_movevalues_z;

if (self.pmove_flags & PMF_PRE_MOVE)
{
@@ -1758,53 +1607,46 @@ void(vector wishvel, float move_time) PM_SwimAccelerate =
self.pmove_flags &= ~PMF_JUMP_HELD;
// Z velocity was 225
self.velocity_z = PM_JUMPSPEED;
- // we don't care about the 'safety net'
- // in this movement set (unlike vanilla)
- // so don't set teleport_time -- CEV
- // self.teleport_time = time + 2;
}
}
}

#ifdef SSQC
// functionality copied into pmove from client.qc -- CEV
- if (self.conlevel >= WATERLEVEL_WAIST)
+ if (self.conlevel >= WATERLEVEL_WAIST) {
+ if (self.conlevel >= WATERLEVEL_EYES) {
+ if (self.swim_time < time)
{
- if (self.conlevel >= WATERLEVEL_EYES &&
- self.swim_time < time)
- {
- // play swimming sound
- self.swim_time = time + 1;
- if (random() < 0.5)
- sound (self, CHAN_BODY,
- "misc/water1.wav",
- 0.6, ATTN_NORM);
- else
- sound (self, CHAN_BODY,
- "misc/water2.wav",
- 0.6, ATTN_NORM);
- }
- }
+ // play swimming sound
+ self.swim_time = time + 1;
+ if (random() < 0.5)
+ sound (self, CHAN_BODY, "misc/water1.wav",
+ 0.6, ATTN_NORM);
+ else
+ sound (self, CHAN_BODY, "misc/water2.wav",
+ 0.6, ATTN_NORM);
+ } } }
#endif
}

- if (input_buttons & INPUT_BUTTON2 &&
- !(self.pmove_flags & PMF_WATERJUMPED))
- {
- // smartjump
- wishvel_z = max (PM_MAXSPEED, wishvel_z);
- }
- else if (input_buttons & INPUT_BUTTON8 &&
- !(self.pmove_flags & PMF_WATERJUMPED))
- {
- // smartcrouch
- // self.pmove_flags |= PMF_CROUCH_HELD;
- wishvel_z = min (-PM_MAXSPEED, wishvel_z);
- }
- else if (input_movevalues == '0 0 0')
+ if (!(self.pmove_flags & PMF_WATERJUMPED))
{
- // drift towards bottom -- CEV
- wishvel_z -= PM_WATERSINKSPEED;
+ if (input_buttons & INPUT_BUTTON2)
+ {
+ // smartjump
+ wishvel_z = max (PM_MAXSPEED, wishvel_z);
+ }
+ else if (input_buttons & INPUT_BUTTON8)
+ {
+ // smartcrouch
+ // self.pmove_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);
@@ -1821,14 +1663,17 @@ void(vector wishvel, float move_time) PM_SwimAccelerate =
};

//----------------------------------------------------------------------
-// PM_NoClipAccelerate
-//
-// Basic acceleration for flying / noclipping players. Not suitable for
-// swimming. -- CEV
+// PM_NoClipAccelerate -- for flying / noclip; not for swimming -- CEV
//----------------------------------------------------------------------
-void(vector wishvel, float scale, float move_time) PM_NoClipAccelerate =
+void(float scale, float move_time) PM_NoClipAccelerate =
{
local float wishspeed;
+ local vector wishvel;
+
+ makevectors (input_angles);
+ wishvel = v_forward * input_movevalues_x;
+ wishvel += v_right * input_movevalues_y;
+ wishvel += v_up * input_movevalues_z;

if (input_buttons & INPUT_BUTTON2)
// smartjump
@@ -1852,16 +1697,25 @@ void(float move_time) PM_ManageTimers =
else if (self.doublejump_timer < 0)
self.doublejump_timer = 0;

- if (self.doublejump_timer == 0 && self.pmove_flags & PMF_DOUBLEJUMPED)
- self.pmove_flags &= ~PMF_DOUBLEJUMPED;
+ if (self.doublejump_timer <= 0)
+ {
+ if (self.pmove_flags & PMF_DOUBLEJUMPED)
+ self.pmove_flags &= ~PMF_DOUBLEJUMPED;
+ // TODO CEV find a better place to clear STEPPED and AIRSTEPPED
+ if (self.pmove_flags & PMF_STEPPED)
+ self.pmove_flags &= ~PMF_STEPPED;
+ if (self.pmove_flags & PMF_AIRSTEPPED)
+ self.pmove_flags &= ~PMF_AIRSTEPPED;
+ }

if (self.crouchslide_timer > 0 && move_time > 0)
self.crouchslide_timer -= move_time;
else if (self.crouchslide_timer < 0)
self.crouchslide_timer = 0;

- if (self.crouchslide_timer == 0 && self.pmove_flags & PMF_CROUCHSLIDE)
- PM_CrouchSlideStop ();
+ if (self.crouchslide_timer == 0)
+ if (self.pmove_flags & PMF_CROUCHSLIDE)
+ PM_CrouchSlideStop ();
};

//----------------------------------------------------------------------
@@ -1879,55 +1733,14 @@ void(entity e) PM_Move =
view_pl = self;
#endif

- local vector wishvel;
-
// Nudge player's origin if the server is sending low-precision
// (16 bit?) player coordinates. This can be fixed by setting
// sv_bigcoords to 1 (so the server sends float coords). -- CEV
- if (!world_bigcoords)
+ if (world_bigcoords == FALSE)
PM_Nudge ();

- // rework user input, copying something like QuakeSpasm's always run
- // feature here. This turns the +speed button into a hold-to-walk
- // button when cl_run is 0 (when FTE's always run setting is on).
- // -- CEV
- if (world_clrun == FALSE)
- {
- local float m;
-
- // we care about x and y, not so much z -- CEV
- if (input_movevalues_x)
- {
- m = fabs (input_movevalues_x);
- if (m > 400.0f)
- input_movevalues_x = PM_WALKSPEED *
- (input_movevalues_x / m);
- else if (m == 400.0f)
- input_movevalues_x = world_clforwardspeed *
- (input_movevalues_x / m);
- /*
- else if (m != 0)
- input_movevalues_x = PM_RUNSPEED *
- (input_movevalues_x / m);
- */
- }
-
- if (input_movevalues_y)
- {
- m = fabs (input_movevalues_y);
- if (m > 400.0f)
- input_movevalues_y = PM_WALKSPEED *
- (input_movevalues_y / m);
- else if (m == 400.0f)
- input_movevalues_y = world_clsidespeed *
- (input_movevalues_y / m);
- /*
- else if (m != 0)
- input_movevalues_y = PM_RUNSPEED *
- (input_movevalues_y / m);
- */
- }
- }
+ if (self.velocity != '0 0 0')
+ self.velocity = PM_TruncateVector (self.velocity);

// clear JUMP_HELD if it's set and the user isn't pressing BUTTON2
if (!(input_buttons & INPUT_BUTTON2))
@@ -1945,160 +1758,140 @@ void(entity e) PM_Move =
PM_CrouchSlideStop ();
}

- // figure out the properties of the player's position, then clear timers
+ // figure out the properties of the player's position then clear timers
PM_CategorizePosition ();
- PM_ManageTimers (0);
+ // PM_ManageTimers (0);

+ local float half_time = input_timelength * 0.5;
self.speed = vlen ([self.velocity_x, self.velocity_y, 0]);

- switch (self.movetype)
+ if (self.movetype == MOVETYPE_WALK)
{
- case MOVETYPE_WALK:
- // signal acceleration functions that we're pre-move
- self.pmove_flags |= PMF_PRE_MOVE;
+ // signal acceleration functions that we're pre-move
+ self.pmove_flags |= PMF_PRE_MOVE;
+
+ // split acceleration in two to improve responsiveness -- CEV
+ if (self.conlevel >= WATERLEVEL_WAIST)
+ {
+ // swim acceleration
+ PM_SwimAccelerate (half_time);
+ }
+ else
+ {
+ PM_WalkAccelerate (half_time);
+
+ // WalkAccelerate calls Jump which might alter pmove
+ // flags so do our feature checks afterwards -- CEV
+
+ // stick to the ground if we've jumped and haven't
+ // yet doublejumped
+ if (self.doublejump_timer > 0) {
+ if (!(self.pmove_flags & PMF_CLIMB)) {
+ if (!(self.pmove_flags & PMF_CROUCHSLIDE)) {
+ if (!(self.pmove_flags & PMF_PUSHED)) {
+ if (!(self.pmove_flags & PMF_WALLJUMPED)) {
+ if (!(self.pmove_flags & PMF_DOUBLEJUMPED)) {
+ self.pmove_flags |= PMF_SLIDE_STICKY;
+ } } } } } }
+
+ // apply gravity only when in the air, on a ramp,
+ // or in the 'sticky' state -- CEV
+ if (!(self.pmove_flags & PMF_ONGROUND))
+ self.pmove_flags |= PMF_SLIDE_GRAVITY;
+ else if (self.pmove_flags & PMF_SLIDE_STICKY)
+ self.pmove_flags |= PMF_SLIDE_GRAVITY;
+ else if (self.groundnormal_z < PM_PLANE_FLAT)
+ self.pmove_flags |= PMF_SLIDE_GRAVITY;
+
+ // skim / wallclipping checks -- CEV
+ if (self.doublejump_timer > PM_WALLCLIP_WINDOW) {
+ if (!(self.pmove_flags & PMF_STARTGROUND)) {
+ if (!(self.pmove_flags & PMF_ONGROUND)) {
+ if (!(self.pmove_flags & PMF_CLIMB))
+ {
+ self.pmove_flags |= PMF_SLIDE_SKIM;
+ } } } }

- // split the acceleration in two to reduce
- // framerate dependence. -- CEV
- if (self.conlevel >= WATERLEVEL_WAIST)
+ if (self.pmove_flags & PMF_ONLADDER)
{
- // figure out wishvel -- CEV
- makevectors (input_angles);
- wishvel = v_forward * input_movevalues_x +
- v_right * input_movevalues_y +
- v_up * input_movevalues_z;
-
- // swim acceleration
- PM_SwimAccelerate (wishvel,
- input_timelength * 0.5f);
+ // feature set for ladders -- CEV
+ self.pmove_flags &= ~PMF_SLIDE_GRAVITY;
+ self.pmove_flags &= ~PMF_SLIDE_SKIM;
+ self.pmove_flags &= ~PMF_SLIDE_STICKY;
}
- else
- {
- // only yaw matters here -- CEV
- makevectors ([0, input_angles_y, 0]);
- wishvel = v_forward * input_movevalues_x +
- v_right * input_movevalues_y;
- // don't need wishvel_z -- CEV
- // v_up * input_movevalues_z;
-
- PM_WalkAccelerate (wishvel,
- input_timelength * 0.5f);
-
- // WalkAccelerate calls Jump which might
- // alter pmove_flags, so do our feature
- // checks afterwards -- CEV
-
- // stick to the ground if we've jumped and
- // haven't yet doublejumped
- if (self.doublejump_timer > 0 &&
- !(self.pmove_flags & PMF_CROUCHSLIDE) &&
- !(self.pmove_flags & PMF_WALLJUMPED) &&
- !(self.pmove_flags & PMF_DOUBLEJUMPED))
- {
- self.pmove_flags |= PMF_SLIDE_STICKY;
- }
+ }

- // apply gravity only when in the air, on
- // a ramp, or in the 'sticky' state -- CEV
- if (!(self.pmove_flags & PMF_ONGROUND) ||
- self.pmove_flags & PMF_SLIDE_STICKY ||
- self.groundnormal_z < 1.0f)
- {
- self.pmove_flags |= PMF_SLIDE_GRAVITY;
- }
+ // timers (part 1) -- CEV
+ PM_ManageTimers (half_time);

- // skim / wallclipping checks -- CEV
- if (self.doublejump_timer >
- (PM_DOUBLEJUMP_WINDOW -
- PM_WALLCLIP_WINDOW) &&
- !(self.pmove_flags & PMF_WALLJUMPED) &&
- self.teleport_time <= (time - 0.1))
- {
- self.pmove_flags |= PMF_SLIDE_SKIM;
- }
+ // step if nostep is false...
+ if (world_nostep == FALSE)
+ {
+ // ... and either airstep is true or we're onground
+ if (world_airstep == TRUE)
+ self.pmove_flags |= PMF_SLIDE_STEP;
+ else if (self.pmove_flags & PMF_ONGROUND)
+ self.pmove_flags |= PMF_SLIDE_STEP;
+ }

- if (self.pmove_flags & PMF_ONLADDER)
- {
- // feature set for ladders -- CEV
- self.pmove_flags &= ~PMF_SLIDE_GRAVITY;
- self.pmove_flags &= ~PMF_SLIDE_SKIM;
- self.pmove_flags &= ~PMF_SLIDE_STICKY;
- }
- }
+ // Do the move. Bounce, Rock, Skate, Roll -- CEV
+ PM_CheckVelocity ();
+ PM_DanceMove ();

- // timers (part 1) -- CEV
- PM_ManageTimers (input_timelength * 0.5f);
+ // signal accel functions we're post-move -- CEV
+ self.pmove_flags &= ~PMF_PRE_MOVE;

- // Do the move. Bounce, Rock, Skate, Roll -- CEV
- self.pmove_flags |= PMF_SLIDE_STEP;
- PM_DanceMove ();
+ // second pass at acceleration -- CEV
+ if (self.conlevel >= WATERLEVEL_WAIST)
+ PM_SwimAccelerate (half_time);
+ else
+ PM_WalkAccelerate (half_time);

- // signal accel functions we're post-move
- self.pmove_flags &= ~PMF_PRE_MOVE;
+ // timers (part 2) -- CEV
+ PM_ManageTimers (half_time);

- // second pass at acceleration, making sure
- // our v_ vectors are correct
- if (self.conlevel >= WATERLEVEL_WAIST)
- {
- makevectors (input_angles);
- PM_SwimAccelerate (wishvel,
- input_timelength * 0.5f);
- }
- else
- {
- makevectors ([0, input_angles_y, 0]);
- PM_WalkAccelerate (wishvel,
- input_timelength * 0.5f);
- }
+ // clear ladder flag -- CEV
+ if (self.pmove_flags & PMF_ONLADDER)
+ self.pmove_flags &= ~PMF_ONLADDER;
+ }
+ else if (self.movetype == MOVETYPE_FLY)
+ {
+ // split acceleration in two to improve responsiveness -- CEV
+ PM_NoClipAccelerate (1.0f, half_time);

- // timers (part 2) -- CEV
- PM_ManageTimers (input_timelength * 0.5f);
+ // step if nostep is false...
+ if (world_nostep == FALSE)
+ {
+ // ... and either airstep is true or we're onground
+ if (world_airstep == TRUE)
+ self.pmove_flags |= PMF_SLIDE_STEP;
+ else if (self.pmove_flags & PMF_ONGROUND)
+ self.pmove_flags |= PMF_SLIDE_STEP;
+ }

- // clear ladder flag -- CEV
- if (self.pmove_flags & PMF_ONLADDER)
- self.pmove_flags &= ~PMF_ONLADDER;
- break;
+ PM_DanceMove ();
+ PM_NoClipAccelerate (1.0f, half_time);
+ }
+ else if (self.movetype == MOVETYPE_NOCLIP)
+ {
+ // noclip is a debugging feature, no need to
+ // worry about acceleration consistency. -- CEV
+ PM_NoClipAccelerate (1.0f, input_timelength);
+ // we're noclipping so update origin directly -- CEV
+ self.origin += self.velocity * input_timelength;
+ }

- case MOVETYPE_FLY:
- // split acceleration in two to reduce framerate
- // dependence. -- CEV
- makevectors (input_angles);
- wishvel = v_forward * input_movevalues_x;
- wishvel += v_right * input_movevalues_y;
- wishvel += v_up * input_movevalues_z;
-
- PM_NoClipAccelerate (wishvel, 1.0f,
- input_timelength * 0.5f);
- self.pmove_flags |= PMF_SLIDE_STEP;
- PM_DanceMove ();
- PM_NoClipAccelerate (wishvel, 1.0f,
- input_timelength * 0.5f);
- break;
+ touchtriggers ();

- case MOVETYPE_NOCLIP:
- // noclip is a debugging feature, no need to
- // worry about acceleration consistency. -- CEV
- makevectors (input_angles);
- wishvel = v_forward * input_movevalues_x;
- wishvel += v_right * input_movevalues_y;
- wishvel += v_up * input_movevalues_z;
-
- PM_NoClipAccelerate (wishvel, 1.0f, input_timelength);
- // we're noclipping so update origin directly -- CEV
- self.origin += self.velocity * input_timelength;
- break;
+ PM_CategorizePosition ();

- case MOVETYPE_NONE:
- break;
+ if (self.velocity != '0 0 0')
+ {
+ PM_CheckVelocity ();
+ self.velocity = PM_TruncateVector (self.velocity);
}

self.oldorigin = self.origin;
- self.speed = vlen ([self.velocity_x, self.velocity_y, 0]);
-
- // make sure we've touched the ground entity (it might've slipped
- // through the slidemove above) -- CEV
- PM_DoTouch (self.groundentity);
-
- touchtriggers ();

// restore self just in case -- CEV
self = oself;

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

Diff qc/projectiles/bolt.qc

diff --git a/qc/projectiles/bolt.qc b/qc/projectiles/bolt.qc
index edba774..5ba204b 100644
--- a/qc/projectiles/bolt.qc
+++ b/qc/projectiles/bolt.qc
@@ -186,7 +186,7 @@ strip void() projectile_bolt;

e.classname = "projectile_bolt";
e.classtype = CT_PROJECTILE_BOLT;
- e.movetype = MOVETYPE_BOUNCE;
+ e.movetype = MOVETYPE_TOSS;
e.solid = SOLID_BBOX;
e.think = projectile_bolt_think;
e.touch = projectile_bolt_touch;

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

Diff qc/triggers/ladder.qc

diff --git a/qc/triggers/ladder.qc b/qc/triggers/ladder.qc
index fea43a8..71b3941 100644
--- a/qc/triggers/ladder.qc
+++ b/qc/triggers/ladder.qc
@@ -81,7 +81,7 @@ Keys:
//--------------------------------------------------------------
float(entity to, float netflags) trigger_ladder_netsend =
{
- WriteFloat (MSG_ENTITY, self.classtype);
+ WriteShort (MSG_ENTITY, self.classtype);
WriteFloat (MSG_ENTITY, netflags);

if (netflags & BASE_TRIGGER_NET_ORIGIN)

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 ec53c46..d81e013 100644
--- a/qc/triggers/push.qc
+++ b/qc/triggers/push.qc
@@ -179,7 +179,7 @@ vector(float a, float b, float c) solve_quadratic =
//--------------------------------------------------------------
float(entity to, float netflags) base_trigger_push_netsend =
{
- WriteFloat (MSG_ENTITY, self.classtype);
+ WriteShort (MSG_ENTITY, self.classtype);
WriteFloat (MSG_ENTITY, netflags);

if (netflags & BASE_TRIGGER_NET_ORIGIN)

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

Diff qc/triggers/setgravity.qc

diff --git a/qc/triggers/setgravity.qc b/qc/triggers/setgravity.qc
index fe7d382..86febc0 100644
--- a/qc/triggers/setgravity.qc
+++ b/qc/triggers/setgravity.qc
@@ -111,7 +111,7 @@ set the gravity of a player
//--------------------------------------------------------------
float(entity to, float netflags) trigger_setgravity_netsend =
{
- WriteFloat (MSG_ENTITY, self.classtype);
+ WriteShort (MSG_ENTITY, self.classtype);
WriteFloat (MSG_ENTITY, netflags);

if (netflags & BASE_TRIGGER_NET_ORIGIN)

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

Diff qc/triggers/teleport.qc

diff --git a/qc/triggers/teleport.qc b/qc/triggers/teleport.qc
index 501ffcf..dbd816b 100644
--- a/qc/triggers/teleport.qc
+++ b/qc/triggers/teleport.qc
@@ -352,8 +352,7 @@ TRIGGER_TELEPORT_ONLYMONSTER(16) will only teleport monsters
// turn this way immediately
other.fixangle = 1;
other.teleport_time = time + 0.7;
- // push player out at PM_TELEEXITSPEED -- CEV
- other.velocity = v_forward * PM_TELEEXITSPEED;
+ other.velocity = v_forward * PM_MAXSPEED;
// TODO CEV commented out the next line
// other.flags -= other.flags & FL_ONGROUND;
}
@@ -364,10 +363,9 @@ TRIGGER_TELEPORT_ONLYMONSTER(16) will only teleport monsters
// turn this way immediately
other.fixangle = 1;
other.teleport_time = time + 0.7;
+ other.velocity = v_forward * 300;
if (other.flags & FL_ONGROUND)
- other.flags = other.flags - FL_ONGROUND;
- other.velocity = v_forward * PM_TELEEXITSPEED;
- other.flags -= other.flags & FL_ONGROUND;
+ other.flags -= other.flags & FL_ONGROUND;
}
};

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