djcev.com

//

Git Repos / fte_dogmode / commit 6d390b9

Commit: 6d390b97ae7cfb400f697f93b7b83be01a2420a3
Parent: f9955e96a17aa1fc020faf245f03f58b21c9f75b
Author: Cameron Vanderzanden, 2023-10-13 12:38
Committer: Cameron Vanderzanden, 2023-10-13 12:38

Commit Message

Import of an old patch to ironwail, no longer used

This is an old patch to ironwail 0.7.0 that (along with some
QC code) implements some CPM-like movement. This was a previous
attempt at adding new movement that had many disadvantages
(first among them the fact that I don't want to maintain an
engine or engine patches). I've added the patch to this repo
in case I need it in the future for some reason.

Will need to add a readme to go with the patch that explains this.

Change List

Diff engine-patches/ironwail-0.7.0_dogmode-0.1.patch

diff --git a/engine-patches/ironwail-0.7.0_dogmode-0.1.patch b/engine-patches/ironwail-0.7.0_dogmode-0.1.patch
new file mode 100644
index 0000000..8bd2e62
--- /dev/null
+++ b/engine-patches/ironwail-0.7.0_dogmode-0.1.patch
@@ -0,0 +1,577 @@
+diff -Nur ironwail-0.7.0-orig/Quake/sv_main.c ironwail-0.7.0-hacked/Quake/sv_main.c
+--- ironwail-0.7.0-orig/Quake/sv_main.c 2023-03-17 10:53:47.000000000 -0700
++++ ironwail-0.7.0-hacked/Quake/sv_main.c 2023-04-23 18:59:23.484887000 -0700
+@@ -35,6 +35,8 @@
+
+ static cvar_t sv_netsort = {"sv_netsort", "1", CVAR_NONE};
+
++void CEV_Callback_Dogmode (cvar_t *var); // this shouldn't be here CEV
++
+ //============================================================================
+
+ void SV_CalcStats(client_t *client, int *statsi, float *statsf, const char **statss)
+@@ -146,6 +148,9 @@
+ extern cvar_t sv_maxvelocity;
+ extern cvar_t sv_gravity;
+ extern cvar_t sv_nostep;
++ // are you playing those dog maps again? CEV
++ extern cvar_t sv_dogmode;
++ extern cvar_t sv_q3airaccelerate;
+ extern cvar_t sv_freezenonclients;
+ extern cvar_t sv_friction;
+ extern cvar_t sv_edgefriction;
+@@ -173,6 +178,9 @@
+ Cvar_RegisterVariable (&sv_idealpitchscale);
+ Cvar_RegisterVariable (&sv_aim);
+ Cvar_RegisterVariable (&sv_nostep);
++ Cvar_RegisterVariable (&sv_dogmode);
++ Cvar_SetCallback (&sv_dogmode, CEV_Callback_Dogmode);
++ Cvar_RegisterVariable (&sv_q3airaccelerate);
+ Cvar_RegisterVariable (&sv_freezenonclients);
+ Cvar_RegisterVariable (&pr_checkextension);
+ Cvar_RegisterVariable (&sv_altnoclip); //johnfitz
+diff -Nur ironwail-0.7.0-orig/Quake/sv_phys.c ironwail-0.7.0-hacked/Quake/sv_phys.c
+--- ironwail-0.7.0-orig/Quake/sv_phys.c 2023-03-17 10:53:47.000000000 -0700
++++ ironwail-0.7.0-hacked/Quake/sv_phys.c 2023-04-23 18:59:12.342461000 -0700
+@@ -46,6 +46,7 @@
+ cvar_t sv_gravity = {"sv_gravity","800",CVAR_NOTIFY|CVAR_SERVERINFO};
+ cvar_t sv_maxvelocity = {"sv_maxvelocity","2000",CVAR_NONE};
+ cvar_t sv_nostep = {"sv_nostep","0",CVAR_NONE};
++cvar_t sv_dogmode = {"sv_dogmode","0",CVAR_NONE};
+ cvar_t sv_freezenonclients = {"sv_freezenonclients","0",CVAR_NONE};
+
+
+@@ -795,6 +796,433 @@
+
+ /*
+ =====================
++CEV_Callback_Dogmode
++
++When dogmode is flipped on set a default q3airaccelerate value
++=====================
++*/
++void CEV_Callback_Dogmode (cvar_t *var)
++{
++ if (var->value)
++ // 0.275 feels right to me. the fact that it's a
++ // weird value like that probably means something
++ // has gone wrong somewhere. CEV
++ Cvar_SetValue ("sv_q3airaccelerate", 0.275);
++ else
++ Cvar_SetValue ("sv_q3airaccelerate", 0);
++}
++
++/*
++=====================
++VectorNormalize2
++
++Added by CEV to support SlideMove below. I'm sure there's an easy way
++to do this without implementing Normalize2 but here we are.
++=====================
++*/
++vec_t VectorNormalize2(const vec3_t in, vec3_t out)
++{
++ vec_t length, ilength;
++
++ length = sqrt (in[0]*in[0] + in[1]*in[1] + in[2]*in[2]);
++ if (length == 0)
++ {
++ VectorCopy (vec3_origin, out);
++ return 0;
++ }
++
++ ilength = 1.0/length;
++ out[0] = in[0]*ilength;
++ out[1] = in[1]*ilength;
++ out[2] = in[2]*ilength;
++
++ return length;
++}
++
++/*
++=====================
++CEV_SetOnGround
++
++Set onground flag & return true if player is now on ground
++=====================
++*/
++qboolean CEV_SetOnGround (edict_t *ent, trace_t *downtrace)
++{
++ if (downtrace->plane.normal[2] > 0.7)
++ {
++ // removed this check so that player can walk on monsters
++ // if (downtrace->ent->v.solid == SOLID_BSP)
++ // {
++ ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
++ ent->v.groundentity = EDICT_TO_PROG(downtrace->ent);
++ return true;
++ // }
++ }
++ else
++ {
++ ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
++ return false;
++ }
++}
++
++/*
++=====================
++CEV_SlideMove
++
++A backport of Quake 3's PM_SlideMove into Quake 1. Does not handle timers
++or gravity like Q3's version does.
++
++Returns the clipflags if the velocity was modified (similar to FlyMove)
++1 = floor
++2 = wall / step
++4 = dead stop
++8 = hit a non-axial plane
++If steptrace is not NULL, the trace of any vertical wall hit will be stored
++if groundtrace is not NULL, store the trace of last ground plane we encounter
++=====================
++*/
++#define Q3_OVERCLIP 1.001f
++#define Q3_STEPSIZE 18
++#define CEV_MAX_CLIP_PLANES 5
++extern cvar_t developer;
++int CEV_SlideMove (edict_t *ent, float time, trace_t *steptrace, trace_t *groundtrace)
++{
++ int bumpcount, numbumps;
++ vec3_t dir;
++ float d;
++ int numplanes;
++ vec3_t planes[CEV_MAX_CLIP_PLANES];
++ vec3_t clip_velocity;
++ int i, j, k;
++ trace_t trace;
++ vec3_t end;
++ float time_left;
++ int blocked;
++
++ time_left = time;
++ numplanes = 0;
++ numbumps = 4;
++ blocked = 0;
++
++ // never turn against original velocity
++ VectorNormalize2 (ent->v.velocity, planes[numplanes]);
++ numplanes++;
++
++ for (bumpcount=0; bumpcount < numbumps; bumpcount++)
++ {
++ VectorMA (ent->v.origin, time_left, ent->v.velocity, end);
++ trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, false, ent);
++
++ if (trace.allsolid)
++ {
++ // entity is trapped in another solid
++ if (developer.value)
++ Con_Printf ("CEV_SlideMove: entity trapped in another solid\n");
++ ent->v.velocity[2] = 0;
++ if (steptrace)
++ *steptrace = trace;
++ return 3;
++ }
++
++ if (trace.fraction > 0)
++ // covered some distance
++ VectorCopy (trace.endpos, ent->v.origin);
++
++ if (trace.fraction == 1)
++ // moved the entire distance
++ break;
++
++ if (trace.plane.normal[2] > 0.7)
++ {
++ // found the floor (?)
++ blocked |= 1;
++ if (groundtrace) *groundtrace = trace;
++ }
++
++ if (!trace.plane.normal[2])
++ // step or wall
++ blocked |= 2;
++
++ if (!trace.ent)
++ Sys_Error ("CEV_SlideMove: !trace.ent");
++
++ // run the impact function
++ SV_Impact (ent, trace.ent);
++ if (ent->free)
++ // removed by the impact function
++ break;
++
++ time_left -= time_left * trace.fraction;
++
++ // comment from Q3 source: if this is the same plane we
++ // hit before, nudge velocity out along it, which fixes
++ // some epsilon issues with non-axial planes
++ for (i = 0; i < numplanes; i++)
++ {
++ if (DotProduct (trace.plane.normal, planes[i]) > 0.99)
++ {
++ // this seems to happen fairly often on uneven
++ // ground or complicated geometry.
++ if (developer.value)
++ Con_Printf ("CEV_SlideMove: non-axial plane: %f\n", DotProduct (trace.plane.normal, planes[i]));
++ VectorAdd (trace.plane.normal, ent->v.velocity, ent->v.velocity);
++ // set a blocked flag so StepSlideMove knows
++ // to try the move again one stepheight up
++ blocked |= 8;
++ break;
++ }
++ }
++
++ // found a repeated plane
++ if (i < numplanes) continue;
++
++ if (numplanes >= CEV_MAX_CLIP_PLANES)
++ {
++ // this shouldn't really happen
++ if (developer.value)
++ Con_Printf ("CEV_SlideMove: numplanes >= MAX_CLIP_PLANES\n");
++ VectorCopy (vec3_origin, ent->v.velocity);
++ if (steptrace)
++ *steptrace = trace;
++ return 3;
++ }
++
++ VectorCopy (trace.plane.normal, planes[numplanes]);
++ numplanes++;
++
++ // modify velocity so it parallels all of the clip planes
++ // find a plane that it enters
++ for (i = 0; i < numplanes; i++)
++ {
++ if (DotProduct (ent->v.velocity, planes[i]) >= 0.1)
++ {
++ // move doesn't interact with the plane
++ // if (developer.value)
++ // Con_Printf ("CEV_SlideMove: into >= 0.1\n");
++ continue;
++ }
++
++ // slide along the plane
++ ClipVelocity (ent->v.velocity, planes[i], clip_velocity, Q3_OVERCLIP);
++
++ // is there a second plane that the new move enters?
++ for (j = 0; j < numplanes; j++)
++ {
++ if (j == i) continue;
++ if (DotProduct (clip_velocity, planes[j]) >= 0.1)
++ // move doesn't interact with the plane
++ continue;
++
++ // try clipping the move to the plane
++ ClipVelocity (clip_velocity, planes[j], clip_velocity, Q3_OVERCLIP);
++ // see if it goes back into the first clip plane
++ // this seems to happen fairly often
++ if ( DotProduct( clip_velocity, planes[i] ) >= 0 )
++ continue;
++
++ // slide the original velocity along the crease
++ CrossProduct (planes[i], planes[j], dir);
++ VectorNormalize (dir);
++ d = DotProduct (dir, ent->v.velocity);
++ VectorScale (dir, d, clip_velocity);
++
++ // see if there is a third plane the move enters
++ for (k = 0; k < numplanes; k++)
++ {
++ if (k == i || k == j) continue;
++ if (DotProduct(clip_velocity, planes[k]) >= 0.1)
++ // doesn't interact with plane
++ continue;
++ // stop at a triple plane interaction
++ VectorCopy (vec3_origin, ent->v.velocity);
++ if (developer.value)
++ Con_Printf ("CEV_SlideMove: Stopped at a triple plane interaction\n");
++ if (steptrace)
++ *steptrace = trace;
++ return 7;
++ }
++ }
++
++ // if we have fixed all interaction, try another move
++ VectorCopy (clip_velocity, ent->v.velocity);
++ break;
++ }
++
++ }
++
++ // if ((developer.value) && (bumpcount > 1))
++ // Con_Printf ("CEV_SlideMove: bumps, planes: %i, %i\n", bumpcount, numplanes);
++ if (steptrace)
++ *steptrace = trace;
++ return blocked;
++}
++
++/*
++=====================
++CEV_StepSlideMove
++
++Based on Quake 3's PM_StepSlideMove. First attempt a SlideMove; if we're
++blocked by a step or wall, then attempt a second SlideMove one STEPHEIGHT
++up from where we started. Revert to the first slide move if there's a
++problem with the second.
++
++This can definitely be refactored or cut down or simplified. I'm storing
++some traces and/or values that I probably don't need to be. This could
++also be folded into / merged with CEV_WalkMove as that latter function
++isn't doing much right now.
++
++Returns clipflags from the SlideMove.
++=====================
++*/
++int CEV_StepSlideMove (edict_t *ent, float time, qboolean gravity)
++{
++ vec3_t start_o, start_v;
++ vec3_t first_o, first_v;
++ trace_t trace, first_trace, second_trace, first_ground, second_ground;
++ vec3_t up, down;
++ float stepsize;
++ int first_clip, second_clip;
++
++ first_clip = second_clip = 0;
++
++ VectorCopy (ent->v.origin, start_o);
++ VectorCopy (ent->v.velocity, start_v);
++
++ first_clip = CEV_SlideMove (ent, time, &first_trace, &first_ground);
++
++ if (!(first_clip & 2) && !(first_clip & 8))
++ {
++ // we got where we wanted to go first try
++ CEV_SetOnGround(ent, &first_ground);
++ return first_clip;
++ }
++
++ if ((int)sv_player->v.flags & FL_WATERJUMP)
++ {
++ if (developer.value)
++ Con_Printf ("CEV_StepSlideMove: FL_WATERJUMP\n");
++ return first_clip;
++ }
++
++ if (ent->v.movetype != MOVETYPE_WALK)
++ // gibbed by a trigger
++ return first_clip;
++
++ if (sv_nostep.value)
++ {
++ CEV_SetOnGround(ent, &first_ground);
++ return first_clip;
++ }
++
++ VectorCopy (ent->v.origin, first_o);
++ VectorCopy (ent->v.velocity, first_v);
++
++ // test the player position if they were a stepheight higher
++ VectorCopy (start_o, up);
++ up[2] += Q3_STEPSIZE;
++ trace = SV_Move (start_o, ent->v.mins, ent->v.maxs, up, false, ent);
++ if (trace.allsolid)
++ {
++ // can't step up
++ if (developer.value)
++ Con_Printf ("CEV_StepSlideMove: can't step up\n");
++ first_clip |= 2;
++ VectorCopy (first_trace.endpos, ent->v.origin);
++ if (first_trace.fraction < 1.0)
++ ClipVelocity (ent->v.velocity, first_trace.plane.normal, ent->v.velocity, Q3_OVERCLIP);
++ // should this be trace or first_trace or first_ground?
++ CEV_SetOnGround(ent, &first_ground);
++ return first_clip;
++ }
++
++ stepsize = trace.endpos[2] - start_o[2];
++ // try slidemove from this position (in air)
++ VectorCopy (trace.endpos, ent->v.origin);
++ VectorCopy (start_v, ent->v.velocity);
++
++ second_clip = CEV_SlideMove (ent, time, &second_trace, &second_ground);
++
++ // push down the final amount
++ VectorCopy (ent->v.origin, down);
++ down[2] -= stepsize;
++ trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, down, false, ent);
++
++ if (trace.allsolid)
++ {
++ if (developer.value)
++ Con_Printf ("CEV_StepSlideMove: rejecting second slide position\n");
++ // I'm pretty sure the behavior here is wrong but it
++ // seems to work so...
++ VectorCopy (start_o, ent->v.origin);
++ // CEV_SetOnGround(ent, &trace);
++ return 3;
++ }
++
++ if (trace.plane.normal[2] > 0.7)
++ {
++ // we're on "good ground", accept the second slide move
++ VectorCopy (trace.endpos, ent->v.origin);
++ if (trace.fraction < 1.0)
++ ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, Q3_OVERCLIP);
++ CEV_SetOnGround (ent, &trace);
++ return second_clip;
++ }
++ else
++ {
++ // not on "good ground", revert to first slide move.
++ // See the similar section of SV_WalkMove.
++ if (developer.value)
++ Con_Printf ("CEV_StepSlideMove: reverting to first SlideMove\n");
++ VectorCopy (first_trace.endpos, ent->v.origin);
++ if (first_trace.fraction < 1.0)
++ ClipVelocity (ent->v.velocity, first_trace.plane.normal, ent->v.velocity, Q3_OVERCLIP);
++ CEV_SetOnGround (ent, &first_ground);
++ return first_clip;
++ }
++}
++
++/*
++=====================
++CEV_WalkMove
++
++Alternate WalkMove for use by players. At this point largely a wrapper
++around StepSlideMove.
++=====================
++*/
++void CEV_WalkMove (edict_t *ent)
++{
++ vec3_t start_o, start_v;
++ float stepsize;
++ int start_onground;
++ int clip;
++
++ VectorCopy (ent->v.origin, start_o);
++ VectorCopy (ent->v.velocity, start_v);
++ start_onground = (int)ent->v.flags & FL_ONGROUND;
++ ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
++
++ clip = CEV_StepSlideMove (ent, host_frametime, true);
++
++ // this is a complicated check.
++ // if we started in the air and we're now on the ground
++ // and we were moving upward at the start of the move
++ // and the move has resulted in a near complete loss of
++ // Z velocity then we've clipped to ground on a step up.
++ if (!start_onground && (int)ent->v.flags & FL_ONGROUND)
++ {
++ if (start_v[2] > ent->v.velocity[2])
++ if (ent->v.velocity[2] < 1)
++ {
++ stepsize = ent->v.origin[2] - start_o[2];
++ ent->v.flags = (int)ent->v.flags | FL_PARTIALGROUND;
++ if (developer.value)
++ Con_Printf ("CEV_WalkMove: clipped a step. size: %f\n", stepsize);
++ }
++ }
++}
++
++/*
++=====================
+ SV_WalkMove
+
+ Only used by players
+@@ -937,7 +1365,11 @@
+ if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) )
+ SV_AddGravity (ent);
+ SV_CheckStuck (ent);
+- SV_WalkMove (ent);
++ // TODO CEV
++ if (sv_dogmode.value)
++ CEV_WalkMove (ent);
++ else
++ SV_WalkMove (ent);
+ break;
+
+ case MOVETYPE_TOSS:
+diff -Nur ironwail-0.7.0-orig/Quake/sv_user.c ironwail-0.7.0-hacked/Quake/sv_user.c
+--- ironwail-0.7.0-orig/Quake/sv_user.c 2023-03-17 10:53:47.000000000 -0700
++++ ironwail-0.7.0-hacked/Quake/sv_user.c 2023-04-23 18:57:53.611293000 -0700
+@@ -182,6 +182,66 @@
+ velocity[i] += accelspeed*wishdir[i];
+ }
+
++/*
++============
++CEV_Q3CmdScale
++
++Taken from Quake3's bg_pmove.c . I don't exactly know what this does,
++but it seems to be necessary (from my experiments / playtesting) for
++Quake 3 strafejumping to feel correct.
++
++Comment from Quake 3 source:
++Returns the scale factor to apply to cmd movements
++This allows the clients to use axial -127 to 127 values for all directions
++without getting a sqrt(2) distortion in speed.
++============
++*/
++static float CEV_Q3CmdScale (float speed, usercmd_t *cmd)
++{
++ int max;
++ float total;
++ float scale;
++
++ max = fabsf (cmd->forwardmove);
++ if (fabsf(cmd->sidemove ) > max) {
++ max = fabsf (cmd->sidemove);
++ }
++ if (fabsf(cmd->upmove) > max) {
++ max = fabsf(cmd->upmove);
++ }
++ if (!max) {
++ return 0;
++ }
++
++ total = sqrt (cmd->forwardmove * cmd->forwardmove
++ + cmd->sidemove * cmd->sidemove + cmd->upmove * cmd->upmove);
++ scale = speed * max / (127.0 * total);
++
++ return scale;
++}
++
++// Q3's pm_airaccelerate is 1.0; set to 0 here to disable by default
++cvar_t sv_q3airaccelerate = {"sv_q3airaccelerate", "0", CVAR_NONE};
++void CEV_Q3AirAccelerate (float wishspeed, vec3_t wishdir, usercmd_t *cmd)
++{
++ float addspeed, accelspeed, currentspeed, scale;
++
++ currentspeed = DotProduct (velocity, wishdir);
++ scale = CEV_Q3CmdScale (currentspeed, cmd);
++ addspeed = wishspeed - currentspeed;
++ if (addspeed <= 0)
++ return;
++ // Q3 applies scale to wishspeed but for whatever reason that
++ // doesn't feel right to me in Q1. So I'm applying it to the
++ // accel constant here. This is probably the wrong thing to do.
++ // CEV
++ accelspeed = sv_q3airaccelerate.value * scale;
++ accelspeed = accelspeed * host_frametime * wishspeed;
++ if (accelspeed > addspeed)
++ accelspeed = addspeed;
++ VectorMA (velocity, accelspeed, wishdir, velocity);
++}
++
+ void SV_AirAccelerate (float wishspeed, vec3_t wishveloc)
+ {
+ int i;
+@@ -365,7 +425,15 @@
+ }
+ else
+ { // not on ground, so little effect on velocity
+- SV_AirAccelerate (wishspeed, wishvel);
++ // Q3 strafejumping when requesting both forward and side move
++ if ((sv_q3airaccelerate.value) && (fmove != 0) && (smove != 0))
++ {
++ CEV_Q3AirAccelerate (wishspeed, wishdir, &cmd);
++ }
++ else
++ {
++ SV_AirAccelerate (wishspeed, wishvel);
++ }
+ }
+ }
+

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