From a2a61486e27c22f177a2ed2fe40be53a1732f40f Mon Sep 17 00:00:00 2001 From: g-cont Date: Mon, 18 Oct 2010 00:00:00 +0400 Subject: [PATCH] 18 Oct 2010 --- client/hud/hud.cpp | 6 + client/hud/hud.h | 3 + client/hud/hud_msg.cpp | 9 +- common/custom.h | 76 ++++++ common/eiface.h | 22 +- engine/client/cl_main.c | 8 + engine/client/cl_parse.c | 52 +++- engine/common/cm_light.c | 7 + engine/common/net_encode.c | 2 +- engine/common/net_encode.h | 2 +- engine/common/protocol.h | 8 +- engine/host.c | 2 +- engine/server/server.h | 8 +- engine/server/sv_client.c | 2 + engine/server/sv_frame.c | 26 ++ engine/server/sv_game.c | 131 +++++++--- engine/server/sv_init.c | 4 +- engine/server/sv_move.c | 475 ++++++++++++++++++++++++------------- engine/server/sv_phys.c | 5 +- engine/server/sv_world.c | 79 ++++++ 20 files changed, 696 insertions(+), 231 deletions(-) create mode 100644 common/custom.h diff --git a/client/hud/hud.cpp b/client/hud/hud.cpp index 36f95a92..0f1754d7 100644 --- a/client/hud/hud.cpp +++ b/client/hud/hud.cpp @@ -271,6 +271,12 @@ int CHud :: Redraw( float flTime ) // clock was reset, reset delta if( m_flTimeDelta < 0 ) m_flTimeDelta = 0; + if( v_dark ) + { + SetScreenFade( Vector( 0, 0, 0 ), 255, 4, 4, FFADE_IN ); + v_dark = FALSE; + } + // draw screen fade before hud DrawScreenFade(); diff --git a/client/hud/hud.h b/client/hud/hud.h index 122ae2d7..04a2717c 100644 --- a/client/hud/hud.h +++ b/client/hud/hud.h @@ -639,6 +639,9 @@ public: Vector m_vecFadeColor; float m_flFadeAlpha; BOOL m_bModulate; + + // v_dark issues + BOOL v_dark; // error sprite int m_HUD_error; diff --git a/client/hud/hud_msg.cpp b/client/hud/hud_msg.cpp index d18d88c7..f98c250d 100644 --- a/client/hud/hud_msg.cpp +++ b/client/hud/hud_msg.cpp @@ -146,12 +146,9 @@ int CHud :: MsgFunc_ResetHUD(const char *pszName, int iSize, void *pbuf ) m_flStartDist = 0; m_flEndDist = 0; - if( CVAR_GET_FLOAT( "v_dark" )) - { - SetScreenFade( Vector( 0, 0, 0 ), 255, 4, 4, FFADE_IN ); - CVAR_SET_FLOAT( "v_dark", 0.0f ); - } - + v_dark = CVAR_GET_FLOAT( "v_dark" ); + CVAR_SET_FLOAT( "v_dark", 0.0f ); + return 1; } diff --git a/common/custom.h b/common/custom.h new file mode 100644 index 00000000..d637062a --- /dev/null +++ b/common/custom.h @@ -0,0 +1,76 @@ +//======================================================================= +// Copyright XashXT Group 2010 © +// custom.h - create custom user recources +//======================================================================= +#ifndef CUSTOM_H +#define CUSTOM_H + +#include "const.h" + +///////////////// +// Customization +// passed to pfnPlayerCustomization +// For automatic downloading. + +typedef enum +{ + t_sound = 0, + t_skin, + t_model, + t_decal, + t_generic, + t_eventscript, + t_world, // fake type for world, is really t_model +} resourcetype_t; + +typedef struct +{ + int size; +} _resourceinfo_t; + +typedef struct resourceinfo_s +{ + _resourceinfo_t info[8]; +} resourceinfo_t; + +#define RES_FATALIFMISSING (1<<0) // Disconnect if we can't get this file. +#define RES_WASMISSING (1<<1) // Do we have the file locally, did we get it ok? +#define RES_CUSTOM (1<<2) // Is this resource one that corresponds to another player's customization + // or is it a server startup resource. +#define RES_REQUESTED (1<<3) // Already requested a download of this one +#define RES_PRECACHED (1<<4) // Already precached + +typedef struct resource_s +{ + char szFileName[64]; // file name to download/precache. + resourcetype_t type; // t_sound, t_skin, t_model, t_decal. + int nIndex; // for t_decals + int nDownloadSize; // size in bytes if this must be downloaded. + byte ucFlags; + + // for handling client to client resource propagation + byte rgucMD5_hash[16]; // to determine if we already have it. + byte playernum; // which player index this resource is associated with, + // if it's a custom resource. + + byte rguc_reserved[32]; // for future expansion + struct resource_s *pNext; // Next in chain. + struct resource_s *pPrev; +} resource_t; + +typedef struct custom_s +{ + BOOL bInUse; // is this customization in use; + resource_t resource; // the resource_t for this customization + BOOL bTranslated; // has the raw data been translated into a useable format? + // (e.g., raw decal .wad make into texture_t *) + int nUserData1; // sustomization specific data + int nUserData2; // customization specific data + void *pInfo; // buffer that holds the data structure that references + // the data (e.g., the cachewad_t) + void *pBuffer; // buffer that holds the data for the customization + // (the raw .wad data) + struct customization_s *pNext; // next in chain +} customization_t; + +#endif // CUSTOM_H \ No newline at end of file diff --git a/common/eiface.h b/common/eiface.h index f2127276..7534f7e5 100644 --- a/common/eiface.h +++ b/common/eiface.h @@ -6,6 +6,7 @@ #define EIFACE_H #include "cvardef.h" +#include "custom.h" #define INTERFACE_VERSION 140 // GetEntityAPI, GetEntityAPI2 #define NEW_DLL_FUNCTIONS_VERSION 2 // GetNewDLLFunctions (Xash3D uses version 2) @@ -17,9 +18,9 @@ typedef enum { at_notice, at_console, // format: [msg] + at_aiconsole, // same as at_console, but only shown if developer level is 2! at_warning, // format: Warning: [msg] at_error, // format: Error: [msg] - at_aiconsole, // same as at_console, but only shown if developer level is 5! at_logged // server print to console ( only in multiplayer games ). (NOT IMPLEMENTED) } ALERT_TYPE; @@ -34,9 +35,10 @@ typedef enum // for integrity checking of content on clients typedef enum { - force_exactfile, // file on client must exactly match server's file - force_model_samebounds, // for model files only, the geometry must fit in the same bbox - force_model_specifybounds, // for model files only, the geometry must fit in the specified bbox + force_exactfile, // file on client must exactly match server's file + force_model_samebounds, // for model files only, the geometry must fit in the same bbox + force_model_specifybounds, // for model files only, the geometry must fit in the specified bbox + force_model_specifybounds_if_avail, // for model files only, the geometry must fit in the specified bbox (if the file is available) } FORCE_TYPE; typedef struct @@ -63,16 +65,16 @@ typedef struct enginefuncs_s int (*pfnModelFrames)( int modelIndex ); void (*pfnSetSize)( edict_t *e, const float *rgflMin, const float *rgflMax ); void (*pfnChangeLevel)( const char* s1, const char* s2 ); - edict_t* (*pfnFindClientInPHS)( edict_t *pEdict ); - edict_t* (*pfnEntitiesInPHS)( edict_t *pplayer ); + edict_t* (*pfnFindClientInPHS)( edict_t *pEdict ); // was pfnGetSpawnParms + edict_t* (*pfnEntitiesInPHS)( edict_t *pplayer ); // was pfnSaveSpawnParms float (*pfnVecToYaw)( const float *rgflVector ); void (*pfnVecToAngles)( const float *rgflVectorIn, float *rgflVectorOut ); void (*pfnMoveToOrigin)( edict_t *ent, const float *pflGoal, float dist, int iMoveType ); void (*pfnChangeYaw)( edict_t* ent ); void (*pfnChangePitch)( edict_t* ent ); - edict_t* (*pfnFindEntityByString)( edict_t *pStartEdict, const char *pszField, const char *pszValue); + edict_t* (*pfnFindEntityByString)( edict_t *pEdictStartSearchAfter, const char *pszField, const char *pszValue ); int (*pfnGetEntityIllum)( edict_t* pEnt ); - edict_t* (*pfnFindEntityInSphere)( edict_t *pStartEdict, const float *org, float rad ); + edict_t* (*pfnFindEntityInSphere)( edict_t *pEdictStartSearchAfter, const float *org, float rad ); edict_t* (*pfnFindClientInPVS)( edict_t *pEdict ); edict_t* (*pfnEntitiesInPVS)( edict_t *pplayer ); void (*pfnMakeVectors)( const float *rgflVector ); @@ -81,7 +83,7 @@ typedef struct enginefuncs_s void (*pfnRemoveEntity)( edict_t* e ); edict_t* (*pfnCreateNamedEntity)( string_t className ); void (*pfnMakeStatic)( edict_t *ent ); - void (*pfnLinkEdict)( edict_t *e, int touch_triggers ); // a part of CustomPhysics implementation + int (*pfnEntIsOnFloor)( edict_t *e ); int (*pfnDropToFloor)( edict_t* e ); int (*pfnWalkMove)( edict_t *ent, float yaw, float dist, int iMode ); void (*pfnSetOrigin)( edict_t *e, const float *rgflOrigin ); @@ -93,7 +95,7 @@ typedef struct enginefuncs_s void (*pfnTraceHull)( const float *v1, const float *v2, int fNoMonsters, int hullNumber, edict_t *pentToSkip, TraceResult *ptr ); void (*pfnTraceModel)( const float *v1, const float *v2, int hullNumber, edict_t *pent, TraceResult *ptr ); const char *(*pfnTraceTexture)( edict_t *pTextureEntity, const float *v1, const float *v2 ); - int (*pfnBoxVisible)( const float *mins, const float *maxs, const byte *pset ); + int (*pfnBoxVisible)( const float *mins, const float *maxs, const byte *pset ); // was pfnTraceSphere void (*pfnGetAimVector)( edict_t* ent, float speed, float *rgflReturn ); void (*pfnServerCommand)( const char* str ); void (*pfnServerExecute)( void ); diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index de4c169d..d6d53d86 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -285,6 +285,14 @@ usercmd_t CL_CreateCmd( void ) clgame.dllFuncs.pfnCreateMove( &cmd, cl.time - cl.oldtime, ( cls.state == ca_active && !cl.refdef.paused )); + if( re ) + { + vec3_t color; + + re->LightForPoint( cl.frame.clientdata.origin, color ); + cmd.lightlevel = VectorAvg( color ) * 255; + } + // random seed for predictable random values cl.random_seed = Com_RandomLong( 0, 0x7fffffff ); // full range diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index acbb8556..de45d974 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -28,13 +28,13 @@ const char *svc_strings[256] = "svc_setangle", "svc_serverdata", "svc_restore", - "svc_frame", + "svc_updateuserinfo", "svc_usermessage", "svc_clientdata", "svc_download", "svc_updatepings", "svc_particle", - "svc_ambientsound", + "svc_frame", "svc_spawnstatic", "svc_crosshairangle", "svc_spawnbaseline", @@ -44,7 +44,7 @@ const char *svc_strings[256] = "svc_centerprint", "svc_event", "svc_event_reliable", - "svc_updateuserinfo", + "svc_ambientsound", "svc_intermission", "svc_soundfade", "svc_cdtrack", @@ -452,6 +452,46 @@ void CL_ParseParticles( sizebuf_t *msg ) clgame.dllFuncs.pfnParticleEffect( org, dir, color, count ); } +/* +================== +CL_ParseStaticEntity + +================== +*/ +void CL_ParseStaticEntity( sizebuf_t *msg ) +{ + entity_state_t ent; + int i; + + Mem_Set( &ent, 0, sizeof( ent )); + + ent.modelindex = BF_ReadShort( msg ); + ent.sequence = BF_ReadByte( msg ); + ent.frame = BF_ReadByte( msg ); + ent.colormap = BF_ReadWord( msg ); + ent.skin = BF_ReadByte( msg ); + + for( i = 0; i < 3; i++ ) + { + ent.origin[i] = BF_ReadBitCoord( msg ); + ent.angles[i] = BF_ReadBitAngle( msg, 16 ); + } + + ent.rendermode = BF_ReadByte( msg ); + + if( ent.rendermode != kRenderNormal ) + { + ent.renderamt = BF_ReadByte( msg ); + ent.rendercolor.r = BF_ReadByte( msg ); + ent.rendercolor.g = BF_ReadByte( msg ); + ent.rendercolor.b = BF_ReadByte( msg ); + ent.renderfx = BF_ReadByte( msg ); + } + + // FIXME: allocate client entity, add new static... + MsgDev( D_ERROR, "Static entities are not implemented\n" ); +} + /* ================== CL_ParseStaticDecal @@ -1081,12 +1121,12 @@ void CL_ParseServerMessage( sizebuf_t *msg ) case svc_particle: CL_ParseParticles( msg ); break; + case svc_spawnstatic: + CL_ParseStaticEntity( msg ); + break; case svc_ambientsound: CL_ParseSoundPacket( msg, true ); break; - case svc_spawnstatic: - Host_Error( "svc_spawnstatic: not implemented\n" ); - break; case svc_crosshairangle: CL_ParseCrosshairAngle( msg ); break; diff --git a/engine/common/cm_light.c b/engine/common/cm_light.c index bd3333fc..00a9d14b 100644 --- a/engine/common/cm_light.c +++ b/engine/common/cm_light.c @@ -187,6 +187,13 @@ int CM_LightEntity( edict_t *pEdict ) return 255; } + if( pEdict->v.flags & FL_CLIENT ) + { + // client has more precision light level + // that come from client + return pEdict->v.light_level; + } + VectorCopy( pEdict->v.origin, start ); VectorCopy( pEdict->v.origin, end ); diff --git a/engine/common/net_encode.c b/engine/common/net_encode.c index 53a06db8..74498d30 100644 --- a/engine/common/net_encode.c +++ b/engine/common/net_encode.c @@ -697,7 +697,7 @@ void Delta_ParseTable( script_t *delta_script, delta_info_t *dt, const char *enc if( !com.stricmp( encodeDll, "none" )) dt->customEncode = CUSTOM_NONE; else if( !com.stricmp( encodeDll, "gamedll" )) - dt->customEncode = CUSTOM_SEREVR_ENCODE; + dt->customEncode = CUSTOM_SERVER_ENCODE; else if( !com.stricmp( encodeDll, "clientdll" )) dt->customEncode = CUSTOM_CLIENT_ENCODE; diff --git a/engine/common/net_encode.h b/engine/common/net_encode.h index 4715e0c6..582ce2f7 100644 --- a/engine/common/net_encode.h +++ b/engine/common/net_encode.h @@ -29,7 +29,7 @@ enum { CUSTOM_NONE = 0, - CUSTOM_SEREVR_ENCODE, // keyword "gamedll" + CUSTOM_SERVER_ENCODE, // keyword "gamedll" CUSTOM_CLIENT_ENCODE, // keyword "client" }; diff --git a/engine/common/protocol.h b/engine/common/protocol.h index 625d675b..d6a3ad11 100644 --- a/engine/common/protocol.h +++ b/engine/common/protocol.h @@ -21,14 +21,14 @@ #define svc_setangle 10 // [angle angle] set the view angle to this absolute value #define svc_serverdata 11 // [long] protocol ... #define svc_restore 12 // restore saved game on the client -#define svc_frame 13 // begin a new server frame +#define svc_updateuserinfo 13 // [byte] playernum, [string] userinfo #define svc_usermessage 14 // [string][byte] REG_USER_MSG stuff #define svc_clientdata 15 // [...] #define svc_download 16 // [short] size [size bytes] #define svc_updatepings 17 // [bit][idx][ping][packet_loss] #define svc_particle 18 // [float*3][char*3][byte][byte] -#define svc_ambientsound 19 // -#define svc_spawnstatic 20 // NOT IMPLEMENTED +#define svc_frame 19 // +#define svc_spawnstatic 20 // creates a static client entity #define svc_crosshairangle 21 // [short][short][short] #define svc_spawnbaseline 22 // #define svc_temp_entity 23 // @@ -37,7 +37,7 @@ #define svc_centerprint 26 // [string] to put in center of the screen #define svc_event 27 // playback event queue #define svc_event_reliable 28 // playback event directly from message, not queue -#define svc_updateuserinfo 29 // [byte] playernum, [string] userinfo +#define svc_ambientsound 29 // #define svc_intermission 30 // empty message (event) #define svc_soundfade 31 // [float*4] sound fade parms #define svc_cdtrack 32 // [byte] track [byte] looptrack diff --git a/engine/host.c b/engine/host.c index 6cbce550..42099e8a 100644 --- a/engine/host.c +++ b/engine/host.c @@ -219,7 +219,7 @@ void Host_CheckChanges( void ) if(( host_video->modified || host_audio->modified ) && CL_Active( )) { host.soundList = (soundlist_t *)Z_Malloc( sizeof( soundlist_t ) * 128 ); - host.numsounds = S_GetCurrentStaticSounds( host.soundList, 128, CHAN_AUTO ); + host.numsounds = S_GetCurrentStaticSounds( host.soundList, 128, CHAN_STATIC ); Msg( "Total stored %i sounds\n", host.numsounds ); } diff --git a/engine/server/server.h b/engine/server/server.h index 2b6820aa..6addda6f 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -153,6 +153,8 @@ typedef struct sv_client_s float latency; float ping; + int listeners; // 32 bits == MAX_CLIENTS (voice listeners) + float addangle; // add angles to client position edict_t *edict; // EDICT_NUM(clientnum+1) @@ -381,9 +383,10 @@ bool SV_TestPlayerPosition( edict_t *ent ); // for PlayerInSolid checks // // sv_move.c // -bool SV_WalkMove( edict_t *ent, const vec3_t move, int iMode ); +bool SV_MoveStep( edict_t *ent, vec3_t move, bool relink ); +bool SV_MoveTest( edict_t *ent, vec3_t move, bool relink ); void SV_MoveToOrigin( edict_t *ed, const vec3_t goal, float dist, int iMode ); -bool SV_CheckBottom( edict_t *ent, float flStepSize, int iMode ); +bool SV_CheckBottom( edict_t *ent, int iMode ); float SV_VecToYaw( const vec3_t src ); // @@ -432,6 +435,7 @@ void SV_BuildClientFrame( sv_client_t *client ); void SV_ClearFrames( client_frame_t **frames ); void SV_InactivateClients( void ); void SV_SendMessagesToAll( void ); +void SV_SkipUpdates( void ); // // sv_game.c diff --git a/engine/server/sv_client.c b/engine/server/sv_client.c index d7c9f9ea..fbdc8945 100644 --- a/engine/server/sv_client.c +++ b/engine/server/sv_client.c @@ -814,6 +814,7 @@ void SV_PutClientInServer( edict_t *ent ) { if( ent->v.flags & FL_SPECTATOR ) { + svgame.globals->time = sv.time; svgame.dllFuncs.pfnSpectatorConnect( ent ); } else @@ -823,6 +824,7 @@ void SV_PutClientInServer( edict_t *ent ) else ent->v.netname = MAKE_STRING( "player" ); // fisrt entering + svgame.globals->time = sv.time; svgame.dllFuncs.pfnClientPutInServer( ent ); } } diff --git a/engine/server/sv_frame.c b/engine/server/sv_frame.c index 060a4efb..88a74b0a 100644 --- a/engine/server/sv_frame.c +++ b/engine/server/sv_frame.c @@ -723,6 +723,9 @@ void SV_SendMessagesToAll( void ) int i; sv_client_t *cl; + if( sv.state == ss_dead ) + return; + for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ ) { if( cl->state >= cs_connected ) @@ -731,6 +734,29 @@ void SV_SendMessagesToAll( void ) SV_SendClientMessages(); } +/* +======================= +SV_SkipUpdates + +used before changing level +======================= +*/ +void SV_SkipUpdates( void ) +{ + int i; + sv_client_t *cl; + + if( sv.state == ss_dead ) + return; + + for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ ) + { + if( cl->state != cs_spawned || cl->fakeclient ) + continue; + cl->skip_message = true; + } +} + /* ======================= SV_InactivateClients diff --git a/engine/server/sv_game.c b/engine/server/sv_game.c index 096ea38f..f4f036d6 100644 --- a/engine/server/sv_game.c +++ b/engine/server/sv_game.c @@ -560,6 +560,18 @@ void SV_FreeEdict( edict_t *pEdict ) // unlink from world SV_UnlinkEdict( pEdict ); + // never remove global entities from map + if( pEdict->v.globalname && sv.state == ss_active ) + { + pEdict->v.solid = SOLID_NOT; + pEdict->v.flags &= ~FL_KILLME; + pEdict->v.effects = EF_NODRAW; + pEdict->v.movetype = MOVETYPE_NONE; + pEdict->v.modelindex = 0; + pEdict->v.nextthink = -1; + return; + } + if( pEdict->pvPrivateData ) { if( svgame.dllFuncs2.pfnOnFreeEntPrivateData ) @@ -912,6 +924,8 @@ void pfnChangeLevel( const char* s1, const char* s2 ) svs.changelevel_next_time = host.realtime + 1.0f; // rest 1 secs if failed + SV_SkipUpdates (); + if( !s2 ) Cbuf_AddText( va( "changelevel %s\n", s1 )); // Quake changlevel else Cbuf_AddText( va( "changelevel %s %s\n", s1, s2 )); // Half-Life changelevel } @@ -1341,32 +1355,60 @@ disable entity updates to client */ static void pfnMakeStatic( edict_t *ent ) { + int index, i; + if( !SV_IsValidEdict( ent )) { MsgDev( D_WARN, "SV_MakeStatic: invalid entity %s\n", SV_ClassName( ent )); return; } - // FIXME: write svc_spawnstatic to the client - ent->v.flags |= FL_KILLME; + index = SV_ModelIndex( STRING( ent->v.model )); + BF_WriteByte( &sv.signon, svc_spawnstatic ); + BF_WriteShort(&sv.signon, index ); + BF_WriteByte( &sv.signon, ent->v.sequence ); + BF_WriteByte( &sv.signon, ent->v.frame ); + BF_WriteWord( &sv.signon, ent->v.colormap ); + BF_WriteByte( &sv.signon, ent->v.skin ); + + for(i = 0; i < 3; i++ ) + { + BF_WriteBitCoord( &sv.signon, ent->v.origin[i] ); + BF_WriteBitAngle( &sv.signon, ent->v.angles[i], 16 ); + } + + BF_WriteByte( &sv.signon, ent->v.rendermode ); + + if( ent->v.rendermode != kRenderNormal ) + { + BF_WriteByte( &sv.signon, ent->v.renderamt ); + BF_WriteByte( &sv.signon, ent->v.rendercolor[0] ); + BF_WriteByte( &sv.signon, ent->v.rendercolor[1] ); + BF_WriteByte( &sv.signon, ent->v.rendercolor[2] ); + BF_WriteByte( &sv.signon, ent->v.renderfx ); + } + + // remove at end of the frame + ent->v.flags |= FL_KILLME; } /* ============= -pfnLinkEntity +pfnEntIsOnFloor -Xash3D extension +legacy builtin ============= */ -static void pfnLinkEntity( edict_t *e, int touch_triggers ) +static int pfnEntIsOnFloor( edict_t *e ) { if( !SV_IsValidEdict( e )) { - MsgDev( D_WARN, "SV_LinkEntity: invalid entity %s\n", SV_ClassName( e )); - return; + MsgDev( D_WARN, "SV_CheckBottom: invalid entity %s\n", SV_ClassName( e )); + return 0; } - SV_LinkEdict( e, touch_triggers ); + + return SV_CheckBottom( e, MOVE_NORMAL ); } /* @@ -1429,7 +1471,19 @@ int pfnWalkMove( edict_t *ent, float yaw, float dist, int iMode ) yaw = yaw * M_PI * 2 / 360; VectorSet( move, com.cos( yaw ) * dist, com.sin( yaw ) * dist, 0.0f ); - return SV_WalkMove( ent, move, iMode ); + switch( iMode ) + { + case WALKMOVE_NORMAL: + return SV_MoveStep( ent, move, true ); + case WALKMOVE_WORLDONLY: + return SV_MoveTest( ent, move, true ); + case WALKMOVE_CHECKONLY: + return SV_MoveStep( ent, move, false); + default: + MsgDev( D_ERROR, "SV_WalkMove: invalid walk mode %i.\n", iMode ); + break; + } + return false; } /* @@ -1623,7 +1677,7 @@ void pfnEmitAmbientSound( edict_t *ent, float *pos, const char *sample, float vo BF_WriteByte( &sv.multicast, svc_ambientsound ); BF_WriteWord( &sv.multicast, flags ); BF_WriteWord( &sv.multicast, sound_idx ); - BF_WriteByte( &sv.multicast, CHAN_AUTO ); + BF_WriteByte( &sv.multicast, CHAN_STATIC ); if( flags & SND_VOLUME ) BF_WriteByte( &sv.multicast, vol * 255 ); if( flags & SND_ATTENUATION ) BF_WriteByte( &sv.multicast, attn * 64 ); @@ -1651,6 +1705,7 @@ static void pfnTraceLine( const float *v1, const float *v2, int fNoMonsters, edi svgame.globals->trace_flags = 0; *ptr = SV_Move( v1, vec3_origin, vec3_origin, v2, fNoMonsters, pentToSkip ); + SV_CopyTraceToGlobal( ptr ); } /* @@ -1670,6 +1725,7 @@ static void pfnTraceToss( edict_t* pent, edict_t* pentToIgnore, TraceResult *ptr } *ptr = SV_MoveToss( pent, pentToIgnore ); + SV_CopyTraceToGlobal( ptr ); } /* @@ -1687,6 +1743,7 @@ static void pfnTraceHull( const float *v1, const float *v2, int fNoMonsters, int svgame.globals->trace_flags = 0; *ptr = SV_MoveHull( v1, hullNumber, v2, fNoMonsters, pentToSkip ); + SV_CopyTraceToGlobal( ptr ); } /* @@ -1698,7 +1755,6 @@ pfnTraceMonsterHull static int pfnTraceMonsterHull( edict_t *pEdict, const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr ) { trace_t result; - float *mins, *maxs; if( !SV_IsValidEdict( pEdict )) { @@ -1710,15 +1766,16 @@ static int pfnTraceMonsterHull( edict_t *pEdict, const float *v1, const float *v fNoMonsters |= FMOVE_SIMPLEBOX; svgame.globals->trace_flags = 0; - mins = pEdict->v.mins; - maxs = pEdict->v.maxs; + result = SV_Move( v1, pEdict->v.mins, pEdict->v.maxs, v2, fNoMonsters, pentToSkip ); + if( ptr ) + { + SV_CopyTraceToGlobal( ptr ); + *ptr = result; + } - if( VectorIsNAN( v1 ) || VectorIsNAN( v2 )) - Host_Error( "TraceMonsterHull: NAN errors detected '%f %f %f', '%f %f %f'\n", v1[0], v1[1], v1[2], v2[0], v2[1], v2[2] ); - result = SV_Move( v1, mins, maxs, v2, fNoMonsters, pentToSkip ); - if( ptr ) Mem_Copy( ptr, &result, sizeof( *ptr )); - - return ptr->fAllSolid; + if( result.fAllSolid || result.flFraction != 1.0f ) + return true; + return false; } /* @@ -1744,6 +1801,7 @@ static void pfnTraceModel( const float *v1, const float *v2, int hullNumber, edi maxs = sv.worldmodel->hulls[hullNumber].clip_maxs; *ptr = SV_TraceHull( pent, hullNumber, v1, mins, maxs, v2 ); + SV_CopyTraceToGlobal( ptr ); } /* @@ -2294,23 +2352,26 @@ static void pfnAlertMessage( ALERT_TYPE level, char *szFmt, ... ) com.vsnprintf( buffer, 2048, szFmt, args ); va_end( args ); - if( host.developer < level ) - return; - - switch( level ) + if( level == at_notice ) { - case at_notice: - case at_console: - case at_aiconsole: - com.print( buffer ); - break; - case at_warning: - com.print( va( "^3Warning:^7 %s", buffer )); - break; - case at_error: - com.print( va( "^1Error:^7 %s", buffer )); - break; + com.print( buffer ); // notice printing always } + else if( level == at_console && host.developer >= D_INFO ) + { + com.print( buffer ); + } + else if( level == at_aiconsole && host.developer >= D_AICONSOLE ) + { + com.print( buffer ); + } + else if( level == at_warning && host.developer >= D_WARN ) + { + com.print( va( "^3Warning:^7 %s", buffer )); + } + else if( level == at_error && host.developer >= D_ERROR ) + { + com.print( va( "^1Error:^7 %s", buffer )); + } } /* @@ -3636,7 +3697,7 @@ static enginefuncs_t gEngfuncs = pfnRemoveEntity, pfnCreateNamedEntity, pfnMakeStatic, - pfnLinkEntity, + pfnEntIsOnFloor, pfnDropToFloor, pfnWalkMove, pfnSetOrigin, diff --git a/engine/server/sv_init.c b/engine/server/sv_init.c index b9a0d27a..6dbb8f3b 100644 --- a/engine/server/sv_init.c +++ b/engine/server/sv_init.c @@ -172,11 +172,11 @@ void SV_DeactivateServer( void ) if( !svs.initialized ) return; - SV_FreeEdicts (); - if( sv.state == ss_dead ) return; sv.state = ss_dead; + SV_FreeEdicts (); + if( svgame.globals->pStringBase ) Mem_EmptyPool( svgame.stringspool ); else StringTable_Clear( svgame.hStringTable ); diff --git a/engine/server/sv_move.c b/engine/server/sv_move.c index b7cab854..067bb7fe 100644 --- a/engine/server/sv_move.c +++ b/engine/server/sv_move.c @@ -22,7 +22,7 @@ is not a staircase. ============= */ -bool SV_CheckBottom( edict_t *ent, float flStepSize, int iMode ) +bool SV_CheckBottom( edict_t *ent, int iMode ) { vec3_t mins, maxs, start, stop; float mid, bottom; @@ -50,12 +50,12 @@ bool SV_CheckBottom( edict_t *ent, float flStepSize, int iMode ) return true; // we got out easy realcheck: // check it for real... - start[2] = mins[2] + flStepSize; + start[2] = mins[2] + svgame.movevars.stepsize; // 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 * flStepSize; + stop[2] = start[2] - 2 * svgame.movevars.stepsize; if( iMode == WALKMOVE_WORLDONLY ) trace = SV_Move( start, vec3_origin, vec3_origin, stop, MOVE_WORLDONLY, ent ); @@ -79,7 +79,7 @@ realcheck: if( trace.flFraction != 1.0f && trace.vecEndPos[2] > bottom ) bottom = trace.vecEndPos[2]; - if( trace.flFraction == 1.0f || mid - trace.vecEndPos[2] > flStepSize ) + if( trace.flFraction == 1.0f || mid - trace.vecEndPos[2] > svgame.movevars.stepsize ) return false; } } @@ -110,199 +110,350 @@ float SV_VecToYaw( const vec3_t src ) } //============================================================================ -/* -====================== -SV_WalkMove -====================== -*/ -bool SV_WalkMove( edict_t *ent, const vec3_t move, int iMode ) +bool SV_MoveStep( edict_t *ent, vec3_t move, bool relink ) { + int i; trace_t trace; vec3_t oldorg, neworg, end; - edict_t *groundent = NULL; - float flStepSize; - bool relink; + edict_t *enemy; + float dz; - if( iMode == WALKMOVE_NORMAL ) - relink = true; - else relink = false; - - // try the move VectorCopy( ent->v.origin, oldorg ); - VectorAdd( oldorg, move, neworg ); - - // flying pawns don't step up + VectorAdd( ent->v.origin, move, neworg ); + + // well, try it. Flying and swimming monsters are easiest. if( ent->v.flags & ( FL_SWIM|FL_FLY )) { - if( iMode == WALKMOVE_WORLDONLY ) - trace = SV_Move( oldorg, ent->v.mins, ent->v.maxs, neworg, MOVE_WORLDONLY, ent ); - else trace = SV_Move( oldorg, ent->v.mins, ent->v.maxs, neworg, MOVE_NORMAL, ent ); + // try one move with vertical motion, then one without + for( i = 0; i < 2; i++ ) + { + VectorAdd( ent->v.origin, move, neworg ); + + enemy = ent->v.enemy; + if( i == 0 && enemy != NULL ) + { + dz = ent->v.origin[2] - enemy->v.origin[2]; + + if( dz > 40 ) neworg[2] -= 8; + else if( dz < 30 ) neworg[2] += 8; + } + + trace = SV_Move( ent->v.origin, ent->v.mins, ent->v.maxs, neworg, MOVE_NORMAL, ent ); + + if( trace.flFraction == 1.0f ) + { + svs.groupmask = ent->v.groupinfo; + + // that move takes us out of the water. + // apparently though, it's okay to travel into solids, lava, sky, etc :) + if(( ent->v.flags & FL_SWIM ) && SV_PointContents( trace.vecEndPos ) == CONTENTS_EMPTY ) + { + return 0; + } + + VectorCopy( trace.vecEndPos, ent->v.origin ); + + if( relink != 0 ) + { + SV_LinkEdict( ent, true ); + } + return 1; + } + else + { + if( enemy == NULL ) + break; + } + } + return 0; + } + else + { + + dz = svgame.movevars.stepsize; + neworg[2] += dz; + VectorCopy( neworg, end ); + end[2] -= dz * 2.0f; + + trace = SV_Move( neworg, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent ); + if( trace.fAllSolid != 0 ) + return 0; + + if( trace.fStartSolid != 0 ) + { + neworg[2] -= dz; + trace = SV_Move( neworg, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent ); + + if( trace.fAllSolid != 0 || trace.fStartSolid != 0 ) + return 0; + } if( trace.flFraction == 1.0f ) { - if( ent->v.flags & FL_SWIM && SV_PointContents( trace.vecEndPos ) == CONTENTS_EMPTY ) - return false; // swim monster left water - + if( ent->v.flags & FL_PARTIALGROUND ) + { + VectorAdd( ent->v.origin, move, ent->v.origin ); + if( relink != 0 ) + { + SV_LinkEdict( ent, true ); + } + ent->v.flags &= ~FL_ONGROUND; + return 1; + } + return 0; + } + else + { VectorCopy( trace.vecEndPos, ent->v.origin ); - if( !VectorCompare( ent->v.origin, oldorg )) - SV_LinkEdict( ent, relink ); - return true; + if( SV_CheckBottom( ent, MOVE_NORMAL ) == 0 ) + { + if( ent->v.flags & FL_PARTIALGROUND ) + { + if( relink != 0 ) + { + SV_LinkEdict( ent, true ); + } + return 1; + } + + VectorCopy( oldorg, ent->v.origin ); + return 0; + } + else + { + if( ent->v.flags & FL_PARTIALGROUND ) + ent->v.flags &= ~FL_PARTIALGROUND; + + ent->v.groundentity = trace.pHit; + + if( relink != 0 ) + { + SV_LinkEdict( ent, true ); + } + return 1; + } } - return false; } +} - // push down from a step height above the wished position - flStepSize = svgame.movevars.stepsize; - neworg[2] += flStepSize; +bool SV_MoveTest( edict_t *ent, vec3_t move, bool relink ) +{ + float temp; + vec3_t oldorg, neworg, end; + trace_t trace; + + VectorCopy( ent->v.origin, oldorg ); + VectorAdd( ent->v.origin, move, neworg ); + + temp = svgame.movevars.stepsize; + + neworg[2] += temp; VectorCopy( neworg, end ); - end[2] -= flStepSize * 2; + end[2] -= temp * 2.0f; - if( iMode == WALKMOVE_WORLDONLY ) - trace = SV_Move( neworg, ent->v.mins, ent->v.maxs, end, MOVE_WORLDONLY, ent ); - else trace = SV_Move( neworg, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent ); - - if( trace.fAllSolid ) - return false; + trace = SV_Move( neworg, ent->v.mins, ent->v.maxs, end, MOVE_WORLDONLY, ent ); - if( trace.fStartSolid ) + if( trace.fAllSolid != 0 ) + return 0; + + if( trace.fStartSolid != 0 ) { - neworg[2] -= flStepSize; + neworg[2] -= temp; + trace = SV_Move( neworg, ent->v.mins, ent->v.maxs, end, MOVE_WORLDONLY, ent ); - if( iMode == WALKMOVE_WORLDONLY ) - trace = SV_Move( neworg, ent->v.mins, ent->v.maxs, end, MOVE_WORLDONLY, ent ); - else trace = SV_Move( neworg, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent ); - - if( trace.fAllSolid || trace.fStartSolid ) - return false; + if( trace.fAllSolid != 0 || trace.fStartSolid != 0 ) + return 0; } if( trace.flFraction == 1.0f ) { - // if monster had the ground pulled out, go ahead and fall if( ent->v.flags & FL_PARTIALGROUND ) { VectorAdd( ent->v.origin, move, ent->v.origin ); - - if( !VectorCompare( ent->v.origin, oldorg )) - SV_LinkEdict( ent, relink ); - - ent->v.flags &= ~FL_ONGROUND; - return true; - } - return false; // walked off an edge - } - - // check point traces down for dangling corners - VectorCopy( trace.vecEndPos, ent->v.origin ); - groundent = trace.pHit; - - // check our pos - if( iMode == WALKMOVE_WORLDONLY ) - trace = SV_Move( ent->v.origin, ent->v.mins, ent->v.maxs, ent->v.origin, MOVE_WORLDONLY, ent ); - else trace = SV_Move( ent->v.origin, ent->v.mins, ent->v.maxs, ent->v.origin, MOVE_NORMAL, ent ); - - if( trace.fStartSolid ) - { - VectorCopy( oldorg, ent->v.origin ); - return false; - } - - if( !SV_CheckBottom( ent, flStepSize, iMode )) - { - if( ent->v.flags & FL_PARTIALGROUND ) - { - // actor had floor mostly pulled out from underneath it - // and is trying to correct - if( !VectorCompare( ent->v.origin, oldorg )) - SV_LinkEdict( ent, relink ); - return true; - } - - ent->v.flags |= FL_PARTIALGROUND; - VectorCopy( oldorg, ent->v.origin ); - return false; - } - - if( ent->v.flags & FL_PARTIALGROUND ) - ent->v.flags &= ~FL_PARTIALGROUND; - - ent->v.groundentity = groundent; - - // the move is ok - if( !VectorCompare( ent->v.origin, oldorg )) - SV_LinkEdict( ent, relink ); - - 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, int iMode ) -{ - vec3_t move, oldorigin; - float delta; - - yaw = yaw * M_PI * 2 / 360; - VectorSet( move, com.cos( yaw ) * dist, com.sin( yaw ) * dist, 0.0f ); - VectorCopy( ent->v.origin, oldorigin ); - - if( SV_WalkMove( ent, move, WALKMOVE_NORMAL )) - { - if( iMode != MOVE_STRAFE ) - { - delta = ent->v.angles[YAW] - ent->v.ideal_yaw; - if( delta > 45 && delta < 315 ) - { - // not turned far enough, so don't take the step - VectorCopy( oldorigin, ent->v.origin ); + if( relink != 0 ) + { + SV_LinkEdict( ent, true ); } + ent->v.flags &= ~FL_ONGROUND; + return 1; } - SV_LinkEdict( ent, false ); - return true; - } - - SV_LinkEdict( ent, false ); - return false; -} - -/* -====================== -SV_MoveToOrigin - -Turns to the movement direction, and walks the current distance if -facing it. -====================== -*/ -void SV_MoveToOrigin( edict_t *ed, const vec3_t goal, float dist, int iMode ) -{ - float yaw, distToGoal; - vec3_t vecDist; - - if( iMode == MOVE_STRAFE ) - { - vec3_t delta; - - VectorSubtract( goal, ed->v.origin, delta ); - VectorNormalizeFast( delta ); - yaw = SV_VecToYaw( delta ); + return 0; } else { - yaw = ed->v.ideal_yaw; + VectorCopy( trace.vecEndPos, ent->v.origin ); + + if( SV_CheckBottom( ent, MOVE_WORLDONLY ) == 0 ) + { + if( ent->v.flags & FL_PARTIALGROUND ) + { + if( relink != 0 ) + { + SV_LinkEdict( ent, true ); + } + return 1; + } + + VectorCopy( oldorg, ent->v.origin ); + return 0; + } + else + { + if( ent->v.flags & FL_PARTIALGROUND ) + ent->v.flags &= ~FL_PARTIALGROUND; + + ent->v.groundentity = trace.pHit; + + if( relink != 0 ) + { + SV_LinkEdict( ent, true ); + } + return 1; + } + } +} + +bool SV_StepDirection( edict_t *ent, float yaw, float dist ) +{ + int ret; + vec3_t move; + + yaw = yaw * M_PI * 2 / 360; + VectorSet( move, com.cos( yaw ) * dist, com.sin( yaw ) * dist, 0.0f ); + + ret = SV_MoveStep( ent, move, 0 ); + SV_LinkEdict( ent, true ); + + return ret; +} + +bool SV_FlyDirection( edict_t *ent, vec3_t move ) +{ + int ret; + + ret = SV_MoveStep( ent, move, 0 ); + SV_LinkEdict( ent, true ); + + return ret; +} + +void SV_NewChaseDir( edict_t *actor, vec3_t destination, float dist ) +{ + float deltax, deltay; + float tempdir, olddir, turnaround; + vec3_t d; + + // so, we're shaving down some of the precision. Ohkay. + olddir = anglemod(((int)( actor->v.ideal_yaw / 45.0f )) * 45.0f ); + turnaround = anglemod( olddir - 180 ); + + deltax = destination[0] - actor->v.origin[0]; + deltay = destination[1] - actor->v.origin[1]; + + if( deltax > 10 ) + d[1] = 0.0f; + else if( deltax < -10 ) + d[1] = 180.0f; + else d[1] = -1; + + if( deltay < -10 ) + d[2] = 270.0f; + else if( deltay > 10 ) + d[2] = 90.0f; + else d[2] = -1; + + // try direct route + if( d[1] != -1 && d[2] != -1 ) + { + if( d[1] == 0.0f ) + tempdir = ( d[2] == 90.0f ) ? 45.0f : 315.0f; + else tempdir = ( d[2] == 90.0f ) ? 135.0f : 215.0f; + + if( tempdir != turnaround && SV_StepDirection( actor, tempdir, dist )) + return; } + // try other directions + if( Com_RandomLong( 0, 1 ) != 0 || fabs( deltay ) > fabs( deltax )) + { + tempdir = d[1]; + d[1] = d[2]; + d[2] = tempdir; + } - VectorSubtract( ed->v.origin, goal, vecDist ); - distToGoal = com.sqrt( vecDist[0] * vecDist[0] + vecDist[1] * vecDist[1] ); - if( dist > distToGoal ) dist = distToGoal; + if( d[1] != -1 && d[1] != turnaround && SV_StepDirection( actor, d[1], dist )) + return; - SV_StepDirection( ed, yaw, dist, iMode ); + 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; + + // fine, just run somewhere. + if( Com_RandomLong( 0, 1 ) != 1 ) + { + for( tempdir = 0; tempdir <= 315; tempdir += 45 ) + { + if( tempdir != turnaround && SV_StepDirection( actor, tempdir, dist )) + return; + } + } + else + { + for( tempdir = 315; tempdir >= 0; tempdir -= 45 ) + { + if( tempdir != turnaround && SV_StepDirection( actor, tempdir, dist )) + return; + } + } + + // we tried. Run backwards. THAT ought to work... + if( turnaround != -1 && SV_StepDirection( actor, turnaround, dist )) + return; + + // well, we're stuck somehow. + actor->v.ideal_yaw = olddir; + + // if a bridge was pulled out from underneath a monster, it may not have + // a valid standing position at all. + + if( !SV_CheckBottom( actor, MOVE_NORMAL )) + { + actor->v.flags |= FL_PARTIALGROUND; + } +} + +void SV_MoveToOrigin( edict_t *ent, const vec3_t pflGoal, float dist, int iMoveType ) +{ + vec3_t vecDist; + + VectorCopy( pflGoal, vecDist ); + + if( ent->v.flags & ( FL_FLY|FL_SWIM|FL_ONGROUND )) + { + if( iMoveType == MOVE_NORMAL ) + { + if( SV_StepDirection( ent, ent->v.ideal_yaw, dist ) == 0 ) + { + SV_NewChaseDir( ent, vecDist, dist ); + } + } + else + { + vecDist[0] -= ent->v.origin[0]; + vecDist[1] -= ent->v.origin[1]; + + if( ent->v.flags & ( FL_FLY|FL_SWIM )) + vecDist[2] -= ent->v.origin[2]; + else vecDist[2] = 0.0f; + + VectorNormalize( vecDist ); + VectorScale( vecDist, dist, vecDist ); + SV_FlyDirection( ent, vecDist ); + } + } } \ No newline at end of file diff --git a/engine/server/sv_phys.c b/engine/server/sv_phys.c index 198f5e2c..5bb1b057 100644 --- a/engine/server/sv_phys.c +++ b/engine/server/sv_phys.c @@ -176,6 +176,7 @@ void SV_Impact( edict_t *e1, trace_t *trace ) return; } + svgame.globals->time = sv.time; SV_CopyTraceToGlobal( trace ); if( !e1->free && !e2->free && e1->v.solid != SOLID_NOT ) @@ -562,7 +563,7 @@ trace_t SV_PushEntity( edict_t *ent, const vec3_t lpush, const vec3_t apush, int type = MOVE_NOMONSTERS; // only clip against bmodels else type = MOVE_NORMAL; - trace = SV_Move( ent->v.origin, ent->v.mins, ent->v.maxs, end, type|FMOVE_SIMPLEBOX, ent ); + trace = SV_Move( ent->v.origin, ent->v.mins, ent->v.maxs, end, type, ent ); if( !trace.fAllSolid && !trace.fStartSolid ) { VectorCopy( trace.vecEndPos, ent->v.origin ); @@ -928,12 +929,14 @@ void SV_Physics_Pusher( edict_t *ent ) if( thinktime > oldtime && thinktime <= ent->v.ltime ) { ent->v.nextthink = 0.0f; + svgame.globals->time = sv.time; svgame.dllFuncs.pfnThink( ent ); if( ent->free ) return; } else if( ent->v.flags & FL_ALWAYSTHINK || ( sv.state == ss_loading && !sv.loadgame )) { ent->v.nextthink = 0.0f; + svgame.globals->time = sv.time; svgame.dllFuncs.pfnThink( ent ); if( ent->free ) return; } diff --git a/engine/server/sv_world.c b/engine/server/sv_world.c index 4b99c30c..4125177f 100644 --- a/engine/server/sv_world.c +++ b/engine/server/sv_world.c @@ -367,6 +367,8 @@ void SV_TouchLinks( edict_t *ent, areanode_t *node ) if( SV_HullPointContents( hull, hull->firstclipnode, test ) == CONTENTS_EMPTY ) continue; } + + svgame.globals->time = sv.time; svgame.dllFuncs.pfnTouch( touch, ent ); } @@ -933,6 +935,83 @@ trace_t SV_TraceHull( edict_t *ent, int hullNum, const vec3_t start, vec3_t mins return trace; } +/* DESCRIPTION: SurfaceAtPoint +// LOCATION: +// PATH: TraceTexture, recursive +// +// A weird one. First, it seems to recursively call itself to dig deep into +// the node tree, treating its own failure as a sign that it's dug deep +// enough. Then, it loops through some odd texture stuff, looking for +// a match. A match of what? Don't know yet. +*/ +msurface_t *SV_RecursiveSurfCheck( model_t *model, mnode_t *node, vec3_t v1, vec3_t v2 ) +{ + double var_4, var_8, var_c; + int var_10, var_10_2; + mplane_t * var_14_plane; + vec3_t var_20; + msurface_t * var_24_surface; + int var_28, var_2c; + int var_30, var_34; + int var_38; + mtexinfo_t * var_3C_texinfo; + + + if(node->contents < 0) { return(NULL); } + + var_14_plane = node->plane; + + var_4 = ((v1[0] * var_14_plane->normal[0]) + (v1[1] * var_14_plane->normal[1]) + (v1[2] * var_14_plane->normal[2])) - var_14_plane->dist; + var_8 = ((v2[0] * var_14_plane->normal[0]) + (v2[1] * var_14_plane->normal[1]) + (v2[2] * var_14_plane->normal[2])) - var_14_plane->dist; + + if(var_4 < 0) { var_10 = 1; } + else { var_10 = 0; } + + if(var_8 < 0) { var_10_2 = 1; } + else { var_10_2 = 0; } + + if(var_10 == var_10_2) { + + return(SV_RecursiveSurfCheck(model, node->children[var_10], v1, v2)); + } + + var_c = var_4 / (var_4 - var_8); + + var_20[0] = ((v2[0] - v1[0]) * var_c) + v1[0]; + var_20[1] = ((v2[1] - v1[1]) * var_c) + v1[1]; + var_20[2] = ((v2[2] - v1[2]) * var_c) + v1[2]; + + //Now THIS is weird. + var_24_surface = SV_RecursiveSurfCheck(model, node->children[var_10], v1, var_20); + if(var_24_surface != NULL || var_10 == var_10_2) { return(var_24_surface); } //Second check not possible as in asm... I think. + + + var_24_surface = node->firstface; + + for(var_38 = 0; var_38 < node->numfaces; var_38++, var_24_surface++) { + + var_3C_texinfo = var_24_surface->texinfo; + + var_28 = (var_20[0] * var_3C_texinfo->vecs[0][0]) + (var_20[1] * var_3C_texinfo->vecs[0][1]) + (var_20[2] * var_3C_texinfo->vecs[0][2]) + var_3C_texinfo->vecs[0][3]; + var_2c = (var_20[0] * var_3C_texinfo->vecs[1][0]) + (var_20[1] * var_3C_texinfo->vecs[1][1]) + (var_20[2] * var_3C_texinfo->vecs[1][2]) + var_3C_texinfo->vecs[1][3]; + + if(var_28 >= var_24_surface->texturemins[0] && var_2c >= var_24_surface->texturemins[1]) { + + var_30 = var_28 - var_24_surface->texturemins[0]; + var_34 = var_2c - var_24_surface->texturemins[1]; + + if(var_30 <= var_24_surface->extents[0] && var_34 <= var_24_surface->extents[1]) { + + return(var_24_surface); + } + } + } + + if(var_10 == 1) { var_10 = 0; } + else { var_10 = 1; } + return(SV_RecursiveSurfCheck( model, node->children[var_10], var_20, v2 )); +} + /* ==================== SV_ClipToLinks