djcev.com

//

Git Repos / fte_dogmode / commit 6145cef

Commit: 6145cef338e80661c33fcb346a730b988dfb7295
Parent: 59d0c37e1082d4559164e9b949313bcf26b4f36e
Author: Cameron Vanderzanden, 2024-11-20 23:54
Committer: Cameron Vanderzanden, 2024-11-20 23:54

Commit Message

pmove refactor into prepoc macros, view bobbing

The major change this commit is that most of the pmove code has
been refactored / re-written to work as preprocessor macros. This
has the effect of inlining all that code into whatever function
calls the macro, hopefully improving performance by reducing the
number of QuakeC function calls. (Testing with the FTEQW QuakeC
profiler this seems to have improved performance by over 2x).
I've also managed to essentially unroll the slidemove velocity
clipping loops by using preproc macros. (I think, anyway, it seems
to work). Unfortunately all this has made the code more difficult
to read and understand and requires some careful attention to keep
one block of code from stepping on another (as they're all now running
consecutively in the same function context). In short: it runs faster
now.

During that process I managed to fix a bug with bad crouching state
tracking & fixed some bugs (+improved) the stair stepping routine
in the slidemove. I don't think stair stepping can be perfect
without calling the SlideMove twice but I can continue to improve it
as I find edge cases (by wallstrafing into increasingly cursed
combinations of stairs and complex wall brushes).

I've also changed some of the CalcRefDef stuff (refactored into
preproc macros) and added view bobbing (cl_bob, based directly
on the implementation in Ironwail).

Lightning beams still don't track players correctly. There are
other additional known bugs I still need to track down. But I'd
better commit this now before I think better of it.

Change List

Diff autoexec.cfg

diff --git a/autoexec.cfg b/autoexec.cfg
index 8e765b3..06356e5 100644
--- a/autoexec.cfg
+++ b/autoexec.cfg
@@ -1,10 +1,14 @@
// don't autoswitch weapons
seta cg_autoswitch 0
//
+seta cl_bob 0.005
seta cl_rollangle 0.5
seta cl_rollspeed 200
//
seta cl_run 0
+seta cl_forwardspeed 320
+seta cl_sidespeed 320
+seta cl_backspeed 320
// enable air stepping
seta pm_airstep 1
// enable wall jumps

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

Diff qc/base_entities.qc

diff --git a/qc/base_entities.qc b/qc/base_entities.qc
index d63b3df..34a68f0 100644
--- a/qc/base_entities.qc
+++ b/qc/base_entities.qc
@@ -434,18 +434,14 @@ void() noclass;

#ifdef SSQC
// do our content transition checks right here -- CEV
- if (e.contype <= CONTENT_WATER && oldtype == CONTENT_EMPTY)
+ if (e.contype <= CONTENT_WATER && oldtype == CONTENT_EMPTY) {
+ if (e.classtype != CT_PLAYER) {
+ if (e.swim_time < time)
{
- if (e.classtype != CT_PLAYER)
- {
- if (e.swim_time < time)
- {
- e.swim_time = time + 2;
- sound (e, CHAN_AUTO, "misc/h2ohit1.wav",
- VOL_MID, ATTN_NORM);
- }
- }
- }
+ e.swim_time = time + 2;
+ sound (e, CHAN_AUTO, "misc/h2ohit1.wav", VOL_MID,
+ ATTN_NORM);
+ } } }

if (e.contype == CONTENT_EMPTY)
{

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 be30ca6..e75564a 100644
--- a/qc/base_func.qc
+++ b/qc/base_func.qc
@@ -346,6 +346,9 @@ strip void() base_func;
{
base_mapentity_init (e);
e.classgroup |= CG_FUNC;
+
+ // TODO CEV
+ e.flags |= FL_LAGGEDMOVE;
};
#endif

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

Diff qc/base_item.qc

diff --git a/qc/base_item.qc b/qc/base_item.qc
index 6c8863d..d85ecc7 100644
--- a/qc/base_item.qc
+++ b/qc/base_item.qc
@@ -241,7 +241,11 @@ strip void() base_item;
sound (self, CHAN_VOICE, ITEM_SOUND_SPAWN, VOL_HIGH, ATTN_NORM);

setorigin (self, self.origin);
- if (self.pos1 && self.pos2)
+ /*
+ dprint (sprintf("base_item_think_respawn: pos1 %v pos2 %v\n",
+ self.pos1, self.pos2));
+ */
+ if (self.pos1 || self.pos2)
setsize (self, self.pos1, self.pos2);
};

@@ -262,7 +266,7 @@ strip void() base_item;
dprint ("base_item_think_rhull: fix for bboxes\n");

// dumptruck_ds -- fix for bounding boxes
- if (self.pos1 && self.pos2)
+ if (self.pos1 || self.pos2)
setsize (self, self.pos1, self.pos2);
else
setsize (self, '0 0 0', '32 32 56');

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

Diff qc/base_trigger.qc

diff --git a/qc/base_trigger.qc b/qc/base_trigger.qc
index 999f265..cbf2199 100644
--- a/qc/base_trigger.qc
+++ b/qc/base_trigger.qc
@@ -13,6 +13,7 @@ const float BASE_TRIGGER_NET_STATE = 1<<2; // state has changed
const float BASE_TRIGGER_NET_ESTATE = 1<<3; // estate has changed
const float BASE_TRIGGER_NET_MOVEDIR = 1<<4; // movedir has changed
const float BASE_TRIGGER_NET_SPEED = 1<<5; // speed has changed
+const float BASE_TRIGGER_NET_ANGLES = 1<<6; // angle has changed
#endif

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

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 7ce9242..05fc34b 100644
--- a/qc/cl_entry.qc
+++ b/qc/cl_entry.qc
@@ -83,6 +83,10 @@ __used var float physics_mode = 2; // 0 = not run, 1 = DP, 2 = movetypes
//======================================================================

#ifdef CSQC
+void(float eid, vector start, vector end) CL_TE_Lightning2;
+#endif
+
+#ifdef CSQC
float(string cmd) CSQC_ConsoleCommand;
// float(float evtype, float scanx, float chary, float devid) CSQC_InputEvent;
// __used void() CSQC_Input_Frame;
@@ -118,6 +122,36 @@ void() SetChangeParms = sub_null;

#ifdef CSQC
//----------------------------------------------------------------------
+void(float eid, vector start, vector end) CL_TE_Lightning2 =
+{
+ // TODO CEV
+ local vector org;
+ local float isknown = getentity (eid, GE_ACTIVE);
+
+ if (isknown)
+ {
+ org = getentity (eid, GE_ORIGIN);
+ dprint (sprintf("CL_TE_Lightning2: known; "
+ "pos %v, end %v, eid %g, org %v\n",
+ start, end, eid, org));
+ te_lightning2 (world, start, end);
+ }
+ else
+ {
+ if (deathmatch == 0)
+ org = view_pl.origin;
+ else
+ org = '999 999 999';
+ dprint (sprintf("CL_TE_Lightning2: unknown; "
+ "pos %v, end %v, eid %g, org %v\n",
+ start, end, eid, org));
+ te_lightning2 (world, start, end);
+ }
+};
+#endif
+
+#ifdef CSQC
+//----------------------------------------------------------------------
// Stubs for extra CSQC functions (not all supported)
//----------------------------------------------------------------------

@@ -156,8 +190,10 @@ __used void() CSQC_Input_Frame =
// 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
@@ -170,11 +206,9 @@ __used void() CSQC_Input_Frame =
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)
@@ -186,13 +220,13 @@ __used void() CSQC_Input_Frame =
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);
- */
}
+ /*
}
+ */
};
#endif

@@ -303,10 +337,10 @@ void(float vwidth, float vheight, float notmenu) CSQC_UpdateView =
// read our smoothed & predicted view origin
setproperty (VF_ORIGIN, view_origin);

- makevectors (view_angles);
-
if (intermission)
{
+ makevectors (view_angles);
+
// camera wobble
view_angles_x += autocvar(v_ipitch_level, 0.3) *
sin(time * autocvar(v_ipitch_cycle, 1));
@@ -321,34 +355,12 @@ void(float vwidth, float vheight, float notmenu) CSQC_UpdateView =
}
else
{
- // punchangle code from Ironwail -- CEV
- if (autocvar(v_gunkick, 1)) {
- if (view_punch2 || view_punch1)
- {
- view_angles_x += view_punch2 + bound (0,
- (time - view_punch_time) / 0.1f, 1) *
- (view_punch1 - view_punch2);
- } }
-
- // roll code from Ironwail -- CEV
- local float rollspeed = autocvar (cl_rollspeed, 200);
- local float rollangle = autocvar (cl_rollangle, 2.0f);
-
- if (rollspeed && rollangle)
- {
- local float roll = view_pl.velocity * v_right;
- local float sign = roll < 0 ? -1 : 1;
- roll = fabs (roll);
-
- if (roll < rollspeed)
- roll *= rollangle / rollspeed;
- else
- roll = rollangle;
-
- view_angles_z += roll * sign;
- }
-
+ // view_angle adjustments performed in
+ // player_prediction_preframe -- CEV
setproperty (VF_ANGLES, view_angles);
+
+ // v_forward et al should still match the makevectors
+ // call in player_prediction_preframe -- CEV
SetListener (view_origin, v_forward, v_right, v_up);

// draw view model when not invisible
@@ -445,19 +457,8 @@ float() CSQC_Parse_TempEntity =
lgend_y = ReadCoord ();
lgend_z = ReadCoord ();

- /*
- dprint (sprintf("CSQC_Parse_TempEntity: TE_LIGHTNING2: "
- "pos %v, end %v, eid %g, player %g\n",
- lgpos, lgend, eid, edict_num(eid)));
- */
-
- /*
- trailparticles (particleeffectnum("te_lightning2"),
- view_pl, getentity(eid, GE_ORIGIN), lgend);
- */
-
// TODO CEV fix FTE particle effect te_lightning2
- te_lightning2 (edict_num(eid), lgpos, lgend);
+ CL_TE_Lightning2 (eid, lgpos, lgend);

return TRUE;
default:

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

Diff qc/cl_progs.src

diff --git a/qc/cl_progs.src b/qc/cl_progs.src
index 4e36570..f430765 100644
--- a/qc/cl_progs.src
+++ b/qc/cl_progs.src
@@ -20,7 +20,6 @@ defs_ctypes.qc // global class list
// utility & helper functions
//----------------------------------------------------------------------
math.qc // Code by Joshua Skelton + misc
-cshift.qc // overlay color shift controller

//----------------------------------------------------------------------
// object bootstrapping
@@ -35,6 +34,7 @@ world.qc //
// movement, CSQC HUD, CSQC entrypoints
//----------------------------------------------------------------------
pmove.qc // player movement code
+cshift.qc // overlay color shift controller
cl_hud.qc // modified AD vanilla HUD (originally by Sock)
cl_entry.qc // modified AD CSQC (originally by Sock)

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 059da86..c9de79c 100644
--- a/qc/cshift.qc
+++ b/qc/cshift.qc
@@ -42,7 +42,7 @@ void(vector ssize) csf_draw;
//----------------------------------------------------------------------
void(entity c, float d, vector col) csf_set_netsend =
{
- col = PM_TruncateVectorToEighth (col);
+ PM_TRUNCATEVECTORTOEIGTH (col)
WriteByte (MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte (MSG_MULTICAST, EVENT_CSHIFT_SET);
WriteShort (MSG_MULTICAST, col_x);

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

Diff qc/defs_const.qc

diff --git a/qc/defs_const.qc b/qc/defs_const.qc
index 2c78ab6..0cc80e2 100644
--- a/qc/defs_const.qc
+++ b/qc/defs_const.qc
@@ -15,6 +15,8 @@ const float FALSE = 0; //
const float TRUE = 1;
const float NEGATIVE = -1;

+const float M_PI = 3.14159265358979323846; // matches value in gcc v2 math.h
+
const float FL_FLY = 1; // standard id1 .flags follow
const float FL_SWIM = 2;
const float FL_CLIENT = 8; // set for all client edicts
@@ -30,6 +32,7 @@ const float FL_JUMPRELEASED = 4096; // for jump debouncing
const float FL_NOSELECT = 8192; // ignored by entity selector
const float FL_NOCENTERPRINT = 65536; // don't centerprint entity's message
// field when its targets are used
+const float FL_LAGGEDMOVE = 65536; // Enables anti-lag on rockets etc.

const float MOVETYPE_NONE = 0; // .movetype values; never moves
// const float MOVETYPE_ANGLENOCLIP = 1;

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

Diff qc/hazards/shooter.qc

diff --git a/qc/hazards/shooter.qc b/qc/hazards/shooter.qc
index 3a3f348..d23c042 100644
--- a/qc/hazards/shooter.qc
+++ b/qc/hazards/shooter.qc
@@ -83,9 +83,8 @@ void() trap_switched_shooter;

local vector laser_velocity = normalize (self.movedir);
// SetSpeed
- laser_velocity *= min (
- LASER_SPEED * self.proj_speed_mod,
- world_maxvelocity);
+ laser_velocity *= min (LASER_SPEED *
+ self.proj_speed_mod, PM_MAXVELOCITY);

// fire_laser
spawn_projectile_laser (self, self.origin,

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

Diff qc/items/backpacks.qc

diff --git a/qc/items/backpacks.qc b/qc/items/backpacks.qc
index ecf557d..cf9118b 100644
--- a/qc/items/backpacks.qc
+++ b/qc/items/backpacks.qc
@@ -66,24 +66,22 @@ e.g. For 'You got a bunch of rockets!' the netname key would be
//--------------------------------------------------------------
void() item_backpack_touch =
{
+ if (sub_checkvalidtouch(other) == FALSE)
+ return;
+
+ // from Copper -- dumptruck_ds
+ if (other.movetype == MOVETYPE_NOCLIP)
+ return;
+ if (other.classtype != CT_PLAYER)
+ return;
+ if (other.health <= 0)
+ return;
+
if (self.spawnflags & BACKPACK_DROPPED)
{
- /*
- if (sub_checkvalidtouch(other) == FALSE)
- return;
- */
-
local string s;
local float acount, best, old, new;

- // from Copper -- dumptruck_ds
- if (other.movetype == MOVETYPE_NOCLIP)
- return;
- if (other.classtype != CT_PLAYER)
- return;
- if (other.health <= 0)
- return;
-
acount = 0;
sprint (other, "You get ");

@@ -363,6 +361,7 @@ e.g. For 'You got a bunch of rockets!' the netname key would be
}
else
{
+ setsize (e, e.pos1, e.pos2);
base_item_init (e);
}
};

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 90533d0..6d5f143 100644
--- a/qc/monsters/playerclient.qc
+++ b/qc/monsters/playerclient.qc
@@ -47,9 +47,11 @@ enumflags
//======================================================================

#ifdef CSQC
-float view_offset; // view smoothing for crouching -- CEV
-float view_offset_old;
-float view_offset_finished;
+float view_bob; // head bobbing -- CEV
+float view_bob_old;
+float view_crouch; // view smoothing for crouching -- CEV
+float view_crouch_old;
+float view_crouch_finished;
float view_punch1; // punchangle_x -- CEV
float view_punch2;
float view_punch_time;
@@ -125,13 +127,18 @@ float modelindex_player;

// player
#ifdef CSQC
+// PLAYER_PREDICTION_SAVE(e)
+// PLAYER_PREDICTION_RESET(e)
+// PLAYER_PREDICTION(e, endframe)
+// PLAYER_VIEW_BOB(e)
+// PLAYER_VIEW_CROUCH(e)
+// PLAYER_VIEW_PUNCHANGLE()
+// PLAYER_VIEW_ROLL(e)
+// PLAYER_VIEW_STEPS(e)
void(float isnew) player_netreceive;
float() player_predraw;
static void() player_remove;
-void(entity e) player_prediction_save;
-void(entity e) player_prediction_reset;
void(entity e) player_prediction_preframe;
-void(entity e, float endframe) player_prediction;
void(entity e) player_prediction_postframe;
#endif
#ifdef SSQC
@@ -311,6 +318,291 @@ $frame axattd1 axattd2 axattd3 axattd4 axattd5 axattd6

#ifdef CSQC
//--------------------------------------------------------------
+ #define PLAYER_PREDICTION_SAVE(e) \
+ { \
+ e.origin_net = e.origin; \
+ e.velocity_net = e.velocity; \
+ e.angles_net = e.angles; \
+ e.flags_net = e.flags; \
+ e.pm_flags_net = e.pm_flags; \
+ e.pm_timer_net = e.pm_timer; \
+ }
+
+ //--------------------------------------------------------------
+ // was Pred_ResetPlayerPrediction in CSQCTest cs/prediction.qc
+ //--------------------------------------------------------------
+ #define PLAYER_PREDICTION_RESET(e) \
+ { \
+ e.origin = e.origin_net; \
+ e.velocity = e.velocity_net; \
+ e.angles = e.angles_net; \
+ e.flags = e.flags_net; \
+ e.pm_flags = e.pm_flags_net; \
+ e.pm_timer = e.pm_timer_net; \
+ /* setsize (e, e.mins, e.maxs); */ \
+ if (e.pm_flags & PMF_CROUCHED) \
+ setsize (e, PM_CROUCH_MIN, PM_CROUCH_MAX); \
+ else \
+ setsize (e, PM_STAND_MIN, PM_STAND_MAX); \
+ if (e.commandframe < clientcommandframe - 128) \
+ /* avoid an infinite loop */ \
+ e.commandframe = clientcommandframe - 128; \
+ }
+
+ //--------------------------------------------------------------
+ // was Pred_RunMovement in CSQCTest cs/prediction.qc
+ //--------------------------------------------------------------
+ #define PLAYER_PREDICTION(e, endframe) \
+ { \
+ if (servercommandframe >= e.commandframe + 63) \
+ { \
+ /* we're meant to be updating the player faster than
+ * this. hopefully its just that we're throttled... */ \
+ /* you can comment out this block and the player will
+ * continue to be predicted locally. But its best to
+ * freeze them */ \
+ /* dprint ("player_prediction: slow update\n"); */ \
+ e.commandframe = servercommandframe - 63; \
+ } \
+ else \
+ { \
+ if (getstatf(STAT_HEALTH) <= 0) \
+ { \
+ /* dead, so don't run prediction. :D */ \
+ e.commandframe = clientcommandframe; \
+ if (getinputstate(e.commandframe - 1) == FALSE) \
+ { \
+ dprint ("PLAYER_PREDICTION: noop?\n"); \
+ /* TODO CEV no-op ? */ \
+ } \
+ } \
+ else \
+ { \
+ /* 'self' needs to be the entity moving for
+ * the macros below to work -- CEV */ \
+ local entity oself = self; \
+ self = e; \
+ /* update view_pl -- CEV */ \
+ if (self.entnum == player_localentnum) { \
+ if (self != view_pl) \
+ { \
+ view_pl = self; \
+ } } \
+ for (float lc = e.commandframe + 1; \
+ lc <= endframe; lc++) \
+ { \
+ local float f = getinputstate (lc); \
+ if (f == FALSE) \
+ { \
+ /* no input from client */ \
+ break; \
+ } \
+ if (input_timelength <= 0) \
+ { \
+ break; \
+ } \
+ /*
+ if (i == clientcommandframe)
+ CSQC_Input_Frame ();
+ */ \
+ /* do the move; see pmove.qc -- CEV */ \
+ PM_MOVE_PRE () \
+ PM_MOVE_MOVETYPES () \
+ PM_MOVE_POST () \
+ /* don't do step smoothing when flagged
+ * not to -- CEV */ \
+ if (self.pm_flags & PMF_ONMOVINGENT) { \
+ if (view_step_disable == FALSE) \
+ { \
+ view_step_disable = TRUE; \
+ } } \
+ else if (view_step_disable) \
+ { \
+ view_step_disable = FALSE; \
+ } \
+ } \
+ /* restore 'self' -- CEV */ \
+ self = oself; \
+ /* add anything that was applied after
+ * (for low packet rate protocols) */ \
+ /* input_angles = view_angles; */ \
+ } \
+ } \
+ } \
+
+ //--------------------------------------------------------------
+ // PLAYER_VIEW_BOB -- view bob (based on Ironwail's V_CalcBob) -- CEV
+ //--------------------------------------------------------------
+ #define PLAYER_VIEW_BOB(e) \
+ { \
+ local float cl_bob = autocvar (cl_bob, 0.02); \
+ local float cl_bobcycle = autocvar (cl_bobcycle, 0.6); \
+ if (cl_bob && cl_bobcycle) \
+ { \
+ local float cl_bobup = autocvar (cl_bobup, 0.5); \
+ local float C = 0; \
+ C = time - rint((time / cl_bobcycle)) * cl_bobcycle; \
+ C /= cl_bobcycle; \
+ if (C < cl_bobup) \
+ C = M_PI * C / cl_bobup; \
+ else \
+ C = M_PI + M_PI * (C - cl_bobup) / \
+ (1.0 - cl_bobup); \
+ /* bob is proportional to velocity in the xy plane
+ * (don't count Z, or jumping messes it up) */ \
+ view_bob = vlen ([self.velocity_x, self.velocity_y]); \
+ view_bob *= cl_bob; \
+ view_bob = view_bob * 0.3 + view_bob * 0.7 * sin(C); \
+ view_bob = bound (-7, view_bob, 4); \
+ /* only bob when onground and try to limit abrupt
+ * view changes when landing -- CEV */ \
+ /* this is pretty tortured -- CEV */ \
+ if (e.pm_flags & PMF_ONGROUND && \
+ !(e.pm_flags & PMF_CROUCHSLIDE)) \
+ { \
+ if (view_bob_old) \
+ { \
+ if (fabs(view_bob) - \
+ fabs(view_bob_old) < cl_bob) \
+ { \
+ view_bob_old = 0; \
+ } \
+ else \
+ { \
+ view_bob = view_bob_old; \
+ } \
+ } \
+ } \
+ else \
+ { \
+ if (view_bob_old) \
+ { \
+ view_bob_old *= 0.9f; \
+ if (view_bob_old > 0) \
+ view_bob_old = max (PM_FLMIN, \
+ view_bob_old); \
+ else \
+ view_bob_old = min (-PM_FLMIN, \
+ view_bob_old); \
+ view_bob = view_bob_old; \
+ } \
+ else \
+ { \
+ view_bob_old = view_bob; \
+ } \
+ } \
+ /*
+ dprint (sprintf("PLAYER_VIEW_BOB: view_bob "
+ "%g, old %g\n", view_bob, view_bob_old));
+ */ \
+ } \
+ else \
+ { \
+ if (view_bob) \
+ view_bob = 0; \
+ if (view_bob_old) \
+ view_bob_old = 0; \
+ } \
+ view_origin.z += view_bob; \
+ }
+
+ //--------------------------------------------------------------
+ // PLAYER_VIEW_CROUCH -- smooth crouching -- CEV
+ //--------------------------------------------------------------
+ #define PLAYER_VIEW_CROUCH(e) \
+ { \
+ if (view_crouch_finished > time) \
+ { \
+ if (view_crouch_old != e.view_ofs.z) \
+ { \
+ local float zc; \
+ zc = 1 - (view_crouch_finished - time) / \
+ PLAYER_CROUCH_SMOOTH; \
+ view_crouch = lerp_hermite (view_crouch_old, \
+ e.view_ofs.z, zc); \
+ } \
+ } \
+ else \
+ { \
+ if (view_crouch_old != e.view_ofs.z) \
+ view_crouch_old = e.view_ofs.z; \
+ view_crouch = e.view_ofs.z; \
+ } \
+ view_origin.z += view_crouch; \
+ }
+
+ //--------------------------------------------------------------
+ // PLAYER_VIEW_PUNCHANGLE -- punchangle code from Ironwail -- CEV
+ //--------------------------------------------------------------
+ #define PLAYER_VIEW_PUNCHANGLE() \
+ { \
+ /* punchangle code from Ironwail -- CEV */ \
+ if (autocvar(v_gunkick, 1)) { \
+ if (view_punch2 || view_punch1) \
+ { \
+ view_angles.x += view_punch2 + bound \
+ (0, (time - view_punch_time) / 0.1f, 1) * \
+ (view_punch1 - view_punch2); \
+ } } \
+ }
+
+ //--------------------------------------------------------------
+ // PLAYER_VIEW_ROLL -- sideways view roll code from Ironwail -- CEV
+ //--------------------------------------------------------------
+ #define PLAYER_VIEW_ROLL(e) \
+ { \
+ local float view_rollspeed = autocvar (cl_rollspeed, 200); \
+ local float view_rollangle = autocvar (cl_rollangle, 2.0f); \
+ if (view_rollspeed && view_rollangle) \
+ { \
+ local float view_roll = e.velocity * v_right; \
+ local float view_sign = view_roll < 0 ? -1 : 1; \
+ view_roll = fabs (view_roll); \
+ if (view_roll < view_rollspeed) \
+ view_roll *= view_rollangle / view_rollspeed; \
+ else \
+ view_roll = view_rollangle; \
+ view_angles.z += view_roll * view_sign; \
+ } \
+ }
+
+ //--------------------------------------------------------------
+ // PLAYER_VIEW_STEPS -- step smoothing, based on CSQCTest -- CEV
+ //--------------------------------------------------------------
+ #define PLAYER_VIEW_STEPS(e) \
+ { \
+ local float view_step_diff = e.origin.z - view_step_oldz; \
+ if (view_step_disable == FALSE) { \
+ if (e.pm_flags & PMF_ONGROUND) { \
+ if (view_step_diff >= 4 && view_step_diff <= PM_STEPHEIGHT) \
+ { \
+ if (e.speed) \
+ view_step_adjust = e.speed * 0.018; \
+ else \
+ view_step_adjust = PM_MAXSPEED * 0.018; \
+ view_step_adjust = bound (4, view_step_adjust, 16); \
+ /* evaluate out the remaining old step */ \
+ if (view_step_time - time > 0) \
+ view_step = (view_step_time - time) * \
+ view_step_adjust * view_step; \
+ else \
+ view_step = 0; \
+ view_step += view_step_diff; \
+ view_step_time = time + (1 / view_step_adjust); \
+ /*
+ dprint (sprintf("player_prediction_preframe: "
+ "pm_step %g, step %g, step_adjust %g\n",
+ view_pm_step, view_step, view_step_adjust));
+ */ \
+ } } } \
+ view_step_oldz = e.origin.z; \
+ /* now do the adjustment -- CEV */ \
+ if (view_step_time - time > 0) \
+ view_origin.z -= (view_step_time - time) * \
+ view_step_adjust * view_step; \
+ }
+
+ //--------------------------------------------------------------
// called from CSQC_Ent_Update for CT_PLAYER entities
//--------------------------------------------------------------
void(float isnew) player_netreceive =
@@ -392,6 +684,7 @@ $frame axattd1 axattd2 axattd3 axattd4 axattd5 axattd6

if (isnew && !(self.predraw))
{
+ dprint ("player_netreceive: init player...\n");
self.pm_flags = newmoveflags;
player_init (self);
}
@@ -400,22 +693,41 @@ $frame axattd1 axattd2 axattd3 axattd4 axattd5 axattd6
if (newmoveflags & PMF_CROUCHED &&
(!(self.pm_flags & PMF_CROUCHED)))
{
+ self.pm_flags = newmoveflags;
PM_CrouchStart ();
}
else if ((!(newmoveflags & PMF_CROUCHED)) &&
self.pm_flags & PMF_CROUCHED)
{
+ self.pm_flags = newmoveflags;
PM_CrouchStop ();
}
-
+ else
+ {
+ if (newmoveflags & PMF_CROUCHED)
+ setsize (self, PM_CROUCH_MIN,
+ PM_CROUCH_MAX);
+ else
+ setsize (self, PM_STAND_MIN,
+ PM_STAND_MAX);
+ self.pm_flags = newmoveflags;
+ }
+ }
+ else
+ {
self.pm_flags = newmoveflags;
+ // Make sure mins & maxs match the server -- CEV
+ if (self.pm_flags & PMF_CROUCHED)
+ setsize (self, PM_CROUCH_MIN, PM_CROUCH_MAX);
+ else
+ setsize (self, PM_STAND_MIN, PM_STAND_MAX);
}

if (self.entnum == player_localentnum)
{
view_pl = self;
self.commandframe = servercommandframe;
- player_prediction_save (self);
+ PLAYER_PREDICTION_SAVE (self)
}

// TODO CEV movement interpolation for other players
@@ -495,34 +807,6 @@ $frame axattd1 axattd2 axattd3 axattd4 axattd5 axattd6
};

//--------------------------------------------------------------
- void(entity e) player_prediction_save =
- {
- e.origin_net = e.origin;
- e.velocity_net = e.velocity;
- e.angles_net = e.angles;
- e.flags_net = e.flags;
- e.pm_flags_net = e.pm_flags;
- e.pm_timer_net = e.pm_timer;
- };
-
- //--------------------------------------------------------------
- // was Pred_ResetPlayerPrediction in CSQCTest cs/prediction.qc
- //--------------------------------------------------------------
- void(entity e) player_prediction_reset =
- {
- e.origin = e.origin_net;
- e.velocity = e.velocity_net;
- e.angles = e.angles_net;
- e.flags = e.flags_net;
- e.pm_flags = e.pm_flags_net;
- e.pm_timer = e.pm_timer_net;
-
- if (e.commandframe < clientcommandframe - 128)
- // avoid an infinite loop
- e.commandframe = clientcommandframe - 128;
- };
-
- //--------------------------------------------------------------
void(entity e) player_prediction_preframe =
{
if (serverkeyfloat(SERVERKEY_PAUSESTATE))
@@ -534,127 +818,26 @@ $frame axattd1 axattd2 axattd3 axattd4 axattd5 axattd6
return;
}

- // player_prediction_save (e);
- player_prediction (e, clientcommandframe);
+ // PLAYER_PREDICTION_SAVE (e)
+ PLAYER_PREDICTION (e, clientcommandframe)

- // step smoothing
- local float view_diff = e.origin_z - view_step_oldz;
- if (view_step_disable == FALSE && e.pm_flags & PMF_ONGROUND
- && view_diff >= 4 && view_diff <= PM_STEPHEIGHT)
- {
- if (e.speed)
- view_step_adjust = e.speed * 0.018;
- else
- view_step_adjust = PM_MAXSPEED * 0.018;
-
- view_step_adjust = bound (4, view_step_adjust, 16);
-
- // evaluate out the remaining old step
- if (view_step_time - time > 0)
- view_step = (view_step_time - time) *
- view_step_adjust * view_step;
- else
- view_step = 0;
-
- view_step += view_diff;
- view_step_time = time + (1 / view_step_adjust);
-
- /*
- dprint (sprintf("player_prediction_preframe: "
- "pm_step %g, step %g, step_adjust %g\n",
- view_pm_step, view_step, view_step_adjust));
- */
- }
-
- // smooth crouching (and other view offset Z changes) -- CEV
- if (view_offset_finished > time)
- {
- if (view_offset_old != e.view_ofs_z)
- {
- local float z = 1 -
- (view_offset_finished - time) /
- PLAYER_CROUCH_SMOOTH;
- view_offset = lerp_hermite (view_offset_old,
- e.view_ofs_z, z);
- }
- }
- else
- {
- if (view_offset_old != e.view_ofs_z)
- view_offset_old = e.view_ofs_z;
- view_offset = e.view_ofs_z;
- }
-
- view_step_oldz = e.origin_z;
view_origin = e.origin;

- // now do the adjustment -- CEV
- if (view_step_time - time > 0)
- view_origin_z -= (view_step_time - time) *
- view_step_adjust * view_step;
+ // view_origin: head bob, crouch smoothing, steps -- CEV
+ PLAYER_VIEW_BOB (e)
+ PLAYER_VIEW_CROUCH (e)
+ PLAYER_VIEW_STEPS (e)

- view_origin_z += view_offset;
- };
-
- //--------------------------------------------------------------
- // was Pred_RunMovement in CSQCTest cs/prediction.qc
- //--------------------------------------------------------------
- void(entity e, float endframe) player_prediction =
- {
- if (servercommandframe >= e.commandframe + 63)
- {
- // we're meant to be updating the player faster than
- // this. hopefully its just that we're throttled...
-
- // you can comment out this block and the player will
- // continue to be predicted locally. But its best to
- // freeze them
- // dprint ("player_prediction: slow update\n");
- e.commandframe = servercommandframe - 63;
- return;
- }
-
- if (getstatf(STAT_HEALTH) <= 0)
- {
- // dead, so don't run prediction. :D
- e.commandframe = clientcommandframe;
- if (getinputstate(e.commandframe - 1) == FALSE)
- {
- dprint ("player_prediction: no-op?\n");
- // TODO CEV no-op ?
- }
- return;
- }
-
- for (float i = e.commandframe + 1; i <= endframe; i++)
- {
- local float f = getinputstate (i);
-
- if (f == FALSE)
- // no input from client
- break;
-
- if (input_timelength <= 0)
- break;
-
- /*
- 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;
+ // view_angles: punchangle, sideways view roll -- CEV
+ makevectors (view_angles);
+ PLAYER_VIEW_PUNCHANGLE ()
+ PLAYER_VIEW_ROLL (e)
};

//--------------------------------------------------------------
void(entity e) player_prediction_postframe =
{
- player_prediction_reset (e);
+ PLAYER_PREDICTION_RESET (e)
setsize (e, e.mins, e.maxs);
setorigin (e, e.origin);
};
@@ -1773,7 +1956,7 @@ $frame axattd1 axattd2 axattd3 axattd4 axattd5 axattd6
// no footsteps below PM_WALKSPEED * 0.9
return;

- if (self.speed < PM_RUNSPEED * 0.9)
+ if (self.speed < PM_MAXSPEED * 0.9)
if (self.frame != $rockrun2 && self.frame != $axrun2)
// half the footsteps when walking
return;
@@ -2666,9 +2849,11 @@ $frame axattd1 axattd2 axattd3 axattd4 axattd5 axattd6
/*
l = normalize (l);
*/
-
+
+ /*
dprint (sprintf("player_postthink: light %v, "
"level %g\n", l, vlen(l)));
+ */
}
}

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 8c16aa5..d89b161 100644
--- a/qc/pmove.qc
+++ b/qc/pmove.qc
@@ -38,16 +38,20 @@ vector input_movevalues; // movement requested by client

#if defined(CSQC) || defined(SSQC)
// acceleration & friction
+// 10 - 6.5265 = 3.4375
+// 3.4375 / 2.0 = 1.71875
+// 10 - 1.71875 = 8.28125
const float PM_AIRACCELY = 70.0f; // (320 / 30) * 6.5625; 106.666 in Q1
-const float PM_AIRACCELXY = 1.0f; // for Q3 strafejumping; 1.0 in Q3
-const float PM_AIRACCELXFWD = 1.0f; // 1 feels close to Q3 / CPM
+const float PM_AIRACCELXY = 1.0f; // for Q3 strafejumping; 1.0 in Q3; 0.85
+const float PM_AIRACCELXFWD = 1.0f; // 1 feels close to Q3 / CPM; 0.85f
const float PM_AIRACCELXBACK = 2.5f; // Air stop speed in Q3? 5.0f?
const float PM_AIRACCELBASE = 32.0f; //
const float PM_AIRACCELTURN = 250.0f; // affects +fwd turning radius; 150.0f
const float PM_GROUNDACCEL = 10.0f; // 10 is Q1 & VQ3, 15 is CPM
const float PM_GROUNDFRICTION = 6.0f; // 4 for Q1, 6 for Q3, 8 for (old?) CPM
+const float PM_SLICKACCEL = 10.0f; // accel while on ice / slick floor
const float PM_SLIDEACCELY = 70.0f; //
-const float PM_SLIDEACCELXY = 1.0f; // crouchslide accel
+const float PM_SLIDEACCELXY = 1.0f; // crouchslide accel; 0.85f
const float PM_SLIDEFRICTION = 0.25f; // crouchslide friction; 1.0?
const float PM_SURFACCELY = 106.666f; // (320 / 30) * 10.0
const float PM_SURFACCELXY = 1.0f; //
@@ -55,16 +59,12 @@ const float PM_WATERACCEL = 10.0f; // water acceleration
const float PM_WATERFRICTION = 4.0f; // friction in water

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

@@ -97,11 +97,11 @@ const float PM_BTN_WALK = INPUT_BUTTON7;// walk key

// misc
const float PM_CLIMBSCALE = 0.75; // scale XY vel by this while climbing
-const float PM_EPSILONF = 0.125f; // 1.0 / 8.0; minimum float precision
-const float PM_MAX_CLIP_PLANES = 3; // counting ground
-const float PM_MAXVELOCITY = 4095; // 32768 / 8.0; vel networked as short
+const float PM_FLMIN = 0.125f; // 1.0 / 8.0; minimum float precision
+const float PM_MAXVELOCITY = 4095.0f; // 32768 / 8.0; vel networked as short
const float PM_OVERCLIP = 1.0f; // Q3 OVERCLIP is 1.001f, Q1 1.0f
const float PM_STEPHEIGHT = 18.0f; // 18 for Q1, 22 for later games?
+const float PM_PLANE_INTERACT = 0.0f; //
const float PM_PLANE_FLAT = 1.0f; // flat horizontal
const float PM_PLANE_GROUND = 0.7f; // above this is ONGROUND
const float PM_PLANE_VERTICAL = 0.0f; // straight up vertical
@@ -129,16 +129,10 @@ 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_MIDMOVE = -2; // called during DanceMove
-const float PMG_TRACEGROUND = -3; // run a trace looking for ground
-const float PMG_NOGROUND = -4; // skip checks and clear ground flags
-
// pmove_flags is used by the engine; FTE defines two constants:
// PMF_JUMP_HELD = 1, PMF_LADDER = 2. So those two constants should
// be first (and in that order) in our enum below. -- CEV
-// this is currently 18 flags; max flags for a float is 23 -- CEV
+// this is currently 19 flags; max flags for a float is 23 -- CEV
enumflags
{
PMF_JUMP_HELD, // player is holding the jump key
@@ -147,6 +141,7 @@ enumflags
PMF_ONRAMP, // entity is on a ramp
PMF_ONSLOPE, // entity is on a steep slope
PMF_ONSLICK, // entity is on a slick (icy) surface
+ PMF_ONMOVINGENT, // entity is standing on a networked ent
PMF_CROUCH_HELD, // player is holding the crouch key
PMF_CROUCHED, // entity is crouching
PMF_CROUCHSLIDE, // entity is crouch sliding
@@ -170,7 +165,7 @@ const float PM_ONSLOPEFLAGS = PMF_ONSLICK | PMF_ONRAMP | PMF_ONGROUND;

// remove these flags when not on ground -- CEV
const float PM_NOGROUNDFLAGS = PMF_ONGROUND | PMF_ONRAMP | PMF_ONSLICK |
- PMF_ONSLOPE;
+ PMF_ONSLOPE | PMF_ONMOVINGENT;

// don't transmit these flags from server to client -- CEV
const float PM_SLIDEFLAGS = PMF_SLIDE_STEP;
@@ -186,14 +181,19 @@ float(float maxspeed, float a, float c, float t) PM_MaxCircleGroundSpeed;
#endif

#if defined(CSQC) || defined (SSQC)
-static void(entity ent) PM_DoTouch;
-vector(vector v) PM_TruncateVectorToEighth;
-void() PM_CheckVelocity;
+// PM_TRUNCATEVECTORTOEIGTH(vec)
+// PM_CHECKVELOCITY(vel)
float() PM_Nudge;
-void(float pmg_flag) PM_SetOnGround;
-void() PM_SetNoClipFlags;
-void() PM_CategorizePosition;
-void() PM_DanceMove;
+// PM_SETONGROUND_NOGROUND()
+// PM_SETONGROUND_TRACEGROUND()
+// PM_SETONGROUND()
+// PM_DANCEMOVE_ADDTOUCH(ent)
+// PM_DANCEMOVE_DOTOUCH(ent)
+// PM_DANCEMOVE_AXIALNUDGE(plane)
+// PM_DANCEMOVE_CLIP_INNER(v, pl_a, pl_b, pl_c, k)
+// PM_DANCEMOVE_CLIP(v, pl_i, pl_j, pl_k, k)
+// PM_DANCEMOVE_GROUNDIMPACT()
+// PM_DANCEMOVE(end, start_vel, i, j, k)
void() PM_CrouchStart;
void() PM_CrouchStop;
void() PM_CrouchSlideStart;
@@ -202,13 +202,21 @@ void() PM_Jump;
void() PM_WallClimb;
void() PM_WallJump;
void() PM_WallJumpCheck;
-void(vector wishvel, float scale, float move_time) PM_NoClipAccelerate;
-void(vector wishvel, float move_time) PM_SwimPreMove;
-void(vector wishvel, float move_time) PM_SwimAccelerate;
-void(vector wishvel, float move_time) PM_WalkPreMove;
-void(vector wishvel, float move_time) PM_WalkAccelerate;
-void(float move_time) PM_ManageTimer;
-void(entity e) PM_Move;
+// PM_FRICTION(speed1, temp, friction, move_time)
+// PM_ACCELERATE(dir, wish, speed1, newspeed, accel, move_time)
+// PM_AIRCONTROL(dir, wish, cur, new, zspeed, dot, move_time)
+// PM_MOVE_MOVETYPES_CATEGORIZEPOSITION()
+// PM_MOVE_MOVETYPES_SETNOCLIPFLAGS()
+// PM_MOVE_MOVETYPES_NOCLIPACCELERATE(scale, move_time)
+// PM_MOVE_MOVETYPES_SWIMPREMOVE_SSQC()
+// PM_MOVE_MOVETYPES_SWIMPREMOVE(start, end, move_time)
+// PM_MOVE_MOVETYPES_SWIMACCELERATE(move_time)
+// PM_MOVE_MOVETYPES_WALKPREMOVE()
+// PM_MOVE_MOVETYPES_WALKACCELERATE(move_time)
+// PM_MOVE_MOVETYPES_MANAGETIMER(adjust_time)
+// PM_MOVE_PRE()
+// PM_MOVE_MOVETYPES()
+// PM_MOVE_POST()
#endif

//------------------------------------------------------------------------------
@@ -254,50 +262,24 @@ float(float maxspeed, float a, float f, float t) PM_MaxCircleGroundSpeed =

#if defined(CSQC) || defined (SSQC)
//----------------------------------------------------------------------
-// PM_DoTouch
+// PM_TRUNCATEVECTORTOEIGTH - truncate a vector to 0.125 precision -- CEV
//----------------------------------------------------------------------
-static void(entity ent) PM_DoTouch =
-{
- if (ent.touch != __NULL__)
- {
- 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 0.125 precision -- CEV
-//----------------------------------------------------------------------
-vector(vector v) PM_TruncateVectorToEighth =
-{
- v_x = (floor(v_x * 8 + (1.0 / 16))) * PM_EPSILONF;
- v_y = (floor(v_y * 8 + (1.0 / 16))) * PM_EPSILONF;
- v_z = (floor(v_z * 8 + (1.0 / 16))) * PM_EPSILONF;
-
- return v;
-};
+#define PM_TRUNCATEVECTORTOEIGTH(vec) \
+{ \
+ vec.x = (floor(vec.x * 8 + (1.0 / 16))) * PM_FLMIN; \
+ vec.y = (floor(vec.y * 8 + (1.0 / 16))) * PM_FLMIN; \
+ vec.z = (floor(vec.z * 8 + (1.0 / 16))) * PM_FLMIN; \
+}

//----------------------------------------------------------------------
-// PM_CheckVelocity - bound self.velocity to server maximums -- CEV
+// PM_CHECKVELOCITY - bound self.velocity to server maximums -- CEV
//----------------------------------------------------------------------
-void() PM_CheckVelocity =
-{
- self.velocity_x = bound (-PM_MAXVELOCITY, self.velocity_x,
- PM_MAXVELOCITY);
- self.velocity_y = bound (-PM_MAXVELOCITY, self.velocity_y,
- PM_MAXVELOCITY);
- self.velocity_z = bound (-PM_MAXVELOCITY, self.velocity_z,
- PM_MAXVELOCITY);
-};
+#define PM_CHECKVELOCITY(vel) \
+{ \
+ vel.x = bound (-PM_MAXVELOCITY, vel.x, PM_MAXVELOCITY); \
+ vel.y = bound (-PM_MAXVELOCITY, vel.y, PM_MAXVELOCITY); \
+ vel.z = bound (-PM_MAXVELOCITY, vel.z, PM_MAXVELOCITY); \
+}

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

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

test = org;

@@ -345,199 +327,239 @@ float() PM_Nudge =
};

//----------------------------------------------------------------------
-// PM_SetOnGround -- manage ground flags and fields
-// arguments in order are: ground entity, ground plane, ground trace
-// end position, ground entity num (or PMG_* flag if negative) -- CEV
-//----------------------------------------------------------------------
-void(float pmg_flag) PM_SetOnGround =
-{
- // flagged to skip checks and clear ONGROUND -- CEV
- if (pmg_flag == PMG_NOGROUND)
- goto PM_SetOnGround_NoGround;
-
- if (pmg_flag == PMG_TRACEGROUND)
- {
- // do a trace to check for ground -- CEV
- tracebox (self.origin, self.mins, self.maxs,
- self.origin - '0 0 0.25', PM_MOVEFLAGS, self);
- }
-
- // onground if we hit something & it faces upwards
- if (trace_fraction < 1.0f)
- {
- if (trace_plane_normal_z > PM_PLANE_GROUND)
- {
- // on ground -- CEV
-
- // 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.pm_flags & PMF_ONGROUND)) {
- if (self.pm_flags & PMF_CROUCH_HELD) {
- if (!(self.pm_flags & PMF_CROUCHSLIDE)) {
- if (self.conlevel < WATERLEVEL_WAIST) {
- if (self.speed > PM_RUNSPEED)
- {
- PM_CrouchSlideStart ();
- } } } } }
-
- // set groundentity and groundnormal -- CEV
- self.groundentity = trace_ent;
- self.groundnormal = trace_plane_normal;
-
- // now manage flags -- CEV
- if (pmg_flag != PMG_MIDMOVE)
- {
- self.flags |= FL_ONGROUND;
- self.pm_flags |= PMF_ONGROUND;
- }
-
- if (self.groundnormal_z < PM_PLANE_FLAT)
- self.pm_flags |= PMF_ONRAMP;
- else if (self.pm_flags & PMF_ONRAMP)
- self.pm_flags &= ~PMF_ONRAMP;
-
- if (trace_surfaceflagsf & Q3SURFACEFLAG_SLICK)
- // on a slick/icy surface -- CEV
- self.pm_flags |= PMF_ONSLICK;
+#define PM_SETONGROUND_NOGROUND() \
+{ \
+ /* not on ground, clear pmove flags & fields -- CEV */ \
+ self.groundentity = __NULL__; \
+ self.groundnormal = '0 0 0'; \
+ self.flags &= ~FL_ONGROUND; \
+ self.pm_flags = self.pm_flags - (self.pm_flags & PM_NOGROUNDFLAGS); \
+ /* don't crouchslide in air -- CEV */ \
+ if (self.pm_flags & PMF_CROUCHSLIDE) \
+ { \
+ if (self.pm_timer < 0) \
+ self.pm_timer = 0; \
+ PM_CrouchSlideStop (); \
+ } \
+}

- self.pm_flags = self.pm_flags -
- (self.pm_flags & PM_ONGROUNDFLAGS);
- }
- else if (trace_plane_normal_z > PM_PLANE_VERTICAL)
- {
- // on a steep slope
-
- // set groundentity and groundnormal -- CEV
- self.groundentity = __NULL__;
- self.groundnormal = '0 0 0';
-
- // now do flags -- CEV
- self.flags &= ~FL_ONGROUND;
- self.pm_flags |= PMF_ONSLOPE;
- self.pm_flags = self.pm_flags -
- (self.pm_flags & PM_ONSLOPEFLAGS);
- self.pm_timer = 0;
-
- // don't crouchslide on a slope -- CEV
- if (self.pm_flags & PMF_CROUCHSLIDE)
- PM_CrouchSlideStop ();
- }
- else
- {
- // we probably shouldn't end up here -- CEV
- goto PM_SetOnGround_NoGround;
- }
+//----------------------------------------------------------------------
+#define PM_SETONGROUND_TRACEGROUND() \
+{ \
+ /* do a trace to check for ground -- CEV */ \
+ tracebox (self.origin, self.mins, self.maxs, \
+ self.origin - '0 0 0.25', PM_MOVEFLAGS, self); \
+}

- #ifdef CSQC
- // don't smooth out steps when on a network ent -- CEV
- if (trace_networkentity > 0 || trace_ent.velocity != '0 0 0')
- view_step_disable = TRUE;
- else if (view_step_disable)
- view_step_disable = FALSE;
- #endif
- }
- else
- {
- // not on ground, clear pmove flags & fields -- CEV
- PM_SetOnGround_NoGround:
- self.groundentity = __NULL__;
- self.groundnormal = '0 0 0';
- self.flags &= ~FL_ONGROUND;
- self.pm_flags = self.pm_flags -
- (self.pm_flags & PM_NOGROUNDFLAGS);
-
- // don't crouchslide in air -- CEV
- if (self.pm_flags & PMF_CROUCHSLIDE)
- {
- if (self.pm_timer < 0)
- self.pm_timer = 0;
- PM_CrouchSlideStop ();
- }
+//----------------------------------------------------------------------
+// PM_SETONGROUND -- manage ground flags and fields -- CEV
+//----------------------------------------------------------------------
+#define PM_SETONGROUND() \
+{ \
+ /* onground if we hit something & it faces upwards */ \
+ if (trace_fraction < 1.0f) \
+ { \
+ if (trace_plane_normal.z > PM_PLANE_GROUND) \
+ { \
+ /* on ground -- CEV */ \
+ /* 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.pm_flags & PMF_ONGROUND)) { \
+ if (self.pm_flags & PMF_CROUCH_HELD) { \
+ if (!(self.pm_flags & PMF_CROUCHSLIDE)) { \
+ if (self.conlevel < WATERLEVEL_WAIST) { \
+ if (self.speed > PM_MAXSPEED) \
+ { \
+ PM_CrouchSlideStart (); \
+ } } } } } \
+ /* set groundentity and groundnormal -- CEV */ \
+ self.groundentity = trace_ent; \
+ self.groundnormal = trace_plane_normal; \
+ /* now manage flags -- CEV */ \
+ if (!(self.pm_flags & PMF_SLIDE_STEP)) \
+ { \
+ self.flags |= FL_ONGROUND; \
+ self.pm_flags |= PMF_ONGROUND; \
+ } \
+ if (self.groundnormal.z < PM_PLANE_FLAT) \
+ self.pm_flags |= PMF_ONRAMP; \
+ else if (self.pm_flags & PMF_ONRAMP) \
+ self.pm_flags &= ~PMF_ONRAMP; \
+ if (trace_surfaceflagsf & Q3SURFACEFLAG_SLICK) \
+ /* on a slick/icy surface -- CEV */ \
+ self.pm_flags |= PMF_ONSLICK; \
+ self.pm_flags = self.pm_flags - \
+ (self.pm_flags & PM_ONGROUNDFLAGS); \
+ } \
+ else if (trace_plane_normal.z > PM_PLANE_VERTICAL) \
+ { \
+ /* on a steep slope */ \
+ /* set groundentity and groundnormal -- CEV */ \
+ self.groundentity = __NULL__; \
+ self.groundnormal = '0 0 0'; \
+ /* now do flags -- CEV */ \
+ self.flags &= ~FL_ONGROUND; \
+ self.pm_flags |= PMF_ONSLOPE; \
+ self.pm_flags = self.pm_flags - \
+ (self.pm_flags & PM_ONSLOPEFLAGS); \
+ self.pm_timer = 0; \
+ /* don't crouchslide on a slope -- CEV */ \
+ if (self.pm_flags & PMF_CROUCHSLIDE) \
+ PM_CrouchSlideStop (); \
+ } \
+ else \
+ { \
+ /* we probably shouldn't end up here -- CEV */ \
+ PM_SETONGROUND_NOGROUND () \
+ } \
+ /* flag when standing on a vertically moving ent -- CEV */ \
+ if (trace_networkentity || trace_ent.velocity.z != 0) \
+ self.pm_flags |= PMF_ONMOVINGENT; \
+ else if (self.pm_flags & PMF_ONMOVINGENT) \
+ self.pm_flags &= ~PMF_ONMOVINGENT; \
+ } \
+ else \
+ { \
+ PM_SETONGROUND_NOGROUND () \
+ } \
+}

- #ifdef CSQC
- if (view_step_disable)
- view_step_disable = FALSE;
- #endif
- }
-};
+//----------------------------------------------------------------------
+#define PM_DANCEMOVE_ADDTOUCH(ent) \
+{ \
+ if (ent) \
+ { \
+ if (ent.touch) \
+ { \
+ if (ent != touched_ent3) { \
+ if (ent != touched_ent2) { \
+ if (ent != touched_ent1) \
+ { \
+ touched_ent3 = touched_ent2; \
+ touched_ent2 = touched_ent1; \
+ touched_ent1 = ent; \
+ } } } \
+ } \
+ } \
+}

//----------------------------------------------------------------------
-void() PM_SetNoClipFlags =
-{
- // noclip is never on ground
- if (self.groundentity != __NULL__)
- self.groundentity = __NULL__;
- if (self.groundnormal != '0 0 0')
- self.groundnormal = '0 0 0';
- if (self.pm_flags & PMF_DOUBLEJUMPED)
- self.pm_flags &= ~PMF_DOUBLEJUMPED;
- if (self.pm_flags & PMF_WALLJUMPED)
- self.pm_flags &= ~PMF_WALLJUMPED;
- if (self.pm_flags & PMF_ONGROUND)
- self.pm_flags &= ~PMF_ONGROUND;
- if (self.flags & FL_ONGROUND)
- self.flags &= ~FL_ONGROUND;
- if (self.pm_flags & PMF_PUSHED)
- self.pm_flags &= ~PMF_PUSHED;
- if (self.pm_flags & PMF_CLIMB)
- self.pm_flags &= ~PMF_CLIMB;
+#define PM_DANCEMOVE_DOTOUCH(ent) \
+{ \
+ if (ent) \
+ { \
+ if (ent.touch != __NULL__) \
+ { \
+ if (ent.touch != sub_null) \
+ { \
+ stemp = self; \
+ otemp = other; \
+ other = self; \
+ self = ent; \
+ self.touch (); \
+ self = stemp; \
+ other = otemp; \
+ } \
+ } \
+ } \
+}

- self.pm_timer = 0;
-};
+//----------------------------------------------------------------------
+#define PM_DANCEMOVE_AXIALNUDGE(plane) \
+{ \
+ if (plane) \
+ { \
+ if (trace_plane_normal * plane > 0.99f) \
+ { \
+ self.velocity += trace_plane_normal; \
+ } \
+ } \
+}

//----------------------------------------------------------------------
-// PM_CategorizePosition
-// Based on similarly-named function in the GPL2 purecsqc pmove.qc
+// PM_DANCEMOVE_CLIP_INNER
+// This macro is meant to be called from PM_DANCEMOVE_CLIP -- CEV
//----------------------------------------------------------------------
-void() PM_CategorizePosition =
-{
- if (self.velocity_z > 180)
- {
- // if Z velocity is greater than 180 and we're not on a
- // ramp or a steep slope then assume we're not onground
- // (an optimization from Warsow / Warfork) -- CEV
- if (self.pm_flags & PMF_ONRAMP)
- PM_SetOnGround (PMG_TRACEGROUND);
- else if (self.pm_flags & PMF_ONSLOPE)
- PM_SetOnGround (PMG_TRACEGROUND);
- else
- PM_SetOnGround (PMG_NOGROUND);
- }
- else
- {
- // look for ground, manage flags & fields -- CEV
- // setting onground here before the acceleration functions
- // turns out to be faster (in my testing) than relying on
- // DanceMove to correctly track ground state -- CEV
- PM_SetOnGround (PMG_TRACEGROUND);
- }
+#define PM_DANCEMOVE_CLIP_INNER(v, pl_a, pl_b, pl_c, k) \
+{ \
+ /* test if plane_b exists, is not identical to plane_a, and
+ * that velocity interacts with it -- CEV */ \
+ if (pl_b) { \
+ if (pl_b != pl_a) \
+ { \
+ k = self.velocity * pl_b; \
+ if (k < PM_PLANE_INTERACT) \
+ { \
+ /* clip to plane_b (the second plane) -- CEV */ \
+ self.velocity -= pl_b * k; \
+ /* test if move goes back into the first plane */ \
+ if (self.velocity * pl_a < 0) \
+ { \
+ /* slide along the crease -- CEV */ \
+ /* ("><" is crossproduct) -- CEV */ \
+ v = pl_a >< pl_b; \
+ v = normalize (v); \
+ self.velocity = v * (v * self.velocity); \
+ /* check if we interact with a 3rd plane */ \
+ if (pl_c) { \
+ if (self.velocity * pl_c < 0) \
+ { \
+ /* stop when 3 planes interact */ \
+ self.velocity = '0 0 0'; \
+ break; \
+ } } \
+ } \
+ } \
+ } } \
+}

- // set waterlevel and watertype -- CEV
- base_entity_positioncontents (self);
+//----------------------------------------------------------------------
+// PM_DANCEMOVE_CLIP
+// This macro is meant to be called from PM_DANCEMOVE -- CEV
+//----------------------------------------------------------------------
+#define PM_DANCEMOVE_CLIP(v, pl_i, pl_j, pl_k, k) \
+{ \
+ /* test if plane_i exists & if velocity interacts with it -- CEV */ \
+ if (pl_i) \
+ { \
+ k = self.velocity * pl_i; \
+ if (k < PM_PLANE_INTERACT) \
+ { \
+ /* clip to the plane -- CEV */ \
+ self.velocity -= pl_i * k; \
+ /* check for 2nd and 3rd plane interactions -- CEV */ \
+ PM_DANCEMOVE_CLIP_INNER (v, pl_i, pl_j, pl_k, k) \
+ PM_DANCEMOVE_CLIP_INNER (v, pl_i, pl_k, pl_j, k) \
+ } \
+ } \
+}

- // don't crouchslide in water -- CEV
- if (self.pm_flags & PMF_CROUCHSLIDE) {
- if (self.pm_flags & PMF_ONGROUND) {
- if (self.conlevel >= WATERLEVEL_WAIST)
- {
- if (self.pm_timer < 0)
- self.pm_timer = 0;
- PM_CrouchSlideStop ();
- } } }
+//----------------------------------------------------------------------
+// PM_DANCEMOVE_GROUNDIMPACT
+// This macro is meant to be called from PM_DANCEMOVE -- CEV
+//----------------------------------------------------------------------
+#ifdef SSQC
+#define PM_DANCEMOVE_GROUNDIMPACT() \
+{ \
+ /* impact info (see player_postthink) -- CEV */ \
+ if (!(self.pm_flags & PMF_ONGROUND)) { \
+ if (self.velocity.z < self.jump_flag) \
+ { \
+ self.jump_flag = self.velocity.z; \
+ } } \
+}
+#endif

- // can't be waterjumping if we're on ground
- if (self.pm_flags & PMF_WATERJUMPED) {
- if (self.conlevel == WATERLEVEL_NONE || self.pm_flags & PMF_ONGROUND)
- {
- self.pm_flags &= ~PMF_WATERJUMPED;
- self.flags &= ~FL_WATERJUMP;
- } }
-};
+#ifdef CSQC
+#define PM_DANCEMOVE_GROUNDIMPACT() \
+{ \
+}
+#endif

//----------------------------------------------------------------------
-// PM_DanceMove
+// PM_DANCEMOVE
//
// Updates origin according to velocity, moves the player through the world.
// Same as Q3 SlideMove and Q1 FlyMove. This version handles steps, applies
@@ -549,359 +571,310 @@ void() PM_CategorizePosition =
// in turn appears to be based on a similar function in the CSQCTest code
// that comes with FTEQW. -- CEV
//----------------------------------------------------------------------
-void() PM_DanceMove =
-{
- local float grav = 0;
-
- if (self.conlevel < WATERLEVEL_WAIST) {
- if (!(self.pm_flags & PMF_ONLADDER)) {
- if (!(self.pm_flags & PMF_ONGROUND) || self.pm_flags & PMF_ONRAMP)
- {
- if (self.gravity)
- grav = self.gravity;
- else
- grav = 1.0;
- // world_gravity is set in worldspawn() -- CEV
- grav *= world_gravity * input_timelength;
- // Half now, half later. Apparently affects framerate
- // dependence. -- CEV
- self.velocity_z -= grav * 0.5f;
- } } }
-
- if (self.velocity == '0 0 0')
- // we aren't moving so skip to clearing flags -- CEV
- goto PM_DanceMove_ClearFlags;
-
- // declare and initialize variables -- CEV
- local vector end, plane1, plane2, start_vel;
- local float i, j, k, time_left;
- local entity touched_ent;
- local vector *jp = __NULL__;
-
- end = plane1 = plane2 = '0 0 0';
- i = j = k = 0;
- time_left = input_timelength;
- start_vel = self.velocity;
-
- // 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);
- tracebox (self.origin, self.mins, self.maxs, end,
- PM_MOVEFLAGS, self);
-
- if (trace_allsolid)
- {
- // self is in something else; attempt to nudge out
- if (PM_Nudge())
- continue;
- else
- setorigin (self, self.oldorigin);
-
- // 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!");
- #elif defined(SSQC)
- dprint ("PM_DanceMove: server player entity stuck!");
- #endif
- self.velocity_z = 0;
- dprint (sprintf(" timestamp %g\n", time));
- break;
- }
-
- // accept the move -- CEV
- self.origin = trace_endpos;
-
- if (trace_fraction >= 1.0f)
- // no obstructions, made the whole move -- CEV
- break;
-
- // save the trace ent for later then reduce time_left -- CEV
- touched_ent = trace_ent;
- time_left -= time_left * trace_fraction;
-
- // 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.pm_flags & PMF_SLIDE_STEP) {
- if (time_left > 0) {
- if (trace_plane_normal_z == PM_PLANE_VERTICAL)
- {
- // store the entity and plane normal from above in
- // case we need to reject the step attempt -- CEV
- local vector first_plane = trace_plane_normal;
- local entity first_ent = trace_ent;
- local float first_frac = trace_fraction;
- #ifdef CSQC
- local float first_net = trace_networkentity;
- #endif
- j = time_left;
-
- // first: move up
- trace_endpos_z += PM_STEPHEIGHT;
- tracebox (self.origin, self.mins, self.maxs,
- trace_endpos, PM_MOVEFLAGS, self);
-
- if (trace_allsolid)
- goto PM_DanceMove_RejectStep;
-
- local vector roof_plane = trace_plane_normal;
-
- if (trace_fraction < 1.0f)
- if (trace_ent.touch)
- touched_ent = trace_ent;
-
- // second: move forward
- k = 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);
-
- if (trace_allsolid)
- goto PM_DanceMove_RejectStep;
-
- // if we hit the same plane we're trying to step over
- // and we made no progress in the move then reject
- // the step attempt -- CEV
- if (trace_plane_normal == first_plane) {
- if (fabs(self.origin_x - trace_endpos_x) < PM_EPSILONF)
- if (fabs(self.origin_y - trace_endpos_y) < PM_EPSILONF)
- goto PM_DanceMove_RejectStep;
- }
-
- if (trace_fraction < 1.0f)
- if (trace_ent.touch)
- touched_ent = trace_ent;
-
- local vector fwd_plane = trace_plane_normal;
- j -= j * trace_fraction;
-
- // third: move down
- end = trace_endpos;
- end_z -= k + 1;
- tracebox (trace_endpos, self.mins, self.maxs, end,
- PM_MOVEFLAGS, self);
-
- // When airborne and directing momentum into the
- // intersection of a step and a wall the down move
- // will sometimes hit nothing (trace_fraction 1
- // plane normal '0 0 0'). We *do not* want to reject
- // the step when this happens. -- CEV
- if (trace_fraction == 1.0f)
- {
- if (trace_plane_normal_z != 0)
- goto PM_DanceMove_RejectStep;
- }
- else if (trace_plane_normal_z <= PM_PLANE_GROUND)
- {
- // this is the expected and regular
- // not-good-ground step rejection -- CEV
- goto PM_DanceMove_RejectStep;
- }
-
- if (trace_allsolid == FALSE)
- {
- // accept the stepped move. update time_left,
- // origin, touched_ent, store any unique
- // planes, then update flags -- CEV
- time_left = j;
- self.origin = trace_endpos;
-
- if (trace_ent.touch)
- touched_ent = trace_ent;
-
- if (roof_plane != trace_plane_normal) {
- if (roof_plane != plane1) {
- if (roof_plane != plane2)
- {
- plane2 = plane1;
- plane1 = roof_plane;
- } } }
-
- if (fwd_plane != trace_plane_normal) {
- if (fwd_plane != plane1) {
- if (fwd_plane != plane2)
- {
- plane2 = plane1;
- plane1 = fwd_plane;
- } } }
-
- self.pm_flags |= PMF_STEPPED;
-
- if (!(self.pm_flags & PMF_ONGROUND))
- // this is nuts. for stairjumps. -- CEV
- if (start_vel_z <= 0)
- self.pm_flags |= PMF_AIRSTEPPED;
- }
- else
- {
- // discard the step attempt -- CEV
- PM_DanceMove_RejectStep:
- trace_plane_normal = first_plane;
- touched_ent = trace_ent = first_ent;
- trace_fraction = first_frac;
- #ifdef CSQC
- trace_networkentity = first_net;
- #endif
- }
- } } }
-
- // we've found a ground plane so call PM_SetOnGround -- CEV
- if (trace_plane_normal_z > PM_PLANE_GROUND)
- {
- #ifdef SSQC
- // impact info (see player_postthink) -- CEV
- if (!(self.pm_flags & PMF_ONGROUND)) {
- if (self.velocity_z < self.jump_flag)
- {
- self.jump_flag = self.velocity_z;
- } }
- #endif
-
- PM_SetOnGround (PMG_MIDMOVE);
- }
-
- // clip to the plane if velocity interacts with it -- CEV
- k = self.velocity * trace_plane_normal;
- if (k < 0)
- self.velocity -= trace_plane_normal * k;
-
- // 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++)
- {
- // no arrays were harmed in this loop -- CEV
- if (j == 0) { jp = &self.groundnormal; }
- else if (j == 1) { jp = &plane1; }
- else if (j == 2) { jp = &plane2; }
-
- // test if plane interacts & is not current plane
- if (*jp == trace_plane_normal) { continue; }
- k = self.velocity * *jp;
- if (k >= 0) { continue; }
-
- // clip to the plane -- CEV
- self.velocity -= *jp * k;
-
- // test if move goes back into the first plane -- CEV
- if (self.velocity * trace_plane_normal >= 0)
- continue;
-
- // slide along crease ("><" is crossproduct) -- CEV
- end = trace_plane_normal >< *jp;
- end = normalize (end);
- self.velocity = end * (end * self.velocity);
-
- // see if we enter a third plane -- CEV
- for (k = 0; k < PM_MAX_CLIP_PLANES; k++)
- {
- if (k == j) { continue; }
-
- if (k == 0) { jp = &self.groundnormal; }
- else if (k == 1) { jp = &plane1; }
- else if (k == 2) { jp = &plane2; }
-
- if (*jp == trace_plane_normal) { continue; }
- if (self.velocity * *jp >= 0) { continue; }
-
- // stop when 3 planes interact -- CEV
- self.velocity = '0 0 0';
- break;
- }
-
- if (self.velocity == '0 0 0') { break; }
- }
-
- // store current plane and plane1 for the next pass -- CEV
- if (trace_plane_normal != self.groundnormal)
- {
- plane2 = plane1;
- plane1 = trace_plane_normal;
- }
-
- // touch last in case doing so changes trace_plane_normal -- CEV
- PM_DoTouch (touched_ent);
-
- // stop if we've turned against original velocity -- CEV
- if (self.velocity * start_vel <= 0)
- self.velocity = '0 0 0';
-
- // stop the loop if velocity is now zero -- CEV
- if (self.velocity == '0 0 0')
- break;
- }
-
- // if we're not onground and the timer is greater than
- // PM_WALLCLIP_WINDOW (within 250ms of pressing jump)
- // then restore velocity (to skim past walls) -- CEV
- if (!(self.pm_flags & PMF_ONGROUND)) {
- if (self.pm_timer > PM_WALLCLIP_WINDOW)
- {
- j = start_vel_z;
- k = self.velocity_z;
- self.velocity = start_vel;
- // need the min of vel_z so headbump doublejumps work -- CEV
- if (fabs(j) > fabs(k))
- self.velocity_z = k;
- else
- self.velocity_z = j;
- } }
-
- // final gravity check here -- CEV
- if (grav)
- self.velocity_z -= grav * 0.5f;
-
- // clip to the ground plane under certain complex conditions
- // (this is done to recreate / simulate Q3/CPM stair behavior) -- CEV
- if (self.pm_timer > 0) {
- if (self.velocity_z) {
- if (self.groundnormal_z > PM_PLANE_GROUND) {
- if (!(self.pm_flags & PMF_CROUCH_HELD)) {
- if (!(self.pm_flags & PMF_WALK_HELD)) {
- if (!(self.pm_flags & PMF_DOUBLEJUMPED))
- {
- #if 0
- dprint (sprintf("PM_DanceMove: glue %f\n", self.origin_z));
- #endif
-
- k = self.velocity * self.groundnormal;
- self.velocity -= self.groundnormal * k;
- } } } } } }
-
- #if 0
+#define PM_DANCEMOVE(end, start_vel, i, j, k) \
+{ \
+ local float grav = 0; \
+ if (self.conlevel < WATERLEVEL_WAIST) { \
+ if (!(self.pm_flags & PMF_ONLADDER)) { \
+ if (!(self.pm_flags & PMF_ONGROUND) || self.pm_flags & PMF_ONRAMP) \
+ { \
+ if (self.gravity) \
+ grav = self.gravity; \
+ else \
+ grav = 1.0; \
+ /* world_gravity is set in worldspawn() -- CEV */ \
+ grav *= world_gravity * input_timelength; \
+ /* Half now, half later. Apparently affects framerate
+ * dependence. -- CEV */ \
+ self.velocity.z -= grav * 0.5f; \
+ } } } \
+ if (self.velocity == '0 0 0') \
+ /* we aren't moving so skip to clearing flags -- CEV */ \
+ goto PM_DanceMove_ClearFlags2; \
+ /* declare and initialize variables -- CEV */ \
+ local vector plane1, plane2; \
+ local float time_left = input_timelength; \
+ local entity stemp, otemp, touched_ent1, touched_ent2, touched_ent3; \
+ plane1 = plane2 = '0 0 0'; \
+ i = j = k = 0; \
+ start_vel = self.velocity; \
+ stemp = otemp = touched_ent1 = touched_ent2 = touched_ent3 = __NULL__; \
+ /* 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); \
+ tracebox (self.origin, self.mins, self.maxs, end, \
+ PM_MOVEFLAGS, self); \
+ if (trace_allsolid) \
+ { \
+ /* self is in something else; attempt to nudge out */ \
+ if (PM_Nudge()) \
+ continue; \
+ else \
+ setorigin (self, self.oldorigin); \
+ /* nah, we're stuck. don't build up falling damage
+ * but allow sideways acceleration -- CEV */ \
+ dprint ("PM_DANCEMOVE: player entity stuck!"); \
+ dprint (sprintf(" timestamp %g\n", time)); \
+ self.velocity.z = 0; \
+ break; \
+ } \
+ /* accept the move -- CEV */ \
+ self.origin = trace_endpos; \
+ if (trace_fraction >= 1.0f) \
+ /* no obstructions, made the whole move -- CEV */ \
+ break; \
+ /* save trace ent for later then reduce time_left -- CEV */ \
+ PM_DANCEMOVE_ADDTOUCH (trace_ent) \
+ time_left -= time_left * trace_fraction; \
+ /* integrated StepSlideMove from Nuclide / CSQCTest
+ * only attempt to step if requested and there's time left
+ * and we hit something like a vertical plane -- CEV */ \
+ if (self.pm_flags & PMF_SLIDE_STEP) { \
+ if (time_left > 0) { \
+ if (trace_plane_normal.z <= PM_PLANE_GROUND) \
+ { \
+ /* store the entity and plane normal from above in
+ * case we need to reject the step attempt -- CEV */ \
+ local vector first_plane = trace_plane_normal; \
+ local entity first_ent = trace_ent; \
+ local float first_frac = trace_fraction; \
+ local float first_net = trace_networkentity; \
+ 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_allsolid || trace_startsolid) \
+ goto PM_DanceMove_RejectStep2; \
+ if (trace_endpos.z - self.origin.z <= 0) \
+ { \
+ /* dprint (sprintf("PM_DANCEMOVE: A %v\n", \
+ trace_endpos - self.origin)); */ \
+ goto PM_DanceMove_RejectStep2; \
+ } \
+ local vector roof_plane = '0 0 0'; \
+ if (trace_fraction < 1.0f) \
+ { \
+ PM_DANCEMOVE_ADDTOUCH (trace_ent) \
+ roof_plane = trace_plane_normal; \
+ } \
+ /* second: move forward */ \
+ k = 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); \
+ if (trace_allsolid) \
+ goto PM_DanceMove_RejectStep2; \
+ /* if we hit the same plane we're trying to step over
+ * and we made no progress in the move then reject
+ * the step attempt -- CEV */ \
+ if (trace_plane_normal == first_plane) { \
+ if (fabs(self.origin.x - trace_endpos.x) < PM_FLMIN) \
+ if (fabs(self.origin.y - trace_endpos.y) < PM_FLMIN) \
+ /* dprint (sprintf("PM_DANCEMOVE: B\n")); */ \
+ goto PM_DanceMove_RejectStep2; \
+ } \
+ local vector fwd_plane = '0 0 0'; \
+ /* local vector save_pos = trace_endpos; */ \
+ j -= j * trace_fraction; \
+ if (trace_fraction < 1.0f) \
+ { \
+ PM_DANCEMOVE_ADDTOUCH (trace_ent) \
+ fwd_plane = trace_plane_normal; \
+ } \
+ /* third: move down; +1 to k is important -- CEV */ \
+ end = trace_endpos; \
+ end.z -= k + 1; \
+ tracebox (trace_endpos, self.mins, self.maxs, end, \
+ PM_MOVEFLAGS, self); \
+ /*
+ if (trace_endpos == save_pos) \
+ { \
+ dprint (sprintf("PM_DANCEMOVE: D\n")); \
+ goto PM_DanceMove_RejectStep2; \
+ } \
+ */ \
+ /* The down move will sometimes hit nothing (frac 1).
+ * In this case trace_plane_normal is unreliable (again
+ * we hit nothing) so do some extra checks to determine
+ * if we keep the step move -- CEV */ \
+ if (trace_fraction == 1.0f) \
+ { \
+ /*
+ dprint (sprintf("PM_DANCEMOVE: norm %v, " \
+ "diff %v, time %g\n", \
+ trace_plane_normal, \
+ trace_endpos - self.origin, \
+ j)); \
+ */ \
+ /* Check the plane just in case -- CEV */ \
+ if (trace_plane_normal.z != 0) \
+ { \
+ dprint ("PM_DANCEMOVE: C\n"); \
+ goto PM_DanceMove_RejectStep2; \
+ } \
+ /* If we haven't moved and first_plane is not
+ * vertical then reject the attempt -- CEV */ \
+ if (trace_endpos == self.origin) \
+ { \
+ if (first_plane.z != 0.0f) \
+ goto PM_DanceMove_RejectStep2; \
+ } \
+ else \
+ { \
+ /* TODO CEV we still need to reject the
+ * step here, don't fully understand
+ * the reason why -- CEV */ \
+ /*
+ dprint (sprintf("PM_DANCEMOVE: Z %v\n",\
+ trace_endpos - save_pos)); \
+ */ \
+ goto PM_DanceMove_RejectStep2; \
+ } \
+ } \
+ else if (trace_plane_normal.z <= PM_PLANE_GROUND) \
+ { \
+ /* this is the expected and regular
+ * not-good-ground step rejection -- CEV */ \
+ goto PM_DanceMove_RejectStep2; \
+ } \
+ if (trace_allsolid == FALSE) \
+ { \
+ /* accept the stepped move. update time_left,
+ * origin, touched ents, and stored planes,
+ * then update flags -- CEV */ \
+ time_left = j; \
+ self.origin = trace_endpos; \
+ if (trace_ent.touch) \
+ PM_DANCEMOVE_ADDTOUCH (trace_ent) \
+ plane2 = plane1 = '0 0 0'; \
+ if (roof_plane) { \
+ if (roof_plane != trace_plane_normal) \
+ { \
+ plane1 = roof_plane; \
+ } } \
+ if (fwd_plane) { \
+ if (fwd_plane != trace_plane_normal) \
+ { \
+ plane2 = plane1; \
+ plane1 = fwd_plane; \
+ } } \
+ self.pm_flags |= PMF_STEPPED; \
+ if (!(self.pm_flags & PMF_ONGROUND)) { \
+ if (start_vel.z <= 0) \
+ { \
+ /* for stairjumps. -- CEV */ \
+ self.pm_flags |= PMF_AIRSTEPPED; \
+ } } \
+ } \
+ else \
+ { \
+ /* discard the step attempt -- CEV */ \
+ PM_DanceMove_RejectStep2: \
+ trace_plane_normal = first_plane; \
+ /* TODO CEV rewind touched ents? */ \
+ trace_ent = first_ent; \
+ trace_fraction = first_frac; \
+ trace_networkentity = first_net; \
+ } \
+ } } } \
+ PM_DANCEMOVE_AXIALNUDGE (self.velocity) \
+ PM_DANCEMOVE_AXIALNUDGE (plane1) \
+ PM_DANCEMOVE_AXIALNUDGE (plane2) \
+ /* we've found a ground plane so call PM_SETONGROUND -- CEV */ \
+ if (trace_plane_normal.z > PM_PLANE_GROUND) \
+ { \
+ PM_DANCEMOVE_GROUNDIMPACT () \
+ PM_SETONGROUND () \
+ } \
+ /* check stored planes and clip velocity as needed -- CEV */ \
+ PM_DANCEMOVE_CLIP (end, trace_plane_normal, plane1, plane2, k) \
+ PM_DANCEMOVE_CLIP (end, plane1, trace_plane_normal, plane2, k) \
+ PM_DANCEMOVE_CLIP (end, plane2, plane1, trace_plane_normal, k) \
+ /* store current plane and plane1 for the next pass -- CEV */ \
+ if (trace_plane_normal != self.groundnormal) \
+ { \
+ plane2 = plane1; \
+ plane1 = trace_plane_normal; \
+ } \
+ /* stop if we've turned against original velocity -- CEV */ \
+ if (self.velocity * start_vel <= 0) \
+ self.velocity = '0 0 0'; \
+ /* stop the loop if velocity is now zero -- CEV */ \
+ if (self.velocity == '0 0 0') \
+ break; \
+ } \
+ /* call the touch functions of any entities we've collided with
+ * (as needed) -- CEV */ \
+ PM_DANCEMOVE_DOTOUCH (touched_ent3) \
+ PM_DANCEMOVE_DOTOUCH (touched_ent2) \
+ PM_DANCEMOVE_DOTOUCH (touched_ent1) \
+ /* if we're not onground and the timer is greater than
+ * PM_WALLCLIP_WINDOW (within 250ms of pressing jump)
+ * then restore velocity (to skim past walls) -- CEV */ \
+ if (!(self.pm_flags & PMF_ONGROUND)) { \
+ if (self.pm_timer > PM_WALLCLIP_WINDOW) \
+ { \
+ j = start_vel.z; \
+ k = self.velocity.z; \
+ self.velocity = start_vel; \
+ /* take min of vel_z so headbump doublejumps work -- CEV */ \
+ if (fabs(j) > fabs(k)) \
+ self.velocity.z = k; \
+ else \
+ self.velocity.z = j; \
+ } } \
+ /* final gravity check here -- CEV */ \
+ if (grav) \
+ self.velocity.z -= grav * 0.5f; \
+ /* clip to the ground plane under certain complex conditions (this
+ * is done to recreate / simulate Q3/CPM stair behavior) -- CEV */ \
+ if (self.pm_timer > 0) { \
+ if (self.velocity.z) { \
+ if (self.groundnormal.z > PM_PLANE_GROUND) { \
+ if (!(self.pm_flags & PMF_CROUCH_HELD)) { \
+ if (!(self.pm_flags & PMF_WALK_HELD)) { \
+ if (!(self.pm_flags & PMF_DOUBLEJUMPED)) \
+ { \
+ /*
+ dprint (sprintf("PM_DANCEMOVE: glue %f\n", self.origin.z));
+ */ \
+ k = self.velocity * self.groundnormal; \
+ self.velocity -= self.groundnormal * k; \
+ } } } } } } \
+ /*
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
-
- PM_DanceMove_ClearFlags:
- // clear slide hint flags -- CEV
- self.pm_flags = self.pm_flags - (self.pm_flags & PM_SLIDEFLAGS);
-};
+ dprint (sprintf("PM_DANCEMOVE: move complete, "
+ "i %g, time_left %g, velocity.z %g\n",
+ i, time_left, self.velocity.z));
+ */ \
+ PM_DanceMove_ClearFlags2: \
+ /* clear slide hint flags -- CEV */ \
+ self.pm_flags = self.pm_flags - (self.pm_flags & PM_SLIDEFLAGS); \
+}

