mirror of
https://github.com/Shpoike/Quakespasm.git
synced 2025-04-20 09:55:38 +00:00
Add runstandardplayerphysics builtin, allowing for csqc-based prediction compatible with quakeworld engines, and just generally handy as a less-dumb more-setup alternative to walkmove.
This commit is contained in:
parent
8fc5860e3c
commit
9b8573aa79
23 changed files with 2593 additions and 120 deletions
|
@ -180,6 +180,8 @@ ADD_EXECUTABLE(quakespasm
|
|||
# Quake/net_wipx.c
|
||||
Quake/pl_linux.c
|
||||
# Quake/pl_win.c
|
||||
Quake/pmove.c
|
||||
Quake/pmovetst.c
|
||||
Quake/pr_cmds.c
|
||||
Quake/pr_edict.c
|
||||
Quake/pr_exec.c
|
||||
|
|
|
@ -290,6 +290,8 @@ OBJS := strlcat.o \
|
|||
pr_ext.o \
|
||||
pr_edict.o \
|
||||
pr_exec.o \
|
||||
pmove.o \
|
||||
pmovetst.o \
|
||||
sv_main.o \
|
||||
sv_move.o \
|
||||
sv_phys.o \
|
||||
|
|
|
@ -306,6 +306,8 @@ OBJS := strlcat.o \
|
|||
pr_ext.o \
|
||||
pr_edict.o \
|
||||
pr_exec.o \
|
||||
pmove.o \
|
||||
pmovetst.o \
|
||||
sv_main.o \
|
||||
sv_move.o \
|
||||
sv_phys.o \
|
||||
|
|
|
@ -268,6 +268,8 @@ OBJS := strlcat.o \
|
|||
pr_ext.o \
|
||||
pr_edict.o \
|
||||
pr_exec.o \
|
||||
pmove.o \
|
||||
pmovetst.o \
|
||||
sv_main.o \
|
||||
sv_move.o \
|
||||
sv_phys.o \
|
||||
|
|
|
@ -260,6 +260,8 @@ OBJS := strlcat.o \
|
|||
pr_ext.o \
|
||||
pr_edict.o \
|
||||
pr_exec.o \
|
||||
pmove.o \
|
||||
pmovetst.o \
|
||||
sv_main.o \
|
||||
sv_move.o \
|
||||
sv_phys.o \
|
||||
|
|
|
@ -234,6 +234,8 @@ OBJS = strlcat.obj &
|
|||
pr_ext.obj &
|
||||
pr_edict.obj &
|
||||
pr_exec.obj &
|
||||
pmove.obj &
|
||||
pmovetxt.obj &
|
||||
sv_main.obj &
|
||||
sv_move.obj &
|
||||
sv_phys.obj &
|
||||
|
|
|
@ -23,6 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
|
||||
#include "quakedef.h"
|
||||
#include "bgmusic.h"
|
||||
#include "pmove.h"
|
||||
|
||||
#include "arch_def.h"
|
||||
#ifdef PLATFORM_UNIX
|
||||
|
@ -1192,66 +1193,6 @@ void CL_AccumulateCmd (void)
|
|||
cl.pendingcmd.seconds = cl.mtime[0] - cl.pendingcmd.servertime;
|
||||
}
|
||||
|
||||
void CL_CSQC_SetInputs(usercmd_t *cmd, qboolean set)
|
||||
{
|
||||
if (set)
|
||||
{
|
||||
if (qcvm->extglobals.input_timelength)
|
||||
*qcvm->extglobals.input_timelength = cmd->seconds;
|
||||
if (qcvm->extglobals.input_angles)
|
||||
VectorCopy(cmd->viewangles, qcvm->extglobals.input_angles);
|
||||
if (qcvm->extglobals.input_movevalues)
|
||||
{
|
||||
qcvm->extglobals.input_movevalues[0] = cmd->forwardmove;
|
||||
qcvm->extglobals.input_movevalues[1] = cmd->sidemove;
|
||||
qcvm->extglobals.input_movevalues[2] = cmd->upmove;
|
||||
}
|
||||
if (qcvm->extglobals.input_buttons)
|
||||
*qcvm->extglobals.input_buttons = cmd->buttons;
|
||||
if (qcvm->extglobals.input_impulse)
|
||||
*qcvm->extglobals.input_impulse = cmd->impulse;
|
||||
|
||||
if (qcvm->extglobals.input_weapon)
|
||||
*qcvm->extglobals.input_weapon = cmd->weapon;
|
||||
if (qcvm->extglobals.input_cursor_screen)
|
||||
qcvm->extglobals.input_cursor_screen[0] = cmd->cursor_screen[0], qcvm->extglobals.input_cursor_screen[1] = cmd->cursor_screen[1];
|
||||
if (qcvm->extglobals.input_cursor_trace_start)
|
||||
VectorCopy(cmd->cursor_start, qcvm->extglobals.input_cursor_trace_start);
|
||||
if (qcvm->extglobals.input_cursor_trace_endpos)
|
||||
VectorCopy(cmd->cursor_impact, qcvm->extglobals.input_cursor_trace_endpos);
|
||||
if (qcvm->extglobals.input_cursor_entitynumber)
|
||||
*qcvm->extglobals.input_cursor_entitynumber = cmd->cursor_entitynumber;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (qcvm->extglobals.input_timelength)
|
||||
cmd->seconds = *qcvm->extglobals.input_timelength;
|
||||
if (qcvm->extglobals.input_angles)
|
||||
VectorCopy(qcvm->extglobals.input_angles, cmd->viewangles);
|
||||
if (qcvm->extglobals.input_movevalues)
|
||||
{
|
||||
cmd->forwardmove = qcvm->extglobals.input_movevalues[0];
|
||||
cmd->sidemove = qcvm->extglobals.input_movevalues[1];
|
||||
cmd->upmove = qcvm->extglobals.input_movevalues[2];
|
||||
}
|
||||
if (qcvm->extglobals.input_buttons)
|
||||
cmd->buttons = *qcvm->extglobals.input_buttons;
|
||||
if (qcvm->extglobals.input_impulse)
|
||||
cmd->impulse = *qcvm->extglobals.input_impulse;
|
||||
|
||||
if (qcvm->extglobals.input_weapon)
|
||||
cmd->weapon = *qcvm->extglobals.input_weapon;
|
||||
if (qcvm->extglobals.input_cursor_screen)
|
||||
cmd->cursor_screen[0] = qcvm->extglobals.input_cursor_screen[0], cmd->cursor_screen[1] = qcvm->extglobals.input_cursor_screen[1];
|
||||
if (qcvm->extglobals.input_cursor_trace_start)
|
||||
VectorCopy(qcvm->extglobals.input_cursor_trace_start, cmd->cursor_start);
|
||||
if (qcvm->extglobals.input_cursor_trace_endpos)
|
||||
VectorCopy(qcvm->extglobals.input_cursor_trace_endpos, cmd->cursor_impact);
|
||||
if (qcvm->extglobals.input_cursor_entitynumber)
|
||||
cmd->cursor_entitynumber = *qcvm->extglobals.input_cursor_entitynumber;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
CL_SendCmd
|
||||
|
@ -1280,9 +1221,9 @@ void CL_SendCmd (void)
|
|||
if (cl.qcvm.extfuncs.CSQC_Input_Frame && !cl.qcvm.nogameaccess)
|
||||
{
|
||||
PR_SwitchQCVM(&cl.qcvm);
|
||||
CL_CSQC_SetInputs(&cmd, true);
|
||||
PR_GetSetInputs(&cmd, true);
|
||||
PR_ExecuteProgram(cl.qcvm.extfuncs.CSQC_Input_Frame);
|
||||
CL_CSQC_SetInputs(&cmd, false);
|
||||
PR_GetSetInputs(&cmd, false);
|
||||
PR_SwitchQCVM(NULL);
|
||||
}
|
||||
|
||||
|
@ -1374,12 +1315,16 @@ static void CL_ServerExtension_FullServerinfo_f(void)
|
|||
{
|
||||
const char *newserverinfo = Cmd_Argv(1);
|
||||
Q_strncpy(cl.serverinfo, newserverinfo, sizeof(cl.serverinfo)); //just replace it
|
||||
|
||||
PMCL_ServerinfoUpdated();
|
||||
}
|
||||
static void CL_ServerExtension_ServerinfoUpdate_f(void)
|
||||
{
|
||||
const char *newserverkey = Cmd_Argv(1);
|
||||
const char *newservervalue = Cmd_Argv(2);
|
||||
Info_SetKey(cl.serverinfo, sizeof(cl.serverinfo), newserverkey, newservervalue);
|
||||
|
||||
PMCL_ServerinfoUpdated();
|
||||
}
|
||||
|
||||
int Sbar_ColorForMap (int m);
|
||||
|
|
|
@ -24,6 +24,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
|
||||
#include "quakedef.h"
|
||||
#include "bgmusic.h"
|
||||
#include "pmove.h"
|
||||
#include <setjmp.h>
|
||||
|
||||
/*
|
||||
|
@ -707,6 +708,9 @@ void Host_ServerFrame (void)
|
|||
// set the time and clear the general datagram
|
||||
SV_ClearDatagram ();
|
||||
|
||||
//respond to cvar changes
|
||||
PMSV_UpdateMovevars ();
|
||||
|
||||
// check for new clients
|
||||
SV_CheckForNewClients ();
|
||||
|
||||
|
|
1355
Quake/pmove.c
Normal file
1355
Quake/pmove.c
Normal file
File diff suppressed because it is too large
Load diff
171
Quake/pmove.h
Normal file
171
Quake/pmove.h
Normal file
|
@ -0,0 +1,171 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
#include "quakedef.h"
|
||||
|
||||
#define BUTTON_ATTACK 1
|
||||
#define BUTTON_JUMP 2
|
||||
|
||||
typedef enum {
|
||||
PM_NORMAL, // normal ground movement
|
||||
PM_OLD_SPECTATOR, // fly, no clip to world (QW bug)
|
||||
PM_SPECTATOR, // fly, no clip to world
|
||||
PM_DEAD, // no acceleration
|
||||
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_6DOF // spaceship mode
|
||||
} pmtype_t;
|
||||
|
||||
#define PMF_JUMP_HELD 1
|
||||
#define PMF_LADDER 2 //pmove flags. seperate from flags
|
||||
|
||||
#define MAX_PHYSENTS 64//2048
|
||||
typedef struct
|
||||
{
|
||||
vec3_t origin;
|
||||
vec3_t angles;
|
||||
qmodel_t *model; // only for bsp models
|
||||
vec3_t mins, maxs; // only for non-bsp models
|
||||
int info; // for client or server to identify
|
||||
unsigned int forcecontentsmask; //set from .skin
|
||||
} physent_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// player state
|
||||
vec3_t origin;
|
||||
vec3_t safeorigin; //valid when safeorigin_known. needed for extrasr4's ladders otherwise they bug out.
|
||||
vec3_t angles;
|
||||
vec3_t velocity;
|
||||
vec3_t gravitydir;
|
||||
qboolean jump_held;
|
||||
float jump_secs; // msec since last jump
|
||||
float waterjumptime;
|
||||
int pm_type;
|
||||
vec3_t player_mins;
|
||||
vec3_t player_maxs;
|
||||
|
||||
// world state
|
||||
int numphysent;
|
||||
physent_t physents[MAX_PHYSENTS]; // 0 should be the world
|
||||
|
||||
// input
|
||||
usercmd_t cmd;
|
||||
|
||||
qboolean onladder;
|
||||
qboolean safeorigin_known;
|
||||
|
||||
// results
|
||||
int skipent;
|
||||
int numtouch;
|
||||
int touchindex[MAX_PHYSENTS];
|
||||
vec3_t touchvel[MAX_PHYSENTS];
|
||||
qboolean onground;
|
||||
int groundent; // index in physents array, only valid
|
||||
// when onground is true
|
||||
int waterlevel;
|
||||
int watertype;
|
||||
|
||||
struct world_s *world;
|
||||
} playermove_t;
|
||||
|
||||
typedef struct {
|
||||
//standard quakeworld
|
||||
float gravity;
|
||||
float stopspeed;
|
||||
float maxspeed;
|
||||
float spectatormaxspeed;
|
||||
float maxairspeed;
|
||||
float accelerate;
|
||||
float airaccelerate;
|
||||
float wateraccelerate;
|
||||
float friction;
|
||||
float waterfriction;
|
||||
float flyfriction;
|
||||
float entgravity;
|
||||
|
||||
//extended stuff, sent via serverinfo
|
||||
float bunnyspeedcap;
|
||||
float watersinkspeed;
|
||||
float ktjump;
|
||||
float edgefriction; //default 2
|
||||
float jumpspeed;
|
||||
int walljump;
|
||||
qboolean slidefix;
|
||||
qboolean airstep;
|
||||
qboolean pground;
|
||||
qboolean stepdown;
|
||||
qboolean slidyslopes;
|
||||
qboolean autobunny;
|
||||
qboolean bunnyfriction; //force at least one frame of friction when bunnying.
|
||||
int stepheight;
|
||||
|
||||
unsigned protocolflags;
|
||||
|
||||
unsigned int flags;
|
||||
} movevars_t;
|
||||
|
||||
#define MOVEFLAG_VALID 0x80000000 //to signal that these are actually known. otherwise reserved.
|
||||
//#define MOVEFLAG_Q2AIRACCELERATE 0x00000001
|
||||
#define MOVEFLAG_NOGRAVITYONGROUND 0x00000002 //no slope sliding
|
||||
//#define MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE 0x00000004 //apply half-gravity both before AND after the move, which better matches the curve
|
||||
#define MOVEFLAG_QWEDGEBOX 0x00010000 //calculate edgefriction using tracebox and a buggy start pos
|
||||
#define MOVEFLAG_QWCOMPAT (MOVEFLAG_NOGRAVITYONGROUND|MOVEFLAG_QWEDGEBOX)
|
||||
|
||||
#define MASK_PLAYERSOLID CONTENTMASK_ANYSOLID
|
||||
#define CONTENTBIT_EMPTY CONTENTMASK_FROMQ1(CONTENTS_EMPTY)
|
||||
#define CONTENTBIT_SOLID CONTENTMASK_FROMQ1(CONTENTS_SOLID)
|
||||
#define CONTENTBIT_WATER CONTENTMASK_FROMQ1(CONTENTS_WATER)
|
||||
#define CONTENTBIT_SLIME CONTENTMASK_FROMQ1(CONTENTS_SLIME)
|
||||
#define CONTENTBIT_LAVA CONTENTMASK_FROMQ1(CONTENTS_LAVA)
|
||||
#define CONTENTBIT_SKY CONTENTMASK_FROMQ1(CONTENTS_SKY)
|
||||
#define CONTENTBIT_CLIP CONTENTMASK_FROMQ1(CONTENTS_CLIP)
|
||||
#define CONTENTBIT_LADDER CONTENTMASK_FROMQ1(CONTENTS_LADDER)
|
||||
#define CONTENTBITS_FLUID (CONTENTBIT_WATER|CONTENTBIT_SLIME|CONTENTBIT_LAVA)
|
||||
|
||||
extern movevars_t movevars;
|
||||
extern playermove_t pmove;
|
||||
|
||||
void PM_PlayerMove (float gamespeed);
|
||||
void PM_Init (void);
|
||||
void PM_InitBoxHull (void);
|
||||
|
||||
void PM_CategorizePosition (void);
|
||||
int PM_HullPointContents (hull_t *hull, int num, vec3_t p);
|
||||
|
||||
int PM_ExtraBoxContents (vec3_t p); //Peeks for HL-style water.
|
||||
int PM_PointContents (vec3_t point);
|
||||
qboolean PM_TestPlayerPosition (vec3_t point);
|
||||
#ifndef __cplusplus
|
||||
struct trace_s PM_PlayerTrace (vec3_t start, vec3_t stop, unsigned int solidmask);
|
||||
#endif
|
||||
|
||||
//stuff that should be elsewhere...
|
||||
int SV_HullPointContents (hull_t *hull, int num, vec3_t p);
|
||||
void SV_Impact (edict_t *e1, edict_t *e2);
|
||||
void World_AddEntsToPmove(edict_t *ignore, vec3_t boxminmax[2]);
|
||||
void PMCL_ServerinfoUpdated(void);
|
||||
void PMSV_SetMoveStats(edict_t *plent, float *fstat, int *istat); //so client has the right movevars as stats.
|
||||
void PM_Register(void);
|
||||
#define VectorClear(v) ((v)[0] = (v)[1] = (v)[2] = 0)
|
||||
#define VectorSet(r,x,y,z) do{(r)[0] = x; (r)[1] = y;(r)[2] = z;}while(0)
|
||||
#define Length VectorLength
|
||||
#define VectorNegate(a,b) ((b)[0]=-(a)[0],(b)[1]=-(a)[1],(b)[2]=-(a)[2])
|
399
Quake/pmovetst.c
Normal file
399
Quake/pmovetst.c
Normal file
|
@ -0,0 +1,399 @@
|
|||
/*
|
||||
Copyright (C) 1996-1997 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
#include "quakedef.h"
|
||||
#include "pmove.h"
|
||||
|
||||
static qboolean PM_TransformedHullCheck (qmodel_t *model, vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, trace_t *trace, vec3_t origin, vec3_t angles);
|
||||
static hull_t box_hull;
|
||||
static mclipnode_t box_clipnodes[6];
|
||||
static mplane_t box_planes[6];
|
||||
|
||||
//axis MUST come from VectorAngles, hence the negation. it being normalized means its also safe to use the transpose(MA-vs-dot) as an inverse to put stuff back into the original coord system. Origin is not handled so subtract/add that before/after.
|
||||
#define QAxisTransform(a, v, c) \
|
||||
do{ c[0] = DotProduct(a[0], v);\
|
||||
c[1] =-DotProduct(a[1], v);\
|
||||
c[2] = DotProduct(a[2], v);}while(0)
|
||||
#define QAxisDeTransform(a, v, c) \
|
||||
do{ VectorScale(a[0], v[0], c);\
|
||||
VectorMA(c, -v[1], a[1], c);\
|
||||
VectorMA(c, v[2], a[2], c);}while(0)
|
||||
|
||||
/*
|
||||
===================
|
||||
PM_InitBoxHull
|
||||
|
||||
Set up the planes and clipnodes so that the six floats of a bounding box
|
||||
can just be stored out and get a proper hull_t structure.
|
||||
===================
|
||||
*/
|
||||
void PM_InitBoxHull (void)
|
||||
{
|
||||
int i;
|
||||
int side;
|
||||
|
||||
box_hull.clipnodes = box_clipnodes;
|
||||
box_hull.planes = box_planes;
|
||||
box_hull.firstclipnode = 0;
|
||||
box_hull.lastclipnode = 5;
|
||||
|
||||
for (i=0 ; i<6 ; i++)
|
||||
{
|
||||
box_clipnodes[i].planenum = i;
|
||||
|
||||
side = i&1;
|
||||
|
||||
box_clipnodes[i].children[side] = CONTENTS_EMPTY;
|
||||
if (i != 5)
|
||||
box_clipnodes[i].children[side^1] = i + 1;
|
||||
else
|
||||
box_clipnodes[i].children[side^1] = CONTENTS_SOLID;
|
||||
|
||||
box_planes[i].type = i>>1;
|
||||
box_planes[i].normal[i>>1] = 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===================
|
||||
PM_HullForBox
|
||||
|
||||
To keep everything totally uniform, bounding boxes are turned into small
|
||||
BSP trees instead of being compared directly.
|
||||
===================
|
||||
*/
|
||||
static hull_t *PM_HullForBox (vec3_t mins, vec3_t maxs)
|
||||
{
|
||||
box_planes[0].dist = maxs[0];
|
||||
box_planes[1].dist = mins[0];
|
||||
box_planes[2].dist = maxs[1];
|
||||
box_planes[3].dist = mins[1];
|
||||
box_planes[4].dist = maxs[2];
|
||||
box_planes[5].dist = mins[2];
|
||||
|
||||
return &box_hull;
|
||||
}
|
||||
|
||||
|
||||
static unsigned int PM_TransformedModelPointContents (qmodel_t *mod, vec3_t p, vec3_t origin, vec3_t angles)
|
||||
{
|
||||
vec3_t p_l, axis[3], p_t;
|
||||
VectorSubtract (p, origin, p_l);
|
||||
|
||||
if (mod->type != mod_brush)
|
||||
return CONTENTMASK_FROMQ1(CONTENTS_EMPTY);
|
||||
|
||||
// rotate start and end into the models frame of reference
|
||||
if (angles[0] || angles[1] || angles[2])
|
||||
{
|
||||
AngleVectors (angles, axis[0], axis[1], axis[2]);
|
||||
QAxisTransform(axis, p_l, p_t);
|
||||
return CONTENTMASK_FROMQ1(SV_HullPointContents(&mod->hulls[0], mod->hulls[0].firstclipnode, p_t));
|
||||
}
|
||||
|
||||
return CONTENTMASK_FROMQ1(SV_HullPointContents(&mod->hulls[0], mod->hulls[0].firstclipnode, p_l));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
PM_PointContents
|
||||
|
||||
==================
|
||||
*/
|
||||
int PM_PointContents (vec3_t p)
|
||||
{
|
||||
int num;
|
||||
|
||||
unsigned int pc;
|
||||
physent_t *pe;
|
||||
qmodel_t *pm;
|
||||
|
||||
//check world.
|
||||
pm = pmove.physents[0].model;
|
||||
if (!pm || pm->needload)
|
||||
return CONTENTBIT_EMPTY;
|
||||
pc = CONTENTMASK_FROMQ1(SV_PointContents(p));
|
||||
|
||||
//we need this for e2m2 - waterjumping on to plats wouldn't work otherwise.
|
||||
for (num = 1; num < pmove.numphysent; num++)
|
||||
{
|
||||
pe = &pmove.physents[num];
|
||||
|
||||
if (pe->info == pmove.skipent)
|
||||
continue;
|
||||
|
||||
pm = pe->model;
|
||||
if (pm)
|
||||
{
|
||||
if (p[0] >= pe->origin[0]+pm->mins[0] && p[0] <= pe->origin[0]+pm->maxs[0] &&
|
||||
p[1] >= pe->origin[1]+pm->mins[1] && p[1] <= pe->origin[1]+pm->maxs[1] &&
|
||||
p[2] >= pe->origin[2]+pm->mins[2] && p[2] <= pe->origin[2]+pm->maxs[2])
|
||||
{
|
||||
if (pe->forcecontentsmask)
|
||||
{
|
||||
if (PM_TransformedModelPointContents(pm, p, pe->origin, pe->angles) != CONTENTBIT_EMPTY)
|
||||
pc |= pe->forcecontentsmask;
|
||||
}
|
||||
else
|
||||
pc |= PM_TransformedModelPointContents(pm, p, pe->origin, pe->angles);
|
||||
}
|
||||
}
|
||||
else if (pe->forcecontentsmask)
|
||||
{
|
||||
if (p[0] >= pe->origin[0]+pe->mins[0] && p[0] <= pe->origin[0]+pe->maxs[0] &&
|
||||
p[1] >= pe->origin[1]+pe->mins[1] && p[1] <= pe->origin[1]+pe->maxs[1] &&
|
||||
p[2] >= pe->origin[2]+pe->mins[2] && p[2] <= pe->origin[2]+pe->maxs[2])
|
||||
pc |= pe->forcecontentsmask;
|
||||
}
|
||||
}
|
||||
|
||||
return pc;
|
||||
}
|
||||
|
||||
int PM_ExtraBoxContents (vec3_t p)
|
||||
{
|
||||
int num;
|
||||
|
||||
int pc = 0;
|
||||
physent_t *pe;
|
||||
qmodel_t *pm;
|
||||
trace_t tr;
|
||||
|
||||
for (num = 1; num < pmove.numphysent; num++)
|
||||
{
|
||||
pe = &pmove.physents[num];
|
||||
pm = pe->model;
|
||||
if (pm)
|
||||
{
|
||||
if (pe->forcecontentsmask)
|
||||
{
|
||||
if (!PM_TransformedHullCheck(pm, p, p, pmove.player_mins, pmove.player_maxs, &tr, pe->origin, pe->angles))
|
||||
continue;
|
||||
if (tr.startsolid || tr.inwater)
|
||||
pc |= pe->forcecontentsmask;
|
||||
}
|
||||
}
|
||||
else if (pe->forcecontentsmask)
|
||||
{
|
||||
if (p[0]+pmove.player_maxs[0] >= pe->origin[0]+pe->mins[0] && p[0]+pmove.player_mins[0] <= pe->origin[0]+pe->maxs[0] &&
|
||||
p[1]+pmove.player_maxs[1] >= pe->origin[1]+pe->mins[1] && p[1]+pmove.player_mins[1] <= pe->origin[1]+pe->maxs[1] &&
|
||||
p[2]+pmove.player_maxs[2] >= pe->origin[2]+pe->mins[2] && p[2]+pmove.player_mins[2] <= pe->origin[2]+pe->maxs[2])
|
||||
pc |= pe->forcecontentsmask;
|
||||
}
|
||||
}
|
||||
|
||||
return pc;
|
||||
}
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
LINE TESTING IN HULLS
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
/*returns if it actually did a trace*/
|
||||
static qboolean PM_TransformedHullCheck (qmodel_t *model, vec3_t start, vec3_t end, vec3_t player_mins, vec3_t player_maxs, trace_t *trace, vec3_t origin, vec3_t angles)
|
||||
{
|
||||
vec3_t start_l, end_l;
|
||||
int i;
|
||||
vec3_t axis[3], start_t, end_t;
|
||||
|
||||
// subtract origin offset
|
||||
VectorSubtract (start, origin, start_l);
|
||||
VectorSubtract (end, origin, end_l);
|
||||
|
||||
// sweep the box through the model
|
||||
if (model && model->type == mod_brush)
|
||||
{
|
||||
hull_t *hull = &model->hulls[(player_maxs[0]-player_mins[0] < 3)?0:1];
|
||||
if (angles[0] || angles[1] || angles[2])
|
||||
{
|
||||
AngleVectors (angles, axis[0], axis[1], axis[2]);
|
||||
QAxisTransform(axis, start_l, start_t);
|
||||
QAxisTransform(axis, end_l, end_t);
|
||||
SV_RecursiveHullCheck(hull, start_t, end_t, trace, MASK_PLAYERSOLID);
|
||||
VectorCopy(trace->plane.normal, end_t); QAxisDeTransform(axis, end_t, trace->plane.normal);
|
||||
VectorCopy(trace->endpos, end_t); QAxisDeTransform(axis, end_t, trace->endpos);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
if (start_l[i]+player_mins[i] > model->maxs[i] && end_l[i] + player_mins[i] > model->maxs[i])
|
||||
return false;
|
||||
if (start_l[i]+player_maxs[i] < model->mins[i] && end_l[i] + player_maxs[i] < model->mins[i])
|
||||
return false;
|
||||
}
|
||||
|
||||
memset (trace, 0, sizeof(trace_t));
|
||||
trace->fraction = 1;
|
||||
trace->allsolid = true;
|
||||
SV_RecursiveHullCheck(hull, start_l, end_l, trace, MASK_PLAYERSOLID);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
if (start_l[i]+player_mins[i] > box_planes[0+i*2].dist && end_l[i] + player_mins[i] > box_planes[0+i*2].dist)
|
||||
return false;
|
||||
if (start_l[i]+player_maxs[i] < box_planes[1+i*2].dist && end_l[i] + player_maxs[i] < box_planes[1+i*2].dist)
|
||||
return false;
|
||||
}
|
||||
|
||||
memset (trace, 0, sizeof(trace_t));
|
||||
trace->fraction = 1;
|
||||
trace->allsolid = true;
|
||||
SV_RecursiveHullCheck (&box_hull, start_l, end_l, trace, MASK_PLAYERSOLID);
|
||||
}
|
||||
|
||||
trace->endpos[0] += origin[0];
|
||||
trace->endpos[1] += origin[1];
|
||||
trace->endpos[2] += origin[2];
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
PM_TestPlayerPosition
|
||||
|
||||
Returns false if the given player position is not valid (in solid)
|
||||
================
|
||||
*/
|
||||
qboolean PM_TestPlayerPosition (vec3_t pos)
|
||||
{
|
||||
int i;
|
||||
physent_t *pe;
|
||||
vec3_t mins, maxs;
|
||||
hull_t *hull;
|
||||
trace_t trace;
|
||||
|
||||
for (i=0 ; i< pmove.numphysent ; i++)
|
||||
{
|
||||
pe = &pmove.physents[i];
|
||||
|
||||
if (pe->info == pmove.skipent)
|
||||
continue;
|
||||
|
||||
if (pe->forcecontentsmask && !(pe->forcecontentsmask & MASK_PLAYERSOLID))
|
||||
continue;
|
||||
|
||||
// get the clipping hull
|
||||
if (pe->model)
|
||||
{
|
||||
if (!PM_TransformedHullCheck (pe->model, pos, pos, pmove.player_mins, pmove.player_maxs, &trace, pe->origin, pe->angles))
|
||||
continue;
|
||||
if (trace.allsolid)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
VectorSubtract (pe->mins, pmove.player_maxs, mins);
|
||||
VectorSubtract (pe->maxs, pmove.player_mins, maxs);
|
||||
hull = PM_HullForBox (mins, maxs);
|
||||
VectorSubtract(pos, pe->origin, mins);
|
||||
|
||||
if (CONTENTMASK_FROMQ1(SV_HullPointContents(hull, hull->firstclipnode, mins)) & MASK_PLAYERSOLID)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
pmove.safeorigin_known = true;
|
||||
VectorCopy (pmove.origin, pmove.safeorigin);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
PM_PlayerTrace
|
||||
================
|
||||
*/
|
||||
trace_t PM_PlayerTrace (vec3_t start, vec3_t end, unsigned int solidmask)
|
||||
{
|
||||
trace_t trace, total;
|
||||
int i;
|
||||
physent_t *pe;
|
||||
|
||||
// fill in a default trace
|
||||
memset (&total, 0, sizeof(trace_t));
|
||||
total.fraction = 1;
|
||||
total.entnum = -1;
|
||||
VectorCopy (end, total.endpos);
|
||||
|
||||
for (i=0 ; i< pmove.numphysent ; i++)
|
||||
{
|
||||
pe = &pmove.physents[i];
|
||||
|
||||
if (pe->info == pmove.skipent)
|
||||
continue;
|
||||
if (pe->forcecontentsmask && !(pe->forcecontentsmask & solidmask))
|
||||
continue;
|
||||
|
||||
if (!pe->model || pe->model->needload)
|
||||
{
|
||||
vec3_t mins, maxs;
|
||||
|
||||
VectorSubtract (pe->mins, pmove.player_maxs, mins);
|
||||
VectorSubtract (pe->maxs, pmove.player_mins, maxs);
|
||||
PM_HullForBox (mins, maxs);
|
||||
|
||||
// trace a line through the apropriate clipping hull
|
||||
if (!PM_TransformedHullCheck (NULL, start, end, pmove.player_mins, pmove.player_maxs, &trace, pe->origin, pe->angles))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 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)
|
||||
trace.startsolid = true;
|
||||
// if (trace.startsolid)
|
||||
// trace.fraction = 0;
|
||||
|
||||
// did we clip the move?
|
||||
if (trace.fraction < total.fraction || (trace.startsolid && !total.startsolid))
|
||||
{
|
||||
// fix trace up by the offset
|
||||
total = trace;
|
||||
total.entnum = i;
|
||||
}
|
||||
}
|
||||
|
||||
// //this is needed to avoid *2 friction. some id bug.
|
||||
if (total.startsolid)
|
||||
total.fraction = 0;
|
||||
return total;
|
||||
}
|
||||
|
||||
//for use outside the pmove code. lame, but works.
|
||||
trace_t PM_TraceLine (vec3_t start, vec3_t end)
|
||||
{
|
||||
VectorClear(pmove.player_mins);
|
||||
VectorClear(pmove.player_maxs);
|
||||
return PM_PlayerTrace(start, end, MASK_PLAYERSOLID);
|
||||
}
|
|
@ -1712,7 +1712,7 @@ static void PF_sv_makestatic (void)
|
|||
sv.max_statics = nm;
|
||||
}
|
||||
st = &sv.static_entities[sv.num_statics];
|
||||
SV_BuildEntityState(ent, st);
|
||||
SV_BuildEntityState(NULL, ent, st);
|
||||
if (st->alpha == ENTALPHA_ZERO)
|
||||
; //no point
|
||||
else
|
||||
|
@ -2102,7 +2102,7 @@ static void PF_cl_makestatic (void)
|
|||
stat = cl.static_entities[i];
|
||||
cl.num_statics++;
|
||||
|
||||
SV_BuildEntityState(ent, &stat->baseline);
|
||||
SV_BuildEntityState(NULL, ent, &stat->baseline);
|
||||
|
||||
// copy it to the current state
|
||||
|
||||
|
|
|
@ -1208,6 +1208,7 @@ static void PR_MergeEngineFieldDefs (void)
|
|||
//{"glowmod", ev_vector}, //fullbright tints
|
||||
//{"fatness", ev_float}, //bloated rendering...
|
||||
//{"gravitydir", ev_vector}, //says which direction gravity should act for this ent...
|
||||
{"pmove_flags", ev_float}, //if runstandardplayerphysics is to work, it needs somewhere to track a couple of flags.
|
||||
|
||||
};
|
||||
int maxofs = qcvm->progs->entityfields;
|
||||
|
|
374
Quake/pr_ext.c
374
Quake/pr_ext.c
|
@ -1811,6 +1811,361 @@ static void PF_TraceToss(void)
|
|||
pr_global_struct->trace_ent = EDICT_TO_PROG(qcvm->edicts);
|
||||
}
|
||||
|
||||
#include "pmove.h"
|
||||
void PR_GetSetInputs(usercmd_t *cmd, qboolean set)
|
||||
{
|
||||
if (set)
|
||||
{
|
||||
if (qcvm->extglobals.input_sequence)
|
||||
*qcvm->extglobals.input_sequence = cmd->sequence;
|
||||
if (qcvm->extglobals.input_servertime)
|
||||
*qcvm->extglobals.input_servertime = cmd->servertime;
|
||||
if (qcvm->extglobals.input_timelength)
|
||||
*qcvm->extglobals.input_timelength = cmd->seconds;
|
||||
if (qcvm->extglobals.input_angles)
|
||||
VectorCopy(cmd->viewangles, qcvm->extglobals.input_angles);
|
||||
if (qcvm->extglobals.input_movevalues)
|
||||
{
|
||||
qcvm->extglobals.input_movevalues[0] = cmd->forwardmove;
|
||||
qcvm->extglobals.input_movevalues[1] = cmd->sidemove;
|
||||
qcvm->extglobals.input_movevalues[2] = cmd->upmove;
|
||||
}
|
||||
if (qcvm->extglobals.input_buttons)
|
||||
*qcvm->extglobals.input_buttons = cmd->buttons;
|
||||
if (qcvm->extglobals.input_impulse)
|
||||
*qcvm->extglobals.input_impulse = cmd->impulse;
|
||||
|
||||
if (qcvm->extglobals.input_weapon)
|
||||
*qcvm->extglobals.input_weapon = cmd->weapon;
|
||||
if (qcvm->extglobals.input_cursor_screen)
|
||||
qcvm->extglobals.input_cursor_screen[0] = cmd->cursor_screen[0], qcvm->extglobals.input_cursor_screen[1] = cmd->cursor_screen[1];
|
||||
if (qcvm->extglobals.input_cursor_trace_start)
|
||||
VectorCopy(cmd->cursor_start, qcvm->extglobals.input_cursor_trace_start);
|
||||
if (qcvm->extglobals.input_cursor_trace_endpos)
|
||||
VectorCopy(cmd->cursor_impact, qcvm->extglobals.input_cursor_trace_endpos);
|
||||
if (qcvm->extglobals.input_cursor_entitynumber)
|
||||
*qcvm->extglobals.input_cursor_entitynumber = cmd->cursor_entitynumber;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (qcvm->extglobals.input_sequence)
|
||||
cmd->sequence = *qcvm->extglobals.input_sequence;
|
||||
if (qcvm->extglobals.input_servertime)
|
||||
cmd->servertime = *qcvm->extglobals.input_servertime;
|
||||
if (qcvm->extglobals.input_timelength)
|
||||
cmd->seconds = *qcvm->extglobals.input_timelength;
|
||||
if (qcvm->extglobals.input_angles)
|
||||
VectorCopy(qcvm->extglobals.input_angles, cmd->viewangles);
|
||||
if (qcvm->extglobals.input_movevalues)
|
||||
{
|
||||
cmd->forwardmove = qcvm->extglobals.input_movevalues[0];
|
||||
cmd->sidemove = qcvm->extglobals.input_movevalues[1];
|
||||
cmd->upmove = qcvm->extglobals.input_movevalues[2];
|
||||
}
|
||||
if (qcvm->extglobals.input_buttons)
|
||||
cmd->buttons = *qcvm->extglobals.input_buttons;
|
||||
if (qcvm->extglobals.input_impulse)
|
||||
cmd->impulse = *qcvm->extglobals.input_impulse;
|
||||
|
||||
if (qcvm->extglobals.input_weapon)
|
||||
cmd->weapon = *qcvm->extglobals.input_weapon;
|
||||
if (qcvm->extglobals.input_cursor_screen)
|
||||
cmd->cursor_screen[0] = qcvm->extglobals.input_cursor_screen[0], cmd->cursor_screen[1] = qcvm->extglobals.input_cursor_screen[1];
|
||||
if (qcvm->extglobals.input_cursor_trace_start)
|
||||
VectorCopy(qcvm->extglobals.input_cursor_trace_start, cmd->cursor_start);
|
||||
if (qcvm->extglobals.input_cursor_trace_endpos)
|
||||
VectorCopy(qcvm->extglobals.input_cursor_trace_endpos, cmd->cursor_impact);
|
||||
if (qcvm->extglobals.input_cursor_entitynumber)
|
||||
cmd->cursor_entitynumber = *qcvm->extglobals.input_cursor_entitynumber;
|
||||
}
|
||||
}
|
||||
static void PF_both_pmove(edict_t *e)
|
||||
{
|
||||
static vec3_t extents = {256, 256, 256};
|
||||
vec3_t bounds[2];
|
||||
eval_t *pmflags = GetEdictFieldValue(e, qcvm->extfields.pmove_flags);
|
||||
unsigned int fl = (pmflags && pmflags->_float)?pmflags->_float:0;
|
||||
|
||||
memset(&pmove, 0, sizeof(pmove));
|
||||
VectorCopy(e->v.mins, pmove.player_mins);
|
||||
VectorCopy(e->v.maxs, pmove.player_maxs);
|
||||
VectorCopy(e->v.oldorigin, pmove.safeorigin); pmove.safeorigin_known = (qcvm==&sv.qcvm); //where we revert to when stuck. only consider this valid for ssqc.
|
||||
VectorCopy(e->v.origin, pmove.origin);
|
||||
VectorCopy(e->v.velocity, pmove.velocity);
|
||||
// VectorCopy(e->v.angles, pmove.angles);
|
||||
VectorClear(pmove.gravitydir);
|
||||
|
||||
pmove.waterjumptime = (e->v.teleport_time>qcvm->time)?e->v.teleport_time - qcvm->time:0;
|
||||
pmove.jump_held = !!(fl&PMF_JUMP_HELD);
|
||||
pmove.onladder = !!(fl&PMF_LADDER);
|
||||
pmove.jump_secs = 0; //has been 0 since Z_EXT_PM_TYPE instead of imposing a delay on rejumps.
|
||||
pmove.onground = !!((int)e->v.flags & FL_ONGROUND); //in case we're using pm_pground
|
||||
switch((int)e->v.movetype)
|
||||
{
|
||||
case MOVETYPE_WALK: pmove.pm_type = PM_NORMAL; break;
|
||||
case MOVETYPE_TOSS: //pmove.pm_type = PM_DEAD; break;
|
||||
case MOVETYPE_BOUNCE: pmove.pm_type = PM_DEAD; break;
|
||||
case MOVETYPE_FLY: pmove.pm_type = PM_FLY; break;
|
||||
case MOVETYPE_NOCLIP: pmove.pm_type = PM_SPECTATOR; break;
|
||||
|
||||
case MOVETYPE_NONE:
|
||||
case MOVETYPE_STEP:
|
||||
case MOVETYPE_PUSH:
|
||||
case MOVETYPE_FLYMISSILE:
|
||||
case MOVETYPE_EXT_BOUNCEMISSILE:
|
||||
case MOVETYPE_EXT_FOLLOW:
|
||||
default: pmove.pm_type = PM_NONE; break;
|
||||
}
|
||||
|
||||
VectorSubtract(e->v.absmin, extents, bounds[0]);
|
||||
VectorAdd(e->v.absmax, extents, bounds[1]);
|
||||
World_AddEntsToPmove(e, bounds);
|
||||
|
||||
PR_GetSetInputs(&pmove.cmd, false); //set pmove.cmd to the input_* globals.
|
||||
|
||||
PM_PlayerMove(1);
|
||||
|
||||
VectorCopy(pmove.safeorigin, e->v.oldorigin);
|
||||
VectorCopy(pmove.origin, e->v.origin);
|
||||
VectorCopy(pmove.velocity, e->v.velocity);
|
||||
// VectorCopy(pmove.angles, e->v.angles);
|
||||
e->v.teleport_time = (pmove.waterjumptime>0)?qcvm->time + pmove.waterjumptime:0;
|
||||
|
||||
//report jumping+onground properly.
|
||||
if (pmove.jump_held && movevars.autobunny) //make sure the qc thinks we released the button at some point, triggering a new jump sound.
|
||||
e->v.flags = (int)e->v.flags | FL_JUMPRELEASED;
|
||||
if (pmove.onground)
|
||||
{
|
||||
e->v.flags = (int)e->v.flags | FL_ONGROUND;
|
||||
e->v.groundentity = (pmove.physents[pmove.groundent].info<0)?0:EDICT_TO_PROG(EDICT_NUM(pmove.physents[pmove.groundent].info));
|
||||
}
|
||||
else
|
||||
e->v.flags = (int)e->v.flags & ~FL_ONGROUND;
|
||||
|
||||
//waterlevel+type
|
||||
e->v.waterlevel = pmove.waterlevel;
|
||||
if (pmove.watertype & CONTENTBIT_SOLID)
|
||||
e->v.watertype = CONTENTS_SOLID;
|
||||
else if (pmove.watertype & CONTENTBIT_SKY)
|
||||
e->v.watertype = CONTENTS_SKY;
|
||||
else if (pmove.watertype & CONTENTBIT_LAVA)
|
||||
e->v.watertype = CONTENTS_LAVA;
|
||||
else if (pmove.watertype & CONTENTBIT_SLIME)
|
||||
e->v.watertype = CONTENTS_SLIME;
|
||||
else if (pmove.watertype & CONTENTBIT_WATER)
|
||||
e->v.watertype = CONTENTS_WATER;
|
||||
else
|
||||
e->v.watertype = CONTENTS_EMPTY;
|
||||
|
||||
if (pmflags)
|
||||
{
|
||||
pmflags->_float = ((int)pmflags->_float&~(PMF_JUMP_HELD|PMF_LADDER))
|
||||
| (pmove.jump_held?PMF_JUMP_HELD:0)
|
||||
| (pmove.onladder?PMF_LADDER:0);
|
||||
}
|
||||
|
||||
//now do the touch events, so we can press buttons etc.
|
||||
if (e->v.solid)
|
||||
{
|
||||
edict_t *other;
|
||||
int i, n;
|
||||
// link into place and touch triggers
|
||||
SV_LinkEdict (e, true);
|
||||
|
||||
// touch other objects
|
||||
for (i=0 ; i<pmove.numtouch ; i++)
|
||||
{
|
||||
n = pmove.physents[pmove.touchindex[i]].info;
|
||||
if (n < 0)
|
||||
continue; //don't trigger touches for engine-networked ents, if only because edict_num can't cope.
|
||||
other = EDICT_NUM(n);
|
||||
|
||||
//FIXME: should probably prevent multiple touches of the same ent.
|
||||
|
||||
SV_Impact(e, other);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cvar_t pm_bunnyspeedcap = {"pm_bunnyspeedcap", "", CVAR_SERVERINFO}; //reduces strafejumps to maxspeed instead of endlessly accelerating
|
||||
cvar_t pm_bunnyfriction = {"pm_bunnyfriction", "1", CVAR_SERVERINFO}; //forces nq's frame of friction
|
||||
cvar_t pm_ktjump = {"pm_ktjump", "", CVAR_SERVERINFO};
|
||||
cvar_t pm_slidefix = {"pm_slidefix", "1", CVAR_SERVERINFO}; //don't bump when going down slopes.
|
||||
cvar_t pm_airstep = {"pm_airstep", "", CVAR_SERVERINFO}; //allow stepping up stairs when eg jumping
|
||||
cvar_t pm_pground = {"pm_pground", "", CVAR_SERVERINFO}; //persistent onground state, supposed to be more precise but has gamecode interaction issues.
|
||||
cvar_t pm_stepdown = {"pm_stepdown", "", CVAR_SERVERINFO}; //glue the player to the ground when going down steps instead of just up. kinda weird.
|
||||
cvar_t pm_walljump = {"pm_walljump", "", CVAR_SERVERINFO}; //bouncing off the walls.
|
||||
cvar_t pm_slidyslopes = {"pm_slidyslopes", "", CVAR_SERVERINFO}; //gradually slide down slopes like vanilla nq
|
||||
cvar_t pm_autobunny = {"pm_autobunny", "", CVAR_SERVERINFO}; //pogostick mode, for lazy noobs
|
||||
cvar_t pm_watersinkspeed = {"pm_watersinkspeed", "", CVAR_SERVERINFO}; //speed you sink at when idle in water
|
||||
cvar_t pm_flyfriction = {"pm_flyfriction", "", CVAR_SERVERINFO}; //friction in fly/noclip modes.
|
||||
cvar_t pm_edgefriction = {"pm_edgefriction", "2",}; //should alias to edgefriction but be listed in the serverinfo as pm_...
|
||||
cvar_t pm_stepheight = {"pm_stepheight", ""}; //should alias to edgefriction but be listed in the serverinfo as pm_...
|
||||
extern cvar_t sv_maxspeed;
|
||||
cvar_t sv_spectatormaxspeed = {"sv_spectatormaxspeed", "500"};
|
||||
extern cvar_t sv_accelerate;
|
||||
cvar_t sv_airaccelerate = {"sv_airaccelerate", "0.7"};
|
||||
cvar_t sv_wateraccelerate = {"sv_wateraccelerate", "10"};
|
||||
cvar_t sv_waterfriction = {"sv_waterfriction", "4"};
|
||||
extern cvar_t sv_waterfriction;
|
||||
extern cvar_t sv_friction;
|
||||
extern cvar_t sv_gravity;
|
||||
extern cvar_t sv_stopspeed;
|
||||
void PM_Register(void)
|
||||
{
|
||||
PM_Init();
|
||||
|
||||
Cvar_RegisterVariable(&pm_bunnyspeedcap);
|
||||
Cvar_RegisterVariable(&pm_bunnyfriction);
|
||||
Cvar_RegisterVariable(&pm_ktjump);
|
||||
Cvar_RegisterVariable(&pm_slidefix);
|
||||
Cvar_RegisterVariable(&pm_airstep);
|
||||
Cvar_RegisterVariable(&pm_pground);
|
||||
Cvar_RegisterVariable(&pm_stepdown);
|
||||
Cvar_RegisterVariable(&pm_walljump);
|
||||
Cvar_RegisterVariable(&pm_slidyslopes);
|
||||
Cvar_RegisterVariable(&pm_autobunny);
|
||||
Cvar_RegisterVariable(&pm_watersinkspeed);
|
||||
Cvar_RegisterVariable(&pm_flyfriction);
|
||||
Cvar_RegisterVariable(&pm_edgefriction);
|
||||
Cvar_RegisterVariable(&pm_stepheight);
|
||||
Cvar_RegisterVariable(&sv_spectatormaxspeed);
|
||||
Cvar_RegisterVariable(&sv_airaccelerate);
|
||||
Cvar_RegisterVariable(&sv_wateraccelerate);
|
||||
Cvar_RegisterVariable(&sv_waterfriction);
|
||||
}
|
||||
static movevars_t svmovevars;
|
||||
void PMSV_UpdateMovevars(void)
|
||||
{
|
||||
memset(&svmovevars, 0, sizeof(svmovevars));
|
||||
svmovevars.accelerate = sv_accelerate.value;
|
||||
svmovevars.airaccelerate = sv_airaccelerate.value;
|
||||
svmovevars.friction = sv_friction.value;
|
||||
svmovevars.gravity = sv_gravity.value;
|
||||
svmovevars.stopspeed = sv_stopspeed.value;
|
||||
svmovevars.wateraccelerate = sv_wateraccelerate.value;
|
||||
svmovevars.waterfriction = sv_waterfriction.value;
|
||||
svmovevars.entgravity = 1.0;
|
||||
svmovevars.maxspeed = sv_maxspeed.value;
|
||||
svmovevars.spectatormaxspeed= sv_spectatormaxspeed.value;
|
||||
svmovevars.bunnyspeedcap = pm_bunnyspeedcap.value;
|
||||
svmovevars.ktjump = pm_ktjump.value;
|
||||
svmovevars.airstep = (pm_airstep.value != 0);
|
||||
svmovevars.stepheight = *pm_stepheight.string?pm_stepheight.value:18;
|
||||
svmovevars.stepdown = (pm_stepdown.value != 0);
|
||||
svmovevars.walljump = (pm_walljump.value);
|
||||
svmovevars.slidefix = (pm_slidefix.value != 0);
|
||||
svmovevars.pground = (pm_pground.value != 0);
|
||||
svmovevars.slidyslopes = (pm_slidyslopes.value!=0);
|
||||
svmovevars.autobunny = (pm_autobunny.value!=0);
|
||||
svmovevars.bunnyfriction = (pm_bunnyfriction.value!=0);
|
||||
svmovevars.watersinkspeed = *pm_watersinkspeed.string?pm_watersinkspeed.value:60;
|
||||
svmovevars.flyfriction = *pm_flyfriction.string?pm_flyfriction.value:4;
|
||||
svmovevars.edgefriction = *pm_edgefriction.string?pm_edgefriction.value:2;
|
||||
svmovevars.protocolflags = sv.protocolflags;
|
||||
svmovevars.jumpspeed = 270;
|
||||
svmovevars.maxairspeed = 30;
|
||||
svmovevars.flags = MOVEFLAG_VALID|MOVEFLAG_NOGRAVITYONGROUND|(*pm_edgefriction.string?0:MOVEFLAG_QWEDGEBOX);
|
||||
};
|
||||
static void PF_sv_pmove(void)
|
||||
{
|
||||
edict_t *e = G_EDICT(OFS_PARM0);
|
||||
movevars = svmovevars;
|
||||
PF_both_pmove(e);
|
||||
}
|
||||
void PMSV_SetMoveStats(edict_t *plent, float *fstat, int *istat)
|
||||
{
|
||||
eval_t *entgrav = GetEdictFieldValue(plent, qcvm->extfields.gravity);
|
||||
fstat[STAT_MOVEVARS_STEPHEIGHT] = svmovevars.stepheight;
|
||||
istat[STAT_MOVEFLAGS] = svmovevars.flags;
|
||||
fstat[STAT_MOVEVARS_GRAVITY] = svmovevars.gravity;
|
||||
fstat[STAT_MOVEVARS_STOPSPEED] = svmovevars.stopspeed;
|
||||
fstat[STAT_MOVEVARS_MAXSPEED] = svmovevars.maxspeed;
|
||||
fstat[STAT_MOVEVARS_SPECTATORMAXSPEED] = svmovevars.spectatormaxspeed;
|
||||
fstat[STAT_MOVEVARS_ACCELERATE] = svmovevars.accelerate;
|
||||
fstat[STAT_MOVEVARS_AIRACCELERATE] = svmovevars.airaccelerate;
|
||||
fstat[STAT_MOVEVARS_WATERACCELERATE] = svmovevars.wateraccelerate;
|
||||
fstat[STAT_MOVEVARS_FRICTION] = svmovevars.friction;
|
||||
fstat[STAT_MOVEVARS_WATERFRICTION] = svmovevars.waterfriction;
|
||||
fstat[STAT_MOVEVARS_EDGEFRICTION] = svmovevars.edgefriction;
|
||||
fstat[STAT_MOVEVARS_ENTGRAVITY] = (entgrav && entgrav->_float)?entgrav->_float:1;
|
||||
fstat[STAT_MOVEVARS_TIMESCALE] = 1; //gamespeed?
|
||||
// statsf[STAT_MOVEVARS_TICRATE] = host_maxfps.value;
|
||||
fstat[STAT_MOVEVARS_JUMPVELOCITY] = svmovevars.jumpspeed;
|
||||
fstat[STAT_MOVEVARS_MAXAIRSPEED] = svmovevars.maxairspeed;
|
||||
}
|
||||
|
||||
static movevars_t clmovevars;
|
||||
float PMCL_GetKeyValue(const char *key, float def)
|
||||
{
|
||||
char buf[64];
|
||||
const char *v;
|
||||
v = Info_GetKey(cl.serverinfo, key, buf, sizeof(buf));
|
||||
if (*v)
|
||||
return atof(v);
|
||||
return def;
|
||||
}
|
||||
void PMCL_ServerinfoUpdated(void)
|
||||
{
|
||||
memset(&clmovevars, 0, sizeof(clmovevars));
|
||||
clmovevars.accelerate = PMCL_GetKeyValue("sv_accelerate", 10);
|
||||
clmovevars.airaccelerate = PMCL_GetKeyValue("sv_airaccelerate", 0.7);
|
||||
clmovevars.friction = PMCL_GetKeyValue("sv_friction", 4);
|
||||
clmovevars.gravity = PMCL_GetKeyValue("sv_gravity", 800);
|
||||
clmovevars.stopspeed = PMCL_GetKeyValue("sv_stopspeed", 100);
|
||||
clmovevars.wateraccelerate = PMCL_GetKeyValue("sv_wateraccelerate", 10);
|
||||
clmovevars.waterfriction = PMCL_GetKeyValue("sv_waterfriction", 4);
|
||||
clmovevars.entgravity = 1.0;
|
||||
clmovevars.maxspeed = PMCL_GetKeyValue("sv_maxspeed", 320);
|
||||
clmovevars.spectatormaxspeed = PMCL_GetKeyValue("sv_spectatormaxspeed", 500);
|
||||
clmovevars.bunnyspeedcap = PMCL_GetKeyValue("pm_bunnyspeedcap", 0);
|
||||
clmovevars.ktjump = PMCL_GetKeyValue("pm_ktjump", 0);
|
||||
clmovevars.airstep = PMCL_GetKeyValue("pm_airstep", 0);
|
||||
clmovevars.stepheight = PMCL_GetKeyValue("pm_stepheight", 18);
|
||||
clmovevars.stepdown = PMCL_GetKeyValue("pm_stepdown", 0);
|
||||
clmovevars.walljump = PMCL_GetKeyValue("pm_walljump", 0);
|
||||
clmovevars.slidefix = PMCL_GetKeyValue("pm_slidefix", 0);
|
||||
clmovevars.pground = PMCL_GetKeyValue("pm_pground", 0);
|
||||
clmovevars.slidyslopes = PMCL_GetKeyValue("pm_slidyslopes", 0);
|
||||
clmovevars.autobunny = PMCL_GetKeyValue("pm_autobunny", 0);
|
||||
clmovevars.bunnyfriction = PMCL_GetKeyValue("pm_bunnyfriction", 0);
|
||||
clmovevars.watersinkspeed = PMCL_GetKeyValue("*pm_watersinkspeed", 60);
|
||||
clmovevars.flyfriction = PMCL_GetKeyValue("*pm_flyfriction", 4);
|
||||
clmovevars.edgefriction = PMCL_GetKeyValue("*pm_edgefriction", 2);
|
||||
clmovevars.protocolflags = cl.protocolflags;
|
||||
clmovevars.flags = MOVEFLAG_VALID|MOVEFLAG_NOGRAVITYONGROUND|((PMCL_GetKeyValue("pm_edgefriction", -1000)!=-1000)?0:MOVEFLAG_QWEDGEBOX);
|
||||
clmovevars.jumpspeed = 270;
|
||||
clmovevars.maxairspeed = 30;
|
||||
};
|
||||
static void PF_cs_pmove(void)
|
||||
{
|
||||
edict_t *e = G_EDICT(OFS_PARM0);
|
||||
|
||||
movevars = clmovevars;
|
||||
if (cl.protocol_pext2 & PEXT2_PREDINFO)
|
||||
{ //protocol provides movevars as stats...
|
||||
float *fstat = (cl.protocol == PROTOCOL_VERSION_DP7)?(float*)cl.stats:cl.statsf; //DPP5 is hideous, aim for compat though.
|
||||
|
||||
movevars.stepheight = fstat[STAT_MOVEVARS_STEPHEIGHT];
|
||||
movevars.flags = cl.stats[STAT_MOVEFLAGS];
|
||||
movevars.gravity = fstat[STAT_MOVEVARS_GRAVITY];
|
||||
movevars.stopspeed = fstat[STAT_MOVEVARS_STOPSPEED];
|
||||
movevars.maxspeed = fstat[STAT_MOVEVARS_MAXSPEED];
|
||||
movevars.spectatormaxspeed = fstat[STAT_MOVEVARS_SPECTATORMAXSPEED];
|
||||
movevars.accelerate = fstat[STAT_MOVEVARS_ACCELERATE];
|
||||
movevars.airaccelerate = fstat[STAT_MOVEVARS_AIRACCELERATE];
|
||||
movevars.wateraccelerate = fstat[STAT_MOVEVARS_WATERACCELERATE];
|
||||
movevars.friction = fstat[STAT_MOVEVARS_FRICTION];
|
||||
movevars.waterfriction = fstat[STAT_MOVEVARS_WATERFRICTION];
|
||||
movevars.edgefriction = fstat[STAT_MOVEVARS_EDGEFRICTION];
|
||||
movevars.entgravity = fstat[STAT_MOVEVARS_ENTGRAVITY];
|
||||
movevars.jumpspeed = fstat[STAT_MOVEVARS_JUMPVELOCITY];
|
||||
movevars.maxairspeed = fstat[STAT_MOVEVARS_MAXAIRSPEED];
|
||||
}
|
||||
|
||||
PF_both_pmove(e);
|
||||
}
|
||||
|
||||
//model stuff
|
||||
void SetMinMaxSize (edict_t *e, float *minvec, float *maxvec, qboolean rotate);
|
||||
static void PF_sv_setmodelindex(void)
|
||||
|
@ -6942,7 +7297,6 @@ static void PF_cs_setlistener(void)
|
|||
VectorCopy(up, cl.listener_axis[2]);
|
||||
}
|
||||
|
||||
void CL_CSQC_SetInputs(usercmd_t *cmd, qboolean set);
|
||||
static void PF_cs_getinputstate(void)
|
||||
{
|
||||
unsigned int seq = G_FLOAT(OFS_PARM0);
|
||||
|
@ -6950,12 +7304,13 @@ static void PF_cs_getinputstate(void)
|
|||
{ //the partial/pending frame!
|
||||
G_FLOAT(OFS_RETURN) = 1;
|
||||
cl.pendingcmd.seconds = cl.time - cl.pendingcmd.servertime; //make sure this is kept current. its important for smoothness.
|
||||
CL_CSQC_SetInputs(&cl.pendingcmd, true);
|
||||
cl.pendingcmd.sequence = seq;
|
||||
PR_GetSetInputs(&cl.pendingcmd, true);
|
||||
}
|
||||
else if (cl.movecmds[seq&MOVECMDS_MASK].sequence == seq)
|
||||
{ //valid sequence slot.
|
||||
G_FLOAT(OFS_RETURN) = 1;
|
||||
CL_CSQC_SetInputs(&cl.movecmds[seq&MOVECMDS_MASK], true);
|
||||
PR_GetSetInputs(&cl.movecmds[seq&MOVECMDS_MASK], true);
|
||||
}
|
||||
else
|
||||
G_FLOAT(OFS_RETURN) = 0; //invalid
|
||||
|
@ -7540,7 +7895,7 @@ static struct
|
|||
{"getmousepos", PF_NoSSQC, PF_NoCSQC, 344, PF_m_getmousepos,66, D("vector()", "Nasty convoluted DP extension. Typically returns deltas instead of positions. Use CSQC_InputEvent for such things in csqc mods.")}, // #344 This is a DP extension
|
||||
{"getinputstate", PF_NoSSQC, PF_cs_getinputstate,345, PF_NoMenu, D("float(float inputsequencenum)", "Looks up an input frame from the log, setting the input_* globals accordingly.\nThe sequence number range used for prediction should normally be servercommandframe < sequence <= clientcommandframe.\nThe sequence equal to clientcommandframe will change between input frames.")},// (EXT_CSQC)
|
||||
{"setsensitivityscaler",PF_NoSSQC, PF_cl_setsensitivity,346, PF_NoMenu, D("void(float sens)", "Temporarily scales the player's mouse sensitivity based upon something like zoom, avoiding potential cvar saving and thus corruption.")},// (EXT_CSQC)
|
||||
// {"runstandardplayerphysics",NULL, PF_FullCSQCOnly, 347, PF_NoMenu, D("void(entity ent)", "Perform the engine's standard player movement prediction upon the given entity using the input_* globals to describe movement.")},
|
||||
{"runstandardplayerphysics",PF_sv_pmove,PF_cs_pmove, 347, PF_NoMenu, D("void(entity ent)", "Perform the engine's standard player movement prediction upon the given entity using the input_* globals to describe movement.")},
|
||||
{"getplayerkeyvalue",NULL, PF_cl_playerkey_s, 348, PF_NoMenu, D("string(float playernum, string keyname)", "Look up a player's userinfo, to discover things like their name, topcolor, bottomcolor, skin, team, *ver.\nAlso includes scoreboard info like frags, ping, pl, userid, entertime, as well as voipspeaking and voiploudness.")},// (EXT_CSQC)
|
||||
{"getplayerkeyfloat",NULL, PF_cl_playerkey_f, 0, PF_NoMenu, D("float(float playernum, string keyname, optional float assumevalue)", "Cheaper version of getplayerkeyvalue that avoids the need for so many tempstrings.")},
|
||||
{"isdemo", PF_NoSSQC, PF_cl_isdemo, 349, PF_cl_isdemo,349, D("float()", "Returns if the client is currently playing a demo or not")},// (EXT_CSQC)
|
||||
|
@ -8311,6 +8666,17 @@ void PR_EnableExtensions(ddef_t *pr_globaldefs)
|
|||
#undef QCEXTGLOBAL_INT
|
||||
#undef QCEXTGLOBAL_VECTOR
|
||||
|
||||
//some need guarentees they exist (inputs get copied into globals and then back out)
|
||||
#define QCEXTGLOBAL_FLOAT(n) if (!qcvm->extglobals.n) qcvm->extglobals.n = &qcvm->fallback_##n;
|
||||
#define QCEXTGLOBAL_VECTOR(n) if (!qcvm->extglobals.n) qcvm->extglobals.n = &qcvm->fallback_##n[0];
|
||||
#define QCEXTGLOBAL_INT QCEXTGLOBAL_FLOAT
|
||||
#define QCEXTGLOBAL_UINT64 QCEXTGLOBAL_FLOAT
|
||||
QCEXTGLOBALS_INPUTS
|
||||
#undef QCEXTGLOBAL_FLOAT
|
||||
#undef QCEXTGLOBAL_VECTOR
|
||||
#undef QCEXTGLOBAL_INT
|
||||
#undef QCEXTGLOBAL_UINT64
|
||||
|
||||
//any #0 functions are remapped to their builtins here, so we don't have to tweak the VM in an obscure potentially-breaking way.
|
||||
for (i = 0; i < (unsigned int)qcvm->progs->numfunctions; i++)
|
||||
{
|
||||
|
|
|
@ -127,6 +127,7 @@ int NUM_FOR_EDICT(edict_t*);
|
|||
|
||||
#define G_FLOAT(o) (qcvm->globals[o])
|
||||
#define G_INT(o) (*(int *)&qcvm->globals[o])
|
||||
#define G_UINT(o) (*(unsigned int *)&qcvm->globals[o])
|
||||
#define G_INT64(o) (*(qcsint64_t *)&qcvm->globals[o])
|
||||
#define G_UINT64(o) (*(qcuint64_t *)&qcvm->globals[o])
|
||||
#define G_DOUBLE(o) (*(qcdouble_t *)&qcvm->globals[o])
|
||||
|
@ -227,7 +228,9 @@ struct pr_extglobals_s
|
|||
QCEXTGLOBAL_FLOAT(time)\
|
||||
QCEXTGLOBAL_FLOAT(frametime)\
|
||||
//end
|
||||
#define QCEXTGLOBALS_GAME \
|
||||
#define QCEXTGLOBALS_INPUTS \
|
||||
QCEXTGLOBAL_FLOAT(input_sequence)\
|
||||
QCEXTGLOBAL_FLOAT(input_servertime)\
|
||||
QCEXTGLOBAL_FLOAT(input_timelength)\
|
||||
QCEXTGLOBAL_VECTOR(input_movevalues)\
|
||||
QCEXTGLOBAL_VECTOR(input_angles)\
|
||||
|
@ -238,6 +241,9 @@ struct pr_extglobals_s
|
|||
QCEXTGLOBAL_VECTOR(input_cursor_trace_start)\
|
||||
QCEXTGLOBAL_VECTOR(input_cursor_trace_endpos)\
|
||||
QCEXTGLOBAL_FLOAT(input_cursor_entitynumber)\
|
||||
//end
|
||||
#define QCEXTGLOBALS_GAME \
|
||||
QCEXTGLOBALS_INPUTS \
|
||||
QCEXTGLOBAL_FLOAT(physics_mode)\
|
||||
//end
|
||||
#define QCEXTGLOBALS_CSQC \
|
||||
|
@ -283,6 +289,7 @@ struct pr_extfields_s
|
|||
/*stuff used by csqc+ssqc, but not menu*/ \
|
||||
QCEXTFIELD(customphysics, ".void()")/*function*/ \
|
||||
QCEXTFIELD(gravity, ".float") /*float*/ \
|
||||
QCEXTFIELD(pmove_flags, ".float") /*float, mostly to hold jump_held*/ \
|
||||
//end of list
|
||||
#define QCEXTFIELDS_CL \
|
||||
QCEXTFIELD(frame2, ".float") /*for csqc's addentity builtin.*/ \
|
||||
|
@ -428,6 +435,17 @@ struct qcvm_s
|
|||
//originally from world.c
|
||||
areanode_t areanodes[AREA_NODES];
|
||||
int numareanodes;
|
||||
|
||||
|
||||
#define QCEXTGLOBAL_FLOAT(n) float fallback_##n;
|
||||
#define QCEXTGLOBAL_VECTOR(n) vec3_t fallback_##n;
|
||||
#define QCEXTGLOBAL_INT(n) int fallback_##n;
|
||||
#define QCEXTGLOBAL_UINT64(n) uint64_t fallback_##n;
|
||||
QCEXTGLOBALS_INPUTS
|
||||
#undef QCEXTGLOBAL_FLOAT
|
||||
#undef QCEXTGLOBAL_VECTOR
|
||||
#undef QCEXTGLOBAL_INT
|
||||
#undef QCEXTGLOBAL_UINT64
|
||||
};
|
||||
extern globalvars_t *pr_global_struct;
|
||||
|
||||
|
@ -440,6 +458,8 @@ extern qcvm_t *qcvm;
|
|||
void PR_SwitchQCVM(qcvm_t *nvm);
|
||||
#endif
|
||||
|
||||
void PR_GetSetInputs(usercmd_t *cmd, qboolean set);
|
||||
|
||||
extern const builtin_t pr_ssqcbuiltins[];
|
||||
extern const int pr_ssqcnumbuiltins;
|
||||
extern const builtin_t pr_csqcbuiltins[];
|
||||
|
|
|
@ -73,9 +73,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#define PEXT2_PREDINFO 0x00000020 //provides input acks and reworks stats such that clc_clientdata becomes redundant.
|
||||
#define PEXT2_NEWSIZEENCODING 0x00000040 //richer size encoding, for more precise bboxes.
|
||||
#define PEXT2_INFOBLOBS 0x00000080 //unbounded userinfo
|
||||
#define PEXT2_ACCEPTED_CLIENT (PEXT2_SUPPORTED_CLIENT|PEXT2_NEWSIZEENCODING|PEXT2_INFOBLOBS) //pext2 flags that we can parse, but don't want to advertise (for demos)
|
||||
#define PEXT2_SUPPORTED_CLIENT (PEXT2_PRYDONCURSOR|PEXT2_VOICECHAT|PEXT2_SETANGLEDELTA|PEXT2_REPLACEMENTDELTAS|PEXT2_MAXPLAYERS|PEXT2_PREDINFO) //pext2 flags that we understand+support
|
||||
#define PEXT2_SUPPORTED_SERVER (PEXT2_PRYDONCURSOR|PEXT2_VOICECHAT| PEXT2_REPLACEMENTDELTAS |PEXT2_PREDINFO)
|
||||
//#define PEXT2_STUNAWARE 0x00000100 //changes the netchan to biased-bigendian (so lead two bits are 1 and not stun's 0, so we don't get confused). not applicable to nq, doesn't change the actual svcs/clcs at all.
|
||||
//#define PEXT2_VRINPUTS 0x00000200 //clc_move changes, more buttons etc. vr stuff!
|
||||
//#define PEXT2_LERPTIME 0x00000400 //fitz-bloat parity. redefines UF_16BIT as UF_LERPEND in favour of length coding.
|
||||
#define PEXT2_ACCEPTED_CLIENT (PEXT2_SUPPORTED_CLIENT|PEXT2_INFOBLOBS) //pext2 flags that we can parse, but don't want to advertise (for demos)
|
||||
#define PEXT2_SUPPORTED_CLIENT (PEXT2_PRYDONCURSOR|PEXT2_VOICECHAT|PEXT2_SETANGLEDELTA|PEXT2_REPLACEMENTDELTAS|PEXT2_MAXPLAYERS|PEXT2_PREDINFO|PEXT2_NEWSIZEENCODING) //pext2 flags that we understand+support
|
||||
#define PEXT2_SUPPORTED_SERVER (PEXT2_PRYDONCURSOR|PEXT2_VOICECHAT| PEXT2_REPLACEMENTDELTAS |PEXT2_PREDINFO|PEXT2_NEWSIZEENCODING)
|
||||
|
||||
// if the high bit of the servercmd is set, the low bits are fast update flags:
|
||||
#define U_MOREBITS (1<<0)
|
||||
|
@ -489,6 +492,7 @@ typedef struct entity_state_s
|
|||
#define ES_SOLID_BSP 31
|
||||
#define ES_SOLID_HULL1 0x80201810
|
||||
#define ES_SOLID_HULL2 0x80401820
|
||||
#define ES_SOLID_HAS_EXTRA_BITS(solid) ((solid&0x0707) || (((solid>>16)-32768+32) & 7))
|
||||
} entity_state_t;
|
||||
#define EFLAGS_STEP 1
|
||||
//#define EFLAGS_GLOWTRAIL 2
|
||||
|
|
|
@ -148,6 +148,44 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#define STAT_PUNCHVECTOR_Y 30
|
||||
#define STAT_PUNCHVECTOR_Z 31
|
||||
|
||||
//dp defines these. most are useless but we fill them in for consistency.
|
||||
//#define STAT_MOVEVARS_AIRACCEL_QW_STRETCHFACTOR 220
|
||||
//#define STAT_MOVEVARS_AIRCONTROL_PENALTY 221
|
||||
//#define STAT_MOVEVARS_AIRSPEEDLIMIT_NONQW 222
|
||||
//#define STAT_MOVEVARS_AIRSTRAFEACCEL_QW 223
|
||||
//#define STAT_MOVEVARS_AIRCONTROL_POWER 224
|
||||
#define STAT_MOVEFLAGS 225
|
||||
//#define STAT_MOVEVARS_WARSOWBUNNY_AIRFORWARDACCEL 226
|
||||
//#define STAT_MOVEVARS_WARSOWBUNNY_ACCEL 227
|
||||
//#define STAT_MOVEVARS_WARSOWBUNNY_TOPSPEED 228
|
||||
//#define STAT_MOVEVARS_WARSOWBUNNY_TURNACCEL 229
|
||||
//#define STAT_MOVEVARS_WARSOWBUNNY_BACKTOSIDERATIO 230
|
||||
//#define STAT_MOVEVARS_AIRSTOPACCELERATE 231
|
||||
//#define STAT_MOVEVARS_AIRSTRAFEACCELERATE 232
|
||||
//#define STAT_MOVEVARS_MAXAIRSTRAFESPEED 233
|
||||
//#define STAT_MOVEVARS_AIRCONTROL 234
|
||||
//#define STAT_FRAGLIMIT 235
|
||||
//#define STAT_TIMELIMIT 236
|
||||
//#define STAT_MOVEVARS_WALLFRICTION 237
|
||||
#define STAT_MOVEVARS_FRICTION 238
|
||||
#define STAT_MOVEVARS_WATERFRICTION 239
|
||||
//#define STAT_MOVEVARS_TICRATE 240
|
||||
#define STAT_MOVEVARS_TIMESCALE 241
|
||||
#define STAT_MOVEVARS_GRAVITY 242
|
||||
#define STAT_MOVEVARS_STOPSPEED 243
|
||||
#define STAT_MOVEVARS_MAXSPEED 244
|
||||
#define STAT_MOVEVARS_SPECTATORMAXSPEED 245
|
||||
#define STAT_MOVEVARS_ACCELERATE 246
|
||||
#define STAT_MOVEVARS_AIRACCELERATE 247
|
||||
#define STAT_MOVEVARS_WATERACCELERATE 248
|
||||
#define STAT_MOVEVARS_ENTGRAVITY 249
|
||||
#define STAT_MOVEVARS_JUMPVELOCITY 250
|
||||
#define STAT_MOVEVARS_EDGEFRICTION 251
|
||||
#define STAT_MOVEVARS_MAXAIRSPEED 252
|
||||
#define STAT_MOVEVARS_STEPHEIGHT 253
|
||||
//#define STAT_MOVEVARS_AIRACCEL_QW 254
|
||||
//#define STAT_MOVEVARS_AIRACCEL_SIDEWAYS_FRICTION 255
|
||||
|
||||
// stock defines
|
||||
//
|
||||
#define IT_SHOTGUN 1
|
||||
|
|
|
@ -317,7 +317,7 @@ void SV_DropClient (qboolean crash);
|
|||
|
||||
void SVFTE_Ack(client_t *client, int sequence);
|
||||
void SVFTE_DestroyFrames(client_t *client);
|
||||
void SV_BuildEntityState(edict_t *ent, entity_state_t *state);
|
||||
void SV_BuildEntityState(client_t *client, edict_t *ent, entity_state_t *state);
|
||||
void SV_SendClientMessages (void);
|
||||
void SV_ClearDatagram (void);
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
// sv_main.c -- server main program
|
||||
|
||||
#include "quakedef.h"
|
||||
#include "pmove.h"
|
||||
|
||||
server_t sv;
|
||||
server_static_t svs;
|
||||
|
@ -88,29 +89,12 @@ void SV_CalcStats(client_t *client, int *statsi, float *statsf, const char **sta
|
|||
statsf[STAT_PUNCHANGLE_Y] = ent->v.punchangle[1];
|
||||
statsf[STAT_PUNCHANGLE_Z] = ent->v.punchangle[2];
|
||||
}
|
||||
/*
|
||||
|
||||
if (client->protocol_pext2 & PEXT2_PREDINFO)
|
||||
{ //prediction needs some info on the server's rules
|
||||
statsf[STAT_MOVEVARS_FRICTION] = sv_friction.value;
|
||||
statsf[STAT_MOVEVARS_WATERFRICTION] = sv_waterfriction.value;
|
||||
statsf[STAT_MOVEVARS_TICRATE] = host_maxfps.value;
|
||||
statsf[STAT_MOVEVARS_TIMESCALE] = sv_gamespeed.value;
|
||||
statsf[STAT_MOVEVARS_GRAVITY] = sv_gravity.value;
|
||||
statsf[STAT_MOVEVARS_STOPSPEED] = sv_stopspeed.value;
|
||||
statsf[STAT_MOVEVARS_MAXSPEED] = client->maxspeed;
|
||||
statsf[STAT_MOVEVARS_SPECTATORMAXSPEED] = sv_spectatormaxspeed.value;
|
||||
statsf[STAT_MOVEVARS_ACCELERATE] = sv_accelerate.value;
|
||||
statsf[STAT_MOVEVARS_AIRACCELERATE] = sv_airaccelerate.value;
|
||||
statsf[STAT_MOVEVARS_WATERACCELERATE] = sv_wateraccelerate.value;
|
||||
statsf[STAT_MOVEVARS_ENTGRAVITY] = client->entgravity/sv_gravity.value;
|
||||
statsf[STAT_MOVEVARS_JUMPVELOCITY] = sv_jumpvelocity.value; //bah
|
||||
statsf[STAT_MOVEVARS_EDGEFRICTION] = sv_edgefriction.value;
|
||||
statsf[STAT_MOVEVARS_MAXAIRSPEED] = client->maxspeed;
|
||||
statsf[STAT_MOVEVARS_STEPHEIGHT] = 18;
|
||||
// statsf[STAT_MOVEVARS_AIRACCEL_QW] = 0;
|
||||
// statsf[STAT_MOVEVARS_AIRACCEL_SIDEWAYS_FRICTION] = sv_gravity.value;
|
||||
PMSV_SetMoveStats(ent, statsf, statsi);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
for (i = 0; i < sv.numcustomstats; i++)
|
||||
{
|
||||
|
@ -175,8 +159,8 @@ void SV_CalcStats(client_t *client, int *statsi, float *statsf, const char **sta
|
|||
static unsigned int SVFTE_DeltaPredCalcBits(entity_state_t *from, entity_state_t *to)
|
||||
{
|
||||
unsigned int bits = 0;
|
||||
// if (from && from->pmovetype != to->pmovetype)
|
||||
// bits |= UFP_MOVETYPE;
|
||||
if (from && from->pmovetype != to->pmovetype)
|
||||
bits |= UFP_MOVETYPE;
|
||||
|
||||
// if (to->movement[0])
|
||||
// bits |= UFP_FORWARD;
|
||||
|
@ -250,8 +234,8 @@ static unsigned int MSGFTE_DeltaCalcBits(entity_state_t *from, entity_state_t *t
|
|||
bits |= UF_EFFECTS;
|
||||
if (to->eflags != from->eflags)
|
||||
bits |= UF_FLAGS;
|
||||
// if (to->solidsize != from->solidsize)
|
||||
// bits |= UF_SOLID;
|
||||
if (to->solidsize != from->solidsize)
|
||||
bits |= UF_SOLID;
|
||||
|
||||
if (to->scale != from->scale)
|
||||
bits |= UF_SCALE;
|
||||
|
@ -292,6 +276,24 @@ static unsigned int MSGFTE_DeltaCalcBits(entity_state_t *from, entity_state_t *t
|
|||
return bits;
|
||||
}
|
||||
|
||||
static void MSG_WriteSize16 (sizebuf_t *sb, int sz)
|
||||
{
|
||||
if (sz == ES_SOLID_BSP)
|
||||
MSG_WriteShort(sb, ES_SOLID_BSP);
|
||||
else if (sz)
|
||||
{
|
||||
//decode the 32bit version and recode it.
|
||||
int x = sz & 255;
|
||||
int zd = (sz >> 8) & 255;
|
||||
int zu = ((sz >> 16) & 65535) - 32768;
|
||||
MSG_WriteShort(sb,
|
||||
((x>>3)<<0) |
|
||||
((zd>>3)<<5) |
|
||||
(((zu+32)>>3)<<10));
|
||||
}
|
||||
else
|
||||
MSG_WriteShort(sb, 0);
|
||||
}
|
||||
static void MSGFTE_WriteEntityUpdate(unsigned int bits, entity_state_t *state, sizebuf_t *msg, unsigned int pext2, unsigned int protocolflags)
|
||||
{
|
||||
unsigned int predbits = 0;
|
||||
|
@ -323,7 +325,7 @@ static void MSGFTE_WriteEntityUpdate(unsigned int bits, entity_state_t *state, s
|
|||
}
|
||||
}
|
||||
|
||||
// if (!(pext2 & PEXT2_NEWSIZEENCODING)) //was added at the same time
|
||||
if (!(pext2 & PEXT2_NEWSIZEENCODING)) //was added at the same time
|
||||
bits &= ~UF_BONEDATA;
|
||||
|
||||
/*check if we need more precision for some things*/
|
||||
|
@ -472,7 +474,7 @@ static void MSGFTE_WriteEntityUpdate(unsigned int bits, entity_state_t *state, s
|
|||
|
||||
if (bits & UF_SOLID)
|
||||
{
|
||||
/* if (pext2 & PEXT2_NEWSIZEENCODING)
|
||||
if (pext2 & PEXT2_NEWSIZEENCODING)
|
||||
{
|
||||
if (!state->solidsize)
|
||||
MSG_WriteByte(msg, 0);
|
||||
|
@ -495,7 +497,7 @@ static void MSGFTE_WriteEntityUpdate(unsigned int bits, entity_state_t *state, s
|
|||
}
|
||||
else
|
||||
MSG_WriteSize16(msg, state->solidsize);
|
||||
*/ }
|
||||
}
|
||||
|
||||
if (bits & UF_FLAGS)
|
||||
MSG_WriteByte(msg, state->eflags);
|
||||
|
@ -1114,7 +1116,7 @@ SV_BuildEntityState
|
|||
copies edict state into a more compact entity_state_t with all the extension fields etc sorted out and neatened up for network precision.
|
||||
note: ignores viewmodelforclient and other client-specific stuff.
|
||||
*/
|
||||
void SV_BuildEntityState(edict_t *ent, entity_state_t *state)
|
||||
void SV_BuildEntityState(client_t *client, edict_t *ent, entity_state_t *state)
|
||||
{
|
||||
eval_t *val;
|
||||
state->eflags = 0;
|
||||
|
@ -1166,6 +1168,21 @@ void SV_BuildEntityState(edict_t *ent, entity_state_t *state)
|
|||
|
||||
state->pmovetype = 0;
|
||||
state->velocity[0] = state->velocity[1] = state->velocity[2] = 0;
|
||||
|
||||
if (client && client->edict && (ent->v.owner == EDICT_TO_PROG(client->edict)))
|
||||
state->solidsize = 0;
|
||||
else if (ent->v.solid == SOLID_BSP || (ent->v.skin < 0 && ent->v.modelindex))
|
||||
state->solidsize = ES_SOLID_BSP;
|
||||
else if (ent->v.solid == SOLID_BBOX || ent->v.solid == SOLID_SLIDEBOX || ent->v.skin < 0)
|
||||
{
|
||||
state->solidsize = CLAMP(0, (int)-ent->v.mins[0], 255);
|
||||
state->solidsize |= CLAMP(0, (int)-ent->v.mins[2], 255)<<8;
|
||||
state->solidsize |= CLAMP(0, (int)((ent->v.maxs[2]+32768)), 65535)<<16; /*up can be negative*/
|
||||
if (state->solidsize == 0x80000000)
|
||||
state->solidsize = ES_SOLID_NOT; //point sized stuff should just be non-solid. you'll thank me for splitscreens.
|
||||
}
|
||||
else
|
||||
state->solidsize = 0;
|
||||
}
|
||||
|
||||
byte *SV_FatPVS (vec3_t org, qmodel_t *worldmodel);
|
||||
|
@ -1288,20 +1305,30 @@ invisible:
|
|||
maxents += 64;
|
||||
ents = realloc(ents, maxents*sizeof(*ents));
|
||||
}
|
||||
|
||||
|
||||
ents[numents].num = e;
|
||||
SV_BuildEntityState(ent, &ents[numents].state);
|
||||
SV_BuildEntityState(client, ent, &ents[numents].state);
|
||||
if ((unsigned int)ents[numents].state.modelindex >= client->limit_models)
|
||||
ents[numents].state.modelindex = 0;
|
||||
if (ent == clent) //add velocity, but we only care for the local player (should add prediction for other entities some time too).
|
||||
{
|
||||
ents[numents].state.pmovetype = 0;//ent->v.movetype; //fixme: we don't do prediction, so don't tell the client that it can try
|
||||
if ((int)ent->v.flags & FL_ONGROUND)
|
||||
eflags |= EFLAGS_ONGROUND;
|
||||
if (qcvm->extfuncs.SV_RunClientCommand)
|
||||
ents[numents].state.pmovetype = ent->v.movetype; //looks like prediction is available. assuming SV_RunClientCommand just calls runstandardplayerphysics then we can predict it with matching clientside stuff.
|
||||
else
|
||||
ents[numents].state.pmovetype = 0; //fixme: we don't do prediction, so don't tell the client that it can try
|
||||
if (ents[numents].state.pmovetype)
|
||||
{ //add some extra pmove flags...
|
||||
eval_t *pmflags = GetEdictFieldValue(ent, qcvm->extfields.pmove_flags);
|
||||
if ((int)ent->v.flags & FL_ONGROUND) //nq likes to know this for bob states.
|
||||
ents[numents].state.pmovetype |= 0x80;
|
||||
if ((int)pmflags->_float & 1) //'jump_held' so no pogostick surprises.
|
||||
ents[numents].state.pmovetype |= 0x40;
|
||||
}
|
||||
ents[numents].state.velocity[0] = ent->v.velocity[0]*8;
|
||||
ents[numents].state.velocity[1] = ent->v.velocity[1]*8;
|
||||
ents[numents].state.velocity[2] = ent->v.velocity[2]*8;
|
||||
}
|
||||
/*TODO: other players *should* provide movetype+msec+v_angle+movement+velocity info so they can be extrapolated by fancy clients*/
|
||||
else if (ent->alpha == ENTALPHA_ZERO && !ent->v.effects) //don't send invisible entities unless they have effects
|
||||
continue;
|
||||
val = GetEdictFieldValue(ent, qcvm->extfields.exteriormodeltoclient);
|
||||
|
@ -1520,7 +1547,7 @@ void SV_Init (void)
|
|||
extern cvar_t sv_sound_watersplash; //spike - making these changable is handy...
|
||||
extern cvar_t sv_sound_land; //spike - and also mutable...
|
||||
|
||||
|
||||
PM_Register();
|
||||
Cvar_RegisterVariable (&sv_maxvelocity);
|
||||
Cvar_RegisterVariable (&sv_gravity);
|
||||
Cvar_RegisterVariable (&sv_friction);
|
||||
|
|
|
@ -1650,6 +1650,6 @@ void SV_Physics (double frametime)
|
|||
PR_ExecuteProgram (qcvm->extfuncs.EndFrame);
|
||||
}
|
||||
|
||||
if (!(sv_freezenonclients.value && qcvm == &sv.qcvm))
|
||||
if (!(sv_freezenonclients.value && qcvm == &sv.qcvm)) //FIXME: this breaks input_timelength
|
||||
qcvm->time += frametime;
|
||||
}
|
||||
|
|
|
@ -392,6 +392,8 @@ void SV_ClientThink (void)
|
|||
|
||||
if (sv_player->v.movetype == MOVETYPE_NONE)
|
||||
return;
|
||||
if (qcvm->extfuncs.SV_RunClientCommand)
|
||||
return; //this stuff is handled on inputs. don't corrupt anything.
|
||||
|
||||
onground = (int)sv_player->v.flags & FL_ONGROUND;
|
||||
|
||||
|
@ -510,7 +512,7 @@ void SV_ReadClientMove (usercmd_t *move)
|
|||
return; //okay, we don't care about that then
|
||||
|
||||
// calc ping times
|
||||
host_client->lastmovemessage = sequence;
|
||||
host_client->lastmovemessage = sequence; //so client can know which input frames still need predicting.
|
||||
if (!(host_client->protocol_pext2 & PEXT2_PREDINFO))
|
||||
{
|
||||
host_client->ping_times[host_client->num_pings%NUM_PING_TIMES]
|
||||
|
@ -555,14 +557,8 @@ void SV_ReadClientMove (usercmd_t *move)
|
|||
//FIXME: attempt to apply physics command now, if the mod has custom physics+csqc-prediction
|
||||
|
||||
|
||||
if (qcvm->extfuncs.SV_RunClientCommand)
|
||||
if (qcvm->extfuncs.SV_RunClientCommand && host_client->knowntoqc)
|
||||
{
|
||||
pr_global_struct->self = EDICT_TO_PROG(host_client->edict);
|
||||
PR_ExecuteProgram(pr_global_struct->PlayerPreThink);
|
||||
|
||||
if (!SV_RunThink (host_client->edict))
|
||||
return; //ent was removed? o.O
|
||||
|
||||
if (timestamp > qcvm->time)
|
||||
timestamp = qcvm->time; //don't let the client exceed the current time
|
||||
if (timestamp < qcvm->time-0.5)
|
||||
|
@ -573,6 +569,10 @@ void SV_ReadClientMove (usercmd_t *move)
|
|||
*qcvm->extglobals.input_timelength = timestamp - host_client->lastmovetime;
|
||||
host_client->lastmovetime = timestamp;
|
||||
|
||||
if (qcvm->extglobals.input_sequence)
|
||||
*qcvm->extglobals.input_sequence = sequence;
|
||||
if (qcvm->extglobals.input_servertime)
|
||||
*qcvm->extglobals.input_servertime = timestamp;
|
||||
if (qcvm->extglobals.input_buttons)
|
||||
*qcvm->extglobals.input_buttons = buttonbits;
|
||||
if (qcvm->extglobals.input_impulse)
|
||||
|
@ -593,8 +593,13 @@ void SV_ReadClientMove (usercmd_t *move)
|
|||
*qcvm->extglobals.input_cursor_entitynumber = curs_entity;
|
||||
|
||||
pr_global_struct->self = EDICT_TO_PROG(host_client->edict);
|
||||
PR_ExecuteProgram(qcvm->extfuncs.SV_RunClientCommand);
|
||||
PR_ExecuteProgram(pr_global_struct->PlayerPreThink);
|
||||
|
||||
if (!SV_RunThink (host_client->edict))
|
||||
return; //ent was removed? o.O
|
||||
|
||||
pr_global_struct->self = EDICT_TO_PROG(host_client->edict);
|
||||
PR_ExecuteProgram(qcvm->extfuncs.SV_RunClientCommand);
|
||||
|
||||
pr_global_struct->self = EDICT_TO_PROG(host_client->edict);
|
||||
PR_ExecuteProgram(pr_global_struct->PlayerPostThink);
|
||||
|
|
129
Quake/world.c
129
Quake/world.c
|
@ -262,6 +262,131 @@ void SV_UnlinkEdict (edict_t *ent)
|
|||
ent->area.prev = ent->area.next = NULL;
|
||||
}
|
||||
|
||||
#include "pmove.h"
|
||||
static void
|
||||
World_AreaAddEntsToPmove ( edict_t *ignore, areanode_t *node, vec3_t boxminmax[2] )
|
||||
{
|
||||
link_t *l, *next;
|
||||
edict_t *other;
|
||||
|
||||
// touch linked edicts
|
||||
for (l = node->solid_edicts.next ; l != &node->solid_edicts ; l = next)
|
||||
{
|
||||
next = l->next;
|
||||
other = EDICT_FROM_AREA(l);
|
||||
if (other == ignore)
|
||||
continue;
|
||||
if (other->v.solid != SOLID_BBOX && other->v.solid != SOLID_SLIDEBOX && other->v.solid != SOLID_BSP)
|
||||
continue;
|
||||
if (boxminmax[0][0] > other->v.absmax[0]
|
||||
|| boxminmax[0][1] > other->v.absmax[1]
|
||||
|| boxminmax[0][2] > other->v.absmax[2]
|
||||
|| boxminmax[1][0] < other->v.absmin[0]
|
||||
|| boxminmax[1][1] < other->v.absmin[1]
|
||||
|| boxminmax[1][2] < other->v.absmin[2] )
|
||||
continue;
|
||||
|
||||
if (PROG_TO_EDICT(other->v.owner) == ignore)
|
||||
continue; // don't clip against own missiles
|
||||
if (PROG_TO_EDICT(ignore->v.owner) == other)
|
||||
continue; // don't clip against owner
|
||||
|
||||
if (pmove.numphysent == countof(pmove.physents))
|
||||
return; //too many... ooer.
|
||||
|
||||
pmove.physents[pmove.numphysent].info = NUM_FOR_EDICT(other);
|
||||
pmove.physents[pmove.numphysent].model = (other->v.solid == SOLID_BSP)?qcvm->GetModel(other->v.modelindex):NULL;
|
||||
VectorCopy(other->v.origin, pmove.physents[pmove.numphysent].origin);
|
||||
VectorCopy(other->v.mins, pmove.physents[pmove.numphysent].mins);
|
||||
VectorCopy(other->v.maxs, pmove.physents[pmove.numphysent].maxs);
|
||||
VectorCopy(other->v.angles, pmove.physents[pmove.numphysent].angles);
|
||||
|
||||
pmove.physents[pmove.numphysent].forcecontentsmask = 0;
|
||||
if (other->v.skin < 0)
|
||||
switch((int)other->v.skin)
|
||||
{
|
||||
case CONTENTS_WATER: pmove.physents[pmove.numphysent].forcecontentsmask = CONTENTBIT_WATER; break;
|
||||
case CONTENTS_LAVA: pmove.physents[pmove.numphysent].forcecontentsmask = CONTENTBIT_LAVA; break;
|
||||
case CONTENTS_SLIME: pmove.physents[pmove.numphysent].forcecontentsmask = CONTENTBIT_SLIME; break;
|
||||
case CONTENTS_SKY: pmove.physents[pmove.numphysent].forcecontentsmask = CONTENTBIT_SKY; break;
|
||||
case CONTENTS_CLIP: pmove.physents[pmove.numphysent].forcecontentsmask = CONTENTBIT_CLIP; break;
|
||||
case CONTENTS_LADDER: pmove.physents[pmove.numphysent].forcecontentsmask = CONTENTBIT_LADDER; break;
|
||||
}
|
||||
|
||||
pmove.numphysent++;
|
||||
}
|
||||
|
||||
// recurse down both sides
|
||||
if (node->axis == -1)
|
||||
return;
|
||||
|
||||
if ( boxminmax[1][node->axis] > node->dist )
|
||||
World_AreaAddEntsToPmove ( ignore, node->children[0], boxminmax );
|
||||
if ( boxminmax[0][node->axis] < node->dist )
|
||||
World_AreaAddEntsToPmove ( ignore, node->children[1], boxminmax );
|
||||
}
|
||||
void World_AddEntsToPmove(edict_t *ignore, vec3_t boxminmax[2])
|
||||
{
|
||||
pmove.skipent = NUM_FOR_EDICT(ignore);
|
||||
pmove.physents[0].model = qcvm->worldmodel;
|
||||
pmove.numphysent = 1;
|
||||
World_AreaAddEntsToPmove (ignore, qcvm->areanodes, boxminmax);
|
||||
|
||||
//csqc needs to be able to clip against the server's ents, too
|
||||
if (qcvm == &cl.qcvm)
|
||||
{
|
||||
entity_t *touch;
|
||||
int i;
|
||||
|
||||
for (i=1,touch=cl.entities+1 ; i<cl.num_entities ; i++,touch++)
|
||||
{
|
||||
if (!touch->model)
|
||||
continue;
|
||||
if (touch->netstate.solidsize == ES_SOLID_NOT)
|
||||
continue; //not relevant
|
||||
|
||||
if (pmove.numphysent == countof(pmove.physents))
|
||||
return; //too many... ooer.
|
||||
|
||||
if (touch->netstate.solidsize == ES_SOLID_BSP)
|
||||
{
|
||||
if (!touch->model || touch->model->type != mod_brush)
|
||||
continue;
|
||||
VectorCopy(touch->model->mins, pmove.physents[pmove.numphysent].mins);
|
||||
VectorCopy(touch->model->maxs, pmove.physents[pmove.numphysent].maxs);
|
||||
pmove.physents[pmove.numphysent].model = touch->model;
|
||||
}
|
||||
else
|
||||
{
|
||||
float *touch_mins = pmove.physents[pmove.numphysent].mins;
|
||||
float *touch_maxs = pmove.physents[pmove.numphysent].maxs;
|
||||
touch_maxs[0] = touch_maxs[1] = touch->netstate.solidsize & 255;
|
||||
touch_mins[0] = touch_mins[1] = -touch_maxs[0];
|
||||
touch_mins[2] = -(int)((touch->netstate.solidsize >> 8) & 255);
|
||||
touch_maxs[2] = (int)((touch->netstate.solidsize>>16) & 65535) - 32768;
|
||||
pmove.physents[pmove.numphysent].model = NULL;
|
||||
}
|
||||
|
||||
pmove.physents[pmove.numphysent].info = -i; //kinda backwards, but oh well. the csqc won't know their numbers.
|
||||
VectorCopy(touch->origin, pmove.physents[pmove.numphysent].origin);
|
||||
VectorCopy(touch->angles, pmove.physents[pmove.numphysent].angles);
|
||||
|
||||
pmove.physents[pmove.numphysent].forcecontentsmask = 0;
|
||||
if (touch->skinnum < 0)
|
||||
switch(touch->skinnum)
|
||||
{
|
||||
case CONTENTS_WATER: pmove.physents[pmove.numphysent].forcecontentsmask = CONTENTBIT_WATER; break;
|
||||
case CONTENTS_LAVA: pmove.physents[pmove.numphysent].forcecontentsmask = CONTENTBIT_LAVA; break;
|
||||
case CONTENTS_SLIME: pmove.physents[pmove.numphysent].forcecontentsmask = CONTENTBIT_SLIME; break;
|
||||
case CONTENTS_SKY: pmove.physents[pmove.numphysent].forcecontentsmask = CONTENTBIT_SKY; break;
|
||||
case CONTENTS_CLIP: pmove.physents[pmove.numphysent].forcecontentsmask = CONTENTBIT_CLIP; break;
|
||||
case CONTENTS_LADDER: pmove.physents[pmove.numphysent].forcecontentsmask = CONTENTBIT_LADDER; break;
|
||||
}
|
||||
|
||||
pmove.numphysent++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
|
@ -1208,8 +1333,8 @@ static void World_ClipToNetwork ( moveclip_t *clip )
|
|||
|
||||
touch_maxs[0] = touch_maxs[1] = touch->netstate.solidsize & 255;
|
||||
touch_mins[0] = touch_mins[1] = -touch_maxs[0];
|
||||
touch_mins[2] = -((touch->netstate.solidsize >>8) & 255);
|
||||
touch_maxs[2] = ((touch->netstate.solidsize>>16) & 65535) - 32768;
|
||||
touch_mins[2] = -(int)((touch->netstate.solidsize >>8) & 255);
|
||||
touch_maxs[2] = (int)((touch->netstate.solidsize>>16) & 65535) - 32768;
|
||||
|
||||
VectorSubtract (touch_mins, clip->maxs, hullmins);
|
||||
VectorSubtract (touch_maxs, clip->mins, hullmaxs);
|
||||
|
|
|
@ -29,7 +29,7 @@ typedef struct
|
|||
float dist;
|
||||
} plane_t;
|
||||
|
||||
typedef struct
|
||||
typedef struct trace_s
|
||||
{
|
||||
qboolean allsolid; // if true, plane is not valid
|
||||
qboolean startsolid; // if true, the initial point was in a solid area
|
||||
|
@ -40,6 +40,7 @@ typedef struct
|
|||
edict_t *ent; // entity the surface is on
|
||||
|
||||
int contents; // spike -- the content type(s) that we found.
|
||||
int entnum; // pmove prefers numbers not pointers.
|
||||
} trace_t;
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue