1
0
Fork 0
forked from fte/fteqw

added multiple joystick support in windows.

fixed portals. again. now pushing the player out (reverting origin) if they get de-spawned.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4711 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2014-07-12 06:56:17 +00:00
parent d710d945d0
commit b97bc5685c
17 changed files with 391 additions and 302 deletions

View file

@ -405,6 +405,7 @@ void CL_PredictUsercmd (int pnum, int entnum, player_state_t *from, player_state
movevars.maxspeed = cl.playerview[pnum].maxspeed; movevars.maxspeed = cl.playerview[pnum].maxspeed;
movevars.bunnyspeedcap = cl.bunnyspeedcap; movevars.bunnyspeedcap = cl.bunnyspeedcap;
pmove.onladder = false; pmove.onladder = false;
pmove.safeorigin_known = false;
VectorCopy(from->szmins, pmove.player_mins); VectorCopy(from->szmins, pmove.player_mins);
VectorCopy(from->szmaxs, pmove.player_maxs); VectorCopy(from->szmaxs, pmove.player_maxs);

View file

@ -120,7 +120,6 @@ static DWORD dwAxisFlags[JOY_MAX_AXES] =
static DWORD dwAxisMap[JOY_MAX_AXES]; static DWORD dwAxisMap[JOY_MAX_AXES];
static DWORD dwControlMap[JOY_MAX_AXES]; static DWORD dwControlMap[JOY_MAX_AXES];
static PDWORD pdwRawValue[JOY_MAX_AXES];
// none of these cvars are saved over a session // none of these cvars are saved over a session
// this means that advanced controller configuration needs to be executed // this means that advanced controller configuration needs to be executed
@ -147,12 +146,23 @@ static cvar_t joy_yawsensitivity = CVAR("joyyawsensitivity", "-1.0");
static cvar_t joy_wwhack1 = CVAR("joywwhack1", "0.0"); static cvar_t joy_wwhack1 = CVAR("joywwhack1", "0.0");
static cvar_t joy_wwhack2 = CVAR("joywwhack2", "0.0"); static cvar_t joy_wwhack2 = CVAR("joywwhack2", "0.0");
static qboolean joy_avail, joy_advancedinit, joy_haspov; static qboolean joy_advancedinit;
static DWORD joy_oldbuttonstate, joy_oldpovstate;
static int joy_id;
static DWORD joy_flags; static DWORD joy_flags;
static DWORD joy_numbuttons; #define MAX_JOYSTICKS 4
static struct wjoy_s {
unsigned int id; //windows id. device id is the index.
unsigned int devid; //quake id (generally player index)
DWORD numbuttons;
qboolean haspov;
DWORD povstate;
DWORD oldpovstate;
DWORD buttonstate;
DWORD oldbuttonstate;
DWORD axis[JOY_MAX_AXES];
} wjoy[MAX_JOYSTICKS];
static int joy_count;
#ifdef AVAIL_DINPUT #ifdef AVAIL_DINPUT
static const GUID fGUID_XAxis = {0xA36D02E0, 0xC9F3, 0x11CF, {0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}}; static const GUID fGUID_XAxis = {0xA36D02E0, 0xC9F3, 0x11CF, {0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}};
@ -1318,8 +1328,7 @@ void INS_Move (float *movements, int pnum)
if (ActiveApp && !Minimized) if (ActiveApp && !Minimized)
{ {
INS_MouseMove (movements, pnum); INS_MouseMove (movements, pnum);
if (pnum == 1 || cl.splitclients<2) INS_JoyMove (movements, pnum);
INS_JoyMove (movements, pnum);
} }
} }
@ -1530,20 +1539,50 @@ void INS_ClearStates (void)
} }
} }
/* /*
=============== ===============
INS_StartupJoystick INS_StartupJoystick
=============== ===============
*/ */
void INS_StartupJoystick (void) static void INS_StartupJoystickId(unsigned int id)
{ {
int numdevs;
JOYCAPS jc; JOYCAPS jc;
MMRESULT mmr; MMRESULT mmr;
struct wjoy_s *joy;
if (joy_count == MAX_JOYSTICKS)
return;
joy = &wjoy[joy_count];
memset(joy, 0, sizeof(*joy));
joy->id = id;
joy->devid = 1+joy_count; //FIXME: this is a hack. make joysticks 1-based. this means mouse0 controls 1st player, joy0 controls 2nd player (controls wrap so joy1 controls 1st player too.
// assume no joystick // get the capabilities of the selected joystick
joy_avail = false; // abort startup if command fails
memset (&jc, 0, sizeof(jc));
if ((mmr = joyGetDevCaps (joy->id, &jc, sizeof(jc))) != JOYERR_NOERROR)
{
Con_Printf ("joystick %03x not found -- invalid joystick capabilities (%x)\n", id, mmr);
return;
}
// save the joystick's number of buttons and POV status
joy->numbuttons = jc.wNumButtons;
joy->haspov = jc.wCaps & JOYCAPS_HASPOV;
// mark the joystick as available and advanced initialization not completed
// this is needed as cvars are not available during initialization
joy_advancedinit = false;
joy_count++;
}
void INS_StartupJoystick (void)
{
unsigned int id, numdevs;
MMRESULT mmr;
// assume no joysticks
joy_count = 0;
// abort startup if user requests no joystick // abort startup if user requests no joystick
if ( COM_CheckParm ("-nojoy") ) if ( COM_CheckParm ("-nojoy") )
@ -1559,75 +1598,21 @@ void INS_StartupJoystick (void)
mmr = JOYERR_UNPLUGGED; mmr = JOYERR_UNPLUGGED;
// cycle through the joystick ids for the first valid one // cycle through the joystick ids for the first valid one
for (joy_id=0 ; joy_id<numdevs ; joy_id++) for (id=0 ; id<numdevs ; id++)
{ {
memset (&ji, 0, sizeof(ji)); memset (&ji, 0, sizeof(ji));
ji.dwSize = sizeof(ji); ji.dwSize = sizeof(ji);
ji.dwFlags = JOY_RETURNCENTERED; ji.dwFlags = JOY_RETURNCENTERED;
if ((mmr = joyGetPosEx (joy_id, &ji)) == JOYERR_NOERROR) if ((mmr = joyGetPosEx (id, &ji)) == JOYERR_NOERROR)
break; {
INS_StartupJoystickId(id);
}
} }
// abort startup if we didn't find a valid joystick Con_Printf ("found %i joysticks\n", joy_count);
if (mmr != JOYERR_NOERROR)
{
// Con_Printf ("joystick not found -- no valid joysticks (%x)\n", mmr);
return;
}
// get the capabilities of the selected joystick
// abort startup if command fails
memset (&jc, 0, sizeof(jc));
if ((mmr = joyGetDevCaps (joy_id, &jc, sizeof(jc))) != JOYERR_NOERROR)
{
Con_Printf ("joystick not found -- invalid joystick capabilities (%x)\n", mmr);
return;
}
// save the joystick's number of buttons and POV status
joy_numbuttons = jc.wNumButtons;
joy_haspov = jc.wCaps & JOYCAPS_HASPOV;
// old button and POV states default to no buttons pressed
joy_oldbuttonstate = joy_oldpovstate = 0;
// mark the joystick as available and advanced initialization not completed
// this is needed as cvars are not available during initialization
joy_avail = true;
joy_advancedinit = false;
Con_Printf ("joystick detected\n");
} }
/*
===========
RawValuePointer
===========
*/
static PDWORD RawValuePointer (int axis)
{
switch (axis)
{
case JOY_AXIS_X:
return &ji.dwXpos;
case JOY_AXIS_Y:
return &ji.dwYpos;
case JOY_AXIS_Z:
return &ji.dwZpos;
case JOY_AXIS_R:
return &ji.dwRpos;
case JOY_AXIS_U:
return &ji.dwUpos;
case JOY_AXIS_V:
return &ji.dwVpos;
}
return 0; //compiler shut up.
}
/* /*
=========== ===========
Joy_AdvancedUpdate_f Joy_AdvancedUpdate_f
@ -1646,7 +1631,6 @@ void Joy_AdvancedUpdate_f (void)
{ {
dwAxisMap[i] = AxisNada; dwAxisMap[i] = AxisNada;
dwControlMap[i] = JOY_ABSOLUTE_AXIS; dwControlMap[i] = JOY_ABSOLUTE_AXIS;
pdwRawValue[i] = RawValuePointer(i);
} }
if( joy_advanced.value == 0.0) if( joy_advanced.value == 0.0)
@ -1709,63 +1693,64 @@ void INS_Commands (void)
{ {
int i, key_index; int i, key_index;
DWORD buttonstate, povstate; DWORD buttonstate, povstate;
unsigned int idx;
struct wjoy_s *joy;
if (!joy_avail) for (idx = 0; idx < joy_count; idx++)
{ {
return; joy = &wjoy[idx];
}
// loop through the joystick buttons
// loop through the joystick buttons // key a joystick event or auxillary event for higher number buttons for each state change
// key a joystick event or auxillary event for higher number buttons for each state change buttonstate = joy->buttonstate;
buttonstate = ji.dwButtons; for (i=0 ; i < joy->numbuttons ; i++)
for (i=0 ; i < joy_numbuttons ; i++)
{
if ( (buttonstate & (1<<i)) && !(joy_oldbuttonstate & (1<<i)) )
{ {
key_index = (i < 4) ? K_JOY1 : K_AUX1; if ( (buttonstate & (1<<i)) && !(joy->oldbuttonstate & (1<<i)) )
Key_Event (0, key_index + i, 0, true);
}
if ( !(buttonstate & (1<<i)) && (joy_oldbuttonstate & (1<<i)) )
{
key_index = (i < 4) ? K_JOY1 : K_AUX1;
Key_Event (0, key_index + i, 0, false);
}
}
joy_oldbuttonstate = buttonstate;
if (joy_haspov)
{
// convert POV information into 4 bits of state information
// this avoids any potential problems related to moving from one
// direction to another without going through the center position
povstate = 0;
if(ji.dwPOV != JOY_POVCENTERED)
{
if (ji.dwPOV == JOY_POVFORWARD)
povstate |= 0x01;
if (ji.dwPOV == JOY_POVRIGHT)
povstate |= 0x02;
if (ji.dwPOV == JOY_POVBACKWARD)
povstate |= 0x04;
if (ji.dwPOV == JOY_POVLEFT)
povstate |= 0x08;
}
// determine which bits have changed and key an auxillary event for each change
for (i=0 ; i < 4 ; i++)
{
if ( (povstate & (1<<i)) && !(joy_oldpovstate & (1<<i)) )
{ {
Key_Event (0, K_AUX29 + i, 0, true); key_index = (i < 4) ? K_JOY1 : K_AUX1;
Key_Event (joy->devid, key_index + i, 0, true);
} }
if ( !(povstate & (1<<i)) && (joy_oldpovstate & (1<<i)) ) if ( !(buttonstate & (1<<i)) && (joy->oldbuttonstate & (1<<i)) )
{ {
Key_Event (0, K_AUX29 + i, 0, false); key_index = (i < 4) ? K_JOY1 : K_AUX1;
Key_Event (joy->devid, key_index + i, 0, false);
} }
} }
joy_oldpovstate = povstate; joy->oldbuttonstate = buttonstate;
if (joy->haspov)
{
// convert POV information into 4 bits of state information
// this avoids any potential problems related to moving from one
// direction to another without going through the center position
povstate = 0;
if(joy->povstate != JOY_POVCENTERED)
{
if (joy->povstate == JOY_POVFORWARD)
povstate |= 0x01;
if (joy->povstate == JOY_POVRIGHT)
povstate |= 0x02;
if (joy->povstate == JOY_POVBACKWARD)
povstate |= 0x04;
if (joy->povstate == JOY_POVLEFT)
povstate |= 0x08;
}
// determine which bits have changed and key an auxillary event for each change
for (i=0 ; i < 4 ; i++)
{
if ( (povstate & (1<<i)) && !(joy->oldpovstate & (1<<i)) )
{
Key_Event (joy->devid, K_AUX29 + i, 0, true);
}
if ( !(povstate & (1<<i)) && (joy->oldpovstate & (1<<i)) )
{
Key_Event (joy->devid, K_AUX29 + i, 0, false);
}
}
joy->oldpovstate = povstate;
}
} }
} }
@ -1775,14 +1760,13 @@ void INS_Commands (void)
INS_ReadJoystick INS_ReadJoystick
=============== ===============
*/ */
qboolean INS_ReadJoystick (void) qboolean INS_ReadJoystick (struct wjoy_s *joy)
{ {
memset (&ji, 0, sizeof(ji)); memset (&ji, 0, sizeof(ji));
ji.dwSize = sizeof(ji); ji.dwSize = sizeof(ji);
ji.dwFlags = joy_flags; ji.dwFlags = joy_flags;
if (joyGetPosEx (joy_id, &ji) == JOYERR_NOERROR) if (joyGetPosEx (joy->id, &ji) == JOYERR_NOERROR)
{ {
// this is a hack -- there is a bug in the Logitech WingMan Warrior DirectInput Driver // this is a hack -- there is a bug in the Logitech WingMan Warrior DirectInput Driver
// rather than having 32768 be the zero point, they have the zero point at 32668 // rather than having 32768 be the zero point, they have the zero point at 32668
@ -1791,6 +1775,14 @@ qboolean INS_ReadJoystick (void)
{ {
ji.dwUpos += 100; ji.dwUpos += 100;
} }
joy->povstate = ji.dwPOV;
joy->buttonstate = ji.dwButtons;
joy->axis[JOY_AXIS_X] = ji.dwXpos;
joy->axis[JOY_AXIS_Y] = ji.dwYpos;
joy->axis[JOY_AXIS_Z] = ji.dwZpos;
joy->axis[JOY_AXIS_R] = ji.dwRpos;
joy->axis[JOY_AXIS_U] = ji.dwUpos;
joy->axis[JOY_AXIS_V] = ji.dwVpos;
return true; return true;
} }
else else
@ -1804,34 +1796,27 @@ qboolean INS_ReadJoystick (void)
} }
} }
static void INS_JoyMovePtr (struct wjoy_s *joy, float *movements, int pnum)
/*
===========
INS_JoyMove
===========
*/
void INS_JoyMove (float *movements, int pnum)
{ {
float speed, aspeed; float speed, aspeed;
float fAxisValue, fTemp; float fAxisValue, fTemp;
int i; int i;
int wpnum;
// complete initialization if first time in /*each device will be processed when its player comes to be processed*/
// this is needed as cvars are not available at initialization time wpnum = cl.splitclients;
if( joy_advancedinit != true ) if (wpnum < 1)
{ wpnum = 1;
Joy_AdvancedUpdate_f(); if (cl_forcesplitclient.ival)
joy_advancedinit = true; wpnum = (cl_forcesplitclient.ival-1) % wpnum;
} else
wpnum = joy->devid % wpnum;
// verify joystick is available and that the user wants to use it if (wpnum != pnum)
if (!joy_avail || !in_joystick.value)
{
return; return;
}
// collect the joystick data, if possible // collect the joystick data, if possible
if (INS_ReadJoystick () != true) if (INS_ReadJoystick (joy) != true)
{ {
return; return;
} }
@ -1846,7 +1831,7 @@ void INS_JoyMove (float *movements, int pnum)
for (i = 0; i < JOY_MAX_AXES; i++) for (i = 0; i < JOY_MAX_AXES; i++)
{ {
// get the floating point zero-centered, potentially-inverted data for the current axis // get the floating point zero-centered, potentially-inverted data for the current axis
fAxisValue = (float) *pdwRawValue[i]; fAxisValue = (float) joy->axis[i];
// move centerpoint to zero // move centerpoint to zero
fAxisValue -= 32768.0; fAxisValue -= 32768.0;
@ -1870,7 +1855,7 @@ void INS_JoyMove (float *movements, int pnum)
fAxisValue /= 32768.0; fAxisValue /= 32768.0;
#ifdef CSQC_DAT #ifdef CSQC_DAT
if (CSQC_JoystickAxis(i, fAxisValue, 0)) if (CSQC_JoystickAxis(i, fAxisValue, joy->devid))
continue; continue;
#endif #endif
@ -1983,6 +1968,32 @@ void INS_JoyMove (float *movements, int pnum)
CL_ClampPitch(pnum); CL_ClampPitch(pnum);
} }
/*
===========
INS_JoyMove
===========
*/
void INS_JoyMove (float *movements, int pnum)
{
unsigned int idx;
// complete initialization if first time in
// this is needed as cvars are not available at initialization time
if( joy_advancedinit != true )
{
Joy_AdvancedUpdate_f();
joy_advancedinit = true;
}
// verify joystick is available and that the user wants to use it
if (!in_joystick.value)
return;
for (idx = 0; idx < joy_count; idx++)
{
INS_JoyMovePtr(&wjoy[idx], movements, idx);
}
}
static qbyte scantokey[] = static qbyte scantokey[] =
{ {

View file

@ -2133,6 +2133,7 @@ void Key_Event (int devid, int key, unsigned int unicode, qboolean down)
if (key_repeats[key] > 1) if (key_repeats[key] > 1)
return; return;
//first player is normally assumed anyway.
if (devid) if (devid)
Q_snprintfz (p, sizeof(p), "p %i ", devid+1); Q_snprintfz (p, sizeof(p), "p %i ", devid+1);
else else

View file

@ -2512,6 +2512,7 @@ static void QCBUILTIN PF_cs_runplayerphysics (pubprogfuncs_t *prinst, struct glo
pmove.cmd.sidemove = csqcg.input_movevalues[1]; pmove.cmd.sidemove = csqcg.input_movevalues[1];
pmove.cmd.upmove = csqcg.input_movevalues[2]; pmove.cmd.upmove = csqcg.input_movevalues[2];
pmove.cmd.buttons = *csqcg.input_buttons; pmove.cmd.buttons = *csqcg.input_buttons;
pmove.safeorigin_known = false;
if (ent) if (ent)
{ {

View file

@ -1129,7 +1129,7 @@ qboolean rag_animate(skelobject_t *sko, doll_t *doll, float *emat)
int i; int i;
for (i = 0; i < sko->numbodies; i++) for (i = 0; i < sko->numbodies; i++)
{ {
if (!doll->body[i].animate) if (!sko->body[i].animstrength)
continue; continue;
rag_genbodymatrix(sko, &doll->body[i], emat, sko->body[i].animmatrix); rag_genbodymatrix(sko, &doll->body[i], emat, sko->body[i].animmatrix);
} }
@ -1370,7 +1370,7 @@ void rag_doallanimations(world_t *world)
for (j = 0; j < sko->numbodies; j++) for (j = 0; j < sko->numbodies; j++)
{ {
if (!doll->body[j].animate) if (!sko->body[j].animstrength)
continue; continue;
World_ODE_RagMatrixToBody(&sko->body[j].odebody, sko->body[j].animmatrix); World_ODE_RagMatrixToBody(&sko->body[j].odebody, sko->body[j].animmatrix);
} }
@ -1606,7 +1606,7 @@ void QCBUILTIN PF_skel_ragedit(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
} }
else if (!doll) else if (!doll)
{ {
G_FLOAT(OFS_RETURN) = 1; //technically success. G_FLOAT(OFS_RETURN) = !!*ragname; //technically success.
return; return;
} }
else if (sko->numanimated) else if (sko->numanimated)

View file

@ -3857,7 +3857,7 @@ qboolean Mod_GetTag(model_t *model, int tagnum, framestate_t *fstate, float *res
result[10] = 1; result[10] = 1;
while(tagnum >= 0) while(tagnum >= 0)
{ {
for (lerp = lerps; tagnum < lerp->endbone; lerp++) for (lerp = lerps; tagnum < lerp->firstbone; lerp++)
; ;
//set up the per-bone transform matrix //set up the per-bone transform matrix
matrix = lerp->pose[0] + tagnum*12; matrix = lerp->pose[0] + tagnum*12;

View file

@ -228,16 +228,9 @@ Netchan_Init
*/ */
void Netchan_Init (void) void Netchan_Init (void)
{ {
static char qportstr[16];
int port; int port;
Cvar_Register (&pext_nqpredinfo, "Protocol Extensions");
Cvar_Register (&pext_replacementdeltas, "Protocol Extensions");
Cvar_Register (&showpackets, "Networking");
Cvar_Register (&showdrop, "Networking");
Cvar_Register (&qport, "Networking");
Cvar_Register (&net_mtu, "Networking");
Cvar_Register (&net_compress, "Networking");
// pick a port value that should be nice and random // pick a port value that should be nice and random
#ifdef _WIN32 #ifdef _WIN32
port = (time(NULL)) & 0xffff; port = (time(NULL)) & 0xffff;
@ -246,8 +239,16 @@ void Netchan_Init (void)
#else #else
port = ((int)(getpid()+getuid()*1000) * time(NULL)) & 0xffff; port = ((int)(getpid()+getuid()*1000) * time(NULL)) & 0xffff;
#endif #endif
Q_snprintfz(qportstr, sizeof(qportstr), "%i", port);
qport.string = qportstr;
Cvar_SetValue (&qport, port); Cvar_Register (&pext_nqpredinfo, "Protocol Extensions");
Cvar_Register (&pext_replacementdeltas, "Protocol Extensions");
Cvar_Register (&showpackets, "Networking");
Cvar_Register (&showdrop, "Networking");
Cvar_Register (&qport, "Networking");
Cvar_Register (&net_mtu, "Networking");
Cvar_Register (&net_compress, "Networking");
} }
/* /*

View file

@ -84,12 +84,15 @@ void PM_ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
} }
#include "pr_common.h" #include "pr_common.h"
static qboolean PM_PortalTransform(world_t *w, int portalnum, vec3_t org, vec3_t move) static qboolean PM_PortalTransform(world_t *w, int portalnum, vec3_t org, vec3_t move, vec3_t newang, vec3_t newvel)
{ {
vec3_t rounded;
qboolean okay = true; qboolean okay = true;
wedict_t *portal = WEDICT_NUM(w->progs, portalnum); wedict_t *portal = WEDICT_NUM(w->progs, portalnum);
int oself = *w->g.self; int oself = *w->g.self;
void *pr_globals = PR_globals(w->progs, PR_CURRENT); void *pr_globals = PR_globals(w->progs, PR_CURRENT);
int i;
int tmp;
*w->g.self = EDICT_TO_PROG(w->progs, portal); *w->g.self = EDICT_TO_PROG(w->progs, portal);
//transform origin+velocity etc //transform origin+velocity etc
@ -103,15 +106,20 @@ static qboolean PM_PortalTransform(world_t *w, int portalnum, vec3_t org, vec3_t
PR_ExecuteProgram (w->progs, portal->xv->camera_transform); PR_ExecuteProgram (w->progs, portal->xv->camera_transform);
for (i = 0; i < 3; i++)
{
tmp = floor(G_VECTOR(OFS_RETURN)[i]*8 + 0.5);
rounded[i] = tmp/8.0;
}
//make sure the new origin is okay for the player. back out if its invalid. //make sure the new origin is okay for the player. back out if its invalid.
if (!PM_TestPlayerPosition(G_VECTOR(OFS_RETURN), true)) if (!PM_TestPlayerPosition(rounded, true))
okay = false; okay = false;
else else
{ {
VectorCopy(G_VECTOR(OFS_RETURN), org); VectorCopy(rounded, org);
VectorCopy(w->g.v_forward, pmove.velocity); VectorCopy(w->g.v_forward, newvel);
VectorCopy(w->g.v_right, move); VectorCopy(w->g.v_right, move);
VectorCopy(w->g.v_up, pmove.gravitydir); // VectorCopy(w->g.v_up, pmove.gravitydir);
//transform the angles too //transform the angles too
@ -119,8 +127,8 @@ static qboolean PM_PortalTransform(world_t *w, int portalnum, vec3_t org, vec3_t
VectorCopy(pmove.angles, G_VECTOR(OFS_PARM1)); VectorCopy(pmove.angles, G_VECTOR(OFS_PARM1));
AngleVectors(pmove.angles, w->g.v_forward, w->g.v_right, w->g.v_up); AngleVectors(pmove.angles, w->g.v_forward, w->g.v_right, w->g.v_up);
PR_ExecuteProgram (w->progs, portal->xv->camera_transform); PR_ExecuteProgram (w->progs, portal->xv->camera_transform);
VectorAngles(w->g.v_forward, w->g.v_up, pmove.angles); VectorAngles(w->g.v_forward, w->g.v_up, newang);
pmove.angles[0] *= -1; newang[0] *= -1;
} }
*w->g.self = oself; *w->g.self = oself;
@ -139,18 +147,32 @@ static trace_t PM_PlayerTracePortals(vec3_t start, vec3_t end, unsigned int soli
{ {
vec3_t move; vec3_t move;
vec3_t from; vec3_t from;
vec3_t newang, newvel;
VectorCopy(trace.endpos, from); //just in case VectorCopy(trace.endpos, from); //just in case
VectorSubtract(end, trace.endpos, move); VectorSubtract(end, trace.endpos, move);
if (PM_PortalTransform(pmove.world, impact->info, from, move)) if (PM_PortalTransform(pmove.world, impact->info, from, move, newang, newvel))
{ {
trace_t exit;
int i, tmp;
VectorAdd(from, move, end); VectorAdd(from, move, end);
//if we follow the portal, then we basically need to restart from the other side. //if we follow the portal, then we basically need to restart from the other side.
if (tookportal) exit = PM_PlayerTrace (from, end, MASK_PLAYERSOLID);
*tookportal = trace.fraction;
for (i = 0; i < 3; i++)
return PM_PlayerTrace (from, end, MASK_PLAYERSOLID); {
tmp = floor(exit.endpos[i]*8 + 0.5);
exit.endpos[i] = tmp/8.0;
}
if (PM_TestPlayerPosition(exit.endpos, false))
{
if (tookportal)
*tookportal = trace.fraction;
VectorCopy(newang, pmove.angles);
VectorCopy(newvel, pmove.velocity);
return exit;
}
} }
} }
} }
@ -1073,15 +1095,16 @@ void PM_NudgePosition (void)
for (i=0 ; i<3 ; i++) for (i=0 ; i<3 ; i++)
base[i] = ((int)(base[i]*8)) * 0.125; base[i] = ((int)(base[i]*8)) * 0.125;
if (pmove.velocity[0] || pmove.velocity[1]) //if we're moving, allow that spot without snapping to any grid
if (pmove.velocity[0] || pmove.velocity[1] || pmove.velocity[2])
if (PM_TestPlayerPosition (pmove.origin, false)) if (PM_TestPlayerPosition (pmove.origin, false))
return; return;
for (z=0 ; z<=4 ; z++) for (z=0 ; z<sizeof(sign)/sizeof(sign[0]) ; z++)
{ {
for (x=0 ; x<=4 ; x++) for (x=0 ; x<sizeof(sign)/sizeof(sign[0]) ; x++)
{ {
for (y=0 ; y<=4 ; y++) for (y=0 ; y<sizeof(sign)/sizeof(sign[0]) ; y++)
{ {
pmove.origin[0] = base[0] + (sign[x] * 1.0/8); pmove.origin[0] = base[0] + (sign[x] * 1.0/8);
pmove.origin[1] = base[1] + (sign[y] * 1.0/8); pmove.origin[1] = base[1] + (sign[y] * 1.0/8);
@ -1091,7 +1114,10 @@ void PM_NudgePosition (void)
} }
} }
} }
VectorCopy (base, pmove.origin); if (pmove.safeorigin_known)
VectorCopy (pmove.safeorigin, pmove.origin);
else
VectorCopy (base, pmove.origin);
// Com_DPrintf ("NudgePosition: stuck\n"); // Com_DPrintf ("NudgePosition: stuck\n");
} }
@ -1267,6 +1293,7 @@ void PM_PlayerMove (float gamespeed)
PM_ClipVelocity (pmove.velocity, groundplane.normal, pmove.velocity, 1); PM_ClipVelocity (pmove.velocity, groundplane.normal, pmove.velocity, 1);
} }
/*
//round to network precision //round to network precision
for (i = 0; i < 3; i++) for (i = 0; i < 3; i++)
{ {
@ -1275,4 +1302,5 @@ void PM_PlayerMove (float gamespeed)
tmp = floor(pmove.origin[i]*8 + 0.5); tmp = floor(pmove.origin[i]*8 + 0.5);
pmove.origin[i] = tmp/8.0; pmove.origin[i] = tmp/8.0;
} }
*/
} }

View file

@ -56,6 +56,7 @@ typedef struct
// player state // player state
vec3_t origin; vec3_t origin;
vec3_t safeorigin;
vec3_t angles; vec3_t angles;
vec3_t velocity; vec3_t velocity;
vec3_t basevelocity; vec3_t basevelocity;
@ -75,6 +76,7 @@ typedef struct
usercmd_t cmd; usercmd_t cmd;
qboolean onladder; qboolean onladder;
qboolean safeorigin_known;
// results // results
int skipent; int skipent;

View file

@ -358,13 +358,14 @@ PM_TestPlayerPosition
Returns false if the given player position is not valid (in solid) Returns false if the given player position is not valid (in solid)
================ ================
*/ */
qboolean PM_TestPlayerPosition (vec3_t pos, qboolean ignoreportals) int PM_TestPlayerPosition (vec3_t pos, qboolean ignoreportals)
{ {
int i, j; int i, j;
physent_t *pe; physent_t *pe;
vec3_t mins, maxs; vec3_t mins, maxs;
hull_t *hull; hull_t *hull;
trace_t trace; trace_t trace;
int csged = false;
for (i=0 ; i< pmove.numphysent ; i++) for (i=0 ; i< pmove.numphysent ; i++)
{ {
@ -416,6 +417,7 @@ qboolean PM_TestPlayerPosition (vec3_t pos, qboolean ignoreportals)
} }
if (trace.allsolid) if (trace.allsolid)
return false; return false;
csged = true;
} }
} }
else else
@ -431,6 +433,13 @@ qboolean PM_TestPlayerPosition (vec3_t pos, qboolean ignoreportals)
} }
} }
if (!csged && !ignoreportals)
{
//the point the player is returned to if the portal dissipates
pmove.safeorigin_known = true;
VectorCopy (pmove.origin, pmove.safeorigin);
}
return true; return true;
} }