//----------------------------------------------------------------------
void() PM_CrouchStart =
{
// crouch
self.pm_flags |= PMF_CROUCHED;
- // self.pm_flags |= PMF_CROUCH_HELD;
setsize (self, PM_CROUCH_MIN, PM_CROUCH_MAX);
- self.view_ofs = PM_CROUCH_VIEWOFS;

#ifdef CSQC
- // smooth crouching -- CEV
- if (self.entnum == player_localentnum)
+ // transition to crouch view offset (if not already in progress) -- CEV
+ if (self.entnum == player_localentnum) {
+ if (self.view_ofs != PM_CROUCH_VIEWOFS)
{
- view_offset_old = PM_STAND_VIEWOFS_z;
- view_offset_finished = time + PLAYER_CROUCH_SMOOTH;
- }
+ view_crouch_old = PM_STAND_VIEWOFS.z;
+ view_crouch_finished = time + PLAYER_CROUCH_SMOOTH;
+ } }
#endif
+
+ self.view_ofs = PM_CROUCH_VIEWOFS;
};

//----------------------------------------------------------------------
@@ -916,16 +889,18 @@ void() PM_CrouchStop =
{
self.pm_flags &= ~PMF_CROUCHED;
setsize (self, PM_STAND_MIN, PM_STAND_MAX);
- self.view_ofs = PM_STAND_VIEWOFS;

#ifdef CSQC
- // smooth crouching -- CEV
- if (self.entnum == player_localentnum)
+ // transition to stand view offset (like above) -- CEV
+ if (self.entnum == player_localentnum) {
+ if (self.view_ofs != PM_STAND_VIEWOFS)
{
- view_offset_old = PM_CROUCH_VIEWOFS_z;
- view_offset_finished = time + PLAYER_CROUCH_SMOOTH;
- }
+ view_crouch_old = PM_CROUCH_VIEWOFS_z;
+ view_crouch_finished = time + PLAYER_CROUCH_SMOOTH;
+ } }
#endif
+
+ self.view_ofs = PM_STAND_VIEWOFS;
} }
};

