1
0
Fork 0
forked from fte/fteqw

portal tweaks. prediction code can now use portals, but cannot actually predict them yet, for a couple of reasons.

gravitydir on monsters should now be workable (qc needs to be careful with ideal_yaw, which is now relative to the gravitydir rather than the xy plane).
fix an issue where shaders were not loaded after gamedir switches.
added 6dof command (and player movetype).

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4689 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2014-06-21 17:58:17 +00:00
parent 49a04eacae
commit ed54ed2dcf
29 changed files with 811 additions and 307 deletions

View file

@ -39,6 +39,7 @@ cvar_t cl_queueimpulses = CVAR("cl_queueimpulses", "0");
cvar_t cl_smartjump = CVAR("cl_smartjump", "1");
cvar_t cl_run = CVARD("cl_run", "0", "Enables autorun, inverting the state of the +speed key.");
cvar_t cl_fastaccel = CVARD("cl_fastaccel", "1", "Begin moving at full speed instantly, instead of waiting a frame or so.");
extern cvar_t cl_rollspeed;
cvar_t cl_prydoncursor = CVAR("cl_prydoncursor", ""); //for dp protocol
cvar_t cl_instantrotate = CVARF("cl_instantrotate", "1", CVAR_SEMICHEAT);
@ -143,7 +144,7 @@ kbutton_t in_mlook, in_klook;
kbutton_t in_left, in_right, in_forward, in_back;
kbutton_t in_lookup, in_lookdown, in_moveleft, in_moveright;
kbutton_t in_strafe, in_speed, in_use, in_jump, in_attack;
kbutton_t in_up, in_down;
kbutton_t in_rollleft, in_rollright, in_up, in_down;
kbutton_t in_button3, in_button4, in_button5, in_button6, in_button7, in_button8;
@ -252,6 +253,10 @@ void IN_MoveleftDown(void) {KeyDown(&in_moveleft);}
void IN_MoveleftUp(void) {KeyUp(&in_moveleft);}
void IN_MoverightDown(void) {KeyDown(&in_moveright);}
void IN_MoverightUp(void) {KeyUp(&in_moveright);}
void IN_RollLeftDown(void) {KeyDown(&in_rollleft);}
void IN_RollLeftUp(void) {KeyUp(&in_rollleft);}
void IN_RollRightDown(void) {KeyDown(&in_rollright);}
void IN_RollRightUp(void) {KeyUp(&in_rollright);}
void IN_SpeedDown(void) {KeyDown(&in_speed);}
void IN_SpeedUp(void) {KeyUp(&in_speed);}
@ -546,6 +551,10 @@ void CL_AdjustAngles (int pnum, double frametime)
cl.playerview[pnum].viewanglechange[PITCH] -= speed*quant * CL_KeyState (&in_forward, pnum, false);
cl.playerview[pnum].viewanglechange[PITCH] += speed*quant * CL_KeyState (&in_back, pnum, false);
}
quant = cl_rollspeed.ival;
cl.playerview[pnum].viewanglechange[ROLL] -= speed*quant * CL_KeyState (&in_rollleft, pnum, false);
cl.playerview[pnum].viewanglechange[ROLL] += speed*quant * CL_KeyState (&in_rollright, pnum, false);
up = CL_KeyState (&in_lookup, pnum, false);
down = CL_KeyState(&in_lookdown, pnum, false);
@ -604,15 +613,15 @@ void CL_ClampPitch (int pnum)
float roll;
static float oldtime;
float timestep = realtime - oldtime;
playerview_t *pv = &cl.playerview[pnum];
oldtime = realtime;
if (cl.intermission)
{
memset(cl.playerview[pnum].viewanglechange, 0, sizeof(cl.playerview[pnum].viewanglechange));
memset(pv->viewanglechange, 0, sizeof(pv->viewanglechange));
return;
}
#if 0
if (cl.pmovetype[pnum] == PM_WALLWALK)
if (pv->pmovetype == PM_6DOF)
{
vec3_t impact;
vec3_t norm;
@ -620,16 +629,20 @@ void CL_ClampPitch (int pnum)
vec3_t cross;
vec3_t view[4];
float dot;
AngleVectors(cl.viewangles[pnum], view[0], view[1], view[2]);
AngleVectors(pv->viewangles, view[0], view[1], view[2]);
Matrix4x4_RM_FromVectors(mat, view[0], view[1], view[2], vec3_origin);
Matrix4_Multiply(Matrix4x4_CM_NewRotation(-cl.viewanglechange[pnum][PITCH], 0, 1, 0), mat, mat2);
Matrix4_Multiply(Matrix4x4_CM_NewRotation(cl.viewanglechange[pnum][YAW], 0, 0, 1), mat2, mat);
Matrix4_Multiply(Matrix4x4_CM_NewRotation(-pv->viewanglechange[PITCH], 0, 1, 0), mat, mat2);
Matrix4_Multiply(Matrix4x4_CM_NewRotation(pv->viewanglechange[YAW], 0, 0, 1), mat2, mat);
#if 1
//roll angles
Matrix4_Multiply(Matrix4x4_CM_NewRotation(pv->viewanglechange[ROLL], 1, 0, 0), mat, mat2);
#else
//auto-roll
Matrix3x4_RM_ToVectors(mat, view[0], view[1], view[2], view[3]);
VectorMA(cl.simorg[pnum], -48, view[2], view[3]);
if (!TraceLineN(cl.simorg[pnum], view[3], impact, norm))
VectorMA(pv->simorg, -48, view[2], view[3]);
if (!TraceLineN(pv->simorg, view[3], impact, norm))
{
norm[0] = 0;
norm[1] = 0;
@ -641,17 +654,16 @@ void CL_ClampPitch (int pnum)
dot = DotProduct(view[0], cross);
roll = timestep * 360 * -(dot);
Matrix4_Multiply(Matrix4x4_CM_NewRotation(roll, 1, 0, 0), mat, mat2);
#endif
Matrix3x4_RM_ToVectors(mat2, view[0], view[1], view[2], view[3]);
VectorAngles(view[0], view[2], cl.viewangles[pnum]);
cl.viewangles[pnum][PITCH]=360 - cl.viewangles[pnum][PITCH];
VectorClear(cl.viewanglechange[pnum]);
VectorAngles(view[0], view[2], pv->viewangles);
pv->viewangles[PITCH]=360 - pv->viewangles[PITCH];
VectorClear(pv->viewanglechange);
return;
}
#endif
#if 1
if ((cl.playerview[pnum].gravitydir[2] != -1 || cl.playerview[pnum].viewangles[2]))
if ((pv->gravitydir[2] != -1 || pv->viewangles[2]))
{
float surfm[16], invsurfm[16];
float viewm[16];
@ -661,17 +673,17 @@ void CL_ClampPitch (int pnum)
void PerpendicularVector( vec3_t dst, const vec3_t src );
/*calc current view matrix relative to the surface*/
AngleVectors(cl.playerview[pnum].viewangles, view[0], view[1], view[2]);
AngleVectors(pv->viewangles, view[0], view[1], view[2]);
VectorNegate(view[1], view[1]);
/*calculate the surface axis with up from the pmove code and right/forwards relative to the player's directions*/
if (!cl.playerview[pnum].gravitydir[0] && !cl.playerview[pnum].gravitydir[1] && !cl.playerview[pnum].gravitydir[2])
if (!pv->gravitydir[0] && !pv->gravitydir[1] && !pv->gravitydir[2])
{
VectorSet(surf[2], 0, 0, 1);
}
else
{
VectorNegate(cl.playerview[pnum].gravitydir, surf[2]);
VectorNegate(pv->gravitydir, surf[2]);
}
VectorNormalize(surf[2]);
PerpendicularVector(surf[1], surf[2]);
@ -691,8 +703,8 @@ void CL_ClampPitch (int pnum)
vang[PITCH] *= -1;
/*edit it*/
vang[PITCH] += cl.playerview[pnum].viewanglechange[PITCH];
vang[YAW] += cl.playerview[pnum].viewanglechange[YAW];
vang[PITCH] += pv->viewanglechange[PITCH];
vang[YAW] += pv->viewanglechange[YAW];
if (vang[PITCH] <= -180)
vang[PITCH] += 360;
if (vang[PITCH] > 180)
@ -705,7 +717,7 @@ void CL_ClampPitch (int pnum)
/*keep the player looking relative to their ground (smoothlyish)*/
if (!vang[ROLL])
{
if (!cl.playerview[pnum].viewanglechange[PITCH] && !cl.playerview[pnum].viewanglechange[YAW] && !cl.playerview[pnum].viewanglechange[ROLL])
if (!pv->viewanglechange[PITCH] && !pv->viewanglechange[YAW] && !pv->viewanglechange[ROLL])
return;
}
else
@ -723,7 +735,7 @@ void CL_ClampPitch (int pnum)
vang[ROLL] += host_frametime*180;
}
}
VectorClear(cl.playerview[pnum].viewanglechange);
VectorClear(pv->viewanglechange);
/*clamp pitch*/
if (vang[PITCH] > cl.maxpitch)
vang[PITCH] = cl.maxpitch;
@ -741,19 +753,19 @@ void CL_ClampPitch (int pnum)
VectorAngles(view[0], view[2], cl.playerview[pnum].viewangles);
cl.playerview[pnum].viewangles[PITCH] *= -1;
if (cl.playerview[pnum].viewangles[ROLL] >= 360)
cl.playerview[pnum].viewangles[ROLL] -= 360;
if (cl.playerview[pnum].viewangles[ROLL] < 0)
cl.playerview[pnum].viewangles[ROLL] += 360;
if (cl.playerview[pnum].viewangles[PITCH] < -180)
cl.playerview[pnum].viewangles[PITCH] += 360;
if (pv->viewangles[ROLL] >= 360)
pv->viewangles[ROLL] -= 360;
if (pv->viewangles[ROLL] < 0)
pv->viewangles[ROLL] += 360;
if (pv->viewangles[PITCH] < -180)
pv->viewangles[PITCH] += 360;
return;
}
#endif
cl.playerview[pnum].viewangles[PITCH] += cl.playerview[pnum].viewanglechange[PITCH];
cl.playerview[pnum].viewangles[YAW] += cl.playerview[pnum].viewanglechange[YAW];
cl.playerview[pnum].viewangles[ROLL] += cl.playerview[pnum].viewanglechange[ROLL];
VectorClear(cl.playerview[pnum].viewanglechange);
pv->viewangles[PITCH] += pv->viewanglechange[PITCH];
pv->viewangles[YAW] += pv->viewanglechange[YAW];
pv->viewangles[ROLL] += pv->viewanglechange[ROLL];
VectorClear(pv->viewanglechange);
#ifdef Q2CLIENT
if (cls.protocol == CP_QUAKE2)
@ -763,15 +775,15 @@ void CL_ClampPitch (int pnum)
if (pitch > 180)
pitch -= 360;
if (cl.playerview[pnum].viewangles[PITCH] + pitch < -360)
cl.playerview[pnum].viewangles[PITCH] += 360; // wrapped
if (cl.playerview[pnum].viewangles[PITCH] + pitch > 360)
cl.playerview[pnum].viewangles[PITCH] -= 360; // wrapped
if (pv->viewangles[PITCH] + pitch < -360)
pv->viewangles[PITCH] += 360; // wrapped
if (pv->viewangles[PITCH] + pitch > 360)
pv->viewangles[PITCH] -= 360; // wrapped
if (cl.playerview[pnum].viewangles[PITCH] + pitch > cl.maxpitch)
cl.playerview[pnum].viewangles[PITCH] = cl.maxpitch - pitch;
if (cl.playerview[pnum].viewangles[PITCH] + pitch < cl.minpitch)
cl.playerview[pnum].viewangles[PITCH] = cl.minpitch - pitch;
if (pv->viewangles[PITCH] + pitch > cl.maxpitch)
pv->viewangles[PITCH] = cl.maxpitch - pitch;
if (pv->viewangles[PITCH] + pitch < cl.minpitch)
pv->viewangles[PITCH] = cl.minpitch - pitch;
}
else
#endif
@ -783,21 +795,21 @@ void CL_ClampPitch (int pnum)
else
#endif
{
if (cl.playerview[pnum].viewangles[PITCH] > cl.maxpitch)
cl.playerview[pnum].viewangles[PITCH] = cl.maxpitch;
if (cl.playerview[pnum].viewangles[PITCH] < cl.minpitch)
cl.playerview[pnum].viewangles[PITCH] = cl.minpitch;
if (pv->viewangles[PITCH] > cl.maxpitch)
pv->viewangles[PITCH] = cl.maxpitch;
if (pv->viewangles[PITCH] < cl.minpitch)
pv->viewangles[PITCH] = cl.minpitch;
}
// if (cl.viewangles[pnum][ROLL] > 50)
// cl.viewangles[pnum][ROLL] = 50;
// if (cl.viewangles[pnum][ROLL] < -50)
// cl.viewangles[pnum][ROLL] = -50;
roll = timestep*cl.playerview[pnum].viewangles[ROLL]*30;
if ((cl.playerview[pnum].viewangles[ROLL]-roll < 0) != (cl.playerview[pnum].viewangles[ROLL]<0))
cl.playerview[pnum].viewangles[ROLL] = 0;
roll = timestep*pv->viewangles[ROLL]*30;
if ((pv->viewangles[ROLL]-roll < 0) != (pv->viewangles[ROLL]<0))
pv->viewangles[ROLL] = 0;
else
cl.playerview[pnum].viewangles[ROLL] -= timestep*cl.playerview[pnum].viewangles[ROLL]*3;
pv->viewangles[ROLL] -= timestep*pv->viewangles[ROLL]*3;
}
/*
@ -1977,6 +1989,10 @@ void CL_InitInput (void)
Cmd_AddCommand ("-moveleft", IN_MoveleftUp);
Cmd_AddCommand ("+moveright", IN_MoverightDown);
Cmd_AddCommand ("-moveright", IN_MoverightUp);
Cmd_AddCommand ("+rollleft", IN_RollLeftDown);
Cmd_AddCommand ("-rollleft", IN_RollLeftUp);
Cmd_AddCommand ("+rollright", IN_RollRightDown);
Cmd_AddCommand ("-rollright", IN_RollRightUp);
Cmd_AddCommand ("+speed", IN_SpeedDown);
Cmd_AddCommand ("-speed", IN_SpeedUp);
Cmd_AddCommand ("+attack", IN_AttackDown);

View file

@ -1809,6 +1809,8 @@ void CL_CheckServerInfo(void)
movevars.stepheight = *s?Q_atof(s):PM_DEFAULTSTEPHEIGHT;
s = Info_ValueForKey(cl.serverinfo, "pm_watersinkspeed");
movevars.watersinkspeed = *s?Q_atof(s):60;
s = Info_ValueForKey(cl.serverinfo, "pm_flyfriction");
movevars.flyfriction = *s?Q_atof(s):4;
// Initialize cl.maxpitch & cl.minpitch
if (cls.protocol == CP_QUAKEWORLD || cls.protocol == CP_NETQUAKE)
@ -3655,9 +3657,11 @@ void CL_Init (void)
Cmd_AddCommand ("god", NULL); //cheats
Cmd_AddCommand ("give", NULL);
Cmd_AddCommand ("noclip", NULL);
Cmd_AddCommand ("notarget", NULL);
Cmd_AddCommand ("6dof", NULL);
Cmd_AddCommand ("spiderpig", NULL);
Cmd_AddCommand ("fly", NULL);
Cmd_AddCommand ("setpos", NULL);
Cmd_AddCommand ("notarget", NULL);
Cmd_AddCommand ("topten", NULL);

View file

@ -6088,6 +6088,7 @@ void CLQW_ParseServerMessage (void)
case svc_cdtrack:
{
//quakeworld got a crippled svc_cdtrack.
unsigned int firsttrack;
firsttrack = MSG_ReadByte ();
Media_NumberedTrack (firsttrack, firsttrack);

View file

@ -720,6 +720,9 @@ static void CL_EntStateToPlayerState(player_state_t *plstate, entity_state_t *st
case MOVETYPE_WALLWALK:
pmtype = PM_WALLWALK;
break;
case MOVETYPE_6DOF:
pmtype = PM_6DOF;
break;
default:
pmtype = PM_NORMAL;
break;

View file

@ -445,7 +445,10 @@ void CD_f (void)
if (Q_strcasecmp(command, "loop") == 0)
{
Media_BackgroundTrack(Cmd_Argv(2), NULL);
if (Cmd_Argc() < 4)
Media_BackgroundTrack(Cmd_Argv(2), NULL);
else
Media_BackgroundTrack(Cmd_Argv(2), Cmd_Argv(3));
return;
}

View file

@ -3622,6 +3622,7 @@ static int PScript_RunParticleEffectState (vec3_t org, vec3_t dir, float count,
part_type_t *ptype = &part_type[typenum];
int i, j, k, l, spawnspc;
float m, pcount, orgadd, veladd;
vec3_t axis[3]={{1,0,0},{0,1,0},{0,0,-1}};
particle_t *p;
beamseg_t *b, *bfirst;
vec3_t ofsvec, arsvec; // offsetspread vec, areaspread vec
@ -3889,6 +3890,17 @@ static int PScript_RunParticleEffectState (vec3_t org, vec3_t dir, float count,
break;
}
if (dir)
{
void PerpendicularVector( vec3_t dst, const vec3_t src );
VectorCopy(dir, axis[2]);
VectorNormalize(axis[2]);
PerpendicularVector(axis[0], axis[2]);
VectorNormalize(axis[0]);
CrossProduct(axis[2], axis[0], axis[1]);
VectorNormalize(axis[1]);
}
// time limit (for completeness)
if (ptype->spawntime && ts)
{
@ -4112,30 +4124,43 @@ static int PScript_RunParticleEffectState (vec3_t org, vec3_t dir, float count,
}
break;
default: // SM_BALL, SM_CIRCLE
ofsvec[0] = hrandom();
ofsvec[1] = hrandom();
if (ptype->areaspreadvert)
ofsvec[2] = hrandom();
else
ofsvec[2] = 0;
{
ofsvec[0] = hrandom();
ofsvec[1] = hrandom();
if (ptype->areaspreadvert)
ofsvec[2] = hrandom();
else
ofsvec[2] = 0;
VectorNormalize(ofsvec);
if (ptype->spawnmode != SM_CIRCLE)
VectorScale(ofsvec, frandom(), ofsvec);
VectorNormalize(ofsvec);
if (ptype->spawnmode != SM_CIRCLE)
VectorScale(ofsvec, frandom(), ofsvec);
arsvec[0] = ofsvec[0]*ptype->areaspread;
arsvec[1] = ofsvec[1]*ptype->areaspread;
arsvec[2] = ofsvec[2]*ptype->areaspreadvert;
arsvec[0] = ofsvec[0]*ptype->areaspread;
arsvec[1] = ofsvec[1]*ptype->areaspread;
arsvec[2] = ofsvec[2]*ptype->areaspreadvert;
}
break;
}
p->org[0] = org[0] + arsvec[0];
p->org[1] = org[1] + arsvec[1];
p->org[2] = org[2] + arsvec[2];
// apply arsvec+ofsvec
orgadd = ptype->orgadd + frandom()*ptype->randomorgadd;
veladd = ptype->veladd + frandom()*ptype->randomveladd;
#if 1
if (dir)
veladd *= VectorLength(dir);
VectorMA(p->vel, ofsvec[0]*ptype->spawnvel, axis[0], p->vel);
VectorMA(p->vel, ofsvec[1]*ptype->spawnvel, axis[1], p->vel);
VectorMA(p->vel, veladd+ofsvec[2]*ptype->spawnvelvert, axis[2], p->vel);
VectorCopy(org, p->org);
VectorMA(p->org, arsvec[0], axis[0], p->org);
VectorMA(p->org, arsvec[1], axis[1], p->org);
VectorMA(p->org, orgadd+arsvec[2], axis[2], p->org);
#else
p->org[0] = org[0] + arsvec[0];
p->org[1] = org[1] + arsvec[1];
p->org[2] = org[2] + arsvec[2];
if (dir)
{
p->vel[0] += dir[0]*veladd+ofsvec[0]*ptype->spawnvel;
@ -4154,7 +4179,7 @@ static int PScript_RunParticleEffectState (vec3_t org, vec3_t dir, float count,
p->org[2] -= orgadd;
}
#endif
VectorAdd(p->org, ptype->orgbias, p->org);
p->die = particletime + ptype->die - p->die;

View file

@ -3592,16 +3592,6 @@ static void QCBUILTIN PF_rotatevectorsbytag (pubprogfuncs_t *prinst, struct glob
//fixme merge with ssqc
static void QCBUILTIN PF_cs_checkbottom (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
csqcedict_t *ent;
ent = (csqcedict_t*)G_EDICT(prinst, OFS_PARM0);
G_FLOAT(OFS_RETURN) = World_CheckBottom (&csqc_world, (wedict_t*)ent);
}
static void QCBUILTIN PF_cs_break (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
Con_Printf ("break statement\n");
@ -3613,14 +3603,16 @@ static void QCBUILTIN PF_cs_break (pubprogfuncs_t *prinst, struct globalvars_s *
//fixme merge with ssqc
static void QCBUILTIN PF_cs_walkmove (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
csqcedict_t *ent;
wedict_t *ent;
float yaw, dist;
vec3_t move;
// dfunction_t *oldf;
int oldself;
qboolean settrace;
vec3_t axis[3];
float s;
ent = (csqcedict_t*)PROG_TO_EDICT(prinst, *csqcg.self);
ent = PROG_TO_WEDICT(prinst, *csqcg.self);
yaw = G_FLOAT(OFS_PARM0);
dist = G_FLOAT(OFS_PARM1);
if (prinst->callargc >= 3 && G_FLOAT(OFS_PARM2))
@ -3634,16 +3626,19 @@ static void QCBUILTIN PF_cs_walkmove (pubprogfuncs_t *prinst, struct globalvars_
return;
}
World_GetEntGravityAxis(ent, axis);
yaw = yaw*M_PI*2 / 360;
move[0] = cos(yaw)*dist;
move[1] = sin(yaw)*dist;
move[2] = 0;
s = cos(yaw)*dist;
VectorScale(axis[0], s, move);
s = sin(yaw)*dist;
VectorMA(move, s, axis[1], move);
// save program state, because CS_movestep may call other progs
oldself = *csqcg.self;
G_FLOAT(OFS_RETURN) = World_movestep(&csqc_world, (wedict_t*)ent, move, true, false, settrace?cs_settracevars:NULL, pr_globals);
G_FLOAT(OFS_RETURN) = World_movestep(&csqc_world, (wedict_t*)ent, move, axis, true, false, settrace?cs_settracevars:NULL, pr_globals);
// restore program state
*csqcg.self = oldself;
@ -4386,7 +4381,7 @@ static struct {
{"ceil", PF_ceil, 38}, // #38 float(float f) ceil (QUAKE)
// {"?", PF_Fixme, 39}, // #39
//40
{"checkbottom", PF_cs_checkbottom, 40}, // #40 float(entity e) checkbottom (QUAKE)
{"checkbottom", PF_checkbottom, 40}, // #40 float(entity e) checkbottom (QUAKE)
{"pointcontents", PF_cs_pointcontents, 41}, // #41 float(vector org) pointcontents (QUAKE)
// {"?", PF_Fixme, 42}, // #42
{"fabs", PF_fabs, 43}, // #43 float(float f) fabs (QUAKE)

View file

@ -509,14 +509,14 @@ void QCBUILTIN PF_CL_precache_pic (pubprogfuncs_t *prinst, struct globalvars_s *
pic = R2D_SafePicFromWad(str);
else
{
if (cls.state
pic = R2D_SafeCachePic(str);
if ((!pic || (pic->flags & SHADER_NOIMAGE)) && cls.state
#ifndef CLIENTONLY
&& !sv.active
#endif
)
&& strchr(str, '.')) //only try to download it if it looks as though it contains a path.
CL_CheckOrEnqueDownloadFile(str, str, 0);
pic = R2D_SafeCachePic(str);
}
if (pic)

View file

@ -2889,6 +2889,13 @@ void FS_ReloadPackFilesFlags(unsigned int reloadflags)
Z_Free(oldpaths);
oldpaths = next;
}
#ifndef SERVERONLY
Shader_NeedReload(true);
#endif
// Mod_ClearAll();
// Cache_Flush();
}
void FS_UnloadPackFiles(void)

View file

@ -995,8 +995,22 @@ static qboolean FSZIP_ReadCentralEntry(zipfile_t *zip, qbyte *data, struct zipce
entry->flags |= ZFL_CORRUPT;
else if (entry->cmethod == 0)
entry->flags |= ZFL_STORED;
//1: shrink
//2-5: reduce
//6: implode
//7: tokenize
else if (entry->cmethod == 8)
entry->flags |= ZFL_DEFLATED;
//8: deflate64 - patented. sometimes written by microsoft's crap. only minor improvements.
//10: implode
//12: bzip2
// else if (entry->cmethod == 12)
// entry->flags |= ZFL_BZIP2;
// else if (entry->cmethod == 14)
// entry->flags |= ZFL_LZMA;
//19: lz77
//97: wavpack
//98: ppmd
else
entry->flags |= ZFL_CORRUPT; //unsupported compression method.
return true;

View file

@ -34,8 +34,6 @@ void PM_Init (void)
#define MIN_STEP_NORMAL 0.7 // roughly 45 degrees
#define pm_flyfriction 4
#define STOP_EPSILON 0.1
#define BLOCKED_FLOOR 1
#define BLOCKED_STEP 2
@ -118,7 +116,6 @@ static qboolean PM_PortalTransform(world_t *w, int portalnum, vec3_t org, vec3_t
//transform the angles too
VectorCopy(org, G_VECTOR(OFS_PARM0));
pmove.angles[0] *= -1;
VectorCopy(pmove.angles, G_VECTOR(OFS_PARM1));
AngleVectors(pmove.angles, w->g.v_forward, w->g.v_right, w->g.v_up);
PR_ExecuteProgram (w->progs, portal->xv->camera_transform);
@ -130,6 +127,36 @@ static qboolean PM_PortalTransform(world_t *w, int portalnum, vec3_t org, vec3_t
return okay;
}
static trace_t PM_PlayerTracePortals(vec3_t start, vec3_t end, unsigned int solidmask, float *tookportal)
{
trace_t trace = PM_PlayerTrace (start, end, MASK_PLAYERSOLID);
if (tookportal)
*tookportal = 0;
if (trace.entnum >= 0 && pmove.world)
{
physent_t *impact = &pmove.physents[trace.entnum];
if (impact->isportal)
{
vec3_t move;
vec3_t from;
VectorCopy(trace.endpos, from); //just in case
VectorSubtract(end, trace.endpos, move);
if (PM_PortalTransform(pmove.world, impact->info, from, move))
{
VectorAdd(from, move, end);
//if we follow the portal, then we basically need to restart from the other side.
if (tookportal)
*tookportal = trace.fraction;
trace = PM_PlayerTrace (from, end, MASK_PLAYERSOLID);
}
}
}
return trace;
}
/*
============
PM_SlideMove
@ -152,6 +179,7 @@ int PM_SlideMove (void)
vec3_t end;
float time_left;
int blocked;
float tookportal;
numbumps = 4;
@ -169,31 +197,14 @@ int PM_SlideMove (void)
for (i=0 ; i<3 ; i++)
end[i] = pmove.origin[i] + time_left * pmove.velocity[i];
trace = PM_PlayerTrace (pmove.origin, end, MASK_PLAYERSOLID);
if (trace.entnum >= 0 && pmove.world)
trace = PM_PlayerTracePortals (pmove.origin, end, MASK_PLAYERSOLID, &tookportal);
if (tookportal)
{
physent_t *impact = &pmove.physents[trace.entnum];
if (impact->isportal)
{
vec3_t move;
vec3_t from;
VectorCopy(trace.endpos, from); //just in case
VectorSubtract(end, trace.endpos, move);
if (PM_PortalTransform(pmove.world, impact->info, from, move))
{
VectorAdd(from, move, end);
//if we follow the portal, then we basically need to restart from the other side.
time_left -= time_left * trace.fraction;
VectorCopy (pmove.velocity, primal_velocity);
VectorCopy (pmove.velocity, original_velocity);
numplanes = 0;
trace = PM_PlayerTrace (from, end, MASK_PLAYERSOLID);
}
}
//made progress, but hit a portal
time_left -= time_left * tookportal;
VectorCopy (pmove.velocity, primal_velocity);
VectorCopy (pmove.velocity, original_velocity);
numplanes = 0;
}
@ -344,6 +355,7 @@ int PM_StepSlideMove (qboolean in_air)
// adjust stepsize, otherwise it would be possible to walk up a
// a step higher than STEPSIZE
//FIXME gravitydir, portals
stepsize = movevars.stepheight - (org[2] - trace.endpos[2]);
}
else
@ -357,12 +369,13 @@ int PM_StepSlideMove (qboolean in_air)
// move up a stair height
VectorMA (pmove.origin, -stepsize, pmove.gravitydir, dest);
trace = PM_PlayerTrace (pmove.origin, dest, MASK_PLAYERSOLID);
trace = PM_PlayerTracePortals (pmove.origin, dest, MASK_PLAYERSOLID, NULL);
if (!trace.startsolid && !trace.allsolid)
{
VectorCopy (trace.endpos, pmove.origin);
}
//FIXME gravitydir
if (in_air && originalvel[2] < 0)
VectorMA(pmove.velocity, -DotProduct(pmove.velocity, pmove.gravitydir), pmove.gravitydir, pmove.velocity); //z=0
@ -370,7 +383,7 @@ int PM_StepSlideMove (qboolean in_air)
// press down the stepheight
VectorMA (pmove.origin, stepsize, pmove.gravitydir, dest);
trace = PM_PlayerTrace (pmove.origin, dest, MASK_PLAYERSOLID);
trace = PM_PlayerTracePortals (pmove.origin, dest, MASK_PLAYERSOLID, NULL);
if (trace.fraction != 1 && -DotProduct(pmove.gravitydir, trace.plane.normal) < MIN_STEP_NORMAL)
goto usedown;
if (!trace.startsolid && !trace.allsolid)
@ -441,7 +454,7 @@ void PM_Friction (void)
//fixme: gravitydir fix needed
pmove.velocity[0] = 0;
pmove.velocity[1] = 0;
if (pmove.pm_type == PM_FLY)
if (pmove.pm_type == PM_FLY || pmove.pm_type == PM_6DOF)
pmove.velocity[2] = 0;
return;
}
@ -449,9 +462,9 @@ void PM_Friction (void)
if (pmove.waterlevel >= 2)
// apply water friction, even if in fly mode
drop = speed*movevars.waterfriction*pmove.waterlevel*frametime;
else if (pmove.pm_type == PM_FLY) {
else if (pmove.pm_type == PM_FLY || pmove.pm_type == PM_6DOF) {
// apply flymode friction
drop = speed * pm_flyfriction * frametime;
drop = speed * movevars.flyfriction * frametime;
}
else if (pmove.onground) {
// apply ground friction
@ -460,6 +473,7 @@ void PM_Friction (void)
// if the leading edge is over a dropoff, increase friction
start[0] = stop[0] = pmove.origin[0] + pmove.velocity[0]/speed*16;
start[1] = stop[1] = pmove.origin[1] + pmove.velocity[1]/speed*16;
//FIXME: gravitydir.
start[2] = pmove.origin[2] + pmove.player_mins[2];
stop[2] = start[2] - 34;
trace = PM_PlayerTrace (start, stop, MASK_PLAYERSOLID);
@ -619,10 +633,18 @@ void PM_FlyMove (void)
float wishspeed;
vec3_t wishdir;
for (i=0 ; i<3 ; i++)
wishvel[i] = forward[i]*pmove.cmd.forwardmove + right[i]*pmove.cmd.sidemove;
if (pmove.pm_type == PM_6DOF)
{
for (i=0 ; i<3 ; i++)
wishvel[i] = forward[i]*pmove.cmd.forwardmove + right[i]*pmove.cmd.sidemove + up[i]*pmove.cmd.upmove;
}
else
{
for (i=0 ; i<3 ; i++)
wishvel[i] = forward[i]*pmove.cmd.forwardmove + right[i]*pmove.cmd.sidemove;
VectorMA(wishvel, -pmove.cmd.upmove, pmove.gravitydir, wishvel);
VectorMA(wishvel, -pmove.cmd.upmove, pmove.gravitydir, wishvel);
}
VectorCopy (wishvel, wishdir);
wishspeed = VectorNormalize(wishdir);
@ -815,7 +837,7 @@ void PM_CategorizePosition (void)
}
else
{
trace = PM_PlayerTrace (pmove.origin, point, MASK_PLAYERSOLID);
trace = PM_PlayerTracePortals (pmove.origin, point, MASK_PLAYERSOLID, NULL);
if (trace.fraction == 1 || -DotProduct(pmove.gravitydir, trace.plane.normal) < MIN_STEP_NORMAL)
pmove.onground = false;
else
@ -837,6 +859,7 @@ void PM_CategorizePosition (void)
pmove.waterlevel = 0;
pmove.watertype = FTECONTENTS_EMPTY;
//FIXME: gravitydir
point[2] = pmove.origin[2] + pmove.player_mins[2] + 1;
cont = PM_PointContents (point);
@ -1220,7 +1243,7 @@ void PM_PlayerMove (float gamespeed)
if (pmove.waterlevel >= 2)
PM_WaterMove ();
else if (pmove.pm_type == PM_FLY)
else if (pmove.pm_type == PM_FLY || pmove.pm_type == PM_6DOF)
PM_FlyMove ();
else if (pmove.onladder)
PM_LadderMove ();

View file

@ -29,7 +29,8 @@ typedef enum {
PM_FLY, // fly, bump into walls
PM_NONE, // can't move
PM_FREEZE, // can't move or look around (TODO)
PM_WALLWALK // sticks to walls. on ground while near one
PM_WALLWALK, // sticks to walls. on ground while near one
PM_6DOF // spaceship mode
} pmtype_t;
#define PMF_JUMP_HELD 1
@ -99,6 +100,7 @@ typedef struct {
float wateraccelerate;
float friction;
float waterfriction;
float flyfriction;
float entgravity;
float bunnyspeedcap;
float watersinkspeed;

View file

@ -259,6 +259,76 @@ static qboolean PM_TransformedHullCheck (model_t *model, vec3_t start, vec3_t en
return true;
}
//a portal is flush with a world surface behind it.
//this causes problems. namely that we can't pass through the portal plane if the bsp behind it prevents out origin from getting through.
//so if the trace was clipped and ended infront of the portal, continue the trace to the edges of the portal cutout instead.
void PM_PortalCSG(physent_t *portal, float trminz, float trmaxz, vec3_t start, vec3_t end, trace_t *trace)
{
vec4_t planes[6]; //far, near, right, left, up, down
int plane;
vec3_t worldpos;
float portalradius = 128;
//only run this code if we impacted on the portal's parent.
if (trace->fraction == 1 && !trace->startsolid)
return;
if (!portalradius)
return;
if (trace->startsolid)
VectorCopy(start, worldpos); //make sure we use a sane valid position.
else
VectorCopy(trace->endpos, worldpos);
//determine the csg area. normals should be facing in
AngleVectors(portal->angles, planes[1], planes[3], planes[5]);
VectorNegate(planes[1], planes[0]);
VectorNegate(planes[3], planes[2]);
VectorNegate(planes[5], planes[4]);
trminz = fabs(trminz);
portalradius/=2;
planes[0][3] = DotProduct(portal->origin, planes[0]) - (trminz+fabs(trmaxz)+16);
planes[1][3] = DotProduct(portal->origin, planes[1]) - (64.0/32); //an epsilon beyond the portal
planes[2][3] = DotProduct(portal->origin, planes[2]) - portalradius+trminz;
planes[3][3] = DotProduct(portal->origin, planes[3]) - portalradius+trminz;
planes[4][3] = DotProduct(portal->origin, planes[4]) - portalradius+trminz;
planes[5][3] = DotProduct(portal->origin, planes[5]) - portalradius+trminz;
//if we're actually inside the csg region
for (plane = 0; plane < 6; plane++)
{
float d = DotProduct(worldpos, planes[plane]);
if (d - planes[plane][3] >= 0)
continue; //endpos is inside
else
return; //end is already outside
}
//yup, we're inside, the trace shouldn't end where it actually did
trace->fraction = 1;
trace->startsolid = trace->allsolid = false;
VectorInterpolate(start, 1, end, trace->endpos);
for (plane = 0; plane < 6; plane++)
{
float ds = DotProduct(start, planes[plane]) - planes[plane][3];
float de = DotProduct(end, planes[plane]) - planes[plane][3];
float frac;
if (ds >= 0 && de < 0)
{
frac = (ds-(1.0/32)) / (ds - de);
if (frac < trace->fraction)
{
if (frac < 0)
frac = 0;
trace->fraction = frac;
VectorInterpolate(start, frac, end, trace->endpos);
VectorCopy(planes[plane], trace->plane.normal);
trace->plane.dist = planes[plane][3];
}
}
}
}
/*
================
PM_TestPlayerPosition
@ -268,12 +338,14 @@ Returns false if the given player position is not valid (in solid)
*/
qboolean PM_TestPlayerPosition (vec3_t pos)
{
int i;
int i, j;
physent_t *pe;
vec3_t mins, maxs;
hull_t *hull;
trace_t trace;
trace.allsolid = false;
for (i=0 ; i< pmove.numphysent ; i++)
{
pe = &pmove.physents[i];
@ -293,7 +365,16 @@ qboolean PM_TestPlayerPosition (vec3_t pos)
if (!PM_TransformedHullCheck (pe->model, pos, pos, pmove.player_mins, pmove.player_maxs, &trace, pe->origin, pe->angles))
continue;
if (trace.allsolid)
return false; //solid
{
for (j = i+1; j < pmove.numphysent && trace.allsolid; j++)
{
pe = &pmove.physents[j];
if (pe->isportal)
PM_PortalCSG(pe, pmove.player_mins[2], pmove.player_maxs[2], pos, pos, &trace);
}
if (trace.allsolid)
return false;
}
}
else
{
@ -318,7 +399,7 @@ PM_PlayerTrace
trace_t PM_PlayerTrace (vec3_t start, vec3_t end, unsigned int solidmask)
{
trace_t trace, total;
int i;
int i, j;
physent_t *pe;
// fill in a default trace
@ -352,6 +433,9 @@ trace_t PM_PlayerTrace (vec3_t start, vec3_t end, unsigned int solidmask)
}
else if (pe->isportal)
{
//make sure we don't hit the world if we're inside the portal
PM_PortalCSG(pe, pmove.player_mins[2], pmove.player_maxs[2], start, end, &total);
// trace a line through the apropriate clipping hull
if (!PM_TransformedHullCheck (pe->model, start, end, vec3_origin, vec3_origin, &trace, pe->origin, pe->angles))
continue;
@ -361,6 +445,17 @@ trace_t PM_PlayerTrace (vec3_t start, vec3_t end, unsigned int solidmask)
// trace a line through the apropriate clipping hull
if (!PM_TransformedHullCheck (pe->model, start, end, pmove.player_mins, pmove.player_maxs, &trace, pe->origin, pe->angles))
continue;
if (trace.allsolid)
{
for (j = i+1; j < pmove.numphysent && trace.allsolid; j++)
{
pe = &pmove.physents[j];
if (pe->isportal)
PM_PortalCSG(pe, pmove.player_mins[2], pmove.player_maxs[2], start, end, &trace);
}
pe = &pmove.physents[i];
}
}
if (trace.allsolid)
@ -370,11 +465,7 @@ trace_t PM_PlayerTrace (vec3_t start, vec3_t end, unsigned int solidmask)
continue;
if (trace.startsolid)
{
// if (!pmove.physents[i].model) //caught inside annother model
// continue; //don't count this.
trace.fraction = 0;
}
// did we clip the move?
if (trace.fraction < total.fraction)

View file

@ -4092,6 +4092,27 @@ void QCBUILTIN PF_droptofloor (pubprogfuncs_t *prinst, struct globalvars_s *pr_g
}
}
/*
=============
PF_checkbottom
=============
*/
void QCBUILTIN PF_checkbottom (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
world_t *world = prinst->parms->user;
wedict_t *ent;
vec3_t gravup;
ent = G_WEDICT(prinst, OFS_PARM0);
if (ent->xv->gravitydir[0] || ent->xv->gravitydir[1] || ent->xv->gravitydir[2])
VectorNegate(ent->xv->gravitydir, gravup);
else
VectorSet(gravup, 0, 0, 1);
G_FLOAT(OFS_RETURN) = World_CheckBottom (world, ent, gravup);
}
////////////////////////////////////////////////////
//Vector functions
@ -4118,12 +4139,16 @@ This was a major timewaster in progs, so it was converted to C
FIXME: add gravitydir support
==============
*/
float World_changeyaw (wedict_t *ent);
void QCBUILTIN PF_changeyaw (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
edict_t *ent;
float ideal, current, move, speed;
wedict_t *ent;
// float ideal, current, move, speed;
ent = PROG_TO_EDICT(prinst, pr_global_struct->self);
ent = PROG_TO_WEDICT(prinst, pr_global_struct->self);
World_changeyaw(ent);
/*
current = anglemod( ent->v->angles[1] );
ideal = ent->v->ideal_yaw;
speed = ent->v->yaw_speed;
@ -4153,6 +4178,7 @@ void QCBUILTIN PF_changeyaw (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
}
ent->v->angles[1] = anglemod (current + move);
*/
}
//void() changepitch = #63;
@ -4194,20 +4220,33 @@ void QCBUILTIN PF_changepitch (pubprogfuncs_t *prinst, struct globalvars_s *pr_g
ent->v->angles[1] = anglemod (current + move);
}
//float vectoyaw(vector)
//FIXME: support gravitydir
//float vectoyaw(vector, optional entity reference)
void QCBUILTIN PF_vectoyaw (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
float *value1;
float x, y;
float yaw;
value1 = G_VECTOR(OFS_PARM0);
if (value1[1] == 0 && value1[0] == 0)
if (prinst->callargc >= 2)
{
vec3_t axis[3];
World_GetEntGravityAxis(G_WEDICT(prinst, OFS_PARM1), axis);
x = DotProduct(value1, axis[0]);
y = DotProduct(value1, axis[1]);
}
else
{
x = value1[0];
y = value1[1];
}
if (y == 0 && x == 0)
yaw = 0;
else
{
yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
yaw = (int) (atan2(y, x) * 180 / M_PI);
if (yaw < 0)
yaw += 360;
}

View file

@ -125,6 +125,7 @@ void QCBUILTIN PF_dupstring(pubprogfuncs_t *prinst, struct globalvars_s *pr_glob
void QCBUILTIN PF_forgetstring(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_Spawn (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_droptofloor (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_checkbottom (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_min (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_max (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_registercvar (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
@ -481,6 +482,7 @@ pbool QDECL ED_CanFree (edict_t *ed);
#define MOVETYPE_FOLLOW 12 // track movement of aiment
#define MOVETYPE_H2PUSHPULL 13 // pushable/pullable object
#define MOVETYPE_H2SWIM 14 // should keep the object in water
#define MOVETYPE_6DOF 30 // flightsim mode
#define MOVETYPE_WALLWALK 31 // walks up walls and along ceilings
#define MOVETYPE_PHYSICS 32

View file

@ -798,6 +798,48 @@ void Q1BSP_LoadBrushes(model_t *model)
model->engineflags |= MDLF_HASBRUSHES;
}
hull_t *Q1BSP_ChooseHull(model_t *model, int forcehullnum, vec3_t mins, vec3_t maxs, vec3_t offset)
{
hull_t *hull;
vec3_t size;
VectorSubtract (maxs, mins, size);
if (forcehullnum >= 1 && forcehullnum <= MAX_MAP_HULLSM && model->hulls[forcehullnum-1].available)
hull = &model->hulls[forcehullnum-1];
else
{
if (model->hulls[5].available)
{ //choose based on hexen2 sizes.
if (size[0] < 3) // Point
hull = &model->hulls[0];
else if (size[0] <= 8.1 && model->hulls[4].available)
hull = &model->hulls[4]; //Pentacles
else if (size[0] <= 32.1 && size[2] <= 28.1) // Half Player
hull = &model->hulls[3];
else if (size[0] <= 32.1) // Full Player
hull = &model->hulls[1];
else // Golumn
hull = &model->hulls[5];
}
else
{
if (size[0] < 3 || !model->hulls[1].available)
hull = &model->hulls[0];
else if (size[0] <= 32.1)
{
if (size[2] < 54.1 && model->hulls[3].available)
hull = &model->hulls[3]; // 32x32x36 (half-life's crouch)
else
hull = &model->hulls[1];
}
else
hull = &model->hulls[2];
}
}
VectorSubtract (hull->clip_mins, mins, offset);
return hull;
}
qboolean Q1BSP_Trace(model_t *model, int forcehullnum, int frame, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, unsigned int hitcontentsmask, trace_t *trace)
{
hull_t *hull;
@ -805,7 +847,6 @@ qboolean Q1BSP_Trace(model_t *model, int forcehullnum, int frame, vec3_t axis[3]
vec3_t start_l, end_l;
vec3_t offset;
VectorSubtract (maxs, mins, size);
if ((model->engineflags & MDLF_HASBRUSHES))// && (size[0] || size[1] || size[2]))
{
struct traceinfo_s traceinfo;
@ -846,42 +887,7 @@ qboolean Q1BSP_Trace(model_t *model, int forcehullnum, int frame, vec3_t axis[3]
trace->fraction = 1;
trace->allsolid = true;
if (forcehullnum >= 1 && forcehullnum <= MAX_MAP_HULLSM && model->hulls[forcehullnum-1].available)
hull = &model->hulls[forcehullnum-1];
else
{
if (model->hulls[5].available)
{ //choose based on hexen2 sizes.
if (size[0] < 3) // Point
hull = &model->hulls[0];
else if (size[0] <= 8.1 && model->hulls[4].available)
hull = &model->hulls[4]; //Pentacles
else if (size[0] <= 32.1 && size[2] <= 28.1) // Half Player
hull = &model->hulls[3];
else if (size[0] <= 32.1) // Full Player
hull = &model->hulls[1];
else // Golumn
hull = &model->hulls[5];
}
else
{
if (size[0] < 3 || !model->hulls[1].available)
hull = &model->hulls[0];
else if (size[0] <= 32.1)
{
if (size[2] < 54.1 && model->hulls[3].available)
hull = &model->hulls[3]; // 32x32x36 (half-life's crouch)
else
hull = &model->hulls[1];
}
else
hull = &model->hulls[2];
}
}
// calculate an offset value to center the origin
VectorSubtract (hull->clip_mins, mins, offset);
hull = Q1BSP_ChooseHull(model, forcehullnum, mins, maxs, offset);
// offset[0] = 0;
// offset[1] = 0;

View file

@ -281,9 +281,10 @@ void Q2BSP_FindTouchedLeafs(model_t *mod, struct pvscache_s *ent, float *mins, f
/*sv_move.c*/
qboolean World_CheckBottom (world_t *world, wedict_t *ent);
qboolean World_movestep (world_t *world, wedict_t *ent, vec3_t move, qboolean relink, qboolean noenemy, void (*set_move_trace)(trace_t *trace, struct globalvars_s *pr_globals), struct globalvars_s *set_trace_globs);
qboolean World_CheckBottom (world_t *world, wedict_t *ent, vec3_t up);
qboolean World_movestep (world_t *world, wedict_t *ent, vec3_t move, vec3_t axis[3], qboolean relink, qboolean noenemy, void (*set_move_trace)(trace_t *trace, struct globalvars_s *pr_globals), struct globalvars_s *set_trace_globs);
qboolean World_MoveToGoal (world_t *world, wedict_t *ent, float dist);
qboolean World_GetEntGravityAxis(wedict_t *ent, vec3_t axis[3]);
void WPhys_Init(void);
void World_Physics_Frame(world_t *w);

View file

@ -2820,6 +2820,7 @@ void Shader_FlushCache(void)
for (i = 0; i < HASH_SIZE; i++)
{
cache = shader_hash[i];
shader_hash[i] = NULL;
for (; cache; cache = cache_next)
{
@ -4962,6 +4963,8 @@ void Shader_DoReload(void)
if (shader_rescan_needed && ruleset_allow_shaders.ival)
{
Shader_FlushCache();
COM_EnumerateFiles("materials/*.mtr", Shader_InitCallback, NULL);
COM_EnumerateFiles("shaders/*.shader", Shader_InitCallback, NULL);
COM_EnumerateFiles("scripts/*.shader", Shader_InitCallback, NULL);

View file

@ -369,8 +369,11 @@ pbool PDECL SV_BadField(pubprogfuncs_t *inst, edict_t *foo, const char *keyname,
{
/*hexen2 midi - just mute it, we don't support it*/
if (!stricmp(keyname, "MIDI"))
{
Q_strncpyz(sv.h2miditrack, value, sizeof(sv.h2miditrack));
return true;
/*hexen2 does cd tracks slightly differently too*/
}
/*hexen2 does cd tracks slightly differently too, so there's consistancy for you*/
if (!stricmp(keyname, "CD"))
{
sv.h2cdtrack = atoi(value);
@ -3915,14 +3918,16 @@ float(float yaw, float dist) walkmove
*/
static void QCBUILTIN PF_walkmove (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
edict_t *ent;
wedict_t *ent;
float yaw, dist;
vec3_t move;
// dfunction_t *oldf;
int oldself;
qboolean settrace;
vec3_t axis[3];
float s;
ent = PROG_TO_EDICT(prinst, pr_global_struct->self);
ent = PROG_TO_WEDICT(prinst, pr_global_struct->self);
yaw = G_FLOAT(OFS_PARM0);
dist = G_FLOAT(OFS_PARM1);
if (svprogfuncs->callargc >= 3 && G_FLOAT(OFS_PARM2))
@ -3937,10 +3942,12 @@ static void QCBUILTIN PF_walkmove (pubprogfuncs_t *prinst, struct globalvars_s *
}
yaw = yaw*M_PI*2 / 360;
World_GetEntGravityAxis(ent, axis);
move[0] = cos(yaw)*dist;
move[1] = sin(yaw)*dist;
move[2] = 0;
s = cos(yaw)*dist;
VectorScale(axis[0], s, move);
s = sin(yaw)*dist;
VectorMA(move, s, axis[1], move);
// save program state, because SV_movestep may call other progs
// oldf = pr_xfunction;
@ -3952,7 +3959,7 @@ static void QCBUILTIN PF_walkmove (pubprogfuncs_t *prinst, struct globalvars_s *
// }
// else if (!SV_TestEntityPosition(ent))
// {
G_FLOAT(OFS_RETURN) = World_movestep(&sv.world, (wedict_t*)ent, move, true, false, settrace?set_trace_globals:NULL, pr_globals);
G_FLOAT(OFS_RETURN) = World_movestep(&sv.world, (wedict_t*)ent, move, axis, true, false, settrace?set_trace_globals:NULL, pr_globals);
// if (SV_TestEntityPosition(ent))
// Con_Printf("Entity became stuck\n");
// }
@ -4097,20 +4104,6 @@ static void QCBUILTIN PF_lightstylestatic (pubprogfuncs_t *prinst, struct global
PF_applylightstyle(style, val, col);
}
/*
=============
PF_checkbottom
=============
*/
static void QCBUILTIN PF_checkbottom (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
edict_t *ent;
ent = G_EDICT(prinst, OFS_PARM0);
G_FLOAT(OFS_RETURN) = World_CheckBottom (&sv.world, (wedict_t*)ent);
}
/*
=============
PF_pointcontents
@ -6869,7 +6862,7 @@ static void QCBUILTIN PF_h2movestep (pubprogfuncs_t *prinst, struct globalvars_s
// save program state, because SV_movestep may call other progs
oldself = pr_global_struct->self;
G_INT(OFS_RETURN) = World_movestep (&sv.world, (wedict_t*)ent, v, false, true, set_trace?set_trace_globals:NULL, pr_globals);
G_INT(OFS_RETURN) = World_movestep (&sv.world, (wedict_t*)ent, v, NULL, false, true, set_trace?set_trace_globals:NULL, pr_globals);
// restore program state
pr_global_struct->self = oldself;
@ -8402,33 +8395,6 @@ static void QCBUILTIN PF_setcolors (pubprogfuncs_t *prinst, struct globalvars_s
SV_ExtractFromUserinfo (client, true);
}
static client_t *DirectSplit(client_t *cl, int svc, int svclen)
{
if (cl->controller)
{ //this is a slave client.
//find the right number and send.
client_t *sp;
int pnum = 0;
for (sp = cl->controller; sp; sp = sp->controlled)
{
if (sp == cl)
break;
pnum++;
}
sp = cl->controller;
ClientReliableWrite_Begin (sp, svcfte_choosesplitclient, 2+svclen);
ClientReliableWrite_Byte (sp, pnum);
ClientReliableWrite_Byte (sp, svc);
return sp;
}
else
{
ClientReliableWrite_Begin (cl, svc, svclen);
return cl;
}
}
static void ParamNegateFix ( float * xx, float * yy, int Zone )
{
float x,y;
@ -8466,7 +8432,7 @@ static void QCBUILTIN PF_ShowPic(pubprogfuncs_t *prinst, struct globalvars_s *pr
if (!(svs.clients[entnum].fteprotocolextensions & PEXT_SHOWPIC))
return; //need an extension for this. duh.
cl = DirectSplit(&svs.clients[entnum], svcfte_showpic, 8 + strlen(slot)+strlen(picname));
cl = ClientReliableWrite_BeginSplit(&svs.clients[entnum], svcfte_showpic, 8 + strlen(slot)+strlen(picname));
ClientReliableWrite_Byte(cl, zone);
ClientReliableWrite_String(cl, slot);
ClientReliableWrite_String(cl, picname);
@ -8499,7 +8465,7 @@ static void QCBUILTIN PF_HidePic(pubprogfuncs_t *prinst, struct globalvars_s *pr
if (!(svs.clients[entnum].fteprotocolextensions & PEXT_SHOWPIC))
return; //need an extension for this. duh.
cl = DirectSplit(&svs.clients[entnum], svcfte_hidepic, 2 + strlen(slot));
cl = ClientReliableWrite_BeginSplit(&svs.clients[entnum], svcfte_hidepic, 2 + strlen(slot));
ClientReliableWrite_String(cl, slot);
}
else
@ -8534,7 +8500,7 @@ static void QCBUILTIN PF_MovePic(pubprogfuncs_t *prinst, struct globalvars_s *pr
if (!(svs.clients[entnum].fteprotocolextensions & PEXT_SHOWPIC))
return; //need an extension for this. duh.
cl = DirectSplit(&svs.clients[entnum], svcfte_movepic, 6 + strlen(slot));
cl = ClientReliableWrite_BeginSplit(&svs.clients[entnum], svcfte_movepic, 6 + strlen(slot));
ClientReliableWrite_String(cl, slot);
ClientReliableWrite_Byte(cl, zone);
ClientReliableWrite_Short(cl, x);
@ -8567,7 +8533,7 @@ static void QCBUILTIN PF_ChangePic(pubprogfuncs_t *prinst, struct globalvars_s *
if (!(svs.clients[entnum].fteprotocolextensions & PEXT_SHOWPIC))
return; //need an extension for this. duh.
cl = DirectSplit(&svs.clients[entnum], svcfte_updatepic, 3 + strlen(slot)+strlen(newpic));
cl = ClientReliableWrite_BeginSplit(&svs.clients[entnum], svcfte_updatepic, 3 + strlen(slot)+strlen(newpic));
ClientReliableWrite_String(cl, slot);
ClientReliableWrite_String(cl, newpic);
}
@ -9000,7 +8966,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"error", PF_error, 10, 10, 10, 0, D("void(string e)", "Ends the game with an easily readable error message.")},
{"objerror", PF_objerror, 11, 11, 11, 0, D("void(string e)", "Displays a non-fatal easily readable error message concerning the self entity, including a field dump. self will be removed!")},
{"vlen", PF_vlen, 12, 12, 12, 0, D("float(vector v)", "Returns the square root of the dotproduct of a vector with itself. Or in other words the length of a distance vector, in quake units.")},
{"vectoyaw", PF_vectoyaw, 13, 13, 13, 0, D("float(vector v)", "Given a direction vector, returns the yaw (_y) angle in which that direction vector points.")},
{"vectoyaw", PF_vectoyaw, 13, 13, 13, 0, D("float(vector v, optional entity reference)", "Given a direction vector, returns the yaw angle in which that direction vector points. If an entity is passed, the yaw angle will be relative to that entity's gravity direction.")},
{"spawn", PF_Spawn, 14, 14, 14, 0, D("entity()", "Adds a brand new entity into the world! Hurrah, you're now a parent!")},
{"remove", PF_Remove, 15, 15, 15, 0, D("void(entity e)", "Destroys the given entity and clears some limited fields (including model, modelindex, solid, classname). Any references to the entity following the call are an error. After two seconds, the entity will be reused, in the interim you can unfortunatly still read its fields to see if the reference is no longer valid.")},
{"traceline", PF_svtraceline, 16, 16, 16, 0, D("void(vector v1, vector v2, float flags, entity ent)", "Traces an infinitely thin line through the world from v1 towards v2.\nWill not collide with ent, ent.owner, or any entity who's owner field refers to ent.\nThere are no side effects beyond the trace_* globals being written.\nflags&MOVE_NOMONSTERS will not impact on non-bsp entities.\nflags&MOVE_MISSILE will impact with increased size.\nflags&MOVE_HITMODEL will impact upon model meshes, instead of their bounding boxes.\nflags&MOVE_TRIGGERS will also stop on triggers\nflags&MOVE_EVERYTHING will stop if it hits anything, even non-solid entities.\nflags&MOVE_LAGGED will backdate entity positions for the purposes of this builtin according to the indicated player ent's latency, to provide lag compensation.")},

View file

@ -1011,6 +1011,7 @@ static int bi_lua_walkmove(lua_State *L)
float yaw, dist;
vec3_t move;
int oldself;
vec3_t axis;
ent = PROG_TO_WEDICT(prinst, *world->g.self);
yaw = lua.tonumberx(L, 1, NULL);
@ -1022,16 +1023,17 @@ static int bi_lua_walkmove(lua_State *L)
return 1;
}
World_GetEntGravityAxis(ent, axis);
yaw = yaw*M_PI*2 / 360;
move[0] = cos(yaw)*dist;
move[1] = sin(yaw)*dist;
move[2] = 0;
VectorScale(axis[0], cos(yaw)*dist, move);
VectorMA(move, sin(yaw)*dist, axis[1], move);
// save program state, because World_movestep may call other progs
oldself = *world->g.self;
lua.pushboolean(L, World_movestep(world, ent, move, true, false, NULL, NULL));
lua.pushboolean(L, World_movestep(world, ent, move, axis, true, false, NULL, NULL));
// restore program state
*world->g.self = oldself;

View file

@ -734,17 +734,20 @@ static qintptr_t syscallhandle (void *offset, quintptr_t mask, qintptr_t fn, con
case G_WALKMOVE:
{
edict_t *ed = EDICT_NUM(svprogfuncs, arg[0]);
wedict_t *ed = WEDICT_NUM(svprogfuncs, arg[0]);
float yaw = VM_FLOAT(arg[1]);
float dist = VM_FLOAT(arg[2]);
vec3_t move;
vec3_t axis[3];
World_GetEntGravityAxis(ed, axis);
yaw = yaw*M_PI*2 / 360;
move[0] = cos(yaw)*dist;
move[1] = sin(yaw)*dist;
move[2] = 0;
return World_movestep(&sv.world, (wedict_t*)ed, move, true, false, NULL, NULL);
return World_movestep(&sv.world, (wedict_t*)ed, move, axis, true, false, NULL, NULL);
}
case G_DROPTOFLOOR:
@ -780,7 +783,10 @@ static qintptr_t syscallhandle (void *offset, quintptr_t mask, qintptr_t fn, con
break;
case G_CHECKBOTTOM:
return World_CheckBottom(&sv.world, (wedict_t*)EDICT_NUM(svprogfuncs, VM_LONG(arg[0])));
{
vec3_t up = {0,0,1};
return World_CheckBottom(&sv.world, (wedict_t*)EDICT_NUM(svprogfuncs, VM_LONG(arg[0])), up);
}
case G_POINTCONTENTS:
{

View file

@ -141,6 +141,7 @@ typedef struct
qbyte lightstylecolours[MAX_LIGHTSTYLES];
};
} strings;
char h2miditrack[MAX_QPATH];
qbyte h2cdtrack;
int allocated_client_slots; //number of slots available. (used mostly to stop single player saved games cacking up)
@ -1190,6 +1191,7 @@ void SV_CSQC_DropAll(client_t *client);
void ClientReliableCheckBlock(client_t *cl, int maxsize);
void ClientReliable_FinishWrite(client_t *cl);
void ClientReliableWrite_Begin(client_t *cl, int c, int maxsize);
client_t *ClientReliableWrite_BeginSplit(client_t *cl, int svc, int svclen);
void ClientReliableWrite_Angle(client_t *cl, float f);
void ClientReliableWrite_Angle16(client_t *cl, float f);
void ClientReliableWrite_Byte(client_t *cl, int c);

View file

@ -5168,6 +5168,7 @@ void SV_InitLocal (void)
extern cvar_t pm_walljump;
extern cvar_t pm_slidyslopes;
extern cvar_t pm_watersinkspeed;
extern cvar_t pm_flyfriction;
SV_InitOperatorCommands ();
SV_UserInit ();
@ -5221,6 +5222,7 @@ void SV_InitLocal (void)
Cvar_Register (&pm_bunnyspeedcap, cvargroup_serverphysics);
Cvar_Register (&pm_watersinkspeed, cvargroup_serverphysics);
Cvar_Register (&pm_flyfriction, cvargroup_serverphysics);
Cvar_Register (&pm_ktjump, cvargroup_serverphysics);
Cvar_Register (&pm_slidefix, cvargroup_serverphysics);
Cvar_Register (&pm_slidyslopes, cvargroup_serverphysics);

View file

@ -23,7 +23,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "pr_common.h"
#if defined(CSQC_DAT) || !defined(CLIENTONLY)
/*
=============
SV_CheckBottom
@ -35,26 +34,59 @@ is not a staircase.
*/
int c_yes, c_no;
qboolean World_CheckBottom (world_t *world, wedict_t *ent)
hull_t *Q1BSP_ChooseHull(model_t *model, int hullnum, vec3_t mins, vec3_t maxs, vec3_t offset);
//this function is axial. major axis determines ground. if it switches slightly, a new axis may become the ground...
qboolean World_CheckBottom (world_t *world, wedict_t *ent, vec3_t up)
{
int savedhull;
vec3_t mins, maxs, start, stop;
trace_t trace;
int x, y;
float mid, bottom;
float mid;
int a0,a1,a2; //logical x, y, z
int sign;
mins[0] = fabs(up[0]);
mins[1] = fabs(up[1]);
mins[2] = fabs(up[2]);
if (mins[2] > mins[0] && mins[2] > mins[1])
{
a0 = 0;
a1 = 1;
a2 = 2;
}
else
{
a2 = mins[1] > mins[0];
a0 = 1 - a2;
a1 = 2;
}
sign = (up[a2]>0)?1:-1;
VectorAdd (ent->v->origin, ent->v->mins, mins);
VectorAdd (ent->v->origin, ent->v->maxs, maxs);
if (world->worldmodel->fromgame == fg_quake)
{
//quake's hulls are weird. sizes are defined as from mins to mins+hullsize. the actual maxs is ignored other than for its size.
hull_t *hull;
hull = Q1BSP_ChooseHull(world->worldmodel, ent->xv->hull, ent->v->mins, ent->v->maxs, start);
VectorAdd (mins, start, mins);
VectorSubtract (mins, hull->clip_mins, maxs);
VectorAdd (maxs, hull->clip_maxs, maxs);
}
else
VectorAdd (ent->v->origin, ent->v->maxs, maxs);
// if all of the points under the corners are solid world, don't bother
// with the tougher checks
// the corners must be within 16 of the midpoint
start[2] = mins[2] - 1;
start[a2] = (sign<0)?maxs[a2]:mins[a2] - sign;
for (x=0 ; x<=1 ; x++)
for (y=0 ; y<=1 ; y++)
{
start[0] = x ? maxs[0] : mins[0];
start[1] = y ? maxs[1] : mins[1];
start[a0] = x ? maxs[a0] : mins[a0];
start[a1] = y ? maxs[a1] : mins[a1];
if (!(World_PointContents (world, start) & FTECONTENTS_SOLID))
goto realcheck;
}
@ -67,12 +99,12 @@ realcheck:
//
// check it for real...
//
start[2] = mins[2];
start[a2] = (sign<0)?maxs[a2]:mins[a2];
// the midpoint must be within 16 of the bottom
start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
stop[2] = start[2] - 2*movevars.stepheight;
start[a0] = stop[a0] = (mins[a0] + maxs[a0])*0.5;
start[a1] = stop[a1] = (mins[a1] + maxs[a1])*0.5;
stop[a2] = start[a2] - 2*movevars.stepheight*sign;
savedhull = ent->xv->hull;
ent->xv->hull = 0; //stop the hull from breaking tracelines
trace = World_Move (world, start, vec3_origin, vec3_origin, stop, true, ent);
@ -82,20 +114,20 @@ realcheck:
ent->xv->hull = savedhull;
return false;
}
mid = bottom = trace.endpos[2];
mid = trace.endpos[2];
mid = (mid-start[a2]-(movevars.stepheight*sign)) / (stop[a2]-start[a2]);
// the corners must be within 16 of the midpoint
for (x=0 ; x<=1 ; x++)
for (y=0 ; y<=1 ; y++)
{
start[0] = stop[0] = x ? maxs[0] : mins[0];
start[1] = stop[1] = y ? maxs[1] : mins[1];
start[a0] = stop[a0] = x ? maxs[a0] : mins[a0];
start[a1] = stop[a1] = y ? maxs[a1] : mins[a1];
trace = World_Move (world, start, vec3_origin, vec3_origin, stop, true, ent);
if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
bottom = trace.endpos[2];
if (trace.fraction == 1.0 || mid - trace.endpos[2] > movevars.stepheight)
if (trace.fraction == 1.0 || trace.fraction > mid)//mid - trace.endpos[2] > movevars.stepheight)
{
ent->xv->hull = savedhull;
return false;
@ -117,7 +149,7 @@ possible, no move is done, false is returned, and
pr_global_struct->trace_normal is set to the normal of the blocking wall
=============
*/
qboolean World_movestep (world_t *world, wedict_t *ent, vec3_t move, qboolean relink, qboolean noenemy, void (*set_move_trace)(trace_t *trace, struct globalvars_s *pr_globals), struct globalvars_s *set_trace_globs)
qboolean World_movestep (world_t *world, wedict_t *ent, vec3_t move, vec3_t axis[3], qboolean relink, qboolean noenemy, void (*set_move_trace)(trace_t *trace, struct globalvars_s *pr_globals), struct globalvars_s *set_trace_globs)
{
float dz;
vec3_t oldorg, neworg, end;
@ -125,6 +157,14 @@ qboolean World_movestep (world_t *world, wedict_t *ent, vec3_t move, qboolean re
int i;
wedict_t *enemy = world->edicts;
int eflags = ent->v->flags;
vec3_t eaxis[3];
if (!axis)
{
//fixme?
World_GetEntGravityAxis(ent, eaxis);
axis = eaxis;
}
#ifndef CLIENTONLY
if (progstype != PROG_H2 || world != &sv.world)
@ -147,13 +187,14 @@ qboolean World_movestep (world_t *world, wedict_t *ent, vec3_t move, qboolean re
enemy = (wedict_t*)PROG_TO_EDICT(world->progs, ent->v->enemy);
if (i == 0 && enemy->entnum)
{
dz = ent->v->origin[2] - ((wedict_t*)PROG_TO_EDICT(world->progs, ent->v->enemy))->v->origin[2];
VectorSubtract(ent->v->origin, ((wedict_t*)PROG_TO_EDICT(world->progs, ent->v->enemy))->v->origin, end);
dz = DotProduct(end, axis[2]);
if (eflags & FLH2_HUNTFACE) /*get the ent's origin_z to match its victims face*/
dz += ((wedict_t*)PROG_TO_EDICT(world->progs, ent->v->enemy))->v->view_ofs[2];
if (dz > 40)
neworg[2] -= 8;
VectorMA(neworg, -8, axis[2], neworg);
if (dz < 30)
neworg[2] += 8;
VectorMA(neworg, 8, axis[2], neworg);
}
}
trace = World_Move (world, ent->v->origin, ent->v->mins, ent->v->maxs, neworg, false, ent);
@ -179,9 +220,8 @@ qboolean World_movestep (world_t *world, wedict_t *ent, vec3_t move, qboolean re
}
// push down from a step height above the wished position
neworg[2] += movevars.stepheight;
VectorCopy (neworg, end);
end[2] -= movevars.stepheight*2;
VectorMA(neworg, movevars.stepheight, axis[2], neworg);
VectorMA(neworg, movevars.stepheight*-2, axis[2], end);
trace = World_Move (world, neworg, ent->v->mins, ent->v->maxs, end, false, ent);
if (set_move_trace)
@ -192,7 +232,8 @@ qboolean World_movestep (world_t *world, wedict_t *ent, vec3_t move, qboolean re
if (trace.startsolid)
{
neworg[2] -= movevars.stepheight;
//move up by an extra step, if needed
VectorMA(neworg, -movevars.stepheight, axis[2], neworg);
trace = World_Move (world, neworg, ent->v->mins, ent->v->maxs, end, false, ent);
if (set_move_trace)
set_move_trace(&trace, set_trace_globs);
@ -218,7 +259,7 @@ qboolean World_movestep (world_t *world, wedict_t *ent, vec3_t move, qboolean re
// check point traces down for dangling corners
VectorCopy (trace.endpos, ent->v->origin);
if (!World_CheckBottom (world, ent))
if (!World_CheckBottom (world, ent, axis[2]))
{
if ( (int)ent->v->flags & FL_PARTIALGROUND )
{ // entity had floor mostly pulled out from underneath it
@ -247,6 +288,28 @@ qboolean World_movestep (world_t *world, wedict_t *ent, vec3_t move, qboolean re
//============================================================================
qboolean World_GetEntGravityAxis(wedict_t *ent, vec3_t axis[3])
{
if (ent->xv->gravitydir[0] || ent->xv->gravitydir[1] || ent->xv->gravitydir[2])
{
void PerpendicularVector( vec3_t dst, const vec3_t src );
VectorNegate(ent->xv->gravitydir, axis[2]);
VectorNormalize(axis[2]);
PerpendicularVector(axis[0], axis[2]);
VectorNormalize(axis[0]);
CrossProduct(axis[2], axis[0], axis[1]);
VectorNormalize(axis[1]);
return true;
}
else
{
VectorSet(axis[0], 1, 0, 0);
VectorSet(axis[1], 0, 1, 0);
VectorSet(axis[2], 0, 0, 1);
return false;
}
}
/*
==============
PF_changeyaw
@ -254,9 +317,80 @@ PF_changeyaw
This was a major timewaster in progs, so it was converted to C
==============
*/
void World_changeyaw (wedict_t *ent)
float World_changeyaw (wedict_t *ent)
{
float ideal, current, move, speed;
vec3_t surf[3];
if (World_GetEntGravityAxis(ent, surf))
{
//complex matrix stuff
float mat[16];
float surfm[16], invsurfm[16];
float viewm[16];
vec3_t view[4];
vec3_t vang;
/*calc current view matrix relative to the surface*/
ent->v->angles[PITCH] *= -1;
AngleVectors(ent->v->angles, view[0], view[1], view[2]);
VectorNegate(view[1], view[1]);
World_GetEntGravityAxis(ent, surf);
Matrix4x4_RM_FromVectors(surfm, surf[0], surf[1], surf[2], vec3_origin);
Matrix3x4_InvertTo4x4_Simple(surfm, invsurfm);
/*calc current view matrix relative to the surface*/
Matrix4x4_RM_FromVectors(viewm, view[0], view[1], view[2], vec3_origin);
Matrix4_Multiply(viewm, invsurfm, mat);
/*convert that back to angles*/
Matrix3x4_RM_ToVectors(mat, view[0], view[1], view[2], view[3]);
VectorAngles(view[0], view[2], vang);
/*edit it*/
ideal = ent->v->ideal_yaw;
speed = ent->v->yaw_speed;
move = ideal - anglemod(vang[YAW]);
if (move > 180)
move -= 360;
else if (move < -180)
move += 360;
if (move > 0)
{
if (move > speed)
move = speed;
}
else
{
if (move < -speed)
move = -speed;
}
vang[YAW] = anglemod(vang[YAW] + move);
/*clamp pitch, kill roll. monsters don't pitch/roll.*/
vang[PITCH] = 0;
vang[ROLL] = 0;
move = ideal - vang[YAW];
/*turn those angles back to a matrix*/
AngleVectors(vang, view[0], view[1], view[2]);
VectorNegate(view[1], view[1]);
Matrix4x4_RM_FromVectors(mat, view[0], view[1], view[2], vec3_origin);
/*rotate back into world space*/
Matrix4_Multiply(mat, surfm, viewm);
/*and figure out the final result*/
Matrix3x4_RM_ToVectors(viewm, view[0], view[1], view[2], view[3]);
VectorAngles(view[0], view[2], ent->v->angles);
//make sure everything is sane
ent->v->angles[PITCH] = anglemod(ent->v->angles[PITCH]);
ent->v->angles[YAW] = anglemod(ent->v->angles[YAW]);
ent->v->angles[ROLL] = anglemod(ent->v->angles[ROLL]);
return move;
}
//FIXME: gravitydir. reorient the angles to change the yaw with respect to the current ground surface.
@ -265,7 +399,7 @@ void World_changeyaw (wedict_t *ent)
speed = ent->v->yaw_speed;
if (current == ideal)
return;
return 0;
move = ideal - current;
if (ideal > current)
{
@ -289,6 +423,8 @@ void World_changeyaw (wedict_t *ent)
}
ent->v->angles[1] = anglemod (current + move);
return ideal - ent->v->angles[1];
}
/*
@ -300,29 +436,31 @@ facing it.
======================
*/
qboolean World_StepDirection (world_t *world, wedict_t *ent, float yaw, float dist)
qboolean World_StepDirection (world_t *world, wedict_t *ent, float yaw, float dist, vec3_t axis[3])
{
vec3_t move, oldorigin;
float delta;
float delta, s;
ent->v->ideal_yaw = yaw;
World_changeyaw(ent);
delta = World_changeyaw(ent);
yaw = yaw*M_PI*2 / 360;
//FIXME: gravitydir
move[0] = cos(yaw)*dist;
move[1] = sin(yaw)*dist;
move[2] = 0;
s = cos(yaw)*dist;
VectorScale(axis[0], s, move);
s = sin(yaw)*dist;
VectorMA(move, s, axis[1], move);
//FIXME: Hexen2: ent flags & FL_SET_TRACE
VectorCopy (ent->v->origin, oldorigin);
if (World_movestep (world, ent, move, false, false, NULL, NULL))
if (World_movestep (world, ent, move, axis, false, false, NULL, NULL))
{
delta = ent->v->angles[YAW] - ent->v->ideal_yaw;
delta = anglemod(delta);
if (delta > 45 && delta < 315)
{ // not turned far enough, so don't take the step
{ // not turned far enough, so don't take the step
//FIXME: surely this is noticably inefficient?
VectorCopy (oldorigin, ent->v->origin);
}
World_LinkEdict (world, ent, true);
@ -356,7 +494,7 @@ SV_NewChaseDir
*/
#define DI_NODIR -1
void World_NewChaseDir (world_t *world, wedict_t *actor, wedict_t *enemy, float dist)
void World_NewChaseDir (world_t *world, wedict_t *actor, wedict_t *enemy, float dist, vec3_t axis[3])
{
float deltax,deltay;
float d[3];
@ -365,8 +503,9 @@ void World_NewChaseDir (world_t *world, wedict_t *actor, wedict_t *enemy, float
olddir = anglemod( (int)(actor->v->ideal_yaw/45)*45 );
turnaround = anglemod(olddir - 180);
deltax = enemy->v->origin[0] - actor->v->origin[0];
deltay = enemy->v->origin[1] - actor->v->origin[1];
VectorSubtract(enemy->v->origin, actor->v->origin, d);
deltax = DotProduct(d, axis[0]);
deltay = DotProduct(d, axis[1]);
if (deltax>10)
d[1]= 0;
else if (deltax<-10)
@ -388,7 +527,7 @@ void World_NewChaseDir (world_t *world, wedict_t *actor, wedict_t *enemy, float
else
tdir = d[2] == 90 ? 135 : 215;
if (tdir != turnaround && World_StepDirection(world, actor, tdir, dist))
if (tdir != turnaround && World_StepDirection(world, actor, tdir, dist, axis))
return;
}
@ -401,32 +540,32 @@ void World_NewChaseDir (world_t *world, wedict_t *actor, wedict_t *enemy, float
}
if (d[1]!=DI_NODIR && d[1]!=turnaround
&& World_StepDirection(world, actor, d[1], dist))
&& World_StepDirection(world, actor, d[1], dist, axis))
return;
if (d[2]!=DI_NODIR && d[2]!=turnaround
&& World_StepDirection(world, actor, d[2], dist))
&& World_StepDirection(world, actor, d[2], dist, axis))
return;
/* there is no direct path to the player, so pick another direction */
if (olddir!=DI_NODIR && World_StepDirection(world, actor, olddir, dist))
if (olddir!=DI_NODIR && World_StepDirection(world, actor, olddir, dist, axis))
return;
if (rand()&1) /*randomly determine direction of search*/
{
for (tdir=0 ; tdir<=315 ; tdir += 45)
if (tdir!=turnaround && World_StepDirection(world, actor, tdir, dist) )
if (tdir!=turnaround && World_StepDirection(world, actor, tdir, dist, axis) )
return;
}
else
{
for (tdir=315 ; tdir >=0 ; tdir -= 45)
if (tdir!=turnaround && World_StepDirection(world, actor, tdir, dist) )
if (tdir!=turnaround && World_StepDirection(world, actor, tdir, dist, axis) )
return;
}
if (turnaround != DI_NODIR && World_StepDirection(world, actor, turnaround, dist) )
if (turnaround != DI_NODIR && World_StepDirection(world, actor, turnaround, dist, axis) )
return;
actor->v->ideal_yaw = olddir; // can't move
@ -434,7 +573,7 @@ void World_NewChaseDir (world_t *world, wedict_t *actor, wedict_t *enemy, float
// if a bridge was pulled out from underneath a monster, it may not have
// a valid standing position at all
if (!World_CheckBottom (world, actor))
if (!World_CheckBottom (world, actor, axis[2]))
World_FixCheckBottom (actor);
}
@ -468,6 +607,7 @@ SV_MoveToGoal
qboolean World_MoveToGoal (world_t *world, wedict_t *ent, float dist)
{
wedict_t *goal;
vec3_t axis[3];
ent = (wedict_t*)PROG_TO_EDICT(world->progs, *world->g.self);
goal = (wedict_t*)PROG_TO_EDICT(world->progs, ent->v->goalentity);
@ -481,11 +621,14 @@ qboolean World_MoveToGoal (world_t *world, wedict_t *ent, float dist)
if ( PROG_TO_EDICT(world->progs, ent->v->enemy) != (edict_t*)world->edicts && World_CloseEnough (ent, goal, dist) )
return true;
World_GetEntGravityAxis(ent, axis);
// bump around...
if ( (rand()&3)==1 ||
!World_StepDirection (world, ent, ent->v->ideal_yaw, dist))
!World_StepDirection (world, ent, ent->v->ideal_yaw, dist, axis))
{
World_NewChaseDir (world, ent, goal, dist);
World_NewChaseDir (world, ent, goal, dist, axis);
}
return true;
}

View file

@ -70,6 +70,33 @@ void ClientReliableWrite_Begin(client_t *cl, int c, int maxsize)
ClientReliableWrite_Byte(cl, c);
}
client_t *ClientReliableWrite_BeginSplit(client_t *cl, int svc, int svclen)
{
if (cl->controller)
{ //this is a slave client.
//find the right number and send.
client_t *sp;
int pnum = 0;
for (sp = cl->controller; sp; sp = sp->controlled)
{
if (sp == cl)
break;
pnum++;
}
sp = cl->controller;
ClientReliableWrite_Begin (sp, svcfte_choosesplitclient, 2+svclen);
ClientReliableWrite_Byte (sp, pnum);
ClientReliableWrite_Byte (sp, svc);
return sp;
}
else
{
ClientReliableWrite_Begin (cl, svc, svclen);
return cl;
}
}
void ClientReliable_FinishWrite(client_t *cl)
{
if (cl->num_backbuf)

View file

@ -63,6 +63,7 @@ cvar_t sv_stepheight = CVARAFD("pm_stepheight", "", "sv_stepheight", CVAR_SERV
cvar_t pm_ktjump = CVARF("pm_ktjump", "", CVAR_SERVERINFO);
cvar_t pm_bunnyspeedcap = CVARFD("pm_bunnyspeedcap", "", CVAR_SERVERINFO, "0 or 1, ish. If the player is traveling faster than this speed while turning, their velocity will be gracefully reduced to match their current maxspeed. You can still rocket-jump to gain high velocity, but turning will reduce your speed back to the max. This can be used to disable bunny hopping.");
cvar_t pm_watersinkspeed = CVARFD("pm_watersinkspeed", "", CVAR_SERVERINFO, "This is the speed that players will sink at while inactive in water. Empty means 60.");
cvar_t pm_flyfriction = CVARFD("pm_flyfriction", "", CVAR_SERVERINFO, "Amount of friction that applies in fly or 6dof mode. Empty means 4.");
cvar_t pm_slidefix = CVARF("pm_slidefix", "", CVAR_SERVERINFO);
cvar_t pm_slidyslopes = CVARF("pm_slidyslopes", "", CVAR_SERVERINFO);
cvar_t pm_airstep = CVARF("pm_airstep", "", CVAR_SERVERINFO);
@ -281,13 +282,17 @@ static void WPhys_PortalTransform(world_t *w, wedict_t *ent, wedict_t *portal, v
VectorCopy(w->g.v_right, move);
// VectorCopy(w->g.v_up, ent->xv->gravitydir);
//monsters get their gravitydir set if it isn't already, to ensure that they still work (angle issues).
if ((int)ent->v->flags & FL_MONSTER)
if (!ent->xv->gravitydir[0] && !ent->xv->gravitydir[1] && !ent->xv->gravitydir[2])
ent->xv->gravitydir[2] = -1;
//transform the angles too
VectorCopy(org, G_VECTOR(OFS_PARM0));
if (ent->entnum <= svs.allocated_client_slots)
{
VectorCopy(ent->v->v_angle, ent->v->angles);
ent->v->fixangle = true;
}
else
ent->v->angles[0] *= -1;
@ -295,8 +300,36 @@ static void WPhys_PortalTransform(world_t *w, wedict_t *ent, wedict_t *portal, v
AngleVectors(ent->v->angles, w->g.v_forward, w->g.v_right, w->g.v_up);
PR_ExecuteProgram (w->progs, portal->xv->camera_transform);
VectorAngles(w->g.v_forward, w->g.v_up, ent->v->angles);
if (ent->entnum <= svs.allocated_client_slots)
if (ent->entnum > 0 && ent->entnum <= svs.allocated_client_slots)
{
client_t *cl = &svs.clients[ent->entnum-1];
int i;
vec3_t delta;
ent->v->angles[0] *= -1;
if (!cl->lockangles && (cl->fteprotocolextensions2 & PEXT2_SETANGLEDELTA))
{
cl = ClientReliableWrite_BeginSplit(cl, svcfte_setangledelta, 7);
VectorSubtract(ent->v->angles, ent->v->v_angle, delta);
delta[2] = anglemod(delta[2]);
if (delta[2] > 90 && delta[2] < 270)
{
delta[2] -= 180;
delta[1] -= 180;
delta[0] -= -180;
}
for (i=0 ; i < 3 ; i++)
ClientReliableWrite_Angle16 (cl, delta[i]);
}
else
{
cl = ClientReliableWrite_BeginSplit (cl, svc_setangle, 7);
for (i=0 ; i < 3 ; i++)
ClientReliableWrite_Angle (cl, ent->v->angles[i]);
}
VectorCopy(ent->v->angles, ent->v->v_angle);
ent->v->angles[0] *= -1;
}
/*
avelocity is horribly dependant upon eular angles. trying to treat it as a matrix is folly.
@ -2491,5 +2524,6 @@ void SV_SetMoveVars(void)
movevars.entgravity = 1.0;
movevars.stepheight = *sv_stepheight.string?sv_stepheight.value:PM_DEFAULTSTEPHEIGHT;
movevars.watersinkspeed = *pm_watersinkspeed.string?pm_watersinkspeed.value:60;
movevars.flyfriction = *pm_flyfriction.string?pm_flyfriction.value:60;
}
#endif

View file

@ -1307,7 +1307,7 @@ void SV_WriteClientdataToMessage (client_t *client, sizebuf_t *msg)
if (client->chokecount)
{
MSG_WriteByte (msg, svc_chokecount);
MSG_WriteByte (msg, client->chokecount);
MSG_WriteByte (msg, bound(0, client->chokecount, 255));
client->chokecount = 0;
}

View file

@ -90,6 +90,7 @@ extern cvar_t pm_slidyslopes;
extern cvar_t pm_airstep;
extern cvar_t pm_walljump;
extern cvar_t pm_watersinkspeed;
extern cvar_t pm_flyfriction;
cvar_t sv_pushplayers = SCVAR("sv_pushplayers", "0");
//yes, realip cvars need to be fully initialised or realip will be disabled
@ -938,6 +939,9 @@ void SV_SendClientPrespawnInfo(client_t *client)
ClientReliableWrite_Byte (client, track);
if (ISNQCLIENT(client))
ClientReliableWrite_Byte (client, track);
if (!track && *sv.h2miditrack)
SV_StuffcmdToClient(client, va("cd loop \"%s\"\n"));
}
else if (client->prespawn_idx == 2)
{
@ -4140,6 +4144,34 @@ void Cmd_Give_f (void)
}
}
void Cmd_Spiderpig_f(void)
{
if (!SV_MayCheat())
{
SV_TPrintToClient(host_client, PRINT_HIGH, "Cheats are not allowed on this server\n");
return;
}
if (!svprogfuncs)
return;
SV_LogPlayer(host_client, "spiderpig cheat");
if (sv_player->v->movetype != MOVETYPE_WALLWALK)
{
sv_player->v->movetype = MOVETYPE_WALLWALK;
sv_player->v->solid = SOLID_TRIGGER;
SV_ClientTPrintf (host_client, PRINT_HIGH, "Spider-Pig, Spider-Pig, does whatever a Spider-Pig does...\n");
}
else
{
sv_player->v->movetype = MOVETYPE_WALK;
if (sv_player->v->health > 0)
sv_player->v->solid = SOLID_SLIDEBOX;
else
sv_player->v->solid = SOLID_NOT;
SV_ClientTPrintf (host_client, PRINT_HIGH, "Spider-Pig, Spider-Pig!\n");
}
}
void Cmd_Noclip_f (void)
{
if (!SV_MayCheat())
@ -4169,6 +4201,34 @@ void Cmd_Noclip_f (void)
}
}
void Cmd_6dof_f (void)
{
if (!SV_MayCheat())
{
SV_TPrintToClient(host_client, PRINT_HIGH, "Cheats are not allowed on this server\n");
return;
}
if (!svprogfuncs)
return;
SV_LogPlayer(host_client, "6dof cheat");
if (sv_player->v->movetype != MOVETYPE_6DOF)
{
sv_player->v->movetype = MOVETYPE_6DOF;
SV_ClientTPrintf (host_client, PRINT_HIGH, "6dof mode ON\n");
}
else
{
sv_player->v->movetype = MOVETYPE_WALK;
if (sv_player->v->health > 0)
sv_player->v->solid = SOLID_SLIDEBOX;
else
sv_player->v->solid = SOLID_NOT;
SV_ClientTPrintf (host_client, PRINT_HIGH, "6dof mode OFF\n");
}
}
void Cmd_Fly_f (void)
{
if (!SV_MayCheat())
@ -5066,6 +5126,8 @@ ucmd_t ucmds[] =
{"god", Cmd_God_f},
{"give", Cmd_Give_f},
{"noclip", Cmd_Noclip_f},
{"spiderpig", Cmd_Spiderpig_f},
{"6dof", Cmd_6dof_f},
{"fly", Cmd_Fly_f},
{"notarget", Cmd_Notarget_f},
{"setpos", Cmd_SetPos_f},
@ -5635,6 +5697,9 @@ int SV_PMTypeForClient (client_t *cl)
case MOVETYPE_WALLWALK:
return PM_WALLWALK;
case MOVETYPE_6DOF:
return PM_6DOF;
case MOVETYPE_FLY:
return PM_FLY;
@ -5785,6 +5850,7 @@ void SV_RunCmd (usercmd_t *ucmd, qboolean recurse)
movevars.walljump = (pm_walljump.value);
movevars.slidyslopes = (pm_slidyslopes.value!=0);
movevars.watersinkspeed = *pm_watersinkspeed.string?pm_watersinkspeed.value:60;
movevars.flyfriction = *pm_flyfriction.string?pm_flyfriction.value:4;
for (i=0 ; i<3 ; i++)
{
@ -5977,6 +6043,7 @@ void SV_RunCmd (usercmd_t *ucmd, qboolean recurse)
movevars.walljump = (pm_walljump.value);
movevars.slidyslopes = (pm_slidyslopes.value!=0);
movevars.watersinkspeed = *pm_watersinkspeed.string?pm_watersinkspeed.value:60;
movevars.flyfriction = *pm_flyfriction.string?pm_flyfriction.value:4;
if (sv_player->xv->hasted)
movevars.maxspeed*=sv_player->xv->hasted;
@ -6015,6 +6082,19 @@ if (sv_player->v->health > 0 && before && !after )
#endif
pmove.world = NULL;
{
vec3_t delta;
VectorSubtract (pmove.angles, sv_player->v->v_angle, delta);
if (delta[0] || delta[1] || delta[2])
{
client_t *cl = ClientReliableWrite_BeginSplit(host_client, svcfte_setangledelta, 7);
for (i=0 ; i < 3 ; i++)
ClientReliableWrite_Angle16 (cl, delta[i]);
}
}
host_client->jump_held = pmove.jump_held;
if (progstype != PROG_QW) //this is just annoying.
{
@ -6049,7 +6129,7 @@ if (sv_player->v->health > 0 && before && !after )
VectorCopy (pmove.origin, sv_player->v->origin);
VectorCopy (pmove.angles, sv_player->v->v_angle);
VectorCopy (pmove.gravitydir, sv_player->xv->gravitydir);
// VectorCopy (pmove.gravitydir, sv_player->xv->gravitydir);
if (pmove.gravitydir[0] || pmove.gravitydir[1] || (pmove.gravitydir[2] && pmove.gravitydir[2] != -1))
{
if (!sv_player->v->fixangle)

View file

@ -1043,7 +1043,7 @@ static trace_t World_ClipMoveToEntity (world_t *w, wedict_t *ent, vec3_t eorg, v
//solid_portal cares only about origins and as such has no mins/max
TransformedTrace(model, 0, ent->v->frame, start, end, vec3_origin, vec3_origin, &trace, eorg, ent->v->angles, hitcontentsmask);
if (trace.startsolid) //portals should not block traces. this prevents infinite looping
trace.startsolid = trace.allsolid = false;
trace.startsolid = false;
hitmodel = false;
}
else if (ent->v->solid != SOLID_BSP)
@ -1368,7 +1368,7 @@ void WorldQ2_ClipMoveToEntities (world_t *w, moveclip_t *clip )
//a portal is flush with a world surface behind it.
//this causes problems. namely that we can't pass through the portal plane if the bsp behind it prevents out origin from getting through.
//so if the trace was clipped and ended infront of the portal, continue the trace to the edges of the portal cutout instead.
void World_PortalCSG(wedict_t *portal, float trminz, float trmaxz, vec3_t start, vec3_t end, trace_t *trace)
void World_PortalCSG(wedict_t *portal, float *trmin, float *trmax, vec3_t start, vec3_t end, trace_t *trace)
{
vec4_t planes[6]; //far, near, right, left, up, down
int plane;
@ -1391,19 +1391,26 @@ void World_PortalCSG(wedict_t *portal, float trminz, float trmaxz, vec3_t start,
VectorNegate(planes[3], planes[2]);
VectorNegate(planes[5], planes[4]);
trminz = fabs(trminz);
portalradius/=2;
planes[0][3] = DotProduct(portal->v->origin, planes[0]) - trminz-16;
planes[0][3] = DotProduct(portal->v->origin, planes[0]) - (1.0/32);
planes[1][3] = DotProduct(portal->v->origin, planes[1]) - (1.0/32); //an epsilon beyond the portal
planes[2][3] = DotProduct(portal->v->origin, planes[2]) - portalradius+trminz;
planes[3][3] = DotProduct(portal->v->origin, planes[3]) - portalradius+trminz;
planes[4][3] = DotProduct(portal->v->origin, planes[4]) - portalradius+trminz;
planes[5][3] = DotProduct(portal->v->origin, planes[5]) - portalradius+trminz;
planes[2][3] = DotProduct(portal->v->origin, planes[2]) - portalradius;
planes[3][3] = DotProduct(portal->v->origin, planes[3]) - portalradius;
planes[4][3] = DotProduct(portal->v->origin, planes[4]) - portalradius;
planes[5][3] = DotProduct(portal->v->origin, planes[5]) - portalradius;
//if we're actually inside the csg region
for (plane = 0; plane < 6; plane++)
{
vec3_t nearest;
float d = DotProduct(worldpos, planes[plane]);
int k;
for (k = 0; k < 3; k++)
nearest[k] = (planes[plane][k]>=0)?trmax[k]:trmin[k];
if (!plane) //front plane gets further away with side
planes[plane][3] -= DotProduct(nearest, planes[plane]);
else if (plane>1) //side planes get nearer with size
planes[plane][3] += DotProduct(nearest, planes[plane]);
if (d - planes[plane][3] >= 0)
continue; //endpos is inside
else
@ -1418,7 +1425,7 @@ void World_PortalCSG(wedict_t *portal, float trminz, float trmaxz, vec3_t start,
float ds = DotProduct(start, planes[plane]) - planes[plane][3];
float de = DotProduct(end, planes[plane]) - planes[plane][3];
float frac;
if (ds > 0 && de < 0)
if (ds >= 0 && de < 0)
{
frac = (ds-(1.0/32)) / (ds - de);
if (frac < trace->fraction)
@ -1504,7 +1511,7 @@ static void World_ClipToEverything (world_t *w, moveclip_t *clip)
if (touch->v->solid == SOLID_PORTAL)
{
//make sure we don't hit the world if we're inside the portal
World_PortalCSG(touch, clip->mins[2], clip->maxs[2], clip->start, clip->end, &clip->trace);
World_PortalCSG(touch, clip->mins, clip->maxs, clip->start, clip->end, &clip->trace);
}
if ((int)touch->v->flags & FL_MONSTER)
@ -1611,7 +1618,7 @@ static void World_ClipToLinks (world_t *w, areanode_t *node, moveclip_t *clip)
if (touch->v->solid == SOLID_PORTAL)
{
//make sure we don't hit the world if we're inside the portal
World_PortalCSG(touch, clip->mins[2], clip->maxs[2], clip->start, clip->end, &clip->trace);
World_PortalCSG(touch, clip->mins, clip->maxs, clip->start, clip->end, &clip->trace);
}
if ((int)touch->v->flags & FL_MONSTER)