View file

@ -3019,6 +3019,13 @@ void QCBUILTIN PF_strftime (pubprogfuncs_t *prinst, struct globalvars_s *pr_glob
tm = localtime(&ctime); tm = localtime(&ctime);
else else
tm = gmtime(&ctime); tm = gmtime(&ctime);
//msvc sucks.
if (!strcmp(in, "%R"))
in = "%H:%M";
else if (!strcmp(in, "%F"))
in = "%Y-%m-%d";
strftime(result, sizeof(result), in, tm); strftime(result, sizeof(result), in, tm);
unicode_strtoupper(result, uresult, sizeof(uresult), VMUTF8MARKUP); unicode_strtoupper(result, uresult, sizeof(uresult), VMUTF8MARKUP);

View file

@ -167,6 +167,7 @@ struct world_s
model_t *worldmodel; model_t *worldmodel;
areanode_t areanodes[AREA_NODES]; areanode_t areanodes[AREA_NODES];
int numareanodes; int numareanodes;
areanode_t portallist;
double physicstime; // the last time global physics were run double physicstime; // the last time global physics were run
unsigned int framenum; unsigned int framenum;

View file

@ -8605,6 +8605,8 @@ static void QCBUILTIN PF_runclientphys(pubprogfuncs_t *prinst, struct globalvars
pmove.cmd.upmove = (pr_global_struct->input_movevalues)[2]; pmove.cmd.upmove = (pr_global_struct->input_movevalues)[2];
pmove.cmd.buttons = pr_global_struct->input_buttons; pmove.cmd.buttons = pr_global_struct->input_buttons;
pmove.safeorigin_known = true;
VectorCopy(ent->v->oldorigin, pmove.safeorigin);
VectorCopy(ent->v->origin, pmove.origin); VectorCopy(ent->v->origin, pmove.origin);
VectorCopy(ent->v->velocity, pmove.velocity); VectorCopy(ent->v->velocity, pmove.velocity);
VectorCopy(ent->v->maxs, pmove.player_maxs); VectorCopy(ent->v->maxs, pmove.player_maxs);
@ -8630,6 +8632,7 @@ static void QCBUILTIN PF_runclientphys(pubprogfuncs_t *prinst, struct globalvars
} }
AddLinksToPmove(ent, sv.world.areanodes); AddLinksToPmove(ent, sv.world.areanodes);
// AddAllEntsToPmove(); // AddAllEntsToPmove();
AddLinksToPmove_Force ( ent, &sv.world.portallist );
SV_PreRunCmd(); SV_PreRunCmd();
@ -8650,6 +8653,7 @@ static void QCBUILTIN PF_runclientphys(pubprogfuncs_t *prinst, struct globalvars
else else
ent->v->teleport_time = pmove.waterjumptime; ent->v->teleport_time = pmove.waterjumptime;
VectorCopy(pmove.origin, ent->v->origin); VectorCopy(pmove.origin, ent->v->origin);
VectorCopy(pmove.safeorigin, ent->v->oldorigin);
VectorCopy(pmove.velocity, ent->v->velocity); VectorCopy(pmove.velocity, ent->v->velocity);
@ -10607,9 +10611,9 @@ void PR_DumpPlatform_f(void)
{"VF_SCREENPSIZE", "const float", CS|MENU, "Provides a reliable way to retrieve the current physical screen size (cvars need vid_restart for them to take effect).", VF_SCREENPSIZE}, {"VF_SCREENPSIZE", "const float", CS|MENU, "Provides a reliable way to retrieve the current physical screen size (cvars need vid_restart for them to take effect).", VF_SCREENPSIZE},
{"VF_VIEWENTITY", "const float", CS, "Changes the RF_EXTERNALMODEL flag on entities to match the new selection, and removes entities flaged with RF_VIEWENTITY. Requires cunning use of .entnum and typically requires calling addentities(MASK_VIEWMODEL) too.", VF_VIEWENTITY}, {"VF_VIEWENTITY", "const float", CS, "Changes the RF_EXTERNALMODEL flag on entities to match the new selection, and removes entities flaged with RF_VIEWENTITY. Requires cunning use of .entnum and typically requires calling addentities(MASK_VIEWMODEL) too.", VF_VIEWENTITY},
{"VF_RT_DESTCOLOUR", "const float", CS|MENU, "The FrameBuffer texture index to write colour info into. 1-based. Additional arguments are: format (rgba8=1,rgba16f=2,rgba32f=3), sizexy. Written to by both 3d and 2d rendering.", VF_RT_DESTCOLOUR}, {"VF_RT_DESTCOLOUR", "const float", CS|MENU, "The FrameBuffer texture index to write colour info into. 1-based. Additional arguments are: format (rgba8=1,rgba16f=2,rgba32f=3), sizexy. Written to by both 3d and 2d rendering. Note that any rendertargets may be destroyed on video mode changes or so.", VF_RT_DESTCOLOUR},
{"VF_RT_SOURCECOLOUR", "const float", CS|MENU, "The FrameBuffer texture index to use with shaders that specify a $sourcecolour map.", VF_RT_SOURCECOLOUR}, {"VF_RT_SOURCECOLOUR", "const float", CS|MENU, "The FrameBuffer texture index to use with shaders that specify a $sourcecolour map.", VF_RT_SOURCECOLOUR},
{"VF_RT_DEPTH", "const float", CS|MENU, "The FrameBuffer texture index to use as a depth buffer. Also used for shaders that specify $sourcedepth. 1-based. Additional arguments are: format (16=4,24=5,32=6), sizexy.", VF_RT_DEPTH}, {"VF_RT_DEPTH", "const float", CS|MENU, "The FrameBuffer texture index to use as a depth buffer. Also used for shaders that specify $sourcedepth. 1-based. Additional arguments are: format (16bit=4,24bit=5,32bit=6), sizexy.", VF_RT_DEPTH},
{"VF_RT_RIPPLE", "const float", CS|MENU, "The FrameBuffer texture index to use as a ripplemap (target for shaders with 'sort ripple'). Also used for shaders that specify $ripplemap. 1-based. Additional arguments are: format, sizexy.", VF_RT_RIPPLE}, {"VF_RT_RIPPLE", "const float", CS|MENU, "The FrameBuffer texture index to use as a ripplemap (target for shaders with 'sort ripple'). Also used for shaders that specify $ripplemap. 1-based. Additional arguments are: format, sizexy.", VF_RT_RIPPLE},
{"RF_VIEWMODEL", "const float", CS, "Specifies that the entity is a view model, and that its origin is relative to the current view position. These entities are also subject to viewweapon bob.", CSQCRF_VIEWMODEL}, {"RF_VIEWMODEL", "const float", CS, "Specifies that the entity is a view model, and that its origin is relative to the current view position. These entities are also subject to viewweapon bob.", CSQCRF_VIEWMODEL},

View file

@ -1403,6 +1403,7 @@ void SV_LogPlayer(client_t *cl, char *msg);
extern vec3_t pmove_mins, pmove_maxs; //abs min/max extents extern vec3_t pmove_mins, pmove_maxs; //abs min/max extents
void AddLinksToPmove ( edict_t *player, areanode_t *node ); void AddLinksToPmove ( edict_t *player, areanode_t *node );
void AddLinksToPmove_Force ( edict_t *player, areanode_t *node );
#ifdef HLSERVER #ifdef HLSERVER

View file

@ -1989,7 +1989,7 @@ void WPhys_MoveChain(world_t *w, wedict_t *ent, wedict_t *movechain, float *init
for(i=16;i && movechain != w->edicts && !movechain->isfree;i--, movechain = PROG_TO_WEDICT(w->progs, movechain->xv->movechain)) for(i=16;i && movechain != w->edicts && !movechain->isfree;i--, movechain = PROG_TO_WEDICT(w->progs, movechain->xv->movechain))
{ {
if ((int)movechain->v->flags & FL_MOVECHAIN_ANGLE) if ((int)movechain->v->flags & FL_MOVECHAIN_ANGLE)
VectorAdd(movechain->v->angles, moveang, movechain->v->angles); VectorAdd(movechain->v->angles, moveang, movechain->v->angles); //FIXME: axial only
VectorAdd(movechain->v->origin, moveorg, movechain->v->origin); VectorAdd(movechain->v->origin, moveorg, movechain->v->origin);
if (movechain->xv->chainmoved && callfunc) if (movechain->xv->chainmoved && callfunc)

View file

@ -5488,6 +5488,71 @@ float V_CalcRoll (vec3_t angles, vec3_t velocity)
vec3_t pmove_mins, pmove_maxs; vec3_t pmove_mins, pmove_maxs;
static qboolean AddEntityToPmove(edict_t *player, edict_t *check)
{
physent_t *pe;
int solid = check->v->solid;
int q1contents;
if (pmove.numphysent == MAX_PHYSENTS)
return false;
pe = &pmove.physents[pmove.numphysent];
pe->notouch = !((int)player->xv->dimension_solid & (int)check->xv->dimension_hit);
if (!((int)player->xv->dimension_hit & (int)check->xv->dimension_solid))
return true;
if (!check->v->size[0]) //points are not meant to be solid
return true;
pmove.numphysent++;
VectorCopy (check->v->origin, pe->origin);
pe->info = NUM_FOR_EDICT(svprogfuncs, check);
pe->nonsolid = solid == SOLID_TRIGGER;
pe->isportal = solid == SOLID_PORTAL;
q1contents = (int)check->v->skin;
if (solid == SOLID_LADDER)
q1contents = Q1CONTENTS_LADDER; //legacy crap
switch(q1contents)
{
case Q1CONTENTS_WATER:
pe->nonsolid = true;
pe->forcecontentsmask = FTECONTENTS_WATER;
break;
case Q1CONTENTS_LAVA:
pe->nonsolid = true;
pe->forcecontentsmask = FTECONTENTS_LAVA;
break;
case Q1CONTENTS_SLIME:
pe->nonsolid = true;
pe->forcecontentsmask = FTECONTENTS_SLIME;
break;
case Q1CONTENTS_SKY:
pe->nonsolid = true;
pe->forcecontentsmask = FTECONTENTS_SKY;
break;
case Q1CONTENTS_LADDER:
pe->nonsolid = true;
pe->forcecontentsmask = FTECONTENTS_LADDER;
break;
default:
pe->forcecontentsmask = 0;
break;
}
if (solid == SOLID_PORTAL || solid == SOLID_BSP)
{
if(progstype != PROG_H2)
pe->angles[0]*=-1; //quake is wierd. I guess someone fixed it hexen2... or my code is buggy or something...
pe->model = sv.models[(int)(check->v->modelindex)];
VectorCopy (check->v->angles, pe->angles);
}
else
{
pe->model = NULL;
VectorCopy (check->v->mins, pe->mins);
VectorCopy (check->v->maxs, pe->maxs);
VectorClear (pe->angles);
}
return true;
}
/* /*
==================== ====================
AddLinksToPmove AddLinksToPmove
@ -5502,9 +5567,6 @@ void AddLinksToPmove ( edict_t *player, areanode_t *node )
int pl; int pl;
int i; int i;
int solid; int solid;
physent_t *pe;
model_t *model;
pl = EDICT_TO_PROG(svprogfuncs, player); pl = EDICT_TO_PROG(svprogfuncs, player);
@ -5525,6 +5587,7 @@ void AddLinksToPmove ( edict_t *player, areanode_t *node )
|| solid == SOLID_PORTAL || solid == SOLID_PORTAL
|| solid == SOLID_BBOX || solid == SOLID_BBOX
|| solid == SOLID_SLIDEBOX || solid == SOLID_SLIDEBOX
|| solid == SOLID_LADDER
//|| (solid == SOLID_PHASEH2 && progstype == PROG_H2) //logically matches hexen2, but I hate it //|| (solid == SOLID_PHASEH2 && progstype == PROG_H2) //logically matches hexen2, but I hate it
) )
{ {
@ -5536,92 +5599,8 @@ void AddLinksToPmove ( edict_t *player, areanode_t *node )
if (i != 3) if (i != 3)
continue; continue;
if (pmove.numphysent == MAX_PHYSENTS) if (!AddEntityToPmove(player, check))
break; break;
pe = &pmove.physents[pmove.numphysent];
pe->notouch = !((int)player->xv->dimension_solid & (int)check->xv->dimension_hit);
if (!((int)player->xv->dimension_hit & (int)check->xv->dimension_solid))
continue;
if (!check->v->size[0]) //points are not meant to be solid
continue;
pmove.numphysent++;
VectorCopy (check->v->origin, pe->origin);
pe->info = NUM_FOR_EDICT(svprogfuncs, check);
pe->nonsolid = solid == SOLID_TRIGGER;
pe->isportal = solid == SOLID_PORTAL;
switch((int)check->v->skin)
{
case Q1CONTENTS_WATER:
pe->nonsolid = true;
pe->forcecontentsmask = FTECONTENTS_WATER;
break;
case Q1CONTENTS_LAVA:
pe->nonsolid = true;
pe->forcecontentsmask = FTECONTENTS_LAVA;
break;
case Q1CONTENTS_SLIME:
pe->nonsolid = true;
pe->forcecontentsmask = FTECONTENTS_SLIME;
break;
case Q1CONTENTS_SKY:
pe->nonsolid = true;
pe->forcecontentsmask = FTECONTENTS_SKY;
break;
case Q1CONTENTS_LADDER:
pe->nonsolid = true;
pe->forcecontentsmask = FTECONTENTS_LADDER;
break;
default:
pe->forcecontentsmask = 0;
break;
}
if (solid == SOLID_PORTAL || solid == SOLID_BSP)
{
if(progstype != PROG_H2)
pe->angles[0]*=-1; //quake is wierd. I guess someone fixed it hexen2... or my code is buggy or something...
pe->model = sv.models[(int)(check->v->modelindex)];
VectorCopy (check->v->angles, pe->angles);
}
else
{
pe->model = NULL;
VectorCopy (check->v->mins, pe->mins);
VectorCopy (check->v->maxs, pe->maxs);
VectorClear (pe->angles);
}
}
}
if (player->v->mins[2] != 24) //crouching/dead
for (l = node->edicts.next ; l != &node->edicts ; l = next)
{
next = l->next;
check = (edict_t*)EDICT_FROM_AREA(l);
if (check->v->owner == pl)
continue; // player's own missile
if (check->v->solid == SOLID_LADDER)
{
for (i=0 ; i<3 ; i++)
if (check->v->absmin[i] > pmove_maxs[i]
|| check->v->absmax[i] < pmove_mins[i])
break;
if (i != 3)
continue;
if (!((int)player->xv->dimension_hit & (int)check->xv->dimension_solid))
continue;
model = sv.models[(int)check->v->modelindex];
if (model)
{
vec3_t axis[3];
AngleVectors(check->v->angles, axis[0], axis[1], axis[2]);
VectorNegate(axis[1], axis[1]);
// test the point
if (model->funcs.PointContents (model, axis, player->v->origin) == FTECONTENTS_SOLID)
player->xv->pmove_flags = (int)player->xv->pmove_flags | PMF_LADDER; //touch that ladder!
}
} }
} }
@ -5635,6 +5614,54 @@ void AddLinksToPmove ( edict_t *player, areanode_t *node )
AddLinksToPmove (player, node->children[1]); AddLinksToPmove (player, node->children[1]);
} }
//ignores mins/maxs.
//portals are expected to be weird. player movement code is nasty.
void AddLinksToPmove_Force ( edict_t *player, areanode_t *node )
{
link_t *l, *next;
edict_t *check;
int pl;
int i;
int solid;
pl = EDICT_TO_PROG(svprogfuncs, player);
// touch linked edicts
for (l = node->edicts.next ; l != &node->edicts ; l = next)
{
next = l->next;
check = (edict_t*)EDICT_FROM_AREA(l);
if (check->v->owner == pl)
continue; // player's own missile
if (check == player)
continue;
solid = check->v->solid;
if (
(solid == SOLID_TRIGGER && check->v->skin < 0)
|| solid == SOLID_BSP
|| solid == SOLID_PORTAL
|| solid == SOLID_BBOX
|| solid == SOLID_SLIDEBOX
|| solid == SOLID_LADDER
//|| (solid == SOLID_PHASEH2 && progstype == PROG_H2) //logically matches hexen2, but I hate it
)
{
if (!AddEntityToPmove(player, check))
break;
}
}
// recurse down both sides
if (node->axis == -1)
return;
if (pmove_maxs[node->axis] > node->dist)
AddLinksToPmove_Force (player, node->children[0]);
if (pmove_mins[node->axis] < node->dist)
AddLinksToPmove_Force (player, node->children[1]);
}
/* /*
================ ================
@ -5643,15 +5670,14 @@ AddAllEntsToPmove
For debugging For debugging
================ ================
*/ */
void AddAllEntsToPmove (void) void AddAllEntsToPmove (edict_t *player)
{ {
int e; int e;
edict_t *check; edict_t *check;
int i; int i;
physent_t *pe;
int pl; int pl;
pl = EDICT_TO_PROG(svprogfuncs, sv_player); pl = EDICT_TO_PROG(svprogfuncs, player);
for (e=1 ; e<sv.world.num_edicts ; e++) for (e=1 ; e<sv.world.num_edicts ; e++)
{ {
check = EDICT_NUM(svprogfuncs, e); check = EDICT_NUM(svprogfuncs, e);
@ -5663,7 +5689,7 @@ void AddAllEntsToPmove (void)
|| check->v->solid == SOLID_BBOX || check->v->solid == SOLID_BBOX
|| check->v->solid == SOLID_SLIDEBOX) || check->v->solid == SOLID_SLIDEBOX)
{ {
if (check == sv_player) if (check == player)
continue; continue;
for (i=0 ; i<3 ; i++) for (i=0 ; i<3 ; i++)
@ -5672,24 +5698,8 @@ void AddAllEntsToPmove (void)
break; break;
if (i != 3) if (i != 3)
continue; continue;
pe = &pmove.physents[pmove.numphysent];
VectorCopy (check->v->origin, pe->origin); if (!AddEntityToPmove(player, check))
pmove.physents[pmove.numphysent].info = e;
if (check->v->solid == SOLID_BSP)
{
VectorCopy (check->v->angles, pe->angles);
pe->model = sv.models[(int)(check->v->modelindex)];
}
else
{
pe->angles[0] = pe->angles[1] = pe->angles[2] = 0;
pe->model = NULL;
VectorCopy (check->v->mins, pe->mins);
VectorCopy (check->v->maxs, pe->maxs);
}
if (++pmove.numphysent == MAX_PHYSENTS)
break; break;
} }
} }
@ -6048,9 +6058,9 @@ void SV_RunCmd (usercmd_t *ucmd, qboolean recurse)
pmove.player_maxs[2] = sv_player->v->maxs[2]; pmove.player_maxs[2] = sv_player->v->maxs[2];
VectorCopy(sv_player->xv->gravitydir, pmove.gravitydir); VectorCopy(sv_player->xv->gravitydir, pmove.gravitydir);
VectorCopy(sv_player->v->origin, pmove.origin);
for (i=0 ; i<3 ; i++) VectorCopy(sv_player->v->oldorigin, pmove.safeorigin);
pmove.origin[i] = sv_player->v->origin[i];// + (sv_player->v->mins[i] - player_mins[i]); pmove.safeorigin_known = true;
VectorCopy (sv_player->v->velocity, pmove.velocity); VectorCopy (sv_player->v->velocity, pmove.velocity);
VectorCopy (sv_player->v->v_angle, pmove.angles); VectorCopy (sv_player->v->v_angle, pmove.angles);
@ -6090,8 +6100,9 @@ void SV_RunCmd (usercmd_t *ucmd, qboolean recurse)
#if 1 #if 1
AddLinksToPmove ( sv_player, sv.world.areanodes ); AddLinksToPmove ( sv_player, sv.world.areanodes );
#else #else
AddAllEntsToPmove (); AddAllEntsToPmove (sv_player);
#endif #endif
AddLinksToPmove_Force ( sv_player, &sv.world.portallist );
if ((int)sv_player->xv->pmove_flags & PMF_LADDER) if ((int)sv_player->xv->pmove_flags & PMF_LADDER)
pmove.onladder = true; pmove.onladder = true;
@ -6168,6 +6179,7 @@ if (sv_player->v->health > 0 && before && !after )
else else
sv_player->v->flags = (int)sv_player->v->flags & ~FL_ONGROUND; sv_player->v->flags = (int)sv_player->v->flags & ~FL_ONGROUND;
VectorCopy (pmove.safeorigin, sv_player->v->oldorigin);
VectorCopy (pmove.origin, sv_player->v->origin); VectorCopy (pmove.origin, sv_player->v->origin);
VectorCopy (pmove.angles, sv_player->v->v_angle); VectorCopy (pmove.angles, sv_player->v->v_angle);

View file

@ -181,6 +181,10 @@ void World_ClearWorld (world_t *w)
{ {
World_InitBoxHull (); World_InitBoxHull ();
memset (&w->portallist, 0, sizeof(w->portallist));
ClearLink (&w->portallist.edicts);
w->portallist.axis = -1;
memset (w->areanodes, 0, sizeof(w->areanodes)); memset (w->areanodes, 0, sizeof(w->areanodes));
w->numareanodes = 0; w->numareanodes = 0;
if (!w->worldmodel) if (!w->worldmodel)
@ -473,17 +477,22 @@ void World_LinkEdict (world_t *w, wedict_t *ent, qboolean touch_triggers)
} }
// find the first node that the ent's box crosses // find the first node that the ent's box crosses
node = w->areanodes; if (ent->v->solid == SOLID_PORTAL)
while (1) node = &w->portallist;
else
{ {
if (node->axis == -1) node = w->areanodes;
break; while (1)
if (ent->v->absmin[node->axis] > node->dist) {
node = node->children[0]; if (node->axis == -1)
else if (ent->v->absmax[node->axis] < node->dist) break;
node = node->children[1]; if (ent->v->absmin[node->axis] > node->dist)
else node = node->children[0];
break; // crosses the node else if (ent->v->absmax[node->axis] < node->dist)
node = node->children[1];
else
break; // crosses the node
}
} }
// link it in // link it in
@ -1966,6 +1975,7 @@ trace_t World_Move (world_t *w, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t e
} }
else else
World_ClipToLinks (w, w->areanodes, &clip ); World_ClipToLinks (w, w->areanodes, &clip );
World_ClipToLinks(w, &w->portallist, &clip);
} }
// if (clip.trace.startsolid) // if (clip.trace.startsolid)