@@ -952,7 +927,7 @@ void() PM_CrouchSlideStart =
}

#ifdef SSQC
- dprint (sprintf("PM_CrouchSlideStart: lesgo %g\n", self.velocity_z));
+ dprint (sprintf("PM_CrouchSlideStart: lesgo %g\n", self.velocity.z));
#endif

self.pm_flags |= PMF_CROUCHSLIDE;
@@ -988,14 +963,14 @@ void() PM_Jump =

// make sure we get at least jumpspeed upwards from the ground
// plane by clipping velocity to it. necessary for rampjumps. -- CEV
- if (self.groundnormal_z > PM_PLANE_GROUND)
+ if (self.groundnormal.z > PM_PLANE_GROUND)
if (self.velocity * self.groundnormal < 0)
self.velocity -= self.groundnormal *
(self.velocity * self.groundnormal);

// this changes the behavior of downward ramps -- CEV
- if (self.velocity_z < 0)
- self.velocity_z = 0;
+ if (self.velocity.z < 0)
+ self.velocity.z = 0;

if (self.pm_timer > 0)
{
@@ -1006,18 +981,18 @@ void() PM_Jump =
// a teleport jump: allow a larger (+0.2) window to
// account for time to travel thru teleporter -- CEV
// non-additive jump, though it shouldn't matter -- CEV
- self.velocity_z = PM_TELEJUMPSPEED;
+ self.velocity.z = PM_TELEJUMPSPEED;
}
else if (self.pm_flags & PMF_ONRAMP)
{
// the groundnormal is weird - a ramp - so we
// want an additive doublejump here -- CEV
- self.velocity_z += PM_DOUBLEJUMPSPEED;
+ self.velocity.z += PM_DOUBLEJUMPSPEED;
}
else
{
// flat ground, don't do an additive jump -- CEV
- self.velocity_z = PM_STAIRJUMPSPEED;
+ self.velocity.z = PM_STAIRJUMPSPEED;
}

