diff --git a/engine/client/cl_pred.c b/engine/client/cl_pred.c index 683abf602..33c6bdf83 100644 --- a/engine/client/cl_pred.c +++ b/engine/client/cl_pred.c @@ -405,6 +405,7 @@ void CL_PredictUsercmd (int pnum, int entnum, player_state_t *from, player_state movevars.maxspeed = cl.playerview[pnum].maxspeed; movevars.bunnyspeedcap = cl.bunnyspeedcap; pmove.onladder = false; + pmove.safeorigin_known = false; VectorCopy(from->szmins, pmove.player_mins); VectorCopy(from->szmaxs, pmove.player_maxs); diff --git a/engine/client/in_win.c b/engine/client/in_win.c index 81c9333da..eb3731720 100644 --- a/engine/client/in_win.c +++ b/engine/client/in_win.c @@ -120,7 +120,6 @@ static DWORD dwAxisFlags[JOY_MAX_AXES] = static DWORD dwAxisMap[JOY_MAX_AXES]; static DWORD dwControlMap[JOY_MAX_AXES]; -static PDWORD pdwRawValue[JOY_MAX_AXES]; // none of these cvars are saved over a session // 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_wwhack2 = CVAR("joywwhack2", "0.0"); -static qboolean joy_avail, joy_advancedinit, joy_haspov; -static DWORD joy_oldbuttonstate, joy_oldpovstate; +static qboolean joy_advancedinit; -static int joy_id; 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 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) { 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 =============== */ -void INS_StartupJoystick (void) +static void INS_StartupJoystickId(unsigned int id) { - int numdevs; JOYCAPS jc; 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 - joy_avail = false; + // 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 %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 if ( COM_CheckParm ("-nojoy") ) @@ -1559,75 +1598,21 @@ void INS_StartupJoystick (void) mmr = JOYERR_UNPLUGGED; // cycle through the joystick ids for the first valid one - for (joy_id=0 ; joy_idbuttonstate; + for (i=0 ; i < joy->numbuttons ; i++) { - key_index = (i < 4) ? K_JOY1 : K_AUX1; - Key_Event (0, key_index + i, 0, true); - } - - if ( !(buttonstate & (1<oldbuttonstate & (1<devid, key_index + i, 0, true); } - if ( !(povstate & (1<oldbuttonstate & (1<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<oldpovstate & (1<devid, K_AUX29 + i, 0, true); + } + + if ( !(povstate & (1<oldpovstate & (1<devid, K_AUX29 + i, 0, false); + } + } + joy->oldpovstate = povstate; + } } } @@ -1775,14 +1760,13 @@ void INS_Commands (void) INS_ReadJoystick =============== */ -qboolean INS_ReadJoystick (void) +qboolean INS_ReadJoystick (struct wjoy_s *joy) { - memset (&ji, 0, sizeof(ji)); ji.dwSize = sizeof(ji); 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 // 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; } + 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; } else @@ -1804,34 +1796,27 @@ qboolean INS_ReadJoystick (void) } } - -/* -=========== -INS_JoyMove -=========== -*/ -void INS_JoyMove (float *movements, int pnum) +static void INS_JoyMovePtr (struct wjoy_s *joy, float *movements, int pnum) { float speed, aspeed; float fAxisValue, fTemp; int i; + int wpnum; - // 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 (!joy_avail || !in_joystick.value) - { + /*each device will be processed when its player comes to be processed*/ + wpnum = cl.splitclients; + if (wpnum < 1) + wpnum = 1; + if (cl_forcesplitclient.ival) + wpnum = (cl_forcesplitclient.ival-1) % wpnum; + else + wpnum = joy->devid % wpnum; + if (wpnum != pnum) return; - } + // collect the joystick data, if possible - if (INS_ReadJoystick () != true) + if (INS_ReadJoystick (joy) != true) { return; } @@ -1846,7 +1831,7 @@ void INS_JoyMove (float *movements, int pnum) for (i = 0; i < JOY_MAX_AXES; i++) { // 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 fAxisValue -= 32768.0; @@ -1870,7 +1855,7 @@ void INS_JoyMove (float *movements, int pnum) fAxisValue /= 32768.0; #ifdef CSQC_DAT - if (CSQC_JoystickAxis(i, fAxisValue, 0)) + if (CSQC_JoystickAxis(i, fAxisValue, joy->devid)) continue; #endif @@ -1983,6 +1968,32 @@ void INS_JoyMove (float *movements, int 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[] = { diff --git a/engine/client/keys.c b/engine/client/keys.c index d6a48fcf5..a4be13ad6 100644 --- a/engine/client/keys.c +++ b/engine/client/keys.c @@ -2133,6 +2133,7 @@ void Key_Event (int devid, int key, unsigned int unicode, qboolean down) if (key_repeats[key] > 1) return; + //first player is normally assumed anyway. if (devid) Q_snprintfz (p, sizeof(p), "p %i ", devid+1); else diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index f1f77aaa2..a59c5ae2c 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -2512,6 +2512,7 @@ static void QCBUILTIN PF_cs_runplayerphysics (pubprogfuncs_t *prinst, struct glo pmove.cmd.sidemove = csqcg.input_movevalues[1]; pmove.cmd.upmove = csqcg.input_movevalues[2]; pmove.cmd.buttons = *csqcg.input_buttons; + pmove.safeorigin_known = false; if (ent) { diff --git a/engine/client/pr_skelobj.c b/engine/client/pr_skelobj.c index 4291e0a8b..e7fd93465 100644 --- a/engine/client/pr_skelobj.c +++ b/engine/client/pr_skelobj.c @@ -1129,7 +1129,7 @@ qboolean rag_animate(skelobject_t *sko, doll_t *doll, float *emat) int i; for (i = 0; i < sko->numbodies; i++) { - if (!doll->body[i].animate) + if (!sko->body[i].animstrength) continue; 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++) { - if (!doll->body[j].animate) + if (!sko->body[j].animstrength) continue; 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) { - G_FLOAT(OFS_RETURN) = 1; //technically success. + G_FLOAT(OFS_RETURN) = !!*ragname; //technically success. return; } else if (sko->numanimated) diff --git a/engine/common/com_mesh.c b/engine/common/com_mesh.c index 01a53b418..bfb3c10b2 100644 --- a/engine/common/com_mesh.c +++ b/engine/common/com_mesh.c @@ -3857,7 +3857,7 @@ qboolean Mod_GetTag(model_t *model, int tagnum, framestate_t *fstate, float *res result[10] = 1; while(tagnum >= 0) { - for (lerp = lerps; tagnum < lerp->endbone; lerp++) + for (lerp = lerps; tagnum < lerp->firstbone; lerp++) ; //set up the per-bone transform matrix matrix = lerp->pose[0] + tagnum*12; diff --git a/engine/common/net_chan.c b/engine/common/net_chan.c index 5ef55b69e..53c4a1122 100644 --- a/engine/common/net_chan.c +++ b/engine/common/net_chan.c @@ -228,16 +228,9 @@ Netchan_Init */ void Netchan_Init (void) { + static char qportstr[16]; 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 #ifdef _WIN32 port = (time(NULL)) & 0xffff; @@ -246,8 +239,16 @@ void Netchan_Init (void) #else port = ((int)(getpid()+getuid()*1000) * time(NULL)) & 0xffff; #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"); } /* diff --git a/engine/common/pmove.c b/engine/common/pmove.c index d63cdfcb1..40f01313e 100644 --- a/engine/common/pmove.c +++ b/engine/common/pmove.c @@ -84,12 +84,15 @@ void PM_ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce) } #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; wedict_t *portal = WEDICT_NUM(w->progs, portalnum); int oself = *w->g.self; void *pr_globals = PR_globals(w->progs, PR_CURRENT); + int i; + int tmp; *w->g.self = EDICT_TO_PROG(w->progs, portal); //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); + 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. - if (!PM_TestPlayerPosition(G_VECTOR(OFS_RETURN), true)) + if (!PM_TestPlayerPosition(rounded, true)) okay = false; else { - VectorCopy(G_VECTOR(OFS_RETURN), org); - VectorCopy(w->g.v_forward, pmove.velocity); + VectorCopy(rounded, org); + VectorCopy(w->g.v_forward, newvel); VectorCopy(w->g.v_right, move); - VectorCopy(w->g.v_up, pmove.gravitydir); +// VectorCopy(w->g.v_up, pmove.gravitydir); //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)); AngleVectors(pmove.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, pmove.angles); - pmove.angles[0] *= -1; + VectorAngles(w->g.v_forward, w->g.v_up, newang); + newang[0] *= -1; } *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 from; + vec3_t newang, newvel; VectorCopy(trace.endpos, from); //just in case 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); //if we follow the portal, then we basically need to restart from the other side. - if (tookportal) - *tookportal = trace.fraction; - - return PM_PlayerTrace (from, end, MASK_PLAYERSOLID); + exit = PM_PlayerTrace (from, end, MASK_PLAYERSOLID); + + for (i = 0; i < 3; i++) + { + 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++) 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)) return; - for (z=0 ; z<=4 ; z++) + for (z=0 ; zinput_movevalues)[2]; 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->velocity, pmove.velocity); 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); // AddAllEntsToPmove(); + AddLinksToPmove_Force ( ent, &sv.world.portallist ); SV_PreRunCmd(); @@ -8650,6 +8653,7 @@ static void QCBUILTIN PF_runclientphys(pubprogfuncs_t *prinst, struct globalvars else ent->v->teleport_time = pmove.waterjumptime; VectorCopy(pmove.origin, ent->v->origin); + VectorCopy(pmove.safeorigin, ent->v->oldorigin); 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_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_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}, {"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}, diff --git a/engine/server/server.h b/engine/server/server.h index 0cb68571c..3b6df8971 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -1403,6 +1403,7 @@ void SV_LogPlayer(client_t *cl, char *msg); extern vec3_t pmove_mins, pmove_maxs; //abs min/max extents void AddLinksToPmove ( edict_t *player, areanode_t *node ); +void AddLinksToPmove_Force ( edict_t *player, areanode_t *node ); #ifdef HLSERVER diff --git a/engine/server/sv_phys.c b/engine/server/sv_phys.c index b2324e76e..68f1bd9f3 100644 --- a/engine/server/sv_phys.c +++ b/engine/server/sv_phys.c @@ -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)) { 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); if (movechain->xv->chainmoved && callfunc) diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c index 595c28924..7959abba9 100644 --- a/engine/server/sv_user.c +++ b/engine/server/sv_user.c @@ -5488,6 +5488,71 @@ float V_CalcRoll (vec3_t angles, vec3_t velocity) 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 @@ -5502,9 +5567,6 @@ void AddLinksToPmove ( edict_t *player, areanode_t *node ) int pl; int i; int solid; - physent_t *pe; - - model_t *model; pl = EDICT_TO_PROG(svprogfuncs, player); @@ -5525,6 +5587,7 @@ void AddLinksToPmove ( edict_t *player, areanode_t *node ) || 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 ) { @@ -5536,92 +5599,8 @@ void AddLinksToPmove ( edict_t *player, areanode_t *node ) if (i != 3) continue; - if (pmove.numphysent == MAX_PHYSENTS) + if (!AddEntityToPmove(player, check)) 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]); } +//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 ================ */ -void AddAllEntsToPmove (void) +void AddAllEntsToPmove (edict_t *player) { int e; edict_t *check; int i; - physent_t *pe; int pl; - pl = EDICT_TO_PROG(svprogfuncs, sv_player); + pl = EDICT_TO_PROG(svprogfuncs, player); for (e=1 ; ev->solid == SOLID_BBOX || check->v->solid == SOLID_SLIDEBOX) { - if (check == sv_player) + if (check == player) continue; for (i=0 ; i<3 ; i++) @@ -5672,24 +5698,8 @@ void AddAllEntsToPmove (void) break; if (i != 3) continue; - pe = &pmove.physents[pmove.numphysent]; - VectorCopy (check->v->origin, pe->origin); - 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) + if (!AddEntityToPmove(player, check)) break; } } @@ -6048,9 +6058,9 @@ void SV_RunCmd (usercmd_t *ucmd, qboolean recurse) pmove.player_maxs[2] = sv_player->v->maxs[2]; VectorCopy(sv_player->xv->gravitydir, pmove.gravitydir); - - for (i=0 ; i<3 ; i++) - pmove.origin[i] = sv_player->v->origin[i];// + (sv_player->v->mins[i] - player_mins[i]); + VectorCopy(sv_player->v->origin, pmove.origin); + VectorCopy(sv_player->v->oldorigin, pmove.safeorigin); + pmove.safeorigin_known = true; VectorCopy (sv_player->v->velocity, pmove.velocity); VectorCopy (sv_player->v->v_angle, pmove.angles); @@ -6090,8 +6100,9 @@ void SV_RunCmd (usercmd_t *ucmd, qboolean recurse) #if 1 AddLinksToPmove ( sv_player, sv.world.areanodes ); #else - AddAllEntsToPmove (); + AddAllEntsToPmove (sv_player); #endif + AddLinksToPmove_Force ( sv_player, &sv.world.portallist ); if ((int)sv_player->xv->pmove_flags & PMF_LADDER) pmove.onladder = true; @@ -6168,6 +6179,7 @@ if (sv_player->v->health > 0 && before && !after ) else 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.angles, sv_player->v->v_angle); diff --git a/engine/server/world.c b/engine/server/world.c index 2c4fa8f8b..83132c957 100644 --- a/engine/server/world.c +++ b/engine/server/world.c @@ -181,6 +181,10 @@ void World_ClearWorld (world_t *w) { World_InitBoxHull (); + memset (&w->portallist, 0, sizeof(w->portallist)); + ClearLink (&w->portallist.edicts); + w->portallist.axis = -1; + memset (w->areanodes, 0, sizeof(w->areanodes)); w->numareanodes = 0; 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 - node = w->areanodes; - while (1) + if (ent->v->solid == SOLID_PORTAL) + node = &w->portallist; + else { - if (node->axis == -1) - break; - if (ent->v->absmin[node->axis] > node->dist) - node = node->children[0]; - else if (ent->v->absmax[node->axis] < node->dist) - node = node->children[1]; - else - break; // crosses the node + node = w->areanodes; + while (1) + { + if (node->axis == -1) + break; + if (ent->v->absmin[node->axis] > node->dist) + node = node->children[0]; + else if (ent->v->absmax[node->axis] < node->dist) + node = node->children[1]; + else + break; // crosses the node + } } // 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 World_ClipToLinks (w, w->areanodes, &clip ); + World_ClipToLinks(w, &w->portallist, &clip); } // if (clip.trace.startsolid)