31 Jul 2008

This commit is contained in:
g-cont 2008-07-31 00:00:00 +04:00 committed by Alibek Omarov
parent f4cee11c57
commit ad1f8e3181
63 changed files with 3941 additions and 4249 deletions

View File

@ -1,5 +1,5 @@
//=======================================================================
// Copyright XashXT Group 2007 ©
// Copyright XashXT Group 2008 ©
// rc_main.c - resource library
//=======================================================================

View File

@ -260,7 +260,7 @@ void ProcessModels (void)
EndBSPFile ();
}
static void AddCollision(void* handle, const void* buffer, size_t size)
static void AddCollision( void* handle, const void* buffer, size_t size )
{
Mem_Copy( dcollision + dcollisiondatasize, (void *)buffer, size );
dcollisiondatasize += size;

View File

@ -27,7 +27,7 @@ platform.dll needs for some setup operations
so do it manually
==================
*/
void InitPlatform ( uint funcname, int argc, char **argv )
void InitPlatform ( int argc, char **argv )
{
byte bspflags = 0, qccflags = 0, roqflags = 0;
char source[64], gamedir[64];
@ -38,13 +38,13 @@ void InitPlatform ( uint funcname, int argc, char **argv )
// for custom cmdline parsing
com_argc = argc;
com_argv = argv;
app_name = funcname;
app_name = g_Instance;
Sys_LoadLibrary( &imglib_dll ); // load imagelib
CreateImglib = (void *)imglib_dll.main;
Image = CreateImglib( &com, NULL ); // second interface not allowed
switch( funcname )
switch( app_name )
{
case COMP_BSPLIB:
if(!FS_GetParmFromCmdLine("-game", gamedir ))
@ -63,7 +63,7 @@ void InitPlatform ( uint funcname, int argc, char **argv )
CreateVprogs = (void *)vprogs_dll.main;
PRVM = CreateVprogs( &com, NULL ); // second interface not allowed
PRVM->Init( funcname, argc, argv );
PRVM->Init( argc, argv );
if(!FS_GetParmFromCmdLine("-dir", gamedir ))
com.strncpy(gamedir, ".", sizeof(gamedir));
@ -84,7 +84,7 @@ void InitPlatform ( uint funcname, int argc, char **argv )
break;
}
Image->Init( funcname ); // initialize image support
Image->Init(); // initialize image support
}
void RunPlatform ( void )

View File

@ -15,7 +15,7 @@
// platform export
//=====================================
void InitPlatform ( uint funcname, int argc, char **argv ); // init host
void InitPlatform ( int argc, char **argv ); // init host
void RunPlatform ( void ); // host frame
void ClosePlatform ( void ); // close host

View File

@ -90,7 +90,7 @@ void CL_WriteDemoHeader( const char *name )
{
ent = PRVM_EDICT_NUM( i );
state = &ent->priv.cl->baseline;
if(!state->modelindex) continue;
if(!state->model.index) continue;
if( buf.cursize + 64 > buf.maxsize )
{

View File

@ -59,14 +59,19 @@ struct cl_entvars_s
float modelindex;
float soundindex;
int chain;
int owner;
string_t model;
vec3_t origin;
vec3_t angles;
vec3_t mins;
vec3_t maxs;
float solid;
float sequence;
float effects;
float frame;
float body;
float skin;
float flags;
};
@ -74,9 +79,9 @@ struct cl_entvars_s
static fields_t cl_reqfields[] =
{
{17, 2, "flags"}
{26, 2, "aiflags"}
};
#define PROG_CRC_CLIENT 4546
#define PROG_CRC_CLIENT 3720
#endif//CL_EDICT_H

View File

@ -78,8 +78,8 @@ void CL_DeltaEntity( sizebuf_t *msg, frame_t *frame, int newnum, entity_state_t
frame->num_entities++;
// some data changes will force no lerping
if( state->modelindex != ent->priv.cl->current.modelindex || state->weaponmodel != ent->priv.cl->current.weaponmodel || state->body != ent->priv.cl->current.body
|| state->sequence != ent->priv.cl->current.sequence || abs(state->origin[0] - ent->priv.cl->current.origin[0]) > 512
if( state->model.index != ent->priv.cl->current.model.index || state->pmodel.index != ent->priv.cl->current.pmodel.index || state->model.body != ent->priv.cl->current.model.body
|| state->model.sequence != ent->priv.cl->current.model.sequence || abs(state->origin[0] - ent->priv.cl->current.origin[0]) > 512
|| abs(state->origin[1] - ent->priv.cl->current.origin[1]) > 512 || abs(state->origin[2] - ent->priv.cl->current.origin[2]) > 512 )
{
ent->priv.cl->serverframe = -99;
@ -335,27 +335,27 @@ void CL_AddPacketEntities( frame_t *frame )
effects = s1->effects;
renderfx = s1->renderfx;
refent.frame = s1->frame;
refent.frame = s1->model.frame;
// copy state to progs
ent->progs.cl->modelindex = ent->priv.cl->current.modelindex;
ent->progs.cl->modelindex = ent->priv.cl->current.model.index;
ent->progs.cl->soundindex = ent->priv.cl->current.soundindex;
//ent->progs.cl->model = PRVM_SetEngineString( cl.configstrings[CS_MODELS+ent->priv.cl->current.modelindex] );
//ent->progs.cl->model = PRVM_SetEngineString( cl.configstrings[CS_MODELS+ent->priv.cl->current.model.index] );
// copy state to render
refent.prev.frame = ent->priv.cl->prev.frame;
refent.prev.frame = ent->priv.cl->prev.model.frame;
refent.backlerp = 1.0 - cl.lerpfrac;
refent.alpha = s1->alpha;
refent.body = s1->body;
refent.sequence = s1->sequence;
refent.animtime = s1->animtime;
refent.alpha = s1->renderamt;
refent.body = s1->model.body;
refent.sequence = s1->model.sequence;
refent.animtime = s1->model.animtime;
// setup latchedvars
refent.prev.animtime = ent->priv.cl->prev.animtime;
refent.prev.animtime = ent->priv.cl->prev.model.animtime;
VectorCopy( ent->priv.cl->prev.origin, refent.prev.origin );
VectorCopy( ent->priv.cl->prev.angles, refent.prev.angles );
refent.prev.sequence = ent->priv.cl->prev.sequence;
refent.prev.frame = ent->priv.cl->prev.frame;
refent.prev.sequence = ent->priv.cl->prev.model.sequence;
refent.prev.frame = ent->priv.cl->prev.model.frame;
//refent.prev.sequencetime;
// interpolate origin
@ -366,10 +366,10 @@ void CL_AddPacketEntities( frame_t *frame )
}
// set skin
refent.skin = s1->skin;
refent.model = cl.model_draw[s1->modelindex];
refent.weaponmodel = cl.model_draw[s1->weaponmodel];
refent.flags = renderfx;
refent.skin = s1->model.skin;
refent.model = cl.model_draw[s1->model.index];
refent.weaponmodel = cl.model_draw[s1->pmodel.index];
refent.flags = renderfx;//FIXME: it's wrong!!!
// calculate angles
if( effects & EF_ROTATE )
@ -402,7 +402,7 @@ void CL_AddPacketEntities( frame_t *frame )
}
// if set to invisible, skip
if( !s1->modelindex ) continue;
if( !s1->model.index ) continue;
// add to refresh list
V_AddEntity( &refent );
@ -416,10 +416,9 @@ void CL_AddPacketEntities( frame_t *frame )
CL_AddViewWeapon
==============
*/
void CL_AddViewWeapon( player_state_t *ps, player_state_t *ops )
void CL_AddViewWeapon( entity_state_t *ps, entity_state_t *ops )
{
entity_t gun; // view model
int i;
// allow the gun to be completely removed
if( !cl_gun->value ) return;
@ -434,11 +433,8 @@ void CL_AddViewWeapon( player_state_t *ps, player_state_t *ops )
if (!gun.model) return;
// set up gun position
for( i = 0; i < 3; i++ )
{
gun.origin[i] = gun.oldorigin[i] = cl.refdef.vieworg[i] + ops->vmodel.offset[i] + (ps->vmodel.offset[i] - ops->vmodel.offset[i]) * cl.lerpfrac;
gun.angles[i] = cl.refdef.viewangles[i] + LerpAngle (ops->vmodel.angles[i], ps->vmodel.angles[i], cl.lerpfrac);
}
VectorCopy( cl.refdef.vieworg, gun.origin );
VectorCopy( cl.refdef.viewangles, gun.angles );
gun.frame = ps->vmodel.frame;
if( gun.frame == 0 ) gun.prev.frame = 0; // just changed weapons, don't lerp from old
@ -467,7 +463,7 @@ void CL_CalcViewValues( void )
int i;
float lerp, backlerp;
frame_t *oldframe;
player_state_t *ps, *ops;
entity_state_t *ps, *ops;
// clamp time
if( cl.time > cl.frame.servertime )
@ -540,7 +536,7 @@ void CL_CalcViewValues( void )
}
for( i = 0; i < 3; i++ )
cl.refdef.viewangles[i] += LerpAngle( ops->kick_angles[i], ps->kick_angles[i], lerp );
cl.refdef.viewangles[i] += LerpAngle( ops->punch_angles[i], ps->punch_angles[i], lerp );
AngleVectors( cl.refdef.viewangles, cl.v_forward, cl.v_right, cl.v_up );
@ -548,8 +544,7 @@ void CL_CalcViewValues( void )
cl.refdef.fov_x = ops->fov + lerp * ( ps->fov - ops->fov );
// don't interpolate blend color
for( i = 0; i < 4; i++ )
cl.refdef.blend[i] = ps->blend[i];
Vector4Set( cl.refdef.blend, 0, 0, 0, 0 ); // FIXME: calculate blend on client-side
// add the weapon
CL_AddViewWeapon( ps, ops );
@ -606,7 +601,7 @@ void CL_GetEntitySoundSpatialization( int entnum, vec3_t origin, vec3_t velocity
// if a brush model, offset the origin
if( VectorIsNull( origin ))
{
cmodel = cl.model_clip[ent->priv.cl->current.modelindex];
cmodel = cl.models[ent->priv.cl->current.model.index];
if(!cmodel) return;
VectorAverage( cmodel->mins, cmodel->maxs, midPoint );
VectorAdd( origin, midPoint, origin );

View File

@ -1119,12 +1119,6 @@ void Key_Event(int key, bool down, uint time)
// escape is always handled special
if ( key == K_ESCAPE && down )
{
if (cl.frame.ps.stats[STAT_LAYOUTS] && cls.key_dest == key_game)
{
// put away help computer / inventory
Cbuf_AddText ("cmd putaway\n");
return;
}
switch( cls.key_dest )
{
case key_message:

View File

@ -74,10 +74,6 @@ client_t cl;
entity_state_t cl_parse_entities[MAX_PARSE_ENTITIES];
extern cvar_t *allow_download;
extern cvar_t *allow_download_players;
extern cvar_t *allow_download_models;
extern cvar_t *allow_download_sounds;
extern cvar_t *allow_download_maps;
//======================================================================
//======================================================================
@ -900,83 +896,77 @@ void CL_RequestNextDownload (void)
{
// confirm map
precache_check = CS_MODELS+2; // 0 isn't used
if (allow_download_maps->value)
if (!CL_CheckOrDownloadFile(cl.configstrings[CS_MODELS+1]))
return; // started a download
if (!CL_CheckOrDownloadFile(cl.configstrings[CS_MODELS+1]))
return; // started a download
}
if (precache_check >= CS_MODELS && precache_check < CS_MODELS+MAX_MODELS)
{
if (allow_download_models->value)
while (precache_check < CS_MODELS+MAX_MODELS && cl.configstrings[precache_check][0])
{
while (precache_check < CS_MODELS+MAX_MODELS &&
cl.configstrings[precache_check][0]) {
if (cl.configstrings[precache_check][0] == '*' ||
cl.configstrings[precache_check][0] == '#') {
if (cl.configstrings[precache_check][0] == '*' || cl.configstrings[precache_check][0] == '#')
{
precache_check++;
continue;
}
if (precache_model_skin == 0)
{
if (!CL_CheckOrDownloadFile(cl.configstrings[precache_check])) {
precache_model_skin = 1;
return; // started a download
}
precache_model_skin = 1;
}
// checking for skins in the model
if (!precache_model)
{
precache_model = FS_LoadFile (cl.configstrings[precache_check], NULL);
if (!precache_model)
{
precache_model_skin = 0;
precache_check++;
continue; // couldn't load it
}
if (LittleLong(*(uint *)precache_model) != IDSTUDIOHEADER)
{
// not an studio model
precache_model = 0;
precache_model_skin = 0;
precache_check++;
continue;
}
if (precache_model_skin == 0) {
if (!CL_CheckOrDownloadFile(cl.configstrings[precache_check])) {
precache_model_skin = 1;
return; // started a download
}
precache_model_skin = 1;
}
// checking for skins in the model
if (!precache_model) {
precache_model = FS_LoadFile (cl.configstrings[precache_check], NULL);
if (!precache_model)
{
precache_model_skin = 0;
precache_check++;
continue; // couldn't load it
}
if (LittleLong(*(uint *)precache_model) != IDSTUDIOHEADER)
{
// not an studio model
precache_model = 0;
precache_model_skin = 0;
precache_check++;
continue;
}
pheader = (studiohdr_t *)precache_model;
if (LittleLong (pheader->version) != STUDIO_VERSION)
{
precache_check++;
precache_model_skin = 0;
continue; // couldn't load it
}
}
pheader = (studiohdr_t *)precache_model;
if (precache_model)
{
precache_model = 0;
if (LittleLong (pheader->version) != STUDIO_VERSION)
{
precache_check++;
precache_model_skin = 0;
continue; // couldn't load it
}
precache_model_skin = 0;
precache_check++;
}
pheader = (studiohdr_t *)precache_model;
if (precache_model)
{
precache_model = 0;
}
precache_model_skin = 0;
precache_check++;
}
precache_check = CS_SOUNDS;
}
if (precache_check >= CS_SOUNDS && precache_check < CS_SOUNDS+MAX_SOUNDS)
{
if (allow_download_sounds->value)
if (precache_check == CS_SOUNDS) precache_check++; // zero is blank
while (precache_check < CS_SOUNDS+MAX_SOUNDS && cl.configstrings[precache_check][0])
{
if (precache_check == CS_SOUNDS) precache_check++; // zero is blank
while (precache_check < CS_SOUNDS+MAX_SOUNDS && cl.configstrings[precache_check][0])
if (cl.configstrings[precache_check][0] == '*')
{
if (cl.configstrings[precache_check][0] == '*')
{
precache_check++;
continue;
}
com.sprintf(fn, "sound/%s", cl.configstrings[precache_check++]);
if (!CL_CheckOrDownloadFile(fn)) return; // started a download
precache_check++;
continue;
}
com.sprintf(fn, "sound/%s", cl.configstrings[precache_check++]);
if (!CL_CheckOrDownloadFile(fn)) return; // started a download
}
precache_check = CS_IMAGES;
}
@ -995,59 +985,55 @@ void CL_RequestNextDownload (void)
// so precache_check is now *3
if (precache_check >= CS_PLAYERSKINS && precache_check < CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT)
{
if (allow_download_players->value)
while (precache_check < CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT)
{
while (precache_check < CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT)
int i, n;
char model[MAX_QPATH], skin[MAX_QPATH], *p;
i = (precache_check - CS_PLAYERSKINS)/PLAYER_MULT;
n = (precache_check - CS_PLAYERSKINS)%PLAYER_MULT;
if (!cl.configstrings[CS_PLAYERSKINS+i][0])
{
int i, n;
char model[MAX_QPATH], skin[MAX_QPATH], *p;
precache_check = CS_PLAYERSKINS + (i + 1) * PLAYER_MULT;
continue;
}
i = (precache_check - CS_PLAYERSKINS)/PLAYER_MULT;
n = (precache_check - CS_PLAYERSKINS)%PLAYER_MULT;
if ((p = strchr(cl.configstrings[CS_PLAYERSKINS+i], '\\')) != NULL)
p++;
else p = cl.configstrings[CS_PLAYERSKINS+i];
strcpy(model, p);
p = strchr(model, '/');
if (!p) p = strchr(model, '\\');
if (p)
{
*p++ = 0;
strcpy(skin, p);
}
else *skin = 0;
if (!cl.configstrings[CS_PLAYERSKINS+i][0]) {
precache_check = CS_PLAYERSKINS + (i + 1) * PLAYER_MULT;
continue;
}
if ((p = strchr(cl.configstrings[CS_PLAYERSKINS+i], '\\')) != NULL)
p++;
else p = cl.configstrings[CS_PLAYERSKINS+i];
strcpy(model, p);
p = strchr(model, '/');
if (!p)
p = strchr(model, '\\');
if (p)
switch (n)
{
case 0: // model
com.sprintf(fn, "models/players/%s/player.mdl", model);
if (!CL_CheckOrDownloadFile(fn))
{
*p++ = 0;
strcpy(skin, p);
precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 1;
return; // started a download
}
else *skin = 0;
switch (n)
n++;
/*FALL THROUGH*/
case 1: // weapon model
com.sprintf(fn, "weapons/%s.mdl", model);
if (!CL_CheckOrDownloadFile(fn))
{
case 0: // model
com.sprintf(fn, "models/players/%s/player.mdl", model);
if (!CL_CheckOrDownloadFile(fn))
{
precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 1;
return; // started a download
}
n++;
/*FALL THROUGH*/
case 1: // weapon model
com.sprintf(fn, "weapons/%s.mdl", model);
if (!CL_CheckOrDownloadFile(fn))
{
precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 2;
return; // started a download
}
n++;
/*FALL THROUGH*/
default:
break;
precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 2;
return; // started a download
}
n++;
/*FALL THROUGH*/
default:
break;
}
}
// precache phase completed
@ -1058,7 +1044,7 @@ void CL_RequestNextDownload (void)
{
precache_check = ENV_CNT + 1;
pe->BeginRegistration( cl.configstrings[CS_MODELS+1], true, &map_checksum );
cl.worldmodel = pe->BeginRegistration( cl.configstrings[CS_MODELS+1], true, &map_checksum );
if( map_checksum != com.atoi(cl.configstrings[CS_MAPCHECKSUM]))
{
Host_Error("Local map version differs from server: %i != '%s'\n", map_checksum, cl.configstrings[CS_MAPCHECKSUM]);
@ -1068,7 +1054,7 @@ void CL_RequestNextDownload (void)
if (precache_check > ENV_CNT && precache_check < TEXTURE_CNT)
{
if (allow_download->value && allow_download_maps->value)
if( allow_download->value )
{
while (precache_check < TEXTURE_CNT)
{
@ -1091,7 +1077,7 @@ void CL_RequestNextDownload (void)
// confirm existance of textures, download any that don't exist
if (precache_check == TEXTURE_CNT+1)
{
if (allow_download->value && allow_download_maps->value)
if( allow_download->value )
{
while( precache_tex < pe->NumTextures())
{

View File

@ -466,10 +466,8 @@ void CL_ParseConfigString( sizebuf_t *msg )
{
if(cl.refresh_prepped)
{
cl.model_draw[i-CS_MODELS] = re->RegisterModel (cl.configstrings[i]);
if (cl.configstrings[i][0] == '*')
cl.model_clip[i-CS_MODELS] = pe->RegisterModel(cl.configstrings[i] );
else cl.model_clip[i-CS_MODELS] = NULL;
cl.model_draw[i-CS_MODELS] = re->RegisterModel( cl.configstrings[i] );
cl.models[i-CS_MODELS] = pe->RegisterModel( cl.configstrings[i] );
}
}
else if (i >= CS_SOUNDS && i < CS_SOUNDS+MAX_MODELS)

View File

@ -20,6 +20,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "common.h"
#include "client.h"
#include "matrixlib.h"
/*
===================
@ -60,6 +61,127 @@ void CL_CheckPredictionError (void)
}
}
/*
==================
CL_Trace
==================
*/
trace_t CL_Trace( const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, edict_t *passedict, int contentsmask )
{
vec3_t hullmins, hullmaxs;
int i, bodycontents;
int passedictprog;
bool pointtrace;
edict_t *traceowner, *touch;
trace_t trace;
vec3_t clipboxmins, clipboxmaxs; // bounding box of entire move area
vec3_t clipmins, clipmaxs; // size of the moving object
vec3_t clipmins2, clipmaxs2; // size when clipping against monsters
vec3_t clipstart, clipend; // start and end origin of move
trace_t cliptrace; // trace results
matrix4x4 matrix, imatrix; // matrices to transform into/out of other entity's space
cmodel_t *model; // model of other entity
int numtouchedicts = 0; // list of entities to test for collisions
edict_t *touchedicts[MAX_EDICTS];
VectorCopy( start, clipstart );
VectorCopy( end, clipend );
VectorCopy( mins, clipmins );
VectorCopy( maxs, clipmaxs );
VectorCopy( mins, clipmins2 );
VectorCopy( maxs, clipmaxs2 );
// clip to world
pe->ClipToWorld( &cliptrace, cl.worldmodel, clipstart, clipmins, clipmaxs, clipend, contentsmask );
cliptrace.startstuck = cliptrace.startsolid;
if( cliptrace.startsolid || cliptrace.fraction < 1 ) cliptrace.ent = prog ? prog->edicts : NULL;
if( type == MOVE_WORLDONLY ) return cliptrace;
if( type == MOVE_MISSILE )
{
for( i = 0; i < 3; i++ )
{
clipmins2[i] -= 15;
clipmaxs2[i] += 15;
}
}
// get adjusted box for bmodel collisions if the world is q1bsp or hlbsp
VectorCopy( clipmins, hullmins );
VectorCopy( clipmaxs, hullmaxs );
// create the bounding box of the entire move
for( i = 0; i < 3; i++ )
{
clipboxmins[i] = min(clipstart[i], cliptrace.endpos[i]) + min(hullmins[i], clipmins2[i]) - 1;
clipboxmaxs[i] = max(clipstart[i], cliptrace.endpos[i]) + max(hullmaxs[i], clipmaxs2[i]) + 1;
}
// if the passedict is world, make it NULL (to avoid two checks each time)
// this checks prog because this function is often called without a CSQC
// VM context
if( prog == NULL || passedict == prog->edicts ) passedict = NULL;
// precalculate prog value for passedict for comparisons
passedictprog = prog != NULL ? PRVM_EDICT_TO_PROG(passedict) : 0;
// figure out whether this is a point trace for comparisons
pointtrace = VectorCompare( clipmins, clipmaxs );
// precalculate passedict's owner edict pointer for comparisons
traceowner = passedict ? PRVM_PROG_TO_EDICT( passedict->progs.cl->owner ) : NULL;
// clip to entities
// because this uses World_EntitiestoBox, we know all entity boxes overlap
// the clip region, so we can skip culling checks in the loop below
// note: if prog is NULL then there won't be any linked entities
numtouchedicts = 0;//CL_AreaEdicts( clipboxmins, clipboxmaxs, touchedicts, host.max_edicts );
if( numtouchedicts > host.max_edicts )
{
// this never happens
MsgDev( D_WARN, "CL_AreaEdicts returned %i edicts, max was %i\n", numtouchedicts, host.max_edicts );
numtouchedicts = host.max_edicts;
}
for( i = 0; i < numtouchedicts; i++ )
{
touch = touchedicts[i];
if( touch->progs.cl->solid < SOLID_BBOX ) continue;
if( type == MOVE_NOMONSTERS && touch->progs.cl->solid != SOLID_BSP )
continue;
if( passedict )
{
// don't clip against self
if( passedict == touch ) continue;
// don't clip owned entities against owner
if( traceowner == touch ) continue;
// don't clip owner against owned entities
if( passedictprog == touch->progs.cl->owner ) continue;
// don't clip points against points (they can't collide)
if( pointtrace && VectorCompare( touch->progs.cl->mins, touch->progs.cl->maxs) && (type != MOVE_MISSILE || !((int)touch->progs.cl->flags & FL_MONSTER)))
continue;
}
bodycontents = CONTENTS_BODY;
// might interact, so do an exact clip
model = NULL;
if((int)touch->progs.cl->solid == SOLID_BSP || type == MOVE_HITMODEL )
{
uint modelindex = (uint)touch->progs.cl->modelindex;
// if the modelindex is 0, it shouldn't be SOLID_BSP!
if( modelindex > 0 && modelindex < MAX_MODELS )
model = cl.models[(int)touch->progs.cl->modelindex];
}
if( model ) Matrix4x4_CreateFromEntity( matrix, touch->progs.cl->origin[0], touch->progs.cl->origin[1], touch->progs.cl->origin[2], touch->progs.cl->angles[0], touch->progs.cl->angles[1], touch->progs.cl->angles[2], 1 );
else Matrix4x4_CreateTranslate( matrix, touch->progs.cl->origin[0], touch->progs.cl->origin[1], touch->progs.cl->origin[2] );
Matrix4x4_Invert_Simple( imatrix, matrix );
if((int)touch->progs.cl->flags & FL_MONSTER)
pe->ClipToGenericEntity(&trace, model, touch->progs.cl->mins, touch->progs.cl->maxs, bodycontents, matrix, imatrix, clipstart, clipmins2, clipmaxs2, clipend, contentsmask );
else pe->ClipToGenericEntity(&trace, model, touch->progs.cl->mins, touch->progs.cl->maxs, bodycontents, matrix, imatrix, clipstart, clipmins, clipmaxs, clipend, contentsmask );
pe->CombineTraces(&cliptrace, &trace, touch, touch->progs.cl->solid == SOLID_BSP );
}
return cliptrace;
}
/*
====================
@ -69,57 +191,36 @@ CL_ClipMoveToEntities
*/
void CL_ClipMoveToEntities ( vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, trace_t *tr )
{
int i, x, zd, zu;
trace_t trace;
float *angles;
entity_state_t *ent;
int num;
cmodel_t *cmodel;
vec3_t bmins, bmaxs;
/*
for( i = 0; i < cl.frame.num_entities; i++ )
{
num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
ent = &cl_parse_entities[num];
for( i = 0; i < cl.frame.num_entities; i++ )
{
num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
ent = &cl_parse_entities[num];
if(!ent->solid) continue;
if(ent->number == cl.playernum + 1) continue;
if(!ent->solid) continue;
if(ent->number == cl.playernum + 1) continue;
if( ent->solid == SOLID_BMODEL )
{
// special value for bmodel
cmodel = cl.model_clip[ent->modelindex];
if(!cmodel) continue;
angles = ent->angles;
}
else
{ // encoded bbox
x = (ent->solid & 255);
zd = ((ent->solid>>8) & 255);
zu = ((ent->solid>>16) & 255) - 32;
bmins[0] = bmins[1] = -x;
bmaxs[0] = bmaxs[1] = x;
bmins[2] = -zd;
bmaxs[2] = zu;
angles = ent->angles;
}
if( tr->allsolid ) return;
trace = pe->TransformedBoxTrace( start, end, mins, maxs, cmodel, MASK_PLAYERSOLID, ent->origin, angles, false );
if( trace.allsolid || trace.startsolid || trace.fraction < tr->fraction )
{
trace.ent = (edict_t *)ent;
if (tr->startsolid)
{
*tr = trace;
tr->startsolid = true;
}
else *tr = trace;
}
else if (trace.startsolid) tr->startsolid = true;
if( ent->solid == SOLID_BMODEL )
{
// special value for bmodel
cmodel = cl.model_clip[ent->modelindex];
if(!cmodel) continue;
angles = ent->angles;
}
else
{ // encoded bbox
x = (ent->solid & 255);
zd = ((ent->solid>>8) & 255);
zu = ((ent->solid>>16) & 255) - 32;
bmins[0] = bmins[1] = -x;
bmaxs[0] = bmaxs[1] = x;
bmins[2] = -zd;
bmaxs[2] = zu;
angles = ent->angles;
}
}
*/
}
@ -130,38 +231,15 @@ CL_PMTrace
*/
void CL_PMTrace( vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, trace_t *tr )
{
// check against world
pe->BoxTrace( start, end, mins, maxs, NULL, tr, MASK_PLAYERSOLID );
if( tr->fraction < 1.0 ) tr->ent = (edict_t *)1; //FIXME: get client entity = world
// check all other solid models
CL_ClipMoveToEntities( start, mins, maxs, end, tr );
*tr = CL_Trace( start, mins, maxs, end, MOVE_NORMAL, NULL, MASK_PLAYERSOLID );
}
int CL_PMpointcontents( vec3_t point )
{
int i;
entity_state_t *ent;
int num;
cmodel_t *cmodel;
int contents;
contents = pe->PointContents( point, NULL );
for( i = 0; i < cl.frame.num_entities; i++ )
{
num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
ent = &cl_parse_entities[num];
if (ent->solid != SOLID_BMODEL) // special value for bmodel
continue;
cmodel = cl.model_clip[ent->modelindex];
if (!cmodel) continue;
contents |= pe->TransformedPointContents( point, cmodel, ent->origin, ent->angles );
}
return contents;
// get world supercontents at this point
if( cl.worldmodel && cl.worldmodel->PointContents )
return cl.worldmodel->PointContents( point, cl.worldmodel );
return 0;
}

View File

@ -55,7 +55,7 @@ void CL_DrawHUD( void )
CL_VM_Begin();
// setup pparms
prog->globals.cl->health = cl.frame.ps.stats[STAT_HEALTH];
prog->globals.cl->health = cl.frame.ps.health;
prog->globals.cl->maxclients = com.atoi(cl.configstrings[CS_MAXCLIENTS]);
prog->globals.cl->realtime = cls.realtime * 0.001f;
prog->globals.cl->paused = cl_paused->integer;
@ -70,7 +70,7 @@ bool CL_ParseUserMessage( int svc_number )
bool msg_parsed = false;
// setup pparms
prog->globals.cl->health = cl.frame.ps.stats[STAT_HEALTH];
prog->globals.cl->health = cl.frame.ps.health;
prog->globals.cl->maxclients = com.atoi(cl.configstrings[CS_MAXCLIENTS]);
prog->globals.cl->realtime = cls.realtime * 0.001f;
prog->globals.cl->paused = cl_paused->integer;

View File

@ -312,8 +312,7 @@ void CL_PrepRefresh( void )
Sys_SendKeyEvents(); // pump message loop
cl.model_draw[i] = re->RegisterModel( name );
if (name[0] == '*') cl.model_clip[i] = pe->RegisterModel( name );
else cl.model_clip[i] = NULL;//get studio models here?
cl.models[i] = pe->RegisterModel( name );
Cvar_SetValue("scr_loading", scr_loading->value + 50.0f/mdlcount );
SCR_UpdateScreen();
}

View File

@ -40,7 +40,7 @@ typedef struct frame_s
byte areabits[MAX_MAP_AREAS/8]; // portalarea visibility bits
int num_entities;
int parse_entities; // non-masked index into cl_parse_entities array
player_state_t ps;
entity_state_t ps;
} frame_t;
// console stuff
@ -140,7 +140,8 @@ typedef struct
// locally derived information from server state
//
model_t *model_draw[MAX_MODELS];
cmodel_t *model_clip[MAX_MODELS];
cmodel_t *models[MAX_MODELS];
cmodel_t *worldmodel;
sound_t sound_precache[MAX_SOUNDS];
image_t *image_precache[MAX_IMAGES];

View File

@ -83,6 +83,18 @@ void VM_ValidateString( const char *s )
if( s[0] <= ' ' ) PRVM_ERROR( "%s: bad string\n", PRVM_NAME );
}
void VM_SetTraceGlobals( const trace_t *trace )
{
prog->globals.sv->trace_allsolid = trace->allsolid;
prog->globals.sv->trace_startsolid = trace->startsolid;
prog->globals.sv->trace_fraction = trace->fraction;
prog->globals.sv->trace_contents = trace->contents;
VectorCopy (trace->endpos, prog->globals.sv->trace_endpos);
VectorCopy (trace->plane.normal, prog->globals.sv->trace_plane_normal);
prog->globals.sv->trace_plane_dist = trace->plane.dist;
if( trace->ent ) prog->globals.sv->trace_ent = PRVM_EDICT_TO_PROG( trace->ent );
else prog->globals.sv->trace_ent = PRVM_EDICT_TO_PROG( prog->edicts ); // world
}
/*
=========

View File

@ -193,7 +193,7 @@ typedef struct host_parm_s
extern host_parm_t host;
long Host_WndProc( void *hWnd, uint uMsg, uint wParam, long lParam );
void Host_Init ( uint funcname, int argc, char **argv );
void Host_Init ( int argc, char **argv );
void Host_Main ( void );
void Host_Free ( void );
void Host_SetServerState( int state );
@ -220,6 +220,16 @@ CLIENT / SERVER SYSTEMS
==============================================================
*/
#define FL_CLIENT (1<<0) // this is client
#define FL_MONSTER (1<<1) // this is npc
#define FL_DEADMONSTER (1<<2) // dead npc or dead player
#define FL_WORLDBRUSH (1<<3) // Not moveable/removeable brush entity
#define FL_DORMANT (1<<4) // Entity is dormant, no updates to client
#define FL_FRAMETHINK (1<<5) // entity will be thinking every frame
#define FL_GRAPHED (1<<6) // worldgraph has this ent listed as something that blocks a conection
#define FL_FLOAT (1<<7) // this entity can be floating. FIXME: remove this ?
#define FL_TRACKTRAIN (1<<8) // old stuff...
void CL_Init( void );
void CL_Shutdown( void );
void CL_Frame( dword time );
@ -261,6 +271,8 @@ _inline edict_t *_PRVM_EDICT_NUM( int n, const char * file, const int line )
#define PRVM_PUSH_GLOBALS prog->pev_save = prog->globals.sv->pev, prog->other_save = prog->globals.sv->other
#define PRVM_POP_GLOBALS prog->globals.sv->pev = prog->pev_save, prog->globals.sv->other = prog->other_save
#define PRVM_E_FLOAT(e,o) (((float*)e->progs.vp)[o])
#define PRVM_E_INT(e,o) (((int*)e->progs.vp)[o])
#define PRVM_G_FLOAT(o) (prog->globals.gp[o])
#define PRVM_G_INT(o) (*(int *)&prog->globals.gp[o])
#define PRVM_G_EDICT(o) (PRVM_PROG_TO_EDICT(*(int *)&prog->globals.gp[o]))
@ -274,6 +286,7 @@ _inline edict_t *_PRVM_EDICT_NUM( int n, const char * file, const int line )
// helper common functions
const char *VM_VarArgs( int start_arg );
bool VM_ValidateArgs( const char *builtin, int num_argc );
void VM_SetTraceGlobals( const trace_t *trace );
void VM_ValidateString( const char *s );
void VM_Cmd_Init( void );
void VM_Cmd_Reset( void );
@ -392,6 +405,15 @@ MISC COMMON FUNCTIONS
#define MAX_INFO_VALUE 64
#define MAX_INFO_STRING 512
enum e_trace
{
MOVE_NORMAL = 0,
MOVE_NOMONSTERS,
MOVE_MISSILE,
MOVE_WORLDONLY,
MOVE_HITMODEL,
};
// client printf level
enum e_clprint
{

View File

@ -494,7 +494,7 @@ void _MSG_WriteDeltaEntity( entity_state_t *from, entity_state_t *to, sizebuf_t
{
// NOTE: entity must have changes from one at first of 32 fields
// otherwise it will ignore updates
if( flags == 0 && force == 0 )
if( flags == 0 && force == 0 && i < 32 )
{
msg->cursize -= sizeof(word); // kill header
return;
@ -559,7 +559,7 @@ void MSG_ReadDeltaEntity( sizebuf_t *msg, entity_state_t *from, entity_state_t *
/*
============================================================================
player_state_t communication
player state communication
============================================================================
*/
@ -569,10 +569,10 @@ MSG_WriteDeltaPlayerstate
=============
*/
void MSG_WriteDeltaPlayerstate( player_state_t *from, player_state_t *to, sizebuf_t *msg )
void MSG_WriteDeltaPlayerstate( entity_state_t *from, entity_state_t *to, sizebuf_t *msg )
{
player_state_t dummy;
player_state_t *ops, *ps = to;
entity_state_t dummy;
entity_state_t *ops, *ps = to;
net_field_t *field, *field2;
int *fromF, *toF;
int i, j, k;
@ -588,12 +588,12 @@ void MSG_WriteDeltaPlayerstate( player_state_t *from, player_state_t *to, sizebu
MSG_WriteByte( msg, svc_playerinfo );
for( i = j = 0, field = field2 = ps_fields; field->name; i++, j++, field++ )
for( i = j = 0, field = field2 = ent_fields; field->name; i++, j++, field++ )
{
fromF = (int *)((byte *)ops + field->offset );
toF = (int *)((byte *)ps + field->offset );
if(*fromF != *toF || field->force) flags |= 1<<j;
if( j > 31 || !ps_fields[i+1].name) // dump packet
if( j > 31 || !ent_fields[i+1].name) // dump packet
{
MSG_WriteLong( msg, flags ); // send flags who indicates changes
for( k = 0; field2->name; k++, field2++ )
@ -605,15 +605,6 @@ void MSG_WriteDeltaPlayerstate( player_state_t *from, player_state_t *to, sizebu
j = flags = 0;
}
}
// send stats
for( i = 0, flags = 0; i < MAX_STATS; i++ )
if( ps->stats[i] != ops->stats[i] )
flags |= 1<<i;
MSG_WriteLong( msg, flags );
for( i = 0; i < MAX_STATS; i++ )
if(flags & (1<<i)) MSG_WriteShort( msg, ps->stats[i]);
}
@ -622,11 +613,11 @@ void MSG_WriteDeltaPlayerstate( player_state_t *from, player_state_t *to, sizebu
MSG_ReadDeltaPlayerstate
===================
*/
void MSG_ReadDeltaPlayerstate( sizebuf_t *msg, player_state_t *from, player_state_t *to )
void MSG_ReadDeltaPlayerstate( sizebuf_t *msg, entity_state_t *from, entity_state_t *to )
{
net_field_t *field;
int *fromF, *toF;
player_state_t dummy;
entity_state_t dummy;
uint i, flags;
// clear to old value before delta parsing
@ -637,7 +628,7 @@ void MSG_ReadDeltaPlayerstate( sizebuf_t *msg, player_state_t *from, player_stat
}
*to = *from;
for( i = 0, field = ps_fields; field->name; i++, field++ )
for( i = 0, field = ent_fields; field->name; i++, field++ )
{
// get flags of next packet if LONG out of range
if((i & 31) == 0) flags = MSG_ReadLong( msg );
@ -647,11 +638,4 @@ void MSG_ReadDeltaPlayerstate( sizebuf_t *msg, player_state_t *from, player_stat
if(flags & (1<<i)) *toF = MSG_ReadBits( msg, field->bits );
else *toF = *fromF; // no change
}
// parse stats
for( i = 0; i < MAX_STATS; i++ )
{
if((i & 31) == 0) flags = MSG_ReadLong( msg );
if(flags & (1<<i)) to->stats[i] = MSG_ReadShort( msg );
}
}

View File

@ -121,7 +121,6 @@ static const net_desc_t NWDesc[] =
#define MAX_GENERAL (MAX_CLIENTS * 2) // general config strings
#define ES_FIELD(x) #x,(int)&((entity_state_t*)0)->x
#define PS_FIELD(x) #x,(int)&((player_state_t*)0)->x
#define CM_FIELD(x) #x,(int)&((usercmd_t*)0)->x
// config strings are a general means of communication from
@ -156,84 +155,107 @@ static const net_desc_t NWDesc[] =
static net_field_t ent_fields[] =
{
{ ES_FIELD(origin[0]), NET_FLOAT, false },
{ ES_FIELD(origin[1]), NET_FLOAT, false },
{ ES_FIELD(origin[2]), NET_FLOAT, false },
{ ES_FIELD(angles[0]), NET_FLOAT, false },
{ ES_FIELD(angles[1]), NET_FLOAT, false },
{ ES_FIELD(angles[2]), NET_FLOAT, false },
{ ES_FIELD(old_origin[0]), NET_FLOAT, true },
{ ES_FIELD(old_origin[1]), NET_FLOAT, true },
{ ES_FIELD(old_origin[2]), NET_FLOAT, true },
{ ES_FIELD(modelindex), NET_WORD, false }, // 4096 models
{ ES_FIELD(soundindex), NET_WORD, false }, // 512 sounds ( OpenAL software limit is 255 )
{ ES_FIELD(weaponmodel), NET_WORD, false }, // 4096 models
{ ES_FIELD(skin), NET_BYTE, false }, // 255 skins
{ ES_FIELD(frame), NET_FLOAT, false }, // interpolate value
{ ES_FIELD(body), NET_BYTE, false }, // 255 bodies
{ ES_FIELD(sequence), NET_WORD, false }, // 1024 sequences
{ ES_FIELD(effects), NET_LONG, false }, // effect flags
{ ES_FIELD(renderfx), NET_LONG, false }, // renderfx flags
{ ES_FIELD(solid), NET_LONG, false }, // encoded mins/maxs
{ ES_FIELD(alpha), NET_FLOAT, false }, // alpha value (FIXME: send a byte ? )
{ ES_FIELD(animtime), NET_FLOAT, false }, // auto-animating time
{ NULL }, // terminator
};
static net_field_t ps_fields[] =
{
{ PS_FIELD(pm_type), NET_BYTE, false }, // 16 player movetypes allowed
{ PS_FIELD(pm_flags), NET_WORD, true }, // 16 movetype flags allowed
{ PS_FIELD(pm_time), NET_BYTE, true }, // each unit 8 msec
#ifdef USE_COORD_FRAC
{ PS_FIELD(origin[0]), NET_COORD, false },
{ PS_FIELD(origin[1]), NET_COORD, false },
{ PS_FIELD(origin[2]), NET_COORD, false },
{ PS_FIELD(velocity[0]), NET_COORD, false },
{ PS_FIELD(velocity[1]), NET_COORD, false },
{ PS_FIELD(velocity[2]), NET_COORD, false },
#else
{ PS_FIELD(origin[0]), NET_FLOAT, false },
{ PS_FIELD(origin[1]), NET_FLOAT, false },
{ PS_FIELD(origin[2]), NET_FLOAT, false },
{ PS_FIELD(velocity[0]), NET_FLOAT, false },
{ PS_FIELD(velocity[1]), NET_FLOAT, false },
{ PS_FIELD(velocity[2]), NET_FLOAT, false },
#endif
{ PS_FIELD(delta_angles[0]), NET_FLOAT, false },
{ PS_FIELD(delta_angles[1]), NET_FLOAT, false },
{ PS_FIELD(delta_angles[2]), NET_FLOAT, false },
{ PS_FIELD(gravity), NET_SHORT, false }, // may be 12 bits ?
{ PS_FIELD(effects), NET_LONG, false }, // copied to entity_state_t->effects
{ PS_FIELD(viewangles[0]), NET_FLOAT, false }, // for fixed views
{ PS_FIELD(viewangles[1]), NET_FLOAT, false },
{ PS_FIELD(viewangles[2]), NET_FLOAT, false },
{ PS_FIELD(viewoffset[0]), NET_SCALE, false }, // get rid of this
{ PS_FIELD(viewoffset[1]), NET_SCALE, false },
{ PS_FIELD(viewoffset[2]), NET_SCALE, false },
{ PS_FIELD(kick_angles[0]), NET_SCALE, false },
{ PS_FIELD(kick_angles[1]), NET_SCALE, false },
{ PS_FIELD(kick_angles[2]), NET_SCALE, false },
{ PS_FIELD(blend[0]), NET_COLOR, false }, // FIXME: calc on client, don't send over the net
{ PS_FIELD(blend[1]), NET_COLOR, false },
{ PS_FIELD(blend[2]), NET_COLOR, false },
{ PS_FIELD(blend[3]), NET_COLOR, false },
{ PS_FIELD(fov), NET_FLOAT, false }, // FIXME: send as byte * 4 ?
{ PS_FIELD(vmodel.index), NET_WORD, false }, // 4096 models
{ PS_FIELD(vmodel.angles[0]), NET_SCALE, false }, // can be some different with viewangles
{ PS_FIELD(vmodel.angles[1]), NET_SCALE, false },
{ PS_FIELD(vmodel.angles[2]), NET_SCALE, false },
{ PS_FIELD(vmodel.offset[0]), NET_SCALE, false }, // center offset
{ PS_FIELD(vmodel.offset[1]), NET_SCALE, false },
{ PS_FIELD(vmodel.offset[2]), NET_SCALE, false },
{ PS_FIELD(vmodel.sequence), NET_WORD, false }, // 1024 sequences
{ PS_FIELD(vmodel.frame), NET_FLOAT, false }, // interpolate value
{ PS_FIELD(vmodel.body), NET_BYTE, false }, // 255 bodies
{ PS_FIELD(vmodel.skin), NET_BYTE, false }, // 255 skins
{ PS_FIELD(pmodel.index), NET_WORD, false }, // 4096 models
{ PS_FIELD(pmodel.sequence), NET_WORD, false }, // 1024 sequences
{ PS_FIELD(vmodel.frame), NET_FLOAT, false }, // interpolate value
{ NULL }, // terminator
{ ES_FIELD(ed_type), NET_BYTE, true },
{ ES_FIELD(soundindex), NET_WORD, false }, // 512 sounds ( OpenAL software limit is 255 )
{ ES_FIELD(origin[0]), NET_FLOAT, false },
{ ES_FIELD(origin[1]), NET_FLOAT, false },
{ ES_FIELD(origin[2]), NET_FLOAT, false },
{ ES_FIELD(angles[0]), NET_FLOAT, false },
{ ES_FIELD(angles[1]), NET_FLOAT, false },
{ ES_FIELD(angles[2]), NET_FLOAT, false },
{ ES_FIELD(velocity[0]), NET_FLOAT, false },
{ ES_FIELD(velocity[1]), NET_FLOAT, false },
{ ES_FIELD(velocity[2]), NET_FLOAT, false },
{ ES_FIELD(old_origin[0]), NET_FLOAT, true }, // send always
{ ES_FIELD(old_origin[1]), NET_FLOAT, true },
{ ES_FIELD(old_origin[2]), NET_FLOAT, true },
{ ES_FIELD(old_velocity[0]), NET_FLOAT, true }, // client velocity
{ ES_FIELD(old_velocity[1]), NET_FLOAT, true },
{ ES_FIELD(old_velocity[2]), NET_FLOAT, true },
{ ES_FIELD(model.index), NET_WORD, false }, // 4096 models
{ ES_FIELD(model.colormap), NET_WORD, false }, // encoded as two shorts for top and bottom color
{ ES_FIELD(model.scale), NET_COLOR, false }, // 0-255 values
{ ES_FIELD(model.frame), NET_FLOAT, false }, // interpolate value
{ ES_FIELD(model.animtime), NET_FLOAT, false }, // auto-animating time
{ ES_FIELD(model.framerate), NET_FLOAT, false }, // custom framerate
{ ES_FIELD(model.sequence), NET_WORD, false }, // 1024 sequences
{ ES_FIELD(model.gaitsequence), NET_WORD, false }, // 1024 gaitsequences
{ ES_FIELD(model.skin), NET_BYTE, false }, // 255 skins
{ ES_FIELD(model.body), NET_BYTE, false }, // 255 bodies
{ ES_FIELD(model.blending[0]), NET_COLOR, false }, // animation blending
{ ES_FIELD(model.blending[1]), NET_COLOR, false },
{ ES_FIELD(model.blending[2]), NET_COLOR, false },
{ ES_FIELD(model.blending[3]), NET_COLOR, false },
{ ES_FIELD(model.blending[4]), NET_COLOR, false }, // send flags (first 4 bytes)
{ ES_FIELD(model.blending[5]), NET_COLOR, false },
{ ES_FIELD(model.blending[6]), NET_COLOR, false },
{ ES_FIELD(model.blending[7]), NET_COLOR, false },
{ ES_FIELD(model.blending[8]), NET_COLOR, false },
{ ES_FIELD(model.controller[0]), NET_COLOR, false }, // bone controllers #
{ ES_FIELD(model.controller[1]), NET_COLOR, false },
{ ES_FIELD(model.controller[2]), NET_COLOR, false },
{ ES_FIELD(model.controller[3]), NET_COLOR, false },
{ ES_FIELD(model.controller[4]), NET_COLOR, false },
{ ES_FIELD(model.controller[5]), NET_COLOR, false },
{ ES_FIELD(model.controller[6]), NET_COLOR, false },
{ ES_FIELD(model.controller[7]), NET_COLOR, false },
{ ES_FIELD(model.controller[8]), NET_COLOR, false },
{ ES_FIELD(model.controller[9]), NET_COLOR, false },
{ ES_FIELD(model.controller[10]), NET_COLOR, false },
{ ES_FIELD(model.controller[11]), NET_COLOR, false },
{ ES_FIELD(model.controller[12]), NET_COLOR, false },
{ ES_FIELD(model.controller[13]), NET_COLOR, false },
{ ES_FIELD(model.controller[14]), NET_COLOR, false },
{ ES_FIELD(model.controller[15]), NET_COLOR, false },
{ ES_FIELD(model.controller[16]), NET_COLOR, false }, // FIXME: sending as array
{ ES_FIELD(solidtype), NET_BYTE, false },
{ ES_FIELD(movetype), NET_BYTE, false }, // send flags (second 4 bytes)
{ ES_FIELD(gravity), NET_SHORT, false }, // gravity multiplier
{ ES_FIELD(aiment), NET_WORD, false }, // entity index
{ ES_FIELD(solid), NET_LONG, false }, // encoded mins/maxs
{ ES_FIELD(mins[0]), NET_FLOAT, false },
{ ES_FIELD(mins[1]), NET_FLOAT, false },
{ ES_FIELD(mins[2]), NET_FLOAT, false },
{ ES_FIELD(maxs[0]), NET_FLOAT, false },
{ ES_FIELD(maxs[1]), NET_FLOAT, false },
{ ES_FIELD(maxs[2]), NET_FLOAT, false },
{ ES_FIELD(effects), NET_LONG, false }, // effect flags
{ ES_FIELD(renderfx), NET_LONG, false }, // renderfx flags
{ ES_FIELD(renderamt), NET_COLOR, false }, // alpha amount
{ ES_FIELD(rendercolor[0]), NET_COLOR, false }, // animation blending
{ ES_FIELD(rendercolor[1]), NET_COLOR, false },
{ ES_FIELD(rendercolor[2]), NET_COLOR, false },
{ ES_FIELD(rendermode), NET_BYTE, false }, // render mode (legacy stuff)
{ ES_FIELD(pm_type), NET_BYTE, false }, // 16 player movetypes allowed
{ ES_FIELD(pm_flags), NET_WORD, true }, // 16 movetype flags allowed
{ ES_FIELD(pm_time), NET_BYTE, true }, // each unit 8 msec
{ ES_FIELD(delta_angles[0]), NET_FLOAT, false },
{ ES_FIELD(delta_angles[1]), NET_FLOAT, false },
{ ES_FIELD(delta_angles[2]), NET_FLOAT, false },
{ ES_FIELD(punch_angles[0]), NET_SCALE, false },
{ ES_FIELD(punch_angles[1]), NET_SCALE, false },
{ ES_FIELD(punch_angles[2]), NET_SCALE, false },
{ ES_FIELD(viewangles[0]), NET_FLOAT, false }, // for fixed views
{ ES_FIELD(viewangles[1]), NET_FLOAT, false },
{ ES_FIELD(viewangles[2]), NET_FLOAT, false },
// FIXME: replace with viewoffset
//{ ES_FIELD(viewheight), NET_SHORT, false }, // client viewheight
{ ES_FIELD(viewoffset[0]), NET_SCALE, false }, // get rid of this
{ ES_FIELD(viewoffset[1]), NET_SCALE, false },
{ ES_FIELD(viewoffset[2]), NET_SCALE, false },
{ ES_FIELD(maxspeed), NET_WORD, false }, // send flags (third 4 bytes )
{ ES_FIELD(fov), NET_FLOAT, false }, // client horizontal field of view
{ ES_FIELD(vmodel.index), NET_WORD, false }, // 4096 models
{ ES_FIELD(vmodel.colormap), NET_LONG, false }, // 4096 models
{ ES_FIELD(vmodel.sequence), NET_WORD, false }, // 1024 sequences
{ ES_FIELD(vmodel.frame), NET_FLOAT, false }, // interpolate value
{ ES_FIELD(vmodel.body), NET_BYTE, false }, // 255 bodies
{ ES_FIELD(vmodel.skin), NET_BYTE, false }, // 255 skins
{ ES_FIELD(pmodel.index), NET_WORD, false }, // 4096 models
{ ES_FIELD(pmodel.colormap), NET_LONG, false }, // 4096 models
{ ES_FIELD(pmodel.sequence), NET_WORD, false }, // 1024 sequences
{ ES_FIELD(vmodel.frame), NET_FLOAT, false }, // interpolate value
{ NULL }, // terminator
};
// probably usercmd_t never reached 32 field integer limit (in theory of course)
@ -307,8 +329,8 @@ void MSG_ReadPos( sizebuf_t *sb, vec3_t pos );
void MSG_ReadData( sizebuf_t *sb, void *buffer, size_t size );
void MSG_ReadDeltaUsercmd( sizebuf_t *sb, usercmd_t *from, usercmd_t *cmd );
void MSG_ReadDeltaEntity( sizebuf_t *sb, entity_state_t *from, entity_state_t *to, int number );
void MSG_WriteDeltaPlayerstate( player_state_t *from, player_state_t *to, sizebuf_t *msg );
void MSG_ReadDeltaPlayerstate( sizebuf_t *msg, player_state_t *from, player_state_t *to );
void MSG_WriteDeltaPlayerstate( entity_state_t *from, entity_state_t *to, sizebuf_t *msg );
void MSG_ReadDeltaPlayerstate( sizebuf_t *msg, entity_state_t *from, entity_state_t *to );
// huffman compression
void Huff_Init( void );

View File

@ -226,6 +226,10 @@ SOURCE=.\server\sv_main.c
# End Source File
# Begin Source File
SOURCE=.\server\sv_move.c
# End Source File
# Begin Source File
SOURCE=.\server\sv_phys.c
# End Source File
# Begin Source File
@ -238,10 +242,6 @@ SOURCE=.\server\sv_spawn.c
# End Source File
# Begin Source File
SOURCE=.\server\sv_studio.c
# End Source File
# Begin Source File
SOURCE=.\server\sv_world.c
# End Source File
# End Group

View File

@ -156,7 +156,7 @@ void Host_InitVprogs( int argc, char **argv )
CreateVprogs = (void *)vprogs_dll.main;
vm = CreateVprogs( &newcom, NULL ); // second interface not allowed
vm->Init( host.type, argc, argv );
vm->Init( argc, argv );
}
void Host_FreeVprogs( void )
@ -700,7 +700,7 @@ static void Host_Crash_f (void)
*(int *)0 = 0xffffffff;
}
void Host_InitCommon( uint funcname, int argc, char **argv )
void Host_InitCommon( int argc, char **argv )
{
char dev_level[4];
@ -733,16 +733,16 @@ void Host_FreeCommon( void )
Host_Init
=================
*/
void Host_Init (uint funcname, int argc, char **argv)
void Host_Init( int argc, char **argv)
{
char *s;
host.state = HOST_INIT; // initialzation started
host.type = funcname;
host.type = g_Instance;
srand(time(NULL)); // init random generator
Host_InitCommon( funcname, argc, argv ); // loading common.dll
Host_InitCommon( argc, argv ); // loading common.dll
Key_Init();
// get default configuration
@ -779,7 +779,7 @@ void Host_Init (uint funcname, int argc, char **argv)
Host_InitVprogs( argc, argv );
// per level user limit
host.max_edicts = bound( 8, Cvar_VariableValue("prvm_maxedicts"), 65535 );
host.max_edicts = bound( 8, Cvar_VariableValue("prvm_maxedicts"), MAX_EDICTS - 1 );
SV_Init();
CL_Init();

View File

@ -52,16 +52,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define AI_SPECTATOR (1<<12) // spectator mode for clients
#define AI_WATERJUMP (1<<13) // npc or player take out of water
#define FL_CLIENT (1<<0) // this is client
#define FL_MONSTER (1<<1) // this is npc
#define FL_DEADMONSTER (1<<2) // dead npc or dead player
#define FL_WORLDBRUSH (1<<3) // Not moveable/removeable brush entity
#define FL_DORMANT (1<<4) // Entity is dormant, no updates to client
#define FL_FRAMETHINK (1<<5) // entity will be thinking every frame
#define FL_GRAPHED (1<<6) // worldgraph has this ent listed as something that blocks a conection
#define FL_FLOAT (1<<7) // this entity can be floating. FIXME: remove this ?
#define FL_TRACKTRAIN (1<<8) // old stuff...
typedef enum
{
ss_dead, // no map loaded
@ -91,6 +81,7 @@ typedef struct server_s
char name[MAX_QPATH]; // map name, or cinematic name
cmodel_t *models[MAX_MODELS];
cmodel_t *worldmodel;
char configstrings[MAX_CONFIGSTRINGS][MAX_QPATH];
@ -107,7 +98,7 @@ typedef struct server_s
typedef struct
{
player_state_t ps;
entity_state_t ps;
int areabytes;
byte areabits[MAX_MAP_AREAS/8]; // portalarea visibility bits
int num_entities;
@ -121,12 +112,15 @@ typedef struct sv_client_s
{
cl_state_t state;
player_state_t ps; // communicated by server to clients
entity_state_t ps; // communicated by server to clients
char userinfo[MAX_INFO_STRING]; // name, etc
int lastframe; // for delta compression
usercmd_t lastcmd; // for filling in big drops
usercmd_t cmd; // current user commands
vec3_t fix_angles; // q1 legacy
bool fixangle;
// commands exhaust it, assume time cheating
int ping;
int rate;
@ -147,6 +141,7 @@ typedef struct sv_client_s
int downloadsize; // total bytes (can't use EOF because of paks)
int downloadcount; // bytes sent
int skipframes; // client synchronyze with phys frame
int lastmessage; // sv.framenum when packet was last received
int lastconnect;
@ -156,8 +151,6 @@ typedef struct sv_client_s
} sv_client_t;
typedef struct worldsector_s
{
int axis; // -1 = leaf node
@ -182,13 +175,19 @@ struct sv_edict_s
int num_clusters; // if -1, use headnode instead
int clusternums[MAX_ENT_CLUSTERS];
int areanum, areanum2;
bool forceupdate; // physic_push force update
bool suspended; // suspended in air toss object
vec3_t water_origin; // step old origin
vec3_t moved_origin; // push old origin
vec3_t moved_angles; // push old angles
int serialnumber; // unical entity #id
int solid; // see entity_state_t for details
physbody_t *physbody; // ptr to phys body
// baselines
entity_state_t s;
entity_state_t s; // this is a player_state too
};
/*
@ -229,6 +228,7 @@ typedef struct
int next_client_entities; // next client_entity to use
entity_state_t *client_entities; // [num_client_entities]
entity_state_t *baselines; // [host.max_edicts]
func_t ClientMove; // qc client physic
int last_heartbeat;
@ -246,6 +246,8 @@ extern cvar_t *sv_paused;
extern cvar_t *maxclients;
extern cvar_t *sv_noreload; // don't reload level state when reentering
extern cvar_t *sv_airaccelerate; // don't reload level state when reentering
extern cvar_t *sv_accelerate;
extern cvar_t *sv_friction;
extern cvar_t *sv_maxvelocity;
extern cvar_t *sv_gravity;
extern cvar_t *sv_fps; // running server at
@ -255,6 +257,11 @@ extern cvar_t *allow_download;
extern cvar_t *rcon_password;
extern cvar_t *sv_fatpvs;
extern cvar_t *hostname;
extern cvar_t *sv_stepheight;
extern cvar_t *sv_playersonly;
extern cvar_t *sv_rollangle;
extern cvar_t *sv_rollspeed;
extern cvar_t *sv_maxspeed;
extern sv_client_t *sv_client;
@ -292,15 +299,23 @@ void SV_VM_End(void);
//
// sv_phys.c
//
void SV_Physics( void );
void SV_PlayerMove( sv_edict_t *ed );
void SV_PrepWorldFrame (void);
void SV_Physics (edict_t *ent);
void SV_DropToFloor (edict_t *ent);
void SV_CheckGround (edict_t *ent);
int SV_ContentsMask( const edict_t *passedict );
bool SV_MoveStep (edict_t *ent, vec3_t move, bool relink);
void SV_Physics_ClientMove( sv_client_t *cl, usercmd_t *cmd );
void SV_CheckVelocity (edict_t *ent);
bool SV_CheckBottom (edict_t *ent);
//
// sv_move.c
//
void SV_Transform( sv_edict_t *ed, matrix4x3 transform );
void SV_PlaySound( sv_edict_t *ed, float volume, const char *sample );
bool SV_movestep( edict_t *ent, vec3_t move, bool relink, bool noenemy, bool settrace );
//
// sv_send.c
//
@ -318,6 +333,7 @@ char *SV_StatusString( void );
void SV_GetChallenge( netadr_t from );
void SV_DirectConnect( netadr_t from );
void SV_PutClientInServer( edict_t *ent );
void SV_ClientThink( sv_client_t *cl, usercmd_t *cmd );
void SV_ExecuteClientMessage( sv_client_t *cl, sizebuf_t *msg );
void SV_ConnectionlessPacket( netadr_t from, sizebuf_t *msg );
@ -350,6 +366,7 @@ void SV_SetModel (edict_t *ent, const char *name);
void SV_CreatePhysBody( edict_t *ent );
void SV_SetPhysForce( edict_t *ent );
void SV_SetMassCentre( edict_t *ent);
float SV_AngleMod( float ideal, float current, float speed );
//
// sv_studio.c
@ -364,18 +381,12 @@ bool SV_CreateMeshBuffer( edict_t *in, cmodel_t *out );
//
void SV_SpawnEntities( const char *mapname, const char *entities );
void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count);
void SV_Transform( sv_edict_t *ed, matrix4x3 transform );
void SV_PlaySound( sv_edict_t *ed, float volume, const char *sample );
void SV_FreeEdict (edict_t *ed);
void SV_InitEdict (edict_t *e);
edict_t *SV_Spawn (void);
void SV_RunFrame (void);
void SV_ClientUserinfoChanged (edict_t *ent, char *userinfo);
bool SV_ClientConnect (edict_t *ent, char *userinfo);
void SV_ClientBegin (edict_t *ent);
void ClientThink (edict_t *ent, usercmd_t *ucmd);
void SV_ClientDisconnect (edict_t *ent);
void SV_ClientCommand (edict_t *ent);
void SV_TouchTriggers (edict_t *ent);
//
@ -416,14 +427,12 @@ int SV_AreaEdicts( const vec3_t mins, const vec3_t maxs, edict_t **list, int max
//
// functions that interact with everything apropriate
//
int SV_PointContents( const vec3_t p, edict_t *passedict );
int SV_PointContents( const vec3_t p );
// returns the CONTENTS_* value from the world at the given point.
// Quake 2 extends this to also check entities, to allow moving liquids
trace_t SV_ClipMoveToEntity(edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int contentsmask );
trace_t SV_Trace( const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, edict_t *passedict, int contentmask );
trace_t SV_TraceToss (edict_t *tossent, edict_t *ignore);
trace_t SV_Trace( const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, edict_t *passedict, int contentmask );
trace_t SV_TraceToss( edict_t *tossent, edict_t *ignore );
// mins and maxs are relative
// if the entire move stays in a solid volume, trace.allsolid will be set,

View File

@ -12,6 +12,10 @@ typedef struct ucmd_s
void (*func)( sv_client_t *cl );
} ucmd_t;
static vec3_t wishdir, forward, right, up;
static float wishspeed;
static bool onground;
/*
=================
SV_GetChallenge
@ -205,6 +209,31 @@ gotnewcl:
svs.last_heartbeat = MAX_HEARTBEAT;
}
/*
=====================
SV_ClientCconnect
QC code can rejected a connection for some reasons
e.g. ipban
=====================
*/
bool SV_ClientConnect( edict_t *ent, char *userinfo )
{
bool result = true;
// make sure we start with known default
ent->progs.sv->flags = 0;
ent->progs.sv->health = 100;
MsgDev(D_NOTE, "SV_ClientConnect()\n");
prog->globals.sv->time = sv.time;
prog->globals.sv->pev = PRVM_EDICT_TO_PROG(ent);
PRVM_ExecuteProgram (prog->globals.sv->ClientConnect, "ClientConnect");
result = (int)PRVM_G_FLOAT(OFS_RETURN);
return result;
}
/*
=====================
SV_DropClient
@ -319,7 +348,7 @@ char *SV_StatusString( void )
cl = &svs.clients[i];
if( cl->state == cs_connected || cl->state == cs_spawned )
{
com.sprintf( player, "%i %i \"%s\"\n", cl->edict->priv.sv->client->ps.stats[STAT_FRAGS], cl->ping, cl->name );
com.sprintf( player, "%i %i \"%s\"\n", (int)cl->edict->progs.sv->frags, cl->ping, cl->name );
playerLength = com.strlen(player);
if( statusLength + playerLength >= sizeof(status))
break; // can't hold any more
@ -617,7 +646,7 @@ void SV_Baselines_f( sv_client_t *cl )
while( start < host.max_edicts )
{
base = &svs.baselines[start];
if( base->modelindex || base->soundindex || base->effects )
if( base->model.index || base->soundindex || base->effects )
{
MSG_WriteByte( &cl->netchan.message, svc_spawnbaseline );
MSG_WriteDeltaEntity( &nullstate, base, &cl->netchan.message, true, true );
@ -648,7 +677,7 @@ void SV_Begin_f( sv_client_t *cl )
return;
}
cl->state = cs_spawned;
SV_ClientBegin( cl->edict );
SV_PutClientInServer( cl->edict );
}
/*
@ -979,6 +1008,267 @@ void SV_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
else MsgDev( D_ERROR, "bad connectionless packet from %s:\n%s\n", NET_AdrToString( from ), s );
}
void SV_ApplyClientMove( sv_client_t *cl, usercmd_t *cmd )
{
short temp;
int i;
// set the edict fields
cl->edict->progs.sv->button0 = cmd->buttons & 1;
cl->edict->progs.sv->button2 = (cmd->buttons & 2)>>1;
if( cmd->impulse ) cl->edict->progs.sv->impulse = cmd->impulse;
// only send the impulse to qc once
cmd->impulse = 0;
// circularly clamp the angles with deltas
for( i = 0; i < 3; i++ )
{
temp = cmd->angles[i] + cl->ps.delta_angles[i];
cl->ps.viewangles[i] = SHORT2ANGLE( temp );
}
// don't let the player look up or down more than 90 degrees
if( cl->ps.viewangles[PITCH] > 89 && cl->ps.viewangles[PITCH] < 180 )
cl->ps.viewangles[PITCH] = 89;
else if( cl->ps.viewangles[PITCH] < 271 && cl->ps.viewangles[PITCH] >= 180 )
cl->ps.viewangles[PITCH] = 271;
VectorCopy( cl->ps.viewangles, cl->edict->progs.sv->v_angle );
VectorCopy( cl->ps.viewangles, cl->edict->progs.sv->angles );
}
void SV_DropPunchAngle( sv_client_t *cl )
{
float len;
len = VectorNormalizeLength( cl->edict->progs.sv->punchangle );
len -= 10 * sv.frametime;
if( len < 0 ) len = 0;
VectorScale( cl->edict->progs.sv->punchangle, len, cl->edict->progs.sv->punchangle );
}
/*
==================
SV_UserFriction
==================
*/
void SV_UserFriction( sv_client_t *cl )
{
float speed, newspeed;
float control, friction;
vec3_t start, stop;
trace_t trace;
speed = sqrt(cl->edict->progs.sv->velocity[0] * cl->edict->progs.sv->velocity[0] + cl->edict->progs.sv->velocity[1] * cl->edict->progs.sv->velocity[1]);
if( !speed ) return;
// if the leading edge is over a dropoff, increase friction
start[0] = stop[0] = cl->edict->progs.sv->origin[0] + cl->edict->progs.sv->velocity[0] / speed * 16;
start[1] = stop[1] = cl->edict->progs.sv->origin[1] + cl->edict->progs.sv->velocity[1] / speed * 16;
start[2] = cl->edict->progs.sv->origin[2] + cl->edict->progs.sv->mins[2];
stop[2] = start[2] - 34;
trace = SV_Trace( start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, cl->edict, SV_ContentsMask( cl->edict ));
if( trace.fraction == 1.0 ) friction = sv_friction->value * 2;
else friction = sv_friction->value;
// apply friction
control = speed < 100 ? 100 : speed;
newspeed = speed - sv.frametime * control * friction;
if( newspeed < 0 ) newspeed = 0;
else newspeed /= speed;
VectorScale( cl->edict->progs.sv->velocity, newspeed, cl->edict->progs.sv->velocity );
}
/*
===============
V_CalcRoll
Used by view and sv_user
===============
*/
float SV_CalcRoll( vec3_t angles, vec3_t velocity )
{
vec3_t right;
float sign, side, value;
AngleVectors( angles, NULL, right, NULL );
side = DotProduct( velocity, right );
sign = side < 0 ? -1 : 1;
side = fabs( side );
value = sv_rollangle->value;
if( side < sv_rollspeed->value )
side = side * value / sv_rollspeed->value;
else side = value;
return side*sign;
}
/*
==============
SV_Accelerate
==============
*/
void SV_Accelerate( sv_client_t *cl )
{
int i;
float addspeed;
float accelspeed, currentspeed;
currentspeed = DotProduct( cl->edict->progs.sv->velocity, wishdir );
addspeed = wishspeed - currentspeed;
if( addspeed <= 0 ) return;
accelspeed = sv_accelerate->value * sv.frametime * wishspeed;
if( accelspeed > addspeed ) accelspeed = addspeed;
for( i = 0; i < 3; i++ ) cl->edict->progs.sv->velocity[i] += accelspeed * wishdir[i];
}
void SV_AirAccelerate( sv_client_t *cl, vec3_t wishveloc )
{
int i;
float addspeed;
float wishspd, accelspeed, currentspeed;
wishspd = VectorNormalizeLength( wishveloc );
if( wishspd > 30 ) wishspd = 30;
currentspeed = DotProduct( cl->edict->progs.sv->velocity, wishveloc );
addspeed = wishspd - currentspeed;
if( addspeed <= 0 ) return;
accelspeed = sv_accelerate->value * wishspeed * sv.frametime;
if( accelspeed > addspeed ) accelspeed = addspeed;
for( i = 0; i < 3; i++ ) cl->edict->progs.sv->velocity[i] += accelspeed * wishveloc[i];
}
/*
===================
SV_WaterMove
===================
*/
void SV_WaterMove( sv_client_t *cl, usercmd_t *cmd )
{
int i;
vec3_t wishvel;
float speed, newspeed;
float wishspeed, addspeed;
float accelspeed, temp;
// user intentions
AngleVectors( cl->edict->progs.sv->v_angle, forward, right, up );
for( i = 0; i < 3; i++ ) wishvel[i] = forward[i] * cmd->forwardmove + right[i] * cmd->sidemove;
if(!cmd->forwardmove && !cmd->sidemove && !cmd->upmove)
wishvel[2] -= 60; // drift towards bottom
else wishvel[2] += cmd->upmove;
wishspeed = VectorLength( wishvel );
if( wishspeed > sv_maxspeed->value )
{
temp = sv_maxspeed->value / wishspeed;
VectorScale( wishvel, temp, wishvel );
wishspeed = sv_maxspeed->value;
}
wishspeed *= 0.7;
// water friction
speed = VectorLength( cl->edict->progs.sv->velocity );
if( speed )
{
newspeed = speed - sv.frametime * speed * sv_friction->value;
if( newspeed < 0 ) newspeed = 0;
temp = newspeed / speed;
VectorScale( cl->edict->progs.sv->velocity, temp, cl->edict->progs.sv->velocity );
}
else newspeed = 0;
// water acceleration
if( !wishspeed ) return;
addspeed = wishspeed - newspeed;
if( addspeed <= 0 ) return;
VectorNormalize( wishvel );
accelspeed = sv_accelerate->value * wishspeed * sv.frametime;
if( accelspeed > addspeed ) accelspeed = addspeed;
for( i = 0; i < 3; i++ ) cl->edict->progs.sv->velocity[i] += accelspeed * wishvel[i];
}
void SV_WaterJump( sv_client_t *cl )
{
if (sv.time > cl->edict->progs.sv->teleport_time || !cl->edict->progs.sv->waterlevel )
{
cl->edict->progs.sv->flags = (int)cl->edict->progs.sv->aiflags & ~AI_WATERJUMP;
cl->edict->progs.sv->teleport_time = 0;
}
cl->edict->progs.sv->velocity[0] = cl->edict->progs.sv->movedir[0];
cl->edict->progs.sv->velocity[1] = cl->edict->progs.sv->movedir[1];
}
/*
===================
SV_AirMove
===================
*/
void SV_AirMove( sv_client_t *cl, usercmd_t *cmd )
{
int i;
vec3_t wishvel;
float fmove, smove, temp;
wishvel[0] = wishvel[2] = 0;
wishvel[1] = cl->edict->progs.sv->angles[1];
AngleVectors( wishvel, forward, right, up );
fmove = cmd->forwardmove;
smove = cmd->sidemove;
// hack to not let you back into teleporter
if( sv.time < cl->edict->progs.sv->teleport_time && fmove < 0 )
fmove = 0;
for( i = 0; i < 3; i++ ) wishvel[i] = forward[i] * fmove + right[i] * smove;
if((int)cl->edict->progs.sv->movetype != MOVETYPE_WALK )
wishvel[2] += cmd->upmove;
VectorCopy( wishvel, wishdir );
wishspeed = VectorNormalizeLength( wishdir );
if( wishspeed > sv_maxspeed->value )
{
temp = sv_maxspeed->value / wishspeed;
VectorScale( wishvel, temp, wishvel );
wishspeed = sv_maxspeed->value;
}
if( cl->edict->progs.sv->movetype == MOVETYPE_NOCLIP )
{
// noclip
VectorCopy( wishvel, cl->edict->progs.sv->velocity );
}
else if( onground )
{
SV_UserFriction( cl );
SV_Accelerate( cl );
}
else
{
// not on ground, so little effect on velocity
SV_AirAccelerate( cl, wishvel );
}
}
/*
==================
SV_ClientThink
@ -988,12 +1278,71 @@ Also called by bot code
*/
void SV_ClientThink( sv_client_t *cl, usercmd_t *cmd )
{
cl->lastcmd = *cmd;
vec3_t v_angle;
cl->cmd = *cmd;
cl->skipframes = 0;
#if 1
// may have been kicked during the last usercmd
if( sv_paused->integer )
if( sv_paused->integer ) return;
SV_ApplyClientMove( cl, cmd );
// make sure the velocity is sane (not a NaN)
SV_CheckVelocity( cl->edict );
// LordHavoc: QuakeC replacement for SV_ClientThink (player movement)
/*if( svs.ClientMove )
{
prog->globals.sv->time = sv.time;
prog->globals.sv->pev = PRVM_EDICT_TO_PROG( cl->edict );
PRVM_ExecuteProgram( svs.ClientMove, "ClientMove" );
SV_CheckVelocity( cl->edict );
return;
}*/
if( cl->edict->progs.sv->movetype == MOVETYPE_NONE )
return;
onground = (int)cl->edict->progs.sv->aiflags & AI_ONGROUND;
SV_DropPunchAngle( cl );
// if dead, behave differently
if( cl->edict->progs.sv->health <= 0 )
return;
// angles
// show 1/3 the pitch angle and all the roll angle
VectorAdd( cl->edict->progs.sv->v_angle, cl->edict->progs.sv->punchangle, v_angle );
cl->edict->progs.sv->angles[ROLL] = SV_CalcRoll( cl->edict->progs.sv->angles, cl->edict->progs.sv->velocity) * 4;
if( !cl->edict->progs.sv->fixangle )
{
cl->edict->progs.sv->angles[PITCH] = -v_angle[PITCH]/3;
cl->edict->progs.sv->angles[YAW] = v_angle[YAW];
}
if((int)cl->edict->progs.sv->aiflags & AI_WATERJUMP )
{
SV_WaterJump( cl );
SV_CheckVelocity( cl->edict );
return;
}
// walk
if((cl->edict->progs.sv->waterlevel >= 2) && (cl->edict->progs.sv->movetype != MOVETYPE_NOCLIP))
{
SV_WaterMove( cl, &cl->cmd );
SV_CheckVelocity( cl->edict );
return;
}
SV_AirMove( cl, &cl->cmd );
SV_CheckVelocity( cl->edict );
VectorCopy( cl->edict->progs.sv->origin, cl->ps.origin );
VectorCopy( cl->edict->progs.sv->velocity, cl->ps.velocity );
#else
ClientThink( cl->edict, cmd );
#endif
}
/*
@ -1055,13 +1404,13 @@ static void SV_UserMove( sv_client_t *cl, sizebuf_t *msg )
{
while( net_drop > 2 )
{
SV_ClientThink( cl, &cl->lastcmd );
SV_Physics_ClientMove( cl, &cl->lastcmd );
net_drop--;
}
if( net_drop > 1 ) SV_ClientThink( cl, &oldest );
if( net_drop > 0 ) SV_ClientThink( cl, &oldcmd );
if( net_drop > 1 ) SV_Physics_ClientMove( cl, &oldest );
if( net_drop > 0 ) SV_Physics_ClientMove( cl, &oldcmd );
}
SV_ClientThink( cl, &newcmd );
SV_Physics_ClientMove( cl, &newcmd );
}
cl->lastcmd = newcmd;
}

View File

@ -457,7 +457,7 @@ void SV_Status_f( void )
if( !cl->state ) continue;
Msg("%3i ", i);
Msg("%5i ", cl->edict->priv.sv->client->ps.stats[STAT_FRAGS]);
Msg("%5i ", (int)cl->edict->progs.sv->frags );
if (cl->state == cs_connected) Msg("Connect");
else if (cl->state == cs_zombie) Msg ("Zombie ");

View File

@ -103,6 +103,10 @@ struct sv_entvars_s
vec3_t punchangle;
vec3_t view_ofs;
vec3_t v_angle;
float button0;
float button1;
float button2;
float impulse;
string_t v_model;
float v_frame;
float v_body;
@ -121,6 +125,8 @@ struct sv_entvars_s
int owner;
int enemy;
int aiment;
int goalentity;
float fixangle;
float ideal_yaw;
float yaw_speed;
float teleport_time;
@ -129,6 +135,7 @@ struct sv_entvars_s
float nextthink;
float health;
float gravity;
float frags;
float team;
};
@ -137,23 +144,16 @@ struct sv_entvars_s
static fields_t sv_reqfields[] =
{
{142, 6, "walk"},
{143, 6, "jump"},
{144, 6, "duck"},
{145, 2, "v_animtime"},
{146, 2, "frags"},
{147, 2, "weapon"},
{148, 2, "items"},
{149, 1, "target"},
{150, 1, "parent"},
{151, 1, "targetname"},
{152, 4, "goalentity"},
{153, 2, "deadflag"},
{154, 2, "button0"},
{155, 2, "button1"},
{156, 2, "button2"},
{157, 2, "impulse"},
{158, 2, "fixangle"},
{149, 6, "walk"},
{150, 6, "jump"},
{151, 6, "duck"},
{152, 2, "v_animtime"},
{153, 2, "weapon"},
{154, 2, "items"},
{155, 1, "target"},
{156, 1, "parent"},
{157, 1, "targetname"},
{158, 2, "deadflag"},
{159, 2, "idealpitch"},
{160, 1, "netname"},
{161, 2, "max_health"},
@ -244,6 +244,6 @@ static fields_t sv_reqfields[] =
{264, 1, "oldmodel"}
};
#define PROG_CRC_SERVER 2740
#define PROG_CRC_SERVER 61861
#endif//SV_EDICT_H

View File

@ -70,23 +70,24 @@ void SV_UpdateEntityState( edict_t *ent )
VectorCopy (ent->progs.sv->origin, ent->priv.sv->s.origin);
VectorCopy (ent->progs.sv->angles, ent->priv.sv->s.angles);
VectorCopy (ent->progs.sv->old_origin, ent->priv.sv->s.old_origin);
ent->priv.sv->s.modelindex = (int)ent->progs.sv->modelindex;
ent->priv.sv->s.model.index = (int)ent->progs.sv->modelindex;
ent->priv.sv->s.health = ent->progs.sv->health;
if( ent->priv.sv->client )
{
// attached weaponmodel
// FIXME: let any entity send weaponmodel
ent->priv.sv->s.weaponmodel = ent->priv.sv->client->ps.pmodel.index;
ent->priv.sv->s.pmodel.index = ent->priv.sv->client->ps.pmodel.index;
}
ent->priv.sv->s.skin = (short)ent->progs.sv->skin; // studio model skin
ent->priv.sv->s.body = (byte)ent->progs.sv->body; // studio model submodel
ent->priv.sv->s.frame = ent->progs.sv->frame; // any model current frame
ent->priv.sv->s.sequence = (byte)ent->progs.sv->sequence; // studio model sequence
ent->priv.sv->s.effects = (uint)ent->progs.sv->effects; // shared client and render flags
ent->priv.sv->s.renderfx = (int)ent->progs.sv->renderfx; // renderer flags
ent->priv.sv->s.alpha = ent->progs.sv->alpha; // alpha value
ent->priv.sv->s.animtime = ent->progs.sv->animtime; // auto-animating time
ent->priv.sv->s.model.skin = (short)ent->progs.sv->skin; // studio model skin
ent->priv.sv->s.model.body = (byte)ent->progs.sv->body; // studio model submodel
ent->priv.sv->s.model.frame = ent->progs.sv->frame; // any model current frame
ent->priv.sv->s.model.sequence = (byte)ent->progs.sv->sequence; // studio model sequence
ent->priv.sv->s.effects = (uint)ent->progs.sv->effects; // shared client and render flags
ent->priv.sv->s.renderfx = (int)ent->progs.sv->renderfx; // renderer flags
ent->priv.sv->s.renderamt = ent->progs.sv->alpha; // alpha value
ent->priv.sv->s.model.animtime = ent->progs.sv->animtime; // auto-animating time
}
/*
@ -264,7 +265,7 @@ void SV_BuildClientFrame( sv_client_t *cl )
// calculate the visible areas
frame->areabytes = pe->WriteAreaBits( frame->areabits, clientarea );
// grab the current player_state_t
// grab the current player state
frame->ps = clent->priv.sv->client->ps;
clientpvs = pe->ClusterPVS( clientcluster );
@ -389,7 +390,7 @@ bool SV_SendClientDatagram( sv_client_t *cl )
MSG_Init( &msg, msg_buf, sizeof(msg_buf));
// send over all the relevant entity_state_t
// and the player_state_t
// and the player state
SV_WriteFrameToClient( cl, &msg );
// copy the accumulated multicast datagram

View File

@ -185,12 +185,12 @@ void SV_SpawnServer( char *server, char *savename, sv_state_t serverstate )
if (serverstate != ss_active)
{
sv.models[1] = pe->BeginRegistration( "", false, &checksum); // no real map
sv.worldmodel = sv.models[1] = pe->BeginRegistration( "", false, &checksum); // no real map
}
else
{
com.sprintf(sv.configstrings[CS_MODELS+1], "maps/%s", server);
sv.models[1] = pe->BeginRegistration(sv.configstrings[CS_MODELS+1], false, &checksum);
sv.worldmodel = sv.models[1] = pe->BeginRegistration(sv.configstrings[CS_MODELS+1], false, &checksum);
}
com.sprintf(sv.configstrings[CS_MAPCHECKSUM], "%i", checksum);

View File

@ -18,16 +18,18 @@ cvar_t *zombietime; // seconds to sink messages after disconnect
cvar_t *rcon_password; // password for remote server commands
cvar_t *allow_download;
cvar_t *allow_download_players;
cvar_t *allow_download_models;
cvar_t *allow_download_sounds;
cvar_t *allow_download_maps;
cvar_t *sv_airaccelerate;
cvar_t *sv_maxvelocity;
cvar_t *sv_gravity;
cvar_t *sv_stepheight;
cvar_t *sv_noreload; // don't reload level state when reentering
cvar_t *sv_playersonly;
cvar_t *sv_rollangle;
cvar_t *sv_rollspeed;
cvar_t *sv_maxspeed;
cvar_t *sv_accelerate;
cvar_t *sv_friction;
cvar_t *maxclients; // FIXME: rename sv_maxclients
cvar_t *hostname;
@ -192,8 +194,6 @@ SV_RunGameFrame
*/
void SV_RunGameFrame (void)
{
int i;
if( sv_paused->integer && maxclients->integer == 1 )
return;
@ -205,10 +205,7 @@ void SV_RunGameFrame (void)
sv.frametime = HOST_FRAMETIME * 0.001f;
sv.time = sv.framenum * sv.frametime;
if(!cm_paused->value)
for( i = 0; i < 6; i++ )
pe->Frame( sv.frametime * i );//FIXME
SV_RunFrame ();
SV_Physics();
// never get more than one tic behind
if( sv.time * 1000 < svs.realtime )
@ -369,6 +366,8 @@ void SV_Init (void)
Cvar_Get ("protocol", va("%i", PROTOCOL_VERSION), CVAR_SERVERINFO|CVAR_INIT, "displays server protocol version" );
sv_fps = Cvar_Get( "sv_fps", "60", CVAR_ARCHIVE|CVAR_LATCH, "running server at" );
sv_stepheight = Cvar_Get( "sv_stepheight", "18", CVAR_ARCHIVE|CVAR_LATCH, "how high you can step up" );
sv_playersonly = Cvar_Get( "playersonly", "0", 0, "freezes time, except for players" );
maxclients = Cvar_Get ("maxclients", "1", CVAR_SERVERINFO | CVAR_LATCH, "max count of clients for current game" );
hostname = Cvar_Get ("hostname", "unnamed", CVAR_SERVERINFO | CVAR_ARCHIVE, "host name" );
timeout = Cvar_Get ("timeout", "125", 0, "connection timeout" );
@ -376,16 +375,15 @@ void SV_Init (void)
sv_paused = Cvar_Get ("paused", "0", 0, "server pause" );
sv_enforcetime = Cvar_Get ("sv_enforcetime", "0", 0, "client enforce time" );
allow_download = Cvar_Get ("allow_download", "1", CVAR_ARCHIVE, "allow download resources" );
allow_download_players = Cvar_Get ("allow_download_players", "0", CVAR_ARCHIVE, "let downloading playermodels" );
allow_download_models = Cvar_Get ("allow_download_models", "1", CVAR_ARCHIVE, "let downloading models");
allow_download_sounds = Cvar_Get ("allow_download_sounds", "1", CVAR_ARCHIVE, "let downloading sounds" );
allow_download_maps = Cvar_Get ("allow_download_maps", "1", CVAR_ARCHIVE, "let downloading maps" );
sv_noreload = Cvar_Get ("sv_noreload", "0", 0, "ignore savepoints for singleplayer" );
sv_noreload = Cvar_Get("sv_noreload", "0", 0, "ignore savepoints for singleplayer" );
sv_rollangle = Cvar_Get("sv_rollangle", "2", 0, "how much to tilt the view when strafing" );
sv_rollspeed = Cvar_Get("sv_rollspeed", "200", 0, "how much strafing is necessary to tilt the view" );
sv_airaccelerate = Cvar_Get("sv_airaccelerate", "0", CVAR_LATCH, "player accellerate in air" );
sv_maxvelocity = Cvar_Get("sv_maxvelocity", "2000", 0, "max world velocity" );
sv_gravity = Cvar_Get("sv_gravity", "800", 0, "world gravity" );
sv_maxspeed = Cvar_Get("sv_maxspeed", "320", 0, "maximum speed a player can accelerate to when on ground (can be exceeded by tricks)");
sv_accelerate = Cvar_Get( "sv_accelerate", "10", 0, "rate at which a player accelerates to sv_maxspeed" );
sv_friction = Cvar_Get( "sv_friction", "4", 0, "how fast you slow down" );
public_server = Cvar_Get ("public", "0", 0, "change server type from private to public" );

485
engine/server/sv_move.c Normal file
View File

@ -0,0 +1,485 @@
//=======================================================================
// Copyright XashXT Group 2007 ©
// sv_move.c - monsters movement
//=======================================================================
#include "common.h"
#include "server.h"
/*
=============
SV_CheckBottom
Returns false if any part of the bottom of the entity is off an edge that
is not a staircase.
=============
*/
bool SV_CheckBottom( edict_t *ent )
{
vec3_t mins, maxs, start, stop;
float mid, bottom;
trace_t trace;
int x, y;
VectorAdd (ent->progs.sv->origin, ent->progs.sv->mins, mins);
VectorAdd (ent->progs.sv->origin, ent->progs.sv->maxs, maxs);
// if all of the points under the corners are solid world, don't bother
// with the tougher checks
// the corners must be within 16 of the midpoint
start[2] = mins[2] - 1;
for( x = 0; x <= 1; x++ )
{
for( y = 0; y <= 1; y++ )
{
start[0] = x ? maxs[0] : mins[0];
start[1] = y ? maxs[1] : mins[1];
if(!(SV_PointContents( start ) & (CONTENTS_SOLID | CONTENTS_BODY)))
goto realcheck;
}
}
return true; // we got out easy
realcheck:
// check it for real...
start[2] = mins[2];
// the midpoint must be within 16 of the bottom
start[0] = stop[0] = (mins[0] + maxs[0]) * 0.5f;
start[1] = stop[1] = (mins[1] + maxs[1]) * 0.5f;
stop[2] = start[2] - 2 * sv_stepheight->value;
trace = SV_Trace( start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, SV_ContentsMask(ent));
if( trace.fraction == 1.0 )
return false;
mid = bottom = trace.endpos[2];
// the corners must be within 16 of the midpoint
for( x = 0; x <= 1; x++ )
{
for( y = 0; y <= 1; y++ )
{
start[0] = stop[0] = x ? maxs[0] : mins[0];
start[1] = stop[1] = y ? maxs[1] : mins[1];
trace = SV_Trace( start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, SV_ContentsMask(ent));
if( trace.fraction != 1.0 && trace.endpos[2] > bottom )
bottom = trace.endpos[2];
if( trace.fraction == 1.0 || mid - trace.endpos[2] > sv_stepheight->value )
return false;
}
}
return true;
}
/*
=============
SV_movestep
Called by monster program code.
The move will be adjusted for slopes and stairs, but if the move isn't
possible, no move is done and false is returned
=============
*/
bool SV_movestep( edict_t *ent, vec3_t move, bool relink, bool noenemy, bool settrace )
{
float dz;
vec3_t oldorg, neworg, end, traceendpos;
edict_t *enemy;
trace_t trace;
int i;
// try the move
VectorCopy (ent->progs.sv->origin, oldorg);
VectorAdd (ent->progs.sv->origin, move, neworg);
// flying monsters don't step up
if((int)ent->progs.sv->aiflags & (AI_SWIM|AI_FLY))
{
// try one move with vertical motion, then one without
for( i = 0; i < 2; i++ )
{
VectorAdd( ent->progs.sv->origin, move, neworg );
if( noenemy ) enemy = prog->edicts;
else
{
enemy = PRVM_PROG_TO_EDICT( ent->progs.sv->enemy );
if( i == 0 && enemy != prog->edicts )
{
dz = ent->progs.sv->origin[2] - PRVM_PROG_TO_EDICT(ent->progs.sv->enemy)->progs.sv->origin[2];
if( dz > 40 ) neworg[2] -= 8;
if( dz < 30 ) neworg[2] += 8;
}
}
trace = SV_Trace( ent->progs.sv->origin, ent->progs.sv->mins, ent->progs.sv->maxs, neworg, MOVE_NORMAL, ent, SV_ContentsMask(ent));
if( trace.fraction == 1 )
{
VectorCopy( trace.endpos, traceendpos );
if(((int)ent->progs.sv->aiflags & AI_SWIM) && !(SV_PointContents(traceendpos) & MASK_WATER))
return false; // swim monster left water
VectorCopy( traceendpos, ent->progs.sv->origin );
if( relink ) SV_LinkEdict( ent );
return true;
}
if( enemy == prog->edicts ) break;
}
return false;
}
// push down from a step height above the wished position
neworg[2] += sv_stepheight->value;
VectorCopy( neworg, end );
end[2] -= sv_stepheight->value * 2;
trace = SV_Trace( neworg, ent->progs.sv->mins, ent->progs.sv->maxs, end, MOVE_NORMAL, ent, SV_ContentsMask(ent));
if( trace.startsolid )
{
neworg[2] -= sv_stepheight->value;
trace = SV_Trace( neworg, ent->progs.sv->mins, ent->progs.sv->maxs, end, MOVE_NORMAL, ent, SV_ContentsMask(ent));
if( trace.startsolid ) return false;
}
if( trace.fraction == 1 )
{
// if monster had the ground pulled out, go ahead and fall
if((int)ent->progs.sv->aiflags & AI_PARTIALONGROUND )
{
VectorAdd( ent->progs.sv->origin, move, ent->progs.sv->origin );
if (relink) SV_LinkEdict( ent );
ent->progs.sv->aiflags = (int)ent->progs.sv->aiflags & ~AI_ONGROUND;
return true;
}
return false; // walked off an edge
}
// check point traces down for dangling corners
VectorCopy( trace.endpos, ent->progs.sv->origin );
if(!SV_CheckBottom( ent ))
{
if((int)ent->progs.sv->aiflags & AI_PARTIALONGROUND )
{
// entity had floor mostly pulled out from underneath it
// and is trying to correct
if( relink ) SV_LinkEdict( ent );
return true;
}
VectorCopy( oldorg, ent->progs.sv->origin );
return false;
}
if((int)ent->progs.sv->aiflags & AI_PARTIALONGROUND )
ent->progs.sv->flags = (int)ent->progs.sv->flags & ~AI_PARTIALONGROUND;
ent->progs.sv->groundentity = PRVM_EDICT_TO_PROG( trace.ent );
// the move is ok
if( relink ) SV_LinkEdict( ent );
return true;
}
//============================================================================
/*
======================
SV_StepDirection
Turns to the movement direction, and walks the current distance if
facing it.
======================
*/
bool SV_StepDirection( edict_t *ent, float yaw, float dist )
{
vec3_t move, oldorigin;
float delta, current;
ent->progs.sv->ideal_yaw = yaw;
current = anglemod( ent->progs.sv->angles[1] );
ent->progs.sv->angles[1] = SV_AngleMod( ent->progs.sv->ideal_yaw, current, ent->progs.sv->yaw_speed );
yaw = yaw * M_PI*2 / 360;
move[0] = cos(yaw)*dist;
move[1] = sin(yaw)*dist;
move[2] = 0;
VectorCopy( ent->progs.sv->origin, oldorigin );
if(SV_movestep( ent, move, false, false, false ))
{
delta = ent->progs.sv->angles[YAW] - ent->progs.sv->ideal_yaw;
if( delta > 45 && delta < 315 )
{
// not turned far enough, so don't take the step
VectorCopy( oldorigin, ent->progs.sv->origin );
}
SV_LinkEdict( ent );
return true;
}
SV_LinkEdict( ent );
return false;
}
/*
======================
SV_FixCheckBottom
======================
*/
void SV_FixCheckBottom( edict_t *ent )
{
ent->progs.sv->flags = (int)ent->progs.sv->aiflags | AI_PARTIALONGROUND;
}
/*
================
SV_NewChaseDir
================
*/
void SV_NewChaseDir( edict_t *actor, edict_t *enemy, float dist )
{
float deltax, deltay;
float d[3], tdir, olddir, turnaround;
olddir = anglemod((int)(actor->progs.sv->ideal_yaw/45) * 45);
turnaround = anglemod( olddir - 180 );
deltax = enemy->progs.sv->origin[0] - actor->progs.sv->origin[0];
deltay = enemy->progs.sv->origin[1] - actor->progs.sv->origin[1];
if( deltax > 10 ) d[1]= 0;
else if( deltax < -10 ) d[1] = 180;
else d[1] = -1;
if( deltay < -10 ) d[2] = 270;
else if( deltay > 10 ) d[2] = 90;
else d[2] = -1;
// try direct route
if( d[1] != -1 && d[2] != -1 )
{
if( d[1] == 0 ) tdir = d[2] == 90 ? 45 : 315;
else tdir = d[2] == 90 ? 135 : 215;
if( tdir != turnaround && SV_StepDirection( actor, tdir, dist ))
return;
}
// try other directions
if(((rand()&3) & 1) || fabs(deltay) > fabs(deltax))
{
tdir = d[1];
d[1] = d[2];
d[2] = tdir;
}
if( d[1] != -1 && d[1] != turnaround && SV_StepDirection( actor, d[1], dist ))
return;
if( d[2] != -1 && d[2] != turnaround && SV_StepDirection( actor, d[2], dist ))
return;
// there is no direct path to the player, so pick another direction
if( olddir != -1 && SV_StepDirection( actor, olddir, dist ))
return;
// randomly determine direction of search
if( rand() & 1 )
{
for( tdir = 0; tdir <= 315; tdir += 45 )
if( tdir != turnaround && SV_StepDirection( actor, tdir, dist ))
return;
}
else
{
for( tdir = 315; tdir >= 0; tdir -= 45 )
if( tdir != turnaround && SV_StepDirection( actor, tdir, dist ))
return;
}
if( turnaround != -1 && SV_StepDirection( actor, turnaround, dist ))
return;
actor->progs.sv->ideal_yaw = olddir; // can't move
// if a bridge was pulled out from underneath a monster, it may not have
// a valid standing position at all
if(!SV_CheckBottom( actor )) SV_FixCheckBottom( actor );
}
/*
======================
SV_CloseEnough
======================
*/
bool SV_CloseEnough( edict_t *ent, edict_t *goal, float dist )
{
int i;
for( i = 0; i < 3; i++ )
{
if( goal->progs.sv->absmin[i] > ent->progs.sv->absmax[i] + dist )
return false;
if( goal->progs.sv->absmax[i] < ent->progs.sv->absmin[i] - dist )
return false;
}
return true;
}
/*
======================
SV_MoveToGoal
======================
*/
void SV_MoveToGoal( void )
{
edict_t *ent, *goal;
float dist;
if(!VM_ValidateArgs( "movetogoal", 1 ))
return;
ent = PRVM_PROG_TO_EDICT( prog->globals.sv->pev );
goal = PRVM_PROG_TO_EDICT( ent->progs.sv->goalentity );
dist = PRVM_G_FLOAT( OFS_PARM0 );
if(!((int)ent->progs.sv->aiflags & (AI_ONGROUND|AI_FLY|AI_SWIM)))
{
PRVM_G_FLOAT(OFS_RETURN) = 0;
return;
}
// if the next step hits the enemy, return immediately
if(PRVM_PROG_TO_EDICT(ent->progs.sv->enemy) != prog->edicts && SV_CloseEnough( ent, goal, dist))
return;
// bump around...
if(( rand() & 3) == 1 || !SV_StepDirection( ent, ent->progs.sv->ideal_yaw, dist ))
{
SV_NewChaseDir( ent, goal, dist );
}
}
// g-cont: my stupid callbacks
cmodel_t *SV_GetModelPtr( edict_t *ent )
{
return pe->RegisterModel( sv.configstrings[CS_MODELS + (int)ent->progs.sv->modelindex] );
}
float *SV_GetModelVerts( sv_edict_t *ed, int *numvertices )
{
cmodel_t *cmod;
edict_t *ent;
ent = PRVM_EDICT_NUM(ed->serialnumber);
cmod = pe->RegisterModel( sv.configstrings[CS_MODELS + (int)ent->progs.sv->modelindex] );
if( cmod )
{
int i = (int)ent->progs.sv->body;
i = bound( 0, i, cmod->numbodies ); // make sure what body exist
if( cmod->col[i] )
{
*numvertices = cmod->col[i]->numverts;
return (float *)cmod->col[i]->verts;
}
}
return NULL;
}
void SV_Transform( sv_edict_t *ed, matrix4x3 transform )
{
edict_t *edict;
vec3_t origin, angles;
matrix4x4 objmatrix;
if(!ed) return;
edict = PRVM_EDICT_NUM( ed->serialnumber );
// save matrix (fourth value will be reset on save\load)
VectorCopy( transform[0], edict->progs.sv->m_pmatrix[0] );
VectorCopy( transform[1], edict->progs.sv->m_pmatrix[1] );
VectorCopy( transform[2], edict->progs.sv->m_pmatrix[2] );
VectorCopy( transform[3], edict->progs.sv->m_pmatrix[3] );
MatrixLoadIdentity( objmatrix );
VectorCopy( transform[0], objmatrix[0] );
VectorCopy( transform[1], objmatrix[1] );
VectorCopy( transform[2], objmatrix[2] );
VectorCopy( transform[3], objmatrix[3] );
MatrixAngles( objmatrix, origin, angles );
VectorCopy( origin, edict->progs.sv->origin );
VectorCopy( angles, edict->progs.sv->angles );
// refresh force and torque
pe->GetForce( ed->physbody, edict->progs.sv->velocity, edict->progs.sv->avelocity, edict->progs.sv->force, edict->progs.sv->torque );
pe->GetMassCentre( ed->physbody, edict->progs.sv->m_pcentre );
}
/*
==============
SV_ClientMove
grab user cmd from player state
send it to transform callback
==============
*/
void SV_PlayerMove( sv_edict_t *ed )
{
pmove_t pm;
sv_client_t *client;
edict_t *player;
client = ed->client;
player = PRVM_PROG_TO_EDICT( ed->serialnumber );
memset( &pm, 0, sizeof(pm) );
if( player->progs.sv->movetype == MOVETYPE_NOCLIP )
client->ps.pm_type = PM_SPECTATOR;
else client->ps.pm_type = PM_NORMAL;
client->ps.gravity = sv_gravity->value;
if( player->progs.sv->teleport_time )
client->ps.pm_flags |= PMF_TIME_TELEPORT;
else client->ps.pm_flags &= ~PMF_TIME_TELEPORT;
pm.ps = client->ps;
pm.cmd = client->lastcmd;
pm.body = ed->physbody; // member body ptr
VectorCopy( player->progs.sv->origin, pm.ps.origin );
VectorCopy( player->progs.sv->velocity, pm.ps.velocity );
pe->PlayerMove( &pm, false ); // server move
// save results of pmove
client->ps = pm.ps;
VectorCopy(pm.ps.origin, player->progs.sv->origin);
VectorCopy(pm.ps.velocity, player->progs.sv->velocity);
VectorCopy(pm.mins, player->progs.sv->mins);
VectorCopy(pm.maxs, player->progs.sv->maxs);
VectorCopy(pm.ps.viewangles, client->ps.viewangles);
}
void SV_PlaySound( sv_edict_t *ed, float volume, const char *sample )
{
float vol = bound( 0.0f, volume/255.0f, 255.0f );
int sound_idx = SV_SoundIndex( sample );
edict_t *ent;
if( !ed ) ed = prog->edicts->priv.sv;
ent = PRVM_PROG_TO_EDICT( ed->serialnumber );
//SV_StartSound( ent->progs.sv->origin, ent, CHAN_BODY, sound_idx, vol, 1.0f, 0 );
}

File diff suppressed because it is too large Load Diff

View File

@ -101,6 +101,43 @@ void SV_SetMinMaxSize (edict_t *e, float *min, float *max, bool rotate)
SV_LinkEdict (e);
}
static trace_t SV_TraceToss( edict_t *tossent, edict_t *ignore)
{
int i;
float gravity;
vec3_t move, end;
vec3_t original_origin;
vec3_t original_velocity;
vec3_t original_angles;
vec3_t original_avelocity;
trace_t trace;
VectorCopy( tossent->progs.sv->origin, original_origin );
VectorCopy( tossent->progs.sv->velocity, original_velocity );
VectorCopy( tossent->progs.sv->angles, original_angles );
VectorCopy( tossent->progs.sv->avelocity, original_avelocity );
gravity = tossent->progs.sv->gravity * sv_gravity->value * 0.05;
for( i = 0; i < 200; i++ )
{
// LordHavoc: sanity check; never trace more than 10 seconds
SV_CheckVelocity( tossent );
tossent->progs.sv->velocity[2] -= gravity;
VectorMA( tossent->progs.sv->angles, 0.05, tossent->progs.sv->avelocity, tossent->progs.sv->angles );
VectorScale( tossent->progs.sv->velocity, 0.05, move );
VectorAdd( tossent->progs.sv->origin, move, end );
trace = SV_Trace( tossent->progs.sv->origin, tossent->progs.sv->mins, tossent->progs.sv->maxs, end, MOVE_NORMAL, tossent, SV_ContentsMask( tossent ));
VectorCopy( trace.endpos, tossent->progs.sv->origin );
if( trace.fraction < 1 ) break;
}
VectorCopy( original_origin, tossent->progs.sv->origin );
VectorCopy( original_velocity, tossent->progs.sv->velocity );
VectorCopy( original_angles, tossent->progs.sv->angles );
VectorCopy( original_avelocity, tossent->progs.sv->avelocity );
return trace;
}
void SV_CreatePhysBody( edict_t *ent )
{
if( !ent || ent->progs.sv->movetype != MOVETYPE_PHYSIC ) return;
@ -339,7 +376,7 @@ void SV_WriteSaveFile( char *name )
MsgDev(D_ERROR, "SV_WriteSaveFile: can't savegame in a deathmatch\n");
return;
}
if(maxclients->integer == 1 && svs.clients[0].edict->priv.sv->client->ps.stats[STAT_HEALTH] <= 0)
if( maxclients->integer == 1 && svs.clients[0].edict->progs.sv->health <= 0 )
{
MsgDev(D_ERROR, "SV_WriteSaveFile: can't savegame while dead!\n");
return;
@ -1305,7 +1342,7 @@ void PF_droptofloor( void )
VectorCopy( ent->progs.sv->origin, end );
end[2] -= 256;
trace = SV_Trace(ent->progs.sv->origin, ent->progs.sv->mins, ent->progs.sv->maxs, end, ent, MASK_SOLID );
trace = SV_Trace(ent->progs.sv->origin, ent->progs.sv->mins, ent->progs.sv->maxs, end, MOVE_NORMAL, ent, MASK_SOLID );
if( trace.startsolid )
{
@ -1368,7 +1405,7 @@ void PF_walkmove( void )
oldf = prog->xfunction;
oldpev = prog->globals.sv->pev;
PRVM_G_FLOAT(OFS_RETURN) = SV_MoveStep( ent, move, true );
PRVM_G_FLOAT(OFS_RETURN) = SV_movestep( ent, move, true, false, true );
// restore program state
prog->xfunction = oldf;
@ -1538,7 +1575,7 @@ void PF_traceline( void )
PRVM_ERROR("%s: NAN errors detected in traceline('%f %f %f', '%f %f %f', %i, entity %i)\n",
PRVM_NAME, v1[0], v1[1], v1[2], v2[0], v2[1], v2[2], mask, PRVM_EDICT_TO_PROG(ent));
trace = SV_Trace( v1, vec3_origin, vec3_origin, v2, ent, mask );
trace = SV_Trace( v1, vec3_origin, vec3_origin, v2, MOVE_NORMAL, ent, mask );
prog->globals.sv->trace_allsolid = trace.allsolid;
prog->globals.sv->trace_startsolid = trace.startsolid;
@ -1624,7 +1661,7 @@ void PF_tracebox( void )
PRVM_ERROR("%s: NAN errors detected in tracebox('%f %f %f', '%f %f %f', '%f %f %f', '%f %f %f', %i, entity %i)\n",
PRVM_NAME, v1[0], v1[1], v1[2], m1[0], m1[1], m1[2], m2[0], m2[1], m2[2], v2[0], v2[1], v2[2], mask, PRVM_EDICT_TO_PROG(ent));
trace = SV_Trace (v1, m1, m2, v2, ent, mask );
trace = SV_Trace (v1, m1, m2, v2, MOVE_NORMAL, ent, mask );
prog->globals.sv->trace_allsolid = trace.allsolid;
prog->globals.sv->trace_startsolid = trace.startsolid;
@ -1678,7 +1715,7 @@ void PF_aim( void )
// try sending a trace straight
VectorCopy(prog->globals.sv->v_forward, dir);
VectorMA(start, 2048, dir, end);
tr = SV_Trace( start, vec3_origin, vec3_origin, end, ent, MASK_ALL );
tr = SV_Trace( start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent, MASK_ALL );
if( tr.ent && ((edict_t *)tr.ent)->progs.sv->takedamage == 2 && (flags & DF_NO_FRIENDLY_FIRE
|| ent->progs.sv->team <=0 || ent->progs.sv->team != ((edict_t *)tr.ent)->progs.sv->team))
@ -1707,7 +1744,7 @@ void PF_aim( void )
VectorNormalize (dir);
dist = DotProduct (dir, prog->globals.sv->v_forward);
if (dist < bestdist) continue; // to far to turn
tr = SV_Trace (start, vec3_origin, vec3_origin, end, ent, MASK_ALL );
tr = SV_Trace (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent, MASK_ALL );
if (tr.ent == check)
{
// can shoot at this one
@ -1856,7 +1893,7 @@ float pointcontents( vector v )
void PF_pointcontents( void )
{
if(!VM_ValidateArgs( "pointcontents", 1 )) return;
PRVM_G_FLOAT(OFS_RETURN) = SV_PointContents(PRVM_G_VECTOR(OFS_PARM0), NULL );
PRVM_G_FLOAT(OFS_RETURN) = SV_PointContents(PRVM_G_VECTOR(OFS_PARM0));
}
/*
@ -2000,70 +2037,6 @@ void PF_AreaPortalState( void )
pe->SetAreaPortalState((int)PRVM_G_FLOAT(OFS_PARM0), (bool)PRVM_G_FLOAT(OFS_PARM1));
}
/*
=================
PF_setstats
void setstats( entity client, float stat, string value )
=================
*/
void PF_setstats( void )
{
edict_t *e;
int stat_num;
const char *string;
short value;
if(!VM_ValidateArgs( "setstats", 3 )) return;
e = PRVM_G_EDICT(OFS_PARM0);
if(!e->priv.sv->client)
{
VM_Warning("setstats: stats applied only for players\n");
return;
}
stat_num = (int)PRVM_G_FLOAT(OFS_PARM1);
if(stat_num < 0 || stat_num > MAX_STATS)
{
VM_Warning("setstats: invalid stats number\n");
return;
}
string = PRVM_G_STRING(OFS_PARM2);
switch(stat_num)
{
case STAT_ZOOM:
case STAT_SPEED:
case STAT_CHASE:
case STAT_HELPICON:
case STAT_AMMO_ICON:
case STAT_ARMOR_ICON:
case STAT_TIMER_ICON:
case STAT_HEALTH_ICON:
case STAT_PICKUP_ICON:
case STAT_SELECTED_ICON:
case STAT_SELECTED_ITEM:
value = SV_ImageIndex( string );
break;
case STAT_AMMO:
case STAT_FRAGS:
case STAT_TIMER:
case STAT_ARMOR:
case STAT_HEALTH:
case STAT_FLASHES:
case STAT_LAYOUTS:
case STAT_SPECTATOR:
value = (short)com.atoi( string );
break;
default:
MsgDev( D_WARN, "unknown stat type %d\n", stat_num );
return;
}
// refresh stats
e->priv.sv->client->ps.stats[stat_num] = value;
}
/*
=================
PF_InfoPrint
@ -2379,7 +2352,7 @@ NULL, // #164 setView
NULL, // #165 crosshairangle
PF_AreaPortalState, // #166 void areaportal( float num, float state )
NULL, // #167 compareFileTime
PF_setstats, // #168 void setstats(entity e, float f, string stats)
NULL, // #168
PF_InfoPrint, // #169 void Info_Print( entity client )
PF_InfoValueForKey, // #170 string Info_ValueForKey( entity client, string key )
PF_InfoRemoveKey, // #171 void Info_RemoveKey( entity client, string key )
@ -2472,6 +2445,9 @@ void SV_InitServerProgs( void )
prog->error_cmd = VM_Error;
PRVM_LoadProgs( va("%s/server.dat", GI->vprogs_dir ), 0, NULL, SV_NUM_REQFIELDS, sv_reqfields );
}
// try to get custom movement function from qc code
svs.ClientMove = PRVM_ED_FindFunctionOffset( "ClientMove" );
PRVM_End;
}

View File

@ -7,13 +7,13 @@ edict_t *pm_passent;
void PM_trace( vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, trace_t *tr )
{
if( pm_passent->progs.sv->health > 0 )
*tr = SV_Trace (start, mins, maxs, end, pm_passent, MASK_PLAYERSOLID );
*tr = SV_Trace (start, mins, maxs, end, pm_passent, MASK_DEADSOLID );
*tr = SV_Trace (start, mins, maxs, end, MOVE_NORMAL, pm_passent, MASK_PLAYERSOLID );
*tr = SV_Trace (start, mins, maxs, end, MOVE_NORMAL, pm_passent, MASK_DEADSOLID );
}
int PM_pointcontents( vec3_t point )
{
return SV_PointContents( point, pm_passent );
return SV_PointContents( point );
}
/*
@ -25,10 +25,7 @@ SV_TouchTriggers
void SV_TouchTriggers (edict_t *ent)
{
int i, num;
edict_t **touch, *hit;
// list of pointers, not data
touch = Z_Malloc( sizeof(*touch) * host.max_edicts );
edict_t *touch[MAX_EDICTS], *hit;
// dead things don't activate triggers!
if ((ent->priv.sv->client || ((int)ent->progs.sv->flags & FL_MONSTER)) && (ent->progs.sv->health <= 0))
@ -53,7 +50,6 @@ void SV_TouchTriggers (edict_t *ent)
PRVM_ExecuteProgram (hit->progs.sv->touch, "pev->touch");
}
}
Mem_Free( touch );
// restore state
PRVM_POP_GLOBALS;
@ -72,7 +68,7 @@ SV_CalcRoll
===============
*/
float SV_CalcRoll (vec3_t angles, vec3_t velocity)
static float SV_CalcRoll (vec3_t angles, vec3_t velocity)
{
float sign;
float side;
@ -91,50 +87,6 @@ float SV_CalcRoll (vec3_t angles, vec3_t velocity)
}
/*
==============
SV_CalcGunOffset
==============
*/
void SV_CalcGunOffset( edict_t *ent )
{
int i;
float delta;
// gun angles from bobbing
ent->priv.sv->client->ps.vmodel.angles[ROLL] = xyspeed * bobfracsin * 0.005;
ent->priv.sv->client->ps.vmodel.angles[YAW] = xyspeed * bobfracsin * 0.01;
if( bobcycle & 1 )
{
ent->priv.sv->client->ps.vmodel.angles[ROLL] = -ent->priv.sv->client->ps.vmodel.angles[ROLL];
ent->priv.sv->client->ps.vmodel.angles[YAW] = -ent->priv.sv->client->ps.vmodel.angles[YAW];
}
ent->priv.sv->client->ps.vmodel.angles[PITCH] = xyspeed * bobfracsin * 0.005;
// gun angles from delta movement
for (i = 0; i < 3; i++)
{
delta = ent->priv.sv->client->ps.oldviewangles[i] - ent->priv.sv->client->ps.viewangles[i];
if( delta > 180 ) delta -= 360;
if( delta < -180 ) delta += 360;
if( delta > 45 ) delta = 45;
if( delta < -45 ) delta = -45;
if( i == YAW ) ent->priv.sv->client->ps.vmodel.angles[ROLL] += 0.1f * delta;
ent->priv.sv->client->ps.vmodel.angles[i] += 0.2 * delta;
}
// gun height
VectorClear( ent->priv.sv->client->ps.vmodel.offset );
for( i = 0; i < 3; i++ )
{
ent->priv.sv->client->ps.vmodel.offset[i] += forward[i];
ent->priv.sv->client->ps.vmodel.offset[i] += right[i];
ent->priv.sv->client->ps.vmodel.offset[i] += up[i] * -1;
}
}
void SV_CalcViewOffset (edict_t *ent)
{
float *angles;
@ -143,7 +95,7 @@ void SV_CalcViewOffset (edict_t *ent)
vec3_t v;
// base angles
angles = ent->priv.sv->client->ps.kick_angles;
angles = ent->priv.sv->client->ps.punch_angles;
VectorCopy(ent->progs.sv->punchangle, angles);
// add angles based on velocity
@ -180,14 +132,9 @@ void SV_CalcViewOffset (edict_t *ent)
VectorCopy( v, ent->priv.sv->client->ps.viewoffset );
}
void SV_SetStats (edict_t *ent)
{
ent->priv.sv->client->ps.stats[STAT_HEALTH] = ent->progs.sv->health;
}
void ClientEndServerFrame (edict_t *ent)
{
float bobtime;
float bobtime = 0;
current_player = ent;
current_client = ent->priv.sv->client;
@ -222,11 +169,7 @@ void ClientEndServerFrame (edict_t *ent)
//
xyspeed = sqrt(ent->progs.sv->velocity[0] * ent->progs.sv->velocity[0] + ent->progs.sv->velocity[1] * ent->progs.sv->velocity[1]);
if (xyspeed < 5)
{
bobmove = 0;
current_client->ps.bobtime = 0; // start at beginning of cycle again
}
if( xyspeed < 5 ) bobmove = 0;
else if (ent->progs.sv->groundentity)
{
// so bobbing only cycles when on ground
@ -235,7 +178,7 @@ void ClientEndServerFrame (edict_t *ent)
else bobmove = 0.0625;
}
bobtime = (current_client->ps.bobtime += bobmove);
bobtime += bobmove;
if (current_client->ps.pm_flags & PMF_DUCKED)
bobtime *= 4;
@ -245,16 +188,6 @@ void ClientEndServerFrame (edict_t *ent)
// determine the view offsets
SV_CalcViewOffset (ent);
// determine the gun offsets
SV_CalcGunOffset (ent);
SV_SetStats( ent );
// if the scoreboard is up, update it
if (!(sv.framenum & 31))
{
}
}
/*
@ -284,110 +217,8 @@ Advances the world by 0.1 seconds
*/
void SV_RunFrame( void )
{
int i;
edict_t *ent;
// let the progs know that a new frame has started
prog->globals.sv->pev = PRVM_EDICT_TO_PROG(prog->edicts);
prog->globals.sv->other = PRVM_EDICT_TO_PROG(prog->edicts);
prog->globals.sv->time = sv.time;
prog->globals.sv->frametime = sv.frametime;
PRVM_ExecuteProgram (prog->globals.sv->StartFrame, "StartFrame");
for (i = 1; i < prog->num_edicts; i++ )
{
ent = PRVM_EDICT_NUM(i);
if (ent->priv.sv->free) continue;
VectorCopy (ent->progs.sv->origin, ent->progs.sv->old_origin);
// don't apply phys on clients
if (i > 0 && i <= maxclients->value) continue;
SV_Physics( ent );
}
// build the playerstate_t structures for all players
ClientEndServerFrames ();
prog->globals.sv->pev = PRVM_EDICT_TO_PROG(prog->edicts);
prog->globals.sv->other = PRVM_EDICT_TO_PROG(prog->edicts);
prog->globals.sv->time = sv.time;
PRVM_ExecuteProgram (prog->globals.sv->EndFrame, "EndFrame");
// decrement prog->num_edicts if the highest number entities died
for ( ;PRVM_EDICT_NUM(prog->num_edicts - 1)->priv.sv->free; prog->num_edicts-- );
}
bool SV_ClientConnect (edict_t *ent, char *userinfo)
{
// they can connect
ent->progs.sv->flags = 0; // make sure we start with known default
ent->progs.sv->health = 100;
MsgDev(D_NOTE, "SV_ClientConnect()\n");
prog->globals.sv->time = sv.time;
prog->globals.sv->pev = PRVM_EDICT_TO_PROG(ent);
PRVM_ExecuteProgram (prog->globals.sv->ClientConnect, "ClientConnect");
return true;
}
void SV_ClientUserinfoChanged (edict_t *ent, char *userinfo)
{
char *s;
int playernum;
// check for malformed or illegal info strings
if (!Info_Validate(userinfo))
{
strcpy (userinfo, "\\name\\badinfo\\skin\\male/grunt");
}
// set skin
s = Info_ValueForKey (userinfo, "skin");
playernum = PRVM_NUM_FOR_EDICT(ent);
// combine name and skin into a configstring
SV_ConfigString (CS_PLAYERSKINS + playernum, va("%s\\%s", Info_ValueForKey (userinfo, "name"), Info_ValueForKey (userinfo, "skin")));
ent->priv.sv->client->ps.fov = bound(1, atoi(Info_ValueForKey(userinfo, "fov")), 160);
}
/*
===========
SV_ClientBegin
called when a client has finished connecting, and is ready
to be placed into the game. This will happen every level load.
============
*/
void SV_ClientBegin (edict_t *ent)
{
int i;
// if there is already a body waiting for us (a loadgame), just
// take it, otherwise spawn one from scratch
if (ent->priv.sv->free)
{
// the client has cleared the client side viewangles upon
// connecting to the server, which is different than the
// state when the game is saved, so we need to compensate
// with deltaangles
for (i = 0; i < 3; i++)
ent->priv.sv->client->ps.delta_angles[i] = ANGLE2SHORT(ent->priv.sv->client->ps.viewangles[i]);
}
else
{
// a spawn point will completely reinitialize the entity
// except for the persistant data that was initialized at
// ClientConnect() time
SV_InitEdict (ent);
SV_PutClientInServer (ent);
}
// make sure all view stuff is valid
ClientEndServerFrame (ent);
;
//ClientEndServerFrames();
}
/*
@ -461,8 +292,8 @@ void ClientThink (edict_t *ent, usercmd_t *ucmd)
VectorCopy(pm.maxs, ent->progs.sv->maxs);
VectorCopy(pm.ps.viewangles, ent->progs.sv->v_angle);
VectorCopy(pm.ps.viewangles, ent->progs.sv->angles);
if( pm.ps.groundentity )
ent->progs.sv->groundentity = PRVM_EDICT_TO_PROG( pm.ps.groundentity );
if( pm.groundentity )
ent->progs.sv->groundentity = PRVM_EDICT_TO_PROG( pm.groundentity );
else ent->progs.sv->groundentity = 0;
// copy viewmodel info
@ -470,8 +301,6 @@ void ClientThink (edict_t *ent, usercmd_t *ucmd)
client->ps.vmodel.body = ent->progs.sv->v_body;
client->ps.vmodel.skin = ent->progs.sv->v_skin;
client->ps.vmodel.sequence = ent->progs.sv->v_sequence;
VectorCopy(ent->progs.sv->v_offset, client->ps.vmodel.offset );
VectorCopy(ent->progs.sv->v_angles, client->ps.vmodel.angles );
SV_LinkEdict(ent);
@ -506,31 +335,6 @@ void ClientThink (edict_t *ent, usercmd_t *ucmd)
PRVM_ExecuteProgram (prog->globals.sv->PlayerPostThink, "PlayerPostThink");
}
/*
===========
SV_ClientDisconnect
Called when a player drops from the server.
Will not be called between levels.
============
*/
void SV_ClientDisconnect (edict_t *ent)
{
int playernum;
if (!ent->priv.sv->client) return;
SV_UnlinkEdict(ent);
ent->progs.sv->modelindex = 0;
ent->progs.sv->solid = SOLID_NOT;
ent->priv.sv->free = true;
ent->progs.sv->classname = PRVM_SetEngineString("disconnected");
playernum = PRVM_NUM_FOR_EDICT(ent) - 1;
SV_ConfigString (CS_PLAYERSKINS + playernum, "");
}
/*
==================
SV_StartParticle
@ -538,203 +342,7 @@ SV_StartParticle
Make sure the event gets sent to all clients
==================
*/
void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count)
void SV_StartParticle( vec3_t org, vec3_t dir, int color, int count )
{
MsgDev( D_ERROR, "SV_StartParticle: implement me\n");
}
/*
===============
PF_cprintf
Print to a single client
===============
*/
void PF_cprintf (edict_t *ent, int level, char *fmt, ...)
{
char msg[1024];
va_list argptr;
int n;
if (ent)
{
n = PRVM_NUM_FOR_EDICT(ent);
if (n < 1 || n > maxclients->value)
Host_Error("cprintf to a non-client\n");
}
va_start (argptr,fmt);
com.vsprintf (msg, fmt, argptr);
va_end (argptr);
if (ent) SV_ClientPrintf (svs.clients+(n-1), level, "%s", msg);
else Msg ("%s", msg);
}
/*
==================
Cmd_Say_f
==================
*/
void Cmd_Say_f (edict_t *ent, bool team, bool arg0)
{
int j;
edict_t *other;
char *p;
char text[2048];
if (Cmd_Argc () < 2 && !arg0) return;
com.sprintf (text, "%s: ", "all");
if (arg0)
{
strcat (text, Cmd_Argv(0));
strcat (text, " ");
strcat (text, Cmd_Args());
}
else
{
p = Cmd_Args();
if (*p == '"')
{
p++;
p[strlen(p)-1] = 0;
}
strcat(text, p);
}
// don't let text be too long for malicious reasons
if (strlen(text) > 150) text[150] = 0;
com.strcat(text, "\n");
if( host.type == HOST_DEDICATED )
PF_cprintf(NULL, PRINT_CHAT, "%s", text);
for (j = 1; j <= maxclients->value; j++)
{
other = PRVM_EDICT_NUM(j);
if (other->priv.sv->free) continue;
if (!other->priv.sv->client) continue;
PF_cprintf(other, PRINT_CHAT, "%s", text);
}
}
/*
=================
SV_ClientCommand
=================
*/
void SV_ClientCommand (edict_t *ent)
{
char *cmd;
char *parm;
if (!ent->priv.sv->client) return; // not fully in game yet
cmd = Cmd_Argv(0);
if(Cmd_Argc() < 2) parm = NULL;
else parm = Cmd_Argv(1);
if (strcasecmp (cmd, "say") == 0)
{
Cmd_Say_f (ent, false, false);
return;
}
if (strcasecmp (cmd, "say_team") == 0)
{
Cmd_Say_f (ent, true, false);
return;
}
}
void SV_Transform( sv_edict_t *ed, matrix4x3 transform )
{
edict_t *edict;
vec3_t origin, angles;
matrix4x4 objmatrix;
if(!ed) return;
edict = PRVM_EDICT_NUM( ed->serialnumber );
// save matrix (fourth value will be reset on save\load)
VectorCopy( transform[0], edict->progs.sv->m_pmatrix[0] );
VectorCopy( transform[1], edict->progs.sv->m_pmatrix[1] );
VectorCopy( transform[2], edict->progs.sv->m_pmatrix[2] );
VectorCopy( transform[3], edict->progs.sv->m_pmatrix[3] );
MatrixLoadIdentity( objmatrix );
VectorCopy( transform[0], objmatrix[0] );
VectorCopy( transform[1], objmatrix[1] );
VectorCopy( transform[2], objmatrix[2] );
VectorCopy( transform[3], objmatrix[3] );
MatrixAngles( objmatrix, origin, angles );
VectorCopy( origin, edict->progs.sv->origin );
VectorCopy( angles, edict->progs.sv->angles );
// refresh force and torque
pe->GetForce( ed->physbody, edict->progs.sv->velocity, edict->progs.sv->avelocity, edict->progs.sv->force, edict->progs.sv->torque );
pe->GetMassCentre( ed->physbody, edict->progs.sv->m_pcentre );
}
/*
==============
CV_ClientMove
grab user cmd from player_state_t
send it to transform callback
==============
*/
void SV_PlayerMove( sv_edict_t *ed )
{
pmove_t pm;
sv_client_t *client;
edict_t *player;
client = ed->client;
player = PRVM_PROG_TO_EDICT( ed->serialnumber );
memset( &pm, 0, sizeof(pm) );
if( player->progs.sv->movetype == MOVETYPE_NOCLIP )
client->ps.pm_type = PM_SPECTATOR;
else client->ps.pm_type = PM_NORMAL;
client->ps.gravity = sv_gravity->value;
if( player->progs.sv->teleport_time )
client->ps.pm_flags |= PMF_TIME_TELEPORT;
else client->ps.pm_flags &= ~PMF_TIME_TELEPORT;
pm.ps = client->ps;
pm.cmd = client->lastcmd;
pm.body = ed->physbody; // member body ptr
VectorCopy( player->progs.sv->origin, pm.ps.origin );
VectorCopy( player->progs.sv->velocity, pm.ps.velocity );
pe->ServerMove( &pm );
// save results of pmove
client->ps = pm.ps;
VectorCopy(pm.ps.origin, player->progs.sv->origin);
VectorCopy(pm.ps.velocity, player->progs.sv->velocity);
VectorCopy(pm.mins, player->progs.sv->mins);
VectorCopy(pm.maxs, player->progs.sv->maxs);
VectorCopy(pm.ps.viewangles, client->ps.viewangles);
}
void SV_PlaySound( sv_edict_t *ed, float volume, const char *sample )
{
float vol = bound( 0.0f, volume/255.0f, 255.0f );
int sound_idx = SV_SoundIndex( sample );
edict_t *ent;
if( !ed ) ed = prog->edicts->priv.sv;
ent = PRVM_PROG_TO_EDICT( ed->serialnumber );
//SV_StartSound( ent->progs.sv->origin, ent, CHAN_BODY, sound_idx, vol, 1.0f, 0 );
}
}

View File

@ -1,35 +0,0 @@
//=======================================================================
// Copyright XashXT Group 2007 ©
// sv_studio.c - cm inline studio
//=======================================================================
#include "common.h"
#include "server.h"
// g-cont: my stupid callbacks
cmodel_t *SV_GetModelPtr( edict_t *ent )
{
return pe->RegisterModel( sv.configstrings[CS_MODELS + (int)ent->progs.sv->modelindex] );
}
float *SV_GetModelVerts( sv_edict_t *ed, int *numvertices )
{
cmodel_t *cmod;
edict_t *ent;
ent = PRVM_EDICT_NUM(ed->serialnumber);
cmod = pe->RegisterModel( sv.configstrings[CS_MODELS + (int)ent->progs.sv->modelindex] );
if( cmod )
{
int i = (int)ent->progs.sv->body;
i = bound( 0, i, cmod->numbodies ); // make sure what body exist
if( cmod->physmesh[i].verts )
{
*numvertices = cmod->physmesh[i].numverts;
return (float *)cmod->physmesh[i].verts;
}
}
return NULL;
}

View File

@ -217,8 +217,8 @@ void SV_LinkEdict( edict_t *ent )
}
else
{ // normal
VectorAdd (ent->progs.sv->origin, ent->progs.sv->mins, ent->progs.sv->absmin);
VectorAdd (ent->progs.sv->origin, ent->progs.sv->maxs, ent->progs.sv->absmax);
VectorAdd( ent->progs.sv->origin, ent->progs.sv->mins, ent->progs.sv->absmin );
VectorAdd( ent->progs.sv->origin, ent->progs.sv->maxs, ent->progs.sv->absmax );
}
// because movement is clipped an epsilon away from an actual edge,
@ -266,7 +266,7 @@ void SV_LinkEdict( edict_t *ent )
// store as many explicit clusters as we can
sv_ent->num_clusters = 0;
for (i = 0; i < num_leafs; i++)
for( i = 0; i < num_leafs; i++ )
{
cluster = pe->LeafCluster( leafs[i] );
if( cluster )
@ -281,24 +281,24 @@ void SV_LinkEdict( edict_t *ent )
if( i != num_leafs ) sv_ent->lastcluster = pe->LeafCluster( lastleaf );
// if first time, make sure old_origin is valid
if(!ent->priv.sv->linkcount)
if( !ent->priv.sv->linkcount )
{
VectorCopy (ent->progs.sv->origin, ent->progs.sv->old_origin);
VectorCopy( ent->progs.sv->origin, ent->progs.sv->old_origin );
}
ent->priv.sv->linkcount++;
// don't link not solid or rigid bodies
if (ent->progs.sv->solid == SOLID_NOT || ent->progs.sv->solid >= SOLID_BOX)
if( ent->progs.sv->solid == SOLID_NOT || ent->progs.sv->solid >= SOLID_BOX )
return;
// find the first world sector node that the ent's box crosses
node = sv_worldsectors;
while( 1 )
{
if (node->axis == -1) break;
if (ent->progs.sv->absmin[node->axis] > node->dist)
if( node->axis == -1 ) break;
if( ent->progs.sv->absmin[node->axis] > node->dist )
node = node->children[0];
else if (ent->progs.sv->absmax[node->axis] < node->dist)
else if( ent->progs.sv->absmax[node->axis] < node->dist )
node = node->children[1];
else break; // crosses the node
}
@ -372,241 +372,4 @@ int SV_AreaEdicts( const vec3_t mins, const vec3_t maxs, edict_t **list, int max
SV_AreaEdicts_r( sv_worldsectors, &ap );
return ap.count;
}
//===========================================================================
typedef struct
{
vec3_t boxmins, boxmaxs;// enclose the test object along entire move
const float *mins, *maxs;
const float *start;
vec3_t end;
trace_t trace;
edict_t *passedict;
int contentmask;
} moveclip_t;
/*
====================
SV_ClipMoveToEntities
====================
*/
void SV_ClipMoveToEntities( moveclip_t *clip )
{
int i, num;
edict_t **touchlist, *touch;
trace_t trace;
cmodel_t *cmodel;
float *origin, *angles;
// list of pointers, not data
touchlist = Z_Malloc( sizeof(*touchlist) * host.max_edicts );
num = SV_AreaEdicts( clip->boxmins, clip->boxmaxs, touchlist, host.max_edicts );
for( i = 0; i < num; i++ )
{
if( clip->trace.allsolid ) return;
touch = touchlist[i];
if( touch == clip->passedict ) continue;
if( touch->progs.sv->solid == SOLID_NOT ) continue;
if( clip->passedict )
{
if (PRVM_PROG_TO_EDICT(touch->progs.sv->owner) == clip->passedict)
continue; // don't clip against own missiles
if (PRVM_PROG_TO_EDICT(clip->passedict->progs.sv->owner) == touch)
continue; // don't clip against owner
}
if(!(clip->contentmask & CONTENTS_DEADMONSTER) && ((int)touch->progs.sv->flags & FL_DEADMONSTER))
continue;
cmodel = SV_GetModelPtr( touch );
origin = touch->progs.sv->origin;
angles = touch->progs.sv->angles;
if( !touch->progs.sv->solid == SOLID_BSP ) angles = vec3_origin; // boxes don't rotate
trace = pe->TransformedBoxTrace((float *)clip->start, (float *)clip->end, (float *)clip->mins, (float *)clip->maxs, cmodel, clip->contentmask, origin, angles, false );
if( trace.allsolid )
{
clip->trace.allsolid = true;
trace.ent = touch;
}
else if( trace.startsolid )
{
clip->trace.startsolid = true;
trace.ent = touch;
}
if( trace.fraction < clip->trace.fraction )
{
bool oldStart;
// make sure we keep a startsolid from a previous trace
oldStart = clip->trace.startsolid;
trace.ent = touch;
clip->trace = trace;
clip->trace.startsolid |= oldStart;
}
}
Mem_Free( touchlist );
}
/*
==================
SV_Trace
Moves the given mins/maxs volume through the world from start to end.
passEntityNum and entities owned by passEntityNum are explicitly not checked.
==================
*/
trace_t SV_Trace( const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, edict_t *passedict, int contentmask )
{
moveclip_t clip;
int i;
if( !mins ) mins = vec3_origin;
if( !maxs ) maxs = vec3_origin;
memset( &clip, 0, sizeof( moveclip_t ));
// clip to world
pe->BoxTrace( start, end, mins, maxs, NULL, &clip.trace, contentmask );
clip.trace.ent = clip.trace.fraction != 1.0 ? prog->edicts : NULL;
if( clip.trace.fraction == 0 ) return clip.trace; // blocked immediately by the world
clip.contentmask = contentmask;
clip.start = start;
VectorCopy( end, clip.end );
clip.mins = mins;
clip.maxs = maxs;
clip.passedict = passedict;
// create the bounding box of the entire move
// we can limit it to the part of the move not
// already clipped off by the world, which can be
// a significant savings for line of sight and shot traces
for( i = 0; i < 3; i++ )
{
if( end[i] > start[i] )
{
clip.boxmins[i] = clip.start[i] + clip.mins[i] - 1;
clip.boxmaxs[i] = clip.end[i] + clip.maxs[i] + 1;
}
else
{
clip.boxmins[i] = clip.end[i] + clip.mins[i] - 1;
clip.boxmaxs[i] = clip.start[i] + clip.maxs[i] + 1;
}
}
// clip to other solid entities
SV_ClipMoveToEntities( &clip );
return clip.trace;
}
trace_t SV_TraceToss (edict_t *tossent, edict_t *ignore)
{
int i;
float gravity = 1.0;
vec3_t move, end;
vec3_t original_origin;
vec3_t original_velocity;
vec3_t original_angles;
vec3_t original_avelocity;
trace_t trace;
VectorCopy(tossent->progs.sv->origin, original_origin);
VectorCopy(tossent->progs.sv->velocity, original_velocity);
VectorCopy(tossent->progs.sv->angles, original_angles);
VectorCopy(tossent->progs.sv->avelocity, original_avelocity);
gravity *= sv_gravity->value * 0.05;
for (i = 0; i < 200; i++) // LordHavoc: sanity check; never trace more than 10 seconds
{
SV_CheckVelocity (tossent);
tossent->progs.sv->velocity[2] -= gravity;
VectorMA (tossent->progs.sv->angles, 0.05, tossent->progs.sv->avelocity, tossent->progs.sv->angles);
VectorScale (tossent->progs.sv->velocity, 0.05, move);
VectorAdd (tossent->progs.sv->origin, move, end);
trace = SV_Trace(tossent->progs.sv->origin, tossent->progs.sv->mins, tossent->progs.sv->maxs, end, tossent, MASK_SOLID );
VectorCopy (trace.endpos, tossent->progs.sv->origin);
if (trace.fraction < 1) break;
}
VectorCopy(original_origin, tossent->progs.sv->origin);
VectorCopy(original_velocity, tossent->progs.sv->velocity);
VectorCopy(original_angles, tossent->progs.sv->angles);
VectorCopy(original_avelocity, tossent->progs.sv->avelocity);
return trace;
}
trace_t SV_ClipMoveToEntity(edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int contentsmask)
{
edict_t *touch;
cmodel_t *cmodel;
float *origin, *angles;
trace_t trace;
touch = ent;
memset( &trace, 0, sizeof(trace_t));
// if it doesn't have any brushes of a type we
// are looking for, ignore it
if(!(contentsmask & CONTENTS_DEADMONSTER) && ((int)touch->progs.sv->flags & FL_DEADMONSTER))
{
trace.fraction = 1.0;
return trace;
}
// might intersect, so do an exact clip
cmodel = SV_GetModelPtr( touch );
origin = touch->progs.sv->origin;
angles = touch->progs.sv->angles;
if( !touch->progs.sv->solid == SOLID_BSP ) angles = vec3_origin; // boxes don't rotate
trace = pe->TransformedBoxTrace( start, end, mins, maxs, cmodel, contentsmask, origin, angles, true );
if( trace.fraction < 1.0f ) trace.ent = touch;
return trace;
}
/*
=============
SV_PointContents
=============
*/
int SV_PointContents( const vec3_t p, edict_t *passedict )
{
edict_t **touch, *hit;
int i, num;
int contents, c2;
cmodel_t *cmodel;
float *angles;
touch = Z_Malloc( sizeof(*touch) * host.max_edicts );
// get base contents from world
contents = pe->PointContents( p, NULL );
// or in contents from all the other entities
num = SV_AreaEdicts( p, p, touch, host.max_edicts );
for( i = 0; i < num; i++ )
{
if ( touch[i] == passedict ) continue;
hit = touch[i];
// might intersect, so do an exact clip
cmodel = SV_GetModelPtr( hit );
angles = hit->progs.sv->angles;
if( !hit->progs.sv->solid == SOLID_BSP ) angles = vec3_origin; // boxes don't rotate
c2 = pe->TransformedPointContents( p, cmodel, hit->progs.sv->origin, angles );
contents |= c2;
}
Mem_Free( touch );
return contents;
}

View File

@ -10,11 +10,11 @@ byte *zonepool;
int app_name = 0;
cvar_t *img_resample_lerp;
void ImageLib_Init ( uint funcname )
void ImageLib_Init ( void )
{
// init pools
zonepool = Mem_AllocPool( "ImageLib Pool" );
app_name = funcname;
app_name = g_Instance;
img_resample_lerp = Cvar_Get( "img_lerping", "1", CVAR_SYSTEMINFO, "lerping images after resample" );
}

View File

@ -10,10 +10,10 @@
Base Entry Point
=================
*/
DLLEXPORT int CreateAPI( char *funcname, bool console )
DLLEXPORT int CreateAPI( char *hostname, bool console )
{
// memeber name
com_strncpy( Sys.progname, funcname, sizeof(Sys.progname));
com_strncpy( Sys.progname, hostname, sizeof(Sys.progname));
Sys.hooked_out = console; // set mode
Sys_Init();

View File

@ -27,7 +27,7 @@ static const char *show_credits = "\n\n\n\n\tCopyright XashXT Group 2007
All Rights Reserved\n\n\t Visit www.xash.ru\n";
// stubs
void NullInit( uint funcname, int argc, char **argv ) {}
void NullInit( int argc, char **argv ) {}
void NullFunc( void ) {}
void Sys_NullPrint( const char *msg ) {}
@ -382,6 +382,9 @@ void Sys_LookupInstance( void )
com_sprintf(Sys.log_path, "%s/source.log", sys_rootdir ); // default
com_strcpy(Sys.caption, va("QuakeC Decompiler ver.%g", XASH_VERSION ));
}
// share instance over all system
GI.instance = Sys.app_name;
}
/*
@ -443,7 +446,7 @@ void Sys_CreateInstance( void )
}
// init our host now!
Sys.Init( Sys.app_name, fs_argc, fs_argv );
Sys.Init( fs_argc, fs_argv );
// post initializations
switch(Sys.app_name)

View File

@ -68,7 +68,7 @@ typedef struct system_s
double start, end;
void (*Con_Print)( const char *msg );
void ( *Init ) ( uint funcname, int argc, char **argv );
void ( *Init ) ( int argc, char **argv );
void ( *Main ) ( void ); // host frame
void ( *Free ) ( void ); // close host
void (*CPrint)( const char *msg ); // console print

View File

@ -25,7 +25,7 @@
{ return CreateMain32()( #prog, FALSE ); }
// engine entry point format
typedef int (*winmain_t)( char *funcname, int console );
typedef int (*winmain_t)( char *hostname, int console );
char szSearch[ 5 ][ 1024 ];
char szFsPath[ 4096 ];
HINSTANCE hmain;

View File

@ -1364,7 +1364,7 @@ void CM_CollisionClipTrace_Box( trace_t *trace, const vec3_t cmins, const vec3_t
//===========================================
void CM_CollisionClipToGenericEntity( trace_t *trace, cmodel_t *model, int frame, const vec3_t bodymins, const vec3_t bodymaxs, int bodysupercontents, matrix4x4 matrix, matrix4x4 inversematrix, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int hitsupercontentsmask )
void CM_CollisionClipToGenericEntity( trace_t *trace, cmodel_t *model, const vec3_t bodymins, const vec3_t bodymaxs, int bodysupercontents, matrix4x4 matrix, matrix4x4 inversematrix, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int hitsupercontentsmask )
{
float tempnormal[3];
float starttransformed[3];

View File

@ -59,9 +59,11 @@ typedef struct cbsp_s
typedef struct cnode_s
{
// this part shared between node and leaf
struct cnode_s *parent;
cplane_t *plane; // always != NULL
vec3_t mins;
vec3_t maxs;
int contents; // combined contents for node
// this part unique to node
struct cnode_s *children[2];
@ -70,16 +72,20 @@ typedef struct cnode_s
typedef struct cleaf_s
{
// this part shared between node and leaf
struct cnode_s *parent;
cplane_t *plane; // always == NULL
vec3_t mins;
vec3_t maxs;
int contents; // combined contents for leaf
// this part unique to leaf
int contents;
int cluster;
int area;
int firstleafbrush;
bool havepatches; // leaf have collision patches (triangles)
int *firstleafbrush;
int numleafbrushes;
int numleafsurfaces;
int *firstleafsurface;
} cleaf_t;
typedef struct
@ -146,6 +152,7 @@ typedef struct clipmap_s
cplane_t *planes; // 12 extra planes for box hull
cleaf_t *leafs; // 1 extra leaf for box hull
dword *leafbrushes;
dword *leafsurfaces;
cnode_t *nodes; // 6 extra planes for box hull
dvertex_t *vertices;
dedge_t *edges;
@ -162,23 +169,20 @@ typedef struct clipmap_s
carea_t *areas;
dareaportal_t *areaportals;
csurface_t nullsurface;
int numbrushsides;
int numtexinfo;
int numplanes;
int numbmodels;
int numnodes;
int numleafs; // allow leaf funcs to be called without a map
int emptyleaf;
int solidleaf;
int numleafbrushes;
int numleafsurfaces;
int numbrushes;
int numfaces;
int numareas;
int numareaportals;
int numclusters;
int floodvalid;
int num_models;
// misc stuff
NewtonBody *body;
@ -189,7 +193,6 @@ typedef struct clipmap_s
collide_info_t touch_info; // global info about two touching objects
bool loaded; // map is loaded?
bool tree_build; // phys tree is created ?
bool use_thread; // bsplib use thread
vfile_t *world_tree; // pre-calcualated collision tree (worldmodel only)
trace_t trace; // contains result of last trace
int checkcount;
@ -211,32 +214,14 @@ typedef struct studio_s
matrix3x4 rotmatrix;
matrix3x4 bones[MAXSTUDIOBONES];
vec3_t vertices[MAXSTUDIOVERTS];
vec3_t transform[MAXSTUDIOVERTS];
vec3_t indices[MAXSTUDIOVERTS];
vec3_t vtransform[MAXSTUDIOVERTS];
vec3_t ntransform[MAXSTUDIOVERTS];
vec3_t *m_pVerts; // pointer to studio.vertices array
uint numtriangles;
uint bodycount;
} studio_t;
typedef struct convex_hull_s
{
vec3_t *m_pVerts; // pointer to studio.vertices array
uint numverts;
} convex_hull_t;
typedef struct box_s
{
cplane_t *planes;
cbrush_t *brush;
cmodel_t *model;
} box_t;
typedef struct mapleaf_s
{
int count;
int topnode;
int maxcount;
int *list;
float *mins;
float *maxs;
} mapleaf_t;
} studio_t;
typedef struct leaflist_s
{
@ -249,37 +234,8 @@ typedef struct leaflist_s
void (*storeleafs)( struct leaflist_s *ll, cnode_t *node );
} leaflist_t;
typedef struct sphere_s
{
bool use;
float radius;
float halfheight;
vec3_t offset;
} sphere_t;
typedef struct tracework_s
{
vec3_t start;
vec3_t end;
vec3_t mins;
vec3_t maxs;
vec3_t offsets[8]; // [signbits][x] = either size[0][x] or size[1][x]
float maxOffset; // longest corner length from origin
vec3_t bounds[2]; // enclosing box of start and end surrounding by size
vec3_t extents; // greatest of abs(size[0]) and abs(size[1])
vec3_t origin; // origin of the model tracing through
int contents; // trace contents
bool ispoint; // optimized case
trace_t result; // returned from trace call
sphere_t sphere; // sphere for oriendted capsule collision
} tracework_t;
extern clipmap_t cm;
extern studio_t studio;
extern convex_hull_t hull;
extern box_t box;
extern mapleaf_t leaf;
extern tracework_t maptrace;
extern physic_t ph;
extern cvar_t *cm_noareas;
@ -354,13 +310,13 @@ void CM_CollisionTraceLineTriangleFloat( trace_t *trace, const vec3_t linestart,
// entities, only colliding with SOLID_BSP entities (doors, lifts)
//
// passedict is excluded from clipping checks
void CM_CollisionClipToGenericEntity( trace_t *trace, cmodel_t *model, int frame, const vec3_t bodymins, const vec3_t bodymaxs, int bodysupercontents, matrix4x4 matrix, matrix4x4 inversematrix, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int hitcontentsmask );
void CM_CollisionClipToGenericEntity( trace_t *trace, cmodel_t *model, const vec3_t bodymins, const vec3_t bodymaxs, int bodysupercontents, matrix4x4 matrix, matrix4x4 inversematrix, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int hitcontentsmask );
// like above but does not do a transform and does nothing if model is NULL
void CM_CollisionClipToWorld( trace_t *trace, cmodel_t *model, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int hitsupercontents );
// combines data from two traces:
// merges contents flags, startsolid, allsolid, inwater
// updates fraction, endpos, plane and surface info if new fraction is shorter
void CM_CollisionCombineTraces( trace_t *cliptrace, const trace_t *trace, void *touch, bool is_bmodel );
void CM_CollisionCombineTraces( trace_t *cliptrace, const trace_t *trace, edict_t *touch, bool is_bmodel );
void CM_CollisionDrawForEachBrush( void );
void CM_CollisionInit( void );

View File

@ -7,10 +7,6 @@
clipmap_t cm;
studio_t studio;
convex_hull_t hull;
box_t box;
mapleaf_t leaf;
tracework_t maptrace;
cvar_t *cm_noareas;
cmodel_t *loadmodel;
@ -86,8 +82,8 @@ CM_FreeModel
void CM_FreeModel( cmodel_t *mod )
{
Mem_FreePool( &mod->mempool );
memset(mod->physmesh, 0, MAXSTUDIOMODELS * sizeof(cmesh_t));
memset(mod, 0, sizeof(*mod));
memset( mod->col, 0, MAXSTUDIOMODELS * sizeof(*mod->col[0]));
memset( mod, 0, sizeof(*mod));
mod = NULL;
}
@ -116,20 +112,26 @@ void BSP_CreateMeshBuffer( int modelnum )
int flags;
// ignore world or bsplib instance
if(cm.use_thread || modelnum < 1 || modelnum >= cm.num_models)
if( app_name == COMP_BSPLIB || modelnum >= cm.numbmodels )
return;
loadmodel = &cm.bmodels[modelnum];
loadmodel->type = mod_brush;
hull.m_pVerts = &studio.vertices[0]; // using studio vertex buffer for bmodels too
hull.numverts = 0; // clear current count
if( modelnum ) loadmodel->type = mod_brush;
loadmodel->type = mod_static; // level static geometry
loadmodel->TraceBox = CM_TraceBmodel;
loadmodel->PointContents = CM_PointContents;
// because world loading collision tree from LUMP_COLLISION
if( modelnum < 1 ) return;
studio.m_pVerts = &studio.vertices[0]; // using studio vertex buffer for bmodels too
studio.numverts = 0; // clear current count
for( d = 0, i = loadmodel->firstface; d < loadmodel->numfaces; i++, d++ )
{
vec3_t *face;
m_face = cm.surfaces + i;
flags = cm.surfdesc[m_face->desc].flags;
flags = cm.surfdesc[m_face->desc].surfaceflags;
k = m_face->firstedge;
// sky is noclip for all physobjects
@ -137,17 +139,19 @@ void BSP_CreateMeshBuffer( int modelnum )
face = Mem_Alloc( loadmodel->mempool, m_face->numedges * sizeof(vec3_t));
for(j = 0; j < m_face->numedges; j++ )
{
CM_GetPoint2( k+j, hull.m_pVerts[hull.numverts] );
hull.numverts++;
// because it's not a collision tree, just triangle mesh
CM_GetPoint2( k+j, studio.m_pVerts[studio.numverts] );
studio.numverts++;
}
if( face ) Mem_Free( face ); // faces with 0 edges ?
}
if( hull.numverts )
if( studio.numverts )
{
// grab vertices
loadmodel->physmesh[loadmodel->numbodies].verts = Mem_Alloc( loadmodel->mempool, hull.numverts * sizeof(vec3_t));
Mem_Copy( loadmodel->physmesh[loadmodel->numbodies].verts, hull.m_pVerts, hull.numverts * sizeof(vec3_t));
loadmodel->physmesh[loadmodel->numbodies].numverts = hull.numverts;
loadmodel->col[loadmodel->numbodies] = (cmesh_t *)Mem_Alloc( loadmodel->mempool, sizeof(*loadmodel->col[0]));
loadmodel->col[loadmodel->numbodies]->verts = Mem_Alloc( loadmodel->mempool, studio.numverts * sizeof(vec3_t));
Mem_Copy( loadmodel->col[loadmodel->numbodies]->verts, studio.m_pVerts, studio.numverts * sizeof(vec3_t));
loadmodel->col[loadmodel->numbodies]->numverts = studio.numverts;
loadmodel->numbodies++;
}
}
@ -159,15 +163,15 @@ void BSP_LoadModels( lump_t *l )
int i, j, n, c, count;
in = (void *)(cm.mod_base + l->fileofs);
if (l->filelen % sizeof(*in)) Host_Error("CMod_LoadModels: funny lump size\n");
if (l->filelen % sizeof(*in)) Host_Error("BSP_LoadModels: funny lump size\n");
count = l->filelen / sizeof(*in);
if(count < 1) Host_Error("Map %s without models\n", cm.name );
if(count > MAX_MODELS ) Host_Error("Map %s has too many models\n", cm.name );
cm.numbmodels = cm.num_models = count;
cm.numbmodels = count;
out = &cm.bmodels[0];
for ( i = 0; i < count; i++, in++, out++)
for ( i = 0; i < count; i++, in++, out++ )
{
for( j = 0; j < 3; j++ )
{
@ -175,14 +179,23 @@ void BSP_LoadModels( lump_t *l )
out->mins[j] = LittleFloat(in->mins[j]) - 1;
out->maxs[j] = LittleFloat(in->maxs[j]) + 1;
}
// FIXME: calc bounding box right
VectorCopy( out->mins, out->normalmins );
VectorCopy( out->maxs, out->normalmaxs );
VectorCopy( out->mins, out->rotatedmins );
VectorCopy( out->maxs, out->rotatedmaxs );
VectorCopy( out->mins, out->yawmins );
VectorCopy( out->maxs, out->yawmaxs );
out->firstface = n = LittleLong( in->firstface );
out->numfaces = c = LittleLong( in->numfaces );
if( n < 0 || n + c > cm.numfaces )
Host_Error("BSP_LoadModels: invalid face range %i : %i (%i faces)", n, n+c, cm.numfaces );
Host_Error("BSP_LoadModels: invalid face range %i : %i (%i faces)\n", n, n+c, cm.numfaces );
out->firstbrush = n = LittleLong( in->firstbrush );
out->numbrushes = c = LittleLong( in->numbrushes );
if( n < 0 || n + c > cm.numbrushes )
Host_Error("BSP_LoadModels: invalid brush range %i : %i (%i brushes)", n, n+c, cm.numfaces );
Host_Error("BSP_LoadModels: invalid brush range %i : %i (%i brushes)\n", n, n+c, cm.numfaces );
com.strncpy( out->name, va("*%i", i ), sizeof(out->name));
out->mempool = Mem_AllocPool( out->name );
BSP_CreateMeshBuffer( i ); // bsp physic
@ -209,9 +222,13 @@ void BSP_LoadSurfDesc( lump_t *l )
for ( i = 0; i < count; i++, in++, out++)
{
com.strncpy(out->name, CM_GetStringFromTable(LittleLong( in->texid )), MAX_STRING );
out->flags = LittleLong( in->flags );
com.strncpy( out->name, CM_GetStringFromTable(LittleLong( in->texid )), MAX_STRING );
out->surfaceflags = LittleLong( in->flags );
out->contentflags = 0;//FIXME: upgrade BSP version, that include contents for all sides
out->value = LittleLong( in->value );
// currently not used
VectorClear( out->mins );
VectorClear( out->maxs );
}
}
@ -227,7 +244,7 @@ void BSP_LoadNodes( lump_t *l )
int i, j, n, count;
in = (void *)(cm.mod_base + l->fileofs);
if (l->filelen % sizeof(*in)) Host_Error("CMod_LoadNodes: funny lump size\n");
if (l->filelen % sizeof(*in)) Host_Error("BSP_LoadNodes: funny lump size\n");
count = l->filelen / sizeof(*in);
if(count < 1) Host_Error("Map %s has no nodes\n", cm.name );
@ -236,6 +253,7 @@ void BSP_LoadNodes( lump_t *l )
for (i = 0; i < count; i++, out++, in++)
{
out->parent = NULL;
n = LittleLong( in->planenum );
if( n < 0 || n >= cm.numplanes)
Host_Error("BSP_LoadNodes: invalid planenum %i (%i planes)\n", n, cm.numplanes );
@ -246,14 +264,14 @@ void BSP_LoadNodes( lump_t *l )
if( n >= 0 )
{
if( n >= cm.numnodes )
Host_Error("BSP_LoadNodes: invalid child node index %i (%i nodes)", n, cm.numnodes );
Host_Error("BSP_LoadNodes: invalid child node index %i (%i nodes)\n", n, cm.numnodes );
out->children[j] = cm.nodes + n;
}
else
{
n = -1 - n;
if( n >= cm.numleafs )
Host_Error("BSP_LoadNodes: invalid child leaf index %i (%i leafs)", n, cm.numleafs );
Host_Error("BSP_LoadNodes: invalid child leaf index %i (%i leafs)\n", n, cm.numleafs );
out->children[j] = (cnode_t *)(cm.leafs + n);
}
}
@ -281,7 +299,7 @@ void BSP_LoadBrushes( lump_t *l )
cplanef_t *planes = NULL;
in = (void *)(cm.mod_base + l->fileofs);
if (l->filelen % sizeof(*in)) Host_Error("CMod_LoadBrushes: funny lump size\n");
if (l->filelen % sizeof(*in)) Host_Error("BSP_LoadBrushes: funny lump size\n");
count = l->filelen / sizeof(*in);
out = cm.brushes = (cbrush_t *)Mem_Alloc( cmappool, (count + 1) * sizeof(*out));
cm.numbrushes = count;
@ -303,7 +321,7 @@ void BSP_LoadBrushes( lump_t *l )
{
VectorCopy( cm.brushsides[out->firstbrushside + j].plane->normal, planes[j].normal );
planes[j].dist = cm.brushsides[out->firstbrushside + j].plane->dist;
planes[j].surfaceflags = cm.brushsides[out->firstbrushside + j].surface->flags;
planes[j].surfaceflags = cm.brushsides[out->firstbrushside + j].surface->surfaceflags;
planes[j].surface = cm.brushsides[out->firstbrushside + j].surface;
}
// make the colbrush from the planes
@ -313,85 +331,27 @@ void BSP_LoadBrushes( lump_t *l )
/*
=================
BSP_LoadLeafs
BSP_LoadLeafFaces
=================
*/
void BSP_LoadLeafs( lump_t *l )
void BSP_LoadLeafFaces( lump_t *l )
{
dleaf_t *in;
cleaf_t *out;
int i, j, count;
dword *in, *out;
int i, n, count;
in = (void *)(cm.mod_base + l->fileofs);
if (l->filelen % sizeof(*in)) Host_Error("CMod_LoadLeafs: funny lump size\n");
if (l->filelen % sizeof(*in)) Host_Error("BSP_LoadLeafFaces: funny lump size\n");
count = l->filelen / sizeof(*in);
if( count < 1 ) Host_Error("Map %s with no leafs\n", cm.name );
out = cm.leafs = (cleaf_t *)Mem_Alloc( cmappool, (count + 1) * sizeof(*out));
cm.numleafs = count;
cm.numclusters = 0;
for ( i = 0; i < count; i++, in++, out++)
out = cm.leafsurfaces = (dword *)Mem_Alloc( cmappool, count * sizeof(*out));
cm.numleafsurfaces = count;
for( i = 0; i < count; i++, in++, out++ )
{
out->plane = NULL;
out->firstleafbrush = LittleLong( in->firstleafbrush );
out->numleafbrushes = LittleLong( in->numleafbrushes );
out->contents = LittleLong( in->contents );
out->cluster = LittleLong( in->cluster );
out->area = LittleLong( in->area );
if( out->cluster >= cm.numclusters )
cm.numclusters = out->cluster + 1;
for( j = 0; j < 3; j++ )
{
// yes the mins/maxs are ints
out->mins[j] = LittleLong( in->mins[j] ) - 1;
out->maxs[j] = LittleLong( in->maxs[j] ) + 1;
}
}
// probably any wall it's liquid ?
if( cm.leafs[0].contents != CONTENTS_SOLID )
Host_Error("Map %s with leaf 0 is not CONTENTS_SOLID\n", cm.name );
cm.solidleaf = 0;
cm.emptyleaf = -1;
for( i = 1; i < count; i++ )
{
if(!cm.leafs[i].contents)
{
cm.emptyleaf = i;
break;
}
}
// stuck into brushes
if( cm.emptyleaf == -1 ) Host_Error("Map %s does not have an empty leaf\n", cm.name );
}
/*
=================
BSP_LoadPlanes
=================
*/
void BSP_LoadPlanes( lump_t *l )
{
dplane_t *in;
cplane_t *out;
int i, j, count;
in = (void *)(cm.mod_base + l->fileofs);
if (l->filelen % sizeof(*in)) Host_Error("CMod_LoadPlanes: funny lump size\n");
count = l->filelen / sizeof(*in);
if (count < 1) Host_Error("Map %s with no planes\n", cm.name );
out = cm.planes = (cplane_t *)Mem_Alloc( cmappool, (count + 12) * sizeof(*out));
cm.numplanes = count;
for ( i = 0; i < count; i++, in++, out++)
{
for (j = 0; j < 3; j++)
out->normal[j] = LittleFloat(in->normal[j]);
out->dist = LittleFloat( in->dist );
PlaneClassify( out ); // automatic plane classify
n = LittleShort(*in);
if( n < 0 || n >= cm.numfaces )
Host_Error("BSP_LoadLeafFaces: invalid face index %i (%i faces)\n", n, cm.numfaces );
*out = n;
}
}
@ -410,11 +370,105 @@ void BSP_LoadLeafBrushes( lump_t *l )
count = l->filelen / sizeof(*in);
if( count < 1 ) Host_Error("Map %s with no leaf brushes\n", cm.name );
out = cm.leafbrushes = (dword *)Mem_Alloc( cmappool, (count + 1) * sizeof(*out));
out = cm.leafbrushes = (dword *)Mem_Alloc( cmappool, count * sizeof(*out));
cm.numleafbrushes = count;
for ( i = 0; i < count; i++, in++, out++) *out = LittleShort(*in);
}
/*
=================
BSP_LoadLeafs
=================
*/
void BSP_LoadLeafs( lump_t *l )
{
dleaf_t *in;
cleaf_t *out;
int i, j, n, c, count;
int emptyleaf = -1;
in = (void *)(cm.mod_base + l->fileofs);
if (l->filelen % sizeof(*in)) Host_Error("BSP_LoadLeafs: funny lump size\n");
count = l->filelen / sizeof(*in);
if( count < 1 ) Host_Error("Map %s with no leafs\n", cm.name );
out = cm.leafs = (cleaf_t *)Mem_Alloc( cmappool, count * sizeof(*out));
cm.numleafs = count;
cm.numclusters = 0;
for ( i = 0; i < count; i++, in++, out++)
{
out->parent = NULL;
out->plane = NULL;
out->contents = LittleLong( in->contents );
out->cluster = LittleLong( in->cluster );
out->area = LittleLong( in->area );
if( out->cluster >= cm.numclusters )
cm.numclusters = out->cluster + 1;
for( j = 0; j < 3; j++ )
{
// yes the mins/maxs are ints
out->mins[j] = LittleLong( in->mins[j] ) - 1;
out->maxs[j] = LittleLong( in->maxs[j] ) + 1;
}
n = LittleLong( in->firstleafface );
c = LittleLong( in->numleaffaces );
if( n < 0 || n + c > cm.numleafsurfaces )
Host_Error("BSP_LoadLeafs: invalid leafsurface range %i : %i (%i leafsurfaces)\n", n, n + c, cm.numleafsurfaces);
out->firstleafsurface = cm.leafsurfaces + n;
out->numleafsurfaces = c;
n = LittleLong( in->firstleafbrush );
c = LittleLong( in->numleafbrushes );
if( n < 0 || n + c > cm.numleafbrushes )
Host_Error("BSP_LoadLeafs: invalid leafbrush range %i : %i (%i leafbrushes)\n", n, n + c, cm.numleafbrushes);
out->firstleafbrush = cm.leafbrushes + n;
out->numleafbrushes = c;
}
// probably any wall it's liquid ?
if( cm.leafs[0].contents != CONTENTS_SOLID )
Host_Error("Map %s with leaf 0 is not CONTENTS_SOLID\n", cm.name );
for( i = 1; i < count; i++ )
{
if(!cm.leafs[i].contents)
{
emptyleaf = i;
break;
}
}
// stuck into brushes
if( emptyleaf == -1 ) Host_Error("Map %s does not have an empty leaf\n", cm.name );
}
/*
=================
BSP_LoadPlanes
=================
*/
void BSP_LoadPlanes( lump_t *l )
{
dplane_t *in;
cplane_t *out;
int i, j, count;
in = (void *)(cm.mod_base + l->fileofs);
if (l->filelen % sizeof(*in)) Host_Error("CMod_LoadPlanes: funny lump size\n");
count = l->filelen / sizeof(*in);
if (count < 1) Host_Error("Map %s with no planes\n", cm.name );
out = cm.planes = (cplane_t *)Mem_Alloc( cmappool, count * sizeof(*out));
cm.numplanes = count;
for ( i = 0; i < count; i++, in++, out++)
{
for (j = 0; j < 3; j++)
out->normal[j] = LittleFloat(in->normal[j]);
out->dist = LittleFloat( in->dist );
PlaneClassify( out ); // automatic plane classify
}
}
/*
=================
BSP_LoadBrushSides
@ -429,7 +483,7 @@ void BSP_LoadBrushSides( lump_t *l )
in = (void *)(cm.mod_base + l->fileofs);
if (l->filelen % sizeof(*in)) Host_Error("CMod_LoadBrushSides: funny lump size\n");
count = l->filelen / sizeof(*in);
out = cm.brushsides = (cbrushside_t *)Mem_Alloc( cmappool, (count + 6) * sizeof(*out));
out = cm.brushsides = (cbrushside_t *)Mem_Alloc( cmappool, count * sizeof(*out));
cm.numbrushsides = count;
for ( i = 0; i < count; i++, in++, out++)
@ -677,6 +731,58 @@ void BSP_LoadStringTable( lump_t *l )
for ( i = 0; i < count; i++ ) out[i] = LittleLong(in[i]);
}
static void BSP_RecursiveFindNumLeafs( cnode_t *node )
{
int numleafs;
while( node->plane )
{
BSP_RecursiveFindNumLeafs( node->children[0] );
node = node->children[1];
}
numleafs = ((cleaf_t *)node - cm.leafs) + 1;
if( cm.numleafs < numleafs ) cm.numleafs = numleafs;
}
static void BSP_RecursiveSetParent( cnode_t *node, cnode_t *parent )
{
node->parent = parent;
if( node->plane )
{
// this is a node, recurse to children
BSP_RecursiveSetParent( node->children[0], node );
BSP_RecursiveSetParent( node->children[1], node );
// combine contents of children
node->contents = node->children[0]->contents | node->children[1]->contents;
}
else
{
cleaf_t *leaf = (cleaf_t *)node;
int i;
// if this is a leaf, calculate supercontents mask from all collidable
// primitives in the leaf (brushes and collision surfaces)
// also flag if the leaf contains any collision surfaces
leaf->contents = 0;
// combine the supercontents values of all brushes in this leaf
for( i = 0; i < leaf->numleafbrushes; i++ )
leaf->contents |= cm.brushes[leaf->firstleafbrush[i]].contents;
// check if this leaf contains any collision surfaces (patches)
for( i = 0; i < leaf->numleafsurfaces; i++ )
{
dface_t *m_face = cm.surfaces + leaf->firstleafsurface[i];
csurface_t *surface = cm.surfdesc + m_face->desc;
if( surface->numtriangles )
{
leaf->havepatches = true;
leaf->contents |= surface->contentflags;
}
}
}
}
/*
===============================================================================
@ -705,7 +811,7 @@ void BSP_AddCollisionFace( int facenum )
}
m_face = cm.surfaces + facenum;
flags = cm.surfdesc[m_face->desc].flags;
flags = cm.surfdesc[m_face->desc].surfaceflags;
k = m_face->firstedge;
// sky is noclip for all physobjects
@ -734,9 +840,9 @@ void BSP_AddCollisionFace( int facenum )
void BSP_EndBuildTree( void )
{
if( cm.use_thread ) Msg("Optimize collision tree..." );
if( app_name == COMP_BSPLIB ) Msg("Optimize collision tree..." );
NewtonTreeCollisionEndBuild( cm.collision, true );
if( cm.use_thread ) Msg(" done\n");
if( app_name == COMP_BSPLIB ) Msg(" done\n");
}
static void BSP_LoadTree( vfile_t* handle, void* buffer, size_t size )
@ -751,19 +857,15 @@ void CM_LoadBSP( const void *buffer )
header = *(dheader_t *)buffer;
cm.mod_base = (byte *)buffer;
// loading level
// bsplib uses light version of loading
BSP_LoadVerts(&header.lumps[LUMP_VERTEXES]);
BSP_LoadEdges(&header.lumps[LUMP_EDGES]);
BSP_LoadSurfedges(&header.lumps[LUMP_SURFEDGES]);
BSP_LoadFaces(&header.lumps[LUMP_FACES]);
BSP_LoadSurfDesc(&header.lumps[LUMP_SURFDESC]);
BSP_LoadFaces(&header.lumps[LUMP_FACES]);
BSP_LoadModels(&header.lumps[LUMP_MODELS]);
BSP_LoadCollision(&header.lumps[LUMP_COLLISION]);
cm.loaded = true;
cm.use_thread = true;
// keep bspdata because we want create bsp models
// as kinematic objects: doors, fans, pendulums etc
}
void CM_FreeBSP( void )
@ -776,13 +878,14 @@ void CM_MakeCollisionTree( void )
int i, world = 0; // world index
if(!cm.loaded) Host_Error("CM_MakeCollisionTree: map not loaded\n");
if(cm.collision) return; // already generated
if(cm.use_thread) Msg("Building collision tree...\n" );
if( cm.collision ) return; // already generated
if( app_name == COMP_BSPLIB ) Msg("Building collision tree...\n" );
BSP_BeginBuildTree();
// world firstface index always equal 0
if(cm.use_thread) RunThreadsOnIndividual( cm.bmodels[world].numfaces, true, BSP_AddCollisionFace );
if( app_name == COMP_BSPLIB )
RunThreadsOnIndividual( cm.bmodels[world].numfaces, true, BSP_AddCollisionFace );
else for( i = 0; i < cm.bmodels[world].numfaces; i++ ) BSP_AddCollisionFace( i );
BSP_EndBuildTree();
@ -806,11 +909,8 @@ void CM_LoadWorld( const void *buffer )
vec3_t boxP0, boxP1;
vec3_t extra = { 10.0f, 10.0f, 10.0f };
CM_LoadBSP( buffer ); // loading bspdata
cm.use_thread = false;
if(cm.world_tree) CM_LoadCollisionTree();
else CM_MakeCollisionTree(); // can be used for old maps
if( cm.world_tree ) CM_LoadCollisionTree();
else CM_MakeCollisionTree(); // can be used for old maps or for product of alternative map compiler
cm.body = NewtonCreateBody( gWorld, cm.collision );
NewtonBodyGetMatrix( cm.body, &cm.matrix[0][0] ); // set the global position of this body
@ -833,7 +933,11 @@ void CM_FreeWorld( void )
// free old stuff
if( cm.loaded ) Mem_EmptyPool( cmappool );
cm.numplanes = cm.numnodes = cm.numleafs = 0;
cm.num_models = cm.numfaces = cm.numbmodels = 0;
cm.numleafbrushes = cm.numfaces = cm.numbmodels = 0;
cm.floodvalid = cm.numbrushsides = cm.numtexinfo = 0;
cm.numbrushes = cm.numleafsurfaces = cm.numareas = 0;
cm.numareaportals = cm.numclusters = 0;
cm.name[0] = 0;
memset( cm.matrix, 0, sizeof(matrix4x4));
@ -844,6 +948,7 @@ void CM_FreeWorld( void )
if(mod->registration_sequence != registration_sequence)
CM_FreeModel( mod );
}
cm.numbmodels = 0;
if( cm.body )
{
@ -907,18 +1012,32 @@ cmodel_t *CM_BeginRegistration( const char *name, bool clientload, uint *checksu
// load into heap
BSP_LoadStringData(&hdr->lumps[LUMP_STRINGDATA]);
BSP_LoadStringTable(&hdr->lumps[LUMP_STRINGTABLE]);
BSP_LoadEntityString(&hdr->lumps[LUMP_ENTITIES]);
BSP_LoadSurfDesc(&hdr->lumps[LUMP_SURFDESC]);
BSP_LoadLeafs(&hdr->lumps[LUMP_LEAFS]);
BSP_LoadLeafBrushes(&hdr->lumps[LUMP_LEAFBRUSHES]);
BSP_LoadPlanes(&hdr->lumps[LUMP_PLANES]);
BSP_LoadBrushSides(&hdr->lumps[LUMP_BRUSHSIDES]);
BSP_LoadBrushes(&hdr->lumps[LUMP_BRUSHES]);
BSP_LoadVerts(&hdr->lumps[LUMP_VERTEXES]);
BSP_LoadEdges(&hdr->lumps[LUMP_EDGES]);
BSP_LoadSurfedges(&hdr->lumps[LUMP_SURFEDGES]);
BSP_LoadFaces(&hdr->lumps[LUMP_FACES]); // used only for generate NewtonCollisionTree
BSP_LoadLeafBrushes(&hdr->lumps[LUMP_LEAFBRUSHES]);
BSP_LoadLeafFaces(&hdr->lumps[LUMP_LEAFFACES]);
BSP_LoadLeafs(&hdr->lumps[LUMP_LEAFS]);
BSP_LoadNodes(&hdr->lumps[LUMP_NODES]);
BSP_LoadAreas(&hdr->lumps[LUMP_AREAS]);
BSP_LoadAreaPortals(&hdr->lumps[LUMP_AREAPORTALS]);
BSP_LoadVisibility(&hdr->lumps[LUMP_VISIBILITY]);
BSP_LoadEntityString(&hdr->lumps[LUMP_ENTITIES]);
BSP_LoadModels(&hdr->lumps[LUMP_MODELS]);
BSP_LoadCollision(&hdr->lumps[LUMP_COLLISION]);
// test, these probably unneeded
Msg("cm.numleafs %i\n", cm.numleafs );
BSP_RecursiveFindNumLeafs( cm.nodes );
BSP_RecursiveSetParent( cm.nodes, NULL );
Msg("cm.numleafs %i\n", cm.numleafs );
CM_LoadWorld( buf );// load physics collision
Mem_Free( buf ); // release map buffer
@ -1049,7 +1168,7 @@ void CM_StudioSetUpTransform ( void )
vec3_t mins, maxs;
vec3_t modelpos;
hull.numverts = 0; // clear current count
studio.numverts = studio.numtriangles = 0; // clear current count
CM_StudioExtractBbox( studio.hdr, 0, mins, maxs );// adjust model center
VectorAdd( mins, maxs, modelpos );
VectorScale( modelpos, -0.5, modelpos );
@ -1125,19 +1244,20 @@ void CM_StudioAddMesh( int mesh )
{
for(i = abs(i); i > 0; i--, ptricmds += 4)
{
hull.m_pVerts[hull.numverts][0] = INCH2METER(studio.transform[ptricmds[0]][0]);
hull.m_pVerts[hull.numverts][1] = INCH2METER(studio.transform[ptricmds[0]][1]);
hull.m_pVerts[hull.numverts][2] = INCH2METER(studio.transform[ptricmds[0]][2]);
hull.numverts++;
studio.m_pVerts[studio.numverts][0] = INCH2METER(studio.vtransform[ptricmds[0]][0]);
studio.m_pVerts[studio.numverts][1] = INCH2METER(studio.vtransform[ptricmds[0]][1]);
studio.m_pVerts[studio.numverts][2] = INCH2METER(studio.vtransform[ptricmds[0]][2]);
studio.numverts++;
}
}
studio.numtriangles += pmesh->numtris;
}
void CM_StudioLookMeshes ( void )
{
int i;
for (i = 0; i < studio.submodel->nummesh; i++)
for (i = 0; i < studio.submodel->nummesh; i++ )
CM_StudioAddMesh( i );
}
@ -1145,14 +1265,22 @@ void CM_StudioGetVertices( void )
{
int i;
vec3_t *pstudioverts;
vec3_t *pstudionorms;
byte *pvertbone;
byte *pnormbone;
pvertbone = ((byte *)studio.hdr + studio.submodel->vertinfoindex);
pnormbone = ((byte *)studio.hdr + studio.submodel->norminfoindex);
pstudioverts = (vec3_t *)((byte *)studio.hdr + studio.submodel->vertindex);
pstudionorms = (vec3_t *)((byte *)studio.hdr + studio.submodel->normindex);
for (i = 0; i < studio.submodel->numverts; i++)
for( i = 0; i < studio.submodel->numverts; i++ )
{
VectorTransform( pstudioverts[i], studio.bones[pvertbone[i]], studio.transform[i]);
VectorTransform( pstudioverts[i], studio.bones[pvertbone[i]], studio.vtransform[i]);
}
for( i = 0; i < studio.submodel->numnorms; i++ )
{
VectorTransform( pstudionorms[i], studio.bones[pnormbone[i]], studio.ntransform[i]);
}
CM_StudioLookMeshes();
}
@ -1163,14 +1291,14 @@ void CM_CreateMeshBuffer( byte *buffer )
// setup global pointers
studio.hdr = (studiohdr_t *)buffer;
hull.m_pVerts = &studio.vertices[0];
studio.m_pVerts = &studio.vertices[0];
CM_GetBodyCount();
for( i = 0; i < studio.bodycount; i++)
{
// already loaded
if( loadmodel->physmesh[i].verts ) continue;
if( loadmodel->col[i] ) continue;
CM_StudioSetUpTransform();
CM_StudioSetupBones();
@ -1181,11 +1309,13 @@ void CM_CreateMeshBuffer( byte *buffer )
CM_StudioSetupModel( j, i );
CM_StudioGetVertices();
}
if( hull.numverts )
if( studio.numverts )
{
loadmodel->physmesh[i].verts = Mem_Alloc( loadmodel->mempool, hull.numverts * sizeof(vec3_t));
Mem_Copy( loadmodel->physmesh[i].verts, hull.m_pVerts, hull.numverts * sizeof(vec3_t));
loadmodel->physmesh[i].numverts = hull.numverts;
loadmodel->col[i] = (cmesh_t *)Mem_Alloc( loadmodel->mempool, sizeof(*loadmodel->col[0]));
loadmodel->col[i]->verts = Mem_Alloc( loadmodel->mempool, studio.numverts * sizeof(vec3_t));
Mem_Copy( loadmodel->col[i]->verts, studio.m_pVerts, studio.numverts * sizeof(vec3_t));
loadmodel->col[i]->numtris = studio.numtriangles;
loadmodel->col[i]->numverts = studio.numverts;
loadmodel->numbodies++;
}
}
@ -1212,6 +1342,14 @@ bool CM_StudioModel( byte *buffer, uint filesize )
VectorCopy( pseqdesc[0].bbmax, loadmodel->maxs );
loadmodel->numframes = pseqdesc[0].numframes; // FIXME: get numframes from current sequence (not first)
// FIXME: calc bounding box right
VectorCopy( loadmodel->mins, loadmodel->normalmins );
VectorCopy( loadmodel->maxs, loadmodel->normalmaxs );
VectorCopy( loadmodel->mins, loadmodel->rotatedmins );
VectorCopy( loadmodel->maxs, loadmodel->rotatedmaxs );
VectorCopy( loadmodel->mins, loadmodel->yawmins );
VectorCopy( loadmodel->maxs, loadmodel->yawmaxs );
CM_CreateMeshBuffer( buffer ); // newton collision mesh
return true;
@ -1236,6 +1374,15 @@ bool CM_SpriteModel( byte *buffer, uint filesize )
loadmodel->maxs[0] = loadmodel->maxs[1] = phdr->bounds[0] / 2;
loadmodel->mins[2] = -phdr->bounds[1] / 2;
loadmodel->maxs[2] = phdr->bounds[1] / 2;
// FIXME: calc bounding box right
VectorCopy( loadmodel->mins, loadmodel->normalmins );
VectorCopy( loadmodel->maxs, loadmodel->normalmaxs );
VectorCopy( loadmodel->mins, loadmodel->rotatedmins );
VectorCopy( loadmodel->maxs, loadmodel->rotatedmaxs );
VectorCopy( loadmodel->mins, loadmodel->yawmins );
VectorCopy( loadmodel->maxs, loadmodel->yawmaxs );
return true;
}

File diff suppressed because it is too large Load Diff

View File

@ -540,7 +540,7 @@ void PM_AddCurrents( vec3_t wishvel )
v[2] -= 1;
s = pm_waterspeed;
if ((pm->waterlevel == 1) && (pm->ps.groundentity))
if ((pm->waterlevel == 1) && (pm->groundentity))
s /= 2;
VectorMA (wishvel, s, v, wishvel);
@ -550,7 +550,7 @@ void PM_AddCurrents( vec3_t wishvel )
// add conveyor belt velocities
//
if (pm->ps.groundentity)
if (pm->groundentity)
{
VectorClear (v);
@ -567,7 +567,7 @@ void PM_AddCurrents( vec3_t wishvel )
if (pml.groundtrace.contents & CONTENTS_CURRENT_DOWN)
v[2] -= 1;
VectorMA (wishvel, 100 /* pm->ps.groundentity->speed */, v, wishvel);
VectorMA (wishvel, 100 /* pm->groundentity->speed */, v, wishvel);
}
}
@ -624,7 +624,7 @@ static bool PM_CheckJump( void )
pml.groundplane = false; // jumping away
pml.walking = false;
pm->ps.groundentity = NULL;
pm->groundentity = NULL;
pm->ps.pm_flags |= PMF_JUMP_HELD;
pm->ps.velocity[2] = JUMP_VELOCITY;
@ -1180,7 +1180,7 @@ static int PM_CorrectAllSolid( trace_t *trace )
}
}
pm->ps.groundentity = NULL;
pm->groundentity = NULL;
pml.groundplane = false;
pml.walking = false;
return false;
@ -1198,7 +1198,7 @@ static void PM_GroundTraceMissed( void )
trace_t trace;
vec3_t point;
if( pm->ps.groundentity )
if( pm->groundentity )
{
// if they aren't in a jumping animation and the ground is a ways away, force into it
// if we didn't do the trace, the player would be backflipping down staircases
@ -1219,7 +1219,7 @@ static void PM_GroundTraceMissed( void )
}
}
pm->ps.groundentity = NULL;
pm->groundentity = NULL;
pml.groundplane = false;
pml.walking = false;
}
@ -1270,7 +1270,7 @@ static void PM_GroundTrace( void )
// anim jump backward
}
pm->ps.groundentity = NULL;
pm->groundentity = NULL;
pml.groundplane = false;
pml.walking = false;
return;
@ -1281,7 +1281,7 @@ static void PM_GroundTrace( void )
{
// FIXME: if they can't slide down the slope, let them
// walk (sharp crevices)
pm->ps.groundentity = NULL;
pm->groundentity = NULL;
pml.groundplane = true;
pml.walking = false;
return;
@ -1297,7 +1297,7 @@ static void PM_GroundTrace( void )
pm->ps.pm_time = 0;
}
if( !pm->ps.groundentity )
if( !pm->groundentity )
{
PM_CrashLand();
@ -1310,7 +1310,7 @@ static void PM_GroundTrace( void )
}
}
pm->ps.groundentity = trace.ent;
pm->groundentity = trace.ent;
PM_AddTouchEnt( trace.ent );
}
@ -1441,7 +1441,7 @@ This can be used as another entry point when only the viewangles
are being updated isntead of a full move
================
*/
void PM_UpdateViewAngles( player_state_t *ps, const usercmd_t *cmd )
void PM_UpdateViewAngles( entity_state_t *ps, const usercmd_t *cmd )
{
short temp;
int i;

View File

@ -4,7 +4,6 @@
//=======================================================================
#include "cm_local.h"
#include "matrixlib.h"
static float RayCastPlacement(const NewtonBody* body, const float* normal, int collisionID, void* userData, float intersetParam )
{
@ -156,7 +155,7 @@ CM_PointContents
*/
int CM_PointContents( const vec3_t p, cmodel_t *model )
{
int i, num, contents = 0;
int i, contents = 0;
cbrush_t *brush;
if( !cm.numnodes ) return 0; // map not loaded
@ -174,14 +173,14 @@ int CM_PointContents( const vec3_t p, cmodel_t *model )
cnode_t *node = cm.nodes;
cleaf_t *leaf;
leaf = &cm.leafs[CM_PointLeafnum_r( p, cm.nodes )];
// find which leaf the point is in
while( node->plane )
node = node->children[(node->plane->type < 3 ? p[node->plane->type] : DotProduct(p, node->plane->normal)) < node->plane->dist];
leaf = (cleaf_t *)node;
// now check the brushes in the leaf
for( i = 0; i < leaf->numleafbrushes; i++ )
{
num = cm.leafbrushes[leaf->firstleafbrush + i];
brush = &cm.brushes[num];
brush = cm.brushes + leaf->firstleafbrush[i];
if( brush->colbrushf && CM_CollisionPointInsideBrushFloat( p, brush->colbrushf ))
contents |= brush->colbrushf->contents;
}
@ -216,230 +215,4 @@ int CM_TransformedPointContents( const vec3_t p, cmodel_t *model, const vec3_t o
p_l[2] = DotProduct( temp, up );
}
return CM_PointContents( p_l, model );
}
static void CM_TracePoint_r( trace_t *trace, cmodel_t *model, cnode_t *node, const vec3_t p, int markframe )
{
int i;
cleaf_t *leaf;
cbrushf_t *brush;
// find which leaf the point is in
leaf = &cm.leafs[CM_PointLeafnum_r( p, cm.nodes )];
for( i = 0; i < leaf->numleafbrushes; i++ )
{
brush = cm.brushes[leaf->firstleafbrush + i].colbrushf;
if( brush && brush->markframe != markframe && BoxesOverlap( p, p, brush->mins, brush->maxs))
{
brush->markframe = markframe;
CM_CollisionTracePointBrushFloat( trace, p, brush );
}
}
// can't do point traces on curves (they have no thickness)
}
static void CM_TraceLine_r( trace_t *trace, cmodel_t *model, cnode_t *node, const vec3_t start, const vec3_t end, vec_t startfrac, vec_t endfrac, const vec3_t linestart, const vec3_t lineend, int markframe, const vec3_t segmentmins, const vec3_t segmentmaxs )
{
int i, startside, endside;
float dist1, dist2, midfrac, mid[3];
float nodesegmentmins[3], nodesegmentmaxs[3];
cleaf_t *leaf;
cplane_t *plane;
cbrushf_t *brush;
// walk the tree until we hit a leaf, recursing for any split cases
while( node->plane )
{
// abort if this part of the bsp tree can not be hit by this trace
plane = node->plane;
// axial planes are much more common than non-axial, so an optimized
// axial case pays off here
if( plane->type < 3 )
{
dist1 = start[plane->type] - plane->dist;
dist2 = end[plane->type] - plane->dist;
}
else
{
dist1 = DotProduct( start, plane->normal ) - plane->dist;
dist2 = DotProduct( end, plane->normal ) - plane->dist;
}
startside = dist1 < 0;
endside = dist2 < 0;
if( startside == endside )
{
// most of the time the line fragment is on one side of the plane
node = node->children[startside];
}
else
{
// line crosses node plane, split the line
dist1 = PlaneDiff(linestart, plane);
dist2 = PlaneDiff(lineend, plane);
midfrac = dist1 / (dist1 - dist2);
VectorLerp(linestart, midfrac, lineend, mid);
// take the near side first
CM_TraceLine_r( trace, model, node->children[startside], start, mid, startfrac, midfrac, linestart, lineend, markframe, segmentmins, segmentmaxs );
// if we found an impact on the front side, don't waste time
// exploring the far side
if( midfrac <= trace->realfraction )
CM_TraceLine_r( trace, model, node->children[endside], mid, end, midfrac, endfrac, linestart, lineend, markframe, segmentmins, segmentmaxs );
return;
}
}
// hit a leaf
nodesegmentmins[0] = min(start[0], end[0]) - 1;
nodesegmentmins[1] = min(start[1], end[1]) - 1;
nodesegmentmins[2] = min(start[2], end[2]) - 1;
nodesegmentmaxs[0] = max(start[0], end[0]) + 1;
nodesegmentmaxs[1] = max(start[1], end[1]) + 1;
nodesegmentmaxs[2] = max(start[2], end[2]) + 1;
// line trace the brushes
leaf = (cleaf_t *)node;
for( i = 0; i < leaf->numleafbrushes; i++ )
{
brush = cm.brushes[leaf->firstleafbrush + i].colbrushf;
if( brush && brush->markframe != markframe && BoxesOverlap( nodesegmentmins, nodesegmentmaxs, brush->mins, brush->maxs ))
{
brush->markframe = markframe;
CM_CollisionTraceLineBrushFloat( trace, linestart, lineend, brush, brush );
}
}
}
static void CM_TraceBrush_r( trace_t *trace, cmodel_t *model, cnode_t *node, const cbrushf_t *thisbrush_start, const cbrushf_t *thisbrush_end, int markframe, const vec3_t segmentmins, const vec3_t segmentmaxs )
{
int i, sides;
cleaf_t *leaf;
cbrushf_t *brush;
cplane_t *plane;
float nodesegmentmins[3], nodesegmentmaxs[3];
// walk the tree until we hit a leaf, recursing for any split cases
while( node->plane )
{
// abort if this part of the bsp tree can not be hit by this trace
plane = node->plane;
// axial planes are much more common than non-axial, so an optimized
// axial case pays off here
if( plane->type < 3 )
{
// this is an axial plane, compare bounding box directly to it and
// recurse sides accordingly
sides = ((segmentmaxs[plane->type] >= plane->dist) + ((segmentmins[plane->type] < plane->dist) * 2));
}
else
{
// this is a non-axial plane, so check if the start and end boxes
// are both on one side of the plane to handle 'diagonal' cases
sides = BoxOnPlaneSide( thisbrush_start->mins, thisbrush_start->maxs, plane) | BoxOnPlaneSide( thisbrush_end->mins, thisbrush_end->maxs, plane );
}
if( sides == 3 )
{
// segment crosses plane
CM_TraceBrush_r( trace, model, node->children[0], thisbrush_start, thisbrush_end, markframe, segmentmins, segmentmaxs );
sides = 2;
}
// if sides == 0 then the trace itself is bogus (Not A Number values),
// in this case we simply pretend the trace hit nothing
if( sides == 0 ) return; // ERROR: NAN bounding box!
// take whichever side the segment box is on
node = node->children[sides - 1];
}
// abort if this part of the bsp tree can not be hit by this trace
nodesegmentmins[0] = max(segmentmins[0], node->mins[0] - 1);
nodesegmentmins[1] = max(segmentmins[1], node->mins[1] - 1);
nodesegmentmins[2] = max(segmentmins[2], node->mins[2] - 1);
nodesegmentmaxs[0] = min(segmentmaxs[0], node->maxs[0] + 1);
nodesegmentmaxs[1] = min(segmentmaxs[1], node->maxs[1] + 1);
nodesegmentmaxs[2] = min(segmentmaxs[2], node->maxs[2] + 1);
// hit a leaf
leaf = (cleaf_t *)node; //it's right ?
for( i = 0; i < leaf->numleafbrushes; i++ )
{
brush = cm.brushes[leaf->firstleafbrush + i].colbrushf;
if( brush && brush->markframe != markframe && BoxesOverlap( nodesegmentmins, nodesegmentmaxs, brush->mins, brush->maxs ))
{
brush->markframe = markframe;
CM_CollisionTraceBrushBrushFloat( trace, thisbrush_start, thisbrush_end, brush, brush );
}
}
}
void CM_TraceBox( const vec3_t start, const vec3_t end, const vec3_t mins, const vec3_t maxs, cmodel_t *model, trace_t *trace, int contentsmask )
{
int i;
float segmentmins[3], segmentmaxs[3];
static int markframe = 0;
cbrush_t *brush;
memset( trace, 0, sizeof(*trace));
trace->fraction = 1;
trace->realfraction = 1;
trace->contentsmask = contentsmask;
if((VectorLength2( mins ) + VectorLength2( maxs)) == 0)
{
if(VectorCompare( start, end ))
{
// point trace
if( model && model->type == mod_brush )
{
for( i = 0, brush = cm.brushes + model->firstbrush; i < model->numbrushes; i++, brush++ )
if( brush->colbrushf ) CM_CollisionTracePointBrushFloat( trace, start, brush->colbrushf );
}
else CM_TracePoint_r( trace, model, cm.nodes, start, ++markframe );
}
else
{
// line trace
segmentmins[0] = min(start[0], end[0]) - 1;
segmentmins[1] = min(start[1], end[1]) - 1;
segmentmins[2] = min(start[2], end[2]) - 1;
segmentmaxs[0] = max(start[0], end[0]) + 1;
segmentmaxs[1] = max(start[1], end[1]) + 1;
segmentmaxs[2] = max(start[2], end[2]) + 1;
if( model && model->type == mod_brush )
{
for( i = 0, brush = cm.brushes + model->firstbrush; i < model->numbrushes; i++, brush++ )
if( brush->colbrushf ) CM_CollisionTraceLineBrushFloat( trace, start, end, brush->colbrushf, brush->colbrushf );
}
else CM_TraceLine_r( trace, model, cm.nodes, start, end, 0, 1, start, end, ++markframe, segmentmins, segmentmaxs );
}
}
else
{
// box trace, performed as brush trace
cbrushf_t *thisbrush_start, *thisbrush_end;
vec3_t boxstartmins, boxstartmaxs, boxendmins, boxendmaxs;
segmentmins[0] = min(start[0], end[0]) + mins[0] - 1;
segmentmins[1] = min(start[1], end[1]) + mins[1] - 1;
segmentmins[2] = min(start[2], end[2]) + mins[2] - 1;
segmentmaxs[0] = max(start[0], end[0]) + maxs[0] + 1;
segmentmaxs[1] = max(start[1], end[1]) + maxs[1] + 1;
segmentmaxs[2] = max(start[2], end[2]) + maxs[2] + 1;
VectorAdd(start, mins, boxstartmins);
VectorAdd(start, maxs, boxstartmaxs);
VectorAdd(end, mins, boxendmins);
VectorAdd(end, maxs, boxendmaxs);
thisbrush_start = CM_CollisionBrushForBox( identitymatrix, boxstartmins, boxstartmaxs, 0, 0, NULL );
thisbrush_end = CM_CollisionBrushForBox( identitymatrix, boxendmins, boxendmaxs, 0, 0, NULL );
if( model && model->type == mod_brush )
{
for( i = 0, brush = cm.brushes + model->firstbrush; i < model->numbrushes; i++, brush++ )
if( brush->colbrushf ) CM_CollisionTraceBrushBrushFloat( trace, thisbrush_start, thisbrush_end, brush->colbrushf, brush->colbrushf );
}
else CM_TraceBrush_r( trace, model, cm.nodes, thisbrush_start, thisbrush_end, ++markframe, segmentmins, segmentmaxs);
}
}

View File

@ -5,142 +5,7 @@
#include "cm_local.h"
#include "cm_utils.h"
// keep 1/8 unit away to keep the position valid before network snapping
// and to avoid various numeric issues
#define DIST_EPSILON (0.125) // 1/8 epsilon to keep floating point happy
#define RADIUS_EPSILON 1.0f
#define MAX_POSITION_LEAFS 1024
#define Square(x) ((x)*(x))
/*
===============================================================================
CM INTERNAL MATH
===============================================================================
*/
/*
================
RotatePoint
================
*/
void RotatePoint(vec3_t point, const vec3_t matrix[3])
{
vec3_t tvec;
VectorCopy( point, tvec );
point[0] = DotProduct( matrix[0], tvec );
point[1] = DotProduct( matrix[1], tvec );
point[2] = DotProduct( matrix[2], tvec );
}
/*
================
TransposeMatrix
================
*/
void TransposeMatrix( const vec3_t matrix[3], vec3_t transpose[3])
{
int i, j;
for (i = 0; i < 3; i++)
for( j = 0; j < 3; j++)
transpose[i][j] = matrix[j][i];
}
/*
================
CreateRotationMatrix
================
*/
void CreateRotationMatrix(const vec3_t angles, vec3_t matrix[3])
{
AngleVectors(angles, matrix[0], matrix[1], matrix[2]);
VectorNegate( matrix[1], matrix[1] );
}
/*
================
CM_ProjectPointOntoVector
================
*/
void CM_ProjectPointOntoVector( vec3_t point, vec3_t vStart, vec3_t vDir, vec3_t vProj )
{
vec3_t pVec;
VectorSubtract( point, vStart, pVec );
// project onto the directional vector for this segment
VectorMA( vStart, DotProduct( pVec, vDir ), vDir, vProj );
}
/*
================
CM_DistanceFromLineSquared
================
*/
float CM_DistanceFromLineSquared(vec3_t p, vec3_t lp1, vec3_t lp2, vec3_t dir)
{
vec3_t proj, t;
int j;
CM_ProjectPointOntoVector( p, lp1, dir, proj );
for (j = 0; j < 3; j++)
{
if ((proj[j] > lp1[j] && proj[j] > lp2[j]) || (proj[j] < lp1[j] && proj[j] < lp2[j]))
break;
}
if( j < 3 )
{
if(fabs(proj[j] - lp1[j]) < fabs(proj[j] - lp2[j]))
{
VectorSubtract(p, lp1, t);
}
else
{
VectorSubtract(p, lp2, t);
}
return VectorLength2(t);
}
VectorSubtract(p, proj, t);
return VectorLength2(t);
}
/*
================
CM_VectorDistanceSquared
================
*/
float CM_VectorDistanceSquared( vec3_t p1, vec3_t p2 )
{
vec3_t dir;
VectorSubtract(p2, p1, dir);
return VectorLength2(dir);
}
/*
================
SquareRootFloat
================
*/
float SquareRootFloat( float number )
{
long i;
float x, y;
const float f = 1.5F;
x = number * 0.5F;
y = number;
i = *(long*)&y;
i = 0x5f3759df - (i>>1);
y = *(float *)&i;
y = y*(f-(x*y*y));
y = y*(f-(x*y*y));
return number*y;
}
#include "matrixlib.h"
/*
===============================================================================
@ -148,93 +13,316 @@ float SquareRootFloat( float number )
TRACING
===============================================================================
*/
/*
===============================================================================
PUBLIC FUNCTIONS
===============================================================================
*/
/*
==================
CM_BoxTrace
==================
*/
void CM_BoxTrace( const vec3_t start, const vec3_t end, const vec3_t mins, const vec3_t maxs, cmodel_t *model, trace_t *tr, int brushmask )
*/
static void CM_TracePoint_r( trace_t *trace, cmodel_t *model, cnode_t *node, const vec3_t p, int markframe )
{
CM_TraceBox( start, end, mins, maxs, model, tr, brushmask );
int i;
cleaf_t *leaf;
cbrushf_t *brush;
// find which leaf the point is in
while( node->plane )
node = node->children[(node->plane->type < 3 ? p[node->plane->type] : DotProduct(p, node->plane->normal)) < node->plane->dist];
// point trace the brushes
leaf = (cleaf_t *)node;
for( i = 0; i < leaf->numleafbrushes; i++ )
{
brush = cm.brushes[leaf->firstleafbrush[i]].colbrushf;
if( brush && brush->markframe != markframe && BoxesOverlap( p, p, brush->mins, brush->maxs))
{
brush->markframe = markframe;
CM_CollisionTracePointBrushFloat( trace, p, brush );
}
}
// can't do point traces on curves (they have no thickness)
}
/*
==================
CM_TransformedBoxTrace
Handles offseting and rotation of the end points for moving and
rotating entities
==================
*/
trace_t CM_TransformedBoxTrace( const vec3_t start, const vec3_t end, vec3_t mins, vec3_t maxs, cmodel_t *model, int brushmask, vec3_t origin, vec3_t angles, int capsule )
static void CM_TraceLine_r( trace_t *trace, cmodel_t *model, cnode_t *node, const vec3_t start, const vec3_t end, vec_t startfrac, vec_t endfrac, const vec3_t linestart, const vec3_t lineend, int markframe, const vec3_t segmentmins, const vec3_t segmentmaxs )
{
vec3_t start_l, end_l;
vec3_t offset;
vec3_t symetricSize[2];
vec3_t matrix[3], transpose[3];
bool rotated;
int i;
if( !mins ) mins = vec3_origin;
if( !maxs ) maxs = vec3_origin;
// adjust so that mins and maxs are always symetric, which
// avoids some complications with plane expanding of rotated
// bmodels
for ( i = 0 ; i < 3 ; i++ )
int i, startside, endside;
float dist1, dist2, midfrac, mid[3];
float nodesegmentmins[3], nodesegmentmaxs[3];
cleaf_t *leaf;
cplane_t *plane;
cbrushf_t *brush;
csurface_t *surface;
// walk the tree until we hit a leaf, recursing for any split cases
while( node->plane )
{
offset[i] = ( mins[i] + maxs[i] ) * 0.5f;
symetricSize[0][i] = mins[i] - offset[i];
symetricSize[1][i] = maxs[i] - offset[i];
start_l[i] = start[i] + offset[i];
end_l[i] = end[i] + offset[i];
// abort if this part of the bsp tree can not be hit by this trace
plane = node->plane;
// axial planes are much more common than non-axial, so an optimized
// axial case pays off here
if( plane->type < 3 )
{
dist1 = start[plane->type] - plane->dist;
dist2 = end[plane->type] - plane->dist;
}
else
{
dist1 = DotProduct( start, plane->normal ) - plane->dist;
dist2 = DotProduct( end, plane->normal ) - plane->dist;
}
startside = dist1 < 0;
endside = dist2 < 0;
if( startside == endside )
{
// most of the time the line fragment is on one side of the plane
node = node->children[startside];
}
else
{
// line crosses node plane, split the line
dist1 = PlaneDiff(linestart, plane);
dist2 = PlaneDiff(lineend, plane);
midfrac = dist1 / (dist1 - dist2);
VectorLerp(linestart, midfrac, lineend, mid);
// take the near side first
CM_TraceLine_r( trace, model, node->children[startside], start, mid, startfrac, midfrac, linestart, lineend, markframe, segmentmins, segmentmaxs );
// if we found an impact on the front side, don't waste time
// exploring the far side
if( midfrac <= trace->realfraction )
CM_TraceLine_r( trace, model, node->children[endside], mid, end, midfrac, endfrac, linestart, lineend, markframe, segmentmins, segmentmaxs );
return;
}
}
// subtract origin offset
VectorSubtract( start_l, origin, start_l );
VectorSubtract( end_l, origin, end_l );
// hit a leaf
nodesegmentmins[0] = min(start[0], end[0]) - 1;
nodesegmentmins[1] = min(start[1], end[1]) - 1;
nodesegmentmins[2] = min(start[2], end[2]) - 1;
nodesegmentmaxs[0] = max(start[0], end[0]) + 1;
nodesegmentmaxs[1] = max(start[1], end[1]) + 1;
nodesegmentmaxs[2] = max(start[2], end[2]) + 1;
// rotate start and end into the models frame of reference
if(com.strcmp( model->name, "*4095" ) && !VectorIsNull( angles )) rotated = true;
else rotated = false;
// line trace the brushes
leaf = (cleaf_t *)node;
if( rotated )
for( i = 0; i < leaf->numleafbrushes; i++ )
{
// rotation on trace line (start-end) instead of rotating the bmodel
// NOTE: This is still incorrect for bounding boxes because the actual bounding
// box that is swept through the model is not rotated. We cannot rotate
// the bounding box or the bmodel because that would make all the brush
// bevels invalid.
// However this is correct for capsules since a capsule itself is rotated too.
CreateRotationMatrix( angles, matrix );
RotatePoint( start_l, matrix );
RotatePoint( end_l, matrix );
brush = cm.brushes[leaf->firstleafbrush[i]].colbrushf;
if( brush && brush->markframe != markframe && BoxesOverlap( nodesegmentmins, nodesegmentmaxs, brush->mins, brush->maxs ))
{
brush->markframe = markframe;
CM_CollisionTraceLineBrushFloat( trace, linestart, lineend, brush, brush );
}
}
// sweep the box through the model
CM_TraceBox( start_l, end_l, symetricSize[0], symetricSize[1], model, &cm.trace, brushmask );
// if the bmodel was rotated and there was a collision
if( rotated && cm.trace.fraction != 1.0 )
// can't do point traces on curves (they have no thickness)
if( leaf->havepatches && !VectorCompare( start, end ))
{
// rotation of bmodel collision plane
TransposeMatrix( matrix, transpose );
RotatePoint( cm.trace.plane.normal, transpose );
// line trace the curves
for( i = 0; i < leaf->numleafsurfaces; i++ )
{
surface = cm.surfdesc + cm.surfaces[leaf->firstleafsurface[i]].desc;
if( surface->numtriangles && surface->markframe != markframe && BoxesOverlap(nodesegmentmins, nodesegmentmaxs, surface->mins, surface->maxs))
{
surface->markframe = markframe;
CM_CollisionTraceLineTriangleMeshFloat( trace, linestart, lineend, surface->numtriangles, surface->indices, surface->vertices, surface->contentflags, surface->surfaceflags, surface, segmentmins, segmentmaxs );
}
}
}
}
// re-calculate the end position of the trace because the trace.endpos
// calculated by CM_Trace could be rotated and have an offset
cm.trace.endpos[0] = start[0] + cm.trace.fraction * (end[0] - start[0]);
cm.trace.endpos[1] = start[1] + cm.trace.fraction * (end[1] - start[1]);
cm.trace.endpos[2] = start[2] + cm.trace.fraction * (end[2] - start[2]);
static void CM_TraceBrush_r( trace_t *trace, cmodel_t *model, cnode_t *node, const cbrushf_t *thisbrush_start, const cbrushf_t *thisbrush_end, int markframe, const vec3_t segmentmins, const vec3_t segmentmaxs )
{
int i, sides;
cleaf_t *leaf;
cbrushf_t *brush;
cplane_t *plane;
csurface_t *surface;
vec3_t nodesegmentmins;
vec3_t nodesegmentmaxs;
return cm.trace;
// walk the tree until we hit a leaf, recursing for any split cases
while( node->plane )
{
// abort if this part of the bsp tree can not be hit by this trace
plane = node->plane;
// axial planes are much more common than non-axial, so an optimized
// axial case pays off here
if( plane->type < 3 )
{
// this is an axial plane, compare bounding box directly to it and
// recurse sides accordingly
sides = ((segmentmaxs[plane->type] >= plane->dist) + ((segmentmins[plane->type] < plane->dist) * 2));
}
else
{
// this is a non-axial plane, so check if the start and end boxes
// are both on one side of the plane to handle 'diagonal' cases
sides = BoxOnPlaneSide( thisbrush_start->mins, thisbrush_start->maxs, plane) | BoxOnPlaneSide( thisbrush_end->mins, thisbrush_end->maxs, plane );
}
if( sides == 3 )
{
// segment crosses plane
CM_TraceBrush_r( trace, model, node->children[0], thisbrush_start, thisbrush_end, markframe, segmentmins, segmentmaxs );
sides = 2;
}
// if sides == 0 then the trace itself is bogus (Not A Number values),
// in this case we simply pretend the trace hit nothing
if( sides == 0 ) return; // ERROR: NAN bounding box!
// take whichever side the segment box is on
node = node->children[sides - 1];
}
// abort if this part of the bsp tree can not be hit by this trace
nodesegmentmins[0] = max(segmentmins[0], node->mins[0] - 1);
nodesegmentmins[1] = max(segmentmins[1], node->mins[1] - 1);
nodesegmentmins[2] = max(segmentmins[2], node->mins[2] - 1);
nodesegmentmaxs[0] = min(segmentmaxs[0], node->maxs[0] + 1);
nodesegmentmaxs[1] = min(segmentmaxs[1], node->maxs[1] + 1);
nodesegmentmaxs[2] = min(segmentmaxs[2], node->maxs[2] + 1);
// hit a leaf
leaf = (cleaf_t *)node;
for( i = 0; i < leaf->numleafbrushes; i++ )
{
brush = cm.brushes[leaf->firstleafbrush[i]].colbrushf;
if( brush && brush->markframe != markframe && BoxesOverlap( nodesegmentmins, nodesegmentmaxs, brush->mins, brush->maxs ))
{
brush->markframe = markframe;
CM_CollisionTraceBrushBrushFloat( trace, thisbrush_start, thisbrush_end, brush, brush );
}
}
if( leaf->havepatches )
{
for( i = 0; i < leaf->numleafsurfaces; i++ )
{
surface = cm.surfdesc + cm.surfaces[leaf->firstleafsurface[i]].desc;
if( surface->numtriangles && surface->markframe != markframe && BoxesOverlap( nodesegmentmins, nodesegmentmaxs, surface->mins, surface->maxs ))
{
surface->markframe = markframe;
CM_CollisionTraceBrushTriangleMeshFloat( trace, thisbrush_start, thisbrush_end, surface->numtriangles, surface->indices, surface->vertices, surface->contentflags, surface->surfaceflags, surface, segmentmins, segmentmaxs );
}
}
}
}
void CM_TraceBmodel( const vec3_t start, const vec3_t end, const vec3_t mins, const vec3_t maxs, cmodel_t *model, trace_t *trace, int contentsmask )
{
int i, j;
float segmentmins[3], segmentmaxs[3];
static int markframe = 0;
csurface_t *surface;
cbrush_t *brush;
memset( trace, 0, sizeof(*trace));
trace->fraction = 1;
trace->realfraction = 1;
trace->contentsmask = contentsmask;
if((VectorLength2( mins ) + VectorLength2( maxs)) == 0)
{
if(VectorCompare( start, end ))
{
// point trace
if( model && model->type == mod_brush )
{
for( i = 0, brush = cm.brushes + model->firstbrush; i < model->numbrushes; i++, brush++ )
if( brush->colbrushf ) CM_CollisionTracePointBrushFloat( trace, start, brush->colbrushf );
}
else CM_TracePoint_r( trace, model, cm.nodes, start, ++markframe );
}
else
{
// line trace
segmentmins[0] = min(start[0], end[0]) - 1;
segmentmins[1] = min(start[1], end[1]) - 1;
segmentmins[2] = min(start[2], end[2]) - 1;
segmentmaxs[0] = max(start[0], end[0]) + 1;
segmentmaxs[1] = max(start[1], end[1]) + 1;
segmentmaxs[2] = max(start[2], end[2]) + 1;
if( model && model->type == mod_brush )
{
for( i = 0, brush = cm.brushes + model->firstbrush; i < model->numbrushes; i++, brush++ )
if( brush->colbrushf ) CM_CollisionTraceLineBrushFloat( trace, start, end, brush->colbrushf, brush->colbrushf );
for( i = 0, j = model->firstface; i < model->numfaces; i++, j++ )
{
surface = cm.surfdesc + cm.surfaces[j].desc;
if( surface->numtriangles ) CM_CollisionTraceLineTriangleMeshFloat( trace, start, end, surface->numtriangles, surface->indices, surface->vertices, surface->contentflags, surface->surfaceflags, surface, segmentmins, segmentmaxs );
}
}
else CM_TraceLine_r( trace, model, cm.nodes, start, end, 0, 1, start, end, ++markframe, segmentmins, segmentmaxs );
}
}
else
{
// box trace, performed as brush trace
cbrushf_t *thisbrush_start, *thisbrush_end;
vec3_t boxstartmins, boxstartmaxs, boxendmins, boxendmaxs;
segmentmins[0] = min(start[0], end[0]) + mins[0] - 1;
segmentmins[1] = min(start[1], end[1]) + mins[1] - 1;
segmentmins[2] = min(start[2], end[2]) + mins[2] - 1;
segmentmaxs[0] = max(start[0], end[0]) + maxs[0] + 1;
segmentmaxs[1] = max(start[1], end[1]) + maxs[1] + 1;
segmentmaxs[2] = max(start[2], end[2]) + maxs[2] + 1;
VectorAdd(start, mins, boxstartmins);
VectorAdd(start, maxs, boxstartmaxs);
VectorAdd(end, mins, boxendmins);
VectorAdd(end, maxs, boxendmaxs);
thisbrush_start = CM_CollisionBrushForBox( identitymatrix, boxstartmins, boxstartmaxs, 0, 0, NULL );
thisbrush_end = CM_CollisionBrushForBox( identitymatrix, boxendmins, boxendmaxs, 0, 0, NULL );
if( model && model->type == mod_brush )
{
for( i = 0, brush = cm.brushes + model->firstbrush; i < model->numbrushes; i++, brush++ )
if( brush->colbrushf ) CM_CollisionTraceBrushBrushFloat( trace, thisbrush_start, thisbrush_end, brush->colbrushf, brush->colbrushf );
for( i = 0, j = model->firstface; i < model->numfaces; i++, j++ )
{
surface = cm.surfdesc + cm.surfaces[j].desc;
if( surface->numtriangles ) CM_CollisionTraceLineTriangleMeshFloat( trace, start, end, surface->numtriangles, surface->indices, surface->vertices, surface->contentflags, surface->surfaceflags, surface, segmentmins, segmentmaxs );
}
}
else CM_TraceBrush_r( trace, model, cm.nodes, thisbrush_start, thisbrush_end, ++markframe, segmentmins, segmentmaxs);
}
}
void CM_TraceStudio( const vec3_t start, const vec3_t end, const vec3_t mins, const vec3_t maxs, cmodel_t *mod, trace_t *trace, int contentsmask )
{
vec3_t segmentmins;
vec3_t segmentmaxs;
memset(trace, 0, sizeof(*trace));
trace->fraction = 1;
trace->realfraction = 1;
trace->contentsmask = contentsmask;
if( VectorLength2(mins) + VectorLength2(maxs) == 0 )
{
// line trace
segmentmins[0] = min(start[0], end[0]) - 1;
segmentmins[1] = min(start[1], end[1]) - 1;
segmentmins[2] = min(start[2], end[2]) - 1;
segmentmaxs[0] = max(start[0], end[0]) + 1;
segmentmaxs[1] = max(start[1], end[1]) + 1;
segmentmaxs[2] = max(start[2], end[2]) + 1;
CM_CollisionTraceLineTriangleMeshFloat( trace, start, end, mod->col[0]->numtris, mod->col[0]->indices, (const float *)mod->col[0]->verts, CONTENTS_SOLID, 0, NULL, segmentmins, segmentmaxs );
}
else
{
// box trace, performed as brush trace
cbrushf_t *thisbrush_start, *thisbrush_end;
vec3_t boxstartmins, boxstartmaxs, boxendmins, boxendmaxs;
segmentmins[0] = min(start[0], end[0]) + mins[0] - 1;
segmentmins[1] = min(start[1], end[1]) + mins[1] - 1;
segmentmins[2] = min(start[2], end[2]) + mins[2] - 1;
segmentmaxs[0] = max(start[0], end[0]) + maxs[0] + 1;
segmentmaxs[1] = max(start[1], end[1]) + maxs[1] + 1;
segmentmaxs[2] = max(start[2], end[2]) + maxs[2] + 1;
VectorAdd(start, mins, boxstartmins);
VectorAdd(start, maxs, boxstartmaxs);
VectorAdd(end, mins, boxendmins);
VectorAdd(end, maxs, boxendmaxs);
thisbrush_start = CM_CollisionBrushForBox( identitymatrix, boxstartmins, boxstartmaxs, 0, 0, NULL );
thisbrush_end = CM_CollisionBrushForBox( identitymatrix, boxendmins, boxendmaxs, 0, 0, NULL );
CM_CollisionTraceBrushTriangleMeshFloat( trace, thisbrush_start, thisbrush_end, mod->col[0]->numtris, mod->col[0]->indices, (const float *)mod->col[0]->verts, CONTENTS_SOLID, 0, NULL, segmentmins, segmentmaxs );
}
}

View File

@ -55,7 +55,8 @@ const char *CM_EntityString( void );
const char *CM_TexName( int index );
int CM_PointContents( const vec3_t p, cmodel_t *model );
int CM_TransformedPointContents( const vec3_t p, cmodel_t *model, const vec3_t origin, const vec3_t angles );
void CM_TraceBox( const vec3_t start, const vec3_t end, const vec3_t mins, const vec3_t maxs, cmodel_t *model, trace_t *trace, int brushsmask );
void CM_TraceBmodel( const vec3_t start, const vec3_t end, const vec3_t mins, const vec3_t maxs, cmodel_t *model, trace_t *trace, int contentsmask );
void CM_TraceStudio( const vec3_t start, const vec3_t end, const vec3_t mins, const vec3_t maxs, cmodel_t *model, trace_t *trace, int contentsmask );
void CM_BoxTrace( const vec3_t start, const vec3_t end, const vec3_t mins, const vec3_t maxs, cmodel_t *model, trace_t *trace, int brushsmask );
trace_t CM_TransformedBoxTrace( const vec3_t start, const vec3_t end, vec3_t mins, vec3_t maxs, cmodel_t *model, int brushmask, vec3_t origin, vec3_t angles, bool capsule );
byte *CM_ClusterPVS( int cluster );

View File

@ -11,6 +11,7 @@ physic_t ph; // physic globalstate
byte *physpool;
byte *cmappool;
NewtonWorld *gWorld;
int app_name;
cvar_t *cm_use_triangles;
cvar_t *cm_solver_model;
@ -25,6 +26,7 @@ bool InitPhysics( void )
physpool = Mem_AllocPool("Physics Pool");
cmappool = Mem_AllocPool("CM Zone");
gWorld = NewtonCreate( Palloc, Pfree ); // alloc world
app_name = g_Instance;
// check developer mode
if( FS_GetParmFromCmdLine("-dev", dev_level ))
@ -88,10 +90,9 @@ physic_exp_t DLLEXPORT *CreateAPI ( stdlib_api_t *input, physic_imp_t *engfuncs
Phys.NumBmodels = CM_NumInlineModels;
Phys.GetEntityString = CM_EntityString;
Phys.GetTextureName = CM_TexName;
Phys.PointContents = CM_PointContents;
Phys.TransformedPointContents = CM_TransformedPointContents;
Phys.BoxTrace = CM_BoxTrace;
Phys.TransformedBoxTrace = CM_TransformedBoxTrace;
Phys.ClipToGenericEntity = CM_CollisionClipToGenericEntity;
Phys.ClipToWorld = CM_CollisionClipToWorld;
Phys.CombineTraces = CM_CollisionCombineTraces;
Phys.ClusterPVS = CM_ClusterPVS;
Phys.ClusterPHS = CM_ClusterPHS;
@ -108,8 +109,6 @@ physic_exp_t DLLEXPORT *CreateAPI ( stdlib_api_t *input, physic_imp_t *engfuncs
Phys.SetParameters = Phys_SetParameters;
Phys.PlayerMove = CM_PlayerMove;
Phys.ServerMove = CM_ServerMove;
Phys.ClientMove = CM_ClientMove;
Phys.SetOrigin = CM_SetOrigin;
Phys.GetForce = Phys_GetForce;

View File

@ -24,6 +24,7 @@ extern stdlib_api_t com;
extern byte *physpool;
extern byte *cmappool;
extern NewtonWorld *gWorld;
extern int app_name;
// cvars
extern cvar_t *cm_use_triangles;

View File

@ -42,4 +42,264 @@ _inline void Matrix4x4_Transform3x3( const matrix4x4 in, const float v[3], float
#endif
}
_inline void Matrix4x4_Invert_Simple( matrix4x4 out, const matrix4x4 in1 )
{
// we only support uniform scaling, so assume the first row is enough
// (note the lack of sqrt here, because we're trying to undo the scaling,
// this means multiplying by the inverse scale twice - squaring it, which
// makes the sqrt a waste of time)
double scale = 1.0 / (in1[0][0] * in1[0][0] + in1[0][1] * in1[0][1] + in1[0][2] * in1[0][2]);
// invert the rotation by transposing and multiplying by the squared
// recipricol of the input matrix scale as described above
out[0][0] = in1[0][0] * scale;
out[0][1] = in1[1][0] * scale;
out[0][2] = in1[2][0] * scale;
out[1][0] = in1[0][1] * scale;
out[1][1] = in1[1][1] * scale;
out[1][2] = in1[2][1] * scale;
out[2][0] = in1[0][2] * scale;
out[2][1] = in1[1][2] * scale;
out[2][2] = in1[2][2] * scale;
#ifdef OPENGL_STYLE
// invert the translate
out[3][0] = -(in1[3][0] * out[0][0] + in1[3][1] * out[1][0] + in1[3][2] * out[2][0]);
out[3][1] = -(in1[3][0] * out[0][1] + in1[3][1] * out[1][1] + in1[3][2] * out[2][1]);
out[3][2] = -(in1[3][0] * out[0][2] + in1[3][1] * out[1][2] + in1[3][2] * out[2][2]);
// don't know if there's anything worth doing here
out[0][3] = 0;
out[1][3] = 0;
out[2][3] = 0;
out[3][3] = 1;
#else
// invert the translate
out[0][3] = -(in1[0][3] * out[0][0] + in1[1][3] * out[0][1] + in1[2][3] * out[0][2]);
out[1][3] = -(in1[0][3] * out[1][0] + in1[1][3] * out[1][1] + in1[2][3] * out[1][2]);
out[2][3] = -(in1[0][3] * out[2][0] + in1[1][3] * out[2][1] + in1[2][3] * out[2][2]);
// don't know if there's anything worth doing here
out[3][0] = 0;
out[3][1] = 0;
out[3][2] = 0;
out[3][3] = 1;
#endif
}
_inline void Matrix4x4_CreateTranslate( matrix4x4 out, double x, double y, double z )
{
#ifdef OPENGL_STYLE
out[0][0] = 1.0f;
out[1][0] = 0.0f;
out[2][0] = 0.0f;
out[3][0] = x;
out[0][1] = 0.0f;
out[1][1] = 1.0f;
out[2][1] = 0.0f;
out[3][1] = y;
out[0][2] = 0.0f;
out[1][2] = 0.0f;
out[2][2] = 1.0f;
out[3][2] = z;
out[0][3] = 0.0f;
out[1][3] = 0.0f;
out[2][3] = 0.0f;
out[3][3] = 1.0f;
#else
out[0][0] = 1.0f;
out[0][1] = 0.0f;
out[0][2] = 0.0f;
out[0][3] = x;
out[1][0] = 0.0f;
out[1][1] = 1.0f;
out[1][2] = 0.0f;
out[1][3] = y;
out[2][0] = 0.0f;
out[2][1] = 0.0f;
out[2][2] = 1.0f;
out[2][3] = z;
out[3][0] = 0.0f;
out[3][1] = 0.0f;
out[3][2] = 0.0f;
out[3][3] = 1.0f;
#endif
}
_inline void Matrix4x4_CreateFromEntity( matrix4x4 out, double x, double y, double z, double pitch, double yaw, double roll, double scale )
{
double angle, sr, sp, sy, cr, cp, cy;
if( roll )
{
angle = yaw * (M_PI*2 / 360);
sy = sin(angle);
cy = cos(angle);
angle = pitch * (M_PI*2 / 360);
sp = sin(angle);
cp = cos(angle);
angle = roll * (M_PI*2 / 360);
sr = sin(angle);
cr = cos(angle);
#ifdef OPENGL_STYLE
out[0][0] = (cp*cy) * scale;
out[1][0] = (sr*sp*cy+cr*-sy) * scale;
out[2][0] = (cr*sp*cy+-sr*-sy) * scale;
out[3][0] = x;
out[0][1] = (cp*sy) * scale;
out[1][1] = (sr*sp*sy+cr*cy) * scale;
out[2][1] = (cr*sp*sy+-sr*cy) * scale;
out[3][1] = y;
out[0][2] = (-sp) * scale;
out[1][2] = (sr*cp) * scale;
out[2][2] = (cr*cp) * scale;
out[3][2] = z;
out[0][3] = 0;
out[1][3] = 0;
out[2][3] = 0;
out[3][3] = 1;
#else
out[0][0] = (cp*cy) * scale;
out[0][1] = (sr*sp*cy+cr*-sy) * scale;
out[0][2] = (cr*sp*cy+-sr*-sy) * scale;
out[0][3] = x;
out[1][0] = (cp*sy) * scale;
out[1][1] = (sr*sp*sy+cr*cy) * scale;
out[1][2] = (cr*sp*sy+-sr*cy) * scale;
out[1][3] = y;
out[2][0] = (-sp) * scale;
out[2][1] = (sr*cp) * scale;
out[2][2] = (cr*cp) * scale;
out[2][3] = z;
out[3][0] = 0;
out[3][1] = 0;
out[3][2] = 0;
out[3][3] = 1;
#endif
}
else if( pitch )
{
angle = yaw * (M_PI*2 / 360);
sy = sin(angle);
cy = cos(angle);
angle = pitch * (M_PI*2 / 360);
sp = sin(angle);
cp = cos(angle);
#ifdef OPENGL_STYLE
out[0][0] = (cp*cy) * scale;
out[1][0] = (-sy) * scale;
out[2][0] = (sp*cy) * scale;
out[3][0] = x;
out[0][1] = (cp*sy) * scale;
out[1][1] = (cy) * scale;
out[2][1] = (sp*sy) * scale;
out[3][1] = y;
out[0][2] = (-sp) * scale;
out[1][2] = 0;
out[2][2] = (cp) * scale;
out[3][2] = z;
out[0][3] = 0;
out[1][3] = 0;
out[2][3] = 0;
out[3][3] = 1;
#else
out[0][0] = (cp*cy) * scale;
out[0][1] = (-sy) * scale;
out[0][2] = (sp*cy) * scale;
out[0][3] = x;
out[1][0] = (cp*sy) * scale;
out[1][1] = (cy) * scale;
out[1][2] = (sp*sy) * scale;
out[1][3] = y;
out[2][0] = (-sp) * scale;
out[2][1] = 0;
out[2][2] = (cp) * scale;
out[2][3] = z;
out[3][0] = 0;
out[3][1] = 0;
out[3][2] = 0;
out[3][3] = 1;
#endif
}
else if( yaw )
{
angle = yaw * (M_PI*2 / 360);
sy = sin(angle);
cy = cos(angle);
#ifdef OPENGL_STYLE
out[0][0] = (cy) * scale;
out[1][0] = (-sy) * scale;
out[2][0] = 0;
out[3][0] = x;
out[0][1] = (sy) * scale;
out[1][1] = (cy) * scale;
out[2][1] = 0;
out[3][1] = y;
out[0][2] = 0;
out[1][2] = 0;
out[2][2] = scale;
out[3][2] = z;
out[0][3] = 0;
out[1][3] = 0;
out[2][3] = 0;
out[3][3] = 1;
#else
out[0][0] = (cy) * scale;
out[0][1] = (-sy) * scale;
out[0][2] = 0;
out[0][3] = x;
out[1][0] = (sy) * scale;
out[1][1] = (cy) * scale;
out[1][2] = 0;
out[1][3] = y;
out[2][0] = 0;
out[2][1] = 0;
out[2][2] = scale;
out[2][3] = z;
out[3][0] = 0;
out[3][1] = 0;
out[3][2] = 0;
out[3][3] = 1;
#endif
}
else
{
#ifdef OPENGL_STYLE
out[0][0] = scale;
out[1][0] = 0;
out[2][0] = 0;
out[3][0] = x;
out[0][1] = 0;
out[1][1] = scale;
out[2][1] = 0;
out[3][1] = y;
out[0][2] = 0;
out[1][2] = 0;
out[2][2] = scale;
out[3][2] = z;
out[0][3] = 0;
out[1][3] = 0;
out[2][3] = 0;
out[3][3] = 1;
#else
out[0][0] = scale;
out[0][1] = 0;
out[0][2] = 0;
out[0][3] = x;
out[1][0] = 0;
out[1][1] = scale;
out[1][2] = 0;
out[1][3] = y;
out[2][0] = 0;
out[2][1] = 0;
out[2][2] = scale;
out[2][3] = z;
out[3][0] = 0;
out[3][1] = 0;
out[3][2] = 0;
out[3][3] = 1;
#endif
}
}
#endif//BASEMATRIX_H

View File

@ -518,7 +518,7 @@ Studio models are position independent, so the cache manager can move them.
#define STUDIO_NF_FLATSHADE 0x0001
#define STUDIO_NF_CHROME 0x0002
#define STUDIO_NF_FULLBRIGHT 0x0004
#define STUDIO_NF_RESERVED 0x0008 // reserved
#define STUDIO_NF_COLORMAP 0x0008 // can changed by colormap command
#define STUDIO_NF_BLENDED 0x0010 // rendering as semiblended
#define STUDIO_NF_ADDITIVE 0x0020 // rendering with additive mode
#define STUDIO_NF_TRANSPARENT 0x0040 // use texture with alpha channel
@ -651,17 +651,12 @@ typedef struct
vec3_t bbmax;
} mstudiobbox_t;
typedef struct cache_user_s
{
void *data;
} cache_user_t;
// demand loaded sequence groups
typedef struct
{
char label[32]; // textual name
char name[64]; // file name
void* cache; // cache index pointer
void *cache; // cache index pointer (only in memory)
int data; // hack for group 0
} mstudioseqgroup_t;
@ -720,7 +715,6 @@ typedef struct
char options[64];
} mstudioevent_t;
// pivots
typedef struct
{
@ -785,7 +779,7 @@ typedef struct
char name[64];
int type;
float boundingradius;
float boundingradius; // software stuff
int nummesh;
int meshindex;

View File

@ -13,7 +13,7 @@
enum host_state
{ // paltform states
HOST_OFFLINE = 0, // host_init( funcname *arg ) same much as:
HOST_OFFLINE = 0, // host_init( g_Instance ) same much as:
HOST_NORMAL, // "normal"
HOST_DEDICATED, // "dedicated"
HOST_VIEWER, // "viewer"
@ -41,7 +41,7 @@ enum host_state
#define DLLEXPORT __declspec(dllexport)
#define USE_COORD_FRAC //FIXME: disable this
//#define USE_COORD_FRAC //FIXME: disable this
// network precision coords factor
#ifdef USE_COORD_FRAC
@ -64,7 +64,7 @@ typedef struct { byte r; byte g; byte b; byte a; } color32;
typedef struct { const char *name; void **func; } dllfunc_t; // Sys_LoadLibrary stuff
typedef struct { int ofs; int type; const char *name; } fields_t; // prvm custom fields
typedef void (*cmread_t) (void* handle, void* buffer, size_t size);
typedef enum { mod_bad, mod_brush, mod_studio, mod_sprite } modtype_t;
typedef enum { mod_bad, mod_static, mod_brush, mod_studio, mod_sprite } modtype_t;
typedef void (*cmsave_t) (void* handle, const void* buffer, size_t size);
typedef void (*cmdraw_t)( int color, int numpoints, const float *points );
typedef struct { int numfilenames; char **filenames; char *filenamesbuffer; } search_t;
@ -110,87 +110,122 @@ typedef struct model_s model_t;
typedef void (*xcommand_t) (void);
typedef enum
{
ED_SPAWNED = 0, // this entity requris to set own type with SV_ClassifyEdict
ED_STATIC, // this is a logic without model or entity with static model
ED_AMBIENT, // this is entity emitted ambient sounds only
ED_NORMAL, // normal entity with model (and\or) sound
ED_CLIENT, // this is a client entity
ED_MONSTER, // monster or bot (generic npc with AI)
ED_TEMPENTITY, // this edict will be removed on server when "lifetime" exceeds
ED_BEAM, // laser beam (needs to recalculate pvs and frustum)
ED_MOVER, // func_train, func_door and another bsp or mdl movers
ED_VIEWMODEL, // client or bot viewmodel (for spectating)
ED_ITEM, // holdable items
ED_RAGDOLL, // dead body with simulated ragdolls
ED_RIGIDBODY, // simulated physic
ED_TRIGGER, // just for sorting on a server
ED_PORTAL, // realtime display, portal or mirror brush or model
ED_MISSILE, // greande, rocket e.t.c
ED_DECAL, // render will be merge real coords and normal
ED_VEHICLE, // controllable vehicle
ED_MAXTYPES,
} edtype_t;
// phys movetype
typedef enum
{
MOVETYPE_NONE, // never moves
MOVETYPE_NOCLIP, // origin and angles change with no interaction
MOVETYPE_PUSH, // no clip to world, push on box contact
MOVETYPE_WALK, // gravity
MOVETYPE_STEP, // gravity, special edge handling
MOVETYPE_FLY,
MOVETYPE_TOSS, // gravity
MOVETYPE_BOUNCE,
MOVETYPE_FOLLOW, // attached models
MOVETYPE_CONVEYOR,
MOVETYPE_PUSHABLE,
MOVETYPE_PHYSIC, // phys simulation
} movetype_t;
// phys collision mode
typedef enum
{
SOLID_NOT = 0, // no interaction with other objects
SOLID_TRIGGER, // only touch when inside, after moving
SOLID_BBOX, // touch on edge
SOLID_BSP, // bsp clip, touch on edge
SOLID_BOX, // physbox
SOLID_SPHERE, // sphere
SOLID_CYLINDER, // cylinder e.g. barrel
SOLID_MESH, // custom convex hull
} solid_t;
// model_state_t communication
typedef struct model_state_s
{
int index; // server & client shared modelindex
int colormap; // change base color for some textures or sprite frames
float scale; // model or sprite scale, affects to physics too
float frame; // % playback position in animation sequences (0..255)
float animtime; // auto-animating time
float framerate; // custom framerate, specified by QC
int sequence; // animation sequence (0 - 255)
int gaitsequence; // client\nps\bot gaitsequence
int skin; // skin for studiomodels
int body; // sub-model selection for studiomodels
float blending[8]; // studio animation blending
float controller[32]; // studio bone controllers
vec3_t calcbonepos[128]; // too hard: ragdoll or like it, animated by physic engine
} model_state_t;
// entity_state_t communication
typedef struct entity_state_s
{
// engine specific
uint number; // edict index
edtype_t ed_type; // edict type
int soundindex; // looped ambient sound
// physics information
vec3_t origin;
vec3_t angles;
vec3_t angles; // entity angles, not viewangles
vec3_t velocity; // player velocity
vec3_t old_origin; // for lerping animation
int modelindex;
int soundindex;
int weaponmodel;
vec3_t old_velocity; // for movement predicting
model_state_t model; // general entity model
solid_t solidtype; // entity solidtype
movetype_t movetype; // entity movetype
int gravity; // gravity multiplier
int aiment; // attahced entity (not a physic attach, only rendering)
int solid; // using for symmetric bboxes
vec3_t mins; // not symmetric entity bbox
vec3_t maxs;
int skin; // skin for studiomodels
float frame; // % playback position in animation sequences (0..512)
int body; // sub-model selection for studiomodels
int sequence; // animation sequence (0 - 255)
uint effects; // PGM - we're filling it, so it needs to be unsigned
int renderfx;
int solid; // for client side prediction, 8*(bits 0-4) is x/y radius
// 8*(bits 5-9) is z down distance, 8(bits10-15) is z up
// gi.linkentity sets this properly
float alpha; // alpha value
float animtime; // auto-animating time
// render information
uint effects; // effect flags like q1 and hl1
int renderfx; // render effects same as hl1
float renderamt; // alpha value or like somewhat
vec3_t rendercolor; // hl1 legacy stuff, working, but not needed
int rendermode; // hl1 legacy stuff, working, but not needed
} entity_state_t;
// viewmodel state
typedef struct vmodel_state_s
{
int index; // client modelindex
vec3_t angles; // can be some different with viewangles
vec3_t offset; // center offset
int sequence; // studio animation sequence
float frame; // studio frame
int body; // weapon body
int skin; // weapon skin
} vmodel_state_t;
// thirdperson model state
typedef struct pmodel_state_s
{
int index; // client modelindex
int sequence; // studio animation sequence
float frame; // studio frame
} pmodel_state_t;
// player_state_t communication
typedef struct player_state_s
{
int bobcycle; // for view bobbing and footstep generation
float bobtime;
int pm_type; // player movetype
// client specific
int pm_type; // client movetype
int pm_flags; // ducked, jump_held, etc
int pm_time; // each unit = 8 ms
#ifdef USE_COORD_FRAC
int origin[3];
int velocity[3];
#else
vec3_t origin;
vec3_t velocity;
#endif
vec3_t delta_angles; // add to command angles to get view direction
int gravity; // gravity value
int speed; // maxspeed
edict_t *groundentity; // current ground entity
vec3_t delta_angles; // add to command angles to get view direction
vec3_t punch_angles; // add to view direction to get render angles
vec3_t viewangles; // already calculated view angles on server-side
vec3_t viewoffset; // FIXME: replace with viewheight
int viewheight; // height over ground
int effects; // copied to entity_state_t->effects
vec3_t viewangles; // for fixed views
vec3_t viewoffset; // add to pmovestate->origin
vec3_t kick_angles; // add to view direction to get render angles
vec3_t oldviewangles; // for lerping viewmodel position
vec4_t blend; // rgba full screen effect
int stats[32]; // integer limit
int maxspeed; // sv_maxspeed will be duplicate on all clients
float health; // client health (other parms can be send by custom messages)
float fov; // horizontal field of view
// player model and viewmodel
vmodel_state_t vmodel;
pmodel_state_t pmodel;
} player_state_t;
model_state_t vmodel; // viewmodel info
model_state_t pmodel; // weaponmodel info
} entity_state_t;
// usercmd_t communication
typedef struct usercmd_s
@ -265,7 +300,8 @@ typedef struct gameinfo_s
string source_dir; // default source directory
char key[16]; // cd-key info
char TXcommand; // quark command (get rid of this)
char TXcommand; // quark .map comment
char instance; // global engine instance
} gameinfo_t;
/*
@ -658,7 +694,8 @@ typedef struct stdilib_api_s
#define Com_SkipToken com.Com_SkipToken
#define Com_MatchToken com.Com_MatchToken
#define com_token com.com_token
#define g_TXcommand com.GameInfo->TXcommand // get rid of this
#define g_TXcommand com.GameInfo->TXcommand
#define g_Instance com.GameInfo->instance
/*
===========================================
@ -824,36 +861,6 @@ internal physic data
hold linear and angular velocity, current position stored too
========================================================================
*/
// phys movetype
typedef enum
{
MOVETYPE_NONE, // never moves
MOVETYPE_NOCLIP, // origin and angles change with no interaction
MOVETYPE_PUSH, // no clip to world, push on box contact
MOVETYPE_WALK, // gravity
MOVETYPE_STEP, // gravity, special edge handling
MOVETYPE_FLY,
MOVETYPE_TOSS, // gravity
MOVETYPE_BOUNCE,
MOVETYPE_FOLLOW, // attached models
MOVETYPE_CONVEYOR,
MOVETYPE_PUSHABLE,
MOVETYPE_PHYSIC, // phys simulation
} movetype_t;
// phys collision mode
typedef enum
{
SOLID_NOT = 0, // no interaction with other objects
SOLID_TRIGGER, // only touch when inside, after moving
SOLID_BBOX, // touch on edge
SOLID_BSP, // bsp clip, touch on edge
SOLID_BOX, // physbox
SOLID_SPHERE, // sphere
SOLID_CYLINDER, // cylinder e.g. barrel
SOLID_MESH, // custom convex hull
} solid_t;
typedef struct physdata_s
{
vec3_t origin;
@ -896,6 +903,7 @@ typedef struct cvar_s
#define ROLL 2
#define MAX_LIGHTSTYLES 256
#define MAX_EDICTS 65535 // absolute limit that never be reached
#define EF_ROTATE (1<<0) // rotate (bonus items)
@ -951,7 +959,7 @@ MAP CONTENTS & SURFACES DESCRIPTION
#define CONTENTS_CURRENT_UP 0x400000
#define CONTENTS_CURRENT_DOWN 0x800000
#define CONTENTS_ORIGIN 0x1000000 // removed before bsping an entity
#define CONTENTS_MONSTER 0x2000000 // should never be on a brush, only in game
#define CONTENTS_BODY 0x2000000 // should never be on a brush, only in game
#define CONTENTS_DEADMONSTER 0x4000000
#define CONTENTS_DETAIL 0x8000000 // brushes to be added after vis leafs
#define CONTENTS_TRANSLUCENT 0x10000000// auto set if any surface has trans
@ -1009,7 +1017,9 @@ typedef struct cplane_s
typedef struct cmesh_s
{
vec3_t *verts;
int *indices;
uint numverts;
uint numtris;
} cmesh_t;
typedef struct cmodel_s
@ -1026,7 +1036,15 @@ typedef struct cmodel_s
int numbrushes;
int numframes; // sprite framecount
int numbodies; // physmesh numbody
cmesh_t physmesh[MAXSTUDIOMODELS]; // max bodies
cmesh_t *col[256]; // max bodies
// g-cont: stupid pushmodel stuff
vec3_t normalmins; // bounding box at angles '0 0 0'
vec3_t normalmaxs;
vec3_t yawmins; // bounding box if yaw angle is not 0, but pitch and roll are
vec3_t yawmaxs;
vec3_t rotatedmins; // bounding box if pitch or roll are used
vec3_t rotatedmaxs;
// custom traces for various model types
void (*TraceBox)( const vec3_t start, const vec3_t end, const vec3_t mins, const vec3_t maxs, struct cmodel_s *model, struct trace_s *trace, int brushsmask );
@ -1036,12 +1054,19 @@ typedef struct cmodel_s
typedef struct csurface_s
{
string name;
int flags;
int surfaceflags;
int contentflags;
int value;
// physics stuff
int firstedge; // look up in model->surfedges[], negative numbers
int numedges; // are backwards edges
vec3_t mins;
vec3_t maxs;
// patches support
int numtriangles;
int numvertices;
int *indices;
float *vertices;
int markframe;
} csurface_t;
typedef struct trace_s
@ -1066,12 +1091,12 @@ typedef struct trace_s
// content masks
#define MASK_ALL (-1)
#define MASK_SOLID (CONTENTS_SOLID|CONTENTS_WINDOW)
#define MASK_PLAYERSOLID (CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_WINDOW|CONTENTS_MONSTER)
#define MASK_PLAYERSOLID (CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_WINDOW|CONTENTS_BODY)
#define MASK_DEADSOLID (CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_WINDOW)
#define MASK_MONSTERSOLID (CONTENTS_SOLID|CONTENTS_MONSTERCLIP|CONTENTS_WINDOW|CONTENTS_MONSTER)
#define MASK_MONSTERSOLID (CONTENTS_SOLID|CONTENTS_MONSTERCLIP|CONTENTS_WINDOW|CONTENTS_BODY)
#define MASK_WATER (CONTENTS_WATER|CONTENTS_LAVA|CONTENTS_SLIME)
#define MASK_OPAQUE (CONTENTS_SOLID|CONTENTS_SLIME|CONTENTS_LAVA)
#define MASK_SHOT (CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_WINDOW|CONTENTS_DEADMONSTER)
#define MASK_SHOT (CONTENTS_SOLID|CONTENTS_BODY|CONTENTS_WINDOW|CONTENTS_DEADMONSTER)
#define MASK_CURRENT (CONTENTS_CURRENT_0|CONTENTS_CURRENT_90|CONTENTS_CURRENT_180|CONTENTS_CURRENT_270|CONTENTS_CURRENT_UP|CONTENTS_CURRENT_DOWN)
// pmove_state_t is the information necessary for client side movement
@ -1250,7 +1275,7 @@ typedef struct
typedef struct pmove_s
{
player_state_t ps; // state (in / out)
entity_state_t ps; // state (in / out)
// command (in)
usercmd_t cmd;
@ -1260,6 +1285,7 @@ typedef struct pmove_s
// results (out)
int numtouch;
edict_t *touchents[PM_MAXTOUCH]; // max touch
edict_t *groundentity;
vec3_t mins, maxs; // bounding box size
int watertype;
@ -1282,7 +1308,7 @@ typedef struct launch_exp_s
// interface validator
size_t api_size; // must matched with sizeof(launch_api_t)
void ( *Init ) ( uint funcname, int argc, char **argv ); // init host
void ( *Init ) ( int argc, char **argv ); // init host
void ( *Main ) ( void ); // host frame
void ( *Free ) ( void ); // close host
void (*CPrint) ( const char *msg ); // host print
@ -1316,8 +1342,8 @@ typedef struct imglib_exp_s
// interface validator
size_t api_size; // must matched with sizeof(imglib_api_t)
void ( *Init ) ( uint funcname ); // init host
void ( *Free ) ( void ); // close host
void ( *Init ) ( void ); // init host
void ( *Free ) ( void ); // close host
// global operations
rgbdata_t *(*LoadImage)(const char *path, const byte *data, size_t size ); // extract image into rgba buffer
@ -1413,10 +1439,6 @@ typedef struct physic_exp_s
int (*NumBmodels )( void );
const char *(*GetEntityString)( void );
const char *(*GetTextureName)( int index );
int (*PointContents)( const vec3_t p, cmodel_t *model );
int (*TransformedPointContents)( const vec3_t p, cmodel_t *model, const vec3_t origin, const vec3_t angles );
void (*BoxTrace)( const vec3_t start, const vec3_t end, vec3_t mins, vec3_t maxs, cmodel_t *model, trace_t *tr, int brushmask );
trace_t (*TransformedBoxTrace)( const vec3_t start, const vec3_t end, vec3_t mins, vec3_t maxs, cmodel_t *model, int brushmask, vec3_t origin, vec3_t angles, bool capsule );
byte *(*ClusterPVS)( int cluster );
byte *(*ClusterPHS)( int cluster );
int (*PointLeafnum)( vec3_t p );
@ -1426,11 +1448,12 @@ typedef struct physic_exp_s
bool (*AreasConnected)( int area1, int area2 );
int (*WriteAreaBits)( byte *buffer, int area );
void (*ClipToGenericEntity)( trace_t *trace, cmodel_t *model, const vec3_t bodymins, const vec3_t bodymaxs, int bodysupercontents, matrix4x4 matrix, matrix4x4 inversematrix, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int contentsmask );
void (*ClipToWorld)( trace_t *trace, cmodel_t *model, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int contentsmask );
void (*CombineTraces)( trace_t *cliptrace, const trace_t *trace, edict_t *touch, bool is_bmodel );
// player movement code
void (*PlayerMove)( pmove_t *pmove, bool clientmove );
void (*ServerMove)( pmove_t *pmove );
void (*ClientMove)( pmove_t *pmove );
// simple objects
physbody_t *(*CreateBody)( sv_edict_t *ed, cmodel_t *mod, matrix4x3 transform, int solid );
@ -1619,8 +1642,8 @@ typedef struct vprogs_exp_s
// interface validator
size_t api_size; // must matched with sizeof(vprogs_api_t)
void ( *Init ) ( uint funcname, int argc, char **argv ); // init host
void ( *Free ) ( void ); // close host
void ( *Init ) ( int argc, char **argv ); // init host
void ( *Free ) ( void ); // close host
// compiler functions
void ( *PrepareDAT )( const char *dir, const char *name );

View File

@ -853,8 +853,9 @@ void Mod_SetupSubmodels( model_t *mod )
starmod->firstmodelsurface = bm->firstface;
starmod->nummodelsurfaces = bm->numfaces;
starmod->type = mod_brush;
starmod->firstnode = bm->headnode;
if (starmod->firstnode >= loadmodel->numnodes)
if( starmod->firstnode >= loadmodel->numnodes )
Host_Error ("Inline model %i has bad firstnode", i);
VectorCopy (bm->maxs, starmod->maxs);
@ -877,7 +878,7 @@ void Mod_LoadBrushModel (model_t *mod, void *buffer)
dheader_t *header;
loadmodel->type = mod_brush;
loadmodel->type = mod_static;
if (loadmodel != mod_known)
{
Msg("Warning: loaded a brush model after the world\n");

View File

@ -172,7 +172,7 @@ void R_SpriteLoadModel( model_t *mod, void *buffer )
pframetype = R_SpriteLoadGroup(mod, pframetype + 1, &psprite->frames[i].frameptr, i );
break;
}
if(pframetype == NULL) break; // technically an error
if( pframetype == NULL ) break; // technically an error
}
}

View File

@ -483,20 +483,17 @@ StudioGetAnim
mstudioanim_t *R_StudioGetAnim( model_t *m_pSubModel, mstudioseqdesc_t *pseqdesc )
{
mstudioseqgroup_t *pseqgroup;
cache_user_t *paSequences;
byte *buf;
int filesize;
byte *paSequences;
size_t filesize;
byte *buf;
//WARNING! Not tested!!!
pseqgroup = (mstudioseqgroup_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqgroupindex) + pseqdesc->seqgroup;
if (pseqdesc->seqgroup == 0)
{
if( pseqdesc->seqgroup == 0 )
return (mstudioanim_t *)((byte *)m_pStudioHeader + pseqgroup->data + pseqdesc->animindex);
}
paSequences = (cache_user_t *)m_pSubModel->submodels;
paSequences = (void *)m_pSubModel->submodels;
if (paSequences == NULL)
{
@ -508,18 +505,18 @@ mstudioanim_t *R_StudioGetAnim( model_t *m_pSubModel, mstudioseqdesc_t *pseqdesc
memset (pseqgroup->name, 0, sizeof(pseqgroup->name));
return NULL;
}
if(IDSEQGRPHEADER == LittleLong(*(unsigned *)buf)) //it's sequence group
if(IDSEQGRPHEADER == LittleLong(*(uint *)buf)) //it's sequence group
{
byte *pin = (byte *)buf;
mstudioseqgroup_t *pseqhdr = (mstudioseqgroup_t *)pin;
paSequences = (cache_user_t *)Mem_Alloc(m_pSubModel->mempool, LittleLong(filesize));
paSequences = (byte *)Mem_Alloc(m_pSubModel->mempool, filesize );
m_pSubModel->submodels = (mmodel_t *)paSequences;
memcpy((struct cache_user_s *)&paSequences[pseqdesc->seqgroup], buf, LittleLong(filesize));
Mem_Copy(&paSequences[pseqdesc->seqgroup], buf, filesize );
}
}
return (mstudioanim_t *)((byte *)paSequences[pseqdesc->seqgroup].data + pseqdesc->animindex);
return (mstudioanim_t *)((byte *)paSequences[pseqdesc->seqgroup] + pseqdesc->animindex);
}
/*

View File

@ -316,7 +316,7 @@ void R_InitTextures( void )
CreateImglib = (void *)imglib_dll.main;
Image = CreateImglib( &com, NULL ); // second interface not allowed
Image->Init( HOST_NORMAL );
Image->Init();
r_imagepool = Mem_AllocPool("Texture Pool");
gl_maxsize = Cvar_Get( "gl_maxsize", "4096", CVAR_ARCHIVE, "texture dimension max size" );

View File

@ -113,7 +113,7 @@ idconv.dll needs for some setup operations
so do it manually
==================
*/
void InitConvertor ( uint funcname, int argc, char **argv )
void InitConvertor ( int argc, char **argv )
{
launch_t CreateImglib, CreateVprogs;
string gamedir;
@ -121,20 +121,20 @@ void InitConvertor ( uint funcname, int argc, char **argv )
// init pools
basepool = Mem_AllocPool( "Temp" );
zonepool = Mem_AllocPool( "Zone" );
app_name = funcname;
app_name = g_Instance;
Sys_LoadLibrary( &imglib_dll ); // load imagelib
CreateImglib = (void *)imglib_dll.main;
Image = CreateImglib( &com, NULL ); // second interface not allowed
switch( funcname )
switch( app_name )
{
case RIPP_QCCDEC:
Sys_LoadLibrary( &vprogs_dll ); // load qcclib
CreateVprogs = (void *)vprogs_dll.main;
PRVM = CreateVprogs( &com, NULL ); // second interface not allowed
PRVM->Init( funcname, argc, argv );
PRVM->Init( argc, argv );
if(!FS_GetParmFromCmdLine("-dir", gamedir ))
com.strncpy( gamedir, ".", sizeof(gamedir));
@ -143,7 +143,7 @@ void InitConvertor ( uint funcname, int argc, char **argv )
break;
default:
FS_InitRootDir(".");
Image->Init( funcname ); // initialize image support
Image->Init(); // initialize image support
break;
}

View File

@ -28,6 +28,8 @@ fopen
5. Собрать все ресурсы в builtin.h OK
6. r_backend.c
0. Новый сетевой протоколб смена entity_state_t
Физика игрока:
1. Убрать отскоки от стен
2. Исправить код деформации хулла

View File

@ -448,7 +448,7 @@ void GUI_LoadWndOptions( wnd_options_t *settings )
s_gui.height = w_opts.height;
}
bool GUI_LoadPlatfrom( uint funcname, int argc, char **argv )
bool GUI_LoadPlatfrom( int argc, char **argv )
{
FS_ClearSearchPath();
FS_AddGameHierarchy( "bin" );
@ -849,7 +849,7 @@ static LRESULT CALLBACK WndProc (HWND hwnd, UINT uMessage, WPARAM wParam, LPARAM
return DefWindowProc (hwnd, uMessage, wParam, lParam);
}
void InitViewer ( uint funcname, int argc, char **argv )
void InitViewer ( int argc, char **argv )
{
HDC hDC;
WNDCLASS wc;
@ -895,7 +895,7 @@ void InitViewer ( uint funcname, int argc, char **argv )
GUI_ResetWndOptions(); // load default settings
InitCommonControls ();
if(GUI_LoadPlatfrom( funcname, argc, argv )) //load config
if(GUI_LoadPlatfrom( argc, argv )) //load config
{
wnd_options_t *config_dat;
int config_size;

View File

@ -22,7 +22,7 @@
//=====================================
// main editor funcs
//=====================================
void InitViewer ( uint funcname, int argc, char **argv );
void InitViewer ( int argc, char **argv );
void ViewerMain ( void );
void FreeViewer ( void );

View File

@ -1214,7 +1214,7 @@ void PRVM_LoadProgs( const char *filename, int numedfunc, char **ed_func, int nu
}
else if( vm.prog->progs->crc != vm.prog->filecrc )
{
PRVM_ERROR("%s: %s system vars have been modified, progdefs.h is out of date %d\n", PRVM_NAME, filename );
PRVM_ERROR("%s: %s system vars have been modified, progdefs.h is out of date %d\n", PRVM_NAME, vm.prog->filecrc );
}
else MsgDev(D_LOAD, "%s [^2CRC %d^7]\n", filename, vm.prog->progs->crc );

View File

@ -255,7 +255,7 @@ void PR_InitDecompile( const char *name )
PR_InitTypes();
}
void PRVM_Init( uint funcname, int argc, char **argv )
void PRVM_Init( int argc, char **argv )
{
char dev_level[4];
@ -263,7 +263,7 @@ void PRVM_Init( uint funcname, int argc, char **argv )
com_argv = argv;
qccpool = Mem_AllocPool( "VM progs" );
host_instance = funcname;
host_instance = g_Instance;
if(FS_GetParmFromCmdLine("-dev", dev_level ))
prvm_developer = com.atoi(dev_level);

View File

@ -551,11 +551,11 @@ word PR_WriteProgdefs( void )
switch( crc )
{
case 2740:
case 61861:
PR_Message("Xash3D unmodified server.dat\n");
if(!com.strcmp(progsoutname, "unknown.dat")) com.strcpy(progsoutname, "server.dat");
break;
case 4546:
case 3720:
PR_Message("Xash3D unmodified client.dat\n");
if(!com.strcmp(progsoutname, "unknown.dat")) com.strcpy(progsoutname, "client.dat");
break;

View File

@ -179,7 +179,7 @@ const char *(_cdecl *palcGetString )( aldevice *device, int param );
void (_cdecl *palcGetIntegerv)( aldevice *device, int param, int size, int *dest );
int (_cdecl *palcGetError)( aldevice *device );
char (_cdecl *palcIsExtensionPresent)( aldevice *device, const char *extname );
void *(_cdecl *palcGetProcAddress)( aldevice *device, const char *funcname );
void *(_cdecl *palcGetProcAddress)( aldevice *device, const char *function );
int (_cdecl *palcGetEnumValue)( aldevice *device, const char *enumname );
void (_cdecl *palBufferData)( uint bid, int format, const void* data, int size, int freq );