#ifdef SSQC
@@ -1040,7 +1015,7 @@ void() PM_Jump =
if (self.pm_flags & PMF_ONRAMP)
{
// do an additive jump on non-flat ground -- CEV
- self.velocity_z += PM_JUMPSPEED;
+ self.velocity.z += PM_JUMPSPEED;
}
else
{
@@ -1048,23 +1023,23 @@ void() PM_Jump =
// up within the last frame (for CPM stairjumps)
// -- CEV
if (self.pm_flags & PMF_AIRSTEPPED)
- self.velocity_z = PM_JUMPSPEED;
+ self.velocity.z = PM_JUMPSPEED;
else if (self.pm_flags & PMF_CROUCH_HELD)
- self.velocity_z = PM_JUMPSPEED;
+ self.velocity.z = PM_JUMPSPEED;
else if (self.pm_flags & PMF_WALK_HELD)
- self.velocity_z = PM_JUMPSPEED;
+ self.velocity.z = PM_JUMPSPEED;
else if (!(self.pm_flags & PMF_STEPPED))
- self.velocity_z = PM_JUMPSPEED;
+ self.velocity.z = PM_JUMPSPEED;
#if 0
else
dprint (sprintf("PM_Jump: eating jump; %f\n",
- self.origin_z));
+ self.origin.z));
#endif
}
}

// manage flags -- CEV
- PM_SetOnGround (PMG_NOGROUND);
+ PM_SETONGROUND_NOGROUND ()
self.pm_flags |= PMF_JUMP_HELD;

if (self.pm_flags & PMF_CROUCHSLIDE)
@@ -1088,7 +1063,7 @@ void() PM_WallClimb =
{
// accelerate upwards toward a vertical ledge -- CEV
local float grav;
- local float zspeed = self.velocity_z;
+ local float zspeed = self.velocity.z;

// counteract gravity with additional Z velocity -- CEV
if (self.gravity)
@@ -1099,7 +1074,7 @@ void() PM_WallClimb =
zspeed += grav + PM_CLIMBACCEL;

self.velocity *= PM_CLIMBSCALE;
- self.velocity_z = bound (PM_CLIMBSPEEDMIN, zspeed, PM_CLIMBSPEEDMAX);
+ self.velocity.z = bound (PM_CLIMBSPEEDMIN, zspeed, PM_CLIMBSPEEDMAX);

// reset pm_timer so we don't stick to the floor -- CEV
self.pm_flags |= PMF_CLIMB;
@@ -1107,7 +1082,7 @@ void() PM_WallClimb =
self.pm_timer = 0;

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

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

if (self.pm_timer > 0)
@@ -1138,7 +1113,7 @@ void() PM_WallJump =
vol = 0.9;
wav = "player/plyrjmp8.wav";
#endif
- self.velocity_z = PM_WALLJUMPDOUBLE;
+ self.velocity.z = PM_WALLJUMPDOUBLE;
}
else
{
@@ -1147,7 +1122,7 @@ void() PM_WallJump =
vol = 0.2;
wav = sprintf ("player/jump0%g.ogg", r + 1);
#endif
- self.velocity_z = PM_WALLJUMPSPEED;
+ self.velocity.z = PM_WALLJUMPSPEED;
}

// manage flags & fields -- CEV
@@ -1173,15 +1148,15 @@ void() PM_WallJumpCheck =
return;
if (self.pm_flags & PMF_WATERJUMPED)
return;
- if (self.velocity_z < PM_WALLJUMPLIMIT)
+ if (self.velocity.z < PM_WALLJUMPLIMIT)
return;

- // are we within 32 units of the floor? -- CEV
+ // are we within PM_WALLJUMPGROUND 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;
+ local float grounddist = self.origin.z - trace_endpos.z;
if (grounddist <= PM_WALLJUMPGROUND)
- if (trace_plane_normal_z > PM_PLANE_GROUND)
+ if (trace_plane_normal.z > PM_PLANE_GROUND)
return;

local float i, checks;
@@ -1197,7 +1172,7 @@ void() PM_WallJumpCheck =
// v_forward and v_right should still be those set by the
// makevectors call from PM_Move -- CEV
if (i < 2)
- if (input_movevalues_x == 0)
+ if (input_movevalues.x == 0)
continue;
else
// check further when +back -- CEV
@@ -1206,7 +1181,7 @@ void() PM_WallJumpCheck =
else if (i == 1)
end = v_forward * 25;
if (i > 1)
- if (input_movevalues_y == 0)
+ if (input_movevalues.y == 0)
continue;
else
end = v_right * 10;
@@ -1223,15 +1198,15 @@ void() PM_WallJumpCheck =
MOVE_NOMONSTERS | PM_MOVEFLAGS, self);

#if 0
- dprint (sprintf("PM_WallJumpCheck: frac %g, norm_z %g, dist "
- "%g\n", trace_fraction, trace_plane_normal_z,
+ dprint (sprintf("PM_WallJumpCheck: frac %g, norm.z %g, dist "
+ "%g\n", trace_fraction, trace_plane_normal.z,
vlen(self.origin - trace_endpos)));
#endif

// 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 >= PM_PLANE_VERTICAL)
+ if (trace_plane_normal.z <= PM_PLANE_GROUND) {
+ if (trace_plane_normal.z >= PM_PLANE_VERTICAL)
{
if (!(self.pm_flags & PMF_JUMP_HELD)) {
if (!(self.pm_flags & PMF_WALLJUMPED)) {
@@ -1245,8 +1220,8 @@ void() PM_WallJumpCheck =

if (i == 0) {
if (self.pm_flags & PMF_JUMP_HELD) {
- if (self.speed <= PM_RUNSPEED) {
- if (fabs(self.velocity_z) < 90.0f) {
+ if (self.speed <= PM_MAXSPEED) {
+ if (fabs(self.velocity.z) < 90.0f) {
if (grounddist > 42)
{
// holding jump and moving *into* the wall
@@ -1258,7 +1233,7 @@ void() PM_WallJumpCheck =
tpn_ang = vectoangles (trace_plane_normal);

// must be facing the impacted surface -- CEV
- if (angledif(input_angles_y, tpn_ang_y) <= 150)
+ if (angledif(input_angles.y, tpn_ang.y) <= 150)
continue;

// we're looking for empty space, for a trace
@@ -1266,7 +1241,7 @@ void() PM_WallJumpCheck =
// below -- CEV

// horizontal forward at least 64u off floor
- start_z += 22;
+ start.z += 22;
traceline (start, start + v_forward * 30,
MOVE_NOMONSTERS | PM_MOVEFLAGS, self);

@@ -1279,7 +1254,7 @@ void() PM_WallJumpCheck =
MOVE_NOMONSTERS | PM_MOVEFLAGS,
self);

- if (trace_plane_normal_z >
+ if (trace_plane_normal.z >
PM_PLANE_GROUND)
{
PM_WallClimb ();
@@ -1288,7 +1263,7 @@ void() PM_WallJumpCheck =
}

// horizontal forward at least 96u off floor
- start_z += 32;
+ start.z += 32;
traceline (start, start + v_forward * 30,
MOVE_NOMONSTERS | PM_MOVEFLAGS, self);

@@ -1299,7 +1274,7 @@ void() PM_WallJumpCheck =
MOVE_NOMONSTERS | PM_MOVEFLAGS,
self);

- if (trace_plane_normal_z >
+ if (trace_plane_normal.z >
PM_PLANE_GROUND)
{
PM_WallClimb ();
@@ -1317,732 +1292,734 @@ void() PM_WallJumpCheck =
};

//----------------------------------------------------------------------
-// PM_NoClipAccelerate -- for flying / noclip; not for swimming -- CEV
-//----------------------------------------------------------------------
-void(vector wishvel, float scale, float move_time) PM_NoClipAccelerate =
-{
- local vector wishdir;
- local float newspeed, speed1, temp, wishspeed;
-
- if (input_buttons & PM_BTN_JUMP)
- // smartjump
- wishvel_z = max (PM_MAXSPEED, wishvel_z);
- else if (input_buttons & PM_BTN_DOWN)
- // smartcrouch
- wishvel_z = min (-PM_MAXSPEED, wishvel_z);
-
- wishspeed = vlen (wishvel) * scale;
- wishdir = normalize (wishvel);
-
- // inline PM_Friction -- CEV
- speed1 = vlen (self.velocity);
-
- if (speed1 < PM_EPSILONF)
- {
- self.velocity = '0 0 0';
- }
- else
- {
- // calculate what their new speed should be & slow them
- temp = speed1 < PM_STOPSPEED ? PM_STOPSPEED : speed1;
- newspeed = speed1 - temp * PM_GROUNDFRICTION * move_time;
- if (newspeed <= 0)
- self.velocity = '0 0 0';
- else
- self.velocity *= newspeed / speed1;
- }
+#define PM_FRICTION(speed1, temp, friction, move_time) \
+{ \
+ speed1 = vlen (self.velocity); \
+ if (speed1 < PM_FLMIN) \
+ { \
+ self.velocity = '0 0 0'; \
+ } \
+ else \
+ { \
+ /* calculate what their new speed should be & slow them */ \
+ if (self.pm_timer > 0) \
+ temp = speed1; \
+ else if (speed1 < PM_STOPSPEED) \
+ temp = PM_STOPSPEED; \
+ else \
+ temp = speed1; \
+ temp = speed1 - temp * friction * move_time; \
+ if (temp <= 0) \
+ self.velocity = '0 0 0'; \
+ else \
+ self.velocity *= temp / speed1; \
+ } \
+}

- // inline PM_Accelerate -- CEV
- speed1 = wishspeed - (self.velocity * wishdir);
+//----------------------------------------------------------------------
+#define PM_ACCELERATE(dir, wish, speed1, newspeed, accel, move_time) \
+{ \
+ speed1 = wish - (self.velocity * dir); \
+ if (speed1 > 0) \
+ { \
+ newspeed = accel * move_time * wish; \
+ newspeed = min (newspeed, speed1); \
+ self.velocity += newspeed * dir; \
+ } \
+}

- if (speed1 > 0)
- {
- newspeed = PM_GROUNDACCEL * move_time * wishspeed;
- newspeed = min (newspeed, speed1);
- self.velocity += newspeed * wishdir;
- }
-};
+//----------------------------------------------------------------------
+#define PM_AIRCONTROL(dir, wish, cur, new, zspeed, dot, move_time) \
+{ \
+ zspeed = self.velocity.z; \
+ self.velocity.z = 0; \
+ cur = vlen (self.velocity); \
+ self.velocity = normalize (self.velocity); \
+ dot = self.velocity * dir; \
+ if (dot > 0) \
+ { \
+ new = PM_AIRACCELBASE; \
+ new *= bound (0, wish / PM_MAXAIRSPEED, 1); \
+ new *= PM_AIRACCELTURN * dot * dot * move_time; \
+ self.velocity = self.velocity * cur + dir * new; \
+ self.velocity = normalize (self.velocity); \
+ } \
+ self.velocity *= cur; \
+ self.velocity.z = zspeed; \
+}

//----------------------------------------------------------------------
-// PM_SwimPreMove -- Check for water jump, water wading sounds -- CEV
+// PM_MOVE_MOVETYPES_CATEGORIZEPOSITION
+// Based on similarly-named function in the GPL2 purecsqc pmove.qc
//----------------------------------------------------------------------
-void(vector wishvel, float move_time) PM_SwimPreMove =
-{
- // CheckWaterJump
- if (self.conlevel == WATERLEVEL_WAIST)
- {
- local vector start, end;
-
- start = self.origin;
- start_z = start_z + 8;
- // use wishvel instead of v_forward -- CEV
- end = [wishvel_x, wishvel_y, 0];
- end = normalize (end);
- traceline (start, (start + end * 24), TRUE, self);
-
- if (trace_fraction < 1)
- {
- // solid at the waist
- start_z = start_z + self.maxs_z - 8;
- self.movedir = trace_plane_normal * -50;
- traceline (start, (start + end * 24),
- TRUE, self);
-
- if (trace_fraction == 1)
- {
- // open at eye level
- self.flags |= FL_WATERJUMP;
- self.pm_flags |= PMF_WATERJUMPED;
- self.flags &= ~FL_JUMPRELEASED;
- self.pm_flags &= ~PMF_JUMP_HELD;
- // Z velocity was 225
- self.velocity_z = PM_JUMPSPEED;
- }
- }
- }
-
- #ifdef SSQC
- // functionality copied into pmove from client.qc -- CEV
- if (self.conlevel >= WATERLEVEL_WAIST) {
- if (self.conlevel >= WATERLEVEL_EYES) {
- if (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);
- } } }
- #endif
+#define PM_MOVE_MOVETYPES_CATEGORIZEPOSITION() \
+{ \
+ /* if Z velocity is greater than 180 and we're not on a ramp or
+ * a steep slope then assume we're not onground (an optimization
+ * from Warsow / Warfork) -- CEV */ \
+ if (self.velocity.z > 180) \
+ { \
+ if (self.pm_flags & PMF_ONRAMP) \
+ { \
+ PM_SETONGROUND_TRACEGROUND () \
+ PM_SETONGROUND () \
+ } \
+ else if (self.pm_flags & PMF_ONSLOPE) \
+ { \
+ PM_SETONGROUND_TRACEGROUND () \
+ PM_SETONGROUND () \
+ } \
+ else \
+ { \
+ PM_SETONGROUND_NOGROUND () \
+ } \
+ } \
+ else \
+ { \
+ /* look for ground, manage flags & fields -- CEV */ \
+ /* setting onground here before the acceleration functions
+ * turns out to be faster (in my testing) than relying on
+ * DanceMove to correctly track ground state -- CEV */ \
+ PM_SETONGROUND_TRACEGROUND () \
+ PM_SETONGROUND () \
+ } \
+ /* set waterlevel and watertype -- CEV */ \
+ base_entity_positioncontents (self); \
+ /* don't crouchslide in water -- CEV */ \
+ if (self.pm_flags & PMF_CROUCHSLIDE) { \
+ if (self.pm_flags & PMF_ONGROUND) { \
+ if (self.conlevel >= WATERLEVEL_WAIST) \
+ { \
+ if (self.pm_timer < 0) \
+ self.pm_timer = 0; \
+ PM_CrouchSlideStop (); \
+ } } } \
+ /* can't be waterjumping if we're on ground */ \
+ if (self.pm_flags & PMF_WATERJUMPED) { \
+ if (self.conlevel == WATERLEVEL_NONE || self.pm_flags & PMF_ONGROUND) \
+ { \
+ self.pm_flags &= ~PMF_WATERJUMPED; \
+ self.flags &= ~FL_WATERJUMP; \
+ } } \
+}

- if (self.pm_flags & PMF_STEPPED)
- {
- self.pm_flags &= ~PMF_STEPPED;
- self.pm_flags &= ~PMF_AIRSTEPPED;
- }
-};
+//----------------------------------------------------------------------
+#define PM_MOVE_MOVETYPES_SETNOCLIPFLAGS() \
+{ \
+ /* noclip is never on ground */ \
+ if (self.groundentity != __NULL__) \
+ self.groundentity = __NULL__; \
+ if (self.groundnormal != '0 0 0') \
+ self.groundnormal = '0 0 0'; \
+ if (self.pm_flags & PMF_DOUBLEJUMPED) \
+ self.pm_flags &= ~PMF_DOUBLEJUMPED; \
+ if (self.pm_flags & PMF_WALLJUMPED) \
+ self.pm_flags &= ~PMF_WALLJUMPED; \
+ if (self.pm_flags & PMF_ONGROUND) \
+ self.pm_flags &= ~PMF_ONGROUND; \
+ if (self.flags & FL_ONGROUND) \
+ self.flags &= ~FL_ONGROUND; \
+ if (self.pm_flags & PMF_PUSHED) \
+ self.pm_flags &= ~PMF_PUSHED; \
+ if (self.pm_flags & PMF_CLIMB) \
+ self.pm_flags &= ~PMF_CLIMB; \
+ self.pm_timer = 0; \
+}

//----------------------------------------------------------------------
-// PM_SwimAccelerate -- Largely copied from id Software's WaterMove -- CEV
+// PM_MOVE_MOVETYPES_NOCLIPACCELERATE -- for flying / noclip -- CEV
//----------------------------------------------------------------------
-void(vector wishvel, float move_time) PM_SwimAccelerate =
-{
- local vector wishdir;
- local float newspeed, speed1, temp, wishspeed;
-
- if (!(self.pm_flags & PMF_WATERJUMPED))
- {
- if (input_buttons & PM_BTN_JUMP)
- // smartjump
- wishvel_z = max (PM_MAXSPEED, wishvel_z);
- else if (input_buttons & PM_BTN_DOWN)
- // smartcrouch
- // self.pm_flags |= PMF_CROUCH_HELD;
- wishvel_z = min (-PM_MAXSPEED, wishvel_z);
- else if (input_movevalues == '0 0 0')
- // drift towards bottom -- CEV
- wishvel_z -= PM_WATERSINKSPEED;
- }
-
- wishspeed = vlen (wishvel);
- wishspeed = min (wishspeed, PM_WATERMAXSPEED);
- wishdir = normalize (wishvel);
-
- // inline PM_Friction -- CEV
- if (!(self.pm_flags & PMF_WATERJUMPED))
- {
- speed1 = vlen (self.velocity);
-
- if (speed1 < PM_EPSILONF)
- {
- self.velocity = '0 0 0';
- }
- else
- {
- // calculate what their new speed should be & slow them
- temp = speed1 < PM_STOPSPEED ? PM_STOPSPEED : speed1;
- newspeed = speed1 - temp * PM_WATERFRICTION * move_time;
- if (newspeed <= 0)
- self.velocity = '0 0 0';
- else
- self.velocity *= newspeed / speed1;
- }
- }
-
- // inline PM_Accelerate -- CEV
- speed1 = wishspeed - (self.velocity * wishdir);
+#define PM_MOVE_MOVETYPES_NOCLIPACCELERATE(move_time) \
+{ \
+ if (input_buttons & PM_BTN_JUMP) \
+ { \
+ /* smartjump */ \
+ wishvel.z = max (PM_MAXSPEED, wishvel.z); \
+ } \
+ else if (input_buttons & PM_BTN_DOWN) \
+ { \
+ /* smartcrouch */ \
+ wishvel.z = min (-PM_MAXSPEED, wishvel.z); \
+ } \
+ wishspeed = vlen (wishvel); \
+ wishdir = normalize (wishvel); \
+ PM_FRICTION (speed1, temp, PM_GROUNDFRICTION, move_time) \
+ PM_ACCELERATE (wishdir, wishspeed, speed1, temp, PM_GROUNDACCEL, \
+ move_time) \
+}

- if (speed1 > 0)
- {
- newspeed = PM_WATERACCEL * move_time * wishspeed;
- newspeed = min (newspeed, speed1);
- self.velocity += newspeed * wishdir;
- }
+#ifdef SSQC
+//----------------------------------------------------------------------
+#define PM_MOVE_MOVETYPES_SWIMPREMOVE_SSQC() \
+{ \
+ /* functionality copied into pmove from client.qc -- CEV */ \
+ if (self.conlevel >= WATERLEVEL_WAIST) { \
+ if (self.conlevel >= WATERLEVEL_EYES) { \
+ if (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); \
+ } } } \
+}
+#endif

-};
+#ifdef CSQC
+//----------------------------------------------------------------------
+#define PM_MOVE_MOVETYPES_SWIMPREMOVE_SSQC() \
+{ \
+}
+#endif

//----------------------------------------------------------------------
-// PM_WalkPreMove -- Check for crouching, jumping, ladders -- CEV
+// PM_MOVE_MOVETYPES_SWIMPREMOVE -- water jump, water wading sounds -- CEV
//----------------------------------------------------------------------
-void(vector wishvel, float move_time) PM_WalkPreMove =
-{
- if (self.pm_flags & PMF_ONLADDER)
- {
- // ladder physics
- local float zspeed = fabs(self.velocity_z) + PM_CLIMBACCEL;
- self.velocity *= PM_CLIMBSCALE;
- self.speed = vlen ([self.velocity_x, self.velocity_y, 0]);
-
- if (input_buttons & PM_BTN_JUMP || input_movevalues_z > 0)
- {
- // PlayerClimb -- johnfitz
- self.velocity_z = bound (PM_CLIMBSPEEDMIN, zspeed,
- PM_CLIMBSPEEDMAX);
- }
- else if (input_buttons & PM_BTN_DOWN || input_movevalues_z < 0)
- {
- // PlayerClimbDown -- CEV
- self.velocity_z = bound (-PM_CLIMBSPEEDMAX, -zspeed,
- -PM_CLIMBSPEEDMIN);
- }
- else
- {
- self.flags |= FL_JUMPRELEASED;
- self.pm_flags &= ~PMF_JUMP_HELD;
- self.velocity_z = 0;
- }
-
- if (self.pm_flags & PMF_ONGROUND)
- PM_SetOnGround (PMG_NOGROUND);
-
- self.pm_timer = 0;
-
- return;
- }
-
- if (input_buttons & PM_BTN_JUMP)
- {
- // +jump was pressed
- if (self.pm_flags & PMF_ONGROUND)
- PM_Jump ();
- else if (world_walljump)
- PM_WallJumpCheck ();
- }
- else
- {
- self.flags |= FL_JUMPRELEASED;
- self.pm_flags &= ~PMF_JUMP_HELD;
- }
-
- if (input_buttons & PM_BTN_DOWN && !(self.pm_flags & PMF_CROUCHED))
- {
- PM_CrouchStart ();
- }
- else if (!(input_buttons & PM_BTN_DOWN) && self.pm_flags & PMF_CROUCHED)
- {
- PM_CrouchStop ();
- }
-
- if (self.pm_flags & PMF_STEPPED)
- {
- self.pm_flags &= ~PMF_STEPPED;
- self.pm_flags &= ~PMF_AIRSTEPPED;
- }
-};
+#define PM_MOVE_MOVETYPES_SWIMPREMOVE(start, end, move_time) \
+{ \
+ /* CheckWaterJump */ \
+ if (self.conlevel == WATERLEVEL_WAIST) \
+ { \
+ start = self.origin; \
+ start.z = start.z + 8; \
+ /* use wishvel instead of v_forward -- CEV */ \
+ end = [wishvel.x, wishvel.y, 0]; \
+ end = normalize (end); \
+ traceline (start, (start + end * 24), TRUE, self); \
+ if (trace_fraction < 1) \
+ { \
+ /* solid at the waist */ \
+ start.z = start.z + self.maxs.z - 8; \
+ self.movedir = trace_plane_normal * -50; \
+ traceline (start, (start + end * 24), TRUE, self); \
+ if (trace_fraction == 1) \
+ { \
+ /* open at eye level */ \
+ self.flags |= FL_WATERJUMP; \
+ self.pm_flags |= PMF_WATERJUMPED; \
+ self.flags &= ~FL_JUMPRELEASED; \
+ self.pm_flags &= ~PMF_JUMP_HELD; \
+ /* Z velocity was 225 */ \
+ self.velocity.z = PM_JUMPSPEED; \
+ } \
+ } \
+ } \
+ PM_MOVE_MOVETYPES_SWIMPREMOVE_SSQC () \
+ if (self.pm_flags & PMF_STEPPED) \
+ { \
+ self.pm_flags &= ~PMF_STEPPED; \
+ self.pm_flags &= ~PMF_AIRSTEPPED; \
+ } \
+}

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

//----------------------------------------------------------------------
-// PM_ManageTimer -- pos when jumping, neg when crouchsliding -- CEV
+// PM_MOVE_MOVETYPES_WALKPREMOVE -- crouching, jumping, ladders -- CEV
//----------------------------------------------------------------------
-void(float move_time) PM_ManageTimer =
-{
- if (self.pm_timer)
- {
- if (self.pm_flags & PMF_CROUCHSLIDE)
- {
- self.pm_timer += move_time;
-
- if (self.pm_timer >= 0)
- self.pm_timer = 0;
- }
- else
- {
- self.pm_timer -= move_time;
-
- if (self.pm_timer <= 0)
- self.pm_timer = 0;
- }
- }
-
- if (self.pm_flags & PMF_CROUCHSLIDE)
- {
- if (self.pm_timer >= 0)
- PM_CrouchSlideStop ();
- }
-
- if (self.pm_flags & PMF_DOUBLEJUMPED)
- {
- if (self.pm_timer <= 0)
- self.pm_flags &= ~PMF_DOUBLEJUMPED;
- }
-};
+#define PM_MOVE_MOVETYPES_WALKPREMOVE() \
+{ \
+ if (self.pm_flags & PMF_ONLADDER) \
+ { \
+ local float zspeed = fabs(self.velocity.z) + PM_CLIMBACCEL; \
+ self.velocity *= PM_CLIMBSCALE; \
+ self.speed = vlen ([self.velocity.x, self.velocity.y, 0]); \
+ if (input_buttons & PM_BTN_JUMP || input_movevalues.z > 0) \
+ { \
+ /* PlayerClimb -- johnfitz */ \
+ self.velocity.z = bound (PM_CLIMBSPEEDMIN, zspeed, \
+ PM_CLIMBSPEEDMAX); \
+ } \
+ else if (input_buttons & PM_BTN_DOWN || input_movevalues.z < 0)\
+ { \
+ /* PlayerClimbDown -- CEV */ \
+ self.velocity.z = bound (-PM_CLIMBSPEEDMAX, -zspeed, \
+ -PM_CLIMBSPEEDMIN); \
+ } \
+ else \
+ { \
+ self.flags |= FL_JUMPRELEASED; \
+ self.pm_flags &= ~PMF_JUMP_HELD; \
+ self.velocity.z = 0; \
+ } \
+ if (self.pm_flags & PMF_ONGROUND) \
+ PM_SETONGROUND_NOGROUND () \
+ self.pm_timer = 0; \
+ } \
+ else \
+ { \
+ if (input_buttons & PM_BTN_JUMP) \
+ { \
+ /* +jump was pressed */ \
+ if (self.pm_flags & PMF_ONGROUND) \
+ { \
+ PM_Jump (); \
+ } \
+ else if (world_walljump) \
+ { \
+ PM_WallJumpCheck (); \
+ } \
+ } \
+ else \
+ { \
+ self.flags |= FL_JUMPRELEASED; \
+ self.pm_flags &= ~PMF_JUMP_HELD; \
+ } \
+ if (input_buttons & PM_BTN_DOWN && \
+ !(self.pm_flags & PMF_CROUCHED)) \
+ { \
+ PM_CrouchStart (); \
+ } \
+ else if (!(input_buttons & PM_BTN_DOWN) && \
+ self.pm_flags & PMF_CROUCHED) \
+ { \
+ PM_CrouchStop (); \
+ } \
+ if (self.pm_flags & PMF_STEPPED) \
+ { \
+ self.pm_flags &= ~PMF_STEPPED; \
+ self.pm_flags &= ~PMF_AIRSTEPPED; \
+ } \
+ } \
+ /* determine the user's requested movement direction / angle.
+ * inspired by IsMoveInDirection from Nexuiz / Xonotic; this
+ * is slow and could be improved -- CEV */ \
+ if (wishspeed) \
+ { \
+ /* work out the requested movement direction -- CEV */ \
+ /* vectoyaw ignores the Z component of its input -- CEV */ \
+ wishyaw -= vectoyaw (input_movevalues); \
+ wishyaw = fabs (wishyaw - 360.0f * rint(wishyaw / 360.0f)); \
+ /* we don't care about 180 (backward) wishyaw; we'll test
+ * the dotproduct of wishvel and self.velocity later to
+ * determine if we're slowing down or speeding up -- CEV */ \
+ if (wishyaw == 180) \
+ wishyaw = 0; \
+ if (wishyaw == 0) \
+ { \
+ /* test if the player is looking perpendicular to
+ * the direction they're moving in (+/- 30 degrees)
+ * if that's the case then alter wishyaw so the
+ * checks below will do Q1 air accel -- CEV */ \
+ temp = input_angles.y - vectoyaw(self.velocity); \
+ temp = fabs (temp - 360.0f * rint(temp / 360.0f)); \
+ wishyaw = -wishyaw; \
+ if (temp > 60.0f) \
+ if (temp < 120.0f) \
+ wishyaw = -90.0f; \
+ } \
+ } \
+}

//----------------------------------------------------------------------
-// PM_Move -- PMOVE entrypoint -- CEV
+// PM_MOVE_MOVETYPES_WALKACCELERATE -- accel & friction for MOVETYPE_WALK -- CEV
//----------------------------------------------------------------------
-void(entity e) PM_Move =
-{
- // 'self' in this context is not reliable; it should be set to
- // the entity passed to this function -- CEV
- local entity oself = self;
- self = e;
-
- #ifdef CSQC
- if (self.entnum == player_localentnum)
- view_pl = self;
- #endif
-
- // 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 == FALSE)
- PM_Nudge ();
-
- if (self.velocity != '0 0 0')
- self.velocity = PM_TruncateVectorToEighth (self.velocity);
-
- // clear JUMP_HELD if it's set and the user isn't pressing jump
- if (!(input_buttons & PM_BTN_JUMP))
- self.pm_flags &= ~PMF_JUMP_HELD;
-
- // crouch key, crouchsliding -- CEV
- if (input_buttons & PM_BTN_DOWN)
- {
- self.pm_flags |= PMF_CROUCH_HELD;
- }
- else
- {
- self.pm_flags &= ~PMF_CROUCH_HELD;
- if (self.pm_flags & PMF_CROUCHSLIDE)
- PM_CrouchSlideStop ();
- }
-
- // walk key, walking -- CEV
- if (input_buttons & PM_BTN_WALK)
- self.pm_flags |= PMF_WALK_HELD;
- else
- self.pm_flags &= ~PMF_WALK_HELD;
-
- local vector wishvel;
- local float half_time = input_timelength * 0.5;
- self.speed = vlen ([self.velocity_x, self.velocity_y, 0]);
-
- if (self.movetype == MOVETYPE_WALK)
- {
- // figure out the properties of the player's position -- CEV
- PM_CategorizePosition ();
-
- // split acceleration in two to improve responsiveness -- CEV
- if (self.conlevel >= WATERLEVEL_WAIST)
- {
- makevectors (input_angles);
- wishvel = v_forward * input_movevalues_x +
- v_right * input_movevalues_y +
- v_up * input_movevalues_z;
-
- // swim acceleration
- PM_SwimPreMove (wishvel, half_time);
- PM_SwimAccelerate (wishvel, half_time);
- }
- else
- {
- // only yaw matters here -- CEV
- makevectors (input_angles_y * '0 1 0');
- wishvel = v_forward * input_movevalues_x +
- v_right * input_movevalues_y;
- wishvel_z = 0;
- PM_WalkPreMove (wishvel, half_time);
- PM_WalkAccelerate (wishvel, half_time);
- }
-
- // timers (part 1) -- CEV
- PM_ManageTimer (half_time);
-
- // step if nostep is false and we're not on a ladder...
- if (world_nostep == FALSE) {
- if (!(self.pm_flags & PMF_ONLADDER))
- {
- // ... and either airstep is true or we're onground
- if (world_airstep == TRUE)
- self.pm_flags |= PMF_SLIDE_STEP;
- else if (self.pm_flags & PMF_ONGROUND)
- self.pm_flags |= PMF_SLIDE_STEP;
- } }
-
- if (self.velocity != '0 0 0')
- PM_CheckVelocity ();
-
- // Do the move. Bounce, Rock, Skate, Roll -- CEV
- PM_DanceMove ();
-
- // second pass at acceleration; note that a touch function
- // might have changed the v_ vectors during the move -- CEV
- if (self.conlevel >= WATERLEVEL_WAIST)
- PM_SwimAccelerate (wishvel, half_time);
- else
- PM_WalkAccelerate (wishvel, half_time);
-
- // timers (part 2) -- CEV
- PM_ManageTimer (half_time);
-
- // clear ladder flag -- CEV
- if (self.pm_flags & PMF_ONLADDER)
- self.pm_flags &= ~PMF_ONLADDER;
-
- touchtriggers ();
- base_entity_positioncontents (self);
- }
- else if (self.movetype == MOVETYPE_FLY)
- {
- // split acceleration in two to improve responsiveness -- CEV
- PM_SetNoClipFlags ();
- makevectors (input_angles);
- wishvel = v_forward * input_movevalues_x;
- wishvel += v_right * input_movevalues_y;
- wishvel += v_up * input_movevalues_z;
- PM_NoClipAccelerate (wishvel, 1.0f, half_time);
-
- // step if nostep is false...
- if (world_nostep == FALSE)
- {
- // ... and either airstep is true or we're onground
- if (world_airstep == TRUE)
- self.pm_flags |= PMF_SLIDE_STEP;
- else if (self.pm_flags & PMF_ONGROUND)
- self.pm_flags |= PMF_SLIDE_STEP;
- }
-
- if (self.velocity != '0 0 0')
- PM_CheckVelocity ();
-
- PM_DanceMove ();
+#define PM_MOVE_MOVETYPES_WALKACCELERATE(move_time) \
+{ \
+ accel = friction = speed1 = temp = 0; \
+ /* priority and sequence of these checks is important -- CEV */ \
+ if (self.pm_flags & PMF_ONGROUND) \
+ { \
+ if (self.pm_flags & PMF_ONSLICK) \
+ { \
+ /* ice physics; friction remains 0 -- CEV */ \
+ wishnew = min (wishspeed, PM_MAXSPEED); \
+ if (wishspeed) \
+ accel = PM_SLICKACCEL; \
+ } \
+ else if (self.pm_flags & PMF_CROUCHSLIDE) \
+ { \
+ /* movement while crouchsliding -- CEV */ \
+ wishnew = min (wishspeed, PM_CROUCHSPEED); \
+ /* water level adds extra friction -- CEV */ \
+ friction = PM_SLIDEFRICTION + self.conlevel; \
+ if (wishspeed) { \
+ if (fabs(wishyaw) == 90) \
+ { \
+ /* Q1 air accel -- CEV */ \
+ /* same behavior as when in the air -- CEV */ \
+ accel = PM_SLIDEACCELY; \
+ wishnew = min (wishspeed, PM_MAXAIRSPEED); \
+ } \
+ else if (wishyaw == 0) \
+ { \
+ /* CPM / Painkiller style control -- CEV */ \
+ if (wishvel * self.velocity < 0) \
+ accel = PM_AIRACCELXBACK; \
+ else \
+ accel = PM_AIRACCELXFWD; \
+ } \
+ else \
+ { \
+ /* regular ground accel -- CEV */ \
+ accel = PM_SLIDEACCELXY; \
+ } } \
+ } \
+ else \
+ { \
+ /* movement onground -- CEV */ \
+ if (self.pm_flags & PMF_STEPPED) \
+ /* changing the friction constant is sketchy;
+ * it might help with navigating stairs */ \
+ friction = PM_GROUNDFRICTION * 0.1f; \
+ else \
+ friction = PM_GROUNDFRICTION; \
+ if (wishspeed) \
+ { \
+ if (self.pm_timer > 0) \
+ { \
+ /* go directly to PM_MAXWISHSPEED
+ * for stairjumps -- CEV */ \
+ wishnew = PM_MAXWISHSPEED; \
+ } \
+ else \
+ { \
+ if (self.pm_flags & PMF_CROUCHED) \
+ temp = PM_CROUCHSPEED; \
+ else if (self.pm_flags & PMF_WALK_HELD)\
+ temp = PM_WALKSPEED; \
+ else \
+ temp = PM_MAXSPEED; \
+ wishnew = min (wishspeed, temp); \
+ } \
+ if (self.pm_flags & PMF_STEPPED) \
+ accel = PM_GROUNDACCEL * 0.1f; \
+ else \
+ accel = PM_GROUNDACCEL; \
+ } \
+ } \
+ } \
+ else if (self.pm_flags & PMF_ONSLOPE) \
+ { \
+ /* movement while surfing -- CEV */ \
+ if (wishspeed) \
+ { \
+ if (wishyaw == 45 || wishyaw == 135) \
+ { \
+ /* Q3 accel -- CEV */ \
+ accel = PM_SURFACCELXY; \
+ wishnew = min (wishspeed, PM_MAXSPEED); \
+ } \
+ else \
+ { \
+ /* Q1 air accel -- CEV */ \
+ accel = PM_SURFACCELY; \
+ wishnew = min (wishspeed, PM_MAXAIRSPEED); \
+ } \
+ } \
+ } \
+ else if (wishspeed) \
+ { \
+ /* movement in the air -- CEV */ \
+ if (fabs(wishyaw) == 90) \
+ { \
+ /* Q1 air accel -- CEV */ \
+ if (wishyaw < 0) { \
+ if (self.speed < PM_MAXSPEED) \
+ { \
+ /* if player is holding +fwd / +back and
+ * they're below MAXSPEED then nudge them
+ * towards wishdir -- CEV */ \
+ wishnew = min (wishspeed, PM_MAXSPEED); \
+ accel = PM_AIRACCELXY; \
+ PM_ACCELERATE (wishdir, wishnew, speed1, \
+ temp, accel, move_time) \
+ } } \
+ accel = PM_AIRACCELY; \
+ wishnew = min (wishspeed, PM_MAXAIRSPEED); \
+ } \
+ else \
+ { \
+ wishnew = min (wishspeed, PM_MAXSPEED); \
+ /* apply a penalty to wishspeed if player is holding
+ * jump (simulating PM_CmdScale behavior in Quake 3)
+ * -- CEV */ \
+ if (self.pm_flags & PMF_JUMP_HELD) { \
+ /*
+ if (!(self.pm_flags & PMF_DOUBLEJUMPED)) \
+ { \
+ */ \
+ /* scale in Q3 is 2.519685 when not holding
+ * jump, 1.781686 when holding jump. 1.78 is
+ * roughly 70% of 2.51. -- CEV */ \
+ wishnew *= (0.7f + (0.3f * \
+ (1 - (self.pm_timer / \
+ PM_DOUBLEJUMP_WINDOW)))); \
+ /* } */ } \
+ if (wishyaw == 0) \
+ { \
+ /* CPM / Painkiller air control -- CEV */ \
+ if (wishvel * self.velocity < 0) \
+ accel = PM_AIRACCELXBACK; \
+ else \
+ accel = PM_AIRACCELXFWD; \
+ } \
+ else \
+ { \
+ /* X and Y in the air: strafejumping -- CEV */ \
+ accel = PM_AIRACCELXY; \
+ } \
+ } \
+ } \
+ if (friction > 0) \
+ { \
+ /* standard Quake friction -- CEV */ \
+ PM_FRICTION (speed1, temp, friction, move_time) \
+ } \
+ if (accel) \
+ { \
+ /* standard Quake ground accel function -- CEV */ \
+ PM_ACCELERATE (wishdir, wishnew, speed1, temp, accel, \
+ move_time) \
+ } \
+ if (wishspeed) { \
+ if (wishyaw == 0 || wishyaw == 180) \
+ { \
+ PM_AIRCONTROL (wishdir, wishnew, speed1, temp, friction, \
+ accel, move_time) \
+ } } \
+}

- // note that the v_ vectors may have changed in the move -- CEV
- PM_NoClipAccelerate (wishvel, 1.0f, half_time);
+//----------------------------------------------------------------------
+// PM_MOVE_MOVETYPES_MANAGETIMER
+// self.pm_timer is pos when jumping, neg when crouchsliding -- CEV
+//----------------------------------------------------------------------
+#define PM_MOVE_MOVETYPES_MANAGETIMER(adjust_time) \
+{ \
+ if (self.pm_timer) \
+ { \
+ if (self.pm_flags & PMF_CROUCHSLIDE) \
+ { \
+ self.pm_timer += adjust_time; \
+ if (self.pm_timer >= 0) \
+ self.pm_timer = 0; \
+ } \
+ else \
+ { \
+ self.pm_timer -= adjust_time; \
+ if (self.pm_timer <= 0) \
+ self.pm_timer = 0; \
+ } \
+ } \
+ if (self.pm_flags & PMF_CROUCHSLIDE) \
+ { \
+ if (self.pm_timer >= 0) \
+ PM_CrouchSlideStop (); \
+ } \
+ if (self.pm_flags & PMF_DOUBLEJUMPED) \
+ { \
+ if (self.pm_timer <= 0) \
+ self.pm_flags &= ~PMF_DOUBLEJUMPED; \
+ } \
+}

- touchtriggers ();
- base_entity_positioncontents (self);
- }
- else if (self.movetype == MOVETYPE_NOCLIP)
- {
- // noclip is a debugging feature, no need to
- // worry about acceleration consistency -- CEV
- PM_SetNoClipFlags ();
- makevectors (input_angles);
- wishvel = v_forward * input_movevalues_x;
- wishvel += v_right * input_movevalues_y;
- 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;
- }
+//----------------------------------------------------------------------
+// PM_MOVE_PRE -- prepare to move the player -- CEV
+//----------------------------------------------------------------------
+#define PM_MOVE_PRE() \
+{ \
+ /* 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 == FALSE) \
+ { \
+ PM_Nudge (); \
+ } \
+ /* truncate velocity to network precision -- CEV */ \
+ if (self.velocity != '0 0 0') \
+ { \
+ PM_TRUNCATEVECTORTOEIGTH (self.velocity); \
+ } \
+ /* clear JUMP_HELD if it's set and the user isn't pressing jump */ \
+ if (!(input_buttons & PM_BTN_JUMP)) \
+ { \
+ self.pm_flags &= ~PMF_JUMP_HELD; \
+ } \
+ /* crouch key, crouchsliding -- CEV */ \
+ if (input_buttons & PM_BTN_DOWN) \
+ { \
+ self.pm_flags |= PMF_CROUCH_HELD; \
+ } \
+ else \
+ { \
+ self.pm_flags &= ~PMF_CROUCH_HELD; \
+ if (self.pm_flags & PMF_CROUCHSLIDE) \
+ PM_CrouchSlideStop (); \
+ } \
+ /* walk key, walking -- CEV */ \
+ if (input_buttons & PM_BTN_WALK) \
+ { \
+ self.pm_flags |= PMF_WALK_HELD; \
+ } \
+ else \
+ { \
+ self.pm_flags &= ~PMF_WALK_HELD; \
+ } \
+}

- if (self.velocity != '0 0 0')
- {
- PM_CheckVelocity ();
- self.velocity = PM_TruncateVectorToEighth (self.velocity);
- }
+//----------------------------------------------------------------------
+// PM_MOVE_MOVETYPES
+//----------------------------------------------------------------------
+#define PM_MOVE_MOVETYPES() \
+{ \
+ local vector wishdir, wishvel; \
+ local float speed1, temp, wishspeed, wishyaw, wishyawdiff; \
+ wishdir = wishvel = '0 0 0'; \
+ speed1 = temp = wishspeed = wishyaw = wishyawdiff = 0; \
+ self.speed = vlen ([self.velocity.x, self.velocity.y, 0]); \
+ if (self.movetype == MOVETYPE_NOCLIP) \
+ { \
+ PM_MOVE_MOVETYPES_SETNOCLIPFLAGS () \
+ makevectors (input_angles); \
+ wishvel = v_forward * input_movevalues.x; \
+ wishvel += v_right * input_movevalues.y; \
+ wishvel += v_up * input_movevalues.z; \
+ PM_MOVE_MOVETYPES_NOCLIPACCELERATE (input_timelength) \
+ /* we're noclipping so update origin directly -- CEV */ \
+ self.origin += self.velocity * input_timelength; \
+ } \
+ else \
+ { \
+ /* the following vars will be used in macros below */ \
+ local vector vec1, vec2; \
+ local float accel, friction, half_time, wishnew; \
+ vec1 = vec2 = '0 0 0'; \
+ accel = friction = wishnew = 0; \
+ half_time = input_timelength * 0.5f; \
+ if (self.movetype == MOVETYPE_WALK) \
+ { \
+ /* work out the properties of the player's position */ \
+ PM_MOVE_MOVETYPES_CATEGORIZEPOSITION () \
+ if (self.conlevel < WATERLEVEL_WAIST) \
+ { \
+ /* intended movement for walking/air accel */ \
+ /* only yaw matters here -- CEV */ \
+ makevectors (input_angles.y * '0 1 0'); \
+ wishvel = v_forward * input_movevalues.x + \
+ v_right * input_movevalues.y; \
+ wishvel.z = 0; \
+ wishdir = normalize (wishvel); \
+ wishspeed = vlen (wishvel); \
+ /* walking & air acceleration -- CEV */ \
+ PM_MOVE_MOVETYPES_WALKPREMOVE () \
+ PM_MOVE_MOVETYPES_WALKACCELERATE (half_time) \
+ } \
+ else \
+ { \
+ /* work out intended movement for swimming */ \
+ makevectors (input_angles); \
+ wishvel = v_forward * input_movevalues.x + \
+ v_right * input_movevalues.y + \
+ v_up * input_movevalues.z; \
+ wishdir = normalize (wishvel); \
+ wishspeed = vlen (wishvel); \
+ /* swim acceleration -- CEV */ \
+ PM_MOVE_MOVETYPES_SWIMPREMOVE (vec1, vec2, \
+ half_time) \
+ PM_MOVE_MOVETYPES_SWIMACCELERATE (half_time) \
+ } \
+ /* handle countdown timers -- CEV */ \
+ PM_MOVE_MOVETYPES_MANAGETIMER (half_time) \
+ } \
+ else if (self.movetype == MOVETYPE_FLY) \
+ { \
+ PM_MOVE_MOVETYPES_SETNOCLIPFLAGS () \
+ makevectors (input_angles); \
+ wishvel = v_forward * input_movevalues.x; \
+ wishvel += v_right * input_movevalues.y; \
+ wishvel += v_up * input_movevalues.z; \
+ PM_MOVE_MOVETYPES_NOCLIPACCELERATE (half_time) \
+ } \
+ /* step if nostep is false and we're not on a ladder... */ \
+ if (world_nostep == FALSE) { \
+ if (!(self.pm_flags & PMF_ONLADDER)) \
+ { \
+ /* ... and either airstep is true or we're onground */ \
+ if (world_airstep == TRUE) \
+ self.pm_flags |= PMF_SLIDE_STEP; \
+ else if (self.pm_flags & PMF_ONGROUND) \
+ self.pm_flags |= PMF_SLIDE_STEP; \
+ } } \
+ /* bound velocity to fixed server maximums -- CEV */ \
+ if (self.velocity != '0 0 0') \
+ { \
+ PM_CHECKVELOCITY (self.velocity) \
+ } \
+ /* Do the move. Bounce, Rock, Skate, Roll -- CEV */ \
+ PM_DANCEMOVE (vec1, vec2, accel, friction, temp) \
+ /* now the back half of player acceleration -- CEV */ \
+ if (self.movetype == MOVETYPE_WALK) \
+ { \
+ if (self.conlevel < WATERLEVEL_WAIST) \
+ { \
+ PM_MOVE_MOVETYPES_WALKACCELERATE (half_time) \
+ } \
+ else \
+ { \
+ PM_MOVE_MOVETYPES_SWIMACCELERATE (half_time) \
+ } \
+ PM_MOVE_MOVETYPES_MANAGETIMER (half_time) \
+ } \
+ else if (self.movetype == MOVETYPE_FLY) \
+ { \
+ PM_MOVE_MOVETYPES_NOCLIPACCELERATE (half_time) \
+ } \
+ /* clear ladder flag -- CEV */ \
+ if (self.pm_flags & PMF_ONLADDER) \
+ self.pm_flags &= ~PMF_ONLADDER; \
+ touchtriggers (); \
+ base_entity_positioncontents (self); \
+ } \
+}

- self.speed = vlen ([self.velocity_x, self.velocity_y, 0]);
- setorigin (self, self.origin);
- self.oldorigin = self.origin;
+//----------------------------------------------------------------------
+// PM_MOVE_POST -- handle any after-move operations -- CEV
+//
+// If we have velocity then restrict it to server maximums and truncate
+// it to network precision -- CEV
+// Then udpate speed, origin, and oldorigin -- CEV
+//----------------------------------------------------------------------
+#define PM_MOVE_POST() \
+{ \
+ if (self.velocity != '0 0 0') \
+ { \
+ PM_CHECKVELOCITY (self.velocity) \
+ PM_TRUNCATEVECTORTOEIGTH (self.velocity) \
+ } \
+ self.speed = vlen ([self.velocity.x, self.velocity.y, 0]); \
+ setorigin (self, self.origin); \
+ self.oldorigin = self.origin; \
+}

- // restore self just in case -- CEV
- self = oself;
-};
#endif

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

Diff qc/sv_entry.qc

diff --git a/qc/sv_entry.qc b/qc/sv_entry.qc
index f672ae2..d8bb186 100644
--- a/qc/sv_entry.qc
+++ b/qc/sv_entry.qc
@@ -18,6 +18,11 @@ float framecount;

nosave float clean_up_client_stuff;
nosave float gamestarted;
+
+// Reports which ssqc entnum was hit when a csqc traceline impacts an
+// ssqc-based brush entity.
+// Only active in CSQC but needed here to compile pmove. -- CEV
+nosave float trace_networkentity;
#endif

//======================================================================
@@ -836,7 +841,9 @@ void() PlayerPreThink =
void() SV_RunClientCommand =
{
// see pmove.qc -- CEV
- PM_Move (self);
+ PM_MOVE_PRE ()
+ PM_MOVE_MOVETYPES ()
+ PM_MOVE_POST ()
};

//----------------------------------------------------------------------
@@ -863,19 +870,20 @@ void() StartFrame =
teamplay = cvar ("teamplay");
skill = cvar ("skill");

- framecount = framecount + 1;
-
if (clean_up_client_stuff)
{
clean_up_client_stuff -= 1;
RestartLoopSounds ();
}
- else if (!gamestarted && framecount > 2)
+ else if (!gamestarted)
{
- if (framecount != 3)
- clean_up_client_stuff += 2;
+ if (framecount > 2)
+ {
+ if (framecount != 3)
+ clean_up_client_stuff += 2;

- gamestarted = TRUE;
+ gamestarted = TRUE;
+ }
}

/*

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

Diff qc/sv_progs.src

diff --git a/qc/sv_progs.src b/qc/sv_progs.src
index a662686..90ae81c 100644
--- a/qc/sv_progs.src
+++ b/qc/sv_progs.src
@@ -21,7 +21,6 @@ defs_ctypes.qc // global class list
//----------------------------------------------------------------------
math.qc // Code by Joshua Skelton + misc
newflags.qc // new spawnflags for all entities
-cshift.qc // background color shift controller
keylock.qc // common code for entities unlockable with keys
custom_snd.qc // mapper-settable sound FX for monsters - iw
custom_mdls.qc // mapper-settable models for monsters - iw
@@ -86,6 +85,7 @@ items/backpacks.qc // backpack code; was in items.qc
cutscene.qc // Drake version -- dumptruck_ds
obituary.qc // ClientObituary
pmove.qc // QC player movement code -- CEV
+cshift.qc // background color shift controller

//----------------------------------------------------------------------
// monster entities

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 5391bb6..ff816f5 100644
--- a/qc/triggers/ladder.qc
+++ b/qc/triggers/ladder.qc
@@ -62,6 +62,13 @@ Keys:
self.movedir_z = ReadShort () * (360 / 32767);
}

+ if (netflags & BASE_TRIGGER_NET_ANGLES)
+ {
+ self.angles_x = ReadAngle ();
+ self.angles_y = ReadAngle ();
+ self.angles_z = ReadAngle ();
+ }
+
if (netflags & BASE_TRIGGER_NET_ESTATE)
self.estate = ReadFloat ();

@@ -108,6 +115,13 @@ Keys:
WriteShort (MSG_ENTITY, self.movedir_z * (32767 / 360));
}

+ if (netflags & BASE_TRIGGER_NET_ANGLES)
+ {
+ WriteAngle (MSG_ENTITY, self.angles_x);
+ WriteAngle (MSG_ENTITY, self.angles_y);
+ WriteAngle (MSG_ENTITY, self.angles_z);
+ }
+
if (netflags & BASE_TRIGGER_NET_ESTATE)
WriteFloat (MSG_ENTITY, self.estate);

@@ -177,9 +191,9 @@ Keys:
e.SendEntity = trigger_ladder_netsend;
e.SendFlags |= BASE_TRIGGER_NET_ORIGIN |
BASE_TRIGGER_NET_SIZE |
- BASE_TRIGGER_NET_ESTATE;
- if (e.movedir)
- e.SendFlags |= BASE_TRIGGER_NET_MOVEDIR;
+ BASE_TRIGGER_NET_ESTATE |
+ BASE_TRIGGER_NET_ANGLES |
+ BASE_TRIGGER_NET_MOVEDIR;
#endif
};
#endif

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

Diff qc/world.qc

diff --git a/qc/world.qc b/qc/world.qc
index 549b886..a034ec6 100644
--- a/qc/world.qc
+++ b/qc/world.qc
@@ -89,8 +89,8 @@ void() world_latched_cvars =
world_nostep = autocvar (pm_nostep, FALSE);
world_walljump = autocvar (pm_walljump, TRUE);

- world_clforwardspeed = autocvar (cl_forwardspeed, PM_RUNSPEED);
- world_clsidespeed = autocvar (cl_sidespeed, PM_RUNSPEED);
+ world_clforwardspeed = autocvar (cl_forwardspeed, PM_MAXSPEED);
+ world_clsidespeed = autocvar (cl_sidespeed, PM_MAXSPEED);
};
#endif

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