26 Dec 2008
This commit is contained in:
parent
0f5ce4a782
commit
093d8f5cb6
10
backup.lst
10
backup.lst
|
@ -13,10 +13,16 @@ launchers.bat
|
|||
todo.log
|
||||
|
||||
baserc\
|
||||
cl_dll\
|
||||
client\
|
||||
client\hud\
|
||||
client\global\
|
||||
public\
|
||||
physic\
|
||||
sv_dll\
|
||||
server\
|
||||
server\ents\
|
||||
server\game\
|
||||
server\global\
|
||||
server\monsters\
|
||||
render\
|
||||
vprogs\
|
||||
vsound\
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
LIBRARY client
|
||||
EXPORTS
|
||||
CreateAPI @1
|
||||
SECTIONS
|
||||
.data READ WRITE
|
|
@ -0,0 +1,260 @@
|
|||
# Microsoft Developer Studio Project File - Name="client" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
|
||||
|
||||
CFG=client - Win32 Release
|
||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||
!MESSAGE use the Export Makefile command and run
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "client.mak".
|
||||
!MESSAGE
|
||||
!MESSAGE You can specify a configuration when running NMAKE
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "client.mak" CFG="client - Win32 Release"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "client - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
|
||||
!MESSAGE "client - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP AllowPerConfigDependencies 0
|
||||
# PROP Scc_ProjName ""$/GoldSrc/client", HGEBAAAA"
|
||||
# PROP Scc_LocalPath "."
|
||||
CPP=cl.exe
|
||||
MTL=midl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "client - Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir ".\!Release"
|
||||
# PROP BASE Intermediate_Dir ".\!Release"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "..\temp\client\!release"
|
||||
# PROP Intermediate_Dir "..\temp\client\!release"
|
||||
# PROP Ignore_Export_Lib 1
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
|
||||
# ADD CPP /nologo /MD /W3 /GX /O2 /I "./" /I "../public" /I "./global" /I "./hud" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c
|
||||
# SUBTRACT CPP /Fr /YX
|
||||
# ADD BASE MTL /nologo /D "NDEBUG" /win32
|
||||
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
|
||||
# ADD LINK32 msvcrt.lib /nologo /subsystem:windows /dll /machine:I386 /nodefaultlib:"libc" /def:".\client.def" /libpath:"..\common\libs"
|
||||
# SUBTRACT LINK32 /map
|
||||
# Begin Custom Build
|
||||
TargetDir=\Xash3D\src_main\temp\client\!release
|
||||
InputPath=\Xash3D\src_main\temp\client\!release\client.dll
|
||||
SOURCE="$(InputPath)"
|
||||
|
||||
"D:\Xash3D\tmpQuArK\bin\client.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
|
||||
copy $(TargetDir)\client.dll "D:\Xash3D\tmpQuArK\bin\client.dll"
|
||||
|
||||
# End Custom Build
|
||||
|
||||
!ELSEIF "$(CFG)" == "client - Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "client___Win32_Debug"
|
||||
# PROP BASE Intermediate_Dir "client___Win32_Debug"
|
||||
# PROP BASE Ignore_Export_Lib 0
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "..\temp\client\!debug"
|
||||
# PROP Intermediate_Dir "..\temp\client\!debug"
|
||||
# PROP Ignore_Export_Lib 1
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /MT /W3 /GX /Zi /O2 /I "..\common\vgui" /I "..\client" /I "..\client\render" /I ".\hud" /I "..\common\engine" /I "..\common" /I "..\server" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "CLIENT_DLL" /YX /FD /c
|
||||
# SUBTRACT BASE CPP /Fr
|
||||
# ADD CPP /nologo /MDd /W3 /Gm /Gi /GX /ZI /Od /I "./" /I "../public" /I "./global" /I "./hud" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /FD /c
|
||||
# SUBTRACT CPP /YX
|
||||
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib opengl32.lib glu32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib winmm.lib vgui.lib wsock32.lib cvaLib.lib /nologo /subsystem:windows /dll /machine:I386 /nodefaultlib:"libc" /def:".\client.def" /libpath:"..\common\libs"
|
||||
# SUBTRACT BASE LINK32 /map
|
||||
# ADD LINK32 msvcrtd.lib /nologo /subsystem:windows /dll /incremental:yes /debug /machine:I386 /nodefaultlib:"libc.lib" /def:".\client.def" /pdbtype:sept /libpath:"..\common\libs"
|
||||
# SUBTRACT LINK32 /map
|
||||
# Begin Custom Build
|
||||
TargetDir=\Xash3D\src_main\temp\client\!debug
|
||||
InputPath=\Xash3D\src_main\temp\client\!debug\client.dll
|
||||
SOURCE="$(InputPath)"
|
||||
|
||||
"D:\Xash3D\tmpQuArK\bin\client.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
|
||||
copy $(TargetDir)\client.dll "D:\Xash3D\tmpQuArK\bin\client.dll"
|
||||
|
||||
# End Custom Build
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "client - Win32 Release"
|
||||
# Name "client - Win32 Debug"
|
||||
# Begin Group "Source Files"
|
||||
|
||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;for;f90"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\global\dll_int.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\hud\hud.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\hud\hud_ammo.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\hud\hud_ammohistory.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\hud\hud_battery.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\hud\hud_death.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\hud\hud_flashlight.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\hud\hud_geiger.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\hud\hud_health.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\hud\hud_icons.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\hud\hud_menu.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\hud\hud_message.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\hud\hud_motd.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\hud\hud_msg.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\hud\hud_saytext.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\hud\hud_scoreboard.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\hud\hud_sound.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\hud\hud_statusbar.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\hud\hud_text.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\hud\hud_train.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\hud\hud_utils.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\hud\hud_warhead.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\hud\hud_zoom.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\global\tempents.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\global\triapi.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\global\view.cpp
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Header Files"
|
||||
|
||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\global\enginecallback.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\global\extdll.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\hud\hud.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\hud\hud_ammo.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\hud\hud_ammohistory.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\hud\hud_health.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\hud\hud_iface.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\global\vector.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# End Target
|
||||
# End Project
|
|
@ -3,14 +3,14 @@
|
|||
<pre>
|
||||
<h1>Build Log</h1>
|
||||
<h3>
|
||||
--------------------Configuration: server - Win32 Debug--------------------
|
||||
--------------------Configuration: client - Win32 Debug--------------------
|
||||
</h3>
|
||||
<h3>Command Lines</h3>
|
||||
|
||||
|
||||
|
||||
<h3>Results</h3>
|
||||
server.dll - 0 error(s), 0 warning(s)
|
||||
client.dll - 0 error(s), 0 warning(s)
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,91 @@
|
|||
//=======================================================================
|
||||
// Copyright XashXT Group 2008 ©
|
||||
// dll_int.cpp - dll entry points
|
||||
//=======================================================================
|
||||
|
||||
#include "extdll.h"
|
||||
#include "hud_iface.h"
|
||||
#include "hud.h"
|
||||
|
||||
cl_enginefuncs_t g_engfuncs;
|
||||
CHud gHUD;
|
||||
|
||||
// main DLL entry point
|
||||
BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static HUD_FUNCTIONS gFunctionTable =
|
||||
{
|
||||
sizeof( HUD_FUNCTIONS ),
|
||||
HUD_VidInit,
|
||||
HUD_Init,
|
||||
HUD_Redraw,
|
||||
HUD_UpdateClientData,
|
||||
HUD_Reset,
|
||||
HUD_Frame,
|
||||
HUD_Shutdown,
|
||||
HUD_DrawNormalTriangles,
|
||||
HUD_DrawTransparentTriangles,
|
||||
HUD_CreateEntities,
|
||||
HUD_StudioEvent,
|
||||
V_CalcRefdef,
|
||||
};
|
||||
|
||||
//=======================================================================
|
||||
// GetApi
|
||||
//=======================================================================
|
||||
int CreateAPI( HUD_FUNCTIONS *pFunctionTable, cl_enginefuncs_t* pEngfuncsFromEngine, int interfaceVersion )
|
||||
{
|
||||
if( !pFunctionTable || !pEngfuncsFromEngine || interfaceVersion != INTERFACE_VERSION )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// copy HUD_FUNCTIONS table to engine, copy engfuncs table from engine
|
||||
memcpy( pFunctionTable, &gFunctionTable, sizeof( HUD_FUNCTIONS ));
|
||||
memcpy( &g_engfuncs, pEngfuncsFromEngine, sizeof( cl_enginefuncs_t ));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int HUD_VidInit( void )
|
||||
{
|
||||
gHUD.VidInit();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void HUD_Init( void )
|
||||
{
|
||||
gHUD.Init();
|
||||
}
|
||||
|
||||
int HUD_Redraw( float flTime, int intermission )
|
||||
{
|
||||
gHUD.Redraw( flTime, intermission );
|
||||
DrawCrosshair();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int HUD_UpdateClientData( ref_params_t *parms, float flTime )
|
||||
{
|
||||
return gHUD.UpdateClientData( parms, flTime );
|
||||
}
|
||||
|
||||
void HUD_Reset( void )
|
||||
{
|
||||
gHUD.VidInit();
|
||||
}
|
||||
|
||||
void HUD_Frame( double time )
|
||||
{
|
||||
// place to call vgui_frame
|
||||
}
|
||||
|
||||
void HUD_Shutdown( void )
|
||||
{
|
||||
// no shutdown operations
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
//=======================================================================
|
||||
// Copyright XashXT Group 2008 ©
|
||||
// enginecallback.h - actual engine callbacks
|
||||
//=======================================================================
|
||||
|
||||
#ifndef ENGINECALLBACKS_H
|
||||
#define ENGINECALLBACKS_H
|
||||
|
||||
// built-in memory manager
|
||||
#define MALLOC( x ) (*g_engfuncs.pfnMemAlloc)( x, __FILE__, __LINE__ )
|
||||
#define CALLOC( x, y ) (*g_engfuncs.pfnMemAlloc)((x) * (y), __FILE__, __LINE__ )
|
||||
#define FREE( x ) (*g_engfuncs.pfnMemFree)( x, __FILE__, __LINE__ )
|
||||
|
||||
// screen handlers
|
||||
#define LOAD_SHADER (*g_engfuncs.pfnLoadShader)
|
||||
#define DrawImage (*g_engfuncs.pfnDrawImage)
|
||||
#define SetColor (*g_engfuncs.pfnSetColor)
|
||||
#define CVAR_REGISTER (*g_engfuncs.pfnRegisterVariable)
|
||||
#define CVAR_SET_FLOAT (*g_engfuncs.pfnCvarSetValue)
|
||||
#define CVAR_GET_FLOAT (*g_engfuncs.pfnGetCvarFloat)
|
||||
#define CVAR_GET_STRING (*g_engfuncs.pfnGetCvarString)
|
||||
|
||||
#define SERVER_COMMAND (*g_engfuncs.pfnServerCmd)
|
||||
#define CLIENT_COMMAND (*g_engfuncs.pfnClientCmd)
|
||||
#define GET_PLAYER_INFO (*g_engfuncs.pfnGetPlayerInfo)
|
||||
#define GET_GAME_MESSAGE (*g_engfuncs.pfnTextMessageGet)
|
||||
#define CMD_ARGC (*g_engfuncs.pfnCmdArgc)
|
||||
#define CMD_ARGV (*g_engfuncs.pfnCmdArgv)
|
||||
#define ALERT (*g_engfuncs.pfnAlertMessage)
|
||||
|
||||
inline void CL_PlaySound( const char *szSound, float flVolume )
|
||||
{
|
||||
g_engfuncs.pfnPlaySoundByName( szSound, flVolume, NULL );
|
||||
}
|
||||
|
||||
inline void CL_PlaySound( int iSound, float flVolume )
|
||||
{
|
||||
g_engfuncs.pfnPlaySoundByIndex( iSound, flVolume, NULL );
|
||||
}
|
||||
|
||||
inline void CL_PlaySound( const char *szSound, float flVolume, Vector &pos )
|
||||
{
|
||||
g_engfuncs.pfnPlaySoundByName( szSound, flVolume, pos );
|
||||
}
|
||||
|
||||
inline void CL_PlaySound( int iSound, float flVolume, Vector &pos )
|
||||
{
|
||||
g_engfuncs.pfnPlaySoundByIndex( iSound, flVolume, pos );
|
||||
}
|
||||
|
||||
#define AngleVectors (*g_engfuncs.pfnAngleVectors)
|
||||
#define DrawCenterPrint (*g_engfuncs.pfnDrawCenterPrint)
|
||||
#define CenterPrint (*g_engfuncs.pfnCenterPrint)
|
||||
#define DrawChar (*g_engfuncs.pfnDrawCharacter)
|
||||
#define DrawString (*g_engfuncs.pfnDrawString)
|
||||
#define GetImageSize (*g_engfuncs.pfnGetImageSize)
|
||||
#define GetViewAngles (*g_engfuncs.pfnGetViewAngles)
|
||||
#define GetEntityByIndex (*g_engfuncs.pfnGetEntityByIndex)
|
||||
#define GetLocalPlayer (*g_engfuncs.pfnGetLocalPlayer)
|
||||
#define IsSpectateOnly (*g_engfuncs.pfnIsSpectateOnly)
|
||||
#define GetClientTime (*g_engfuncs.pfnGetClientTime)
|
||||
#define GetMaxClients (*g_engfuncs.pfnGetMaxClients)
|
||||
#define GetViewModel (*g_engfuncs.pfnGetViewModel)
|
||||
#define POINT_CONTENTS (*g_engfuncs.pfnPointContents)
|
||||
#define TRACE_LINE (*g_engfuncs.pfnTraceLine)
|
||||
#define RANDOM_LONG (*g_engfuncs.pfnRandomLong)
|
||||
#define RANDOM_FLOAT (*g_engfuncs.pfnRandomFloat)
|
||||
#define LOAD_FILE (*g_engfuncs.pfnLoadFile)
|
||||
#define FREE_FILE (*g_engfuncs.pfnFreeFile)
|
||||
#define GET_GAME_DIR (*g_engfuncs.pfnGetGameDir)
|
||||
#define HOST_ERROR (*g_engfuncs.pfnHostError)
|
||||
|
||||
// heavy legacy of Valve...
|
||||
// tune char size by taste
|
||||
inline void TextMessageDrawChar( int xpos, int ypos, int number, int r, int g, int b )
|
||||
{
|
||||
SetColor((r / 255.0f), (g / 255.0f), (b / 255.0f), 1.0f );
|
||||
DrawChar( xpos, ypos, SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT, number );
|
||||
}
|
||||
|
||||
inline void FillRGBA( int x, int y, int width, int height, int r, int g, int b, int a )
|
||||
{
|
||||
Vector RGB;
|
||||
|
||||
RGB.x = (float)(r / 255.0f);
|
||||
RGB.y = (float)(g / 255.0f);
|
||||
RGB.z = (float)(b / 255.0f);
|
||||
|
||||
g_engfuncs.pfnFillRGBA( x, y, width, height, RGB, (float)(a / 255.0f));
|
||||
}
|
||||
|
||||
#endif//ENGINECALLBACKS_H
|
|
@ -0,0 +1,41 @@
|
|||
//=======================================================================
|
||||
// Copyright XashXT Group 2008 ©
|
||||
// extdll.h - must be included into all client files
|
||||
//=======================================================================
|
||||
|
||||
#ifndef EXTDLL_H
|
||||
#define EXTDLL_H
|
||||
|
||||
// shut-up compiler warnings
|
||||
#pragma warning(disable : 4305) // int or float data truncation
|
||||
#pragma warning(disable : 4201) // nameless struct/union
|
||||
#pragma warning(disable : 4514) // unreferenced inline function removed
|
||||
#pragma warning(disable : 4100) // unreferenced formal parameter
|
||||
|
||||
#include "windows.h"
|
||||
|
||||
#ifndef BIT
|
||||
#define BIT( n ) (1<<( n ))
|
||||
#endif
|
||||
|
||||
#define DLLEXPORT _declspec( dllexport )
|
||||
|
||||
// Misc C-runtime library headers
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
// shared engine/DLL constants
|
||||
#include "const.h"
|
||||
|
||||
// Vector class
|
||||
#include "vector.h"
|
||||
|
||||
// Shared header describing protocol between engine and DLLs
|
||||
#include "entity_def.h"
|
||||
#include "qfiles_ref.h"
|
||||
#include "clgame_api.h"
|
||||
|
||||
#endif//EXTDLL_H
|
|
@ -0,0 +1,103 @@
|
|||
//=======================================================================
|
||||
// Copyright XashXT Group 2008 ©
|
||||
// tempents.cpp - client side entity management functions
|
||||
//=======================================================================
|
||||
|
||||
#include "extdll.h"
|
||||
#include "hud_iface.h"
|
||||
|
||||
void HUD_CreateEntities( void )
|
||||
{
|
||||
}
|
||||
|
||||
//======================
|
||||
// DRAW BEAM EVENT
|
||||
//======================
|
||||
void EV_DrawBeam( void )
|
||||
{
|
||||
// special effect for displacer
|
||||
cl_entity_t *view = gEngfuncs.GetViewModel();
|
||||
|
||||
if( view != NULL )
|
||||
{
|
||||
float life = 1.05;
|
||||
int m_iBeam = gEngfuncs.pEventAPI->EV_FindModelIndex( "sprites/plasma.spr" );
|
||||
|
||||
gEngfuncs.pEfxAPI->R_BeamEnts(view->index | 0x1000, view->index | 0x2000, m_iBeam, life, 0.8, 0.5, 0.5, 0.6, 0, 10, 2, 10, 0);
|
||||
gEngfuncs.pEfxAPI->R_BeamEnts(view->index | 0x1000, view->index | 0x3000, m_iBeam, life, 0.8, 0.5, 0.5, 0.6, 0, 10, 2, 10, 0);
|
||||
gEngfuncs.pEfxAPI->R_BeamEnts(view->index | 0x1000, view->index | 0x4000, m_iBeam, life, 0.8, 0.5, 0.5, 0.6, 0, 10, 2, 10, 0);
|
||||
}
|
||||
}
|
||||
|
||||
//======================
|
||||
// Eject Shell
|
||||
//======================
|
||||
void EV_EjectShell( const dstudioevent_t *event, edict_t *entity )
|
||||
{
|
||||
vec3_t view_ofs, ShellOrigin, ShellVelocity, forward, right, up;
|
||||
vec3_t origin = entity->origin;
|
||||
vec3_t angles = entity->angles;
|
||||
|
||||
float fR, fU;
|
||||
|
||||
int shell = g_engfuncs.pEventAPI->EV_FindModelIndex (event->options);
|
||||
g_engfuncs.pEventAPI->EV_LocalPlayerViewheight( view_ofs );
|
||||
origin.z = origin.z - view_ofs[2];
|
||||
|
||||
for(int j = 0; j < 3; j++ )
|
||||
{
|
||||
if(angles[j] < -180) angles[j] += 360;
|
||||
else if(angles[j] > 180) angles[j] -= 360;
|
||||
}
|
||||
angles.x = -angles.x;
|
||||
AngleVectors( angles, forward, right, up );
|
||||
|
||||
fR = gEngfuncs.pfnRandomFloat( 50, 70 );
|
||||
fU = gEngfuncs.pfnRandomFloat( 100, 150 );
|
||||
|
||||
for (int i = 0; i < 3; i++ )
|
||||
{
|
||||
ShellVelocity[i] = p_velocity[i] + right[i] * fR + up[i] * fU + forward[i] * 25;
|
||||
ShellOrigin[i] = origin[i] + view_ofs[i] + up[i] * -12 + forward[i] * 20 + right[i] * 4;
|
||||
}
|
||||
EV_EjectBrass ( ShellOrigin, ShellVelocity, angles[ YAW ], shell, TE_BOUNCE_SHELL );
|
||||
}
|
||||
|
||||
void HUD_StudioEvent( const dstudioevent_t *event, edict_t *entity )
|
||||
{
|
||||
switch( event->event )
|
||||
{
|
||||
case 5001:
|
||||
gEngfuncs.pEfxAPI->R_MuzzleFlash( (float *)&entity->attachment[0], atoi( event->options) );
|
||||
break;
|
||||
case 5011:
|
||||
gEngfuncs.pEfxAPI->R_MuzzleFlash( (float *)&entity->attachment[1], atoi( event->options) );
|
||||
break;
|
||||
case 5021:
|
||||
gEngfuncs.pEfxAPI->R_MuzzleFlash( (float *)&entity->attachment[2], atoi( event->options) );
|
||||
break;
|
||||
case 5031:
|
||||
gEngfuncs.pEfxAPI->R_MuzzleFlash( (float *)&entity->attachment[3], atoi( event->options) );
|
||||
break;
|
||||
case 5002:
|
||||
gEngfuncs.pEfxAPI->R_SparkEffect( (float *)&entity->attachment[0], atoi( event->options), -100, 100 );
|
||||
break;
|
||||
// Client side sound
|
||||
case 5004:
|
||||
gEngfuncs.pfnPlaySoundByNameAtLocation( (char *)event->options, 1.0, (float *)&entity->attachment[0] );
|
||||
break;
|
||||
// Client side sound with random pitch
|
||||
case 5005:
|
||||
gEngfuncs.pEventAPI->EV_PlaySound( entity->index, (float *)&entity->attachment[0], CHAN_WEAPON, (char *)event->options, gEngfuncs.pfnRandomFloat(0.7, 0.9), ATTN_NORM, 0, 85 + gEngfuncs.pfnRandomLong(0,0x1f) );
|
||||
break;
|
||||
// Special event for displacer
|
||||
case 5050:
|
||||
EV_DrawBeam();
|
||||
break;
|
||||
case 5060:
|
||||
EV_EjectShell( event, entity );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
//=======================================================================
|
||||
// Copyright XashXT Group 2008 ©
|
||||
// triapi.cpp - triangle rendering, if any
|
||||
//=======================================================================
|
||||
|
||||
#include "extdll.h"
|
||||
#include "hud_iface.h"
|
||||
|
||||
void HUD_DrawNormalTriangles( void )
|
||||
{
|
||||
}
|
||||
|
||||
void HUD_DrawTransparentTriangles( void )
|
||||
{
|
||||
}
|
|
@ -0,0 +1,243 @@
|
|||
//=======================================================================
|
||||
// Copyright (C) Shambler Team 2005
|
||||
// vector.h - shared vector operations
|
||||
//=======================================================================
|
||||
#ifndef VECTOR_H
|
||||
#define VECTOR_H
|
||||
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#pragma warning(disable : 4244) // int or float down-conversion
|
||||
|
||||
// Header file containing definition of globalvars_t and entvars_t
|
||||
typedef int func_t; //
|
||||
typedef int string_t; // from engine's pr_comp.h;
|
||||
typedef float vec_t; // needed before including progdefs.h
|
||||
|
||||
//=========================================================
|
||||
// 2DVector - used for many pathfinding and many other
|
||||
// operations that are treated as planar rather than 3d.
|
||||
//=========================================================
|
||||
class Vector2D
|
||||
{
|
||||
public:
|
||||
inline Vector2D(void) { }
|
||||
inline Vector2D(float X, float Y) { x = X; y = Y; }
|
||||
inline Vector2D operator+(const Vector2D& v) const { return Vector2D(x+v.x, y+v.y); }
|
||||
inline Vector2D operator-(const Vector2D& v) const { return Vector2D(x-v.x, y-v.y); }
|
||||
inline Vector2D operator*(float fl) const { return Vector2D(x*fl, y*fl); }
|
||||
inline Vector2D operator/(float fl) const { return Vector2D(x/fl, y/fl); }
|
||||
|
||||
inline float Length(void) const { return (float)sqrt(x*x + y*y ); }
|
||||
inline Vector2D Normalize ( void ) const
|
||||
{
|
||||
Vector2D vec2;
|
||||
|
||||
float flLen = Length();
|
||||
if ( flLen == 0 )
|
||||
{
|
||||
return Vector2D( (float)0, (float)0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
flLen = 1 / flLen;
|
||||
return Vector2D( x * flLen, y * flLen );
|
||||
}
|
||||
}
|
||||
vec_t x, y;
|
||||
};
|
||||
|
||||
#define nanmask (255<<23)
|
||||
#define IS_NAN(x) (((*(int *)&x)&nanmask)==nanmask)
|
||||
|
||||
inline float DotProduct(const Vector2D& a, const Vector2D& b) { return( a.x*b.x + a.y*b.y ); }
|
||||
inline Vector2D operator*(float fl, const Vector2D& v) { return v * fl; }
|
||||
|
||||
//=========================================================
|
||||
// 3D Vector
|
||||
//=========================================================
|
||||
class Vector // same data-layout as engine's vec3_t,
|
||||
{ // which is a vec_t[3]
|
||||
public:
|
||||
// Construction/destruction
|
||||
inline Vector(void) { }
|
||||
inline Vector(float X, float Y, float Z) { x = X; y = Y; z = Z; }
|
||||
inline Vector(const Vector& v) { x = v.x; y = v.y; z = v.z; }
|
||||
inline Vector(float rgfl[3]) { x = rgfl[0]; y = rgfl[1]; z = rgfl[2]; }
|
||||
|
||||
// Initialization
|
||||
void Init(vec_t ix=0.0f, vec_t iy=0.0f, vec_t iz=0.0f){ x = ix; y = iy; z = iz; }
|
||||
|
||||
// Operators
|
||||
inline Vector operator-(void) const { return Vector(-x,-y,-z); }
|
||||
inline int operator==(const Vector& v) const { return x==v.x && y==v.y && z==v.z; }
|
||||
inline int operator!=(const Vector& v) const { return !(*this==v); }
|
||||
inline Vector operator+(const Vector& v) const { return Vector(x+v.x, y+v.y, z+v.z); }
|
||||
inline Vector operator-(const Vector& v) const { return Vector(x-v.x, y-v.y, z-v.z); }
|
||||
inline Vector operator*(float fl) const { return Vector(x*fl, y*fl, z*fl); }
|
||||
inline Vector operator/(float fl) const { return Vector(x/fl, y/fl, z/fl); }
|
||||
|
||||
_forceinline Vector& operator+=(const Vector &v)
|
||||
{
|
||||
x+=v.x; y+=v.y; z += v.z;
|
||||
return *this;
|
||||
}
|
||||
_forceinline Vector& operator-=(const Vector &v)
|
||||
{
|
||||
x-=v.x; y-=v.y; z -= v.z;
|
||||
return *this;
|
||||
}
|
||||
_forceinline Vector& operator*=(const Vector &v)
|
||||
{
|
||||
x *= v.x; y *= v.y; z *= v.z;
|
||||
return *this;
|
||||
}
|
||||
_forceinline Vector& operator*=(float s)
|
||||
{
|
||||
x *= s; y *= s; z *= s;
|
||||
return *this;
|
||||
}
|
||||
_forceinline Vector& operator/=(const Vector &v)
|
||||
{
|
||||
x /= v.x; y /= v.y; z /= v.z;
|
||||
return *this;
|
||||
}
|
||||
_forceinline Vector& operator/=(float s)
|
||||
{
|
||||
float oofl = 1.0f / s;
|
||||
x *= oofl; y *= oofl; z *= oofl;
|
||||
return *this;
|
||||
}
|
||||
_forceinline Vector MA( const Vector &start, float scale, const Vector &direction ) const
|
||||
{
|
||||
return Vector(start.x + scale * direction.x, start.y + scale * direction.y, start.z + scale * direction.z) ;
|
||||
}
|
||||
|
||||
// Methods
|
||||
inline void CopyToArray(float* rgfl) const { rgfl[0] = x, rgfl[1] = y, rgfl[2] = z; }
|
||||
inline float Length(void) const { return (float)sqrt(x*x + y*y + z*z); }
|
||||
operator float *() { return &x; } // Vectors will now automatically convert to float * when needed
|
||||
operator const float *() const { return &x; } // Vectors will now automatically convert to float * when needed
|
||||
|
||||
// array access...
|
||||
vec_t operator[](int i) const { return ((vec_t*)this)[i];}
|
||||
vec_t& operator[](int i) { return ((vec_t*)this)[i];}
|
||||
|
||||
inline Vector Normalize(void) const
|
||||
{
|
||||
float flLen = Length();
|
||||
if (flLen == 0) return Vector(0,0,1); // ????
|
||||
flLen = 1 / flLen;
|
||||
return Vector(x * flLen, y * flLen, z * flLen);
|
||||
}
|
||||
vec_t Dot(Vector const& vOther) const
|
||||
{
|
||||
return(x*vOther.x+y*vOther.y+z*vOther.z);
|
||||
}
|
||||
Vector Cross(const Vector &vOther) const
|
||||
{
|
||||
return Vector(y*vOther.z - z*vOther.y, z*vOther.x - x*vOther.z, x*vOther.y - y*vOther.x);
|
||||
}
|
||||
inline Vector2D Make2D ( void ) const
|
||||
{
|
||||
Vector2D Vec2;
|
||||
Vec2.x = x;
|
||||
Vec2.y = y;
|
||||
return Vec2;
|
||||
}
|
||||
|
||||
inline float Length2D(void) const { return (float)sqrt(x*x + y*y); }
|
||||
// Members
|
||||
vec_t x, y, z;
|
||||
};
|
||||
inline Vector operator*(float fl, const Vector& v) { return v * fl; }
|
||||
inline float DotProduct(const Vector& a, const Vector& b) { return(a.x*b.x+a.y*b.y+a.z*b.z); }
|
||||
inline Vector CrossProduct(const Vector& a, const Vector& b) { return Vector( a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x ); }
|
||||
#define vec3_t Vector
|
||||
|
||||
//=========================================================
|
||||
// 4D Vector - for matrix operations
|
||||
//=========================================================
|
||||
class Vector4D
|
||||
{
|
||||
public:
|
||||
// Members
|
||||
vec_t x, y, z, w;
|
||||
|
||||
// Construction/destruction
|
||||
Vector4D(void){}
|
||||
Vector4D(vec_t X, vec_t Y, vec_t Z, vec_t W) { x = X; y = Y; z = Z; w = W;}
|
||||
Vector4D(double X, double Y, double Z, double W) { x = (double)X; y = (double)Y; z = (double)Z; w = (double)W;}
|
||||
Vector4D(const float *pFloat) { x = pFloat[0]; y = pFloat[1]; z = pFloat[2]; w = pFloat[3];}
|
||||
|
||||
// array access...
|
||||
vec_t operator[](int i) const { return ((vec_t*)this)[i];}
|
||||
vec_t& operator[](int i) { return ((vec_t*)this)[i];}
|
||||
|
||||
// equality
|
||||
bool operator==(const Vector4D& src) const{ return(src.x == x) && (src.y == y) && (src.z == z) && (src.w == w);}
|
||||
bool operator!=(const Vector4D& src) const{ return(src.x != x) || (src.y != y) || (src.z != z) || (src.w != w);}
|
||||
|
||||
// arithmetic operations
|
||||
Vector4D& operator+=(const Vector4D &v){ x+=v.x; y+=v.y; z += v.z; return *this;}
|
||||
Vector4D& operator-=(const Vector4D &v){ x-=v.x; y-=v.y; z -= v.z; return *this;}
|
||||
Vector4D operator+ (const Vector4D &v)const {Vector4D res; res.x = x + v.x; res.y = y + v.y; res.z = z + v.z; res.w = w; return res;}
|
||||
Vector4D operator- (const Vector4D &v)const {Vector4D res; res.x = x - v.x; res.y = y - v.y; res.z = z - v.z; res.w = w; return res;}
|
||||
Vector4D operator* (const Vector4D &v)const {Vector4D res; res.x = y * v.z - z * v.y; res.y = z * v.x - x * v.z; res.z = x * v.y - y * v.x; res.w = w; return res;}
|
||||
float operator% (const Vector4D &v)const { return (x * v.x + y * v.y + z * v.z); }
|
||||
Vector4D Scale( float scale)const {Vector4D res; res.x = x * scale; res.y = y * scale; res.z = z * scale; res.w = w;return res; }
|
||||
Vector4D CompProduct (const Vector4D &v)const {Vector4D res; res.x = x * v.x; res.y = y * v.y; res.z = z * v.z; res.w = w; return res;}
|
||||
};
|
||||
|
||||
//=========================================================
|
||||
// RandomRange - for random values
|
||||
//=========================================================
|
||||
class RandomRange
|
||||
{
|
||||
public:
|
||||
float m_flMax, m_flMin;//class members
|
||||
|
||||
RandomRange() { m_flMin = m_flMax = 0; }
|
||||
RandomRange(float fValue) { m_flMin = m_flMax = fValue; }
|
||||
RandomRange(float fMin, float fMax) { m_flMin = fMin; m_flMax = fMax; }
|
||||
RandomRange( char *szToken )
|
||||
{
|
||||
char *cOneDot = NULL;
|
||||
m_flMin = m_flMax = 0;
|
||||
|
||||
for (char *c = szToken; *c; c++)
|
||||
{
|
||||
if (*c == '.')
|
||||
{
|
||||
if (cOneDot != NULL)
|
||||
{
|
||||
// found two dots in a row - it's a range
|
||||
|
||||
*cOneDot = 0; // null terminate the first number
|
||||
m_flMin = atof(szToken); // parse the first number
|
||||
*cOneDot = '.'; // change it back, just in case
|
||||
c++;
|
||||
m_flMax = atof(c); // parse the second number
|
||||
return;
|
||||
}
|
||||
else cOneDot = c;
|
||||
}
|
||||
else cOneDot = NULL;
|
||||
}
|
||||
|
||||
// no range, just record the number
|
||||
m_flMax = m_flMin = atof(szToken);
|
||||
}
|
||||
|
||||
// FIXME: float Random() { return RANDOM_FLOAT(m_flMin, m_flMax); }
|
||||
float Random() { return m_flMin - m_flMax; }
|
||||
|
||||
// array access...
|
||||
float operator[](int i) const { return ((float*)this)[i];}
|
||||
float& operator[](int i) { return ((float*)this)[i];}
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,79 @@
|
|||
//=======================================================================
|
||||
// Copyright XashXT Group 2008 ©
|
||||
// view.cpp - view/refresh setup functions
|
||||
//=======================================================================
|
||||
|
||||
#include "extdll.h"
|
||||
#include "hud_iface.h"
|
||||
#include "hud.h"
|
||||
|
||||
void V_CalcShake( void )
|
||||
{
|
||||
float frametime;
|
||||
int i;
|
||||
float fraction, freq;
|
||||
|
||||
if( gHUD.m_Shake.time == 0 )
|
||||
return;
|
||||
|
||||
if(( gHUD.m_flTime > gHUD.m_Shake.time ) || gHUD.m_Shake.duration <= 0
|
||||
|| gHUD.m_Shake.amplitude <= 0 || gHUD.m_Shake.frequency <= 0 )
|
||||
{
|
||||
memset( &gHUD.m_Shake, 0, sizeof( gHUD.m_Shake ));
|
||||
return;
|
||||
}
|
||||
|
||||
frametime = gHUD.m_flTimeDelta;
|
||||
|
||||
if( gHUD.m_flTime > gHUD.m_Shake.nextShake )
|
||||
{
|
||||
// higher frequency means we recalc the extents more often and perturb the display again
|
||||
gHUD.m_Shake.nextShake = gHUD.m_flTime + (1.0f / gHUD.m_Shake.frequency);
|
||||
|
||||
// Compute random shake extents (the shake will settle down from this)
|
||||
for( i = 0; i < 3; i++ )
|
||||
{
|
||||
gHUD.m_Shake.offset[i] = RANDOM_FLOAT( -gHUD.m_Shake.amplitude, gHUD.m_Shake.amplitude );
|
||||
}
|
||||
gHUD.m_Shake.angle = RANDOM_FLOAT( -gHUD.m_Shake.amplitude * 0.25, gHUD.m_Shake.amplitude * 0.25 );
|
||||
}
|
||||
|
||||
// ramp down amplitude over duration (fraction goes from 1 to 0 linearly with slope 1/duration)
|
||||
fraction = ( gHUD.m_Shake.time - gHUD.m_flTime ) / gHUD.m_Shake.duration;
|
||||
|
||||
// ramp up frequency over duration
|
||||
if( fraction )
|
||||
{
|
||||
freq = (gHUD.m_Shake.frequency / fraction);
|
||||
}
|
||||
else
|
||||
{
|
||||
freq = 0;
|
||||
}
|
||||
|
||||
// square fraction to approach zero more quickly
|
||||
fraction *= fraction;
|
||||
|
||||
// Sine wave that slowly settles to zero
|
||||
fraction = fraction * sin( gHUD.m_flTime * freq );
|
||||
|
||||
// add to view origin
|
||||
gHUD.m_Shake.appliedOffset = gHUD.m_Shake.offset * fraction;
|
||||
|
||||
// add to roll
|
||||
gHUD.m_Shake.appliedAngle = gHUD.m_Shake.angle * fraction;
|
||||
|
||||
// drop amplitude a bit, less for higher frequency shakes
|
||||
float localAmp = gHUD.m_Shake.amplitude * ( frametime / ( gHUD.m_Shake.duration * gHUD.m_Shake.frequency ));
|
||||
gHUD.m_Shake.amplitude -= localAmp;
|
||||
}
|
||||
|
||||
void V_ApplyShake( Vector& origin, Vector& angles, float factor )
|
||||
{
|
||||
origin.MA( origin, factor, gHUD.m_Shake.appliedOffset );
|
||||
angles.z += gHUD.m_Shake.appliedAngle * factor;
|
||||
}
|
||||
|
||||
void V_CalcRefdef( ref_params_t *parms )
|
||||
{
|
||||
}
|
|
@ -0,0 +1,341 @@
|
|||
//=======================================================================
|
||||
// Copyright (C) XashXT Group 2007
|
||||
//=======================================================================
|
||||
|
||||
#include "extdll.h"
|
||||
#include "hud_iface.h"
|
||||
#include "hud.h"
|
||||
|
||||
extern float HUD_GetFOV( void );
|
||||
extern float v_idlescale;
|
||||
float in_fov;
|
||||
|
||||
void CHud :: Init( void )
|
||||
{
|
||||
InitMessages();
|
||||
m_Ammo.Init();
|
||||
m_Health.Init();
|
||||
m_SayText.Init();
|
||||
m_Geiger.Init();
|
||||
m_Train.Init();
|
||||
m_Battery.Init();
|
||||
m_Flash.Init();
|
||||
m_Redeemer.Init();
|
||||
m_Zoom.Init();
|
||||
m_Message.Init();
|
||||
m_Scoreboard.Init();
|
||||
m_StatusBar.Init();
|
||||
m_DeathNotice.Init();
|
||||
m_AmmoSecondary.Init();
|
||||
m_TextMessage.Init();
|
||||
m_StatusIcons.Init();
|
||||
m_Menu.Init();
|
||||
m_Sound.Init();
|
||||
m_MOTD.Init();
|
||||
|
||||
MsgFunc_ResetHUD(0, 0, NULL );
|
||||
}
|
||||
|
||||
CHud :: ~CHud( void )
|
||||
{
|
||||
m_Sound.Close();
|
||||
|
||||
if( m_pHudList )
|
||||
{
|
||||
HUDLIST *pList;
|
||||
while( m_pHudList )
|
||||
{
|
||||
pList = m_pHudList;
|
||||
m_pHudList = m_pHudList->pNext;
|
||||
FREE( pList );
|
||||
}
|
||||
m_pHudList = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int CHud :: GetSpriteIndex( const char *SpriteName )
|
||||
{
|
||||
// use built-in Shader Manager
|
||||
return LOAD_SHADER( SpriteName );
|
||||
}
|
||||
|
||||
void CHud :: VidInit( void )
|
||||
{
|
||||
// ----------
|
||||
// Load Sprites
|
||||
// ---------
|
||||
|
||||
m_hsprCursor = 0;
|
||||
m_hHudError = 0;
|
||||
|
||||
// TODO: build real table of fonts widthInChars
|
||||
for( int i = 0; i < 256; i++ )
|
||||
charWidths[i] = SMALLCHAR_WIDTH;
|
||||
iCharHeight = SMALLCHAR_HEIGHT;
|
||||
|
||||
// assumption: number_1, number_2, etc, are all listed and loaded sequentially
|
||||
m_HUD_number_0 = GetSpriteIndex( "number_0" );
|
||||
GetImageSize( NULL, &m_iFontHeight, m_HUD_number_0 );
|
||||
|
||||
// loading error sprite
|
||||
m_HUD_error = GetSpriteIndex( "error" );
|
||||
m_hHudError = GetSprite( m_HUD_error );
|
||||
|
||||
m_Sound.VidInit();
|
||||
m_Ammo.VidInit();
|
||||
m_Health.VidInit();
|
||||
m_Geiger.VidInit();
|
||||
m_Train.VidInit();
|
||||
m_Battery.VidInit();
|
||||
m_Flash.VidInit();
|
||||
m_Redeemer.VidInit();
|
||||
m_Zoom.VidInit();
|
||||
m_MOTD.VidInit();
|
||||
m_Message.VidInit();
|
||||
m_Scoreboard.VidInit();
|
||||
m_StatusBar.VidInit();
|
||||
m_DeathNotice.VidInit();
|
||||
m_SayText.VidInit();
|
||||
m_Menu.VidInit();
|
||||
m_AmmoSecondary.VidInit();
|
||||
m_TextMessage.VidInit();
|
||||
m_StatusIcons.VidInit();
|
||||
}
|
||||
|
||||
void CHud :: Think( void )
|
||||
{
|
||||
HUDLIST *pList = m_pHudList;
|
||||
|
||||
while( pList )
|
||||
{
|
||||
if (pList->p->m_iFlags & HUD_ACTIVE)
|
||||
pList->p->Think();
|
||||
pList = pList->pNext;
|
||||
}
|
||||
|
||||
// think about default fov
|
||||
if( m_iFOV == 0 )
|
||||
{
|
||||
// only let players adjust up in fov, and only if they are not overriden by something else
|
||||
m_iFOV = max( CVAR_GET_FLOAT( "default_fov" ), 90 );
|
||||
}
|
||||
}
|
||||
|
||||
int CHud :: UpdateClientData( ref_params_t *cdata, float time )
|
||||
{
|
||||
memcpy( m_vecOrigin, cdata->origin, sizeof( vec3_t ));
|
||||
memcpy( m_vecAngles, cdata->angles, sizeof( vec3_t ));
|
||||
|
||||
m_iKeyBits = cdata->iKeyBits;
|
||||
m_iWeaponBits = cdata->iWeaponBits;
|
||||
|
||||
Think();
|
||||
|
||||
cdata->fov = m_iFOV;
|
||||
cdata->iKeyBits = m_iKeyBits;
|
||||
cdata->fov = m_iFOV;
|
||||
cdata->v_idlescale = m_iConcussionEffect;
|
||||
|
||||
if( m_flMouseSensitivity )
|
||||
cdata->mouse_sensitivity = m_flMouseSensitivity;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHud :: Redraw( float flTime, int intermission )
|
||||
{
|
||||
m_fOldTime = m_flTime; // save time of previous redraw
|
||||
m_flTime = flTime;
|
||||
m_flTimeDelta = (double)m_flTime - m_fOldTime;
|
||||
|
||||
// clock was reset, reset delta
|
||||
if( m_flTimeDelta < 0 ) m_flTimeDelta = 0;
|
||||
|
||||
m_iIntermission = intermission;
|
||||
|
||||
// draw screen fade before hud
|
||||
DrawScreenFade();
|
||||
|
||||
// redeemer hud stuff
|
||||
if( m_Redeemer.m_iHudMode > 0 )
|
||||
{
|
||||
m_Redeemer.Draw( flTime );
|
||||
return 1;
|
||||
}
|
||||
|
||||
// zoom hud stuff
|
||||
if( m_Zoom.m_iHudMode > 0 )
|
||||
{
|
||||
m_Zoom.Draw( flTime );
|
||||
return 1;
|
||||
}
|
||||
|
||||
// custom view active, and flag "draw hud" isn't set
|
||||
if(( viewFlags & 1 ) && !( viewFlags & 2 ))
|
||||
return 1;
|
||||
|
||||
if( CVAR_GET_FLOAT( "hud_draw" ))
|
||||
{
|
||||
HUDLIST *pList = m_pHudList;
|
||||
|
||||
while( pList )
|
||||
{
|
||||
if( !intermission )
|
||||
{
|
||||
if(( pList->p->m_iFlags & HUD_ACTIVE ) && !(m_iHideHUDDisplay & HIDEHUD_ALL ))
|
||||
pList->p->Draw(flTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
// it's an intermission, so only draw hud elements
|
||||
// that are set to draw during intermissions
|
||||
if( pList->p->m_iFlags & HUD_INTERMISSION )
|
||||
pList->p->Draw( flTime );
|
||||
}
|
||||
pList = pList->pNext;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHud :: DrawHudString( int xpos, int ypos, int iMaxX, char *szIt, int r, int g, int b )
|
||||
{
|
||||
// draw the string until we hit the null character or a newline character
|
||||
for( ; *szIt != 0 && *szIt != '\n'; szIt++ )
|
||||
{
|
||||
int next = xpos + gHUD.charWidths[*szIt]; // variable-width fonts look cool
|
||||
if ( next > iMaxX )
|
||||
return xpos;
|
||||
|
||||
TextMessageDrawChar( xpos, ypos, *szIt, r, g, b );
|
||||
xpos = next;
|
||||
}
|
||||
|
||||
return xpos;
|
||||
}
|
||||
|
||||
int CHud :: DrawHudNumberString( int xpos, int ypos, int iMinX, int iNumber, int r, int g, int b )
|
||||
{
|
||||
char szString[32];
|
||||
sprintf( szString, "%d", iNumber );
|
||||
return DrawHudStringReverse( xpos, ypos, iMinX, szString, r, g, b );
|
||||
|
||||
}
|
||||
|
||||
int CHud :: DrawHudStringReverse( int xpos, int ypos, int iMinX, char *szString, int r, int g, int b )
|
||||
{
|
||||
// find the end of the string
|
||||
for ( char *szIt = szString; *szIt != 0; szIt++ )
|
||||
{ // we should count the length?
|
||||
}
|
||||
|
||||
// iterate throug the string in reverse
|
||||
for( szIt--; szIt != (szString-1); szIt-- )
|
||||
{
|
||||
int next = xpos - gHUD.charWidths[ *szIt ]; // variable-width fonts look cool
|
||||
if( next < iMinX )
|
||||
return xpos;
|
||||
xpos = next;
|
||||
|
||||
TextMessageDrawChar( xpos, ypos, *szIt, r, g, b );
|
||||
}
|
||||
|
||||
return xpos;
|
||||
}
|
||||
|
||||
int CHud :: DrawHudNumber( int x, int y, int iFlags, int iNumber, int r, int g, int b )
|
||||
{
|
||||
int iWidth = GetSpriteRect( m_HUD_number_0 ).right - GetSpriteRect( m_HUD_number_0 ).left;
|
||||
int k;
|
||||
|
||||
if( iNumber > 0 )
|
||||
{
|
||||
// SPR_Draw 100's
|
||||
if( iNumber >= 100 )
|
||||
{
|
||||
k = iNumber / 100;
|
||||
SPR_Set(GetSprite(m_HUD_number_0 + k), r, g, b );
|
||||
SPR_DrawAdditive( 0, x, y, &GetSpriteRect(m_HUD_number_0 + k));
|
||||
x += iWidth;
|
||||
}
|
||||
else if( iFlags & DHN_3DIGITS )
|
||||
{
|
||||
x += iWidth;
|
||||
}
|
||||
|
||||
// SPR_Draw 10's
|
||||
if( iNumber >= 10 )
|
||||
{
|
||||
k = (iNumber % 100)/10;
|
||||
SPR_Set(GetSprite(m_HUD_number_0 + k), r, g, b );
|
||||
SPR_DrawAdditive( 0, x, y, &GetSpriteRect(m_HUD_number_0 + k));
|
||||
x += iWidth;
|
||||
}
|
||||
else if( iFlags & (DHN_3DIGITS|DHN_2DIGITS))
|
||||
{
|
||||
x += iWidth;
|
||||
}
|
||||
|
||||
// SPR_Draw ones
|
||||
k = iNumber % 10;
|
||||
SPR_Set(GetSprite(m_HUD_number_0 + k), r, g, b );
|
||||
SPR_DrawAdditive(0, x, y, &GetSpriteRect(m_HUD_number_0 + k));
|
||||
x += iWidth;
|
||||
}
|
||||
else if( iFlags & DHN_DRAWZERO )
|
||||
{
|
||||
SPR_Set(GetSprite(m_HUD_number_0), r, g, b );
|
||||
|
||||
// SPR_Draw 100's
|
||||
if( iFlags & DHN_3DIGITS )
|
||||
{
|
||||
x += iWidth;
|
||||
}
|
||||
|
||||
if( iFlags & (DHN_3DIGITS|DHN_2DIGITS)) x += iWidth;
|
||||
SPR_DrawAdditive( 0, x, y, &GetSpriteRect( m_HUD_number_0 ));
|
||||
x += iWidth;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
int CHud::GetNumWidth( int iNumber, int iFlags )
|
||||
{
|
||||
if( iFlags & DHN_3DIGITS ) return 3;
|
||||
if( iFlags & DHN_2DIGITS ) return 2;
|
||||
|
||||
if( iNumber <= 0 )
|
||||
{
|
||||
if( iFlags & DHN_DRAWZERO )
|
||||
return 1;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
if( iNumber < 10 ) return 1;
|
||||
if( iNumber < 100 ) return 2;
|
||||
|
||||
return 3;
|
||||
|
||||
}
|
||||
|
||||
void CHud::AddHudElem( CHudBase *phudelem )
|
||||
{
|
||||
HUDLIST *pdl, *ptemp;
|
||||
|
||||
if( !phudelem ) return;
|
||||
|
||||
pdl = (HUDLIST *)CALLOC( sizeof( HUDLIST ), 1 );
|
||||
pdl->p = phudelem;
|
||||
|
||||
if( !m_pHudList )
|
||||
{
|
||||
m_pHudList = pdl;
|
||||
return;
|
||||
}
|
||||
|
||||
ptemp = m_pHudList;
|
||||
|
||||
while( ptemp->pNext )
|
||||
ptemp = ptemp->pNext;
|
||||
ptemp->pNext = pdl;
|
||||
}
|
|
@ -0,0 +1,680 @@
|
|||
//=======================================================================
|
||||
// Copyright XashXT Group 2008 ©
|
||||
// hud.h - hud primary header
|
||||
//=======================================================================
|
||||
|
||||
#define RGB_YELLOWISH 0x00FFA000 // 255, 160, 0
|
||||
#define RGB_REDISH 0x00FF1010 // 255, 160, 0
|
||||
#define RGB_GREENISH 0x0000A000 // 0, 160, 0
|
||||
|
||||
#include "hud_ammo.h"
|
||||
|
||||
#define DHN_DRAWZERO 1
|
||||
#define DHN_2DIGITS 2
|
||||
#define DHN_3DIGITS 4
|
||||
#define MIN_ALPHA 100
|
||||
|
||||
#define HUDELEM_ACTIVE 1
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int x, y;
|
||||
} POSITION;
|
||||
|
||||
// This structure is sent over the net to describe a screen shake event
|
||||
typedef struct
|
||||
{
|
||||
float time;
|
||||
float duration;
|
||||
float amplitude;
|
||||
float frequency;
|
||||
float nextShake;
|
||||
Vector offset;
|
||||
float angle;
|
||||
Vector appliedOffset;
|
||||
float appliedAngle;
|
||||
} ScreenShake;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int dripsPerSecond;
|
||||
float distFromPlayer;
|
||||
float windX, windY;
|
||||
float randX, randY;
|
||||
int weatherMode; // 0 - snow, 1 - rain
|
||||
float globalHeight;
|
||||
} RainData;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
byte r, g, b, a;
|
||||
} RGBA;
|
||||
|
||||
#define HUD_ACTIVE 1
|
||||
#define HUD_INTERMISSION 2
|
||||
#define MAX_SEC_AMMO_VALUES 4
|
||||
#define MAX_PLAYER_NAME_LENGTH 32
|
||||
#define MAX_MOTD_LENGTH 1536
|
||||
#define FADE_TIME 100
|
||||
#define maxHUDMessages 16
|
||||
#define MAX_SPRITE_NAME_LENGTH 24
|
||||
|
||||
//
|
||||
//-----------------------------------------------------
|
||||
//
|
||||
class CHudBase
|
||||
{
|
||||
public:
|
||||
POSITION m_pos;
|
||||
int m_type;
|
||||
int m_iFlags; // active, moving,
|
||||
|
||||
virtual ~CHudBase(){ }
|
||||
virtual int Init( void ){ return 0; }
|
||||
virtual int VidInit( void ){ return 0; }
|
||||
virtual int Draw( float flTime ){ return 0; }
|
||||
virtual void Think( void ){ return; }
|
||||
virtual void Reset( void ){ return; }
|
||||
virtual void InitHUDData( void ){ } // called every time a server is connected to
|
||||
};
|
||||
|
||||
struct HUDLIST
|
||||
{
|
||||
CHudBase *p;
|
||||
HUDLIST *pNext;
|
||||
};
|
||||
|
||||
//
|
||||
//-----------------------------------------------------
|
||||
//
|
||||
class CHudAmmo: public CHudBase
|
||||
{
|
||||
public:
|
||||
int Init( void );
|
||||
int VidInit( void );
|
||||
int Draw(float flTime);
|
||||
void Think(void);
|
||||
void Reset(void);
|
||||
int DrawWList(float flTime);
|
||||
int MsgFunc_CurWeapon( const char *pszName, int iSize, void *pbuf );
|
||||
int MsgFunc_WeaponList( const char *pszName, int iSize, void *pbuf );
|
||||
int MsgFunc_AmmoX(const char *pszName, int iSize, void *pbuf );
|
||||
int MsgFunc_AmmoPickup( const char *pszName, int iSize, void *pbuf );
|
||||
int MsgFunc_WeapPickup( const char *pszName, int iSize, void *pbuf );
|
||||
int MsgFunc_ItemPickup( const char *pszName, int iSize, void *pbuf );
|
||||
int MsgFunc_HideWeapon( const char *pszName, int iSize, void *pbuf );
|
||||
|
||||
void SlotInput( int iSlot );
|
||||
void _cdecl UserCmd_Slot1( void );
|
||||
void _cdecl UserCmd_Slot2( void );
|
||||
void _cdecl UserCmd_Slot3( void );
|
||||
void _cdecl UserCmd_Slot4( void );
|
||||
void _cdecl UserCmd_Slot5( void );
|
||||
void _cdecl UserCmd_Slot6( void );
|
||||
void _cdecl UserCmd_Slot7( void );
|
||||
void _cdecl UserCmd_Slot8( void );
|
||||
void _cdecl UserCmd_Slot9( void );
|
||||
void _cdecl UserCmd_Slot10( void );
|
||||
void _cdecl UserCmd_Close( void );
|
||||
void _cdecl UserCmd_NextWeapon( void );
|
||||
void _cdecl UserCmd_PrevWeapon( void );
|
||||
|
||||
private:
|
||||
float m_fFade;
|
||||
RGBA m_rgba;
|
||||
WEAPON *m_pWeapon;
|
||||
int m_HUD_bucket0;
|
||||
int m_HUD_selection;
|
||||
|
||||
};
|
||||
|
||||
//
|
||||
//-----------------------------------------------------
|
||||
//
|
||||
class CHudAmmoSecondary: public CHudBase
|
||||
{
|
||||
public:
|
||||
int Init( void );
|
||||
int VidInit( void );
|
||||
void Reset( void );
|
||||
int Draw(float flTime);
|
||||
|
||||
int MsgFunc_SecAmmoVal( const char *pszName, int iSize, void *pbuf );
|
||||
int MsgFunc_SecAmmoIcon( const char *pszName, int iSize, void *pbuf );
|
||||
|
||||
private:
|
||||
int m_HUD_ammoicon; // sprite indices
|
||||
int m_iAmmoAmounts[MAX_SEC_AMMO_VALUES];
|
||||
float m_fFade;
|
||||
};
|
||||
|
||||
|
||||
#include "hud_health.h"
|
||||
|
||||
//
|
||||
//-----------------------------------------------------
|
||||
//
|
||||
class CHudGeiger: public CHudBase
|
||||
{
|
||||
public:
|
||||
int Init( void );
|
||||
int VidInit( void );
|
||||
int Draw( float flTime );
|
||||
int MsgFunc_Geiger( const char *pszName, int iSize, void *pbuf );
|
||||
|
||||
private:
|
||||
int m_iGeigerRange;
|
||||
};
|
||||
|
||||
//
|
||||
//-----------------------------------------------------
|
||||
//
|
||||
class CHudTrain: public CHudBase
|
||||
{
|
||||
public:
|
||||
int Init( void );
|
||||
int VidInit( void );
|
||||
int Draw( float flTime );
|
||||
int MsgFunc_Train( const char *pszName, int iSize, void *pbuf );
|
||||
|
||||
private:
|
||||
HSPRITE m_hSprite;
|
||||
int m_iPos;
|
||||
|
||||
};
|
||||
|
||||
class CHudMOTD : public CHudBase
|
||||
{
|
||||
public:
|
||||
int Init( void );
|
||||
int VidInit( void );
|
||||
int Draw( float flTime );
|
||||
void Reset( void );
|
||||
|
||||
int MsgFunc_MOTD( const char *pszName, int iSize, void *pbuf );
|
||||
|
||||
protected:
|
||||
static int MOTD_DISPLAY_TIME;
|
||||
char m_szMOTD[MAX_MOTD_LENGTH];
|
||||
float m_flActiveTill;
|
||||
int m_iLines;
|
||||
};
|
||||
|
||||
//
|
||||
//-----------------------------------------------------
|
||||
//
|
||||
class CHudSound: public CHudBase
|
||||
{
|
||||
public:
|
||||
int Init( void );
|
||||
int VidInit( void );
|
||||
int MsgFunc_Fsound( const char *pszName, int iSize, void *pbuf );
|
||||
int PlayStream( const char* name );
|
||||
int Draw( float flTime ); // used for get pause
|
||||
int Close( void );
|
||||
private:
|
||||
int m_iStatus;
|
||||
int m_iTime;
|
||||
};
|
||||
|
||||
//
|
||||
//-----------------------------------------------------
|
||||
//
|
||||
class CHudScoreboard: public CHudBase
|
||||
{
|
||||
public:
|
||||
int Init( void );
|
||||
void InitHUDData( void );
|
||||
int VidInit( void );
|
||||
int Draw( float flTime );
|
||||
int DrawPlayers( int xoffset, float listslot, int nameoffset = 0, char *team = NULL ); // returns the ypos where it finishes drawing
|
||||
void UserCmd_ShowScores( void );
|
||||
void UserCmd_HideScores( void );
|
||||
int MsgFunc_ScoreInfo( const char *pszName, int iSize, void *pbuf );
|
||||
int MsgFunc_TeamInfo( const char *pszName, int iSize, void *pbuf );
|
||||
int MsgFunc_TeamScore( const char *pszName, int iSize, void *pbuf );
|
||||
void DeathMsg( int killer, int victim );
|
||||
|
||||
enum
|
||||
{
|
||||
MAX_PLAYERS = 64,
|
||||
MAX_TEAMS = 64,
|
||||
MAX_TEAM_NAME = 16,
|
||||
};
|
||||
|
||||
struct extra_player_info_t
|
||||
{
|
||||
short frags;
|
||||
short deaths;
|
||||
char teamname[MAX_TEAM_NAME];
|
||||
};
|
||||
|
||||
struct team_info_t
|
||||
{
|
||||
char name[MAX_TEAM_NAME];
|
||||
short frags;
|
||||
short deaths;
|
||||
short ping;
|
||||
short packetloss;
|
||||
short ownteam;
|
||||
short players;
|
||||
int already_drawn;
|
||||
int scores_overriden;
|
||||
};
|
||||
|
||||
hud_player_info_t m_PlayerInfoList[MAX_PLAYERS+1]; // player info from the engine
|
||||
extra_player_info_t m_PlayerExtraInfo[MAX_PLAYERS+1]; // additional player info sent directly to the client.dll
|
||||
team_info_t m_TeamInfo[MAX_TEAMS+1];
|
||||
|
||||
int m_iNumTeams;
|
||||
int m_iLastKilledBy;
|
||||
int m_fLastKillTime;
|
||||
int m_iPlayerNum;
|
||||
int m_iShowscoresHeld;
|
||||
|
||||
void GetAllPlayersInfo( void );
|
||||
};
|
||||
|
||||
//
|
||||
//-----------------------------------------------------
|
||||
//
|
||||
class CHudStatusBar : public CHudBase
|
||||
{
|
||||
public:
|
||||
int Init( void );
|
||||
int VidInit( void );
|
||||
int Draw( float flTime );
|
||||
void Reset( void );
|
||||
void ParseStatusString( int line_num );
|
||||
|
||||
int MsgFunc_StatusText( const char *pszName, int iSize, void *pbuf );
|
||||
int MsgFunc_StatusValue( const char *pszName, int iSize, void *pbuf );
|
||||
|
||||
protected:
|
||||
enum
|
||||
{
|
||||
MAX_STATUSTEXT_LENGTH = 128,
|
||||
MAX_STATUSBAR_VALUES = 8,
|
||||
MAX_STATUSBAR_LINES = 2,
|
||||
};
|
||||
|
||||
char m_szStatusText[MAX_STATUSBAR_LINES][MAX_STATUSTEXT_LENGTH]; // a text string describing how the status bar is to be drawn
|
||||
char m_szStatusBar[MAX_STATUSBAR_LINES][MAX_STATUSTEXT_LENGTH]; // the constructed bar that is drawn
|
||||
int m_iStatusValues[MAX_STATUSBAR_VALUES]; // an array of values for use in the status bar
|
||||
|
||||
int m_bReparseString; // set to TRUE whenever the m_szStatusBar needs to be recalculated
|
||||
|
||||
// an array of colors...one color for each line
|
||||
float *m_pflNameColors[MAX_STATUSBAR_LINES];
|
||||
};
|
||||
|
||||
//
|
||||
//-----------------------------------------------------
|
||||
//
|
||||
class CHudDeathNotice : public CHudBase
|
||||
{
|
||||
public:
|
||||
int Init( void );
|
||||
void InitHUDData( void );
|
||||
int VidInit( void );
|
||||
int Draw( float flTime );
|
||||
int MsgFunc_DeathMsg( const char *pszName, int iSize, void *pbuf );
|
||||
|
||||
private:
|
||||
int m_HUD_d_skull; // sprite index of skull icon
|
||||
};
|
||||
|
||||
//
|
||||
//-----------------------------------------------------
|
||||
//
|
||||
class CHudMenu : public CHudBase
|
||||
{
|
||||
public:
|
||||
int Init( void );
|
||||
void InitHUDData( void );
|
||||
int VidInit( void );
|
||||
void Reset( void );
|
||||
int Draw( float flTime );
|
||||
int MsgFunc_ShowMenu( const char *pszName, int iSize, void *pbuf );
|
||||
|
||||
void SelectMenuItem( int menu_item );
|
||||
|
||||
int m_fMenuDisplayed;
|
||||
int m_bitsValidSlots;
|
||||
float m_flShutoffTime;
|
||||
int m_fWaitingForMore;
|
||||
};
|
||||
|
||||
//
|
||||
//-----------------------------------------------------
|
||||
//
|
||||
class CHudSayText : public CHudBase
|
||||
{
|
||||
public:
|
||||
int Init( void );
|
||||
void InitHUDData( void );
|
||||
int VidInit( void );
|
||||
int Draw( float flTime );
|
||||
int MsgFunc_SayText( const char *pszName, int iSize, void *pbuf );
|
||||
void SayTextPrint( const char *pszBuf, int iBufSize, int clientIndex = -1 );
|
||||
void EnsureTextFitsInOneLineAndWrapIfHaveTo( int line );
|
||||
private:
|
||||
|
||||
float m_HUD_saytext;
|
||||
float m_HUD_saytext_time;
|
||||
};
|
||||
|
||||
//
|
||||
//-----------------------------------------------------
|
||||
//
|
||||
class CHudBattery: public CHudBase
|
||||
{
|
||||
public:
|
||||
int Init( void );
|
||||
int VidInit( void );
|
||||
int Draw( float flTime );
|
||||
int MsgFunc_Battery(const char *pszName, int iSize, void *pbuf );
|
||||
|
||||
private:
|
||||
HSPRITE m_hSprite1;
|
||||
HSPRITE m_hSprite2;
|
||||
wrect_t *m_prc1;
|
||||
wrect_t *m_prc2;
|
||||
int m_iBat;
|
||||
float m_fFade;
|
||||
int m_iHeight; // width of the battery innards
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
//-----------------------------------------------------
|
||||
//
|
||||
class CHudFlashlight: public CHudBase
|
||||
{
|
||||
public:
|
||||
int Init( void );
|
||||
int VidInit( void );
|
||||
int Draw(float flTime);
|
||||
void Reset( void );
|
||||
int MsgFunc_Flashlight( const char *pszName, int iSize, void *pbuf );
|
||||
int MsgFunc_FlashBat( const char *pszName, int iSize, void *pbuf );
|
||||
|
||||
private:
|
||||
HSPRITE m_hSprite1;
|
||||
HSPRITE m_hSprite2;
|
||||
HSPRITE m_hBeam;
|
||||
wrect_t *m_prc1;
|
||||
wrect_t *m_prc2;
|
||||
wrect_t *m_prcBeam;
|
||||
float m_flBat;
|
||||
int m_iBat;
|
||||
int m_fOn;
|
||||
float m_fFade;
|
||||
int m_iWidth; // width of the battery innards
|
||||
};
|
||||
|
||||
class CHudRedeemer: public CHudBase
|
||||
{
|
||||
public:
|
||||
int Init( void );
|
||||
int VidInit( void );
|
||||
int Draw( float flTime );
|
||||
int MsgFunc_WarHUD( const char *pszName, int iSize, void *pbuf );
|
||||
int m_iHudMode;
|
||||
private:
|
||||
HSPRITE m_hSprite;
|
||||
HSPRITE m_hCrosshair;
|
||||
HSPRITE m_hStatic;
|
||||
HSPRITE m_hCamera;
|
||||
HSPRITE m_hCamRec;
|
||||
};
|
||||
|
||||
class CHudZoom: public CHudBase
|
||||
{
|
||||
public:
|
||||
int Init( void );
|
||||
int VidInit( void );
|
||||
int Draw( float flTime );
|
||||
int MsgFunc_ZoomHUD( const char *pszName, int iSize, void *pbuf );
|
||||
int m_iHudMode;
|
||||
private:
|
||||
HSPRITE m_hCrosshair;
|
||||
HSPRITE m_hLines;
|
||||
};
|
||||
//
|
||||
//-----------------------------------------------------
|
||||
//
|
||||
struct message_parms_t
|
||||
{
|
||||
client_textmessage_t *pMessage;
|
||||
float time;
|
||||
int x, y;
|
||||
int totalWidth, totalHeight;
|
||||
int width;
|
||||
int lines;
|
||||
int lineLength;
|
||||
int length;
|
||||
int r, g, b;
|
||||
int text;
|
||||
int fadeBlend;
|
||||
float charTime;
|
||||
float fadeTime;
|
||||
};
|
||||
|
||||
//
|
||||
//-----------------------------------------------------
|
||||
//
|
||||
class CHudTextMessage: public CHudBase
|
||||
{
|
||||
public:
|
||||
int Init( void );
|
||||
static char *LocaliseTextString( const char *msg, char *dst_buffer, int buffer_size );
|
||||
static char *BufferedLocaliseTextString( const char *msg );
|
||||
char *LookupString( const char *msg_name, int *msg_dest = NULL );
|
||||
int MsgFunc_TextMsg( const char *pszName, int iSize, void *pbuf );
|
||||
};
|
||||
|
||||
//
|
||||
//-----------------------------------------------------
|
||||
//
|
||||
|
||||
class CHudMessage: public CHudBase
|
||||
{
|
||||
public:
|
||||
int Init( void );
|
||||
int VidInit( void );
|
||||
int Draw( float flTime );
|
||||
int MsgFunc_HudText( const char *pszName, int iSize, void *pbuf );
|
||||
int MsgFunc_GameTitle( const char *pszName, int iSize, void *pbuf );
|
||||
|
||||
float FadeBlend( float fadein, float fadeout, float hold, float localTime );
|
||||
int XPosition( float x, int width, int lineWidth );
|
||||
int YPosition( float y, int height );
|
||||
|
||||
void MessageAdd( const char *pName, float time );
|
||||
void MessageAdd( client_textmessage_t * newMessage );
|
||||
void MessageDrawScan( client_textmessage_t *pMessage, float time );
|
||||
void MessageScanStart( void );
|
||||
void MessageScanNextChar( void );
|
||||
void Reset( void );
|
||||
|
||||
private:
|
||||
client_textmessage_t *m_pMessages[maxHUDMessages];
|
||||
float m_startTime[maxHUDMessages];
|
||||
message_parms_t m_parms;
|
||||
float m_gameTitleTime;
|
||||
client_textmessage_t *m_pGameTitle;
|
||||
int HUD_Logo; // display logo
|
||||
};
|
||||
|
||||
//
|
||||
//-----------------------------------------------------
|
||||
//
|
||||
class CHudStatusIcons: public CHudBase
|
||||
{
|
||||
public:
|
||||
int Init( void );
|
||||
int VidInit( void );
|
||||
void Reset( void );
|
||||
int Draw( float flTime );
|
||||
int MsgFunc_StatusIcon( const char *pszName, int iSize, void *pbuf );
|
||||
|
||||
enum
|
||||
{
|
||||
MAX_ICONSPRITENAME_LENGTH = MAX_SPRITE_NAME_LENGTH,
|
||||
MAX_ICONSPRITES = 4,
|
||||
};
|
||||
|
||||
// had to make these public so CHud could access them (to enable concussion icon)
|
||||
// could use a friend declaration instead...
|
||||
void EnableIcon( char *pszIconName, byte red, byte green, byte blue );
|
||||
void DisableIcon( char *pszIconName );
|
||||
|
||||
private:
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char szSpriteName[MAX_ICONSPRITENAME_LENGTH];
|
||||
HSPRITE spr;
|
||||
wrect_t rc;
|
||||
byte r, g, b;
|
||||
} icon_sprite_t;
|
||||
|
||||
icon_sprite_t m_IconList[MAX_ICONSPRITES];
|
||||
};
|
||||
|
||||
//
|
||||
//-----------------------------------------------------
|
||||
//
|
||||
|
||||
#define SKY_OFF 0
|
||||
#define SKY_ON 1
|
||||
|
||||
class CHud
|
||||
{
|
||||
private:
|
||||
HUDLIST *m_pHudList;
|
||||
float m_flMouseSensitivity;
|
||||
int m_iConcussionEffect;
|
||||
|
||||
public:
|
||||
HSPRITE m_hsprCursor;
|
||||
float m_flTime; // the current client time
|
||||
float m_fOldTime; // the time at which the HUD was last redrawn
|
||||
double m_flTimeDelta;// the difference between flTime and fOldTime
|
||||
float m_vecOrigin[3];
|
||||
float m_vecAngles[3];
|
||||
int m_iKeyBits;
|
||||
int m_iHideHUDDisplay;
|
||||
int m_iFOV;
|
||||
int m_Teamplay;
|
||||
int m_iRes;
|
||||
Vector m_vecSkyPos;
|
||||
int m_iSkyMode;
|
||||
int m_iCameraMode;
|
||||
int m_iLastCameraMode;
|
||||
int m_iFontHeight;
|
||||
int DrawHudNumber( int x, int y, int iFlags, int iNumber, int r, int g, int b );
|
||||
int DrawHudString( int x, int y, int iMaxX, char *szString, int r, int g, int b );
|
||||
int DrawHudStringReverse( int xpos, int ypos, int iMinX, char *szString, int r, int g, int b );
|
||||
int DrawHudNumberString( int xpos, int ypos, int iMinX, int iNumber, int r, int g, int b );
|
||||
int GetNumWidth( int iNumber, int iFlags );
|
||||
int viewEntityIndex;
|
||||
int m_iHUDColor;
|
||||
int viewFlags;
|
||||
private:
|
||||
wrect_t m_Rect;
|
||||
public:
|
||||
HSPRITE GetSprite( int index ) { return (HSPRITE)index; }
|
||||
wrect_t& GetSpriteRect( HSPRITE index )
|
||||
{
|
||||
m_Rect.left = m_Rect.top = 0;
|
||||
GetImageSize( &m_Rect.right, &m_Rect.bottom, index );
|
||||
return m_Rect;
|
||||
}
|
||||
int InitMessages( void ); // init hud messages
|
||||
int GetSpriteIndex( const char *SpriteName );
|
||||
|
||||
CHudAmmo m_Ammo;
|
||||
CHudHealth m_Health;
|
||||
CHudGeiger m_Geiger;
|
||||
CHudBattery m_Battery;
|
||||
CHudTrain m_Train;
|
||||
CHudFlashlight m_Flash;
|
||||
CHudRedeemer m_Redeemer;
|
||||
CHudZoom m_Zoom;
|
||||
CHudMessage m_Message;
|
||||
CHudScoreboard m_Scoreboard;
|
||||
CHudStatusBar m_StatusBar;
|
||||
CHudDeathNotice m_DeathNotice;
|
||||
CHudSayText m_SayText;
|
||||
CHudMenu m_Menu;
|
||||
CHudAmmoSecondary m_AmmoSecondary;
|
||||
CHudTextMessage m_TextMessage;
|
||||
CHudStatusIcons m_StatusIcons;
|
||||
CHudSound m_Sound;
|
||||
CHudMOTD m_MOTD;
|
||||
|
||||
void Init( void );
|
||||
void VidInit( void );
|
||||
void Think( void );
|
||||
int Redraw( float flTime, int intermission );
|
||||
int UpdateClientData( ref_params_t *pparams, float time );
|
||||
|
||||
CHud() : m_pHudList(NULL) { }
|
||||
~CHud(); // destructor, frees allocated memory
|
||||
|
||||
// user messages
|
||||
int _cdecl MsgFunc_Damage( const char *pszName, int iSize, void *pbuf );
|
||||
int _cdecl MsgFunc_GameMode( const char *pszName, int iSize, void *pbuf );
|
||||
int _cdecl MsgFunc_ServerName( const char *pszName, int iSize, void *pbuf );
|
||||
int _cdecl MsgFunc_ResetHUD( const char *pszName, int iSize, void *pbuf);
|
||||
int _cdecl MsgFunc_InitHUD( const char *pszName, int iSize, void *pbuf );
|
||||
int _cdecl MsgFunc_ViewMode( const char *pszName, int iSize, void *pbuf );
|
||||
int _cdecl MsgFunc_SetFOV( const char *pszName, int iSize, void *pbuf );
|
||||
int _cdecl MsgFunc_Concuss( const char *pszName, int iSize, void *pbuf );
|
||||
int _cdecl MsgFunc_ScreenShake( const char *pszName, int iSize, void *pbuf );
|
||||
int _cdecl MsgFunc_RainData( const char *pszName, int iSize, void *pbuf );
|
||||
int _cdecl MsgFunc_HUDColor( const char *pszName, int iSize, void *pbuf);
|
||||
int _cdecl MsgFunc_SetFog( const char *pszName, int iSize, void *pbuf );
|
||||
int _cdecl MsgFunc_SetSky( const char *pszName, int iSize, void *pbuf );
|
||||
int _cdecl MsgFunc_CamData( const char *pszName, int iSize, void *pbuf );
|
||||
int _cdecl MsgFunc_SetBody( const char *pszName, int iSize, void *pbuf );
|
||||
int _cdecl MsgFunc_SetSkin( const char *pszName, int iSize, void *pbuf );
|
||||
int _cdecl MsgFunc_AddScreen( const char *pszName, int iSize, void *pbuf );
|
||||
int _cdecl MsgFunc_AddMirror( const char *pszName, int iSize, void *pbuf );
|
||||
int _cdecl MsgFunc_AddPortal( const char *pszName, int iSize, void *pbuf );
|
||||
int _cdecl MsgFunc_Particle( const char *pszName, int iSize, void *pbuf );
|
||||
|
||||
// from m_screenInfo
|
||||
byte charWidths[256];
|
||||
int iCharHeight;
|
||||
|
||||
qword m_iWeaponBits;
|
||||
int m_fPlayerDead;
|
||||
int m_iIntermission;
|
||||
|
||||
RainData Rain; // buz rain
|
||||
|
||||
// fog stuff
|
||||
Vector m_FogColor;
|
||||
float m_fStartDist;
|
||||
float m_fEndDist;
|
||||
int m_iFinalEndDist;
|
||||
float m_fFadeDuration;
|
||||
|
||||
// sprite indexes
|
||||
int m_HUD_number_0;
|
||||
|
||||
// screen shake handler
|
||||
ScreenShake m_Shake;
|
||||
|
||||
// error sprite
|
||||
int m_HUD_error;
|
||||
HSPRITE m_hHudError;
|
||||
|
||||
void AddHudElem( CHudBase *p );
|
||||
float GetSensitivity() { return m_flMouseSensitivity; }
|
||||
};
|
||||
|
||||
extern CHud gHUD;
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,59 @@
|
|||
/***
|
||||
*
|
||||
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
|
||||
*
|
||||
* This product contains software technology licensed from Id
|
||||
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Use, distribution, and modification of this source code and/or resulting
|
||||
* object code is restricted to non-commercial enhancements to products from
|
||||
* Valve LLC. All other use, distribution, or modification is prohibited
|
||||
* without written permission from Valve LLC.
|
||||
*
|
||||
****/
|
||||
|
||||
#ifndef __AMMO_H__
|
||||
#define __AMMO_H__
|
||||
|
||||
#define MAX_WEAPON_NAME 128
|
||||
#define MAX_WEAPON_SLOTS 5 // hud item selection slots
|
||||
#define WEAPON_FLAGS_SELECTONEMPTY 1
|
||||
#define WEAPON_IS_ONTARGET 0x40
|
||||
|
||||
struct WEAPON
|
||||
{
|
||||
char szName[MAX_WEAPON_NAME];
|
||||
int iAmmoType;
|
||||
int iAmmo2Type;
|
||||
int iMax1;
|
||||
int iMax2;
|
||||
int iSlot;
|
||||
int iSlotPos;
|
||||
int iFlags;
|
||||
int iId;
|
||||
int iClip;
|
||||
int iCount; // # of itesm in plist
|
||||
|
||||
HSPRITE hActive;
|
||||
wrect_t rcActive;
|
||||
HSPRITE hInactive;
|
||||
wrect_t rcInactive;
|
||||
HSPRITE hAmmo;
|
||||
wrect_t rcAmmo;
|
||||
HSPRITE hAmmo2;
|
||||
wrect_t rcAmmo2;
|
||||
HSPRITE hCrosshair;
|
||||
wrect_t rcCrosshair;
|
||||
HSPRITE hAutoaim;
|
||||
wrect_t rcAutoaim;
|
||||
HSPRITE hZoomedCrosshair;
|
||||
wrect_t rcZoomedCrosshair;
|
||||
HSPRITE hZoomedAutoaim;
|
||||
wrect_t rcZoomedAutoaim;
|
||||
};
|
||||
|
||||
typedef int AMMO;
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,186 @@
|
|||
/***
|
||||
*
|
||||
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
|
||||
*
|
||||
* This product contains software technology licensed from Id
|
||||
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Use, distribution, and modification of this source code and/or resulting
|
||||
* object code is restricted to non-commercial enhancements to products from
|
||||
* Valve LLC. All other use, distribution, or modification is prohibited
|
||||
* without written permission from Valve LLC.
|
||||
*
|
||||
****/
|
||||
//
|
||||
// ammohistory.cpp
|
||||
//
|
||||
|
||||
|
||||
#include "extdll.h"
|
||||
#include "hud_iface.h"
|
||||
#include "hud.h"
|
||||
#include "hud_ammohistory.h"
|
||||
|
||||
HistoryResource gHR;
|
||||
|
||||
#define AMMO_PICKUP_GAP (gHR.iHistoryGap+5)
|
||||
#define AMMO_PICKUP_PICK_HEIGHT (32 + (gHR.iHistoryGap * 2))
|
||||
#define AMMO_PICKUP_HEIGHT_MAX (SCREEN_HEIGHT - 100)
|
||||
|
||||
#define MAX_ITEM_NAME 32
|
||||
int HISTORY_DRAW_TIME = 5;
|
||||
|
||||
// keep a list of items
|
||||
struct ITEM_INFO
|
||||
{
|
||||
char szName[MAX_ITEM_NAME];
|
||||
HSPRITE spr;
|
||||
wrect_t rect;
|
||||
};
|
||||
|
||||
void HistoryResource :: AddToHistory( int iType, int iId, int iCount )
|
||||
{
|
||||
if ( iType == HISTSLOT_AMMO && !iCount )
|
||||
return; // no amount, so don't add
|
||||
|
||||
if ( (((AMMO_PICKUP_GAP * iCurrentHistorySlot) + AMMO_PICKUP_PICK_HEIGHT) > AMMO_PICKUP_HEIGHT_MAX) || (iCurrentHistorySlot >= MAX_HISTORY) )
|
||||
{ // the pic would have to be drawn too high
|
||||
// so start from the bottom
|
||||
iCurrentHistorySlot = 0;
|
||||
}
|
||||
|
||||
HIST_ITEM *freeslot = &rgAmmoHistory[iCurrentHistorySlot++]; // default to just writing to the first slot
|
||||
HISTORY_DRAW_TIME = CVAR_GET_FLOAT( "hud_drawhistory_time" );
|
||||
|
||||
freeslot->type = iType;
|
||||
freeslot->iId = iId;
|
||||
freeslot->iCount = iCount;
|
||||
freeslot->DisplayTime = gHUD.m_flTime + HISTORY_DRAW_TIME;
|
||||
}
|
||||
|
||||
void HistoryResource :: AddToHistory( int iType, const char *szName, int iCount )
|
||||
{
|
||||
if ( iType != HISTSLOT_ITEM )
|
||||
return;
|
||||
|
||||
if ( (((AMMO_PICKUP_GAP * iCurrentHistorySlot) + AMMO_PICKUP_PICK_HEIGHT) > AMMO_PICKUP_HEIGHT_MAX) || (iCurrentHistorySlot >= MAX_HISTORY) )
|
||||
{ // the pic would have to be drawn too high
|
||||
// so start from the bottom
|
||||
iCurrentHistorySlot = 0;
|
||||
}
|
||||
|
||||
HIST_ITEM *freeslot = &rgAmmoHistory[iCurrentHistorySlot++]; // default to just writing to the first slot
|
||||
|
||||
// I am really unhappy with all the code in this file
|
||||
|
||||
int i = gHUD.GetSpriteIndex( szName );
|
||||
if ( i == -1 )
|
||||
return; // unknown sprite name, don't add it to history
|
||||
|
||||
freeslot->iId = i;
|
||||
freeslot->type = iType;
|
||||
freeslot->iCount = iCount;
|
||||
|
||||
HISTORY_DRAW_TIME = CVAR_GET_FLOAT( "hud_drawhistory_time" );
|
||||
freeslot->DisplayTime = gHUD.m_flTime + HISTORY_DRAW_TIME;
|
||||
}
|
||||
|
||||
|
||||
void HistoryResource :: CheckClearHistory( void )
|
||||
{
|
||||
for ( int i = 0; i < MAX_HISTORY; i++ )
|
||||
{
|
||||
if ( rgAmmoHistory[i].type )
|
||||
return;
|
||||
}
|
||||
|
||||
iCurrentHistorySlot = 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Draw Ammo pickup history
|
||||
//
|
||||
int HistoryResource :: DrawAmmoHistory( float flTime )
|
||||
{
|
||||
for ( int i = 0; i < MAX_HISTORY; i++ )
|
||||
{
|
||||
if ( rgAmmoHistory[i].type )
|
||||
{
|
||||
rgAmmoHistory[i].DisplayTime = min( rgAmmoHistory[i].DisplayTime, gHUD.m_flTime + HISTORY_DRAW_TIME );
|
||||
|
||||
if ( rgAmmoHistory[i].DisplayTime <= flTime )
|
||||
{ // pic drawing time has expired
|
||||
memset( &rgAmmoHistory[i], 0, sizeof(HIST_ITEM) );
|
||||
CheckClearHistory();
|
||||
}
|
||||
else if ( rgAmmoHistory[i].type == HISTSLOT_AMMO )
|
||||
{
|
||||
wrect_t rcPic;
|
||||
HSPRITE *spr = gWR.GetAmmoPicFromWeapon( rgAmmoHistory[i].iId, rcPic );
|
||||
|
||||
int r, g, b;
|
||||
UnpackRGB(r,g,b, gHUD.m_iHUDColor);
|
||||
float scale = (rgAmmoHistory[i].DisplayTime - flTime) * 80;
|
||||
ScaleColors(r, g, b, min(scale, 255) );
|
||||
|
||||
// Draw the pic
|
||||
int ypos = SCREEN_HEIGHT - (AMMO_PICKUP_PICK_HEIGHT + (AMMO_PICKUP_GAP * i));
|
||||
int xpos = SCREEN_WIDTH - 24;
|
||||
if ( spr && *spr ) // weapon isn't loaded yet so just don't draw the pic
|
||||
{ // the dll has to make sure it has sent info the weapons you need
|
||||
SPR_Set( *spr, r, g, b );
|
||||
SPR_DrawAdditive( 0, xpos, ypos, &rcPic );
|
||||
}
|
||||
|
||||
// Draw the number
|
||||
gHUD.DrawHudNumberString( xpos - 10, ypos, xpos - 100, rgAmmoHistory[i].iCount, r, g, b );
|
||||
}
|
||||
else if ( rgAmmoHistory[i].type == HISTSLOT_WEAP )
|
||||
{
|
||||
WEAPON *weap = gWR.GetWeapon( rgAmmoHistory[i].iId );
|
||||
|
||||
if ( !weap )
|
||||
return 1; // we don't know about the weapon yet, so don't draw anything
|
||||
|
||||
int r, g, b;
|
||||
UnpackRGB(r,g,b, gHUD.m_iHUDColor);
|
||||
|
||||
if ( !gWR.HasAmmo( weap ) )
|
||||
UnpackRGB(r,g,b, RGB_REDISH); // if the weapon doesn't have ammo, display it as red
|
||||
|
||||
float scale = (rgAmmoHistory[i].DisplayTime - flTime) * 80;
|
||||
ScaleColors(r, g, b, min(scale, 255) );
|
||||
|
||||
int ypos = SCREEN_HEIGHT - (AMMO_PICKUP_PICK_HEIGHT + (AMMO_PICKUP_GAP * i));
|
||||
int xpos = SCREEN_WIDTH - (weap->rcInactive.right - weap->rcInactive.left);
|
||||
SPR_Set( weap->hInactive, r, g, b );
|
||||
SPR_DrawAdditive( 0, xpos, ypos, &weap->rcInactive );
|
||||
}
|
||||
else if ( rgAmmoHistory[i].type == HISTSLOT_ITEM )
|
||||
{
|
||||
int r, g, b;
|
||||
|
||||
if ( !rgAmmoHistory[i].iId )
|
||||
continue; // sprite not loaded
|
||||
|
||||
wrect_t rect = gHUD.GetSpriteRect( rgAmmoHistory[i].iId );
|
||||
|
||||
UnpackRGB(r,g,b, gHUD.m_iHUDColor);
|
||||
float scale = (rgAmmoHistory[i].DisplayTime - flTime) * 80;
|
||||
ScaleColors(r, g, b, min(scale, 255) );
|
||||
|
||||
int ypos = SCREEN_HEIGHT - (AMMO_PICKUP_PICK_HEIGHT + (AMMO_PICKUP_GAP * i));
|
||||
int xpos = SCREEN_WIDTH - (rect.right - rect.left) - 10;
|
||||
|
||||
SPR_Set( gHUD.GetSprite( rgAmmoHistory[i].iId ), r, g, b );
|
||||
SPR_DrawAdditive( 0, xpos, ypos, &rect );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
/***
|
||||
*
|
||||
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
|
||||
*
|
||||
* This product contains software technology licensed from Id
|
||||
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Use, distribution, and modification of this source code and/or resulting
|
||||
* object code is restricted to non-commercial enhancements to products from
|
||||
* Valve LLC. All other use, distribution, or modification is prohibited
|
||||
* without written permission from Valve LLC.
|
||||
*
|
||||
****/
|
||||
//
|
||||
// ammohistory.h
|
||||
//
|
||||
|
||||
// this is the max number of items in each bucket
|
||||
#define MAX_WEAPON_POSITIONS MAX_WEAPON_SLOTS
|
||||
|
||||
class WeaponsResource
|
||||
{
|
||||
private:
|
||||
// Information about weapons & ammo
|
||||
WEAPON rgWeapons[MAX_WEAPONS]; // Weapons Array
|
||||
|
||||
// counts of weapons * ammo
|
||||
// The slots currently in use by weapons. The value is a pointer to the weapon;
|
||||
// if it's NULL, no weapon is there
|
||||
WEAPON* rgSlots[MAX_WEAPON_SLOTS+1][MAX_WEAPON_POSITIONS+1];
|
||||
int riAmmo[MAX_AMMO_SLOTS]; // count of each ammo type
|
||||
|
||||
public:
|
||||
void Init( void )
|
||||
{
|
||||
memset( rgWeapons, 0, sizeof rgWeapons );
|
||||
Reset();
|
||||
}
|
||||
|
||||
void Reset( void )
|
||||
{
|
||||
iOldWeaponBits = 0;
|
||||
memset( rgSlots, 0, sizeof rgSlots );
|
||||
memset( riAmmo, 0, sizeof riAmmo );
|
||||
}
|
||||
|
||||
///// WEAPON /////
|
||||
int iOldWeaponBits;
|
||||
|
||||
WEAPON *GetWeapon( int iId ) { return &rgWeapons[iId]; }
|
||||
void AddWeapon( WEAPON *wp )
|
||||
{
|
||||
rgWeapons[ wp->iId ] = *wp;
|
||||
LoadWeaponSprites( &rgWeapons[ wp->iId ] );
|
||||
}
|
||||
|
||||
void PickupWeapon( WEAPON *wp )
|
||||
{
|
||||
rgSlots[ wp->iSlot ][ wp->iSlotPos ] = wp;
|
||||
}
|
||||
|
||||
void DropWeapon( WEAPON *wp )
|
||||
{
|
||||
rgSlots[ wp->iSlot ][ wp->iSlotPos ] = NULL;
|
||||
}
|
||||
|
||||
void DropAllWeapons( void )
|
||||
{
|
||||
for ( int i = 0; i < MAX_WEAPONS; i++ )
|
||||
{
|
||||
if ( rgWeapons[i].iId )
|
||||
DropWeapon( &rgWeapons[i] );
|
||||
}
|
||||
}
|
||||
|
||||
WEAPON* GetWeaponSlot( int slot, int pos ) { return rgSlots[slot][pos]; }
|
||||
|
||||
void LoadWeaponSprite( WEAPON *p, const char *type );
|
||||
void LoadWeaponSprites( WEAPON* wp );
|
||||
void LoadAllWeaponSprites( void );
|
||||
WEAPON* GetFirstPos( int iSlot );
|
||||
void SelectSlot( int iSlot, int fAdvance, int iDirection );
|
||||
WEAPON* GetNextActivePos( int iSlot, int iSlotPos );
|
||||
|
||||
int HasAmmo( WEAPON *p );
|
||||
|
||||
///// AMMO /////
|
||||
AMMO GetAmmo( int iId ) { return iId; }
|
||||
|
||||
void SetAmmo( int iId, int iCount ) { riAmmo[ iId ] = iCount; }
|
||||
|
||||
int CountAmmo( int iId );
|
||||
|
||||
HSPRITE* GetAmmoPicFromWeapon( int iAmmoId, wrect_t& rect );
|
||||
};
|
||||
|
||||
#define MAX_HISTORY 12
|
||||
enum
|
||||
{
|
||||
HISTSLOT_EMPTY,
|
||||
HISTSLOT_AMMO,
|
||||
HISTSLOT_WEAP,
|
||||
HISTSLOT_ITEM,
|
||||
};
|
||||
|
||||
class HistoryResource
|
||||
{
|
||||
private:
|
||||
struct HIST_ITEM
|
||||
{
|
||||
int type;
|
||||
float DisplayTime; // the time at which this item should be removed from the history
|
||||
int iCount;
|
||||
int iId;
|
||||
};
|
||||
|
||||
HIST_ITEM rgAmmoHistory[MAX_HISTORY];
|
||||
public:
|
||||
void Init( void ) { Reset(); }
|
||||
void Reset( void ) { memset( rgAmmoHistory, 0, sizeof rgAmmoHistory ); }
|
||||
|
||||
int iHistoryGap;
|
||||
int iCurrentHistorySlot;
|
||||
|
||||
void AddToHistory( int iType, int iId, int iCount = 0 );
|
||||
void AddToHistory( int iType, const char *szName, int iCount = 0 );
|
||||
|
||||
void CheckClearHistory( void );
|
||||
int DrawAmmoHistory( float flTime );
|
||||
};
|
||||
|
||||
extern WeaponsResource gWR;
|
||||
extern HistoryResource gHR;
|
|
@ -0,0 +1,135 @@
|
|||
/***
|
||||
*
|
||||
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
|
||||
*
|
||||
* This product contains software technology licensed from Id
|
||||
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Use, distribution, and modification of this source code and/or resulting
|
||||
* object code is restricted to non-commercial enhancements to products from
|
||||
* Valve LLC. All other use, distribution, or modification is prohibited
|
||||
* without written permission from Valve LLC.
|
||||
*
|
||||
****/
|
||||
//
|
||||
// battery.cpp
|
||||
//
|
||||
// implementation of CHudBattery class
|
||||
//
|
||||
|
||||
#include "extdll.h"
|
||||
#include "hud_iface.h"
|
||||
#include "hud.h"
|
||||
|
||||
DECLARE_MESSAGE( m_Battery, Battery )
|
||||
|
||||
int CHudBattery :: Init( void )
|
||||
{
|
||||
m_iBat = 0;
|
||||
m_fFade = 0;
|
||||
m_iFlags = 0;
|
||||
|
||||
HOOK_MESSAGE( Battery );
|
||||
|
||||
gHUD.AddHudElem( this );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHudBattery :: VidInit( void )
|
||||
{
|
||||
int HUD_suit_empty = gHUD.GetSpriteIndex( "suit_empty" );
|
||||
int HUD_suit_full = gHUD.GetSpriteIndex( "suit_full" );
|
||||
|
||||
m_hSprite1 = m_hSprite2 = 0; // delaying get sprite handles until we know the sprites are loaded
|
||||
m_prc1 = &gHUD.GetSpriteRect( HUD_suit_empty );
|
||||
m_prc2 = &gHUD.GetSpriteRect( HUD_suit_full );
|
||||
m_iHeight = m_prc2->bottom - m_prc1->top;
|
||||
m_fFade = 0;
|
||||
return 1;
|
||||
};
|
||||
|
||||
int CHudBattery:: MsgFunc_Battery( const char *pszName, int iSize, void *pbuf )
|
||||
{
|
||||
m_iFlags |= HUD_ACTIVE;
|
||||
|
||||
|
||||
BEGIN_READ( pszName, iSize, pbuf );
|
||||
int x = READ_SHORT();
|
||||
|
||||
if( x != m_iBat )
|
||||
{
|
||||
m_fFade = FADE_TIME;
|
||||
m_iBat = x;
|
||||
}
|
||||
|
||||
END_READ();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHudBattery :: Draw( float flTime )
|
||||
{
|
||||
if( gHUD.m_iHideHUDDisplay & HIDEHUD_HEALTH )
|
||||
return 1;
|
||||
|
||||
int r, g, b, x, y, a;
|
||||
wrect_t rc;
|
||||
|
||||
rc = *m_prc2;
|
||||
|
||||
// battery can go from 0 to 100 so * 0.01 goes from 0 to 1
|
||||
rc.top += m_iHeight * ((float)(100-(min(100,m_iBat))) * 0.01);
|
||||
|
||||
UnpackRGB( r, g, b, gHUD.m_iHUDColor );
|
||||
|
||||
if(!( gHUD.m_iHideHUDDisplay & ITEM_SUIT ))
|
||||
return 1;
|
||||
|
||||
// Has health changed? Flash the health #
|
||||
if( m_fFade )
|
||||
{
|
||||
if( m_fFade > FADE_TIME )
|
||||
m_fFade = FADE_TIME;
|
||||
|
||||
m_fFade -= (gHUD.m_flTimeDelta * 20);
|
||||
if( m_fFade <= 0 )
|
||||
{
|
||||
a = 128;
|
||||
m_fFade = 0;
|
||||
}
|
||||
|
||||
// Fade the health number back to dim
|
||||
a = MIN_ALPHA + (m_fFade/FADE_TIME) * 128;
|
||||
|
||||
}
|
||||
else a = MIN_ALPHA;
|
||||
|
||||
ScaleColors( r, g, b, a );
|
||||
|
||||
int iOffset = (m_prc1->bottom - m_prc1->top) / 6;
|
||||
|
||||
y = SCREEN_HEIGHT - gHUD.m_iFontHeight - gHUD.m_iFontHeight / 2;
|
||||
x = SCREEN_WIDTH / 5;
|
||||
|
||||
// make sure we have the right sprite handles
|
||||
if( !m_hSprite1 )
|
||||
m_hSprite1 = gHUD.GetSprite( gHUD.GetSpriteIndex( "suit_empty" ));
|
||||
if( !m_hSprite2 )
|
||||
m_hSprite2 = gHUD.GetSprite( gHUD.GetSpriteIndex( "suit_full" ));
|
||||
|
||||
SPR_Set( m_hSprite1, r, g, b );
|
||||
SPR_DrawAdditive( 0, x, y - iOffset, m_prc1 );
|
||||
|
||||
if( rc.bottom > rc.top )
|
||||
{
|
||||
SPR_Set( m_hSprite2, r, g, b );
|
||||
SPR_DrawAdditive( 0, x, y - iOffset + (rc.top - m_prc2->top), &rc );
|
||||
}
|
||||
|
||||
x += (m_prc1->right - m_prc1->left);
|
||||
x = gHUD.DrawHudNumber( x, y, DHN_3DIGITS|DHN_DRAWZERO, m_iBat, r, g, b );
|
||||
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,232 @@
|
|||
/***
|
||||
*
|
||||
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
|
||||
*
|
||||
* This product contains software technology licensed from Id
|
||||
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Use, distribution, and modification of this source code and/or resulting
|
||||
* object code is restricted to non-commercial enhancements to products from
|
||||
* Valve LLC. All other use, distribution, or modification is prohibited
|
||||
* without written permission from Valve LLC.
|
||||
*
|
||||
****/
|
||||
//
|
||||
// death notice
|
||||
//
|
||||
#include "extdll.h"
|
||||
#include "hud_iface.h"
|
||||
#include "hud.h"
|
||||
|
||||
DECLARE_MESSAGE( m_DeathNotice, DeathMsg );
|
||||
|
||||
struct DeathNoticeItem
|
||||
{
|
||||
char szKiller[MAX_PLAYER_NAME_LENGTH*2];
|
||||
char szVictim[MAX_PLAYER_NAME_LENGTH*2];
|
||||
int iId; // the index number of the associated sprite
|
||||
int iSuicide;
|
||||
int iTeamKill;
|
||||
int iNonPlayerKill;
|
||||
float flDisplayTime;
|
||||
};
|
||||
|
||||
#define MAX_DEATHNOTICES 4
|
||||
static int DEATHNOTICE_DISPLAY_TIME = 6;
|
||||
|
||||
#define DEATHNOTICE_TOP 32
|
||||
|
||||
DeathNoticeItem rgDeathNoticeList[ MAX_DEATHNOTICES + 1 ];
|
||||
|
||||
|
||||
int CHudDeathNotice :: Init( void )
|
||||
{
|
||||
gHUD.AddHudElem( this );
|
||||
|
||||
HOOK_MESSAGE( DeathMsg );
|
||||
|
||||
CVAR_REGISTER( "hud_deathnotice_time", "6", 0, "time to show deathnotice" );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void CHudDeathNotice :: InitHUDData( void )
|
||||
{
|
||||
memset( rgDeathNoticeList, 0, sizeof( rgDeathNoticeList ));
|
||||
}
|
||||
|
||||
|
||||
int CHudDeathNotice :: VidInit( void )
|
||||
{
|
||||
m_HUD_d_skull = gHUD.GetSpriteIndex( "d_skull" );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHudDeathNotice :: Draw( float flTime )
|
||||
{
|
||||
int x, y, r, g, b;
|
||||
|
||||
for( int i = 0; i < MAX_DEATHNOTICES; i++ )
|
||||
{
|
||||
if( rgDeathNoticeList[i].iId == 0 )
|
||||
break; // we've gone through them all
|
||||
|
||||
if( rgDeathNoticeList[i].flDisplayTime < flTime )
|
||||
{
|
||||
// display time has expired
|
||||
// remove the current item from the list
|
||||
memmove( &rgDeathNoticeList[i], &rgDeathNoticeList[i+1], sizeof(DeathNoticeItem) * (MAX_DEATHNOTICES - i));
|
||||
i--; // continue on the next item; stop the counter getting incremented
|
||||
continue;
|
||||
}
|
||||
|
||||
rgDeathNoticeList[i].flDisplayTime = min( rgDeathNoticeList[i].flDisplayTime, gHUD.m_flTime + DEATHNOTICE_DISPLAY_TIME );
|
||||
|
||||
// Draw the death notice
|
||||
|
||||
y = DEATHNOTICE_TOP + (20 * i); //!!!
|
||||
|
||||
int id = (rgDeathNoticeList[i].iId == -1) ? m_HUD_d_skull : rgDeathNoticeList[i].iId;
|
||||
x = SCREEN_WIDTH - ConsoleStringLen(rgDeathNoticeList[i].szVictim) - (gHUD.GetSpriteRect(id).right - gHUD.GetSpriteRect(id).left);
|
||||
|
||||
if ( !rgDeathNoticeList[i].iSuicide )
|
||||
{
|
||||
x -= (5 + ConsoleStringLen( rgDeathNoticeList[i].szKiller ) );
|
||||
|
||||
// Draw killers name
|
||||
x = 5 + DrawConsoleString( x, y, rgDeathNoticeList[i].szKiller );
|
||||
}
|
||||
|
||||
r = 255; g = 80; b = 0;
|
||||
if ( rgDeathNoticeList[i].iTeamKill )
|
||||
{
|
||||
r = 10; g = 240; b = 10; // display it in sickly green
|
||||
}
|
||||
|
||||
// Draw death weapon
|
||||
SPR_Set( gHUD.GetSprite(id), r, g, b );
|
||||
SPR_DrawAdditive( 0, x, y, &gHUD.GetSpriteRect( id ));
|
||||
|
||||
x += (gHUD.GetSpriteRect( id ).right - gHUD.GetSpriteRect( id ).left );
|
||||
|
||||
// Draw victims name
|
||||
x = DrawConsoleString( x, y, rgDeathNoticeList[i].szVictim );
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// This message handler may be better off elsewhere
|
||||
int CHudDeathNotice :: MsgFunc_DeathMsg( const char *pszName, int iSize, void *pbuf )
|
||||
{
|
||||
m_iFlags |= HUD_ACTIVE;
|
||||
|
||||
BEGIN_READ( pszName, iSize, pbuf );
|
||||
|
||||
int killer = READ_BYTE();
|
||||
int victim = READ_BYTE();
|
||||
|
||||
char killedwith[32];
|
||||
strcpy( killedwith, "d_" );
|
||||
strncat( killedwith, READ_STRING(), 32 );
|
||||
|
||||
gHUD.m_Scoreboard.DeathMsg( killer, victim );
|
||||
|
||||
for ( int i = 0; i < MAX_DEATHNOTICES; i++ )
|
||||
{
|
||||
if ( rgDeathNoticeList[i].iId == 0 )
|
||||
break;
|
||||
}
|
||||
if ( i == MAX_DEATHNOTICES )
|
||||
{
|
||||
// move the rest of the list forward to make room for this item
|
||||
memmove( rgDeathNoticeList, rgDeathNoticeList+1, sizeof( DeathNoticeItem ) * MAX_DEATHNOTICES );
|
||||
i = MAX_DEATHNOTICES - 1;
|
||||
}
|
||||
|
||||
gHUD.m_Scoreboard.GetAllPlayersInfo();
|
||||
|
||||
char *killer_name = gHUD.m_Scoreboard.m_PlayerInfoList[ killer ].name;
|
||||
char *victim_name = gHUD.m_Scoreboard.m_PlayerInfoList[ victim ].name;
|
||||
if( !killer_name ) killer_name = "";
|
||||
if( !victim_name ) victim_name = "";
|
||||
|
||||
// Is it a non-player object kill?
|
||||
if ( ((char)victim) == -1 )
|
||||
{
|
||||
rgDeathNoticeList[i].iNonPlayerKill = TRUE;
|
||||
|
||||
// Store the object's name in the Victim slot (skip the d_ bit)
|
||||
strcpy( rgDeathNoticeList[i].szVictim, killedwith+2 );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( killer == victim || killer == 0 )
|
||||
rgDeathNoticeList[i].iSuicide = TRUE;
|
||||
|
||||
if( !strcmp( killedwith, "d_teammate" ) )
|
||||
rgDeathNoticeList[i].iTeamKill = TRUE;
|
||||
}
|
||||
|
||||
// Find the sprite in the list
|
||||
int spr = gHUD.GetSpriteIndex( killedwith );
|
||||
|
||||
rgDeathNoticeList[i].iId = spr;
|
||||
|
||||
DEATHNOTICE_DISPLAY_TIME = CVAR_GET_FLOAT( "hud_deathnotice_time" );
|
||||
rgDeathNoticeList[i].flDisplayTime = gHUD.m_flTime + DEATHNOTICE_DISPLAY_TIME;
|
||||
|
||||
if( rgDeathNoticeList[i].iNonPlayerKill )
|
||||
{
|
||||
ConsolePrint( rgDeathNoticeList[i].szKiller );
|
||||
ConsolePrint( " killed a " );
|
||||
ConsolePrint( rgDeathNoticeList[i].szVictim );
|
||||
ConsolePrint( "\n" );
|
||||
}
|
||||
else
|
||||
{
|
||||
// record the death notice in the console
|
||||
if ( rgDeathNoticeList[i].iSuicide )
|
||||
{
|
||||
ConsolePrint( rgDeathNoticeList[i].szVictim );
|
||||
|
||||
if ( !strcmp( killedwith, "d_world" ) )
|
||||
{
|
||||
ConsolePrint( " died" );
|
||||
}
|
||||
else
|
||||
{
|
||||
ConsolePrint( " killed self" );
|
||||
}
|
||||
}
|
||||
else if ( rgDeathNoticeList[i].iTeamKill )
|
||||
{
|
||||
ConsolePrint( rgDeathNoticeList[i].szKiller );
|
||||
ConsolePrint( " killed his teammate " );
|
||||
ConsolePrint( rgDeathNoticeList[i].szVictim );
|
||||
}
|
||||
else
|
||||
{
|
||||
ConsolePrint( rgDeathNoticeList[i].szKiller );
|
||||
ConsolePrint( " killed " );
|
||||
ConsolePrint( rgDeathNoticeList[i].szVictim );
|
||||
}
|
||||
|
||||
if ( killedwith && *killedwith && (*killedwith > 13 ) && strcmp( killedwith, "d_world" ) && !rgDeathNoticeList[i].iTeamKill )
|
||||
{
|
||||
ConsolePrint( " with " );
|
||||
|
||||
// replace the code names with the 'real' names
|
||||
if( !strcmp( killedwith+2, "egon" ) )
|
||||
strcpy( killedwith, "d_gluon gun" );
|
||||
if( !strcmp( killedwith+2, "gauss" ) )
|
||||
strcpy( killedwith, "d_tau cannon" );
|
||||
|
||||
ConsolePrint( killedwith+2 ); // skip over the "d_" part
|
||||
}
|
||||
ConsolePrint( "\n" );
|
||||
}
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
/***
|
||||
*
|
||||
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
|
||||
*
|
||||
* This product contains software technology licensed from Id
|
||||
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Use, distribution, and modification of this source code and/or resulting
|
||||
* object code is restricted to non-commercial enhancements to products from
|
||||
* Valve LLC. All other use, distribution, or modification is prohibited
|
||||
* without written permission from Valve LLC.
|
||||
*
|
||||
****/
|
||||
//
|
||||
// flashlight.cpp
|
||||
//
|
||||
// implementation of CHudFlashlight class
|
||||
//
|
||||
|
||||
#include "extdll.h"
|
||||
#include "hud_iface.h"
|
||||
#include "hud.h"
|
||||
|
||||
DECLARE_MESSAGE( m_Flash, FlashBat )
|
||||
DECLARE_MESSAGE( m_Flash, Flashlight )
|
||||
|
||||
int CHudFlashlight :: Init( void )
|
||||
{
|
||||
m_fFade = 0;
|
||||
m_fOn = 0;
|
||||
|
||||
HOOK_MESSAGE( Flashlight );
|
||||
HOOK_MESSAGE( FlashBat );
|
||||
|
||||
m_iFlags |= HUD_ACTIVE;
|
||||
|
||||
gHUD.AddHudElem( this );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void CHudFlashlight :: Reset( void )
|
||||
{
|
||||
m_fFade = 0;
|
||||
m_fOn = 0;
|
||||
}
|
||||
|
||||
int CHudFlashlight :: VidInit( void )
|
||||
{
|
||||
int HUD_flash_empty = gHUD.GetSpriteIndex( "flash_empty" );
|
||||
int HUD_flash_full = gHUD.GetSpriteIndex( "flash_full" );
|
||||
int HUD_flash_beam = gHUD.GetSpriteIndex( "flash_beam" );
|
||||
|
||||
m_hSprite1 = gHUD.GetSprite( HUD_flash_empty );
|
||||
m_hSprite2 = gHUD.GetSprite( HUD_flash_full );
|
||||
m_hBeam = gHUD.GetSprite( HUD_flash_beam );
|
||||
m_prc1 = &gHUD.GetSpriteRect( HUD_flash_empty );
|
||||
m_prc2 = &gHUD.GetSpriteRect( HUD_flash_full );
|
||||
m_prcBeam = &gHUD.GetSpriteRect( HUD_flash_beam );
|
||||
m_iWidth = m_prc2->right - m_prc2->left;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHudFlashlight:: MsgFunc_FlashBat(const char *pszName, int iSize, void *pbuf )
|
||||
{
|
||||
BEGIN_READ( pszName, iSize, pbuf );
|
||||
|
||||
int x = READ_BYTE();
|
||||
m_iBat = x;
|
||||
m_flBat = ((float)x) / 100.0;
|
||||
|
||||
END_READ();
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHudFlashlight :: MsgFunc_Flashlight( const char *pszName, int iSize, void *pbuf )
|
||||
{
|
||||
BEGIN_READ( pszName, iSize, pbuf );
|
||||
|
||||
m_fOn = READ_BYTE();
|
||||
int x = READ_BYTE();
|
||||
m_iBat = x;
|
||||
m_flBat = ((float)x) / 100.0;
|
||||
|
||||
END_READ();
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHudFlashlight :: Draw( float flTime )
|
||||
{
|
||||
if( gHUD.m_iHideHUDDisplay & (HIDEHUD_FLASHLIGHT|HIDEHUD_ALL) )
|
||||
return 1;
|
||||
|
||||
int r, g, b, x, y, a;
|
||||
wrect_t rc;
|
||||
|
||||
if(!( gHUD.m_iHideHUDDisplay & ITEM_SUIT ))
|
||||
return 1;
|
||||
|
||||
if( m_fOn )
|
||||
a = 225;
|
||||
else a = MIN_ALPHA;
|
||||
|
||||
if( m_flBat < 0.20 )
|
||||
UnpackRGB( r, g, b, RGB_REDISH );
|
||||
else UnpackRGB( r, g, b, gHUD.m_iHUDColor );
|
||||
|
||||
ScaleColors( r, g, b, a );
|
||||
|
||||
y = (m_prc1->bottom - m_prc2->top) / 2;
|
||||
x = SCREEN_WIDTH - m_iWidth - m_iWidth / 2;
|
||||
|
||||
// draw the flashlight casing
|
||||
SPR_Set( m_hSprite1, r, g, b );
|
||||
SPR_DrawAdditive( 0, x, y, m_prc1 );
|
||||
|
||||
if( m_fOn )
|
||||
{
|
||||
// draw the flashlight beam
|
||||
x = SCREEN_WIDTH - m_iWidth / 2;
|
||||
|
||||
SPR_Set( m_hBeam, r, g, b );
|
||||
SPR_DrawAdditive( 0, x, y, m_prcBeam );
|
||||
}
|
||||
|
||||
// draw the flashlight energy level
|
||||
x = SCREEN_WIDTH - m_iWidth - m_iWidth / 2;
|
||||
int iOffset = m_iWidth * (1.0 - m_flBat);
|
||||
|
||||
if( iOffset < m_iWidth )
|
||||
{
|
||||
rc = *m_prc2;
|
||||
rc.left += iOffset;
|
||||
|
||||
SPR_Set( m_hSprite2, r, g, b );
|
||||
SPR_DrawAdditive( 0, x + iOffset, y, &rc );
|
||||
}
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,177 @@
|
|||
/***
|
||||
*
|
||||
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
|
||||
*
|
||||
* This product contains software technology licensed from Id
|
||||
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Use, distribution, and modification of this source code and/or resulting
|
||||
* object code is restricted to non-commercial enhancements to products from
|
||||
* Valve LLC. All other use, distribution, or modification is prohibited
|
||||
* without written permission from Valve LLC.
|
||||
*
|
||||
****/
|
||||
//
|
||||
// Geiger.cpp
|
||||
//
|
||||
// implementation of CHudAmmo class
|
||||
//
|
||||
|
||||
#include "extdll.h"
|
||||
#include "hud_iface.h"
|
||||
#include "hud.h"
|
||||
|
||||
DECLARE_MESSAGE( m_Geiger, Geiger )
|
||||
|
||||
int CHudGeiger::Init( void )
|
||||
{
|
||||
HOOK_MESSAGE( Geiger );
|
||||
|
||||
m_iGeigerRange = 0;
|
||||
m_iFlags = 0;
|
||||
|
||||
gHUD.AddHudElem( this );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHudGeiger::VidInit( void )
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHudGeiger::MsgFunc_Geiger( const char *pszName, int iSize, void *pbuf )
|
||||
{
|
||||
BEGIN_READ( pszName, iSize, pbuf );
|
||||
|
||||
// update geiger data
|
||||
m_iGeigerRange = READ_BYTE();
|
||||
m_iGeigerRange = m_iGeigerRange << 2;
|
||||
|
||||
m_iFlags |= HUD_ACTIVE;
|
||||
|
||||
END_READ();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHudGeiger::Draw( float flTime )
|
||||
{
|
||||
int pct;
|
||||
float flvol;
|
||||
int rg[3];
|
||||
int i;
|
||||
|
||||
if( m_iGeigerRange < 1000 && m_iGeigerRange > 0 )
|
||||
{
|
||||
// peicewise linear is better than continuous formula for this
|
||||
if( m_iGeigerRange > 800 )
|
||||
{
|
||||
pct = 0; //ALERT( at_console, "range > 800\n" );
|
||||
}
|
||||
else if( m_iGeigerRange > 600 )
|
||||
{
|
||||
pct = 2;
|
||||
flvol = 0.4; //ALERT( at_console, "range > 600\n" );
|
||||
rg[0] = 1;
|
||||
rg[1] = 1;
|
||||
i = 2;
|
||||
}
|
||||
else if( m_iGeigerRange > 500 )
|
||||
{
|
||||
pct = 4;
|
||||
flvol = 0.5; //ALERT( at_console, "range > 500\n" );
|
||||
rg[0] = 1;
|
||||
rg[1] = 2;
|
||||
i = 2;
|
||||
}
|
||||
else if( m_iGeigerRange > 400 )
|
||||
{
|
||||
pct = 8;
|
||||
flvol = 0.6; //ALERT( at_console, "range > 400\n" );
|
||||
rg[0] = 1;
|
||||
rg[1] = 2;
|
||||
rg[2] = 3;
|
||||
i = 3;
|
||||
}
|
||||
else if( m_iGeigerRange > 300 )
|
||||
{
|
||||
pct = 8;
|
||||
flvol = 0.7; //ALERT( at_console, "range > 300\n" );
|
||||
rg[0] = 2;
|
||||
rg[1] = 3;
|
||||
rg[2] = 4;
|
||||
i = 3;
|
||||
}
|
||||
else if( m_iGeigerRange > 200 )
|
||||
{
|
||||
pct = 28;
|
||||
flvol = 0.78; //ALERT( at_console, "range > 200\n" );
|
||||
rg[0] = 2;
|
||||
rg[1] = 3;
|
||||
rg[2] = 4;
|
||||
i = 3;
|
||||
}
|
||||
else if( m_iGeigerRange > 150 )
|
||||
{
|
||||
pct = 40;
|
||||
flvol = 0.80; //ALERT( at_console, "range > 150\n" );
|
||||
rg[0] = 3;
|
||||
rg[1] = 4;
|
||||
rg[2] = 5;
|
||||
i = 3;
|
||||
}
|
||||
else if( m_iGeigerRange > 100 )
|
||||
{
|
||||
pct = 60;
|
||||
flvol = 0.85; //ALERT( at_console, "range > 100\n" );
|
||||
rg[0] = 3;
|
||||
rg[1] = 4;
|
||||
rg[2] = 5;
|
||||
i = 3;
|
||||
}
|
||||
else if( m_iGeigerRange > 75 )
|
||||
{
|
||||
pct = 80;
|
||||
flvol = 0.9;
|
||||
rg[0] = 4;
|
||||
rg[1] = 5;
|
||||
rg[2] = 6;
|
||||
i = 3;
|
||||
}
|
||||
else if( m_iGeigerRange > 50 )
|
||||
{
|
||||
pct = 90;
|
||||
flvol = 0.95;
|
||||
rg[0] = 5;
|
||||
rg[1] = 6;
|
||||
i = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
pct = 95;
|
||||
flvol = 1.0;
|
||||
rg[0] = 5;
|
||||
rg[1] = 6;
|
||||
i = 2;
|
||||
}
|
||||
|
||||
flvol = flvol * RANDOM_FLOAT( 0.25, 0.5 );
|
||||
|
||||
if( RANDOM_LONG( 0, 128 ) < pct )
|
||||
{
|
||||
char sz[256];
|
||||
|
||||
int j = RANDOM_LONG( 0, 2 );
|
||||
if( i > 2 )
|
||||
j += RANDOM_LONG( 0, 2 );
|
||||
|
||||
// player/geiger6.wav isn't used ?
|
||||
sprintf( sz, "player/geiger%d.wav", j + 1 );
|
||||
CL_PlaySound( sz, flvol );
|
||||
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,448 @@
|
|||
/***
|
||||
*
|
||||
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
|
||||
*
|
||||
* This product contains software technology licensed from Id
|
||||
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Use, distribution, and modification of this source code and/or resulting
|
||||
* object code is restricted to non-commercial enhancements to products from
|
||||
* Valve LLC. All other use, distribution, or modification is prohibited
|
||||
* without written permission from Valve LLC.
|
||||
*
|
||||
****/
|
||||
//
|
||||
// Health.cpp
|
||||
//
|
||||
// implementation of CHudHealth class
|
||||
//
|
||||
|
||||
#include "extdll.h"
|
||||
#include "hud_iface.h"
|
||||
#include "hud.h"
|
||||
|
||||
DECLARE_MESSAGE( m_Health, Health )
|
||||
DECLARE_MESSAGE( m_Health, Damage )
|
||||
|
||||
#define PAIN_NAME "hud_pain"
|
||||
#define DAMAGE_NAME "sprites/%d_dmg.spr"
|
||||
|
||||
int giDmgHeight, giDmgWidth;
|
||||
|
||||
int giDmgFlags[NUM_DMG_TYPES] =
|
||||
{
|
||||
DMG_POISON,
|
||||
DMG_ACID,
|
||||
DMG_FREEZE|DMG_SLOWFREEZE,
|
||||
DMG_DROWN,
|
||||
DMG_BURN|DMG_SLOWBURN,
|
||||
DMG_NERVEGAS,
|
||||
DMG_RADIATION,
|
||||
DMG_SHOCK,
|
||||
DMG_NUCLEAR
|
||||
};
|
||||
|
||||
int CHudHealth :: Init( void )
|
||||
{
|
||||
HOOK_MESSAGE( Health );
|
||||
HOOK_MESSAGE( Damage );
|
||||
m_iHealth = 100;
|
||||
m_fFade = 0;
|
||||
m_iFlags = 0;
|
||||
m_bitsDamage = 0;
|
||||
m_fAttackFront = m_fAttackRear = m_fAttackRight = m_fAttackLeft = 0;
|
||||
giDmgHeight = 0;
|
||||
giDmgWidth = 0;
|
||||
|
||||
memset( m_dmg, 0, sizeof(DAMAGE_IMAGE) * NUM_DMG_TYPES );
|
||||
gHUD.AddHudElem( this );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void CHudHealth :: Reset( void )
|
||||
{
|
||||
// make sure the pain compass is cleared when the player respawns
|
||||
m_fAttackFront = m_fAttackRear = m_fAttackRight = m_fAttackLeft = 0;
|
||||
|
||||
// force all the flashing damage icons to expire
|
||||
m_bitsDamage = 0;
|
||||
for( int i = 0; i < NUM_DMG_TYPES; i++ )
|
||||
{
|
||||
m_dmg[i].fExpire = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int CHudHealth :: VidInit( void )
|
||||
{
|
||||
m_hSprite = 0;
|
||||
|
||||
m_HUD_dmg_bio = gHUD.GetSpriteIndex( "dmg_bio" ) + 1;
|
||||
m_HUD_cross = gHUD.GetSpriteIndex( "cross" );
|
||||
|
||||
giDmgHeight = gHUD.GetSpriteRect(m_HUD_dmg_bio).right - gHUD.GetSpriteRect(m_HUD_dmg_bio).left;
|
||||
giDmgWidth = gHUD.GetSpriteRect(m_HUD_dmg_bio).bottom - gHUD.GetSpriteRect(m_HUD_dmg_bio).top;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHudHealth :: MsgFunc_Health( const char *pszName, int iSize, void *pbuf )
|
||||
{
|
||||
// TODO: update local health data
|
||||
BEGIN_READ( pszName, iSize, pbuf );
|
||||
int x = READ_BYTE();
|
||||
|
||||
m_iFlags |= HUD_ACTIVE;
|
||||
|
||||
// only update the fade if we've changed health
|
||||
if( x != m_iHealth )
|
||||
{
|
||||
m_fFade = FADE_TIME;
|
||||
m_iHealth = x;
|
||||
}
|
||||
END_READ();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHudHealth :: MsgFunc_Damage( const char *pszName, int iSize, void *pbuf )
|
||||
{
|
||||
BEGIN_READ( pszName, iSize, pbuf );
|
||||
|
||||
int armor = READ_BYTE(); // armor
|
||||
int damageTaken = READ_BYTE(); // health
|
||||
long bitsDamage = READ_LONG(); // damage bits
|
||||
|
||||
vec3_t vecFrom;
|
||||
|
||||
for( int i = 0 ; i < 3 ; i++)
|
||||
vecFrom[i] = READ_COORD();
|
||||
|
||||
UpdateTiles( gHUD.m_flTime, bitsDamage );
|
||||
|
||||
// actually took damage?
|
||||
if( damageTaken > 0 || armor > 0 )
|
||||
CalcDamageDirection(vecFrom);
|
||||
END_READ();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Returns back a color from the
|
||||
// Green <-> Yellow <-> Red ramp
|
||||
void CHudHealth :: GetPainColor( int &r, int &g, int &b )
|
||||
{
|
||||
int iHealth = m_iHealth;
|
||||
|
||||
if( iHealth > 25 )
|
||||
iHealth -= 25;
|
||||
else if( iHealth < 0 )
|
||||
iHealth = 0;
|
||||
|
||||
if( m_iHealth > 25 )
|
||||
{
|
||||
UnpackRGB( r, g, b, gHUD.m_iHUDColor );
|
||||
}
|
||||
else
|
||||
{
|
||||
r = 250;
|
||||
g = 0;
|
||||
b = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int CHudHealth :: Draw( float flTime )
|
||||
{
|
||||
int r, g, b;
|
||||
int a = 0, x, y;
|
||||
int HealthWidth;
|
||||
|
||||
if((gHUD.m_iHideHUDDisplay & HIDEHUD_HEALTH) || IsSpectateOnly())
|
||||
return 1;
|
||||
|
||||
if( !m_hSprite )
|
||||
m_hSprite = LOAD_SHADER( PAIN_NAME );
|
||||
|
||||
// has health changed? Flash the health #
|
||||
if( m_fFade )
|
||||
{
|
||||
m_fFade -= (gHUD.m_flTimeDelta * 20);
|
||||
if( m_fFade <= 0 )
|
||||
{
|
||||
a = MIN_ALPHA;
|
||||
m_fFade = 0;
|
||||
}
|
||||
|
||||
// fade the health number back to dim
|
||||
a = MIN_ALPHA + (m_fFade/FADE_TIME) * 128;
|
||||
|
||||
}
|
||||
else a = MIN_ALPHA;
|
||||
|
||||
// if health is getting low, make it bright red
|
||||
if( m_iHealth <= 15 ) a = 255;
|
||||
|
||||
GetPainColor( r, g, b );
|
||||
ScaleColors( r, g, b, a );
|
||||
|
||||
// only draw health if we have the suit.
|
||||
if( gHUD.m_iHideHUDDisplay & ITEM_SUIT )
|
||||
{
|
||||
HealthWidth = gHUD.GetSpriteRect(gHUD.m_HUD_number_0).right - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).left;
|
||||
int CrossWidth = gHUD.GetSpriteRect(m_HUD_cross).right - gHUD.GetSpriteRect(m_HUD_cross).left;
|
||||
|
||||
y = SCREEN_HEIGHT - gHUD.m_iFontHeight - gHUD.m_iFontHeight / 2;
|
||||
x = CrossWidth / 2;
|
||||
|
||||
SPR_Set( gHUD.GetSprite( m_HUD_cross ), r, g, b );
|
||||
SPR_DrawAdditive( 0, x, y, &gHUD.GetSpriteRect( m_HUD_cross ));
|
||||
|
||||
x = CrossWidth + HealthWidth / 2;
|
||||
|
||||
x = gHUD.DrawHudNumber( x, y, DHN_3DIGITS | DHN_DRAWZERO, m_iHealth, r, g, b );
|
||||
|
||||
x += HealthWidth / 2;
|
||||
|
||||
int iHeight = gHUD.m_iFontHeight;
|
||||
int iWidth = HealthWidth / 10;
|
||||
|
||||
UnpackRGB( r, g, b, gHUD.m_iHUDColor );
|
||||
FillRGBA( x, y, iWidth, iHeight, r, g, b, a );
|
||||
}
|
||||
|
||||
DrawDamage( flTime );
|
||||
return DrawPain( flTime );
|
||||
}
|
||||
|
||||
void CHudHealth :: CalcDamageDirection( Vector vecFrom )
|
||||
{
|
||||
Vector forward, right, up;
|
||||
float side, front;
|
||||
Vector vecOrigin, vecAngles;
|
||||
|
||||
if( vecFrom == Vector( 0, 0, 0 ))
|
||||
{
|
||||
m_fAttackFront = m_fAttackRear = m_fAttackRight = m_fAttackLeft = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy( vecOrigin, gHUD.m_vecOrigin, sizeof( vec3_t ));
|
||||
memcpy( vecAngles, gHUD.m_vecAngles, sizeof( vec3_t ));
|
||||
|
||||
vecFrom -= vecOrigin;
|
||||
|
||||
float flDistToTarget = vecFrom.Length();
|
||||
|
||||
vecFrom = vecFrom.Normalize();
|
||||
AngleVectors( vecAngles, forward, right, up );
|
||||
|
||||
front = vecFrom.Dot( right );
|
||||
side = vecFrom.Dot( forward );
|
||||
|
||||
if( flDistToTarget <= 50 )
|
||||
{
|
||||
m_fAttackFront = m_fAttackRear = m_fAttackRight = m_fAttackLeft = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( side > 0 )
|
||||
{
|
||||
if( side > 0.3 )
|
||||
m_fAttackFront = max( m_fAttackFront, side );
|
||||
}
|
||||
else
|
||||
{
|
||||
float f = fabs( side );
|
||||
if( f > 0.3 )
|
||||
m_fAttackRear = max( m_fAttackRear, f );
|
||||
}
|
||||
|
||||
if( front > 0 )
|
||||
{
|
||||
if( front > 0.3 )
|
||||
m_fAttackRight = max( m_fAttackRight, front );
|
||||
}
|
||||
else
|
||||
{
|
||||
float f = fabs( front );
|
||||
if( f > 0.3 )
|
||||
m_fAttackLeft = max( m_fAttackLeft, f );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int CHudHealth :: DrawPain( float flTime )
|
||||
{
|
||||
if(!( m_fAttackFront || m_fAttackRear || m_fAttackLeft || m_fAttackRight ))
|
||||
return 1;
|
||||
|
||||
int r, g, b;
|
||||
int x, y, a, shade;
|
||||
|
||||
// TODO: get the shift value of the health
|
||||
a = 255; // max brightness until then
|
||||
|
||||
float fFade = gHUD.m_flTimeDelta * 2;
|
||||
|
||||
// SPR_Draw top
|
||||
if( m_fAttackFront > 0.4 )
|
||||
{
|
||||
GetPainColor( r, g, b );
|
||||
shade = a * max( m_fAttackFront, 0.5 );
|
||||
ScaleColors( r, g, b, shade );
|
||||
SPR_Set( m_hSprite, r, g, b );
|
||||
|
||||
x = SCREEN_WIDTH / 2 - SPR_Width( m_hSprite, 0 ) / 2;
|
||||
y = SCREEN_HEIGHT / 2 - SPR_Height( m_hSprite, 0 ) * 3;
|
||||
SPR_DrawAdditive( 0, x, y, NULL );
|
||||
m_fAttackFront = max( 0, m_fAttackFront - fFade );
|
||||
}
|
||||
else m_fAttackFront = 0;
|
||||
|
||||
if( m_fAttackRight > 0.4 )
|
||||
{
|
||||
GetPainColor( r, g, b );
|
||||
shade = a * max( m_fAttackRight, 0.5 );
|
||||
ScaleColors( r, g, b, shade );
|
||||
SPR_Set( m_hSprite, r, g, b );
|
||||
|
||||
x = SCREEN_WIDTH / 2 + SPR_Width( m_hSprite, 1 ) * 2;
|
||||
y = SCREEN_HEIGHT / 2 - SPR_Height( m_hSprite,1 ) / 2;
|
||||
SPR_DrawAdditive( 1, x, y, NULL );
|
||||
m_fAttackRight = max( 0, m_fAttackRight - fFade );
|
||||
}
|
||||
else m_fAttackRight = 0;
|
||||
|
||||
if( m_fAttackRear > 0.4 )
|
||||
{
|
||||
GetPainColor( r, g, b );
|
||||
shade = a * max( m_fAttackRear, 0.5 );
|
||||
ScaleColors(r, g, b, shade);
|
||||
SPR_Set(m_hSprite, r, g, b );
|
||||
|
||||
x = SCREEN_WIDTH / 2 - SPR_Width( m_hSprite, 2 ) / 2;
|
||||
y = SCREEN_HEIGHT / 2 + SPR_Height( m_hSprite, 2 ) * 2;
|
||||
SPR_DrawAdditive( 2, x, y, NULL);
|
||||
m_fAttackRear = max( 0, m_fAttackRear - fFade );
|
||||
}
|
||||
else m_fAttackRear = 0;
|
||||
|
||||
if( m_fAttackLeft > 0.4 )
|
||||
{
|
||||
GetPainColor( r, g, b );
|
||||
shade = a * max( m_fAttackLeft, 0.5 );
|
||||
ScaleColors( r, g, b, shade );
|
||||
SPR_Set( m_hSprite, r, g, b );
|
||||
|
||||
x = SCREEN_WIDTH / 2 - SPR_Width( m_hSprite, 3 ) * 3;
|
||||
y = SCREEN_HEIGHT / 2 - SPR_Height( m_hSprite,3 ) / 2;
|
||||
SPR_DrawAdditive( 3, x, y, NULL );
|
||||
|
||||
m_fAttackLeft = max( 0, m_fAttackLeft - fFade );
|
||||
}
|
||||
else m_fAttackLeft = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHudHealth :: DrawDamage( float flTime )
|
||||
{
|
||||
int r, g, b, a;
|
||||
DAMAGE_IMAGE *pdmg;
|
||||
|
||||
if( !m_bitsDamage )
|
||||
return 1;
|
||||
|
||||
UnpackRGB( r, g, b, gHUD.m_iHUDColor );
|
||||
|
||||
a = (int)(fabs(sin( flTime * 2)) * 256.0 );
|
||||
|
||||
ScaleColors( r, g, b, a );
|
||||
|
||||
// draw all the items
|
||||
for( int i = 0; i < NUM_DMG_TYPES; i++ )
|
||||
{
|
||||
if( m_bitsDamage & giDmgFlags[i] )
|
||||
{
|
||||
pdmg = &m_dmg[i];
|
||||
SPR_Set( gHUD.GetSprite( m_HUD_dmg_bio + i ), r, g, b );
|
||||
SPR_DrawAdditive( 0, pdmg->x, pdmg->y, &gHUD.GetSpriteRect( m_HUD_dmg_bio + i ));
|
||||
}
|
||||
}
|
||||
|
||||
// check for bits that should be expired
|
||||
for( i = 0; i < NUM_DMG_TYPES; i++ )
|
||||
{
|
||||
DAMAGE_IMAGE *pdmg = &m_dmg[i];
|
||||
|
||||
if( m_bitsDamage & giDmgFlags[i] )
|
||||
{
|
||||
pdmg->fExpire = min( flTime + DMG_IMAGE_LIFE, pdmg->fExpire );
|
||||
|
||||
// when the time has expired and the flash is at the low point of the cycle
|
||||
if( pdmg->fExpire <= flTime && a < 40 )
|
||||
{
|
||||
pdmg->fExpire = 0;
|
||||
|
||||
int y = pdmg->y;
|
||||
pdmg->x = pdmg->y = 0;
|
||||
|
||||
// move everyone above down
|
||||
for( int j = 0; j < NUM_DMG_TYPES; j++ )
|
||||
{
|
||||
pdmg = &m_dmg[j];
|
||||
if(( pdmg->y ) && ( pdmg->y < y ))
|
||||
pdmg->y += giDmgHeight;
|
||||
|
||||
}
|
||||
m_bitsDamage &= ~giDmgFlags[i]; // clear the bits
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void CHudHealth :: UpdateTiles( float flTime, long bitsDamage )
|
||||
{
|
||||
DAMAGE_IMAGE *pdmg;
|
||||
|
||||
// Which types are new?
|
||||
long bitsOn = ~m_bitsDamage & bitsDamage;
|
||||
|
||||
for( int i = 0; i < NUM_DMG_TYPES; i++ )
|
||||
{
|
||||
pdmg = &m_dmg[i];
|
||||
|
||||
// is this one already on?
|
||||
if( m_bitsDamage & giDmgFlags[i] )
|
||||
{
|
||||
pdmg->fExpire = flTime + DMG_IMAGE_LIFE; // extend the duration
|
||||
if( !pdmg->fBaseline )
|
||||
pdmg->fBaseline = flTime;
|
||||
}
|
||||
|
||||
// are we just turning it on?
|
||||
if( bitsOn & giDmgFlags[i] )
|
||||
{
|
||||
// put this one at the bottom
|
||||
pdmg->x = giDmgWidth / 8;
|
||||
pdmg->y = SCREEN_HEIGHT - giDmgHeight * 2;
|
||||
pdmg->fExpire=flTime + DMG_IMAGE_LIFE;
|
||||
|
||||
// move everyone else up
|
||||
for( int j = 0; j < NUM_DMG_TYPES; j++ )
|
||||
{
|
||||
if( j == i ) continue;
|
||||
|
||||
pdmg = &m_dmg[j];
|
||||
if( pdmg->y )
|
||||
pdmg->y -= giDmgHeight;
|
||||
|
||||
}
|
||||
pdmg = &m_dmg[i];
|
||||
}
|
||||
}
|
||||
|
||||
// damage bits are only turned on here; they are turned off when the draw time has expired (in DrawDamage())
|
||||
m_bitsDamage |= bitsDamage;
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
/***
|
||||
*
|
||||
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
|
||||
*
|
||||
* This product contains software technology licensed from Id
|
||||
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Use, distribution, and modification of this source code and/or resulting
|
||||
* object code is restricted to non-commercial enhancements to products from
|
||||
* Valve LLC. All other use, distribution, or modification is prohibited
|
||||
* without written permission from Valve LLC.
|
||||
*
|
||||
****/
|
||||
|
||||
#define DMG_IMAGE_LIFE 2 // seconds that image is up
|
||||
|
||||
#define DMG_IMAGE_POISON 0
|
||||
#define DMG_IMAGE_ACID 1
|
||||
#define DMG_IMAGE_COLD 2
|
||||
#define DMG_IMAGE_DROWN 3
|
||||
#define DMG_IMAGE_BURN 4
|
||||
#define DMG_IMAGE_NERVE 5
|
||||
#define DMG_IMAGE_RAD 6
|
||||
#define DMG_IMAGE_SHOCK 7
|
||||
//tf defines
|
||||
#define DMG_IMAGE_CALTROP 8
|
||||
#define DMG_IMAGE_TRANQ 9
|
||||
#define DMG_IMAGE_CONCUSS 10
|
||||
#define DMG_IMAGE_HALLUC 11
|
||||
#define NUM_DMG_TYPES 12
|
||||
// instant damage
|
||||
|
||||
#define DMG_GENERIC 0 // generic damage was done
|
||||
#define DMG_CRUSH (1 << 0) // crushed by falling or moving object
|
||||
#define DMG_BULLET (1 << 1) // shot
|
||||
#define DMG_SLASH (1 << 2) // cut, clawed, stabbed
|
||||
#define DMG_BURN (1 << 3) // heat burned
|
||||
#define DMG_FREEZE (1 << 4) // frozen
|
||||
#define DMG_FALL (1 << 5) // fell too far
|
||||
#define DMG_BLAST (1 << 6) // explosive blast damage
|
||||
#define DMG_CLUB (1 << 7) // crowbar, punch, headbutt
|
||||
#define DMG_SHOCK (1 << 8) // electric shock
|
||||
#define DMG_SONIC (1 << 9) // sound pulse shockwave
|
||||
#define DMG_ENERGYBEAM (1 << 10) // laser or other high energy beam
|
||||
#define DMG_NEVERGIB (1 << 12) // with this bit OR'd in, no damage type will be able to gib victims upon death
|
||||
#define DMG_ALWAYSGIB (1 << 13) // with this bit OR'd in, any damage type can be made to gib victims upon death.
|
||||
|
||||
|
||||
// time-based damage
|
||||
//mask off TF-specific stuff too
|
||||
#define DMG_TIMEBASED (~(0xff003fff)) // mask for time-based damage
|
||||
|
||||
|
||||
#define DMG_DROWN (1 << 14) // Drowning
|
||||
#define DMG_FIRSTTIMEBASED DMG_DROWN
|
||||
|
||||
#define DMG_PARALYZE (1 << 15) // slows affected creature down
|
||||
#define DMG_NERVEGAS (1 << 16) // nerve toxins, very bad
|
||||
#define DMG_POISON (1 << 17) // blood poisioning
|
||||
#define DMG_RADIATION (1 << 18) // radiation exposure
|
||||
#define DMG_DROWNRECOVER (1 << 19) // drowning recovery
|
||||
#define DMG_ACID (1 << 20) // toxic chemicals or acid burns
|
||||
#define DMG_SLOWBURN (1 << 21) // in an oven
|
||||
#define DMG_SLOWFREEZE (1 << 22) // in a subzero freezer
|
||||
#define DMG_MORTAR (1 << 23) // Hit by air raid (done to distinguish grenade from mortar)
|
||||
#define DMG_NUCLEAR (1 << 24) // Players hit by this begin to burn
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float fExpire;
|
||||
float fBaseline;
|
||||
int x, y;
|
||||
} DAMAGE_IMAGE;
|
||||
|
||||
//
|
||||
//-----------------------------------------------------
|
||||
//
|
||||
class CHudHealth: public CHudBase
|
||||
{
|
||||
public:
|
||||
virtual int Init( void );
|
||||
virtual int VidInit( void );
|
||||
virtual int Draw( float fTime );
|
||||
virtual void Reset( void );
|
||||
int MsgFunc_Health( const char *pszName, int iSize, void *pbuf );
|
||||
int MsgFunc_Damage( const char *pszName, int iSize, void *pbuf );
|
||||
int m_iHealth;
|
||||
int m_HUD_dmg_bio;
|
||||
int m_HUD_cross;
|
||||
float m_fAttackFront, m_fAttackRear, m_fAttackLeft, m_fAttackRight;
|
||||
void GetPainColor( int &r, int &g, int &b );
|
||||
float m_fFade;
|
||||
|
||||
private:
|
||||
HSPRITE m_hSprite;
|
||||
HSPRITE m_hDamage;
|
||||
|
||||
DAMAGE_IMAGE m_dmg[NUM_DMG_TYPES];
|
||||
int m_bitsDamage;
|
||||
int DrawPain( float fTime );
|
||||
int DrawDamage( float fTime );
|
||||
void CalcDamageDirection( vec3_t vecFrom );
|
||||
void UpdateTiles( float fTime, long bits );
|
||||
};
|
|
@ -0,0 +1,150 @@
|
|||
/***
|
||||
*
|
||||
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
|
||||
*
|
||||
* This product contains software technology licensed from Id
|
||||
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Use, distribution, and modification of this source code and/or resulting
|
||||
* object code is restricted to non-commercial enhancements to products from
|
||||
* Valve LLC. All other use, distribution, or modification is prohibited
|
||||
* without written permission from Valve LLC.
|
||||
*
|
||||
****/
|
||||
//
|
||||
// status_icons.cpp
|
||||
//
|
||||
#include "extdll.h"
|
||||
#include "hud_iface.h"
|
||||
#include "hud.h"
|
||||
|
||||
DECLARE_MESSAGE( m_StatusIcons, StatusIcon );
|
||||
|
||||
int CHudStatusIcons::Init( void )
|
||||
{
|
||||
HOOK_MESSAGE( StatusIcon );
|
||||
gHUD.AddHudElem( this );
|
||||
Reset();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHudStatusIcons::VidInit( void )
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
void CHudStatusIcons::Reset( void )
|
||||
{
|
||||
memset( m_IconList, 0, sizeof m_IconList );
|
||||
m_iFlags &= ~HUD_ACTIVE;
|
||||
}
|
||||
|
||||
// Draw status icons along the left-hand side of the screen
|
||||
int CHudStatusIcons::Draw( float flTime )
|
||||
{
|
||||
// find starting position to draw from, along right-hand side of screen
|
||||
int x = 5;
|
||||
int y = SCREEN_HEIGHT / 2;
|
||||
|
||||
// loop through icon list, and draw any valid icons drawing up from the middle of screen
|
||||
for( int i = 0; i < MAX_ICONSPRITES; i++ )
|
||||
{
|
||||
if ( m_IconList[i].spr )
|
||||
{
|
||||
y -= ( m_IconList[i].rc.bottom - m_IconList[i].rc.top ) + 5;
|
||||
|
||||
SPR_Set( m_IconList[i].spr, m_IconList[i].r, m_IconList[i].g, m_IconList[i].b );
|
||||
SPR_DrawAdditive( 0, x, y, &m_IconList[i].rc );
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Message handler for StatusIcon message
|
||||
// accepts five values:
|
||||
// byte : TRUE = ENABLE icon, FALSE = DISABLE icon
|
||||
// string : the sprite name to display
|
||||
// byte : red
|
||||
// byte : green
|
||||
// byte : blue
|
||||
int CHudStatusIcons::MsgFunc_StatusIcon( const char *pszName, int iSize, void *pbuf )
|
||||
{
|
||||
BEGIN_READ( pszName, iSize, pbuf );
|
||||
|
||||
int ShouldEnable = READ_BYTE();
|
||||
char *pszIconName = READ_STRING();
|
||||
if ( ShouldEnable )
|
||||
{
|
||||
int r = READ_BYTE();
|
||||
int g = READ_BYTE();
|
||||
int b = READ_BYTE();
|
||||
EnableIcon( pszIconName, r, g, b );
|
||||
m_iFlags |= HUD_ACTIVE;
|
||||
}
|
||||
else
|
||||
{
|
||||
DisableIcon( pszIconName );
|
||||
}
|
||||
END_READ();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// add the icon to the icon list, and set it's drawing color
|
||||
void CHudStatusIcons::EnableIcon( char *pszIconName, byte red, byte green, byte blue )
|
||||
{
|
||||
// check to see if the sprite is in the current list
|
||||
for( int i = 0; i < MAX_ICONSPRITES; i++ )
|
||||
{
|
||||
if ( !stricmp( m_IconList[i].szSpriteName, pszIconName ) )
|
||||
break;
|
||||
}
|
||||
|
||||
if( i == MAX_ICONSPRITES )
|
||||
{
|
||||
// icon not in list, so find an empty slot to add to
|
||||
for( i = 0; i < MAX_ICONSPRITES; i++ )
|
||||
{
|
||||
if( !m_IconList[i].spr )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if we've run out of space in the list, overwrite the first icon
|
||||
if( i == MAX_ICONSPRITES )
|
||||
{
|
||||
i = 0;
|
||||
}
|
||||
|
||||
// Load the sprite and add it to the list
|
||||
// the sprite must be listed in hud.txt
|
||||
int spr_index = gHUD.GetSpriteIndex( pszIconName );
|
||||
m_IconList[i].spr = gHUD.GetSprite( spr_index );
|
||||
m_IconList[i].rc = gHUD.GetSpriteRect( spr_index );
|
||||
m_IconList[i].r = red;
|
||||
m_IconList[i].g = green;
|
||||
m_IconList[i].b = blue;
|
||||
strcpy( m_IconList[i].szSpriteName, pszIconName );
|
||||
|
||||
// HACKHACK: Play Timer sound when a grenade icon is played (in 0.8 seconds)
|
||||
if( strstr( m_IconList[i].szSpriteName, "grenade" ))
|
||||
{
|
||||
CL_PlaySound( "weapons/timer.wav", 1.0 );
|
||||
}
|
||||
}
|
||||
|
||||
void CHudStatusIcons::DisableIcon( char *pszIconName )
|
||||
{
|
||||
// find the sprite is in the current list
|
||||
for( int i = 0; i < MAX_ICONSPRITES; i++ )
|
||||
{
|
||||
if( !stricmp( m_IconList[i].szSpriteName, pszIconName ) )
|
||||
{
|
||||
// clear the item from the list
|
||||
memset( &m_IconList[i], 0, sizeof icon_sprite_t );
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
//=======================================================================
|
||||
// Copyright XashXT Group 2008 ©
|
||||
// hud_iface.h - client exported funcs
|
||||
//=======================================================================
|
||||
|
||||
#ifndef HUD_IFACE_H
|
||||
#define HUD_IFACE_H
|
||||
|
||||
extern cl_enginefuncs_t g_engfuncs;
|
||||
|
||||
#include "enginecallback.h"
|
||||
|
||||
extern int HUD_VidInit( void );
|
||||
extern void HUD_Init( void );
|
||||
extern int HUD_Redraw( float flTime, int intermission );
|
||||
extern int HUD_UpdateClientData( ref_params_t *parms, float flTime );
|
||||
extern void HUD_Reset( void );
|
||||
extern void HUD_Frame( double time );
|
||||
extern void HUD_Shutdown( void );
|
||||
extern void HUD_DrawNormalTriangles( void );
|
||||
extern void HUD_DrawTransparentTriangles( void );
|
||||
extern void HUD_CreateEntities( void );
|
||||
extern void HUD_StudioEvent( const dstudioevent_t *event, edict_t *entity );
|
||||
extern void V_CalcRefdef( ref_params_t *parms );
|
||||
|
||||
typedef struct rect_s
|
||||
{
|
||||
int left;
|
||||
int right;
|
||||
int top;
|
||||
int bottom;
|
||||
} wrect_t;
|
||||
|
||||
typedef HMODULE dllhandle_t;
|
||||
typedef struct dllfunction_s
|
||||
{
|
||||
const char *name;
|
||||
void **funcvariable;
|
||||
} dllfunction_t;
|
||||
|
||||
// cvar flags
|
||||
#define CVAR_ARCHIVE BIT(0) // set to cause it to be saved to vars.rc
|
||||
#define CVAR_USERINFO BIT(1) // added to userinfo when changed
|
||||
#define CVAR_SERVERINFO BIT(2) // added to serverinfo when changed
|
||||
|
||||
// macros to hook function calls into the HUD object
|
||||
#define HOOK_MESSAGE( x ) (*g_engfuncs.pfnHookUserMsg)( #x, __MsgFunc_##x );
|
||||
|
||||
#define DECLARE_MESSAGE( y, x ) int __MsgFunc_##x(const char *pszName, int iSize, void *pbuf) \
|
||||
{ \
|
||||
return gHUD.##y.MsgFunc_##x(pszName, iSize, pbuf ); \
|
||||
}
|
||||
|
||||
#define DECLARE_HUDMESSAGE( x ) int __MsgFunc_##x( const char *pszName, int iSize, void *pbuf ) \
|
||||
{ \
|
||||
return gHUD.MsgFunc_##x(pszName, iSize, pbuf ); \
|
||||
}
|
||||
|
||||
#define HOOK_COMMAND( x, y ) (*g_engfuncs.pfnAddCommand)( x, __CmdFunc_##y, "user-defined command" );
|
||||
#define DECLARE_COMMAND( y, x ) void __CmdFunc_##x( void ) \
|
||||
{ \
|
||||
gHUD.##y.UserCmd_##x( ); \
|
||||
}
|
||||
|
||||
inline void UnpackRGB( int &r, int &g, int &b, dword ulRGB )
|
||||
{
|
||||
r = (ulRGB & 0xFF0000) >>16;\
|
||||
g = (ulRGB & 0xFF00) >> 8;\
|
||||
b = ulRGB & 0xFF;\
|
||||
}
|
||||
|
||||
inline void ScaleColors( int &r, int &g, int &b, int a )
|
||||
{
|
||||
float x = (float)a / 255;
|
||||
r = (int)(r * x);
|
||||
g = (int)(g * x);
|
||||
b = (int)(b * x);
|
||||
}
|
||||
|
||||
inline int ConsoleStringLen( const char *string )
|
||||
{
|
||||
// console using fixed font size
|
||||
return strlen( string ) * SMALLCHAR_WIDTH;
|
||||
}
|
||||
|
||||
inline void GetConsoleStringSize( const char *string, int *width, int *height )
|
||||
{
|
||||
// console using fixed font size
|
||||
if( width ) *width = ConsoleStringLen( string );
|
||||
if( height ) *height = SMALLCHAR_HEIGHT;
|
||||
}
|
||||
|
||||
// simple huh ?
|
||||
inline int DrawConsoleString( int x, int y, const char *string )
|
||||
{
|
||||
DrawString( x, y, SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT, string );
|
||||
|
||||
return ConsoleStringLen( string );
|
||||
}
|
||||
|
||||
inline void ConsolePrint( const char *string )
|
||||
{
|
||||
ALERT( at_console, "%s", string );
|
||||
}
|
||||
|
||||
// returns the players name of entity no.
|
||||
inline void GetPlayerInfo( int ent_num, hud_player_info_t *pinfo )
|
||||
{
|
||||
GET_PLAYER_INFO( ent_num, pinfo );
|
||||
}
|
||||
|
||||
inline client_textmessage_t *TextMessageGet( const char *pName )
|
||||
{
|
||||
return GET_GAME_MESSAGE( pName );
|
||||
}
|
||||
|
||||
// message reading
|
||||
extern void BEGIN_READ( const char *pszName, int iSize, void *pBuf );
|
||||
extern int READ_CHAR( void );
|
||||
extern int READ_BYTE( void );
|
||||
extern int READ_SHORT( void );
|
||||
extern int READ_WORD( void );
|
||||
extern int READ_LONG( void );
|
||||
extern float READ_FLOAT( void );
|
||||
extern char* READ_STRING( void );
|
||||
extern float READ_COORD( void );
|
||||
extern float READ_ANGLE( void );
|
||||
extern float READ_ANGLE16( void );
|
||||
extern void END_READ( void );
|
||||
|
||||
// drawing stuff
|
||||
extern int SPR_Frames( HSPRITE hPic );
|
||||
extern int SPR_Height( HSPRITE hPic, int frame );
|
||||
extern int SPR_Width( HSPRITE hPic, int frame );
|
||||
extern void SPR_Set( HSPRITE hPic, int r, int g, int b );
|
||||
extern void SPR_Draw( int frame, int x, int y, const wrect_t *prc );
|
||||
extern void SPR_Draw( int frame, int x, int y, int width, int height );
|
||||
extern void SPR_DrawHoles( int frame, int x, int y, const wrect_t *prc );
|
||||
extern void SPR_DrawHoles( int frame, int x, int y, int width, int height );
|
||||
extern void SPR_DrawAdditive( int frame, int x, int y, const wrect_t *prc );
|
||||
extern void SetCrosshair( HSPRITE hspr, wrect_t rc, int r, int g, int b );
|
||||
extern void DrawCrosshair( void );
|
||||
extern void SetScreenFade( Vector fadeColor, float alpha, float duration, float holdTime, int fadeFlags );
|
||||
extern void DrawScreenFade( void );
|
||||
|
||||
// stdio stuff
|
||||
extern char *va( const char *format, ... );
|
||||
|
||||
// dlls stuff
|
||||
BOOL Sys_LoadLibrary( const char* dllname, dllhandle_t* handle, const dllfunction_t *fcts );
|
||||
void* Sys_GetProcAddress( dllhandle_t handle, const char* name );
|
||||
void Sys_UnloadLibrary( dllhandle_t* handle );
|
||||
|
||||
#endif//HUD_IFACE_H
|
|
@ -0,0 +1,172 @@
|
|||
/***
|
||||
*
|
||||
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
|
||||
*
|
||||
* This product contains software technology licensed from Id
|
||||
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Use, distribution, and modification of this source code and/or resulting
|
||||
* object code is restricted to non-commercial enhancements to products from
|
||||
* Valve LLC. All other use, distribution, or modification is prohibited
|
||||
* without written permission from Valve LLC.
|
||||
*
|
||||
****/
|
||||
//
|
||||
// menu.cpp
|
||||
//
|
||||
// generic menu handler
|
||||
//
|
||||
#include "extdll.h"
|
||||
#include "hud_iface.h"
|
||||
#include "hud.h"
|
||||
|
||||
#define MAX_MENU_STRING 512
|
||||
char g_szMenuString[MAX_MENU_STRING];
|
||||
char g_szPrelocalisedMenuString[MAX_MENU_STRING];
|
||||
|
||||
DECLARE_MESSAGE( m_Menu, ShowMenu );
|
||||
|
||||
int CHudMenu :: Init( void )
|
||||
{
|
||||
gHUD.AddHudElem( this );
|
||||
|
||||
HOOK_MESSAGE( ShowMenu );
|
||||
|
||||
InitHUDData();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void CHudMenu :: InitHUDData( void )
|
||||
{
|
||||
m_fMenuDisplayed = 0;
|
||||
m_bitsValidSlots = 0;
|
||||
Reset();
|
||||
}
|
||||
|
||||
void CHudMenu :: Reset( void )
|
||||
{
|
||||
g_szPrelocalisedMenuString[0] = 0;
|
||||
m_fWaitingForMore = FALSE;
|
||||
}
|
||||
|
||||
int CHudMenu :: VidInit( void )
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHudMenu :: Draw( float flTime )
|
||||
{
|
||||
// check for if menu is set to disappear
|
||||
if( m_flShutoffTime > 0 )
|
||||
{
|
||||
if( m_flShutoffTime <= gHUD.m_flTime )
|
||||
{
|
||||
// times up, shutoff
|
||||
m_fMenuDisplayed = 0;
|
||||
m_iFlags &= ~HUD_ACTIVE;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// don't draw the menu if the scoreboard is being shown
|
||||
if( gHUD.m_Scoreboard.m_iShowscoresHeld )
|
||||
return 1;
|
||||
|
||||
// draw the menu, along the left-hand side of the screen
|
||||
|
||||
// count the number of newlines
|
||||
int nlc = 0;
|
||||
for( int i = 0; i < MAX_MENU_STRING && g_szMenuString[i] != '\0'; i++ )
|
||||
{
|
||||
if( g_szMenuString[i] == '\n' )
|
||||
nlc++;
|
||||
}
|
||||
|
||||
// center it
|
||||
int y = (SCREEN_HEIGHT/2) - ((nlc/2)*12) - 40; // make sure it is above the say text
|
||||
int x = 20;
|
||||
|
||||
i = 0;
|
||||
while( i < MAX_MENU_STRING && g_szMenuString[i] != '\0' )
|
||||
{
|
||||
gHUD.DrawHudString( x, y, 320, g_szMenuString + i, 255, 255, 255 );
|
||||
y += 12;
|
||||
|
||||
while( i < MAX_MENU_STRING && g_szMenuString[i] != '\0' && g_szMenuString[i] != '\n' )
|
||||
i++;
|
||||
if( g_szMenuString[i] == '\n' )
|
||||
i++;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// selects an item from the menu
|
||||
void CHudMenu :: SelectMenuItem( int menu_item )
|
||||
{
|
||||
// if menu_item is in a valid slot, send a menuselect command to the server
|
||||
if( (menu_item > 0) && (m_bitsValidSlots & (1<<(menu_item - 1))) )
|
||||
{
|
||||
char szbuf[32];
|
||||
sprintf( szbuf, "menuselect %d\n", menu_item );
|
||||
CLIENT_COMMAND( szbuf );
|
||||
|
||||
// remove the menu
|
||||
m_fMenuDisplayed = 0;
|
||||
m_iFlags &= ~HUD_ACTIVE;
|
||||
}
|
||||
}
|
||||
|
||||
// Message handler for ShowMenu message
|
||||
// takes four values:
|
||||
// short: a bitfield of keys that are valid input
|
||||
// char : the duration, in seconds, the menu should stay up. -1 means is stays until something is chosen.
|
||||
// byte : a boolean, TRUE if there is more string yet to be received before displaying the menu, FALSE if it's the last string
|
||||
// string: menu string to display
|
||||
// if this message is never received, then scores will simply be the combined totals of the players.
|
||||
|
||||
int CHudMenu :: MsgFunc_ShowMenu( const char *pszName, int iSize, void *pbuf )
|
||||
{
|
||||
BEGIN_READ( pszName, iSize, pbuf );
|
||||
|
||||
m_bitsValidSlots = READ_SHORT();
|
||||
int DisplayTime = READ_CHAR();
|
||||
int NeedMore = READ_BYTE();
|
||||
|
||||
if( DisplayTime > 0 )
|
||||
m_flShutoffTime = DisplayTime + gHUD.m_flTime;
|
||||
else m_flShutoffTime = -1;
|
||||
|
||||
if( m_bitsValidSlots )
|
||||
{
|
||||
if( !m_fWaitingForMore ) // this is the start of a new menu
|
||||
{
|
||||
strncpy( g_szPrelocalisedMenuString, READ_STRING(), MAX_MENU_STRING );
|
||||
}
|
||||
else
|
||||
{
|
||||
// append to the current menu string
|
||||
strncat( g_szPrelocalisedMenuString, READ_STRING(), MAX_MENU_STRING - strlen(g_szPrelocalisedMenuString) );
|
||||
}
|
||||
g_szPrelocalisedMenuString[MAX_MENU_STRING-1] = 0; // ensure null termination (strncat/strncpy does not)
|
||||
|
||||
if( !NeedMore )
|
||||
{
|
||||
// we have the whole string, so we can localise it now
|
||||
strcpy( g_szMenuString, gHUD.m_TextMessage.BufferedLocaliseTextString( g_szPrelocalisedMenuString ) );
|
||||
}
|
||||
|
||||
m_fMenuDisplayed = 1;
|
||||
m_iFlags |= HUD_ACTIVE;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_fMenuDisplayed = 0; // no valid slots means that the menu should be turned off
|
||||
m_iFlags &= ~HUD_ACTIVE;
|
||||
}
|
||||
|
||||
m_fWaitingForMore = NeedMore;
|
||||
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,514 @@
|
|||
/***
|
||||
*
|
||||
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
|
||||
*
|
||||
* This product contains software technology licensed from Id
|
||||
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Use, distribution, and modification of this source code and/or resulting
|
||||
* object code is restricted to non-commercial enhancements to products from
|
||||
* Valve LLC. All other use, distribution, or modification is prohibited
|
||||
* without written permission from Valve LLC.
|
||||
*
|
||||
****/
|
||||
//
|
||||
// Message.cpp
|
||||
//
|
||||
// implementation of CHudMessage class
|
||||
//
|
||||
|
||||
#include "extdll.h"
|
||||
#include "hud_iface.h"
|
||||
#include "hud.h"
|
||||
|
||||
DECLARE_MESSAGE( m_Message, HudText )
|
||||
DECLARE_MESSAGE( m_Message, GameTitle )
|
||||
|
||||
// 1 Global client_textmessage_t for custom messages that aren't in the titles.txt
|
||||
client_textmessage_t g_pCustomMessage;
|
||||
char *g_pCustomName = "Custom";
|
||||
char g_pCustomText[1024];
|
||||
|
||||
int CHudMessage :: Init( void )
|
||||
{
|
||||
HOOK_MESSAGE( HudText );
|
||||
HOOK_MESSAGE( GameTitle );
|
||||
|
||||
gHUD.AddHudElem( this );
|
||||
Reset();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHudMessage :: VidInit( void )
|
||||
{
|
||||
HUD_Logo = gHUD.GetSpriteIndex( "logo" );
|
||||
return 1;
|
||||
}
|
||||
|
||||
void CHudMessage :: Reset( void )
|
||||
{
|
||||
memset( m_pMessages, 0, sizeof( m_pMessages[0] ) * maxHUDMessages );
|
||||
memset( m_startTime, 0, sizeof( m_startTime[0] ) * maxHUDMessages );
|
||||
|
||||
m_gameTitleTime = 0;
|
||||
m_pGameTitle = NULL;
|
||||
}
|
||||
|
||||
float CHudMessage :: FadeBlend( float fadein, float fadeout, float hold, float localTime )
|
||||
{
|
||||
float fadeTime = fadein + hold;
|
||||
float fadeBlend;
|
||||
|
||||
if( localTime < 0 )
|
||||
return 0;
|
||||
|
||||
if( localTime < fadein )
|
||||
{
|
||||
fadeBlend = 1 - ((fadein - localTime) / fadein);
|
||||
}
|
||||
else if( localTime > fadeTime )
|
||||
{
|
||||
if( fadeout > 0 )
|
||||
fadeBlend = 1 - ((localTime - fadeTime) / fadeout);
|
||||
else fadeBlend = 0;
|
||||
}
|
||||
else fadeBlend = 1;
|
||||
|
||||
return fadeBlend;
|
||||
}
|
||||
|
||||
int CHudMessage::XPosition( float x, int width, int totalWidth )
|
||||
{
|
||||
int xPos;
|
||||
|
||||
if( x == -1 )
|
||||
{
|
||||
xPos = (SCREEN_WIDTH - width) / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( x < 0 )
|
||||
xPos = (1.0 + x) * SCREEN_WIDTH - totalWidth; // Alight right
|
||||
else
|
||||
xPos = x * SCREEN_WIDTH;
|
||||
}
|
||||
|
||||
if( xPos + width > SCREEN_WIDTH )
|
||||
xPos = SCREEN_WIDTH - width;
|
||||
else if( xPos < 0 )
|
||||
xPos = 0;
|
||||
|
||||
return xPos;
|
||||
}
|
||||
|
||||
int CHudMessage::YPosition( float y, int height )
|
||||
{
|
||||
int yPos;
|
||||
|
||||
if( y == -1 ) // Centered?
|
||||
yPos = (SCREEN_HEIGHT - height) * 0.5;
|
||||
else
|
||||
{
|
||||
// Alight bottom?
|
||||
if( y < 0 )
|
||||
yPos = (1.0 + y) * SCREEN_HEIGHT - height; // Alight bottom
|
||||
else // align top
|
||||
yPos = y * SCREEN_HEIGHT;
|
||||
}
|
||||
|
||||
if( yPos + height > SCREEN_HEIGHT )
|
||||
yPos = SCREEN_HEIGHT - height;
|
||||
else if( yPos < 0 )
|
||||
yPos = 0;
|
||||
|
||||
return yPos;
|
||||
}
|
||||
|
||||
void CHudMessage :: MessageScanNextChar( void )
|
||||
{
|
||||
int srcRed, srcGreen, srcBlue, destRed, destGreen, destBlue;
|
||||
int blend;
|
||||
|
||||
srcRed = m_parms.pMessage->r1;
|
||||
srcGreen = m_parms.pMessage->g1;
|
||||
srcBlue = m_parms.pMessage->b1;
|
||||
blend = 0; // Pure source
|
||||
|
||||
switch( m_parms.pMessage->effect )
|
||||
{
|
||||
case 0: // Fade-in / Fade-out
|
||||
case 1:
|
||||
destRed = destGreen = destBlue = 0;
|
||||
blend = m_parms.fadeBlend;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
m_parms.charTime += m_parms.pMessage->fadein;
|
||||
if( m_parms.charTime > m_parms.time )
|
||||
{
|
||||
srcRed = srcGreen = srcBlue = 0;
|
||||
blend = 0; // pure source
|
||||
}
|
||||
else
|
||||
{
|
||||
float deltaTime = m_parms.time - m_parms.charTime;
|
||||
|
||||
destRed = destGreen = destBlue = 0;
|
||||
if( m_parms.time > m_parms.fadeTime )
|
||||
{
|
||||
blend = m_parms.fadeBlend;
|
||||
}
|
||||
else if( deltaTime > m_parms.pMessage->fxtime )
|
||||
blend = 0; // pure dest
|
||||
else
|
||||
{
|
||||
destRed = m_parms.pMessage->r2;
|
||||
destGreen = m_parms.pMessage->g2;
|
||||
destBlue = m_parms.pMessage->b2;
|
||||
blend = 255 - (deltaTime * (1.0 / m_parms.pMessage->fxtime) * 255.0 + 0.5);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if( blend > 255 )
|
||||
blend = 255;
|
||||
else if( blend < 0 )
|
||||
blend = 0;
|
||||
|
||||
m_parms.r = ((srcRed * (255-blend)) + (destRed * blend)) >> 8;
|
||||
m_parms.g = ((srcGreen * (255-blend)) + (destGreen * blend)) >> 8;
|
||||
m_parms.b = ((srcBlue * (255-blend)) + (destBlue * blend)) >> 8;
|
||||
|
||||
if( m_parms.pMessage->effect == 1 && m_parms.charTime != 0 )
|
||||
{
|
||||
if( m_parms.x >= 0 && m_parms.y >= 0 && (m_parms.x + gHUD.charWidths[ m_parms.text ]) <= SCREEN_WIDTH )
|
||||
TextMessageDrawChar( m_parms.x, m_parms.y, m_parms.text, m_parms.pMessage->r2, m_parms.pMessage->g2, m_parms.pMessage->b2 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CHudMessage :: MessageScanStart( void )
|
||||
{
|
||||
switch( m_parms.pMessage->effect )
|
||||
{
|
||||
case 1: // Fade-in / out with flicker
|
||||
case 0:
|
||||
m_parms.fadeTime = m_parms.pMessage->fadein + m_parms.pMessage->holdtime;
|
||||
|
||||
if( m_parms.time < m_parms.pMessage->fadein )
|
||||
{
|
||||
m_parms.fadeBlend = ((m_parms.pMessage->fadein - m_parms.time) * (1.0/m_parms.pMessage->fadein) * 255);
|
||||
}
|
||||
else if( m_parms.time > m_parms.fadeTime )
|
||||
{
|
||||
if ( m_parms.pMessage->fadeout > 0 )
|
||||
m_parms.fadeBlend = (((m_parms.time - m_parms.fadeTime) / m_parms.pMessage->fadeout) * 255);
|
||||
else
|
||||
m_parms.fadeBlend = 255; // Pure dest (off)
|
||||
}
|
||||
else m_parms.fadeBlend = 0; // Pure source (on)
|
||||
m_parms.charTime = 0;
|
||||
|
||||
if( m_parms.pMessage->effect == 1 && (rand() % 100 ) < 10 )
|
||||
m_parms.charTime = 1;
|
||||
break;
|
||||
case 2:
|
||||
m_parms.fadeTime = (m_parms.pMessage->fadein * m_parms.length) + m_parms.pMessage->holdtime;
|
||||
|
||||
if( m_parms.time > m_parms.fadeTime && m_parms.pMessage->fadeout > 0 )
|
||||
m_parms.fadeBlend = (((m_parms.time - m_parms.fadeTime) / m_parms.pMessage->fadeout) * 255);
|
||||
else m_parms.fadeBlend = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CHudMessage :: MessageDrawScan( client_textmessage_t *pMessage, float time )
|
||||
{
|
||||
int i, j, length, width;
|
||||
const char *pText;
|
||||
unsigned char line[80];
|
||||
|
||||
pText = pMessage->pMessage;
|
||||
// Count lines
|
||||
m_parms.lines = 1;
|
||||
m_parms.time = time;
|
||||
m_parms.pMessage = pMessage;
|
||||
length = 0;
|
||||
width = 0;
|
||||
m_parms.totalWidth = 0;
|
||||
|
||||
while( *pText )
|
||||
{
|
||||
if ( *pText == '\n' )
|
||||
{
|
||||
m_parms.lines++;
|
||||
if ( width > m_parms.totalWidth )
|
||||
m_parms.totalWidth = width;
|
||||
width = 0;
|
||||
}
|
||||
else width += gHUD.charWidths[*pText];
|
||||
pText++;
|
||||
length++;
|
||||
}
|
||||
m_parms.length = length;
|
||||
m_parms.totalHeight = (m_parms.lines * gHUD.iCharHeight);
|
||||
|
||||
|
||||
m_parms.y = YPosition( pMessage->y, m_parms.totalHeight );
|
||||
pText = pMessage->pMessage;
|
||||
|
||||
m_parms.charTime = 0;
|
||||
|
||||
MessageScanStart();
|
||||
|
||||
for( i = 0; i < m_parms.lines; i++ )
|
||||
{
|
||||
m_parms.lineLength = 0;
|
||||
m_parms.width = 0;
|
||||
while( *pText && *pText != '\n' )
|
||||
{
|
||||
unsigned char c = *pText;
|
||||
line[m_parms.lineLength] = c;
|
||||
m_parms.width += gHUD.charWidths[c];
|
||||
m_parms.lineLength++;
|
||||
pText++;
|
||||
}
|
||||
pText++; // Skip LineFeed
|
||||
line[m_parms.lineLength] = 0;
|
||||
|
||||
m_parms.x = XPosition( pMessage->x, m_parms.width, m_parms.totalWidth );
|
||||
|
||||
for ( j = 0; j < m_parms.lineLength; j++ )
|
||||
{
|
||||
m_parms.text = line[j];
|
||||
int next = m_parms.x + gHUD.charWidths[ m_parms.text ];
|
||||
MessageScanNextChar();
|
||||
|
||||
if ( m_parms.x >= 0 && m_parms.y >= 0 && next <= SCREEN_WIDTH )
|
||||
TextMessageDrawChar( m_parms.x, m_parms.y, m_parms.text, m_parms.r, m_parms.g, m_parms.b );
|
||||
m_parms.x = next;
|
||||
}
|
||||
m_parms.y += gHUD.iCharHeight;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int CHudMessage :: Draw( float fTime )
|
||||
{
|
||||
int i, drawn;
|
||||
client_textmessage_t *pMessage;
|
||||
float endTime;
|
||||
|
||||
drawn = 0;
|
||||
|
||||
if( m_gameTitleTime > 0 )
|
||||
{
|
||||
float localTime = gHUD.m_flTime - m_gameTitleTime;
|
||||
float brightness;
|
||||
|
||||
// Maybe timer isn't set yet
|
||||
if( m_gameTitleTime > gHUD.m_flTime )
|
||||
m_gameTitleTime = gHUD.m_flTime;
|
||||
|
||||
if( localTime > (m_pGameTitle->fadein + m_pGameTitle->holdtime + m_pGameTitle->fadeout) )
|
||||
m_gameTitleTime = 0;
|
||||
else
|
||||
{
|
||||
brightness = FadeBlend( m_pGameTitle->fadein, m_pGameTitle->fadeout, m_pGameTitle->holdtime, localTime );
|
||||
|
||||
int fullWidth = gHUD.GetSpriteRect(HUD_Logo).right - gHUD.GetSpriteRect(HUD_Logo).left;
|
||||
int fullHeight = gHUD.GetSpriteRect(HUD_Logo).bottom - gHUD.GetSpriteRect(HUD_Logo).top;
|
||||
|
||||
int x = XPosition( m_pGameTitle->x, fullWidth, fullWidth );
|
||||
int y = YPosition( m_pGameTitle->y, fullHeight);
|
||||
|
||||
SPR_Set( gHUD.GetSprite(HUD_Logo), brightness * m_pGameTitle->r1, brightness * m_pGameTitle->g1, brightness * m_pGameTitle->b1 );
|
||||
SPR_DrawAdditive( 0, x, y, &gHUD.GetSpriteRect( HUD_Logo ));
|
||||
|
||||
drawn = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// fixup level transitions
|
||||
for( i = 0; i < maxHUDMessages; i++ )
|
||||
{
|
||||
// assume m_parms.time contains last time
|
||||
if( m_pMessages[i] )
|
||||
{
|
||||
pMessage = m_pMessages[i];
|
||||
if( m_startTime[i] > gHUD.m_flTime )
|
||||
{
|
||||
// Server takes 0.2 seconds to spawn, adjust for this
|
||||
m_startTime[i] = gHUD.m_flTime + m_parms.time - m_startTime[i] + 0.2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for( i = 0; i < maxHUDMessages; i++ )
|
||||
{
|
||||
if ( m_pMessages[i] )
|
||||
{
|
||||
pMessage = m_pMessages[i];
|
||||
|
||||
// This is when the message is over
|
||||
switch( pMessage->effect )
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
endTime = m_startTime[i] + pMessage->fadein + pMessage->fadeout + pMessage->holdtime;
|
||||
break;
|
||||
|
||||
// Fade in is per character in scanning messages
|
||||
case 2:
|
||||
endTime = m_startTime[i] + (pMessage->fadein * strlen( pMessage->pMessage )) + pMessage->fadeout + pMessage->holdtime;
|
||||
break;
|
||||
}
|
||||
|
||||
if( fTime <= endTime )
|
||||
{
|
||||
float messageTime = fTime - m_startTime[i];
|
||||
|
||||
// Draw the message
|
||||
// effect 0 is fade in/fade out
|
||||
// effect 1 is flickery credits
|
||||
// effect 2 is write out (training room)
|
||||
MessageDrawScan( pMessage, messageTime );
|
||||
|
||||
drawn++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The message is over
|
||||
m_pMessages[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remember the time -- to fix up level transitions
|
||||
m_parms.time = gHUD.m_flTime;
|
||||
|
||||
// Don't call until we get another message
|
||||
if( !drawn ) m_iFlags &= ~HUD_ACTIVE;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void CHudMessage :: MessageAdd( const char *pName, float time )
|
||||
{
|
||||
int i, j;
|
||||
client_textmessage_t *tempMessage;
|
||||
|
||||
for( i = 0; i < maxHUDMessages; i++ )
|
||||
{
|
||||
if( !m_pMessages[i] )
|
||||
{
|
||||
// Trim off a leading # if it's there
|
||||
if( pName[0] == '#' )
|
||||
tempMessage = TextMessageGet( pName+1 );
|
||||
else tempMessage = TextMessageGet( pName );
|
||||
|
||||
// If we couldnt find it in the titles.txt, just create it
|
||||
if( !tempMessage )
|
||||
{
|
||||
g_pCustomMessage.effect = 2;
|
||||
g_pCustomMessage.r1 = g_pCustomMessage.g1 = g_pCustomMessage.b1 = g_pCustomMessage.a1 = 100;
|
||||
g_pCustomMessage.r2 = 240;
|
||||
g_pCustomMessage.g2 = 110;
|
||||
g_pCustomMessage.b2 = 0;
|
||||
g_pCustomMessage.a2 = 0;
|
||||
g_pCustomMessage.x = -1; // Centered
|
||||
g_pCustomMessage.y = 0.7;
|
||||
g_pCustomMessage.fadein = 0.01;
|
||||
g_pCustomMessage.fadeout = 1.5;
|
||||
g_pCustomMessage.fxtime = 0.25;
|
||||
g_pCustomMessage.holdtime = 5;
|
||||
g_pCustomMessage.pName = g_pCustomName;
|
||||
strcpy( g_pCustomText, pName );
|
||||
g_pCustomMessage.pMessage = g_pCustomText;
|
||||
|
||||
tempMessage = &g_pCustomMessage;
|
||||
}
|
||||
|
||||
for( j = 0; j < maxHUDMessages; j++ )
|
||||
{
|
||||
if( m_pMessages[j] )
|
||||
{
|
||||
// is this message already in the list
|
||||
if( !strcmp( tempMessage->pMessage, m_pMessages[j]->pMessage ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// get rid of any other messages in same location (only one displays at a time)
|
||||
if( fabs( tempMessage->y - m_pMessages[j]->y ) < 0.0001 )
|
||||
{
|
||||
if ( fabs( tempMessage->x - m_pMessages[j]->x ) < 0.0001 )
|
||||
{
|
||||
m_pMessages[j] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
m_pMessages[i] = tempMessage;
|
||||
m_startTime[i] = time;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int CHudMessage::MsgFunc_HudText( const char *pszName, int iSize, void *pbuf )
|
||||
{
|
||||
BEGIN_READ( pszName, iSize, pbuf );
|
||||
|
||||
char *pString = READ_STRING();
|
||||
|
||||
MessageAdd( pString, gHUD.m_flTime );
|
||||
// Remember the time -- to fix up level transitions
|
||||
m_parms.time = gHUD.m_flTime;
|
||||
|
||||
// Turn on drawing
|
||||
if(!( m_iFlags & HUD_ACTIVE ))
|
||||
m_iFlags |= HUD_ACTIVE;
|
||||
END_READ();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHudMessage::MsgFunc_GameTitle( const char *pszName, int iSize, void *pbuf )
|
||||
{
|
||||
m_pGameTitle = TextMessageGet( "GAMETITLE" );
|
||||
|
||||
if( m_pGameTitle != NULL )
|
||||
{
|
||||
m_gameTitleTime = gHUD.m_flTime;
|
||||
|
||||
// Turn on drawing
|
||||
if(!( m_iFlags & HUD_ACTIVE ))
|
||||
m_iFlags |= HUD_ACTIVE;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void CHudMessage :: MessageAdd( client_textmessage_t *newMessage )
|
||||
{
|
||||
m_parms.time = gHUD.m_flTime;
|
||||
|
||||
// Turn on drawing
|
||||
if(!( m_iFlags & HUD_ACTIVE ))
|
||||
m_iFlags |= HUD_ACTIVE;
|
||||
|
||||
for( int i = 0; i < maxHUDMessages; i++ )
|
||||
{
|
||||
if( !m_pMessages[i] )
|
||||
{
|
||||
m_pMessages[i] = newMessage;
|
||||
m_startTime[i] = gHUD.m_flTime;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
/***
|
||||
*
|
||||
* Copyright (c) 1999, Valve LLC. All rights reserved.
|
||||
*
|
||||
* This product contains software technology licensed from Id
|
||||
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Use, distribution, and modification of this source code and/or resulting
|
||||
* object code is restricted to non-commercial enhancements to products from
|
||||
* Valve LLC. All other use, distribution, or modification is prohibited
|
||||
* without written permission from Valve LLC.
|
||||
*
|
||||
****/
|
||||
//
|
||||
//
|
||||
// for displaying a server-sent message of the day
|
||||
//
|
||||
|
||||
#include "extdll.h"
|
||||
#include "hud_iface.h"
|
||||
#include "hud.h"
|
||||
|
||||
DECLARE_MESSAGE( m_MOTD, MOTD );
|
||||
|
||||
int CHudMOTD :: MOTD_DISPLAY_TIME;
|
||||
|
||||
int CHudMOTD :: Init( void )
|
||||
{
|
||||
gHUD.AddHudElem( this );
|
||||
|
||||
HOOK_MESSAGE( MOTD );
|
||||
CVAR_REGISTER( "motd_display_time", "6", 0, "time to show message of the day" );
|
||||
m_iFlags &= ~HUD_ACTIVE; // start out inactive
|
||||
m_szMOTD[0] = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHudMOTD :: VidInit( void )
|
||||
{
|
||||
// Load sprites here
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void CHudMOTD :: Reset( void )
|
||||
{
|
||||
m_iFlags &= ~HUD_ACTIVE; // start out inactive
|
||||
m_szMOTD[0] = 0;
|
||||
m_iLines = 0;
|
||||
m_flActiveTill = 0;
|
||||
}
|
||||
|
||||
#define LINE_HEIGHT 13
|
||||
|
||||
int CHudMOTD :: Draw( float fTime )
|
||||
{
|
||||
// Draw MOTD line-by-line
|
||||
|
||||
if( m_flActiveTill < gHUD.m_flTime )
|
||||
{
|
||||
// finished with MOTD, disable it
|
||||
m_szMOTD[0] = 0;
|
||||
m_iLines = 0;
|
||||
m_iFlags &= ~HUD_ACTIVE;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// cap activetill time to the display time
|
||||
m_flActiveTill = min( gHUD.m_flTime + MOTD_DISPLAY_TIME, m_flActiveTill );
|
||||
|
||||
// find the top of where the MOTD should be drawn, so the whole thing is centered in the screen
|
||||
int ypos = max(((SCREEN_HEIGHT - (m_iLines * LINE_HEIGHT)) / 2) - 40, 30 ); // shift it up slightly
|
||||
char *ch = m_szMOTD;
|
||||
while( *ch )
|
||||
{
|
||||
int line_length = 0; // count the length of the current line
|
||||
for( char *next_line = ch; *next_line != '\n' && *next_line != 0; next_line++ )
|
||||
line_length += gHUD.charWidths[ *next_line ];
|
||||
char *top = next_line;
|
||||
if( *top == '\n' )
|
||||
*top = 0;
|
||||
else
|
||||
top = NULL;
|
||||
|
||||
// find where to start drawing the line
|
||||
int xpos = (SCREEN_WIDTH - line_length) / 2;
|
||||
|
||||
gHUD.DrawHudString( xpos, ypos, SCREEN_WIDTH, ch, 255, 180, 0 );
|
||||
|
||||
ypos += LINE_HEIGHT;
|
||||
|
||||
if( top ) *top = '\n'; // restore
|
||||
|
||||
ch = next_line;
|
||||
if( *ch == '\n' )
|
||||
ch++;
|
||||
|
||||
if ( ypos > ( SCREEN_HEIGHT - 20 ))
|
||||
break; // don't let it draw too low
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHudMOTD :: MsgFunc_MOTD( const char *pszName, int iSize, void *pbuf )
|
||||
{
|
||||
if( m_iFlags & HUD_ACTIVE )
|
||||
{
|
||||
Reset(); // clear the current MOTD in prep for this one
|
||||
}
|
||||
|
||||
BEGIN_READ( pszName, iSize, pbuf );
|
||||
|
||||
int is_finished = READ_BYTE();
|
||||
strcat( m_szMOTD, READ_STRING() );
|
||||
|
||||
if( is_finished )
|
||||
{
|
||||
m_iFlags |= HUD_ACTIVE;
|
||||
|
||||
MOTD_DISPLAY_TIME = CVAR_GET_FLOAT( "motd_display_time" );
|
||||
m_flActiveTill = gHUD.m_flTime + MOTD_DISPLAY_TIME;
|
||||
|
||||
for( char *sz = m_szMOTD; *sz != 0; sz++ ) // count the number of lines in the MOTD
|
||||
{
|
||||
if( *sz == '\n' )
|
||||
m_iLines++;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,426 @@
|
|||
/***
|
||||
*
|
||||
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
|
||||
*
|
||||
* This product contains software technology licensed from Id
|
||||
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Use, distribution, and modification of this source code and/or resulting
|
||||
* object code is restricted to non-commercial enhancements to products from
|
||||
* Valve LLC. All other use, distribution, or modification is prohibited
|
||||
* without written permission from Valve LLC.
|
||||
*
|
||||
****/
|
||||
//
|
||||
// hud_msg.cpp
|
||||
//
|
||||
#include "extdll.h"
|
||||
#include "hud_iface.h"
|
||||
#include "hud.h"
|
||||
|
||||
// CHud message handlers
|
||||
DECLARE_HUDMESSAGE( HUDColor );
|
||||
DECLARE_HUDMESSAGE( SetFog );
|
||||
DECLARE_HUDMESSAGE( SetSky );
|
||||
DECLARE_HUDMESSAGE( RainData );
|
||||
DECLARE_HUDMESSAGE( SetBody );
|
||||
DECLARE_HUDMESSAGE( SetSkin );
|
||||
DECLARE_HUDMESSAGE( ResetHUD );
|
||||
DECLARE_HUDMESSAGE( InitHUD );
|
||||
DECLARE_HUDMESSAGE( ViewMode );
|
||||
DECLARE_HUDMESSAGE( Particle );
|
||||
DECLARE_HUDMESSAGE( SetFOV );
|
||||
DECLARE_HUDMESSAGE( Concuss );
|
||||
DECLARE_HUDMESSAGE( GameMode );
|
||||
DECLARE_HUDMESSAGE( CamData );
|
||||
DECLARE_HUDMESSAGE( AddMirror );
|
||||
DECLARE_HUDMESSAGE( AddScreen );
|
||||
DECLARE_HUDMESSAGE( AddPortal );
|
||||
DECLARE_HUDMESSAGE( ServerName );
|
||||
DECLARE_HUDMESSAGE( ScreenShake );
|
||||
|
||||
int CHud :: InitMessages( void )
|
||||
{
|
||||
HOOK_MESSAGE( ResetHUD );
|
||||
HOOK_MESSAGE( GameMode );
|
||||
HOOK_MESSAGE( ServerName );
|
||||
HOOK_MESSAGE( InitHUD );
|
||||
HOOK_MESSAGE( ViewMode );
|
||||
HOOK_MESSAGE( SetFOV );
|
||||
HOOK_MESSAGE( Concuss );
|
||||
HOOK_MESSAGE( HUDColor );
|
||||
HOOK_MESSAGE( Particle );
|
||||
HOOK_MESSAGE( SetFog );
|
||||
HOOK_MESSAGE( SetSky );
|
||||
HOOK_MESSAGE( CamData );
|
||||
HOOK_MESSAGE( RainData );
|
||||
HOOK_MESSAGE( SetBody );
|
||||
HOOK_MESSAGE( SetSkin );
|
||||
HOOK_MESSAGE( AddMirror);
|
||||
HOOK_MESSAGE( AddScreen );
|
||||
HOOK_MESSAGE( AddPortal );
|
||||
|
||||
viewEntityIndex = 0; // trigger_viewset stuff
|
||||
viewFlags = 0;
|
||||
m_iFOV = 0;
|
||||
m_iHUDColor = RGB_YELLOWISH; // 255,160,0
|
||||
|
||||
CVAR_REGISTER( "zoom_sensitivity_ratio", "1.2", 0, "mouse sensitivity when zooming" );
|
||||
CVAR_REGISTER( "default_fov", "90", 0, "default client fov" );
|
||||
CVAR_REGISTER( "hud_draw", "1", CVAR_ARCHIVE, "hud drawing modes" );
|
||||
|
||||
// clear any old HUD list
|
||||
if( m_pHudList )
|
||||
{
|
||||
HUDLIST *pList;
|
||||
while( m_pHudList )
|
||||
{
|
||||
pList = m_pHudList;
|
||||
m_pHudList = m_pHudList->pNext;
|
||||
FREE( pList );
|
||||
}
|
||||
m_pHudList = NULL;
|
||||
}
|
||||
|
||||
m_flTime = 1.0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHud :: MsgFunc_ResetHUD(const char *pszName, int iSize, void *pbuf )
|
||||
{
|
||||
// clear all hud data
|
||||
HUDLIST *pList = m_pHudList;
|
||||
|
||||
while( pList )
|
||||
{
|
||||
if( pList->p ) pList->p->Reset();
|
||||
pList = pList->pNext;
|
||||
}
|
||||
|
||||
// reset sensitivity
|
||||
m_flMouseSensitivity = 0;
|
||||
|
||||
// reset concussion effect
|
||||
m_iConcussionEffect = 0;
|
||||
|
||||
// reset fog
|
||||
m_fStartDist = 0;
|
||||
m_fEndDist = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHud :: MsgFunc_ViewMode( const char *pszName, int iSize, void *pbuf )
|
||||
{
|
||||
// CAM_ToFirstPerson();
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHud :: MsgFunc_InitHUD( const char *pszName, int iSize, void *pbuf )
|
||||
{
|
||||
m_fStartDist = 0;
|
||||
m_fEndDist = 0;
|
||||
m_iSkyMode = SKY_OFF;
|
||||
|
||||
// prepare all hud data
|
||||
HUDLIST *pList = m_pHudList;
|
||||
|
||||
while (pList)
|
||||
{
|
||||
if ( pList->p ) pList->p->InitHUDData();
|
||||
pList = pList->pNext;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHud::MsgFunc_SetFOV( const char *pszName, int iSize, void *pbuf )
|
||||
{
|
||||
BEGIN_READ( pszName, iSize, pbuf );
|
||||
|
||||
int newfov = READ_BYTE();
|
||||
int def_fov = CVAR_GET_FLOAT( "default_fov" );
|
||||
|
||||
if( newfov == 0 )
|
||||
{
|
||||
m_iFOV = def_fov;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_iFOV = newfov;
|
||||
}
|
||||
|
||||
if( m_iFOV == def_fov )
|
||||
{
|
||||
m_flMouseSensitivity = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// set a new sensitivity that is proportional to the change from the FOV default
|
||||
m_flMouseSensitivity = CVAR_GET_FLOAT( "sensitivity" ) * ( (float)newfov / (float)def_fov );
|
||||
m_flMouseSensitivity *= CVAR_GET_FLOAT( "zoom_sensitivity_ratio" ); // apply zoom factor
|
||||
}
|
||||
END_READ();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int CHud::MsgFunc_HUDColor(const char *pszName, int iSize, void *pbuf)
|
||||
{
|
||||
BEGIN_READ( pszName, iSize, pbuf );
|
||||
|
||||
m_iHUDColor = READ_LONG();
|
||||
|
||||
END_READ();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHud :: MsgFunc_SetFog( const char *pszName, int iSize, void *pbuf )
|
||||
{
|
||||
BEGIN_READ( pszName, iSize, pbuf );
|
||||
|
||||
m_FogColor.x = (float)(READ_BYTE() / 255.0f);
|
||||
m_FogColor.y = (float)(READ_BYTE() / 255.0f);
|
||||
m_FogColor.z = (float)(READ_BYTE() / 255.0f);
|
||||
|
||||
m_fStartDist = READ_SHORT();
|
||||
m_fEndDist = READ_SHORT();
|
||||
|
||||
END_READ();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHud :: MsgFunc_SetSky( const char *pszName, int iSize, void *pbuf )
|
||||
{
|
||||
BEGIN_READ( pszName, iSize, pbuf );
|
||||
|
||||
m_iSkyMode = READ_BYTE();
|
||||
m_vecSkyPos[0] = READ_COORD();
|
||||
m_vecSkyPos[1] = READ_COORD();
|
||||
m_vecSkyPos[2] = READ_COORD();
|
||||
|
||||
END_READ();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHud :: MsgFunc_GameMode( const char *pszName, int iSize, void *pbuf )
|
||||
{
|
||||
BEGIN_READ( pszName, iSize, pbuf );
|
||||
|
||||
m_Teamplay = READ_BYTE();
|
||||
|
||||
END_READ();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int CHud :: MsgFunc_Damage( const char *pszName, int iSize, void *pbuf )
|
||||
{
|
||||
int armor, blood;
|
||||
int i;
|
||||
float count;
|
||||
|
||||
BEGIN_READ( pszName, iSize, pbuf );
|
||||
armor = READ_BYTE();
|
||||
blood = READ_BYTE();
|
||||
|
||||
float from[3];
|
||||
for( i = 0; i < 3; i++ )
|
||||
from[i] = READ_COORD();
|
||||
|
||||
count = (blood * 0.5) + (armor * 0.5);
|
||||
if( count < 10 ) count = 10;
|
||||
|
||||
END_READ();
|
||||
|
||||
// TODO: kick viewangles, show damage visually
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHud :: MsgFunc_Concuss( const char *pszName, int iSize, void *pbuf )
|
||||
{
|
||||
BEGIN_READ( pszName, iSize, pbuf );
|
||||
|
||||
m_iConcussionEffect = READ_BYTE();
|
||||
if( m_iConcussionEffect )
|
||||
m_StatusIcons.EnableIcon( "dmg_concuss", 255, 160, 0 );
|
||||
else m_StatusIcons.DisableIcon( "dmg_concuss" );
|
||||
|
||||
END_READ();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHud :: MsgFunc_CamData( const char *pszName, int iSize, void *pbuf )
|
||||
{
|
||||
BEGIN_READ( pszName, iSize, pbuf );
|
||||
|
||||
gHUD.viewEntityIndex = READ_SHORT();
|
||||
gHUD.viewFlags = READ_SHORT();
|
||||
|
||||
if( gHUD.viewFlags )
|
||||
m_iCameraMode = 1;
|
||||
else m_iCameraMode = m_iLastCameraMode;
|
||||
|
||||
END_READ();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHud :: MsgFunc_RainData( const char *pszName, int iSize, void *pbuf )
|
||||
{
|
||||
BEGIN_READ( pszName, iSize, pbuf );
|
||||
|
||||
Rain.dripsPerSecond = READ_SHORT();
|
||||
Rain.distFromPlayer = READ_COORD();
|
||||
Rain.windX = READ_COORD();
|
||||
Rain.windY = READ_COORD();
|
||||
Rain.randX = READ_COORD();
|
||||
Rain.randY = READ_COORD();
|
||||
Rain.weatherMode = READ_SHORT();
|
||||
Rain.globalHeight= READ_COORD(); // FIXME: calc on client side ?
|
||||
|
||||
END_READ();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHud :: MsgFunc_SetBody( const char *pszName, int iSize, void *pbuf )
|
||||
{
|
||||
BEGIN_READ( pszName, iSize, pbuf );
|
||||
|
||||
edict_t *viewmodel = GetViewModel();
|
||||
int body = READ_BYTE();
|
||||
|
||||
if( viewmodel )
|
||||
viewmodel->v.body = body;
|
||||
|
||||
END_READ();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHud :: MsgFunc_SetSkin( const char *pszName, int iSize, void *pbuf )
|
||||
{
|
||||
BEGIN_READ( pszName, iSize, pbuf );
|
||||
|
||||
edict_t *viewmodel = GetViewModel();
|
||||
int skin = READ_BYTE();
|
||||
|
||||
if( viewmodel )
|
||||
viewmodel->v.skin = skin;
|
||||
|
||||
END_READ();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHud :: MsgFunc_AddScreen( const char *pszName, int iSize, void *pbuf )
|
||||
{
|
||||
BEGIN_READ( pszName, iSize, pbuf );
|
||||
|
||||
// AddScreenBrushEntity( READ_BYTE() );
|
||||
|
||||
END_READ();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHud :: MsgFunc_AddMirror( const char *pszName, int iSize, void *pbuf )
|
||||
{
|
||||
BEGIN_READ( pszName, iSize, pbuf );
|
||||
|
||||
// AddMirrorBrushEntity( READ_BYTE() );
|
||||
|
||||
END_READ();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHud :: MsgFunc_AddPortal( const char *pszName, int iSize, void *pbuf )
|
||||
{
|
||||
BEGIN_READ( pszName, iSize, pbuf );
|
||||
|
||||
// AddPortalBrushEntity( READ_BYTE() );
|
||||
|
||||
END_READ();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHud :: MsgFunc_Particle( const char *pszName, int iSize, void *pbuf )
|
||||
{
|
||||
BEGIN_READ( pszName, iSize, pbuf );
|
||||
|
||||
int idx = READ_BYTE();
|
||||
char *sz = READ_STRING();
|
||||
// CreateAurora( idx, sz );
|
||||
|
||||
END_READ();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHud::MsgFunc_ServerName( const char *pszName, int iSize, void *pbuf )
|
||||
{
|
||||
char m_szServerName[32];
|
||||
|
||||
BEGIN_READ( pszName, iSize, pbuf );
|
||||
strncpy( m_szServerName, READ_STRING(), 32 );
|
||||
END_READ();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHud::MsgFunc_ScreenShake( const char *pszName, int iSize, void *pbuf )
|
||||
{
|
||||
BEGIN_READ( pszName, iSize, pbuf );
|
||||
|
||||
ShakeCommand_t eCommand = (ShakeCommand_t)READ_BYTE();
|
||||
float amplitude = READ_FLOAT();
|
||||
float frequency = READ_FLOAT();
|
||||
float duration = READ_FLOAT();
|
||||
|
||||
if( eCommand == SHAKE_STOP )
|
||||
{
|
||||
m_Shake.amplitude = 0;
|
||||
m_Shake.frequency = 0;
|
||||
m_Shake.duration = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(( eCommand == SHAKE_START) || ( eCommand == SHAKE_FREQUENCY ))
|
||||
{
|
||||
m_Shake.frequency = frequency;
|
||||
}
|
||||
|
||||
if(( eCommand == SHAKE_START) || ( eCommand == SHAKE_AMPLITUDE ))
|
||||
{
|
||||
// don't overwrite larger existing shake unless we are told to.
|
||||
if(( amplitude > m_Shake.amplitude ) || ( eCommand == SHAKE_AMPLITUDE ))
|
||||
{
|
||||
m_Shake.amplitude = amplitude;
|
||||
}
|
||||
}
|
||||
|
||||
// only reset the timer for a new shake.
|
||||
if( eCommand == SHAKE_START )
|
||||
{
|
||||
m_Shake.duration = duration;
|
||||
m_Shake.nextShake = 0;
|
||||
m_Shake.time = m_flTime + duration;
|
||||
}
|
||||
}
|
||||
|
||||
END_READ();
|
||||
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,226 @@
|
|||
/***
|
||||
*
|
||||
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
|
||||
*
|
||||
* This product contains software technology licensed from Id
|
||||
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Use, distribution, and modification of this source code and/or resulting
|
||||
* object code is restricted to non-commercial enhancements to products from
|
||||
* Valve LLC. All other use, distribution, or modification is prohibited
|
||||
* without written permission from Valve LLC.
|
||||
*
|
||||
****/
|
||||
//
|
||||
// saytext.cpp
|
||||
//
|
||||
// implementation of CHudSayText class
|
||||
//
|
||||
|
||||
#include "extdll.h"
|
||||
#include "hud_iface.h"
|
||||
#include "hud.h"
|
||||
|
||||
#define MAX_LINES 5
|
||||
#define MAX_CHARS_PER_LINE 256 /* it can be less than this, depending on char size */
|
||||
|
||||
// allow 20 pixels on either side of the text
|
||||
#define MAX_LINE_WIDTH ( SCREEN_WIDTH - 40 )
|
||||
#define LINE_START 10
|
||||
static float SCROLL_SPEED = 5;
|
||||
|
||||
static char g_szLineBuffer[ MAX_LINES + 1 ][ MAX_CHARS_PER_LINE ];
|
||||
static float flScrollTime = 0; // the time at which the lines next scroll up
|
||||
|
||||
static int Y_START = 0;
|
||||
static int line_height = 0;
|
||||
|
||||
DECLARE_MESSAGE( m_SayText, SayText );
|
||||
|
||||
int CHudSayText :: Init( void )
|
||||
{
|
||||
gHUD.AddHudElem( this );
|
||||
|
||||
HOOK_MESSAGE( SayText );
|
||||
|
||||
InitHUDData();
|
||||
|
||||
CVAR_REGISTER( "hud_saytext_time", "5", 0, "time to show message text" );
|
||||
m_iFlags |= HUD_INTERMISSION; // is always drawn during an intermission
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void CHudSayText :: InitHUDData( void )
|
||||
{
|
||||
memset( g_szLineBuffer, 0, sizeof g_szLineBuffer );
|
||||
}
|
||||
|
||||
int CHudSayText :: VidInit( void )
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void ScrollTextUp( void )
|
||||
{
|
||||
ConsolePrint( g_szLineBuffer[0] ); // move the first line into the console buffer
|
||||
memmove( g_szLineBuffer[0], g_szLineBuffer[1], sizeof(g_szLineBuffer) - sizeof(g_szLineBuffer[0]) ); // overwrite the first line
|
||||
|
||||
if( g_szLineBuffer[0][0] == ' ' ) // also scroll up following lines
|
||||
{
|
||||
g_szLineBuffer[0][0] = 2;
|
||||
ScrollTextUp();
|
||||
}
|
||||
}
|
||||
|
||||
int CHudSayText :: Draw( float flTime )
|
||||
{
|
||||
int y = Y_START;
|
||||
|
||||
// make sure the scrolltime is within reasonable bounds, to guard against the clock being reset
|
||||
flScrollTime = min( flScrollTime, flTime + CVAR_GET_FLOAT( "hud_saytext_time" ));
|
||||
|
||||
// make sure the scrolltime is within reasonable bounds, to guard against the clock being reset
|
||||
flScrollTime = min( flScrollTime, flTime + CVAR_GET_FLOAT( "hud_saytext_time" ));
|
||||
|
||||
if( flScrollTime <= flTime )
|
||||
{
|
||||
if( *g_szLineBuffer[0] )
|
||||
{
|
||||
flScrollTime = flTime + CVAR_GET_FLOAT( "hud_saytext_time" );
|
||||
// push the console up
|
||||
ScrollTextUp();
|
||||
}
|
||||
else
|
||||
{
|
||||
// buffer is empty, just disable drawing of this section
|
||||
m_iFlags &= ~HUD_ACTIVE;
|
||||
}
|
||||
}
|
||||
|
||||
for ( int i = 0; i < MAX_LINES; i++ )
|
||||
{
|
||||
if ( *g_szLineBuffer[i] )
|
||||
DrawConsoleString( LINE_START, y, g_szLineBuffer[i] );
|
||||
|
||||
y += line_height;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHudSayText :: MsgFunc_SayText( const char *pszName, int iSize, void *pbuf )
|
||||
{
|
||||
BEGIN_READ( pszName, iSize, pbuf );
|
||||
|
||||
int client_index = READ_BYTE(); // the client who spoke the message
|
||||
SayTextPrint( READ_STRING(), iSize - 1, client_index );
|
||||
END_READ();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void CHudSayText :: SayTextPrint( const char *pszBuf, int iBufSize, int clientIndex )
|
||||
{
|
||||
// find an empty string slot
|
||||
for( int i = 0; i < MAX_LINES; i++ )
|
||||
{
|
||||
if( !*g_szLineBuffer[i] )
|
||||
break;
|
||||
}
|
||||
|
||||
if( i == MAX_LINES )
|
||||
{
|
||||
// force scroll buffer up
|
||||
ScrollTextUp();
|
||||
i = MAX_LINES - 1;
|
||||
}
|
||||
|
||||
strncpy( g_szLineBuffer[i], pszBuf, max(iBufSize -1, MAX_CHARS_PER_LINE-1) );
|
||||
|
||||
// make sure the text fits in one line
|
||||
EnsureTextFitsInOneLineAndWrapIfHaveTo( i );
|
||||
|
||||
// set scroll time
|
||||
if( i == 0 )
|
||||
{
|
||||
flScrollTime = gHUD.m_flTime + CVAR_GET_FLOAT( "hud_saytext_time" );
|
||||
}
|
||||
|
||||
m_iFlags |= HUD_ACTIVE;
|
||||
CL_PlaySound( "misc/talk.wav", 1.0f );
|
||||
|
||||
Y_START = SCREEN_HEIGHT - 60;
|
||||
Y_START -= (line_height * (MAX_LINES+1));
|
||||
|
||||
}
|
||||
|
||||
void CHudSayText :: EnsureTextFitsInOneLineAndWrapIfHaveTo( int line )
|
||||
{
|
||||
int line_width = 0;
|
||||
GetConsoleStringSize( g_szLineBuffer[line], &line_width, &line_height );
|
||||
|
||||
if((line_width + LINE_START) > MAX_LINE_WIDTH )
|
||||
{
|
||||
// string is too long to fit on line
|
||||
// scan the string until we find what word is too long, and wrap the end of the sentence after the word
|
||||
int length = LINE_START;
|
||||
int tmp_len = 0;
|
||||
char *last_break = NULL;
|
||||
for ( char *x = g_szLineBuffer[line]; *x != 0; x++ )
|
||||
{
|
||||
char buf[2];
|
||||
buf[1] = 0;
|
||||
|
||||
if( *x == ' ' && x != g_szLineBuffer[line] ) // store each line break, except for the very first character
|
||||
last_break = x;
|
||||
|
||||
buf[0] = *x; // get the length of the current character
|
||||
GetConsoleStringSize( buf, &tmp_len, &line_height );
|
||||
length += tmp_len;
|
||||
|
||||
if( length > MAX_LINE_WIDTH )
|
||||
{
|
||||
// needs to be broken up
|
||||
if( !last_break )
|
||||
last_break = x-1;
|
||||
x = last_break;
|
||||
|
||||
// find an empty string slot
|
||||
for( int j = 0; j < MAX_LINES; j++ )
|
||||
{
|
||||
if( !*g_szLineBuffer[j] )
|
||||
break;
|
||||
}
|
||||
if( j == MAX_LINES )
|
||||
{
|
||||
j = MAX_LINES - 1;
|
||||
}
|
||||
|
||||
// copy remaining string into next buffer, making sure it starts with a space character
|
||||
if( (char)*last_break == (char)' ' )
|
||||
{
|
||||
int linelen = strlen(g_szLineBuffer[j]);
|
||||
int remaininglen = strlen(last_break);
|
||||
|
||||
if( (linelen - remaininglen) <= MAX_CHARS_PER_LINE )
|
||||
strcat( g_szLineBuffer[j], last_break );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( (strlen(g_szLineBuffer[j]) - strlen(last_break) - 2) < MAX_CHARS_PER_LINE )
|
||||
{
|
||||
strcat( g_szLineBuffer[j], " " );
|
||||
strcat( g_szLineBuffer[j], last_break );
|
||||
}
|
||||
}
|
||||
|
||||
*last_break = 0; // cut off the last string
|
||||
|
||||
EnsureTextFitsInOneLineAndWrapIfHaveTo( j );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,505 @@
|
|||
/***
|
||||
*
|
||||
* Copyright (c) 1999, Valve LLC. All rights reserved.
|
||||
*
|
||||
* This product contains software technology licensed from Id
|
||||
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Use, distribution, and modification of this source code and/or resulting
|
||||
* object code is restricted to non-commercial enhancements to products from
|
||||
* Valve LLC. All other use, distribution, or modification is prohibited
|
||||
* without written permission from Valve LLC.
|
||||
*
|
||||
****/
|
||||
//
|
||||
// Scoreboard.cpp
|
||||
//
|
||||
// implementation of CHudScoreboard class
|
||||
//
|
||||
|
||||
#include "extdll.h"
|
||||
#include "hud_iface.h"
|
||||
#include "hud.h"
|
||||
|
||||
DECLARE_COMMAND( m_Scoreboard, ShowScores );
|
||||
DECLARE_COMMAND( m_Scoreboard, HideScores );
|
||||
|
||||
DECLARE_MESSAGE( m_Scoreboard, ScoreInfo );
|
||||
DECLARE_MESSAGE( m_Scoreboard, TeamInfo );
|
||||
DECLARE_MESSAGE( m_Scoreboard, TeamScore );
|
||||
|
||||
int CHudScoreboard :: Init( void )
|
||||
{
|
||||
gHUD.AddHudElem( this );
|
||||
|
||||
// Hook messages & commands here
|
||||
HOOK_COMMAND( "+showscores", ShowScores );
|
||||
HOOK_COMMAND( "-showscores", HideScores );
|
||||
|
||||
HOOK_MESSAGE( ScoreInfo );
|
||||
HOOK_MESSAGE( TeamScore );
|
||||
HOOK_MESSAGE( TeamInfo );
|
||||
|
||||
InitHUDData();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int CHudScoreboard :: VidInit( void )
|
||||
{
|
||||
// Load sprites here
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void CHudScoreboard :: InitHUDData( void )
|
||||
{
|
||||
memset( m_PlayerExtraInfo, 0, sizeof m_PlayerExtraInfo );
|
||||
m_iLastKilledBy = 0;
|
||||
m_fLastKillTime = 0;
|
||||
m_iPlayerNum = 0;
|
||||
m_iNumTeams = 0;
|
||||
memset( m_TeamInfo, 0, sizeof m_TeamInfo );
|
||||
|
||||
m_iFlags &= ~HUD_ACTIVE; // starts out inactive
|
||||
|
||||
m_iFlags |= HUD_INTERMISSION; // is always drawn during an intermission
|
||||
}
|
||||
|
||||
/* The scoreboard
|
||||
We have a minimum width of 1-320 - we could have the field widths scale with it?
|
||||
*/
|
||||
|
||||
// X positions
|
||||
// relative to the side of the scoreboard
|
||||
#define NAME_RANGE_MIN 20
|
||||
#define NAME_RANGE_MAX 145
|
||||
#define KILLS_RANGE_MIN 130
|
||||
#define KILLS_RANGE_MAX 170
|
||||
#define DIVIDER_POS 180
|
||||
#define DEATHS_RANGE_MIN 185
|
||||
#define DEATHS_RANGE_MAX 210
|
||||
#define PING_RANGE_MIN 245
|
||||
#define PING_RANGE_MAX 295
|
||||
|
||||
#define SCOREBOARD_WIDTH 320
|
||||
|
||||
// Y positions
|
||||
#define ROW_GAP 13
|
||||
#define ROW_RANGE_MIN 15
|
||||
#define ROW_RANGE_MAX ( SCREEN_HEIGHT - 50 )
|
||||
|
||||
int CHudScoreboard :: Draw( float fTime )
|
||||
{
|
||||
if( !m_iShowscoresHeld && gHUD.m_Health.m_iHealth > 0 && !gHUD.m_iIntermission )
|
||||
return 1;
|
||||
|
||||
GetAllPlayersInfo();
|
||||
|
||||
// just sort the list on the fly
|
||||
// list is sorted first by frags, then by deaths
|
||||
float list_slot = 0;
|
||||
int xpos_rel = (SCREEN_WIDTH - SCOREBOARD_WIDTH) / 2;
|
||||
|
||||
// print the heading line
|
||||
int ypos = ROW_RANGE_MIN + (list_slot * ROW_GAP);
|
||||
int xpos = NAME_RANGE_MIN + xpos_rel;
|
||||
|
||||
if ( !gHUD.m_Teamplay )
|
||||
gHUD.DrawHudString( xpos, ypos, NAME_RANGE_MAX + xpos_rel, "Player", 255, 140, 0 );
|
||||
else
|
||||
gHUD.DrawHudString( xpos, ypos, NAME_RANGE_MAX + xpos_rel, "Teams", 255, 140, 0 );
|
||||
|
||||
gHUD.DrawHudStringReverse( KILLS_RANGE_MAX + xpos_rel, ypos, 0, "frags", 255, 140, 0 );
|
||||
gHUD.DrawHudString( DIVIDER_POS + xpos_rel, ypos, SCREEN_WIDTH, "/", 255, 140, 0 );
|
||||
gHUD.DrawHudString( DEATHS_RANGE_MIN + xpos_rel + 5, ypos, SCREEN_WIDTH, "deaths", 255, 140, 0 );
|
||||
gHUD.DrawHudString( PING_RANGE_MAX + xpos_rel - 35, ypos, SCREEN_WIDTH, "ping", 255, 140, 0 );
|
||||
|
||||
list_slot += 1.2;
|
||||
ypos = ROW_RANGE_MIN + (list_slot * ROW_GAP);
|
||||
xpos = NAME_RANGE_MIN + xpos_rel;
|
||||
FillRGBA( xpos - 5, ypos, PING_RANGE_MAX - 5, 1, 255, 140, 0, 255); // draw the seperator line
|
||||
|
||||
list_slot += 0.8;
|
||||
|
||||
if ( !gHUD.m_Teamplay )
|
||||
{
|
||||
// it's not teamplay, so just draw a simple player list
|
||||
DrawPlayers( xpos_rel, list_slot );
|
||||
return 1;
|
||||
}
|
||||
|
||||
// clear out team scores
|
||||
for ( int i = 1; i <= m_iNumTeams; i++ )
|
||||
{
|
||||
if ( !m_TeamInfo[i].scores_overriden )
|
||||
m_TeamInfo[i].frags = m_TeamInfo[i].deaths = 0;
|
||||
m_TeamInfo[i].ping = m_TeamInfo[i].packetloss = 0;
|
||||
}
|
||||
|
||||
// recalc the team scores, then draw them
|
||||
for ( i = 1; i < MAX_PLAYERS; i++ )
|
||||
{
|
||||
if ( m_PlayerInfoList[i].name == NULL )
|
||||
continue; // empty player slot, skip
|
||||
|
||||
if ( m_PlayerExtraInfo[i].teamname[0] == 0 )
|
||||
continue; // skip over players who are not in a team
|
||||
|
||||
// find what team this player is in
|
||||
for ( int j = 1; j <= m_iNumTeams; j++ )
|
||||
{
|
||||
if ( !stricmp( m_PlayerExtraInfo[i].teamname, m_TeamInfo[j].name ) )
|
||||
break;
|
||||
}
|
||||
if ( j > m_iNumTeams ) // player is not in a team, skip to the next guy
|
||||
continue;
|
||||
|
||||
if ( !m_TeamInfo[j].scores_overriden )
|
||||
{
|
||||
m_TeamInfo[j].frags += m_PlayerExtraInfo[i].frags;
|
||||
m_TeamInfo[j].deaths += m_PlayerExtraInfo[i].deaths;
|
||||
}
|
||||
|
||||
m_TeamInfo[j].ping += m_PlayerInfoList[i].ping;
|
||||
m_TeamInfo[j].packetloss += m_PlayerInfoList[i].packetloss;
|
||||
|
||||
if ( m_PlayerInfoList[i].thisplayer )
|
||||
m_TeamInfo[j].ownteam = TRUE;
|
||||
else
|
||||
m_TeamInfo[j].ownteam = FALSE;
|
||||
}
|
||||
|
||||
// find team ping/packetloss averages
|
||||
for ( i = 1; i <= m_iNumTeams; i++ )
|
||||
{
|
||||
m_TeamInfo[i].already_drawn = FALSE;
|
||||
|
||||
if ( m_TeamInfo[i].players > 0 )
|
||||
{
|
||||
m_TeamInfo[i].ping /= m_TeamInfo[i].players; // use the average ping of all the players in the team as the teams ping
|
||||
m_TeamInfo[i].packetloss /= m_TeamInfo[i].players; // use the average ping of all the players in the team as the teams ping
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the teams
|
||||
while ( 1 )
|
||||
{
|
||||
int highest_frags = -99999; int lowest_deaths = 99999;
|
||||
int best_team = 0;
|
||||
|
||||
for ( i = 1; i <= m_iNumTeams; i++ )
|
||||
{
|
||||
if ( m_TeamInfo[i].players < 0 )
|
||||
continue;
|
||||
|
||||
if ( !m_TeamInfo[i].already_drawn && m_TeamInfo[i].frags >= highest_frags )
|
||||
{
|
||||
if ( m_TeamInfo[i].frags > highest_frags || m_TeamInfo[i].deaths < lowest_deaths )
|
||||
{
|
||||
best_team = i;
|
||||
lowest_deaths = m_TeamInfo[i].deaths;
|
||||
highest_frags = m_TeamInfo[i].frags;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// draw the best team on the scoreboard
|
||||
if ( !best_team )
|
||||
break;
|
||||
|
||||
// draw out the best team
|
||||
team_info_t *team_info = &m_TeamInfo[best_team];
|
||||
|
||||
ypos = ROW_RANGE_MIN + (list_slot * ROW_GAP);
|
||||
|
||||
// check we haven't drawn too far down
|
||||
if ( ypos > ROW_RANGE_MAX ) // don't draw to close to the lower border
|
||||
break;
|
||||
|
||||
xpos = NAME_RANGE_MIN + xpos_rel;
|
||||
int r = 255, g = 225, b = 55; // draw the stuff kinda yellowish
|
||||
|
||||
if ( team_info->ownteam ) // if it is their team, draw the background different color
|
||||
{
|
||||
// overlay the background in blue, then draw the score text over it
|
||||
FillRGBA( NAME_RANGE_MIN + xpos_rel - 5, ypos, PING_RANGE_MAX - 5, ROW_GAP, 0, 0, 255, 70 );
|
||||
}
|
||||
|
||||
// draw their name (left to right)
|
||||
gHUD.DrawHudString( xpos, ypos, NAME_RANGE_MAX + xpos_rel, team_info->name, r, g, b );
|
||||
|
||||
// draw kills (right to left)
|
||||
xpos = KILLS_RANGE_MAX + xpos_rel;
|
||||
gHUD.DrawHudNumberString( xpos, ypos, KILLS_RANGE_MIN + xpos_rel, team_info->frags, r, g, b );
|
||||
|
||||
// draw divider
|
||||
xpos = DIVIDER_POS + xpos_rel;
|
||||
gHUD.DrawHudString( xpos, ypos, xpos + 20, "/", r, g, b );
|
||||
|
||||
// draw deaths
|
||||
xpos = DEATHS_RANGE_MAX + xpos_rel;
|
||||
gHUD.DrawHudNumberString( xpos, ypos, DEATHS_RANGE_MIN + xpos_rel, team_info->deaths, r, g, b );
|
||||
|
||||
// draw ping
|
||||
// draw ping & packetloss
|
||||
static char buf[64];
|
||||
sprintf( buf, "%d", team_info->ping );
|
||||
xpos = ((PING_RANGE_MAX - PING_RANGE_MIN) / 2) + PING_RANGE_MIN + xpos_rel + 25;
|
||||
UnpackRGB( r, g, b, RGB_YELLOWISH );
|
||||
gHUD.DrawHudStringReverse( xpos, ypos, xpos - 50, buf, r, g, b );
|
||||
|
||||
team_info->already_drawn = TRUE; // set the already_drawn to be TRUE, so this team won't get drawn again
|
||||
list_slot++;
|
||||
|
||||
// draw all the players that belong to this team, indented slightly
|
||||
list_slot = DrawPlayers( xpos_rel, list_slot, 10, team_info->name );
|
||||
}
|
||||
|
||||
// draw all the players who are not in a team
|
||||
list_slot += 0.5;
|
||||
DrawPlayers( xpos_rel, list_slot, 0, "" );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// returns the ypos where it finishes drawing
|
||||
int CHudScoreboard :: DrawPlayers( int xpos_rel, float list_slot, int nameoffset, char *team )
|
||||
{
|
||||
// draw the players, in order, and restricted to team if set
|
||||
while ( 1 )
|
||||
{
|
||||
// Find the top ranking player
|
||||
int highest_frags = -99999; int lowest_deaths = 99999;
|
||||
int best_player = 0;
|
||||
|
||||
for ( int i = 1; i < MAX_PLAYERS; i++ )
|
||||
{
|
||||
if ( m_PlayerInfoList[i].name && m_PlayerExtraInfo[i].frags >= highest_frags )
|
||||
{
|
||||
if ( !(team && stricmp(m_PlayerExtraInfo[i].teamname, team)) ) // make sure it is the specified team
|
||||
{
|
||||
extra_player_info_t *pl_info = &m_PlayerExtraInfo[i];
|
||||
if ( pl_info->frags > highest_frags || pl_info->deaths < lowest_deaths )
|
||||
{
|
||||
best_player = i;
|
||||
lowest_deaths = pl_info->deaths;
|
||||
highest_frags = pl_info->frags;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( !best_player )
|
||||
break;
|
||||
|
||||
// draw out the best player
|
||||
hud_player_info_t *pl_info = &m_PlayerInfoList[best_player];
|
||||
|
||||
int ypos = ROW_RANGE_MIN + (list_slot * ROW_GAP);
|
||||
|
||||
// check we haven't drawn too far down
|
||||
if ( ypos > ROW_RANGE_MAX ) // don't draw to close to the lower border
|
||||
break;
|
||||
|
||||
int xpos = NAME_RANGE_MIN + xpos_rel;
|
||||
int r = 255, g = 255, b = 255;
|
||||
if ( best_player == m_iLastKilledBy && m_fLastKillTime && m_fLastKillTime > gHUD.m_flTime )
|
||||
{
|
||||
if ( pl_info->thisplayer )
|
||||
{ // green is the suicide color? i wish this could do grey...
|
||||
FillRGBA( NAME_RANGE_MIN + xpos_rel - 5, ypos, PING_RANGE_MAX - 5, ROW_GAP, 80, 155, 0, 70 );
|
||||
}
|
||||
else
|
||||
{ // Highlight the killers name - overlay the background in red, then draw the score text over it
|
||||
FillRGBA( NAME_RANGE_MIN + xpos_rel - 5, ypos, PING_RANGE_MAX - 5, ROW_GAP, 255, 0, 0, ((float)15 * (float)(m_fLastKillTime - gHUD.m_flTime)) );
|
||||
}
|
||||
}
|
||||
else if ( pl_info->thisplayer ) // if it is their name, draw it a different color
|
||||
{
|
||||
// overlay the background in blue, then draw the score text over it
|
||||
FillRGBA( NAME_RANGE_MIN + xpos_rel - 5, ypos, PING_RANGE_MAX - 5, ROW_GAP, 0, 0, 255, 70 );
|
||||
}
|
||||
|
||||
// draw their name (left to right)
|
||||
gHUD.DrawHudString( xpos + nameoffset, ypos, NAME_RANGE_MAX + xpos_rel, pl_info->name, r, g, b );
|
||||
|
||||
// draw kills (right to left)
|
||||
xpos = KILLS_RANGE_MAX + xpos_rel;
|
||||
gHUD.DrawHudNumberString( xpos, ypos, KILLS_RANGE_MIN + xpos_rel, m_PlayerExtraInfo[best_player].frags, r, g, b );
|
||||
|
||||
// draw divider
|
||||
xpos = DIVIDER_POS + xpos_rel;
|
||||
gHUD.DrawHudString( xpos, ypos, xpos + 20, "/", r, g, b );
|
||||
|
||||
// draw deaths
|
||||
xpos = DEATHS_RANGE_MAX + xpos_rel;
|
||||
gHUD.DrawHudNumberString( xpos, ypos, DEATHS_RANGE_MIN + xpos_rel, m_PlayerExtraInfo[best_player].deaths, r, g, b );
|
||||
|
||||
// draw ping & packetloss
|
||||
static char buf[64];
|
||||
sprintf( buf, "%d", m_PlayerInfoList[best_player].ping );
|
||||
xpos = ((PING_RANGE_MAX - PING_RANGE_MIN) / 2) + PING_RANGE_MIN + xpos_rel + 25;
|
||||
gHUD.DrawHudStringReverse( xpos, ypos, xpos - 50, buf, r, g, b );
|
||||
|
||||
pl_info->name = NULL; // set the name to be NULL, so this client won't get drawn again
|
||||
list_slot++;
|
||||
}
|
||||
return list_slot;
|
||||
}
|
||||
|
||||
void CHudScoreboard :: GetAllPlayersInfo( void )
|
||||
{
|
||||
for ( int i = 1; i < MAX_PLAYERS; i++ )
|
||||
{
|
||||
GetPlayerInfo( i, &m_PlayerInfoList[i] );
|
||||
|
||||
if ( m_PlayerInfoList[i].thisplayer )
|
||||
m_iPlayerNum = i; // !!!HACK: this should be initialized elsewhere... maybe gotten from the engine
|
||||
}
|
||||
}
|
||||
|
||||
int CHudScoreboard :: MsgFunc_ScoreInfo( const char *pszName, int iSize, void *pbuf )
|
||||
{
|
||||
m_iFlags |= HUD_ACTIVE;
|
||||
|
||||
BEGIN_READ( pszName, iSize, pbuf );
|
||||
short cl = READ_BYTE();
|
||||
short frags = READ_SHORT();
|
||||
short deaths = READ_SHORT();
|
||||
|
||||
if( cl > 0 && cl <= MAX_PLAYERS )
|
||||
{
|
||||
m_PlayerExtraInfo[cl].frags = frags;
|
||||
m_PlayerExtraInfo[cl].deaths = deaths;
|
||||
}
|
||||
END_READ();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Message handler for TeamInfo message
|
||||
// accepts two values:
|
||||
// byte: client number
|
||||
// string: client team name
|
||||
int CHudScoreboard :: MsgFunc_TeamInfo( const char *pszName, int iSize, void *pbuf )
|
||||
{
|
||||
BEGIN_READ( pszName, iSize, pbuf );
|
||||
short cl = READ_BYTE();
|
||||
|
||||
if( cl > 0 && cl <= MAX_PLAYERS )
|
||||
{
|
||||
// set the players team
|
||||
strncpy( m_PlayerExtraInfo[cl].teamname, READ_STRING(), MAX_TEAM_NAME );
|
||||
}
|
||||
|
||||
// rebuild the list of teams
|
||||
|
||||
// clear out player counts from teams
|
||||
for ( int i = 1; i <= m_iNumTeams; i++ )
|
||||
{
|
||||
m_TeamInfo[i].players = 0;
|
||||
}
|
||||
|
||||
// rebuild the team list
|
||||
GetAllPlayersInfo();
|
||||
m_iNumTeams = 0;
|
||||
for ( i = 1; i < MAX_PLAYERS; i++ )
|
||||
{
|
||||
if ( m_PlayerInfoList[i].name == NULL )
|
||||
continue;
|
||||
|
||||
if ( m_PlayerExtraInfo[i].teamname[0] == 0 )
|
||||
continue; // skip over players who are not in a team
|
||||
|
||||
// is this player in an existing team?
|
||||
for ( int j = 1; j <= m_iNumTeams; j++ )
|
||||
{
|
||||
if ( m_TeamInfo[j].name[0] == '\0' )
|
||||
break;
|
||||
|
||||
if ( !stricmp( m_PlayerExtraInfo[i].teamname, m_TeamInfo[j].name ) )
|
||||
break;
|
||||
}
|
||||
|
||||
if ( j > m_iNumTeams )
|
||||
{ // they aren't in a listed team, so make a new one
|
||||
// search through for an empty team slot
|
||||
for ( int j = 1; j <= m_iNumTeams; j++ )
|
||||
{
|
||||
if ( m_TeamInfo[j].name[0] == '\0' )
|
||||
break;
|
||||
}
|
||||
m_iNumTeams = max( j, m_iNumTeams );
|
||||
|
||||
strncpy( m_TeamInfo[j].name, m_PlayerExtraInfo[i].teamname, MAX_TEAM_NAME );
|
||||
m_TeamInfo[j].players = 0;
|
||||
}
|
||||
|
||||
m_TeamInfo[j].players++;
|
||||
}
|
||||
|
||||
// clear out any empty teams
|
||||
for ( i = 1; i <= m_iNumTeams; i++ )
|
||||
{
|
||||
if ( m_TeamInfo[i].players < 1 )
|
||||
memset( &m_TeamInfo[i], 0, sizeof(team_info_t) );
|
||||
}
|
||||
END_READ();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Message handler for TeamScore message
|
||||
// accepts three values:
|
||||
// string: team name
|
||||
// short: teams kills
|
||||
// short: teams deaths
|
||||
// if this message is never received, then scores will simply be the combined totals of the players.
|
||||
int CHudScoreboard :: MsgFunc_TeamScore( const char *pszName, int iSize, void *pbuf )
|
||||
{
|
||||
BEGIN_READ( pszName, iSize, pbuf );
|
||||
char *TeamName = READ_STRING();
|
||||
|
||||
// find the team matching the name
|
||||
for ( int i = 1; i <= m_iNumTeams; i++ )
|
||||
{
|
||||
if ( !stricmp( TeamName, m_TeamInfo[i].name ) )
|
||||
break;
|
||||
}
|
||||
if ( i > m_iNumTeams )
|
||||
return 1;
|
||||
|
||||
// use this new score data instead of combined player scores
|
||||
m_TeamInfo[i].scores_overriden = TRUE;
|
||||
m_TeamInfo[i].frags = READ_SHORT();
|
||||
m_TeamInfo[i].deaths = READ_SHORT();
|
||||
END_READ();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void CHudScoreboard :: DeathMsg( int killer, int victim )
|
||||
{
|
||||
// if we were the one killed, or the world killed us, set the scoreboard to indicate suicide
|
||||
if ( victim == m_iPlayerNum || killer == 0 )
|
||||
{
|
||||
m_iLastKilledBy = killer ? killer : m_iPlayerNum;
|
||||
m_fLastKillTime = gHUD.m_flTime + 10; // display who we were killed by for 10 seconds
|
||||
|
||||
if ( killer == m_iPlayerNum )
|
||||
m_iLastKilledBy = m_iPlayerNum;
|
||||
}
|
||||
}
|
||||
|
||||
void CHudScoreboard :: UserCmd_ShowScores( void )
|
||||
{
|
||||
m_iShowscoresHeld = TRUE;
|
||||
}
|
||||
|
||||
void CHudScoreboard :: UserCmd_HideScores( void )
|
||||
{
|
||||
m_iShowscoresHeld = FALSE;
|
||||
}
|
|
@ -0,0 +1,357 @@
|
|||
//=======================================================================
|
||||
// Copyright (C) XashXT Group 2006
|
||||
//=======================================================================
|
||||
|
||||
#include "extdll.h"
|
||||
#include "hud_iface.h"
|
||||
#include "hud.h"
|
||||
|
||||
/*
|
||||
====================
|
||||
FMOD definitions
|
||||
|
||||
====================
|
||||
*/
|
||||
enum FSOUND_OUTPUTTYPES
|
||||
{
|
||||
FSOUND_OUTPUT_NOSOUND, /* NoSound driver, all calls to this succeed but do nothing. */
|
||||
FSOUND_OUTPUT_WINMM, /* Windows Multimedia driver. */
|
||||
FSOUND_OUTPUT_DSOUND, /* DirectSound driver. You need this to get EAX or EAX2 support. */
|
||||
FSOUND_OUTPUT_A3D, /* A3D driver. You need this to get geometry support. */
|
||||
FSOUND_OUTPUT_OSS, /* Linux/Unix OSS (Open Sound System) driver, i.e. the kernel sound drivers. */
|
||||
FSOUND_OUTPUT_ESD, /* Linux/Unix ESD (Enlightment Sound Daemon) driver. */
|
||||
FSOUND_OUTPUT_ALSA /* Linux Alsa driver. */
|
||||
};
|
||||
|
||||
enum FMOD_ERRORS
|
||||
{
|
||||
FMOD_ERR_NONE, /* No errors */
|
||||
FMOD_ERR_BUSY, /* Cannot call this command after FSOUND_Init. Call FSOUND_Close first. */
|
||||
FMOD_ERR_UNINITIALIZED, /* This command failed because FSOUND_Init or FSOUND_SetOutput was not called */
|
||||
FMOD_ERR_INIT, /* Error initializing output device. */
|
||||
FMOD_ERR_ALLOCATED, /* Error initializing output device, but more specifically, the output device is already in use and cannot be reused. */
|
||||
FMOD_ERR_PLAY, /* Playing the sound failed. */
|
||||
FMOD_ERR_OUTPUT_FORMAT, /* Soundcard does not support the features needed for this soundsystem (16bit stereo output) */
|
||||
FMOD_ERR_COOPERATIVELEVEL, /* Error setting cooperative level for hardware. */
|
||||
FMOD_ERR_CREATEBUFFER, /* Error creating hardware sound buffer. */
|
||||
FMOD_ERR_FILE_NOTFOUND, /* File not found */
|
||||
FMOD_ERR_FILE_FORMAT, /* Unknown file format */
|
||||
FMOD_ERR_FILE_BAD, /* Error loading file */
|
||||
FMOD_ERR_MEMORY, /* Not enough memory or resources */
|
||||
FMOD_ERR_VERSION, /* The version number of this file format is not supported */
|
||||
FMOD_ERR_INVALID_PARAM, /* An invalid parameter was passed to this function */
|
||||
FMOD_ERR_NO_EAX, /* Tried to use an EAX command on a non EAX enabled channel or output. */
|
||||
FMOD_ERR_CHANNEL_ALLOC, /* Failed to allocate a new channel */
|
||||
FMOD_ERR_RECORD, /* Recording is not supported on this machine */
|
||||
FMOD_ERR_MEDIAPLAYER, /* Windows Media Player not installed so cannot play wma or use internet streaming. */
|
||||
FMOD_ERR_CDDEVICE /* An error occured trying to open the specified CD device */
|
||||
};
|
||||
|
||||
static char *FMOD_ErrorString( int errcode )
|
||||
{
|
||||
switch (errcode)
|
||||
{
|
||||
case FMOD_ERR_NONE: return "No errors";
|
||||
case FMOD_ERR_BUSY: return "Cannot call this command after FSOUND_Init. Call FSOUND_Close first.";
|
||||
case FMOD_ERR_UNINITIALIZED: return "This command failed because FSOUND_Init was not called";
|
||||
case FMOD_ERR_PLAY: return "Playing the sound failed.";
|
||||
case FMOD_ERR_INIT: return "Error initializing output device.";
|
||||
case FMOD_ERR_ALLOCATED: return "The output device is already in use and cannot be reused.";
|
||||
case FMOD_ERR_OUTPUT_FORMAT: return "Soundcard does not support the features needed for this soundsystem (16bit stereo output)";
|
||||
case FMOD_ERR_COOPERATIVELEVEL: return "Error setting cooperative level for hardware.";
|
||||
case FMOD_ERR_CREATEBUFFER: return "Error creating hardware sound buffer.";
|
||||
case FMOD_ERR_FILE_NOTFOUND: return "File not found";
|
||||
case FMOD_ERR_FILE_FORMAT: return "Unknown file format";
|
||||
case FMOD_ERR_FILE_BAD: return "Error loading file";
|
||||
case FMOD_ERR_MEMORY: return "Not enough memory ";
|
||||
case FMOD_ERR_VERSION: return "The version number of this file format is not supported";
|
||||
case FMOD_ERR_INVALID_PARAM: return "An invalid parameter was passed to this function";
|
||||
case FMOD_ERR_NO_EAX: return "Tried to use an EAX command on a non EAX enabled channel or output.";
|
||||
case FMOD_ERR_CHANNEL_ALLOC: return "Failed to allocate a new channel";
|
||||
case FMOD_ERR_RECORD: return "Recording not supported on this device";
|
||||
case FMOD_ERR_MEDIAPLAYER: return "Required Mediaplayer codec is not installed";
|
||||
default : return "Unknown error";
|
||||
};
|
||||
}
|
||||
|
||||
#define FSOUND_LOOP_OFF 0x00000001
|
||||
#define FSOUND_LOOP_NORMAL 0x00000002
|
||||
#define FSOUND_LOADMEMORY 0x00008000
|
||||
#define FSOUND_MPEGACCURATE 0x00020000
|
||||
|
||||
enum FSOUND_MIXERTYPES
|
||||
{
|
||||
FSOUND_MIXER_AUTODETECT, /* CE/PS2/GC Only - Non interpolating/low quality mixer. */
|
||||
FSOUND_MIXER_BLENDMODE, /* Removed / obsolete. */
|
||||
FSOUND_MIXER_MMXP5, /* Removed / obsolete. */
|
||||
FSOUND_MIXER_MMXP6, /* Removed / obsolete. */
|
||||
|
||||
FSOUND_MIXER_QUALITY_AUTODETECT,/* All platforms - Autodetect the fastest quality mixer based on your cpu. */
|
||||
FSOUND_MIXER_QUALITY_FPU, /* Win32/Linux only - Interpolating/volume ramping FPU mixer. */
|
||||
FSOUND_MIXER_QUALITY_MMXP5, /* Win32/Linux only - Interpolating/volume ramping P5 MMX mixer. */
|
||||
FSOUND_MIXER_QUALITY_MMXP6, /* Win32/Linux only - Interpolating/volume ramping ppro+ MMX mixer. */
|
||||
|
||||
FSOUND_MIXER_MONO, /* CE/PS2/GC only - MONO non interpolating/low quality mixer. For speed*/
|
||||
FSOUND_MIXER_QUALITY_MONO, /* CE/PS2/GC only - MONO Interpolating mixer. For speed */
|
||||
|
||||
FSOUND_MIXER_MAX
|
||||
};
|
||||
|
||||
/*
|
||||
====================
|
||||
Cl definitions
|
||||
|
||||
====================
|
||||
*/
|
||||
|
||||
static int (_stdcall *qfmod_geterror)();
|
||||
static float (_stdcall *qfmod_getversion)();
|
||||
static signed char (_stdcall *qfmod_setoutput)(int outputtype);
|
||||
static signed char (_stdcall *qfmod_setdriver)(int driver);
|
||||
static signed char (_stdcall *qfmod_setmixer)(int mixer);
|
||||
static signed char (_stdcall *qfmod_setbuffersize)(int len_ms);
|
||||
static signed char (_stdcall *qfmod_init)(int mixrate, int maxsoftwarechannels, unsigned int flags);
|
||||
static void (_stdcall *qfmod_close)();
|
||||
static int (_stdcall *qfmod_getmixer)();
|
||||
static signed char (_stdcall *qfmod_freesong)(void *mod);
|
||||
static signed char (_stdcall *qfmod_playsong)(void *mod);
|
||||
static signed char (_stdcall *qfmod_stopsong)(void *mod);
|
||||
static void (_stdcall *qfmod_stopallsongs)();
|
||||
static void* (_stdcall *qfmod_loadsong)(const char *name);
|
||||
static void* (_stdcall *qfmod_loadsongmemory)(void *data, int length);
|
||||
static signed char (_stdcall *qfmod_setmodpause)(void *data, signed char pause);
|
||||
static signed char (_stdcall *qfmod_getmodpause)(void *data);
|
||||
static void* (_stdcall *qfmod_loadstream)(const char *data, unsigned int mode, int memlength);
|
||||
static int (_stdcall *qfmod_playstream)(int channel, void *data);
|
||||
static signed char (_stdcall *qfmod_freestream)(void *data);
|
||||
static signed char (_stdcall *qfmod_getstreampause)(int channel);
|
||||
static int (_stdcall *qfmod_getstreampos)(void *data);
|
||||
static signed char (_stdcall *qfmod_setstreampause)(int channel, signed char paused);
|
||||
static signed char (_stdcall *qfmod_setstreampos)(void *data, unsigned int pos);
|
||||
static signed char (_stdcall *qfmod_stopstream)(void *data);
|
||||
static signed char (_stdcall *qfmod_setvolume)(int channel, int vol);
|
||||
|
||||
|
||||
static dllfunction_t fmodfuncs[] =
|
||||
{
|
||||
{"_FSOUND_GetError@0", (void **) &qfmod_geterror},
|
||||
{"_FSOUND_GetVersion@0", (void **) &qfmod_getversion},
|
||||
{"_FSOUND_SetOutput@4", (void **) &qfmod_setoutput},
|
||||
{"_FSOUND_SetDriver@4", (void **) &qfmod_setdriver},
|
||||
{"_FSOUND_SetMixer@4", (void **) &qfmod_setmixer},
|
||||
{"_FSOUND_SetBufferSize@4", (void **) &qfmod_setbuffersize},
|
||||
{"_FSOUND_Init@12", (void **) &qfmod_init},
|
||||
{"_FSOUND_Close@0", (void **) &qfmod_close},
|
||||
{"_FSOUND_GetMixer@0", (void **) &qfmod_getmixer},
|
||||
{"_FMUSIC_FreeSong@4", (void **) &qfmod_freesong},
|
||||
{"_FMUSIC_PlaySong@4", (void **) &qfmod_playsong},
|
||||
{"_FMUSIC_StopSong@4", (void **) &qfmod_stopsong},
|
||||
{"_FMUSIC_StopAllSongs@0", (void **) &qfmod_stopallsongs},
|
||||
{"_FMUSIC_LoadSong@4", (void **) &qfmod_loadsong},
|
||||
{"_FMUSIC_LoadSongMemory@8", (void **) &qfmod_loadsongmemory},
|
||||
{"_FMUSIC_SetPaused@8", (void **) &qfmod_setmodpause},
|
||||
{"_FMUSIC_GetPaused@4", (void **) &qfmod_getmodpause},
|
||||
{"_FSOUND_Stream_OpenFile@12",(void **) &qfmod_loadstream},
|
||||
{"_FSOUND_Stream_Play@8", (void **) &qfmod_playstream},
|
||||
{"_FSOUND_Stream_Close@4", (void **) &qfmod_freestream},
|
||||
{"_FSOUND_GetPaused@4", (void **) &qfmod_getstreampause},
|
||||
{"_FSOUND_Stream_GetPosition@4",(void **) &qfmod_getstreampos},
|
||||
{"_FSOUND_SetPaused@8", (void **) &qfmod_setstreampause},
|
||||
{"_FSOUND_Stream_SetPosition@8",(void **) &qfmod_setstreampos},
|
||||
{"_FSOUND_Stream_Stop@4", (void **) &qfmod_stopstream},
|
||||
{"_FSOUND_SetVolume@8", (void **) &qfmod_setvolume},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
DECLARE_MESSAGE(m_Sound, Fsound)
|
||||
#define STREAM 1
|
||||
#define TRACK 2
|
||||
|
||||
// Handle for fmod
|
||||
static dllhandle_t fmod_dll = NULL;
|
||||
void *fmod_data = NULL;
|
||||
static char songname[256];
|
||||
int last_state = 0;
|
||||
|
||||
int CheckFormat( BOOL skip_buffer )
|
||||
{
|
||||
int i;
|
||||
|
||||
// check buffer
|
||||
if( !fmod_data && !skip_buffer ) return false;
|
||||
|
||||
// detect of music type
|
||||
for( i = 0; songname[i]; i++ )
|
||||
{
|
||||
if( songname[i] == '.' )//found extension
|
||||
{
|
||||
if( !strncmp( &songname[i+1], "mp3", 3 )) return STREAM;
|
||||
else if( !strncmp(&songname[i+1], "wma", 3 )) return STREAM;
|
||||
else if( !strncmp(&songname[i+1], "ogg", 3 )) return STREAM;
|
||||
else if( !strncmp(&songname[i+1], "xm", 2 )) return TRACK;
|
||||
else if( !strncmp(&songname[i+1], "it", 2 )) return TRACK;
|
||||
else if( !strncmp(&songname[i+1], "s3m", 3 )) return TRACK;
|
||||
else return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int CHudSound :: Init( void )
|
||||
{
|
||||
m_iStatus = 0;
|
||||
m_iTime = 0;
|
||||
|
||||
HOOK_MESSAGE( Fsound );
|
||||
|
||||
m_iFlags |= HUD_ACTIVE;
|
||||
gHUD.AddHudElem( this );
|
||||
|
||||
// already loaded?
|
||||
if( fmod_dll ) return 1;
|
||||
|
||||
if( Sys_LoadLibrary( "fmod.dll", &fmod_dll, fmodfuncs ))
|
||||
{
|
||||
if( qfmod_getversion() > 3.4f && qfmod_getversion() < 3.3f )
|
||||
{
|
||||
Sys_UnloadLibrary( &fmod_dll ); //free library
|
||||
ALERT( at_warning, "Invalid fmod version: %g\n", qfmod_getversion());
|
||||
return 1;
|
||||
}
|
||||
|
||||
qfmod_setbuffersize( 100 );
|
||||
qfmod_setoutput( FSOUND_OUTPUT_DSOUND );
|
||||
qfmod_setdriver( 0 );
|
||||
if( !qfmod_init( 48000, 32, 0 ))
|
||||
{
|
||||
ALERT( at_error, "%s\n", FMOD_ErrorString( qfmod_geterror() ));
|
||||
return 1;
|
||||
}
|
||||
qfmod_setmixer( FSOUND_MIXER_AUTODETECT );
|
||||
}
|
||||
else ALERT( at_error, "fmod.dll not installed\n" );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHudSound :: VidInit( void )
|
||||
{
|
||||
// MsgFunc_Fsound( 0, 0, NULL );
|
||||
if( fmod_dll ) qfmod_stopallsongs(); // stop all songs
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHudSound :: MsgFunc_Fsound( const char *pszName, int iSize, void *pbuf )
|
||||
{
|
||||
if( !fmod_dll ) return 1;
|
||||
|
||||
BEGIN_READ( pszName, iSize, pbuf );
|
||||
|
||||
strcpy( songname, READ_STRING( )); // songname
|
||||
m_iTime = READ_SHORT(); // song position
|
||||
m_iStatus = READ_BYTE();
|
||||
|
||||
if( m_iStatus & 1 ) PlayStream( songname );
|
||||
else if( fmod_data )
|
||||
{
|
||||
if( CheckFormat( FALSE ) == TRACK ) qfmod_freesong( fmod_data );
|
||||
else if( CheckFormat( FALSE ) == STREAM ) qfmod_freestream( fmod_data );
|
||||
memset( fmod_data, 0, sizeof( fmod_data ));
|
||||
memset( (char*)songname, 0, sizeof( songname ));
|
||||
m_iTime = 0;
|
||||
m_iStatus = 0;
|
||||
}
|
||||
END_READ();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHudSound :: PlayStream( const char* name )
|
||||
{
|
||||
int filesize;
|
||||
char *data;
|
||||
|
||||
if( !fmod_dll ) return false;
|
||||
|
||||
// Load the file
|
||||
data = (char *)LOAD_FILE( name, &filesize );
|
||||
|
||||
if( !data )
|
||||
{
|
||||
ALERT( at_console, "couldn't load %s\n", name );
|
||||
return false;
|
||||
}
|
||||
|
||||
// try to open this file as stream default
|
||||
int flags;
|
||||
if( m_iStatus & 2 ) flags = FSOUND_LOADMEMORY|FSOUND_MPEGACCURATE|FSOUND_LOOP_NORMAL;
|
||||
else flags = FSOUND_LOADMEMORY|FSOUND_MPEGACCURATE|FSOUND_LOOP_OFF;
|
||||
fmod_data = qfmod_loadstream( data, flags, filesize );
|
||||
|
||||
if( !fmod_data ) // may be it's tracker?
|
||||
{
|
||||
// check for .xm .it .s3m headers
|
||||
if( memcmp( data, "Extended Module:", 16 ) && memcmp( data, "IMPM", 4 ) && memcmp( data + 44, "SCRM", 4 ))
|
||||
{
|
||||
for( int i = 0; name[i]; i++ )
|
||||
{
|
||||
if( name[i] == '.' ) // found extension
|
||||
{
|
||||
ALERT( at_console, "%s is not a %s file\n", name, &name[i+1] );
|
||||
break;
|
||||
}
|
||||
}
|
||||
FREE_FILE( data );
|
||||
return 1;
|
||||
}
|
||||
|
||||
// it's tracker, try to load
|
||||
fmod_data = qfmod_loadsongmemory( data, filesize );
|
||||
|
||||
if( !fmod_data ) // what's hell?
|
||||
{
|
||||
ALERT( at_console, "%s\n", FMOD_ErrorString(qfmod_geterror()));
|
||||
FREE_FILE( data );
|
||||
return 1;
|
||||
}
|
||||
|
||||
qfmod_playsong( fmod_data );
|
||||
FREE_FILE( data );
|
||||
return 1;
|
||||
}
|
||||
|
||||
qfmod_playstream( 0, fmod_data );
|
||||
FREE_FILE( data );
|
||||
m_iStatus = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHudSound :: Draw( float flTime )
|
||||
{
|
||||
int pause = CVAR_GET_FLOAT( "paused" ); // engine cvar
|
||||
|
||||
if( fmod_dll && fmod_data )
|
||||
{
|
||||
if( last_state != pause )
|
||||
{
|
||||
// detect of music type
|
||||
if( CheckFormat( FALSE ) == TRACK )
|
||||
qfmod_setmodpause( fmod_data, !qfmod_getmodpause( fmod_data ));
|
||||
else if( CheckFormat( FALSE ) == STREAM )
|
||||
qfmod_setstreampause( 0, !qfmod_getstreampause( 0 ));
|
||||
last_state = pause;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHudSound :: Close( void )
|
||||
{
|
||||
if( fmod_dll )
|
||||
{
|
||||
qfmod_stopallsongs(); // stop all songs
|
||||
qfmod_close();
|
||||
Sys_UnloadLibrary( &fmod_dll ); // free library
|
||||
}
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,246 @@
|
|||
/***
|
||||
*
|
||||
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
|
||||
*
|
||||
* This product contains software technology licensed from Id
|
||||
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Use, distribution, and modification of this source code and/or resulting
|
||||
* object code is restricted to non-commercial enhancements to products from
|
||||
* Valve LLC. All other use, distribution, or modification is prohibited
|
||||
* without written permission from Valve LLC.
|
||||
*
|
||||
****/
|
||||
//
|
||||
// statusbar.cpp
|
||||
//
|
||||
// generic text status bar, set by game dll
|
||||
// runs across bottom of screen
|
||||
//
|
||||
|
||||
#include "extdll.h"
|
||||
#include "hud_iface.h"
|
||||
#include "hud.h"
|
||||
|
||||
DECLARE_MESSAGE( m_StatusBar, StatusText );
|
||||
DECLARE_MESSAGE( m_StatusBar, StatusValue );
|
||||
|
||||
#define STATUSBAR_ID_LINE 1
|
||||
|
||||
int CHudStatusBar :: Init( void )
|
||||
{
|
||||
gHUD.AddHudElem( this );
|
||||
|
||||
HOOK_MESSAGE( StatusText );
|
||||
HOOK_MESSAGE( StatusValue );
|
||||
|
||||
Reset();
|
||||
|
||||
CVAR_REGISTER( "hud_centerid", "0", CVAR_ARCHIVE, "disables center id" );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHudStatusBar :: VidInit( void )
|
||||
{
|
||||
// Load sprites here
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void CHudStatusBar :: Reset( void )
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
m_iFlags &= ~HUD_ACTIVE; // start out inactive
|
||||
for ( i = 0; i < MAX_STATUSBAR_LINES; i++ )
|
||||
m_szStatusText[i][0] = 0;
|
||||
memset( m_iStatusValues, 0, sizeof m_iStatusValues );
|
||||
|
||||
m_iStatusValues[0] = 1; // 0 is the special index, which always returns true
|
||||
}
|
||||
|
||||
void CHudStatusBar :: ParseStatusString( int line_num )
|
||||
{
|
||||
// localise string first
|
||||
char szBuffer[MAX_STATUSTEXT_LENGTH];
|
||||
memset( szBuffer, 0, sizeof szBuffer );
|
||||
gHUD.m_TextMessage.LocaliseTextString( m_szStatusText[line_num], szBuffer, MAX_STATUSTEXT_LENGTH );
|
||||
|
||||
// parse m_szStatusText & m_iStatusValues into m_szStatusBar
|
||||
memset( m_szStatusBar[line_num], 0, MAX_STATUSTEXT_LENGTH );
|
||||
char *src = szBuffer;
|
||||
char *dst = m_szStatusBar[line_num];
|
||||
|
||||
char *src_start = src, *dst_start = dst;
|
||||
|
||||
while ( *src != 0 )
|
||||
{
|
||||
while ( *src == '\n' )
|
||||
src++; // skip over any newlines
|
||||
|
||||
if ( ((src - src_start) >= MAX_STATUSTEXT_LENGTH) || ((dst - dst_start) >= MAX_STATUSTEXT_LENGTH) )
|
||||
break;
|
||||
|
||||
int index = atoi( src );
|
||||
// should we draw this line?
|
||||
if ( (index >= 0 && index < MAX_STATUSBAR_VALUES) && (m_iStatusValues[index] != 0) )
|
||||
{ // parse this line and append result to the status bar
|
||||
while ( *src >= '0' && *src <= '9' )
|
||||
src++;
|
||||
|
||||
if ( *src == '\n' || *src == 0 )
|
||||
continue; // no more left in this text line
|
||||
|
||||
// copy the text, char by char, until we hit a % or a \n
|
||||
while ( *src != '\n' && *src != 0 )
|
||||
{
|
||||
if ( *src != '%' )
|
||||
{ // just copy the character
|
||||
*dst = *src;
|
||||
dst++, src++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// get the descriptor
|
||||
char valtype = *(++src); // move over %
|
||||
|
||||
// if it's a %, draw a % sign
|
||||
if ( valtype == '%' )
|
||||
{
|
||||
*dst = valtype;
|
||||
dst++, src++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// move over descriptor, then get and move over the index
|
||||
index = atoi( ++src );
|
||||
while ( *src >= '0' && *src <= '9' )
|
||||
src++;
|
||||
|
||||
if ( index >= 0 && index < MAX_STATUSBAR_VALUES )
|
||||
{
|
||||
int indexval = m_iStatusValues[index];
|
||||
|
||||
// get the string to substitute in place of the %XX
|
||||
char szRepString[MAX_PLAYER_NAME_LENGTH];
|
||||
switch ( valtype )
|
||||
{
|
||||
case 'p': // player name
|
||||
GetPlayerInfo( indexval, &gHUD.m_Scoreboard.m_PlayerInfoList[indexval] );
|
||||
if ( gHUD.m_Scoreboard.m_PlayerInfoList[indexval].name != NULL )
|
||||
{
|
||||
strncpy( szRepString, gHUD.m_Scoreboard.m_PlayerInfoList[indexval].name, MAX_PLAYER_NAME_LENGTH );
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy( szRepString, "******" );
|
||||
}
|
||||
break;
|
||||
case 'i': // number
|
||||
sprintf( szRepString, "%d", indexval );
|
||||
break;
|
||||
default:
|
||||
szRepString[0] = 0;
|
||||
}
|
||||
|
||||
for ( char *cp = szRepString; *cp != 0 && ((dst - dst_start) < MAX_STATUSTEXT_LENGTH); cp++, dst++ )
|
||||
*dst = *cp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// skip to next line of text
|
||||
while ( *src != 0 && *src != '\n' )
|
||||
src++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int CHudStatusBar :: Draw( float fTime )
|
||||
{
|
||||
if ( m_bReparseString )
|
||||
{
|
||||
for ( int i = 0; i < MAX_STATUSBAR_LINES; i++ )
|
||||
ParseStatusString( i );
|
||||
m_bReparseString = FALSE;
|
||||
}
|
||||
|
||||
// Draw the status bar lines
|
||||
for ( int i = 0; i < MAX_STATUSBAR_LINES; i++ )
|
||||
{
|
||||
int TextHeight, TextWidth;
|
||||
GetConsoleStringSize( m_szStatusBar[i], &TextWidth, &TextHeight );
|
||||
|
||||
int Y_START = SCREEN_HEIGHT - 45;
|
||||
int x = 4;
|
||||
int y = Y_START - ( 4 + TextHeight * i ); // draw along bottom of screen
|
||||
|
||||
// let user set status ID bar centering
|
||||
if ( (i == STATUSBAR_ID_LINE) && CVAR_GET_FLOAT( "hud_centerid" ))
|
||||
{
|
||||
x = max( 0, max( 2, (SCREEN_WIDTH - TextWidth)) / 2 );
|
||||
y = (SCREEN_HEIGHT / 2) + (TextHeight * CVAR_GET_FLOAT( "hud_centerid" ));
|
||||
}
|
||||
DrawConsoleString( x, y, m_szStatusBar[i] );
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Message handler for StatusText message
|
||||
// accepts two values:
|
||||
// byte: line number of status bar text
|
||||
// string: status bar text
|
||||
// this string describes how the status bar should be drawn
|
||||
// a semi-regular expression:
|
||||
// ( slotnum ([a..z] [%pX] [%iX])*)*
|
||||
// where slotnum is an index into the Value table (see below)
|
||||
// if slotnum is 0, the string is always drawn
|
||||
// if StatusValue[slotnum] != 0, the following string is drawn, upto the next newline - otherwise the text is skipped upto next newline
|
||||
// %pX, where X is an integer, will substitute a player name here, getting the player index from StatusValue[X]
|
||||
// %iX, where X is an integer, will substitute a number here, getting the number from StatusValue[X]
|
||||
|
||||
int CHudStatusBar :: MsgFunc_StatusText( const char *pszName, int iSize, void *pbuf )
|
||||
{
|
||||
BEGIN_READ( pszName, iSize, pbuf );
|
||||
|
||||
int line = READ_BYTE();
|
||||
|
||||
if ( line < 0 || line >= MAX_STATUSBAR_LINES )
|
||||
return 1;
|
||||
|
||||
strncpy( m_szStatusText[line], READ_STRING(), MAX_STATUSTEXT_LENGTH );
|
||||
m_szStatusText[line][MAX_STATUSTEXT_LENGTH-1] = 0; // ensure it's null terminated ( strncpy() won't null terminate if read string too long)
|
||||
|
||||
if( m_szStatusText[0] == 0 )
|
||||
m_iFlags &= ~HUD_ACTIVE;
|
||||
else m_iFlags |= HUD_ACTIVE; // we have status text, so turn on the status bar
|
||||
|
||||
m_bReparseString = TRUE;
|
||||
END_READ();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Message handler for StatusText message
|
||||
// accepts two values:
|
||||
// byte: index into the status value array
|
||||
// short: value to store
|
||||
int CHudStatusBar :: MsgFunc_StatusValue( const char *pszName, int iSize, void *pbuf )
|
||||
{
|
||||
BEGIN_READ( pszName, iSize, pbuf );
|
||||
|
||||
int index = READ_BYTE();
|
||||
if( index < 1 || index >= MAX_STATUSBAR_VALUES )
|
||||
return 1; // index out of range
|
||||
|
||||
m_iStatusValues[index] = READ_SHORT();
|
||||
m_bReparseString = TRUE;
|
||||
END_READ();
|
||||
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,204 @@
|
|||
/***
|
||||
*
|
||||
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
|
||||
*
|
||||
* This product contains software technology licensed from Id
|
||||
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Use, distribution, and modification of this source code and/or resulting
|
||||
* object code is restricted to non-commercial enhancements to products from
|
||||
* Valve LLC. All other use, distribution, or modification is prohibited
|
||||
* without written permission from Valve LLC.
|
||||
*
|
||||
****/
|
||||
//
|
||||
// text_message.cpp
|
||||
//
|
||||
// implementation of CHudTextMessage class
|
||||
//
|
||||
// this class routes messages through titles.txt for localisation
|
||||
//
|
||||
|
||||
#include "extdll.h"
|
||||
#include "hud_iface.h"
|
||||
#include "hud.h"
|
||||
|
||||
DECLARE_MESSAGE( m_TextMessage, TextMsg );
|
||||
|
||||
int CHudTextMessage::Init(void)
|
||||
{
|
||||
HOOK_MESSAGE( TextMsg );
|
||||
|
||||
gHUD.AddHudElem( this );
|
||||
|
||||
Reset();
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
||||
// Searches through the string for any msg names (indicated by a '#')
|
||||
// any found are looked up in titles.txt and the new message substituted
|
||||
// the new value is pushed into dst_buffer
|
||||
char *CHudTextMessage::LocaliseTextString( const char *msg, char *dst_buffer, int buffer_size )
|
||||
{
|
||||
char *dst = dst_buffer;
|
||||
for ( char *src = (char*)msg; *src != 0 && buffer_size > 0; buffer_size-- )
|
||||
{
|
||||
if ( *src == '#' )
|
||||
{
|
||||
// cut msg name out of string
|
||||
static char word_buf[255];
|
||||
char *wdst = word_buf, *word_start = src;
|
||||
for ( ++src ; (*src >= 'A' && *src <= 'z') || (*src >= '0' && *src <= '9'); wdst++, src++ )
|
||||
{
|
||||
*wdst = *src;
|
||||
}
|
||||
*wdst = 0;
|
||||
|
||||
// lookup msg name in titles.txt
|
||||
client_textmessage_t *clmsg = TextMessageGet( word_buf );
|
||||
if ( !clmsg || !(clmsg->pMessage) )
|
||||
{
|
||||
src = word_start;
|
||||
*dst = *src;
|
||||
dst++, src++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// copy string into message over the msg name
|
||||
for ( char *wsrc = (char*)clmsg->pMessage; *wsrc != 0; wsrc++, dst++ )
|
||||
{
|
||||
*dst = *wsrc;
|
||||
}
|
||||
*dst = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
*dst = *src;
|
||||
dst++, src++;
|
||||
*dst = 0;
|
||||
}
|
||||
}
|
||||
|
||||
dst_buffer[buffer_size-1] = 0; // ensure null termination
|
||||
return dst_buffer;
|
||||
}
|
||||
|
||||
// As above, but with a local static buffer
|
||||
char *CHudTextMessage::BufferedLocaliseTextString( const char *msg )
|
||||
{
|
||||
static char dst_buffer[1024];
|
||||
LocaliseTextString( msg, dst_buffer, 1024 );
|
||||
return dst_buffer;
|
||||
}
|
||||
|
||||
// Simplified version of LocaliseTextString; assumes string is only one word
|
||||
char *CHudTextMessage::LookupString( const char *msg, int *msg_dest )
|
||||
{
|
||||
if ( !msg )
|
||||
return "";
|
||||
|
||||
// '#' character indicates this is a reference to a string in titles.txt, and not the string itself
|
||||
if ( msg[0] == '#' )
|
||||
{
|
||||
// this is a message name, so look up the real message
|
||||
client_textmessage_t *clmsg = TextMessageGet( msg+1 );
|
||||
|
||||
if ( !clmsg || !(clmsg->pMessage) )
|
||||
return (char*)msg; // lookup failed, so return the original string
|
||||
|
||||
if ( msg_dest )
|
||||
{
|
||||
// check to see if titles.txt info overrides msg destination
|
||||
// if clmsg->effect is less than 0, then clmsg->effect holds -1 * message_destination
|
||||
if ( clmsg->effect < 0 ) //
|
||||
*msg_dest = -clmsg->effect;
|
||||
}
|
||||
|
||||
return (char*)clmsg->pMessage;
|
||||
}
|
||||
else
|
||||
{ // nothing special about this message, so just return the same string
|
||||
return (char*)msg;
|
||||
}
|
||||
}
|
||||
|
||||
void StripEndNewlineFromString( char *str )
|
||||
{
|
||||
int s = strlen( str ) - 1;
|
||||
if ( str[s] == '\n' || str[s] == '\r' )
|
||||
str[s] = 0;
|
||||
}
|
||||
|
||||
// converts all '\r' characters to '\n', so that the engine can deal with the properly
|
||||
// returns a pointer to str
|
||||
char* ConvertCRtoNL( char *str )
|
||||
{
|
||||
for ( char *ch = str; *ch != 0; ch++ )
|
||||
if ( *ch == '\r' )
|
||||
*ch = '\n';
|
||||
return str;
|
||||
}
|
||||
|
||||
// Message handler for text messages
|
||||
// displays a string, looking them up from the titles.txt file, which can be localised
|
||||
// parameters:
|
||||
// byte: message direction ( HUD_PRINTCONSOLE, HUD_PRINTNOTIFY, HUD_PRINTCENTER, HUD_PRINTTALK )
|
||||
// string: message
|
||||
// optional parameters:
|
||||
// string: message parameter 1
|
||||
// string: message parameter 2
|
||||
// string: message parameter 3
|
||||
// string: message parameter 4
|
||||
// any string that starts with the character '#' is a message name, and is used to look up the real message in titles.txt
|
||||
// the next (optional) one to four strings are parameters for that string (which can also be message names if they begin with '#')
|
||||
int CHudTextMessage::MsgFunc_TextMsg( const char *pszName, int iSize, void *pbuf )
|
||||
{
|
||||
BEGIN_READ( pszName, iSize, pbuf );
|
||||
|
||||
int msg_dest = READ_BYTE();
|
||||
|
||||
static char szBuf[6][128];
|
||||
char *msg_text = LookupString( READ_STRING(), &msg_dest );
|
||||
msg_text = strcpy( szBuf[0], msg_text );
|
||||
|
||||
// keep reading strings and using C format strings for subsituting the strings into the localised text string
|
||||
char *sstr1 = LookupString( READ_STRING() );
|
||||
sstr1 = strcpy( szBuf[1], sstr1 );
|
||||
StripEndNewlineFromString( sstr1 ); // these strings are meant for subsitution into the main strings, so cull the automatic end newlines
|
||||
char *sstr2 = LookupString( READ_STRING() );
|
||||
sstr2 = strcpy( szBuf[2], sstr2 );
|
||||
StripEndNewlineFromString( sstr2 );
|
||||
char *sstr3 = LookupString( READ_STRING() );
|
||||
sstr3 = strcpy( szBuf[3], sstr3 );
|
||||
StripEndNewlineFromString( sstr3 );
|
||||
char *sstr4 = LookupString( READ_STRING() );
|
||||
sstr4 = strcpy( szBuf[4], sstr4 );
|
||||
StripEndNewlineFromString( sstr4 );
|
||||
char *psz = szBuf[5];
|
||||
|
||||
switch ( msg_dest )
|
||||
{
|
||||
case HUD_PRINTCENTER:
|
||||
sprintf( psz, msg_text, sstr1, sstr2, sstr3, sstr4 );
|
||||
CenterPrint( ConvertCRtoNL( psz ), SCREEN_HEIGHT / 2, BIGCHAR_WIDTH );
|
||||
break;
|
||||
case HUD_PRINTNOTIFY:
|
||||
psz[0] = 1; // mark this message to go into the notify buffer
|
||||
sprintf( psz+1, msg_text, sstr1, sstr2, sstr3, sstr4 );
|
||||
ConsolePrint( ConvertCRtoNL( psz ) );
|
||||
break;
|
||||
case HUD_PRINTTALK:
|
||||
sprintf( psz, msg_text, sstr1, sstr2, sstr3, sstr4 );
|
||||
gHUD.m_SayText.SayTextPrint( ConvertCRtoNL( psz ), 128 );
|
||||
break;
|
||||
case HUD_PRINTCONSOLE:
|
||||
sprintf( psz, msg_text, sstr1, sstr2, sstr3, sstr4 );
|
||||
ConsolePrint( ConvertCRtoNL( psz ) );
|
||||
break;
|
||||
}
|
||||
END_READ();
|
||||
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
/***
|
||||
*
|
||||
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
|
||||
*
|
||||
* This product contains software technology licensed from Id
|
||||
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Use, distribution, and modification of this source code and/or resulting
|
||||
* object code is restricted to non-commercial enhancements to products from
|
||||
* Valve LLC. All other use, distribution, or modification is prohibited
|
||||
* without written permission from Valve LLC.
|
||||
*
|
||||
****/
|
||||
//
|
||||
// Train.cpp
|
||||
//
|
||||
// implementation of CHudAmmo class
|
||||
//
|
||||
|
||||
#include "extdll.h"
|
||||
#include "hud_iface.h"
|
||||
#include "hud.h"
|
||||
|
||||
DECLARE_MESSAGE( m_Train, Train )
|
||||
|
||||
int CHudTrain :: Init( void )
|
||||
{
|
||||
HOOK_MESSAGE( Train );
|
||||
|
||||
m_iPos = 0;
|
||||
m_iFlags = 0;
|
||||
gHUD.AddHudElem( this );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHudTrain::VidInit( void )
|
||||
{
|
||||
m_hSprite = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHudTrain::Draw(float fTime)
|
||||
{
|
||||
if( !m_hSprite )
|
||||
m_hSprite = LOAD_SHADER( "hud_train" );
|
||||
|
||||
if( m_iPos )
|
||||
{
|
||||
int r, g, b, x, y;
|
||||
|
||||
UnpackRGB( r, g, b, gHUD.m_iHUDColor );
|
||||
SPR_Set( m_hSprite, r, g, b );
|
||||
|
||||
// This should show up to the right and part way up the armor number
|
||||
y = SCREEN_HEIGHT - SPR_Height( m_hSprite, 0 ) - gHUD.m_iFontHeight;
|
||||
x = SCREEN_WIDTH / 3 + SPR_Width( m_hSprite, 0 ) / 4;
|
||||
|
||||
SPR_DrawAdditive( m_iPos - 1, x, y, NULL);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int CHudTrain::MsgFunc_Train( const char *pszName, int iSize, void *pbuf )
|
||||
{
|
||||
BEGIN_READ( pszName, iSize, pbuf );
|
||||
|
||||
// update Train data
|
||||
m_iPos = READ_BYTE();
|
||||
|
||||
if( m_iPos )
|
||||
m_iFlags |= HUD_ACTIVE;
|
||||
else m_iFlags &= ~HUD_ACTIVE;
|
||||
END_READ();
|
||||
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,356 @@
|
|||
//=======================================================================
|
||||
// Copyright XashXT Group 2008 ©
|
||||
// hud_utils.cpp - client game utilities code
|
||||
//=======================================================================
|
||||
|
||||
#include "extdll.h"
|
||||
#include "hud_iface.h"
|
||||
#include "hud.h"
|
||||
|
||||
// NOTE: modify these functions with caution
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *name;
|
||||
byte *buf;
|
||||
int size;
|
||||
int read;
|
||||
BOOL badRead;
|
||||
char string[2048]; // using for store strings
|
||||
} user_message_t;
|
||||
|
||||
static user_message_t gMsg;
|
||||
|
||||
void BEGIN_READ( const char *pszName, int iSize, void *pBuf )
|
||||
{
|
||||
memset( &gMsg, 0, sizeof( gMsg ));
|
||||
|
||||
gMsg.size = iSize;
|
||||
gMsg.buf = (byte *)pBuf;
|
||||
}
|
||||
|
||||
void END_READ( void )
|
||||
{
|
||||
if( gMsg.badRead )
|
||||
{
|
||||
ALERT( at_console, "%s was received with errors\n", gMsg.name );
|
||||
}
|
||||
}
|
||||
|
||||
int READ_CHAR( void )
|
||||
{
|
||||
int c;
|
||||
|
||||
if( gMsg.read + 1 > gMsg.size )
|
||||
{
|
||||
gMsg.badRead = true;
|
||||
return -1;
|
||||
}
|
||||
|
||||
c = (signed char)gMsg.buf[gMsg.read];
|
||||
gMsg.read++;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
int READ_BYTE( void )
|
||||
{
|
||||
int c;
|
||||
|
||||
if( gMsg.read+1 > gMsg.size )
|
||||
{
|
||||
gMsg.badRead = true;
|
||||
return -1;
|
||||
}
|
||||
|
||||
c = (unsigned char)gMsg.buf[gMsg.read];
|
||||
gMsg.read++;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
int READ_SHORT( void )
|
||||
{
|
||||
int c;
|
||||
|
||||
if( gMsg.read + 2 > gMsg.size )
|
||||
{
|
||||
gMsg.badRead = true;
|
||||
return -1;
|
||||
}
|
||||
|
||||
c = (short)( gMsg.buf[gMsg.read] + ( gMsg.buf[gMsg.read+1] << 8 ));
|
||||
gMsg.read += 2;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
int READ_WORD( void ) { return READ_SHORT(); }
|
||||
|
||||
int READ_LONG( void )
|
||||
{
|
||||
int c;
|
||||
|
||||
if( gMsg.read + 4 > gMsg.size )
|
||||
{
|
||||
gMsg.badRead = true;
|
||||
return -1;
|
||||
}
|
||||
c = gMsg.buf[gMsg.read]+(gMsg.buf[gMsg.read+1]<<8)+(gMsg.buf[gMsg.read+2]<<16)+(gMsg.buf[gMsg.read+3]<<24);
|
||||
gMsg.read += 4;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
float READ_FLOAT( void )
|
||||
{
|
||||
union { float f; int l; } dat;
|
||||
|
||||
dat.l = READ_LONG();
|
||||
return dat.f;
|
||||
}
|
||||
|
||||
char* READ_STRING( void )
|
||||
{
|
||||
int l, c;
|
||||
|
||||
gMsg.string[0] = 0;
|
||||
|
||||
l = 0;
|
||||
do
|
||||
{
|
||||
if( gMsg.read+1 > gMsg.size ) break; // no more characters
|
||||
|
||||
c = READ_CHAR();
|
||||
if( c == -1 || c == '\0' )
|
||||
break;
|
||||
|
||||
// translate all fmt spec to avoid crash bugs
|
||||
if( c == '%' ) c = '.';
|
||||
|
||||
gMsg.string[l] = c;
|
||||
l++;
|
||||
} while( l < sizeof( gMsg.string ) - 1 );
|
||||
|
||||
gMsg.string[l] = 0; // terminator
|
||||
|
||||
return gMsg.string;
|
||||
}
|
||||
|
||||
//
|
||||
// Xash3D network specs. Don't modify!
|
||||
//
|
||||
float READ_COORD( void )
|
||||
{
|
||||
return READ_FLOAT();
|
||||
}
|
||||
|
||||
float READ_ANGLE( void )
|
||||
{
|
||||
return READ_FLOAT();
|
||||
}
|
||||
|
||||
float READ_ANGLE16( void )
|
||||
{
|
||||
return (float)(READ_SHORT() * (360.0 / 65536));
|
||||
}
|
||||
|
||||
//
|
||||
// Sprites draw stuff
|
||||
//
|
||||
typedef struct
|
||||
{
|
||||
// temp handle
|
||||
HSPRITE hSprite;
|
||||
|
||||
// crosshair members
|
||||
HSPRITE hCrosshair;
|
||||
wrect_t rcCrosshair;
|
||||
Vector rgbCrosshair;
|
||||
} draw_stuff_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float fadeSpeed; // How fast to fade (tics / second) (+ fade in, - fade out)
|
||||
float fadeEnd; // When the fading hits maximum
|
||||
float fadeTotalEnd; // Total End Time of the fade (used for FFADE_OUT)
|
||||
float fadeReset; // When to reset to not fading (for fadeout and hold)
|
||||
Vector fadeColor;
|
||||
float fadealpha;
|
||||
int fadeFlags; // Fading flags
|
||||
} screenfade_t;
|
||||
|
||||
static draw_stuff_t ds;
|
||||
static screenfade_t sf;
|
||||
|
||||
int SPR_Frames( HSPRITE hPic )
|
||||
{
|
||||
// FIXME: engfuncs GetImageFrames
|
||||
return 1;
|
||||
}
|
||||
|
||||
int SPR_Height( HSPRITE hPic, int frame )
|
||||
{
|
||||
int Height;
|
||||
|
||||
GetImageSize( NULL, &Height, hPic );
|
||||
|
||||
return Height;
|
||||
}
|
||||
|
||||
int SPR_Width( HSPRITE hPic, int frame )
|
||||
{
|
||||
int Width;
|
||||
|
||||
GetImageSize( &Width, NULL, hPic );
|
||||
|
||||
return Width;
|
||||
}
|
||||
|
||||
void SPR_Set( HSPRITE hPic, int r, int g, int b )
|
||||
{
|
||||
ds.hSprite = hPic;
|
||||
SetColor((r / 255.0f), (g / 255.0f), (b / 255.0f), 1.0f );
|
||||
}
|
||||
|
||||
void SPR_Draw( int frame, int x, int y, const wrect_t *prc )
|
||||
{
|
||||
// FIXME: switch rendermode
|
||||
DrawImage( ds.hSprite, x, y, prc->right, prc->bottom, frame );
|
||||
}
|
||||
|
||||
void SPR_Draw( int frame, int x, int y, int width, int height )
|
||||
{
|
||||
// FIXME: switch rendermode
|
||||
DrawImage( ds.hSprite, x, y, width, height, frame );
|
||||
}
|
||||
|
||||
void SPR_DrawHoles( int frame, int x, int y, const wrect_t *prc )
|
||||
{
|
||||
// FIXME: switch rendermode
|
||||
DrawImage( ds.hSprite, x, y, prc->right, prc->bottom, frame );
|
||||
}
|
||||
|
||||
void SPR_DrawHoles( int frame, int x, int y, int width, int height )
|
||||
{
|
||||
// FIXME: switch rendermode
|
||||
DrawImage( ds.hSprite, x, y, width, height, frame );
|
||||
}
|
||||
|
||||
void SPR_DrawAdditive( int frame, int x, int y, const wrect_t *prc )
|
||||
{
|
||||
// FIXME: switch rendermode
|
||||
DrawImage( ds.hSprite, x, y, prc->right, prc->bottom, frame );
|
||||
}
|
||||
|
||||
void SetCrosshair( HSPRITE hspr, wrect_t rc, int r, int g, int b )
|
||||
{
|
||||
ds.rgbCrosshair.x = (float)(r / 255.0f);
|
||||
ds.rgbCrosshair.y = (float)(g / 255.0f);
|
||||
ds.rgbCrosshair.z = (float)(b / 255.0f);
|
||||
ds.hCrosshair = hspr;
|
||||
ds.rcCrosshair = rc;
|
||||
}
|
||||
|
||||
void DrawCrosshair( void )
|
||||
{
|
||||
if( ds.hCrosshair == 0 ) return;
|
||||
|
||||
// find center of screen
|
||||
int x = (SCREEN_WIDTH - ds.rcCrosshair.right) / 2;
|
||||
int y = (SCREEN_HEIGHT - ds.rcCrosshair.bottom) / 2;
|
||||
|
||||
// FIXME: apply crosshair angles
|
||||
SetColor( ds.rgbCrosshair.x, ds.rgbCrosshair.y, ds.rgbCrosshair.z, 1.0f );
|
||||
DrawImage( ds.hCrosshair, x, y, ds.rcCrosshair.right, ds.rcCrosshair.bottom, 0 );
|
||||
}
|
||||
|
||||
void SetScreenFade( Vector fadeColor, float alpha, float duration, float holdTime, int fadeFlags )
|
||||
{
|
||||
sf.fadeColor = fadeColor;
|
||||
sf.fadealpha = alpha;
|
||||
sf.fadeFlags = fadeFlags;
|
||||
sf.fadeEnd = gHUD.m_flTime + duration;
|
||||
sf.fadeTotalEnd = sf.fadeEnd + holdTime;
|
||||
sf.fadeSpeed = duration / gHUD.m_flTimeDelta;
|
||||
}
|
||||
|
||||
void DrawScreenFade( void )
|
||||
{
|
||||
// FIXME: implement
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
Sys LoadGameDLL
|
||||
|
||||
====================
|
||||
*/
|
||||
BOOL Sys_LoadLibrary( const char* dllname, dllhandle_t* handle, const dllfunction_t *fcts )
|
||||
{
|
||||
const dllfunction_t *gamefunc;
|
||||
char dllpath[256], gamedir[256];
|
||||
dllhandle_t dllhandle = 0;
|
||||
|
||||
if( handle == NULL ) return false;
|
||||
|
||||
// Initializations
|
||||
for( gamefunc = fcts; gamefunc && gamefunc->name != NULL; gamefunc++ )
|
||||
*gamefunc->funcvariable = NULL;
|
||||
|
||||
GET_GAME_DIR( gamedir );
|
||||
sprintf( dllpath, "%s/bin/%s", gamedir, dllname );
|
||||
dllhandle = LoadLibrary( dllpath );
|
||||
|
||||
// No DLL found
|
||||
if( !dllhandle ) return false;
|
||||
|
||||
// Get the function adresses
|
||||
for( gamefunc = fcts; gamefunc && gamefunc->name != NULL; gamefunc++ )
|
||||
if(!( *gamefunc->funcvariable = (void *) Sys_GetProcAddress( dllhandle, gamefunc->name )))
|
||||
{
|
||||
Sys_UnloadLibrary( &dllhandle );
|
||||
return false;
|
||||
}
|
||||
|
||||
ALERT( at_loading, "%s loaded succesfully!\n", dllname );
|
||||
*handle = dllhandle;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Sys_UnloadLibrary( dllhandle_t *handle )
|
||||
{
|
||||
if( handle == NULL || *handle == NULL )
|
||||
return;
|
||||
|
||||
FreeLibrary( *handle );
|
||||
*handle = NULL;
|
||||
}
|
||||
|
||||
void* Sys_GetProcAddress( dllhandle_t handle, const char* name )
|
||||
{
|
||||
return (void *)GetProcAddress( handle, name );
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
va
|
||||
|
||||
does a varargs printf into a temp buffer, so I don't need to have
|
||||
varargs versions of all text functions.
|
||||
FIXME: make this buffer size safe someday
|
||||
============
|
||||
*/
|
||||
char *va( const char *format, ... )
|
||||
{
|
||||
va_list argptr;
|
||||
static char string[16][1024], *s;
|
||||
static int stringindex = 0;
|
||||
|
||||
s = string[stringindex];
|
||||
stringindex = (stringindex + 1) & 15;
|
||||
va_start( argptr, format );
|
||||
_vsnprintf( s, sizeof( string[0] ), format, argptr );
|
||||
va_end( argptr );
|
||||
return s;
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
//=======================================================================
|
||||
// Copyright (C) Shambler Team 2004
|
||||
// warhead.cpp - hud for weapon_redeemer
|
||||
//
|
||||
//=======================================================================
|
||||
|
||||
#include "extdll.h"
|
||||
#include "hud_iface.h"
|
||||
#include "hud.h"
|
||||
|
||||
#define GUIDE_S SPR_Width( m_hCrosshair, 0 )
|
||||
#define READOUT_S 128
|
||||
DECLARE_MESSAGE( m_Redeemer, WarHUD )
|
||||
|
||||
int CHudRedeemer::Init( void )
|
||||
{
|
||||
m_iHudMode = 0;
|
||||
|
||||
HOOK_MESSAGE( WarHUD );
|
||||
m_iFlags |= HUD_ACTIVE;
|
||||
gHUD.AddHudElem( this );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHudRedeemer :: VidInit( void )
|
||||
{
|
||||
m_hSprite = LOAD_SHADER( "wh_readout" );
|
||||
m_hCrosshair = LOAD_SHADER( "wh_guidedx");
|
||||
m_hStatic = LOAD_SHADER( "wh_static");
|
||||
m_hCamera = LOAD_SHADER( "wh_camera");
|
||||
m_hCamRec = LOAD_SHADER( "wh_cam_rec");
|
||||
|
||||
m_iHudMode = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHudRedeemer :: MsgFunc_WarHUD( const char *pszName, int iSize, void *pbuf )
|
||||
{
|
||||
BEGIN_READ( pszName, iSize, pbuf );
|
||||
m_iHudMode = READ_BYTE();
|
||||
END_READ();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHudRedeemer :: Draw( float flTime )
|
||||
{
|
||||
int x, y, w, h;
|
||||
wrect_t rc;
|
||||
int frame;
|
||||
|
||||
// setup screen rectangle
|
||||
rc.left = rc.top = 0;
|
||||
rc.right = SCREEN_WIDTH;
|
||||
rc.bottom = SCREEN_HEIGHT;
|
||||
|
||||
if( m_iHudMode == 1 ) // draw crosshair and readout
|
||||
{
|
||||
|
||||
y = (SCREEN_WIDTH - GUIDE_S) / 2;
|
||||
x = (SCREEN_HEIGHT - GUIDE_S) / 2;
|
||||
|
||||
SPR_Set( m_hCrosshair, 255, 128, 128 );
|
||||
SPR_DrawAdditive( 0, y, x, NULL);
|
||||
|
||||
int yOffset = ((int)(flTime * 850) % READOUT_S) - READOUT_S;
|
||||
SPR_Set( m_hSprite, 255, 128, 128 );
|
||||
for( ; yOffset < SCREEN_HEIGHT; yOffset += READOUT_S )
|
||||
SPR_DrawAdditive( 0, 0, yOffset, NULL );
|
||||
SetScreenFade( Vector( 1, 0, 0 ), 0.25, 0, 0, FFADE_STAYOUT ); // enable red fade
|
||||
}
|
||||
else if( m_iHudMode == 2 ) // draw alpha noise
|
||||
{
|
||||
SPR_Set(m_hStatic, 255, 255, 255 );
|
||||
|
||||
// play at 15fps
|
||||
frame = (int)(flTime * 15) % SPR_Frames( m_hStatic );
|
||||
|
||||
y = x = 0;
|
||||
w = SPR_Width( m_hStatic, 0);
|
||||
h = SPR_Height( m_hStatic, 0);
|
||||
|
||||
for( y = -(rand() % h); y < SCREEN_HEIGHT; y += h )
|
||||
for( x = -(rand() % w); x < SCREEN_WIDTH; x += w )
|
||||
SPR_DrawAdditive ( frame, x, y, NULL );
|
||||
|
||||
y = (SCREEN_WIDTH - GUIDE_S) / 2;
|
||||
x = (SCREEN_HEIGHT - GUIDE_S) / 2;
|
||||
|
||||
SPR_Set( m_hCrosshair, 255, 128, 128 );
|
||||
SPR_DrawAdditive( 0, y, x, NULL );
|
||||
|
||||
int yOffset = ((int)(flTime * 850) % READOUT_S) - READOUT_S;
|
||||
SPR_Set(m_hSprite, 255, 128, 128 );
|
||||
for( ; yOffset < SCREEN_HEIGHT; yOffset += READOUT_S )
|
||||
SPR_DrawAdditive( 0, 0, yOffset, NULL );
|
||||
SetScreenFade( Vector( 1, 0, 0 ), 0.25, 0, 0, FFADE_STAYOUT ); // enable red fade
|
||||
}
|
||||
else if( m_iHudMode == 3 ) // draw static noise
|
||||
{
|
||||
// play at 25fps
|
||||
frame = (int)(flTime * 25) % SPR_Frames( m_hStatic );
|
||||
|
||||
SPR_Set( m_hStatic, 255, 255, 255 );
|
||||
SPR_Draw( frame, 0, 0, &rc );
|
||||
|
||||
// disable fade
|
||||
SetScreenFade( Vector( 1, 1, 1 ), 0, 0, 0, FFADE_OUT );
|
||||
}
|
||||
else if( m_iHudMode == 4 ) // draw videocamera screen
|
||||
{
|
||||
// play at 15fps
|
||||
frame = (int)(flTime * 1.5f) % SPR_Frames( m_hCamRec );
|
||||
|
||||
// draw interlaces
|
||||
SPR_Set( m_hCamera, 16, 96, 16 ); //, 64 ); // give this value from breaklight.bsp (xash03)
|
||||
SPR_DrawAdditive( frame, 0, 0, &rc );
|
||||
|
||||
// draw recorder icon
|
||||
SPR_Set( m_hCamRec, 255, 0, 0 ); //, 255 ); // give this value from breaklight.bsp (xash03)
|
||||
|
||||
float scale = 2.5f; // REC[*] sprite scale
|
||||
wrect_t m_rcCamRec;
|
||||
|
||||
// calculating pos with different resolutions
|
||||
w = SPR_Width( m_hCamRec, 0 ) * scale;
|
||||
h = SPR_Height( m_hCamRec, 0 ) * scale;
|
||||
x = SCREEN_WIDTH - (w * 1.5f);
|
||||
y = w * 0.4f;
|
||||
m_rcCamRec.left = x;
|
||||
m_rcCamRec.right = x + w;
|
||||
m_rcCamRec.top = y;
|
||||
m_rcCamRec.bottom = y + h;
|
||||
SPR_DrawAdditive( frame, 0, 0, &m_rcCamRec );
|
||||
|
||||
// disable fade
|
||||
SetScreenFade( Vector( 1, 1, 1 ), 0, 0, 0, FFADE_OUT );
|
||||
}
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
//=======================================================================
|
||||
// Copyright (C) Shambler Team 2004
|
||||
// warhead.cpp - hud for weapon_redeemer
|
||||
//
|
||||
//=======================================================================
|
||||
|
||||
#include "extdll.h"
|
||||
#include "hud_iface.h"
|
||||
#include "hud.h"
|
||||
|
||||
void DrawQuad(float xmin, float ymin, float xmax, float ymax)
|
||||
{
|
||||
//top left
|
||||
g_engfuncs.pTriAPI->TexCoord2f(0,0);
|
||||
g_engfuncs.pTriAPI->Vertex3f(xmin, ymin, 0);
|
||||
//bottom left
|
||||
g_engfuncs.pTriAPI->TexCoord2f(0,1);
|
||||
g_engfuncs.pTriAPI->Vertex3f(xmin, ymax, 0);
|
||||
//bottom right
|
||||
g_engfuncs.pTriAPI->TexCoord2f(1,1);
|
||||
g_engfuncs.pTriAPI->Vertex3f(xmax, ymax, 0);
|
||||
//top right
|
||||
g_engfuncs.pTriAPI->TexCoord2f(1,0);
|
||||
g_engfuncs.pTriAPI->Vertex3f(xmax, ymin, 0);
|
||||
}
|
||||
|
||||
DECLARE_MESSAGE( m_Zoom, ZoomHUD )
|
||||
|
||||
int CHudZoom :: Init( void )
|
||||
{
|
||||
m_iHudMode = 0;
|
||||
HOOK_MESSAGE( ZoomHUD );
|
||||
|
||||
m_iFlags |= HUD_ACTIVE;
|
||||
|
||||
gHUD.AddHudElem( this );
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHudZoom::VidInit( void )
|
||||
{
|
||||
m_hLines = LOAD_SHADER( "sniper_lines" );
|
||||
m_hCrosshair = LOAD_SHADER( "sniper_zoom" );
|
||||
m_iHudMode = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHudZoom :: MsgFunc_ZoomHUD( const char *pszName, int iSize, void *pbuf )
|
||||
{
|
||||
BEGIN_READ( pszName, iSize, pbuf );
|
||||
m_iHudMode = READ_BYTE();
|
||||
END_READ();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CHudZoom :: Draw( float flTime )
|
||||
{
|
||||
if( !m_hLines || !m_hCrosshair ) return 0;
|
||||
if( !m_iHudMode ) return 0; // draw scope
|
||||
|
||||
float left = (SCREEN_WIDTH - SCREEN_HEIGHT)/2;
|
||||
float right = left + SCREEN_HEIGHT;
|
||||
float centerx = SCREEN_WIDTH / 2;
|
||||
float centery = SCREEN_HEIGHT / 2;
|
||||
|
||||
// draw crosshair
|
||||
SPR_Set( m_hCrosshair, 255, 255, 255 );
|
||||
SPR_DrawHoles( 0, left, 0, centerx, centery);
|
||||
SPR_DrawHoles( 1, centerx, 0, right, centery);
|
||||
SPR_DrawHoles( 2, centerx, centery, right, SCREEN_HEIGHT);
|
||||
SPR_DrawHoles( 3, left, centery, centerx, SCREEN_HEIGHT);
|
||||
|
||||
// draw side-lines
|
||||
SPR_Set( m_hLines, 255, 255, 255 );
|
||||
SPR_Draw( 0, 0, 0, left, SCREEN_HEIGHT );
|
||||
SPR_Draw( 0, right, 0, SCREEN_WIDTH, SCREEN_HEIGHT );
|
||||
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,348 @@
|
|||
//=======================================================================
|
||||
// Copyright (C) XashXT Group 2006
|
||||
//=======================================================================
|
||||
|
||||
#pragma once
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define GLEW_STATIC
|
||||
#include "windows.h"
|
||||
#include "glew.h"
|
||||
#include <gl\glu.h>
|
||||
#include "cva.h"
|
||||
#include "ref_params.h"
|
||||
#include "com_model.h"
|
||||
|
||||
#pragma warning(disable:4244)
|
||||
|
||||
#define SAFE_GET_PROC( func, type, name) if (!func) func = (type) wglGetProcAddress( name ); \
|
||||
assert(func != NULL)
|
||||
|
||||
#define VIEWPORT_SIZE 512
|
||||
#define GL_TEXTURE_NUM_BASE (1<<25)
|
||||
|
||||
#define SURF_PLANEBACK 2
|
||||
#define SURF_DRAWTURB 0x10
|
||||
|
||||
#define SURF_MIRROR (1<<16)
|
||||
#define SURF_WARPMIRROR (1<<17)
|
||||
#define SURF_SCREEN (1<<18)
|
||||
#define SURF_PORTAL (1<<19)
|
||||
|
||||
// 0-2 are axial planes
|
||||
#define PLANE_X 0
|
||||
#define PLANE_Y 1
|
||||
#define PLANE_Z 2
|
||||
|
||||
#define MAX_CVA_VERTS 2048
|
||||
|
||||
//We need the following extensions:
|
||||
|
||||
//ARB_multitexture
|
||||
extern PFNGLACTIVETEXTUREARBPROC glActiveTextureARB;
|
||||
extern PFNGLCLIENTACTIVETEXTUREARBPROC glClientActiveTextureARB;
|
||||
extern PFNGLMULTITEXCOORD1FARBPROC glMultiTexCoord1fARB;
|
||||
extern PFNGLMULTITEXCOORD2FARBPROC glMultiTexCoord2fARB;
|
||||
extern PFNGLMULTITEXCOORD2FVARBPROC glMultiTexCoord2fvARB;
|
||||
extern PFNGLMULTITEXCOORD3FARBPROC glMultiTexCoord3fARB;
|
||||
extern PFNGLMULTITEXCOORD3FVARBPROC glMultiTexCoord3fvARB;
|
||||
extern PFNGLMULTITEXCOORD4FARBPROC glMultiTexCoord4fARB;
|
||||
extern PFNGLMULTITEXCOORD4FVARBPROC glMultiTexCoord4fvARB;
|
||||
|
||||
//EXT_texture_3d
|
||||
extern PFNGLTEXIMAGE3DEXTPROC glTexImage3DEXT;
|
||||
|
||||
//ARB_texture_cube_map
|
||||
|
||||
//ARB_vertex_program
|
||||
//ARB_fragment_program
|
||||
extern PFNGLPROGRAMSTRINGARBPROC glProgramStringARB;
|
||||
extern PFNGLBINDPROGRAMARBPROC glBindProgramARB;
|
||||
extern PFNGLDELETEPROGRAMSARBPROC glDeleteProgramsARB;
|
||||
extern PFNGLGENPROGRAMSARBPROC glGenProgramsARB;
|
||||
extern PFNGLGETPROGRAMIVARBPROC glGetProgramivARB;
|
||||
extern PFNGLGETPROGRAMSTRINGARBPROC glGetProgramStringARB;
|
||||
extern PFNGLISPROGRAMARBPROC glIsProgramARB;
|
||||
|
||||
//NV_register_combiners
|
||||
extern PFNGLCOMBINERPARAMETERFVNVPROC glCombinerParameterfvNV;
|
||||
extern PFNGLCOMBINERPARAMETERIVNVPROC glCombinerParameterivNV;
|
||||
extern PFNGLCOMBINERPARAMETERFNVPROC glCombinerParameterfNV;
|
||||
extern PFNGLCOMBINERPARAMETERINVPROC glCombinerParameteriNV;
|
||||
extern PFNGLCOMBINERINPUTNVPROC glCombinerInputNV;
|
||||
extern PFNGLCOMBINEROUTPUTNVPROC glCombinerOutputNV;
|
||||
extern PFNGLFINALCOMBINERINPUTNVPROC glFinalCombinerInputNV;
|
||||
|
||||
//ATI_pn_triangles
|
||||
extern PFNGLPNTRIANGLESIATIPROC glPNTrianglesiATI;
|
||||
extern PFNGLPNTRIANGLESFATIPROC glPNTrianglesfATI;
|
||||
|
||||
inline bool GLEXT_CheckExtension(const char *ext)
|
||||
{
|
||||
return (strstr((const char *)glGetString(GL_EXTENSIONS), ext) != NULL);
|
||||
}
|
||||
|
||||
bool GLEXT_Setup_ARB_multitexture();
|
||||
bool GLEXT_Setup_EXT_texture_3d();
|
||||
bool GLEXT_Setup_ARB_texture_cubemap();
|
||||
bool GLEXT_Setup_ARB_vertex_program();
|
||||
bool GLEXT_Setup_ARB_fragment_program();
|
||||
bool GLEXT_Setup_NV_register_combiners();
|
||||
bool GLEXT_Setup_ATI_pn_triangles();
|
||||
|
||||
void GL_Init( void );
|
||||
void GL_VidInit( void );
|
||||
void GL_Shutdown( void );
|
||||
void GL_PreRender( void );
|
||||
void GL_Render( bool trans );
|
||||
void GL_ExtractFrustum( void );
|
||||
void GL_MarkTextures( void );
|
||||
void R_Draw( bool transparent );
|
||||
|
||||
//Utils
|
||||
float R_SphereInFrustum( vec3_t o, float radius );
|
||||
cl_entity_t *UTIL_GetClientEntityWithServerIndex( int sv_index );
|
||||
|
||||
extern bool g_HardwareCapable;
|
||||
extern bool g_HardwareShaderCapable;
|
||||
|
||||
extern int g_iTotalMirrors;
|
||||
extern int g_iTotalVisibleMirrors;
|
||||
extern int g_iTotalScreens;
|
||||
extern int g_iTotalVisibleScreens;
|
||||
extern int g_iTotalPortals;
|
||||
extern int g_iTotalVisiblePortals;
|
||||
extern double realtime;
|
||||
|
||||
extern bool g_FirstFrame;
|
||||
extern bool g_RenderReady;
|
||||
extern bool g_bFinalPass;
|
||||
extern bool g_bEndCalc;
|
||||
extern int m_RenderRefCount; //refcounter (use for debug)
|
||||
|
||||
//passes info
|
||||
extern bool g_bMirrorShouldpass;
|
||||
extern bool g_bScreenShouldpass;
|
||||
extern bool g_bPortalShouldpass;
|
||||
extern bool g_bSkyShouldpass;
|
||||
extern bool g_bMirrorPass;
|
||||
extern bool g_bPortalPass;
|
||||
extern bool g_bScreenPass;
|
||||
extern bool g_bSkyPass;
|
||||
|
||||
//base origin and angles
|
||||
extern vec3_t g_vecBaseOrigin; //base origin - transformed always
|
||||
extern vec3_t g_vecBaseAngles; //base angles - transformed always
|
||||
extern vec3_t g_vecCurrentOrigin; //current origin
|
||||
extern vec3_t g_vecCurrentAngles; //current angles
|
||||
|
||||
extern float r_projection_matrix[16];
|
||||
extern float r_world_matrix[16];
|
||||
|
||||
extern unsigned int g_uiNoiseTex;
|
||||
extern unsigned int g_uiNoiseTexDsDt;
|
||||
extern unsigned int pTexId;
|
||||
extern unsigned int AllocateTextureIndex(void);
|
||||
|
||||
typedef struct mirror_s
|
||||
{
|
||||
int index;
|
||||
bool enabled;
|
||||
bool visible;
|
||||
float origin[3];
|
||||
float angles[3];
|
||||
float normal[3];
|
||||
float radius;
|
||||
float alpha;
|
||||
|
||||
float pr[16];
|
||||
|
||||
bool water;
|
||||
bool twoside;
|
||||
|
||||
//CVA-related
|
||||
int firstvertex;
|
||||
int numvertices;
|
||||
|
||||
unsigned int texture;
|
||||
msurface_t *surface;
|
||||
|
||||
int sv_entindex;
|
||||
cl_entity_t *ent; //for brush model mirrors
|
||||
|
||||
struct mirror_s *next;
|
||||
}mirror_t;
|
||||
|
||||
typedef struct screen_s
|
||||
{
|
||||
int index;
|
||||
bool enabled;
|
||||
bool visible;
|
||||
float origin[3];
|
||||
float radius;
|
||||
float alpha;
|
||||
|
||||
//current camera member
|
||||
int cam_idx;
|
||||
float cam_origin[3];
|
||||
float cam_angles[3];
|
||||
|
||||
float pr[16];
|
||||
|
||||
//CVA-related
|
||||
int firstvertex;
|
||||
int numvertices;
|
||||
|
||||
unsigned int texture;
|
||||
msurface_t *surface;
|
||||
|
||||
int sv_entindex;
|
||||
cl_entity_t *ent;
|
||||
bool color;
|
||||
|
||||
struct screen_s *next;
|
||||
}screen_t;
|
||||
|
||||
typedef struct portal_s
|
||||
{
|
||||
int index;
|
||||
bool enabled;
|
||||
bool visible;
|
||||
float origin[3];
|
||||
float angles[3];
|
||||
float normal[3];
|
||||
float radius;
|
||||
float alpha;
|
||||
|
||||
//current camera member
|
||||
int cam_idx;
|
||||
float cam_origin[3];
|
||||
float cam_angles[3];
|
||||
|
||||
float pr[16];
|
||||
|
||||
//CVA-related
|
||||
int firstvertex;
|
||||
int numvertices;
|
||||
|
||||
unsigned int texture;
|
||||
msurface_t *surface;
|
||||
|
||||
int sv_entindex;
|
||||
cl_entity_t *ent; //for brush model mirrors
|
||||
|
||||
struct portal_s *next;
|
||||
}portal_t;
|
||||
|
||||
typedef struct cl_sbe_s
|
||||
{
|
||||
int index;
|
||||
bool initialized;
|
||||
}cl_sbe_t;
|
||||
|
||||
extern cvar_t *r_debug; //show renderer info
|
||||
extern cvar_t *r_shadows; //original HL shadows
|
||||
extern cvar_t *r_mirrors; //mirrors
|
||||
extern cvar_t *r_screens; //screens
|
||||
extern cvar_t *r_portals; //portals
|
||||
|
||||
mirror_t *R_AllocateMirror(msurface_t *surf);
|
||||
void R_FreeMirrors(void);
|
||||
void R_InitMirrors(void);
|
||||
void R_SetupMirrorRenderPass(ref_params_t *pparams);
|
||||
void R_SetupNewMirror(ref_params_t *pparams);
|
||||
void R_NewMirrorRenderPass(void);
|
||||
void R_RenderMirrors(bool trans);
|
||||
void R_InitMirrorsForFrame(void);
|
||||
void R_ResetMirrors(void);
|
||||
void AddMirrorBrushEntity( int idx );
|
||||
void R_DrawMirror(bool trans);
|
||||
|
||||
screen_t *R_AllocateScreen(msurface_t *surf);
|
||||
void R_ResetScreens( void );
|
||||
void R_FreeScreens( void );
|
||||
void R_InitScreens( void );
|
||||
void R_RenderScreens( bool trans );
|
||||
void AddScreenBrushEntity( int idx );
|
||||
void R_SetupScreenRenderPass(ref_params_t *pparams);
|
||||
void R_SetupNewScreen(ref_params_t *pparams);
|
||||
void R_NewScreenRenderPass( void );
|
||||
void R_InitScreensForFrame(void);
|
||||
void R_DrawScreen(bool trans);
|
||||
|
||||
portal_t *R_AllocatePortal(msurface_t *surf);
|
||||
void R_FreePortals(void);
|
||||
void R_InitPortals(void);
|
||||
void R_SetupPortalRenderPass(ref_params_t *pparams);
|
||||
void R_SetupNewPortal(ref_params_t *pparams);
|
||||
void R_NewPortalRenderPass(void);
|
||||
void R_RenderPortals(bool trans);
|
||||
void R_InitPortalsForFrame(void);
|
||||
void R_ResetPortals(void);
|
||||
void AddPortalBrushEntity( int idx );
|
||||
void R_DrawPortal(bool trans);
|
||||
|
||||
//Noise
|
||||
void CreateNoiseTexture3D (float scale);
|
||||
void CreateNoiseTextureDsDt (float scale);
|
||||
|
||||
//Water
|
||||
void CreateWaterShader_ARB(void);
|
||||
void DeleteWaterShader_ARB(void);
|
||||
void BindWaterShader_ARB(mirror_t *mir);
|
||||
void UnbindWaterShader_ARB(void);
|
||||
|
||||
//Black & white screen
|
||||
void CreateScreenShader_ARB(void);
|
||||
void DeleteScreenShader_ARB(void);
|
||||
|
||||
//Logging
|
||||
void logInitLog( char *filename );
|
||||
void logCloseLog();
|
||||
void logPrintOpenGLInformation( void );
|
||||
void logPrint( char *str );
|
||||
void logPrintf( char *fmt, ...);
|
||||
|
||||
extern mirror_t *m_pCurrentMirror;
|
||||
extern screen_t *m_pCurrentScreen;
|
||||
extern portal_t *m_pCurrentPortal;
|
||||
|
||||
//GL state management
|
||||
struct glstate_curstate_t
|
||||
{
|
||||
unsigned char
|
||||
blend : 1,
|
||||
depth_test : 1,
|
||||
: 6;
|
||||
};
|
||||
|
||||
struct glstate_curstagestate_t
|
||||
{
|
||||
unsigned char
|
||||
texture2d : 1,
|
||||
texture3d : 1,
|
||||
: 6;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct glstate_curstate_t curstate;
|
||||
struct glstate_curstagestate_t curstagestate[8]; //assume 8 will be max texture stages
|
||||
unsigned int current_texture_stage;
|
||||
} glstate_t;
|
||||
|
||||
extern glstate_t glstate;
|
||||
|
||||
#define GLSTATE_ENABLE_BLEND if(!glstate.curstate.blend) { glEnable(GL_BLEND); glstate.curstate.blend=1; }
|
||||
#define GLSTATE_ENABLE_DEPTH_TEST if(!glstate.curstate.depth_test) { glEnable(GL_DEPTH_TEST); glstate.curstate.depth_test=1; }
|
||||
#define GLSTATE_ENABLE_TEXTURE if(!glstate.curstagestate[glstate.current_texture_stage].texture2d) { glEnable(GL_TEXTURE_2D); glstate.curstagestate[glstate.current_texture_stage].texture2d=1; }
|
||||
#define GLSTATE_ENABLE_TEXTURE3D if(!glstate.curstagestate[glstate.current_texture_stage].texture3d) { glEnable(GL_TEXTURE_3D); glstate.curstagestate[glstate.current_texture_stage].texture3d=1; }
|
||||
#define GLSTATE_DISABLE_BLEND if(glstate.curstate.blend) { glDisable(GL_BLEND); glstate.curstate.blend=0; }
|
||||
#define GLSTATE_DISABLE_DEPTH_TEST if(glstate.curstate.depth_test) { glDisable(GL_DEPTH_TEST); glstate.curstate.depth_test=0; }
|
||||
#define GLSTATE_DISABLE_TEXTURE if(glstate.curstagestate[glstate.current_texture_stage].texture2d) { glDisable(GL_TEXTURE_2D); glstate.curstagestate[glstate.current_texture_stage].texture2d=0; }
|
||||
#define GLSTATE_DISABLE_TEXTURE3D if(glstate.curstagestate[glstate.current_texture_stage].texture3d) { glDisable(GL_TEXTURE_3D); glstate.curstagestate[glstate.current_texture_stage].texture3d=0; }
|
||||
|
||||
void GL_SelectTexture( GLenum mode );
|
||||
|
||||
//client sprite renderer
|
||||
void R_DrawSprite ( cl_entity_t *e, HSPRITE m_hSprite );
|
||||
mspriteframe_t *R_GetSpriteFrame (model_t *mod, int frame);
|
|
@ -0,0 +1,960 @@
|
|||
#include "hud.h"
|
||||
#include "r_main.h"
|
||||
#include "r_util.h"
|
||||
#include "const.h"
|
||||
#include "entity_state.h"
|
||||
#include "event_api.h"
|
||||
#include "cl_entity.h"
|
||||
#include "triangleapi.h"
|
||||
#include "r_particle.h"
|
||||
#include "com_model.h"
|
||||
#include "pmtrace.h" // for contents and traceline
|
||||
#include "pm_defs.h"
|
||||
|
||||
ParticleSystemManager* g_pParticleSystems = NULL;
|
||||
|
||||
void CreateAurora( int idx, char *file )
|
||||
{
|
||||
ParticleSystem *pSystem = new ParticleSystem( idx, file );
|
||||
g_pParticleSystems->AddSystem(pSystem);
|
||||
}
|
||||
|
||||
|
||||
ParticleSystemManager::ParticleSystemManager( void )
|
||||
{
|
||||
m_pFirstSystem = NULL;
|
||||
}
|
||||
|
||||
ParticleSystemManager::~ParticleSystemManager( void )
|
||||
{
|
||||
ClearSystems();
|
||||
}
|
||||
|
||||
void ParticleSystemManager::AddSystem( ParticleSystem* pNewSystem )
|
||||
{
|
||||
pNewSystem->m_pNextSystem = m_pFirstSystem;
|
||||
m_pFirstSystem = pNewSystem;
|
||||
}
|
||||
|
||||
ParticleSystem *ParticleSystemManager::FindSystem( cl_entity_t* pEntity )
|
||||
{
|
||||
for (ParticleSystem *pSys = m_pFirstSystem; pSys; pSys = pSys->m_pNextSystem)
|
||||
{
|
||||
if (pEntity->index == pSys->m_iEntIndex) return pSys;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ParticleSystemManager::UpdateSystems( void )
|
||||
{
|
||||
static float fOldTime, fTime;
|
||||
fOldTime = fTime;
|
||||
fTime = gEngfuncs.GetClientTime();
|
||||
float frametime = fTime - fOldTime;
|
||||
|
||||
ParticleSystem* pSystem;
|
||||
ParticleSystem* pLast = NULL;
|
||||
ParticleSystem*pLastSorted = NULL;
|
||||
|
||||
pSystem = m_pFirstSystem;
|
||||
while( pSystem )
|
||||
{
|
||||
if( pSystem->UpdateSystem(frametime))
|
||||
{
|
||||
pSystem->DrawSystem();
|
||||
pLast = pSystem;
|
||||
pSystem = pSystem->m_pNextSystem;
|
||||
}
|
||||
else // delete this system
|
||||
{
|
||||
if (pLast)
|
||||
{
|
||||
pLast->m_pNextSystem = pSystem->m_pNextSystem;
|
||||
delete pSystem;
|
||||
pSystem = pLast->m_pNextSystem;
|
||||
}
|
||||
else // deleting the first system
|
||||
{
|
||||
m_pFirstSystem = pSystem->m_pNextSystem;
|
||||
delete pSystem;
|
||||
pSystem = m_pFirstSystem;
|
||||
}
|
||||
}
|
||||
}
|
||||
gEngfuncs.pTriAPI->RenderMode(kRenderNormal);
|
||||
}
|
||||
|
||||
void ParticleSystemManager::ClearSystems( void )
|
||||
{
|
||||
ParticleSystem* pSystem = m_pFirstSystem;
|
||||
ParticleSystem* pTemp;
|
||||
|
||||
while( pSystem )
|
||||
{
|
||||
pTemp = pSystem->m_pNextSystem;
|
||||
delete pSystem;
|
||||
pSystem = pTemp;
|
||||
}
|
||||
|
||||
m_pFirstSystem = NULL;
|
||||
}
|
||||
|
||||
float ParticleSystem::c_fCosTable[360 + 90];
|
||||
bool ParticleSystem::c_bCosTableInit = false;
|
||||
|
||||
ParticleType::ParticleType( ParticleType *pNext )
|
||||
{
|
||||
m_pSprayType = m_pOverlayType = NULL;
|
||||
m_StartAngle = RandomRange(45);
|
||||
m_hSprite = 0;
|
||||
m_pNext = pNext;
|
||||
m_szName[0] = 0;
|
||||
m_StartRed = m_StartGreen = m_StartBlue = m_StartAlpha = RandomRange(1);
|
||||
m_EndRed = m_EndGreen = m_EndBlue = m_EndAlpha = RandomRange(1);
|
||||
m_iRenderMode = kRenderTransAdd;
|
||||
m_iDrawCond = 0;
|
||||
m_bEndFrame = false;
|
||||
|
||||
m_bIsDefined = false;
|
||||
m_iCollision = 0;
|
||||
}
|
||||
|
||||
particle* ParticleType::CreateParticle(ParticleSystem *pSys)//particle *pPart)
|
||||
{
|
||||
if (!pSys) return NULL;
|
||||
|
||||
particle *pPart = pSys->ActivateParticle();
|
||||
if (!pPart) return NULL;
|
||||
|
||||
pPart->age = 0.0;
|
||||
pPart->age_death = m_Life.GetInstance();
|
||||
|
||||
InitParticle(pPart, pSys);
|
||||
|
||||
return pPart;
|
||||
}
|
||||
|
||||
void ParticleType::InitParticle(particle *pPart, ParticleSystem *pSys)
|
||||
{
|
||||
float fLifeRecip = 1/pPart->age_death;
|
||||
|
||||
particle *pOverlay = NULL;
|
||||
if (m_pOverlayType)
|
||||
{
|
||||
// create an overlay for this particle
|
||||
pOverlay = pSys->ActivateParticle();
|
||||
if (pOverlay)
|
||||
{
|
||||
pOverlay->age = pPart->age;
|
||||
pOverlay->age_death = pPart->age_death;
|
||||
m_pOverlayType->InitParticle(pOverlay, pSys);
|
||||
}
|
||||
}
|
||||
|
||||
pPart->m_pOverlay = pOverlay;
|
||||
|
||||
pPart->pType = this;
|
||||
pPart->velocity[0] = pPart->velocity[1] = pPart->velocity[2] = 0;
|
||||
pPart->accel[0] = pPart->accel[1] = 0;
|
||||
pPart->accel[2] = m_Gravity.GetInstance();
|
||||
pPart->m_iEntIndex = 0;
|
||||
|
||||
if (m_pSprayType)
|
||||
{
|
||||
pPart->age_spray = 1/m_SprayRate.GetInstance();
|
||||
}
|
||||
else
|
||||
{
|
||||
pPart->age_spray = 0.0f;
|
||||
}
|
||||
|
||||
pPart->m_fSize = m_StartSize.GetInstance();
|
||||
|
||||
if (m_EndSize.IsDefined())
|
||||
pPart->m_fSizeStep = m_EndSize.GetOffset(pPart->m_fSize) * fLifeRecip;
|
||||
else
|
||||
pPart->m_fSizeStep = m_SizeDelta.GetInstance();
|
||||
//pPart->m_fSizeStep = m_EndSize.GetOffset(pPart->m_fSize) * fLifeRecip;
|
||||
|
||||
pPart->frame = m_StartFrame.GetInstance();
|
||||
if (m_EndFrame.IsDefined())
|
||||
pPart->m_fFrameStep = m_EndFrame.GetOffset(pPart->frame) * fLifeRecip;
|
||||
else pPart->m_fFrameStep = m_FrameRate.GetInstance();
|
||||
|
||||
pPart->m_fAlpha = m_StartAlpha.GetInstance();
|
||||
pPart->m_fAlphaStep = m_EndAlpha.GetOffset(pPart->m_fAlpha) * fLifeRecip;
|
||||
pPart->m_fRed = m_StartRed.GetInstance();
|
||||
pPart->m_fRedStep = m_EndRed.GetOffset(pPart->m_fRed) * fLifeRecip;
|
||||
pPart->m_fGreen = m_StartGreen.GetInstance();
|
||||
pPart->m_fGreenStep = m_EndGreen.GetOffset(pPart->m_fGreen) * fLifeRecip;
|
||||
pPart->m_fBlue = m_StartBlue.GetInstance();
|
||||
pPart->m_fBlueStep = m_EndBlue.GetOffset(pPart->m_fBlue) * fLifeRecip;
|
||||
|
||||
pPart->m_fAngle = m_StartAngle.GetInstance();
|
||||
pPart->m_fAngleStep = m_AngleDelta.GetInstance();
|
||||
|
||||
pPart->m_fDrag = m_Drag.GetInstance();
|
||||
|
||||
float fWindStrength = m_WindStrength.GetInstance();
|
||||
float fWindYaw = m_WindYaw.GetInstance();
|
||||
pPart->m_vecWind.x = fWindStrength*ParticleSystem::CosLookup(fWindYaw);
|
||||
pPart->m_vecWind.y = fWindStrength*ParticleSystem::SinLookup(fWindYaw);
|
||||
pPart->m_vecWind.z = 0;
|
||||
}
|
||||
|
||||
//============================================
|
||||
|
||||
|
||||
RandomRange::RandomRange( char *szToken )
|
||||
{
|
||||
char *cOneDot = NULL;
|
||||
m_bDefined = true;
|
||||
|
||||
for (char *c = szToken; *c; c++)
|
||||
{
|
||||
if (*c == '.')
|
||||
{
|
||||
if (cOneDot != NULL)
|
||||
{
|
||||
// found two dots in a row - it's a range
|
||||
|
||||
*cOneDot = 0; // null terminate the first number
|
||||
m_fMin = atof(szToken); // parse the first number
|
||||
*cOneDot = '.'; // change it back, just in case
|
||||
c++;
|
||||
m_fMax = atof(c); // parse the second number
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
cOneDot = c;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cOneDot = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// no range, just record the number
|
||||
m_fMin = m_fMax = atof(szToken);
|
||||
}
|
||||
|
||||
//============================================
|
||||
|
||||
ParticleSystem::ParticleSystem( int iEntIndex, char *szFilename )
|
||||
{
|
||||
int iParticles = 100; // default
|
||||
|
||||
m_iEntIndex = iEntIndex;
|
||||
m_pNextSystem = NULL;
|
||||
m_pFirstType = NULL;
|
||||
if (!c_bCosTableInit)
|
||||
{
|
||||
for (int i = 0; i < 360+90; i++)
|
||||
{
|
||||
c_fCosTable[i] = cos(i*M_PI/180.0);
|
||||
}
|
||||
c_bCosTableInit = true;
|
||||
}
|
||||
|
||||
char *szFile = (char *)gEngfuncs.COM_LoadFile( szFilename, 5, NULL);
|
||||
char szToken[1024];
|
||||
|
||||
if (!szFile)
|
||||
{
|
||||
Msg("Particle %s not found.\n", szFilename );
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
szFile = gEngfuncs.COM_ParseFile(szFile, szToken);
|
||||
|
||||
while (szFile)
|
||||
{
|
||||
if ( !stricmp( szToken, "particles" ) )
|
||||
{
|
||||
szFile = gEngfuncs.COM_ParseFile(szFile,szToken);
|
||||
iParticles = atof(szToken);
|
||||
}
|
||||
else if ( !stricmp( szToken, "maintype" ) )
|
||||
{
|
||||
szFile = gEngfuncs.COM_ParseFile(szFile,szToken);
|
||||
m_pMainType = AddPlaceholderType(szToken);
|
||||
}
|
||||
else if ( !stricmp( szToken, "attachment" ) )
|
||||
{
|
||||
szFile = gEngfuncs.COM_ParseFile(szFile,szToken);
|
||||
m_iEntAttachment = atof(szToken);
|
||||
}
|
||||
else if ( !stricmp( szToken, "killcondition" ) )
|
||||
{
|
||||
szFile = gEngfuncs.COM_ParseFile(szFile,szToken);
|
||||
if ( !stricmp( szToken, "empty" ) )
|
||||
{
|
||||
m_iKillCondition = CONTENTS_EMPTY;
|
||||
}
|
||||
else if ( !stricmp( szToken, "water" ) )
|
||||
{
|
||||
m_iKillCondition = CONTENTS_WATER;
|
||||
}
|
||||
else if ( !stricmp( szToken, "solid" ) )
|
||||
{
|
||||
m_iKillCondition = CONTENTS_SOLID;
|
||||
}
|
||||
}
|
||||
else if ( !stricmp( szToken, "{" ) )
|
||||
{
|
||||
// parse new type
|
||||
this->ParseType( szFile ); // parses the type, moves the file pointer
|
||||
}
|
||||
|
||||
szFile = gEngfuncs.COM_ParseFile(szFile, szToken);
|
||||
}
|
||||
}
|
||||
|
||||
gEngfuncs.COM_FreeFile( szFile );
|
||||
AllocateParticles(iParticles);
|
||||
}
|
||||
|
||||
void ParticleSystem::AllocateParticles( int iParticles )
|
||||
{
|
||||
m_pAllParticles = new particle[iParticles];
|
||||
m_pFreeParticle = m_pAllParticles;
|
||||
m_pActiveParticle = NULL;
|
||||
m_pMainParticle = NULL;
|
||||
|
||||
// initialise the linked list
|
||||
particle *pLast = m_pAllParticles;
|
||||
particle *pParticle = pLast+1;
|
||||
|
||||
for( int i = 1; i < iParticles; i++ )
|
||||
{
|
||||
pLast->nextpart = pParticle;
|
||||
|
||||
pLast = pParticle;
|
||||
pParticle++;
|
||||
}
|
||||
pLast->nextpart = NULL;
|
||||
}
|
||||
|
||||
ParticleSystem::~ParticleSystem( void )
|
||||
{
|
||||
delete[] m_pAllParticles;
|
||||
|
||||
ParticleType *pType = m_pFirstType;
|
||||
ParticleType *pNext;
|
||||
while (pType)
|
||||
{
|
||||
pNext = pType->m_pNext;
|
||||
delete pType;
|
||||
pType = pNext;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// returns the ParticleType with the given name, if there is one
|
||||
ParticleType *ParticleSystem::GetType( const char *szName )
|
||||
{
|
||||
for (ParticleType *pType = m_pFirstType; pType; pType = pType->m_pNext)
|
||||
{
|
||||
if (!stricmp(pType->m_szName, szName))
|
||||
return pType;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ParticleType *ParticleSystem::AddPlaceholderType( const char *szName )
|
||||
{
|
||||
m_pFirstType = new ParticleType( m_pFirstType );
|
||||
strncpy(m_pFirstType->m_szName, szName, sizeof(m_pFirstType->m_szName) );
|
||||
return m_pFirstType;
|
||||
}
|
||||
|
||||
// creates a new particletype from the given file
|
||||
// NB: this changes the value of szFile.
|
||||
ParticleType *ParticleSystem::ParseType( char *&szFile )
|
||||
{
|
||||
ParticleType *pType = new ParticleType();
|
||||
|
||||
// parse the .aur file
|
||||
char szToken[1024];
|
||||
|
||||
szFile = gEngfuncs.COM_ParseFile(szFile, szToken);
|
||||
while ( stricmp( szToken, "}" ) )
|
||||
{
|
||||
if (!szFile)
|
||||
break;
|
||||
|
||||
if ( !stricmp( szToken, "name" ) )
|
||||
{
|
||||
szFile = gEngfuncs.COM_ParseFile(szFile,szToken);
|
||||
strncpy(pType->m_szName, szToken, sizeof(pType->m_szName) );
|
||||
|
||||
ParticleType *pTemp = GetType(szToken);
|
||||
if (pTemp)
|
||||
{
|
||||
// there's already a type with this name
|
||||
if (pTemp->m_bIsDefined)
|
||||
Msg("Warning: Particle type %s is defined more than once!\n", szToken);
|
||||
|
||||
// copy all our data into the existing type, throw away the type we were making
|
||||
*pTemp = *pType;
|
||||
delete pType;
|
||||
pType = pTemp;
|
||||
pType->m_bIsDefined = true; // record the fact that it's defined, so we won't need to add it to the list
|
||||
}
|
||||
}
|
||||
else if ( !stricmp( szToken, "gravity" ) )
|
||||
{
|
||||
szFile = gEngfuncs.COM_ParseFile(szFile,szToken);
|
||||
pType->m_Gravity = RandomRange( szToken );
|
||||
}
|
||||
else if ( !stricmp( szToken, "windyaw" ) )
|
||||
{
|
||||
szFile = gEngfuncs.COM_ParseFile(szFile,szToken);
|
||||
pType->m_WindYaw = RandomRange( szToken );
|
||||
}
|
||||
else if ( !stricmp( szToken, "windstrength" ) )
|
||||
{
|
||||
szFile = gEngfuncs.COM_ParseFile(szFile,szToken);
|
||||
pType->m_WindStrength = RandomRange( szToken );
|
||||
}
|
||||
else if ( !stricmp( szToken, "sprite" ) )
|
||||
{
|
||||
szFile = gEngfuncs.COM_ParseFile(szFile,szToken);
|
||||
pType->m_hSprite = SPR_Load( szToken );
|
||||
}
|
||||
else if ( !stricmp( szToken, "startalpha" ) )
|
||||
{
|
||||
szFile = gEngfuncs.COM_ParseFile(szFile,szToken);
|
||||
pType->m_StartAlpha = RandomRange( szToken );
|
||||
}
|
||||
else if ( !stricmp( szToken, "endalpha" ) )
|
||||
{
|
||||
szFile = gEngfuncs.COM_ParseFile(szFile,szToken);
|
||||
pType->m_EndAlpha = RandomRange( szToken );
|
||||
}
|
||||
else if ( !stricmp( szToken, "startred" ) )
|
||||
{
|
||||
szFile = gEngfuncs.COM_ParseFile(szFile,szToken);
|
||||
pType->m_StartRed = RandomRange( szToken );
|
||||
}
|
||||
else if ( !stricmp( szToken, "endred" ) )
|
||||
{
|
||||
szFile = gEngfuncs.COM_ParseFile(szFile,szToken);
|
||||
pType->m_EndRed = RandomRange( szToken );
|
||||
}
|
||||
else if ( !stricmp( szToken, "startgreen" ) )
|
||||
{
|
||||
szFile = gEngfuncs.COM_ParseFile(szFile,szToken);
|
||||
pType->m_StartGreen = RandomRange( szToken );
|
||||
}
|
||||
else if ( !stricmp( szToken, "endgreen" ) )
|
||||
{
|
||||
szFile = gEngfuncs.COM_ParseFile(szFile,szToken);
|
||||
pType->m_EndGreen = RandomRange( szToken );
|
||||
}
|
||||
else if ( !stricmp( szToken, "startblue" ) )
|
||||
{
|
||||
szFile = gEngfuncs.COM_ParseFile(szFile,szToken);
|
||||
pType->m_StartBlue = RandomRange( szToken );
|
||||
}
|
||||
else if ( !stricmp( szToken, "endblue" ) )
|
||||
{
|
||||
szFile = gEngfuncs.COM_ParseFile(szFile,szToken);
|
||||
pType->m_EndBlue = RandomRange( szToken );
|
||||
}
|
||||
else if ( !stricmp( szToken, "startsize" ) )
|
||||
{
|
||||
szFile = gEngfuncs.COM_ParseFile(szFile,szToken);
|
||||
pType->m_StartSize = RandomRange( szToken );
|
||||
}
|
||||
else if ( !stricmp( szToken, "sizedelta" ) )
|
||||
{
|
||||
szFile = gEngfuncs.COM_ParseFile(szFile,szToken);
|
||||
pType->m_SizeDelta = RandomRange( szToken );
|
||||
}
|
||||
else if ( !stricmp( szToken, "endsize" ) )
|
||||
{
|
||||
szFile = gEngfuncs.COM_ParseFile(szFile,szToken);
|
||||
pType->m_EndSize = RandomRange( szToken );
|
||||
}
|
||||
else if ( !stricmp( szToken, "startangle" ) )
|
||||
{
|
||||
szFile = gEngfuncs.COM_ParseFile(szFile,szToken);
|
||||
pType->m_StartAngle = RandomRange( szToken );
|
||||
}
|
||||
else if ( !stricmp( szToken, "angledelta" ) )
|
||||
{
|
||||
szFile = gEngfuncs.COM_ParseFile(szFile,szToken);
|
||||
pType->m_AngleDelta = RandomRange( szToken );
|
||||
}
|
||||
else if ( !stricmp( szToken, "startframe" ) )
|
||||
{
|
||||
szFile = gEngfuncs.COM_ParseFile(szFile,szToken);
|
||||
pType->m_StartFrame = RandomRange( szToken );
|
||||
}
|
||||
else if ( !stricmp( szToken, "endframe" ) )
|
||||
{
|
||||
szFile = gEngfuncs.COM_ParseFile(szFile,szToken);
|
||||
pType->m_EndFrame = RandomRange( szToken );
|
||||
pType->m_bEndFrame = true;
|
||||
}
|
||||
else if ( !stricmp( szToken, "framerate" ) )
|
||||
{
|
||||
szFile = gEngfuncs.COM_ParseFile(szFile,szToken);
|
||||
pType->m_FrameRate = RandomRange( szToken );
|
||||
}
|
||||
else if ( !stricmp( szToken, "lifetime" ) )
|
||||
{
|
||||
szFile = gEngfuncs.COM_ParseFile(szFile,szToken);
|
||||
pType->m_Life = RandomRange( szToken );
|
||||
}
|
||||
else if ( !stricmp( szToken, "spraytype" ) )
|
||||
{
|
||||
szFile = gEngfuncs.COM_ParseFile(szFile,szToken);
|
||||
ParticleType *pTemp = GetType(szToken);
|
||||
|
||||
if (pTemp) pType->m_pSprayType = pTemp;
|
||||
else pType->m_pSprayType = AddPlaceholderType(szToken);
|
||||
}
|
||||
else if ( !stricmp( szToken, "overlaytype" ) )
|
||||
{
|
||||
szFile = gEngfuncs.COM_ParseFile(szFile,szToken);
|
||||
ParticleType *pTemp = GetType(szToken);
|
||||
|
||||
if (pTemp) pType->m_pOverlayType = pTemp;
|
||||
else pType->m_pOverlayType = AddPlaceholderType(szToken);
|
||||
}
|
||||
else if ( !stricmp( szToken, "sprayrate" ) )
|
||||
{
|
||||
szFile = gEngfuncs.COM_ParseFile(szFile,szToken);
|
||||
pType->m_SprayRate = RandomRange( szToken );
|
||||
}
|
||||
else if ( !stricmp( szToken, "sprayforce" ) )
|
||||
{
|
||||
szFile = gEngfuncs.COM_ParseFile(szFile,szToken);
|
||||
pType->m_SprayForce = RandomRange( szToken );
|
||||
}
|
||||
else if ( !stricmp( szToken, "spraypitch" ) )
|
||||
{
|
||||
szFile = gEngfuncs.COM_ParseFile(szFile,szToken);
|
||||
pType->m_SprayPitch = RandomRange( szToken );
|
||||
}
|
||||
else if ( !stricmp( szToken, "sprayyaw" ) )
|
||||
{
|
||||
szFile = gEngfuncs.COM_ParseFile(szFile,szToken);
|
||||
pType->m_SprayYaw = RandomRange( szToken );
|
||||
}
|
||||
else if ( !stricmp( szToken, "drag" ) )
|
||||
{
|
||||
szFile = gEngfuncs.COM_ParseFile(szFile,szToken);
|
||||
pType->m_Drag = RandomRange( szToken );
|
||||
}
|
||||
else if ( !stricmp( szToken, "bounce" ) )
|
||||
{
|
||||
szFile = gEngfuncs.COM_ParseFile(szFile,szToken);
|
||||
pType->m_Bounce = RandomRange( szToken );
|
||||
if (pType->m_Bounce.m_fMin != 0 || pType->m_Bounce.m_fMax != 0)
|
||||
pType->m_bBouncing = true;
|
||||
}
|
||||
else if ( !stricmp( szToken, "bouncefriction" ) )
|
||||
{
|
||||
szFile = gEngfuncs.COM_ParseFile(szFile,szToken);
|
||||
pType->m_BounceFriction = RandomRange( szToken );
|
||||
}
|
||||
else if ( !stricmp( szToken, "rendermode" ) )
|
||||
{
|
||||
szFile = gEngfuncs.COM_ParseFile(szFile,szToken);
|
||||
if ( !stricmp( szToken, "additive" ) )
|
||||
{
|
||||
pType->m_iRenderMode = kRenderTransAdd;
|
||||
}
|
||||
else if ( !stricmp( szToken, "solid" ) )
|
||||
{
|
||||
pType->m_iRenderMode = kRenderTransAlpha;
|
||||
}
|
||||
else if ( !stricmp( szToken, "texture" ) )
|
||||
{
|
||||
pType->m_iRenderMode = kRenderTransTexture;
|
||||
}
|
||||
else if ( !stricmp( szToken, "color" ) )
|
||||
{
|
||||
pType->m_iRenderMode = kRenderTransColor;
|
||||
}
|
||||
}
|
||||
else if ( !stricmp( szToken, "drawcondition" ) )
|
||||
{
|
||||
szFile = gEngfuncs.COM_ParseFile(szFile,szToken);
|
||||
if ( !stricmp( szToken, "empty" ) )
|
||||
{
|
||||
pType->m_iDrawCond = CONTENTS_EMPTY;
|
||||
}
|
||||
else if ( !stricmp( szToken, "water" ) )
|
||||
{
|
||||
pType->m_iDrawCond = CONTENTS_WATER;
|
||||
}
|
||||
else if ( !stricmp( szToken, "solid" ) )
|
||||
{
|
||||
pType->m_iDrawCond = CONTENTS_SOLID;
|
||||
}
|
||||
else if ( !stricmp( szToken, "special" ) || !stricmp( szToken, "special1" ) )
|
||||
{
|
||||
pType->m_iDrawCond = CONTENT_SPECIAL1;
|
||||
}
|
||||
else if ( !stricmp( szToken, "special2" ) )
|
||||
{
|
||||
pType->m_iDrawCond = CONTENT_SPECIAL2;
|
||||
}
|
||||
else if ( !stricmp( szToken, "special3" ) )
|
||||
{
|
||||
pType->m_iDrawCond = CONTENT_SPECIAL3;
|
||||
}
|
||||
}
|
||||
else if ( !stricmp( szToken, "collision" ) )
|
||||
{
|
||||
szFile = gEngfuncs.COM_ParseFile(szFile,szToken);
|
||||
if ( !stricmp( szToken, "none" ) )
|
||||
{
|
||||
pType->m_iCollision = COLLISION_NONE;
|
||||
}
|
||||
else if ( !stricmp( szToken, "die" ) )
|
||||
{
|
||||
pType->m_iCollision = COLLISION_DIE;
|
||||
}
|
||||
else if ( !stricmp( szToken, "bounce" ) )
|
||||
{
|
||||
pType->m_iCollision = COLLISION_BOUNCE;
|
||||
}
|
||||
}
|
||||
// get the next token
|
||||
szFile = gEngfuncs.COM_ParseFile(szFile, szToken);
|
||||
}
|
||||
|
||||
if (!pType->m_bIsDefined)
|
||||
{
|
||||
// if this is a newly-defined type, we need to add it to the list
|
||||
pType->m_pNext = m_pFirstType;
|
||||
m_pFirstType = pType;
|
||||
pType->m_bIsDefined = true;
|
||||
}
|
||||
|
||||
return pType;
|
||||
}
|
||||
|
||||
particle *ParticleSystem::ActivateParticle()
|
||||
{
|
||||
particle* pActivated = m_pFreeParticle;
|
||||
if (pActivated)
|
||||
{
|
||||
m_pFreeParticle = pActivated->nextpart;
|
||||
pActivated->nextpart = m_pActiveParticle;
|
||||
m_pActiveParticle = pActivated;
|
||||
}
|
||||
return pActivated;
|
||||
}
|
||||
|
||||
extern vec3_t v_origin;
|
||||
|
||||
void ParticleSystem::CalculateDistance()
|
||||
{
|
||||
if (!m_pActiveParticle)
|
||||
return;
|
||||
|
||||
vec3_t offset = v_origin - m_pActiveParticle->origin; // just pick one
|
||||
m_fViewerDist = offset[0]*offset[0] + offset[1]*offset[1] + offset[2]*offset[2];
|
||||
}
|
||||
|
||||
|
||||
bool ParticleSystem::UpdateSystem( float frametime )
|
||||
{
|
||||
// the entity emitting this system
|
||||
cl_entity_t *source = UTIL_GetClientEntityWithServerIndex( m_iEntIndex );
|
||||
if(!source) return false;
|
||||
|
||||
// Don't update if the system is outside the player's PVS.
|
||||
if (source->curstate.msg_time < gEngfuncs.GetClientTime())
|
||||
{ //remove particles
|
||||
enable = 0;
|
||||
}
|
||||
else enable = (source->curstate.renderfx == kRenderFxAurora);
|
||||
//check for contents to remove
|
||||
if(m_iKillCondition == gEngfuncs.PM_PointContents(source->curstate.origin, NULL))
|
||||
{
|
||||
enable = 0;
|
||||
}
|
||||
if (m_pMainParticle == NULL)
|
||||
{
|
||||
if (enable)
|
||||
{
|
||||
ParticleType *pType = m_pMainType;
|
||||
if (pType)
|
||||
{
|
||||
m_pMainParticle = pType->CreateParticle(this);//m_pMainParticle);
|
||||
if (m_pMainParticle)
|
||||
{
|
||||
m_pMainParticle->m_iEntIndex = m_iEntIndex;
|
||||
m_pMainParticle->age_death = -1; // never die
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!enable)
|
||||
{
|
||||
m_pMainParticle->age_death = 0; // die now
|
||||
m_pMainParticle = NULL;
|
||||
}
|
||||
|
||||
particle* pParticle = m_pActiveParticle;
|
||||
particle* pLast = NULL;
|
||||
|
||||
while( pParticle )
|
||||
{
|
||||
if( UpdateParticle( pParticle, frametime ) )
|
||||
{
|
||||
pLast = pParticle;
|
||||
pParticle = pParticle->nextpart;
|
||||
}
|
||||
else // deactivate it
|
||||
{
|
||||
if (pLast)
|
||||
{
|
||||
pLast->nextpart = pParticle->nextpart;
|
||||
pParticle->nextpart = m_pFreeParticle;
|
||||
m_pFreeParticle = pParticle;
|
||||
pParticle = pLast->nextpart;
|
||||
}
|
||||
else // deactivate the first particle in the list
|
||||
{
|
||||
m_pActiveParticle = pParticle->nextpart;
|
||||
pParticle->nextpart = m_pFreeParticle;
|
||||
m_pFreeParticle = pParticle;
|
||||
pParticle = m_pActiveParticle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
void ParticleSystem::DrawSystem()
|
||||
{
|
||||
vec3_t normal, forward, right, up;
|
||||
|
||||
if(g_HardwareCapable)//merge particle pos for openGL
|
||||
{
|
||||
double r_world_matrix[16];
|
||||
glGetDoublev (GL_MODELVIEW_MATRIX, r_world_matrix);
|
||||
|
||||
right.x = r_world_matrix[0];
|
||||
right.y = r_world_matrix[4];
|
||||
right.z = r_world_matrix[8];
|
||||
|
||||
up.x = r_world_matrix[1];
|
||||
up.y = r_world_matrix[5];
|
||||
up.z = r_world_matrix[9];
|
||||
}
|
||||
else //otherwise
|
||||
{
|
||||
gEngfuncs.GetViewAngles((float*)normal);
|
||||
AngleVectors(normal, forward, right, up);
|
||||
}
|
||||
particle* pParticle = m_pActiveParticle;
|
||||
for( pParticle = m_pActiveParticle; pParticle; pParticle = pParticle->nextpart )
|
||||
{
|
||||
DrawParticle( pParticle, right, up );
|
||||
}
|
||||
}
|
||||
|
||||
bool ParticleSystem::ParticleIsVisible( particle* part )
|
||||
{
|
||||
float dv[3];
|
||||
bool visible = true;
|
||||
VectorSubtract(part->origin, v_origin, dv);
|
||||
float d = Length(dv);
|
||||
|
||||
if (fabs(d) > 36.0f)
|
||||
{
|
||||
visible = (R_SphereInFrustum(part->origin, 100 ) > 0);
|
||||
}
|
||||
return visible;
|
||||
}
|
||||
|
||||
bool ParticleSystem::UpdateParticle(particle *part, float frametime)
|
||||
{
|
||||
if (frametime == 0 ) return true;
|
||||
part->age += frametime;
|
||||
|
||||
cl_entity_t *source = UTIL_GetClientEntityWithServerIndex( m_iEntIndex );
|
||||
|
||||
// is this particle bound to an entity?
|
||||
if (part->m_iEntIndex)
|
||||
{
|
||||
if (enable)
|
||||
{
|
||||
if(m_iEntAttachment)
|
||||
{
|
||||
part->velocity = (source->attachment[m_iEntAttachment - 1] - part->origin)/frametime;
|
||||
part->origin = source->attachment[m_iEntAttachment - 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
part->velocity = (source->curstate.origin - part->origin)/frametime;
|
||||
part->origin = source->curstate.origin;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// entity is switched off, die
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// not tied to an entity, check whether it's time to die
|
||||
if (part->age_death >= 0 && part->age > part->age_death)
|
||||
return false;
|
||||
|
||||
// apply acceleration and velocity
|
||||
vec3_t vecOldPos = part->origin;
|
||||
if (part->m_fDrag)
|
||||
VectorMA(part->velocity, -part->m_fDrag*frametime, part->velocity - part->m_vecWind, part->velocity);
|
||||
VectorMA(part->velocity, frametime, part->accel, part->velocity);
|
||||
VectorMA(part->origin, frametime, part->velocity, part->origin);
|
||||
|
||||
if (part->pType->m_bBouncing)
|
||||
{
|
||||
vec3_t vecTarget;
|
||||
VectorMA(part->origin, frametime, part->velocity, vecTarget);
|
||||
pmtrace_t *tr = gEngfuncs.PM_TraceLine( part->origin, vecTarget, PM_TRACELINE_PHYSENTSONLY, 2, -1 );
|
||||
if (tr->fraction < 1)
|
||||
{
|
||||
part->origin = tr->endpos;
|
||||
float bounceforce = DotProduct(tr->plane.normal, part->velocity);
|
||||
float newspeed = (1 - part->pType->m_BounceFriction.GetInstance());
|
||||
part->velocity = part->velocity * newspeed;
|
||||
VectorMA(part->velocity, -bounceforce*(newspeed+part->pType->m_Bounce.GetInstance()), tr->plane.normal, part->velocity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// spray children
|
||||
if (part->age_spray && part->age > part->age_spray)
|
||||
{
|
||||
part->age_spray = part->age + 1/part->pType->m_SprayRate.GetInstance();
|
||||
|
||||
//particle *pChild = ActivateParticle();
|
||||
if (part->pType->m_pSprayType)
|
||||
{
|
||||
particle *pChild = part->pType->m_pSprayType->CreateParticle(this);
|
||||
if (pChild)
|
||||
{
|
||||
pChild->origin = part->origin;
|
||||
float fSprayForce = part->pType->m_SprayForce.GetInstance();
|
||||
pChild->velocity = part->velocity;
|
||||
if (fSprayForce)
|
||||
{
|
||||
float fSprayPitch = part->pType->m_SprayPitch.GetInstance() - source->curstate.angles.x;
|
||||
float fSprayYaw = part->pType->m_SprayYaw.GetInstance() - source->curstate.angles.y;
|
||||
float fSprayRoll = source->curstate.angles.z;
|
||||
float fForceCosPitch = fSprayForce*CosLookup(fSprayPitch);
|
||||
pChild->velocity.x += CosLookup(fSprayYaw) * fForceCosPitch;
|
||||
pChild->velocity.y += SinLookup(fSprayYaw) * fForceCosPitch + SinLookup(fSprayYaw) * fSprayForce * SinLookup(fSprayRoll);
|
||||
pChild->velocity.z -= SinLookup(fSprayPitch) * fSprayForce * CosLookup(fSprayRoll);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
part->m_fSize += part->m_fSizeStep * frametime;
|
||||
part->m_fAlpha += part->m_fAlphaStep * frametime;
|
||||
part->m_fRed += part->m_fRedStep * frametime;
|
||||
part->m_fGreen += part->m_fGreenStep * frametime;
|
||||
part->m_fBlue += part->m_fBlueStep * frametime;
|
||||
part->frame += part->m_fFrameStep * frametime;
|
||||
if (part->m_fAngleStep)
|
||||
{
|
||||
part->m_fAngle += part->m_fAngleStep * frametime;
|
||||
while (part->m_fAngle < 0) part->m_fAngle += 360;
|
||||
while (part->m_fAngle > 360) part->m_fAngle -= 360;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ParticleSystem::DrawParticle(particle *part, vec3_t &right, vec3_t &up)
|
||||
{
|
||||
float fSize = part->m_fSize;
|
||||
vec3_t point1,point2,point3,point4;
|
||||
vec3_t origin = part->origin;
|
||||
|
||||
// nothing to draw?
|
||||
if (fSize == 0) return;
|
||||
|
||||
//frustrum visible check
|
||||
if(!ParticleIsVisible(part)) return;
|
||||
|
||||
float fCosSize = CosLookup(part->m_fAngle)*fSize;
|
||||
float fSinSize = SinLookup(part->m_fAngle)*fSize;
|
||||
|
||||
// calculate the four corners of the sprite
|
||||
VectorMA (origin, fSinSize, up, point1);
|
||||
VectorMA (point1, -fCosSize, right, point1);
|
||||
|
||||
VectorMA (origin, fCosSize, up, point2);
|
||||
VectorMA (point2, fSinSize, right, point2);
|
||||
|
||||
VectorMA (origin, -fSinSize, up, point3);
|
||||
VectorMA (point3, fCosSize, right, point3);
|
||||
|
||||
VectorMA (origin, -fCosSize, up, point4);
|
||||
VectorMA (point4, -fSinSize, right, point4);
|
||||
|
||||
struct model_s * pModel;
|
||||
int iContents = 0;
|
||||
|
||||
for (particle *pDraw = part; pDraw; pDraw = pDraw->m_pOverlay)
|
||||
{
|
||||
if (pDraw->pType->m_hSprite == 0)
|
||||
continue;
|
||||
|
||||
if (pDraw->pType->m_iDrawCond)
|
||||
{
|
||||
if (iContents == 0)
|
||||
iContents = gEngfuncs.PM_PointContents(origin, NULL);
|
||||
|
||||
if (iContents != pDraw->pType->m_iDrawCond)
|
||||
continue;
|
||||
}
|
||||
|
||||
pModel = (struct model_s *)gEngfuncs.GetSpritePointer( pDraw->pType->m_hSprite );
|
||||
|
||||
//Msg("UpdParticle %d: age %f, life %f, R:%f G:%f, B, %f \n", pDraw->pType->m_hSprite, part->age, part->age_death, pDraw->m_fRed, pDraw->m_fGreen, pDraw->m_fBlue);
|
||||
|
||||
// if we've reached the end of the sprite's frames, loop back
|
||||
while (pDraw->frame > pModel->numframes) pDraw->frame -= pModel->numframes;
|
||||
|
||||
while (pDraw->frame < 0) pDraw->frame += pModel->numframes;
|
||||
|
||||
if ( !gEngfuncs.pTriAPI->SpriteTexture( pModel, int(pDraw->frame) ))continue;
|
||||
|
||||
gEngfuncs.pTriAPI->RenderMode(pDraw->pType->m_iRenderMode);
|
||||
gEngfuncs.pTriAPI->Color4f( pDraw->m_fRed, pDraw->m_fGreen, pDraw->m_fBlue, pDraw->m_fAlpha );
|
||||
gEngfuncs.pTriAPI->Begin( TRI_QUADS );
|
||||
gEngfuncs.pTriAPI->TexCoord2f (0, 0);
|
||||
gEngfuncs.pTriAPI->Vertex3fv(point1);
|
||||
|
||||
gEngfuncs.pTriAPI->TexCoord2f (1, 0);
|
||||
gEngfuncs.pTriAPI->Vertex3fv (point2);
|
||||
|
||||
gEngfuncs.pTriAPI->TexCoord2f (1, 1);
|
||||
gEngfuncs.pTriAPI->Vertex3fv (point3);
|
||||
|
||||
gEngfuncs.pTriAPI->TexCoord2f (0, 1);
|
||||
gEngfuncs.pTriAPI->Vertex3fv (point4);
|
||||
gEngfuncs.pTriAPI->End();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,208 @@
|
|||
// 02/08/02 November235: Particle System
|
||||
#pragma once
|
||||
#include "r_main.h"
|
||||
|
||||
class ParticleType;
|
||||
class ParticleSystem;
|
||||
void CreateAurora( int idx, char *file ); //make new partsystem
|
||||
|
||||
#define COLLISION_NONE 0
|
||||
#define COLLISION_DIE 1
|
||||
#define COLLISION_BOUNCE 2
|
||||
|
||||
struct particle
|
||||
{
|
||||
particle* nextpart;
|
||||
|
||||
particle* m_pOverlay; // for making multi-layered particles
|
||||
|
||||
ParticleType *pType;
|
||||
|
||||
vec3_t origin;
|
||||
vec3_t velocity;
|
||||
vec3_t accel;
|
||||
vec3_t m_vecWind;
|
||||
|
||||
int m_iEntIndex; // if non-zero, this particle is tied to the given entity
|
||||
|
||||
float m_fRed;
|
||||
float m_fGreen;
|
||||
float m_fBlue;
|
||||
float m_fRedStep;
|
||||
float m_fGreenStep;
|
||||
float m_fBlueStep;
|
||||
|
||||
float m_fAlpha;
|
||||
float m_fAlphaStep;
|
||||
|
||||
float frame;
|
||||
float m_fFrameStep;
|
||||
|
||||
float m_fAngle;
|
||||
float m_fAngleStep;
|
||||
|
||||
float m_fSize;
|
||||
float m_fSizeStep;
|
||||
|
||||
float m_fDrag;
|
||||
|
||||
float age;
|
||||
float age_death;
|
||||
float age_spray;
|
||||
};
|
||||
|
||||
|
||||
class RandomRange
|
||||
{
|
||||
public:
|
||||
RandomRange() { m_fMin = m_fMax = 0; m_bDefined = false; }
|
||||
RandomRange(float fValue) { m_fMin = m_fMax = fValue; m_bDefined = true; }
|
||||
RandomRange(float fMin, float fMax) { m_fMin = fMin; m_fMax = fMax; m_bDefined = true; }
|
||||
RandomRange( char *szToken );
|
||||
|
||||
float m_fMax;
|
||||
float m_fMin;
|
||||
bool m_bDefined;
|
||||
|
||||
float GetInstance()
|
||||
{ return gEngfuncs.pfnRandomFloat(m_fMin, m_fMax); }
|
||||
|
||||
float GetOffset(float fBasis)
|
||||
{ return GetInstance()-fBasis; }
|
||||
|
||||
bool IsDefined()
|
||||
{ return m_bDefined; } //(m_fMin == 0 && m_fMax == 0); }
|
||||
};
|
||||
|
||||
#define MAX_TYPENAME 30
|
||||
|
||||
class ParticleType
|
||||
{
|
||||
public:
|
||||
ParticleType( ParticleType *pNext = NULL );
|
||||
ParticleType(char *szFilename);
|
||||
|
||||
bool m_bIsDefined; // is this ParticleType just a placeholder?
|
||||
int m_iRenderMode;
|
||||
int m_iDrawCond;
|
||||
int m_iCollision;
|
||||
RandomRange m_Bounce;
|
||||
RandomRange m_BounceFriction;
|
||||
bool m_bBouncing;
|
||||
|
||||
RandomRange m_Life;
|
||||
|
||||
RandomRange m_StartAlpha;
|
||||
RandomRange m_EndAlpha;
|
||||
RandomRange m_StartRed;
|
||||
RandomRange m_EndRed;
|
||||
RandomRange m_StartGreen;
|
||||
RandomRange m_EndGreen;
|
||||
RandomRange m_StartBlue;
|
||||
RandomRange m_EndBlue;
|
||||
|
||||
RandomRange m_StartSize;
|
||||
RandomRange m_SizeDelta;
|
||||
RandomRange m_EndSize;
|
||||
|
||||
RandomRange m_StartFrame;
|
||||
RandomRange m_EndFrame;
|
||||
RandomRange m_FrameRate; // incompatible with EndFrame
|
||||
bool m_bEndFrame;
|
||||
|
||||
RandomRange m_StartAngle;
|
||||
RandomRange m_AngleDelta;
|
||||
|
||||
RandomRange m_SprayRate;
|
||||
RandomRange m_SprayForce;
|
||||
RandomRange m_SprayPitch;
|
||||
RandomRange m_SprayYaw;
|
||||
RandomRange m_SprayRoll;
|
||||
ParticleType *m_pSprayType;
|
||||
|
||||
RandomRange m_Gravity;
|
||||
RandomRange m_WindStrength;
|
||||
RandomRange m_WindYaw;
|
||||
|
||||
HSPRITE m_hSprite;
|
||||
ParticleType *m_pOverlayType;
|
||||
|
||||
RandomRange m_Drag;
|
||||
|
||||
ParticleType *m_pNext;
|
||||
|
||||
char m_szName[MAX_TYPENAME];
|
||||
|
||||
// here is a particle system. Add a (set of) particles according to this type, and initialise their values.
|
||||
particle* CreateParticle(ParticleSystem *pSys);//particle *pPart);
|
||||
|
||||
// initialise this particle. Does not define velocity or age.
|
||||
void InitParticle(particle *pPart, ParticleSystem *pSys);
|
||||
};
|
||||
|
||||
class ParticleSystem
|
||||
{
|
||||
public:
|
||||
ParticleSystem( int entindex, char *szFilename );
|
||||
~ParticleSystem( void );
|
||||
void AllocateParticles( int iParticles );
|
||||
void CalculateDistance();
|
||||
|
||||
ParticleType *GetType( const char *szName );
|
||||
ParticleType *AddPlaceholderType( const char *szName );
|
||||
ParticleType *ParseType( char *&szFile );
|
||||
|
||||
cl_entity_t *GetEntity() { return UTIL_GetClientEntityWithServerIndex(m_iEntIndex); }
|
||||
|
||||
static float c_fCosTable[360 + 90];
|
||||
static bool c_bCosTableInit;
|
||||
|
||||
// General functions
|
||||
bool UpdateSystem( float frametime ); //If this function returns false, the manager deletes the system
|
||||
void DrawSystem();
|
||||
particle *ActivateParticle(); // adds one of the free particles to the active list, and returns it for initialisation.
|
||||
|
||||
static float CosLookup(int angle) { return angle < 0? c_fCosTable[angle+360]: c_fCosTable[angle]; }
|
||||
static float SinLookup(int angle) { return angle < -90? c_fCosTable[angle+450]: c_fCosTable[angle+90]; }
|
||||
|
||||
// returns false if the particle has died
|
||||
bool UpdateParticle( particle *part, float frametime );
|
||||
void DrawParticle( particle* part, vec3_t &right, vec3_t &up );
|
||||
|
||||
// Utility functions that have to be public
|
||||
bool ParticleIsVisible( particle* part );
|
||||
|
||||
// Pointer to next system for linked list structure
|
||||
ParticleSystem* m_pNextSystem;
|
||||
|
||||
particle* m_pActiveParticle;
|
||||
float m_fViewerDist;
|
||||
int m_iEntIndex;
|
||||
int m_iEntAttachment;
|
||||
int m_iKillCondition;
|
||||
int enable;
|
||||
private:
|
||||
// the block of allocated particles
|
||||
particle* m_pAllParticles;
|
||||
// First particles in the linked list for the active particles and the dead particles
|
||||
particle* m_pFreeParticle;
|
||||
particle* m_pMainParticle; // the "source" particle.
|
||||
|
||||
ParticleType *m_pFirstType;
|
||||
|
||||
ParticleType *m_pMainType;
|
||||
};
|
||||
|
||||
class ParticleSystemManager
|
||||
{
|
||||
public:
|
||||
ParticleSystemManager( void );
|
||||
~ParticleSystemManager( void );
|
||||
ParticleSystem *FindSystem( cl_entity_t* pEntity );
|
||||
void AddSystem( ParticleSystem* );
|
||||
void UpdateSystems( void );
|
||||
void ClearSystems( void );
|
||||
ParticleSystem* m_pFirstSystem;
|
||||
};
|
||||
|
||||
extern ParticleSystemManager* g_pParticleSystems;
|
|
@ -0,0 +1,818 @@
|
|||
/***
|
||||
*
|
||||
* Copyright (c) 2001-2006, Chain Studios. All rights reserved.
|
||||
*
|
||||
* This product contains software technology that is a part of Half-Life FX (R)
|
||||
* from Chain Studios ("HLFX Technology"). All rights reserved.
|
||||
*
|
||||
* Use, distribution, and modification of this source code and/or resulting
|
||||
* object code is restricted to non-commercial enhancements to products from
|
||||
* Valve LLC. All other use, distribution, or modification is prohibited
|
||||
* without written permission from Chain Studios.
|
||||
*
|
||||
****/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "hud.h"
|
||||
#include "r_main.h"
|
||||
#include "r_util.h"
|
||||
#include <string.h>
|
||||
|
||||
vec3_t vec3_origin( 0, 0, 0 );
|
||||
|
||||
double sqrt(double x);
|
||||
|
||||
HSPRITE m_hHudFont;
|
||||
|
||||
int *GetRect( void )
|
||||
{
|
||||
RECT wrect;
|
||||
static int extent[4];
|
||||
|
||||
if(GetWindowRect( GetActiveWindow(), &wrect ))
|
||||
{
|
||||
if(!wrect.left)
|
||||
{
|
||||
extent[0] = wrect.left; //+4
|
||||
extent[1] = wrect.top; //+30
|
||||
extent[2] = wrect.right; //-4
|
||||
extent[3] = wrect.bottom; //-4
|
||||
}
|
||||
else
|
||||
{
|
||||
extent[0] = wrect.left + 4; //+4
|
||||
extent[1] = wrect.top + 30; //+30
|
||||
extent[2] = wrect.right - 4; //-4
|
||||
extent[3] = wrect.bottom - 4; //-4
|
||||
}
|
||||
}
|
||||
return extent;
|
||||
}
|
||||
|
||||
void ScaleColors( int &r, int &g, int &b, int a )
|
||||
{
|
||||
float x = (float)a / 255;
|
||||
r = (int)(r * x);
|
||||
g = (int)(g * x);
|
||||
b = (int)(b * x);
|
||||
}
|
||||
|
||||
unsigned int nextpow2(unsigned int x)
|
||||
{
|
||||
unsigned int y = 1;
|
||||
while (x > y) y = y << 1;
|
||||
return y;
|
||||
}
|
||||
|
||||
float Length(const float *v)
|
||||
{
|
||||
int i;
|
||||
float length;
|
||||
|
||||
length = 0;
|
||||
for (i=0 ; i< 3 ; i++)
|
||||
length += v[i]*v[i];
|
||||
length = sqrt (length); // FIXME
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
float Distance(const vec3_t v1, const vec3_t v2)
|
||||
{
|
||||
vec3_t d;
|
||||
VectorSubtract(v2,v1,d);
|
||||
return Length(d);
|
||||
}
|
||||
|
||||
void VectorAngles( const float *forward, float *angles )
|
||||
{
|
||||
float tmp, yaw, pitch;
|
||||
|
||||
if (forward[1] == 0 && forward[0] == 0)
|
||||
{
|
||||
yaw = 0;
|
||||
if (forward[2] > 0)
|
||||
pitch = 90;
|
||||
else
|
||||
pitch = 270;
|
||||
}
|
||||
else
|
||||
{
|
||||
yaw = (atan2(forward[1], forward[0]) * 180 / M_PI);
|
||||
if (yaw < 0)
|
||||
yaw += 360;
|
||||
|
||||
tmp = sqrt (forward[0]*forward[0] + forward[1]*forward[1]);
|
||||
pitch = (atan2(forward[2], tmp) * 180 / M_PI);
|
||||
if (pitch < 0)
|
||||
pitch += 360;
|
||||
}
|
||||
|
||||
angles[0] = pitch;
|
||||
angles[1] = yaw;
|
||||
angles[2] = 0;
|
||||
}
|
||||
|
||||
float VectorNormalize (float *v)
|
||||
{
|
||||
float length, ilength;
|
||||
|
||||
length = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
|
||||
length = sqrt (length); // FIXME
|
||||
|
||||
if (length)
|
||||
{
|
||||
ilength = 1/length;
|
||||
v[0] *= ilength;
|
||||
v[1] *= ilength;
|
||||
v[2] *= ilength;
|
||||
}
|
||||
|
||||
return length;
|
||||
|
||||
}
|
||||
|
||||
void VectorInverse ( float *v )
|
||||
{
|
||||
v[0] = -v[0];
|
||||
v[1] = -v[1];
|
||||
v[2] = -v[2];
|
||||
}
|
||||
|
||||
void VectorScale (const float *in, float scale, float *out)
|
||||
{
|
||||
out[0] = in[0]*scale;
|
||||
out[1] = in[1]*scale;
|
||||
out[2] = in[2]*scale;
|
||||
}
|
||||
|
||||
void VectorMA (const float *veca, float scale, const float *vecb, float *vecc)
|
||||
{
|
||||
vecc[0] = veca[0] + scale*vecb[0];
|
||||
vecc[1] = veca[1] + scale*vecb[1];
|
||||
vecc[2] = veca[2] + scale*vecb[2];
|
||||
}
|
||||
|
||||
HSPRITE LoadSprite(const char *pszName)
|
||||
{
|
||||
int i;
|
||||
char sz[256];
|
||||
|
||||
if (ScreenWidth < 640)
|
||||
i = 320;
|
||||
else
|
||||
i = 640;
|
||||
|
||||
sprintf(sz, pszName, i);
|
||||
|
||||
return SPR_Load(sz);
|
||||
}
|
||||
|
||||
float TransformColor ( float color )
|
||||
{
|
||||
float trns_clr;
|
||||
if(color >= 0 ) trns_clr = color / 255.0f;
|
||||
else trns_clr = 1.0;//default value
|
||||
return trns_clr;
|
||||
}
|
||||
|
||||
#define NOISE_SIZE 64
|
||||
|
||||
inline float fade ( float t )
|
||||
{
|
||||
return t * t * t * (t * (t * 6 - 15) + 10);
|
||||
}
|
||||
|
||||
inline float lerp ( float t, float a, float b )
|
||||
{
|
||||
return a + t * (b - a);
|
||||
}
|
||||
|
||||
inline float grad ( int hash, float x, float y, float z )
|
||||
{
|
||||
int h = hash & 15; // CONVERT LO 4 BITS OF HASH CODE
|
||||
float u = h<8 ? x : y, // INTO 12 GRADIENT DIRECTIONS.
|
||||
v = h<4 ? y : h==12 || h==14 ? x : z;
|
||||
|
||||
return ((h&1) == 0 ? u : -u) + ((h&2) == 0 ? v : -v);
|
||||
}
|
||||
|
||||
int permutation [256] =
|
||||
{
|
||||
151,160,137,91,90,15,
|
||||
131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
|
||||
190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
|
||||
88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
|
||||
77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
|
||||
102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
|
||||
135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
|
||||
5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
|
||||
223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
|
||||
129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
|
||||
251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
|
||||
49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
|
||||
138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180
|
||||
};
|
||||
|
||||
int p[512];
|
||||
|
||||
void InitImprovedNoise()
|
||||
{
|
||||
for ( int i = 0; i < 256; i++ )
|
||||
p [ 256 + i ] = p [ i ] = permutation [i];
|
||||
}
|
||||
|
||||
float noise( float vx, float vy, float vz )
|
||||
{
|
||||
|
||||
float fx = floor ( vx ); // get floor values of coords
|
||||
float fy = floor ( vy );
|
||||
float fz = floor ( vz );
|
||||
|
||||
int X = ((int) fx) & 255, // FIND UNIT CUBE THAT
|
||||
Y = ((int) fy) & 255, // CONTAINS POINT.
|
||||
Z = ((int) fz) & 255;
|
||||
|
||||
float x = vx - fx; // FIND RELATIVE X,Y,Z
|
||||
float y = vy - fy; // OF POINT IN CUBE.
|
||||
float z = vz - fz;
|
||||
|
||||
float u = fade ( x ), // COMPUTE FADE CURVES
|
||||
v = fade ( y ), // FOR EACH OF X,Y,Z.
|
||||
w = fade ( z );
|
||||
|
||||
int a = p [X ]+Y, aa = p [a]+Z, ab = p [a+1]+Z, // HASH COORDINATES OF
|
||||
b = p [X+1]+Y, ba = p [b]+Z, bb = p [b+1]+Z; // THE 8 CUBE CORNERS,
|
||||
|
||||
return lerp(w, lerp(v, lerp(u, grad(p[aa ], x , y , z ), // AND ADD
|
||||
grad(p[ba ], x-1, y , z )), // BLENDED
|
||||
lerp(u, grad(p[ab ], x , y-1, z ), // RESULTS
|
||||
grad(p[bb ], x-1, y-1, z ))),// FROM 8
|
||||
lerp(v, lerp(u, grad(p[aa+1], x , y , z-1 ), // CORNERS
|
||||
grad(p[ba+1], x-1, y , z-1 )), // OF CUBE
|
||||
lerp(u, grad(p[ab+1], x , y-1, z-1 ),
|
||||
grad(p[bb+1], x-1, y-1, z-1 ))));
|
||||
}
|
||||
|
||||
|
||||
void CreateNoiseTexture3D (float scale)
|
||||
{
|
||||
int i;
|
||||
|
||||
GLfloat *img = new GLfloat[NOISE_SIZE * NOISE_SIZE * NOISE_SIZE * 3];
|
||||
GLfloat *p = img;
|
||||
|
||||
InitImprovedNoise();
|
||||
|
||||
for (i=0; i < NOISE_SIZE*NOISE_SIZE*NOISE_SIZE*3 ; i++)
|
||||
{
|
||||
float x = i + sin(i);
|
||||
float y = i + cos(i);
|
||||
*p++ = noise(x, y, i);
|
||||
}
|
||||
|
||||
g_uiNoiseTex = pTexId++;
|
||||
glBindTexture(GL_TEXTURE_3D, g_uiNoiseTex);
|
||||
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glTexImage3DEXT(GL_TEXTURE_3D, 0, 3, NOISE_SIZE, NOISE_SIZE, NOISE_SIZE, 0,
|
||||
GL_RGB, GL_FLOAT, img);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_REPEAT );
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_REPEAT );
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_REPEAT );
|
||||
|
||||
delete [] img;
|
||||
}
|
||||
|
||||
//
|
||||
// R_SphereInFrustum
|
||||
//
|
||||
// Purpose: sphere visibility test
|
||||
//
|
||||
extern float frustumPlanes[6][4];
|
||||
|
||||
float R_SphereInFrustum( vec3_t o, float radius )
|
||||
{
|
||||
int p;
|
||||
float d;
|
||||
|
||||
for( p = 0; p < 6; p++ )
|
||||
{
|
||||
d = frustumPlanes[p][0] * o[0] + frustumPlanes[p][1] * o[1] + frustumPlanes[p][2] * o[2] + frustumPlanes[p][3];
|
||||
if( d <= -radius )
|
||||
return 0;
|
||||
}
|
||||
return d + radius;
|
||||
}
|
||||
|
||||
//
|
||||
// UTIL_GetClientEntityWithServerIndex
|
||||
//
|
||||
// Purpose: searches for the server entity on client
|
||||
// Assumes: colormap has server entity index
|
||||
//
|
||||
cl_entity_t *UTIL_GetClientEntityWithServerIndex( int sv_index )
|
||||
{
|
||||
cl_entity_t *e;
|
||||
|
||||
for (int ic=1;ic<MAX_EDICTS;ic++)
|
||||
{
|
||||
e = gEngfuncs.GetEntityByIndex( ic );
|
||||
if (!e)
|
||||
break;
|
||||
|
||||
if (!e->model)
|
||||
continue;
|
||||
|
||||
if (e->curstate.colormap == sv_index)
|
||||
return e;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
AngleMatrix
|
||||
|
||||
====================
|
||||
*/
|
||||
void AngleMatrix (const float *angles, float (*matrix)[4] )
|
||||
{
|
||||
float angle;
|
||||
float sr, sp, sy, cr, cp, cy;
|
||||
|
||||
angle = angles[YAW] * (M_PI*2 / 360);
|
||||
sy = sin(angle);
|
||||
cy = cos(angle);
|
||||
angle = angles[PITCH] * (M_PI*2 / 360);
|
||||
sp = sin(angle);
|
||||
cp = cos(angle);
|
||||
angle = angles[ROLL] * (M_PI*2 / 360);
|
||||
sr = sin(angle);
|
||||
cr = cos(angle);
|
||||
|
||||
// matrix = (YAW * PITCH) * ROLL
|
||||
matrix[0][0] = cp*cy;
|
||||
matrix[1][0] = cp*sy;
|
||||
matrix[2][0] = -sp;
|
||||
matrix[0][1] = sr*sp*cy+cr*-sy;
|
||||
matrix[1][1] = sr*sp*sy+cr*cy;
|
||||
matrix[2][1] = sr*cp;
|
||||
matrix[0][2] = (cr*sp*cy+-sr*-sy);
|
||||
matrix[1][2] = (cr*sp*sy+-sr*cy);
|
||||
matrix[2][2] = cr*cp;
|
||||
matrix[0][3] = 0.0;
|
||||
matrix[1][3] = 0.0;
|
||||
matrix[2][3] = 0.0;
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
VectorCompare
|
||||
|
||||
====================
|
||||
*/
|
||||
int VectorCompare (const float *v1, const float *v2)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0 ; i<3 ; i++)
|
||||
if (v1[i] != v2[i]) return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
CrossProduct
|
||||
|
||||
====================
|
||||
*/
|
||||
void CrossProduct (const float *v1, const float *v2, float *cross)
|
||||
{
|
||||
cross[0] = v1[1]*v2[2] - v1[2]*v2[1];
|
||||
cross[1] = v1[2]*v2[0] - v1[0]*v2[2];
|
||||
cross[2] = v1[0]*v2[1] - v1[1]*v2[0];
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
VectorTransform
|
||||
|
||||
====================
|
||||
*/
|
||||
void VectorTransform (const float *in1, float in2[3][4], float *out)
|
||||
{
|
||||
out[0] = DotProduct(in1, in2[0]) + in2[0][3];
|
||||
out[1] = DotProduct(in1, in2[1]) + in2[1][3];
|
||||
out[2] = DotProduct(in1, in2[2]) + in2[2][3];
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
ConcatTransforms
|
||||
|
||||
================
|
||||
*/
|
||||
void ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4])
|
||||
{
|
||||
out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] +
|
||||
in1[0][2] * in2[2][0];
|
||||
out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] +
|
||||
in1[0][2] * in2[2][1];
|
||||
out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] +
|
||||
in1[0][2] * in2[2][2];
|
||||
out[0][3] = in1[0][0] * in2[0][3] + in1[0][1] * in2[1][3] +
|
||||
in1[0][2] * in2[2][3] + in1[0][3];
|
||||
out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] +
|
||||
in1[1][2] * in2[2][0];
|
||||
out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] +
|
||||
in1[1][2] * in2[2][1];
|
||||
out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] +
|
||||
in1[1][2] * in2[2][2];
|
||||
out[1][3] = in1[1][0] * in2[0][3] + in1[1][1] * in2[1][3] +
|
||||
in1[1][2] * in2[2][3] + in1[1][3];
|
||||
out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] +
|
||||
in1[2][2] * in2[2][0];
|
||||
out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] +
|
||||
in1[2][2] * in2[2][1];
|
||||
out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] +
|
||||
in1[2][2] * in2[2][2];
|
||||
out[2][3] = in1[2][0] * in2[0][3] + in1[2][1] * in2[1][3] +
|
||||
in1[2][2] * in2[2][3] + in1[2][3];
|
||||
}
|
||||
|
||||
// angles index are not the same as ROLL, PITCH, YAW
|
||||
|
||||
/*
|
||||
====================
|
||||
AngleQuaternion
|
||||
|
||||
====================
|
||||
*/
|
||||
void AngleQuaternion( float *angles, vec4_t quaternion )
|
||||
{
|
||||
float angle;
|
||||
float sr, sp, sy, cr, cp, cy;
|
||||
|
||||
// FIXME: rescale the inputs to 1/2 angle
|
||||
angle = angles[2] * 0.5;
|
||||
sy = sin(angle);
|
||||
cy = cos(angle);
|
||||
angle = angles[1] * 0.5;
|
||||
sp = sin(angle);
|
||||
cp = cos(angle);
|
||||
angle = angles[0] * 0.5;
|
||||
sr = sin(angle);
|
||||
cr = cos(angle);
|
||||
|
||||
quaternion[0] = sr*cp*cy-cr*sp*sy; // X
|
||||
quaternion[1] = cr*sp*cy+sr*cp*sy; // Y
|
||||
quaternion[2] = cr*cp*sy-sr*sp*cy; // Z
|
||||
quaternion[3] = cr*cp*cy+sr*sp*sy; // W
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
QuaternionSlerp
|
||||
|
||||
====================
|
||||
*/
|
||||
void QuaternionSlerp( vec4_t p, vec4_t q, float t, vec4_t qt )
|
||||
{
|
||||
int i;
|
||||
float omega, cosom, sinom, sclp, sclq;
|
||||
|
||||
// decide if one of the quaternions is backwards
|
||||
float a = 0;
|
||||
float b = 0;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
a += (p[i]-q[i])*(p[i]-q[i]);
|
||||
b += (p[i]+q[i])*(p[i]+q[i]);
|
||||
}
|
||||
if (a > b)
|
||||
{
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
q[i] = -q[i];
|
||||
}
|
||||
}
|
||||
|
||||
cosom = p[0]*q[0] + p[1]*q[1] + p[2]*q[2] + p[3]*q[3];
|
||||
|
||||
if ((1.0 + cosom) > 0.000001)
|
||||
{
|
||||
if ((1.0 - cosom) > 0.000001)
|
||||
{
|
||||
omega = acos( cosom );
|
||||
sinom = sin( omega );
|
||||
sclp = sin( (1.0 - t)*omega) / sinom;
|
||||
sclq = sin( t*omega ) / sinom;
|
||||
}
|
||||
else
|
||||
{
|
||||
sclp = 1.0 - t;
|
||||
sclq = t;
|
||||
}
|
||||
for (i = 0; i < 4; i++) {
|
||||
qt[i] = sclp * p[i] + sclq * q[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
qt[0] = -q[1];
|
||||
qt[1] = q[0];
|
||||
qt[2] = -q[3];
|
||||
qt[3] = q[2];
|
||||
sclp = sin( (1.0 - t) * (0.5 * M_PI));
|
||||
sclq = sin( t * (0.5 * M_PI));
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
qt[i] = sclp * p[i] + sclq * qt[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
QuaternionMatrix
|
||||
|
||||
====================
|
||||
*/
|
||||
void QuaternionMatrix( vec4_t quaternion, float (*matrix)[4] )
|
||||
{
|
||||
matrix[0][0] = 1.0 - 2.0 * quaternion[1] * quaternion[1] - 2.0 * quaternion[2] * quaternion[2];
|
||||
matrix[1][0] = 2.0 * quaternion[0] * quaternion[1] + 2.0 * quaternion[3] * quaternion[2];
|
||||
matrix[2][0] = 2.0 * quaternion[0] * quaternion[2] - 2.0 * quaternion[3] * quaternion[1];
|
||||
|
||||
matrix[0][1] = 2.0 * quaternion[0] * quaternion[1] - 2.0 * quaternion[3] * quaternion[2];
|
||||
matrix[1][1] = 1.0 - 2.0 * quaternion[0] * quaternion[0] - 2.0 * quaternion[2] * quaternion[2];
|
||||
matrix[2][1] = 2.0 * quaternion[1] * quaternion[2] + 2.0 * quaternion[3] * quaternion[0];
|
||||
|
||||
matrix[0][2] = 2.0 * quaternion[0] * quaternion[2] + 2.0 * quaternion[3] * quaternion[1];
|
||||
matrix[1][2] = 2.0 * quaternion[1] * quaternion[2] - 2.0 * quaternion[3] * quaternion[0];
|
||||
matrix[2][2] = 1.0 - 2.0 * quaternion[0] * quaternion[0] - 2.0 * quaternion[1] * quaternion[1];
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
MatrixCopy
|
||||
|
||||
====================
|
||||
*/
|
||||
void MatrixCopy( float in[3][4], float out[3][4] )
|
||||
{
|
||||
memcpy( out, in, sizeof( float ) * 3 * 4 );
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
VectorIRotate
|
||||
|
||||
====================
|
||||
*/
|
||||
void VectorIRotate (const vec3_t in1, const float in2[3][4], vec3_t out)
|
||||
{
|
||||
out[0] = in1[0]*in2[0][0] + in1[1]*in2[1][0] + in1[2]*in2[2][0];
|
||||
out[1] = in1[0]*in2[0][1] + in1[1]*in2[1][1] + in1[2]*in2[2][1];
|
||||
out[2] = in1[0]*in2[0][2] + in1[1]*in2[1][2] + in1[2]*in2[2][2];
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
VectorRotateByMatrix
|
||||
VectorTransformByMatrix
|
||||
====================
|
||||
*/
|
||||
void VectorRotateByMatrix (const vec3_t &in1, const float *in2, vec3_t &out)
|
||||
{
|
||||
out[0] = in1[0]*in2[0] + in1[1]*in2[4] + in1[2]*in2[8];
|
||||
out[1] = in1[0]*in2[1] + in1[1]*in2[5] + in1[2]*in2[9];
|
||||
out[2] = in1[0]*in2[2] + in1[1]*in2[6] + in1[2]*in2[10];
|
||||
}
|
||||
|
||||
void VectorTransformByMatrix (const vec3_t &in1, const float *in2, vec3_t &out)
|
||||
{
|
||||
out[0] = in1[0]*in2[0] + in1[1]*in2[4] + in1[2]*in2[8] + in2[12];
|
||||
out[1] = in1[0]*in2[1] + in1[1]*in2[5] + in1[2]*in2[9] + in2[13];
|
||||
out[2] = in1[0]*in2[2] + in1[1]*in2[6] + in1[2]*in2[10] + in2[14];
|
||||
}
|
||||
|
||||
void VectorRotateByMatrix (const float *in1, const float *in2, float *out)
|
||||
{
|
||||
out[0] = in1[0]*in2[0] + in1[1]*in2[4] + in1[2]*in2[8];
|
||||
out[1] = in1[0]*in2[1] + in1[1]*in2[5] + in1[2]*in2[9];
|
||||
out[2] = in1[0]*in2[2] + in1[1]*in2[6] + in1[2]*in2[10];
|
||||
}
|
||||
|
||||
void VectorTransformByMatrix (const float *in1, const float *in2, float *out)
|
||||
{
|
||||
out[0] = in1[0]*in2[0] + in1[1]*in2[4] + in1[2]*in2[8] + in2[12];
|
||||
out[1] = in1[0]*in2[1] + in1[1]*in2[5] + in1[2]*in2[9] + in2[13];
|
||||
out[2] = in1[0]*in2[2] + in1[1]*in2[6] + in1[2]*in2[10] + in2[14];
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
ObjectToWorldMatrix
|
||||
|
||||
====================
|
||||
*/
|
||||
void ObjectToWorldMatrix(cl_entity_t *e, float *result)
|
||||
{
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
|
||||
glTranslatef(e->origin[0], e->origin[1], e->origin[2]);
|
||||
glRotatef ( e->angles[1], 0, 0, 1);
|
||||
glRotatef ( e->angles[0], 0, 1, 0);
|
||||
glRotatef ( e->angles[2], 1, 0, 0);
|
||||
|
||||
glGetFloatv (GL_MODELVIEW_MATRIX, result);
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
SPRITE_GetList
|
||||
|
||||
====================
|
||||
*/
|
||||
|
||||
char *ParseHudSprite( char *pfile, char *psz, client_sprite_t *result )
|
||||
{
|
||||
char token[256];
|
||||
client_sprite_t *p = new client_sprite_t;
|
||||
int x = 0, y = 0, width = 0, height = 0;
|
||||
int section = 0;
|
||||
|
||||
memset( p, 0, sizeof(client_sprite_t) );
|
||||
|
||||
while( pfile )
|
||||
{
|
||||
pfile = gEngfuncs.COM_ParseFile( pfile, token );
|
||||
|
||||
if( !stricmp( token, psz ))
|
||||
{
|
||||
pfile = gEngfuncs.COM_ParseFile( pfile, token );
|
||||
if( !stricmp( token, "{" )) section = 1;
|
||||
}
|
||||
if(section)//parse section
|
||||
{
|
||||
if( !stricmp( token, "}" )) break;//end section
|
||||
|
||||
if ( !stricmp( token, "file" ))
|
||||
{
|
||||
pfile = gEngfuncs.COM_ParseFile(pfile, token);
|
||||
strcpy(p->szSprite, token );
|
||||
if( !gEngfuncs.COM_LoadFile( p->szSprite, 5, NULL )) return pfile;
|
||||
else
|
||||
{
|
||||
gEngfuncs.COM_FreeFile( p->szSprite);
|
||||
//fill structure at default
|
||||
HSPRITE m_hSprite = SPR_Load(p->szSprite);
|
||||
x = y = 0;
|
||||
width = SPR_Width( m_hSprite, 0 );
|
||||
height = SPR_Height( m_hSprite, 0 );
|
||||
}
|
||||
}
|
||||
else if ( !stricmp( token, "name" ))
|
||||
{
|
||||
pfile = gEngfuncs.COM_ParseFile(pfile, token);
|
||||
strcpy(p->szName, token );
|
||||
}
|
||||
else if ( !stricmp( token, "x" ))
|
||||
{
|
||||
pfile = gEngfuncs.COM_ParseFile(pfile, token);
|
||||
x = atoi(token);
|
||||
}
|
||||
else if ( !stricmp( token, "y" ))
|
||||
{
|
||||
pfile = gEngfuncs.COM_ParseFile(pfile, token);
|
||||
y = atoi(token);
|
||||
}
|
||||
else if ( !stricmp( token, "width" ))
|
||||
{
|
||||
pfile = gEngfuncs.COM_ParseFile(pfile, token);
|
||||
width = atoi(token);
|
||||
}
|
||||
else if ( !stricmp( token, "height" ))
|
||||
{
|
||||
pfile = gEngfuncs.COM_ParseFile(pfile, token);
|
||||
height = atoi(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!section) return pfile;//data not found
|
||||
|
||||
//calculate sprite position
|
||||
p->rc.left = x;
|
||||
p->rc.right = x + width;
|
||||
p->rc.top = y;
|
||||
p->rc.bottom = y + height;
|
||||
|
||||
//write resolution for backward compatibility
|
||||
if (ScreenWidth < 640) p->iRes = 320;
|
||||
else p->iRes = 640;
|
||||
|
||||
memcpy( result, p, sizeof(client_sprite_t));
|
||||
return pfile;
|
||||
}
|
||||
|
||||
client_sprite_t *SPR_GetList( char *psz, int *piCount )
|
||||
{
|
||||
int iSprCount = 0;
|
||||
char *pfile = (char *)gEngfuncs.COM_LoadFile( psz, 5, NULL);
|
||||
if (!pfile)
|
||||
{
|
||||
*piCount = iSprCount;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char token[256];
|
||||
char *plist = pfile;
|
||||
|
||||
while ( pfile ) //calculate count of sprites
|
||||
{
|
||||
pfile = gEngfuncs.COM_ParseFile(pfile, token);
|
||||
if ( !stricmp( token, "hudsprite" )) iSprCount++;
|
||||
}
|
||||
|
||||
client_sprite_t *phud = new client_sprite_t[iSprCount];
|
||||
|
||||
for(int i = 0; i < iSprCount; i++ ) //parse structures
|
||||
{
|
||||
plist = ParseHudSprite( plist, "hudsprite", &phud[i] );
|
||||
}
|
||||
|
||||
if(!iSprCount)Msg("SPR_GetList: %s don't have sprites\n", psz );
|
||||
gEngfuncs.COM_FreeFile( pfile );
|
||||
|
||||
*piCount = iSprCount;
|
||||
return phud;
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
Sys LoadGameDLL
|
||||
|
||||
====================
|
||||
*/
|
||||
bool Sys_LoadLibrary (const char* dllname, dllhandle_t* handle, const dllfunction_t *fcts)
|
||||
{
|
||||
const dllfunction_t *gamefunc;
|
||||
char dllpath[128];
|
||||
dllhandle_t dllhandle = 0;
|
||||
|
||||
if (handle == NULL) return false;
|
||||
|
||||
// Initializations
|
||||
for (gamefunc = fcts; gamefunc && gamefunc->name != NULL; gamefunc++)
|
||||
*gamefunc->funcvariable = NULL;
|
||||
|
||||
// Try every possible name
|
||||
|
||||
|
||||
sprintf(dllpath, "%s/cl_dlls/%s", gEngfuncs.pfnGetGameDirectory(), dllname);
|
||||
dllhandle = LoadLibrary (dllpath);
|
||||
|
||||
// No DLL found
|
||||
if (! dllhandle) return false;
|
||||
|
||||
// Get the function adresses
|
||||
for (gamefunc = fcts; gamefunc && gamefunc->name != NULL; gamefunc++)
|
||||
if (!(*gamefunc->funcvariable = (void *) Sys_GetProcAddress (dllhandle, gamefunc->name)))
|
||||
{
|
||||
Sys_UnloadLibrary (&dllhandle);
|
||||
return false;
|
||||
}
|
||||
|
||||
Msg("%s loaded succesfully!\n", dllname);
|
||||
*handle = dllhandle;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void Sys_UnloadLibrary (dllhandle_t* handle)
|
||||
{
|
||||
if (handle == NULL || *handle == NULL)
|
||||
return;
|
||||
|
||||
FreeLibrary (*handle);
|
||||
*handle = NULL;
|
||||
}
|
||||
|
||||
void* Sys_GetProcAddress (dllhandle_t handle, const char* name)
|
||||
{
|
||||
return (void *)GetProcAddress (handle, name);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,45 @@
|
|||
//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================
|
||||
|
||||
#ifndef VIEW_H
|
||||
#define VIEW_H
|
||||
|
||||
void V_StartPitchDrift( void );
|
||||
void V_StopPitchDrift( void );
|
||||
|
||||
//camera flags
|
||||
#define CAMERA_ON 1
|
||||
#define DRAW_HUD 2
|
||||
#define INVERSE_X 4
|
||||
#define MONSTER_VIEW 8
|
||||
|
||||
typedef struct pitchdrift_s
|
||||
{
|
||||
float pitchvel;
|
||||
int nodrift;
|
||||
float driftmove;
|
||||
double laststop;
|
||||
}pitchdrift_t;
|
||||
static pitchdrift_t pd;
|
||||
|
||||
|
||||
#define ORIGIN_BACKUP 64
|
||||
#define ORIGIN_MASK ( ORIGIN_BACKUP - 1 )
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float Origins[ ORIGIN_BACKUP ][3];
|
||||
float OriginTime[ ORIGIN_BACKUP ];
|
||||
|
||||
float Angles[ ORIGIN_BACKUP ][3];
|
||||
float AngleTime[ ORIGIN_BACKUP ];
|
||||
|
||||
int CurrentOrigin;
|
||||
int CurrentAngle;
|
||||
}viewinterp_t;
|
||||
|
||||
#endif // VIEW_H
|
|
@ -0,0 +1,680 @@
|
|||
//=======================================================================
|
||||
// Copyright (C) Shambler Team 2005
|
||||
// rain.cpp - TriAPI weather effects
|
||||
// based on original code from BUzer
|
||||
//=======================================================================
|
||||
|
||||
#include "hud.h"
|
||||
#include "r_main.h"
|
||||
#include "r_util.h"
|
||||
#include "const.h"
|
||||
#include "entity_types.h"
|
||||
#include "cdll_int.h"
|
||||
#include "pm_defs.h"
|
||||
#include "event_api.h"
|
||||
#include "triangleapi.h"
|
||||
#include "r_weather.h"
|
||||
|
||||
void WaterLandingEffect(cl_drip *drip);
|
||||
void ParseRainFile( void );
|
||||
|
||||
rain_properties Rain;
|
||||
|
||||
cl_drip FirstChainDrip;
|
||||
cl_rainfx FirstChainFX;
|
||||
|
||||
double rain_curtime; // current time
|
||||
double rain_oldtime; // last time we have updated drips
|
||||
double rain_timedelta; // difference between old time and current time
|
||||
double rain_nextspawntime; // when the next drip should be spawned
|
||||
|
||||
int dripcounter = 0;
|
||||
int fxcounter = 0;
|
||||
|
||||
|
||||
/*
|
||||
=================================
|
||||
ProcessRain
|
||||
|
||||
Must think every frame.
|
||||
=================================
|
||||
*/
|
||||
void ProcessRain( void )
|
||||
{
|
||||
rain_oldtime = rain_curtime; // save old time
|
||||
rain_curtime = gEngfuncs.GetClientTime();
|
||||
rain_timedelta = rain_curtime - rain_oldtime;
|
||||
|
||||
// first frame
|
||||
if (rain_oldtime == 0)
|
||||
{
|
||||
// fix first frame bug with nextspawntime
|
||||
rain_nextspawntime = gEngfuncs.GetClientTime();
|
||||
ParseRainFile();
|
||||
return;
|
||||
}
|
||||
|
||||
if (Rain.dripsPerSecond == 0 && FirstChainDrip.p_Next == NULL)
|
||||
{
|
||||
// keep nextspawntime correct
|
||||
rain_nextspawntime = rain_curtime;
|
||||
return;
|
||||
}
|
||||
|
||||
if (rain_timedelta == 0)
|
||||
return; // not in pause
|
||||
|
||||
double timeBetweenDrips = 1 / (double)Rain.dripsPerSecond;
|
||||
|
||||
cl_drip* curDrip = FirstChainDrip.p_Next;
|
||||
cl_drip* nextDrip = NULL;
|
||||
|
||||
cl_entity_t *player = gEngfuncs.GetLocalPlayer();
|
||||
|
||||
// save debug info
|
||||
float debug_lifetime = 0;
|
||||
int debug_howmany = 0;
|
||||
int debug_attempted = 0;
|
||||
int debug_dropped = 0;
|
||||
|
||||
while (curDrip != NULL) // go through list
|
||||
{
|
||||
nextDrip = curDrip->p_Next; // save pointer to next drip
|
||||
|
||||
if (Rain.weatherMode == 0)
|
||||
curDrip->origin.z -= rain_timedelta * DRIPSPEED; // rain
|
||||
else
|
||||
curDrip->origin.z -= rain_timedelta * SNOWSPEED; // snow
|
||||
|
||||
curDrip->origin.x += rain_timedelta * curDrip->xDelta;
|
||||
curDrip->origin.y += rain_timedelta * curDrip->yDelta;
|
||||
|
||||
// remove drip if its origin lower than minHeight
|
||||
if (curDrip->origin.z < curDrip->minHeight)
|
||||
{
|
||||
if (curDrip->landInWater/* && Rain.weatherMode == 0*/)
|
||||
WaterLandingEffect(curDrip); // create water rings
|
||||
|
||||
if (r_debug->value > 1)
|
||||
{
|
||||
debug_lifetime += (rain_curtime - curDrip->birthTime);
|
||||
debug_howmany++;
|
||||
}
|
||||
|
||||
curDrip->p_Prev->p_Next = curDrip->p_Next; // link chain
|
||||
if (nextDrip != NULL)
|
||||
nextDrip->p_Prev = curDrip->p_Prev;
|
||||
delete curDrip;
|
||||
|
||||
dripcounter--;
|
||||
}
|
||||
|
||||
curDrip = nextDrip; // restore pointer, so we can continue moving through chain
|
||||
}
|
||||
|
||||
int maxDelta; // maximum height randomize distance
|
||||
float falltime;
|
||||
if (Rain.weatherMode == 0)
|
||||
{
|
||||
maxDelta = DRIPSPEED * rain_timedelta; // for rain
|
||||
falltime = (Rain.globalHeight + 4096) / DRIPSPEED;
|
||||
}
|
||||
else
|
||||
{
|
||||
maxDelta = SNOWSPEED * rain_timedelta; // for snow
|
||||
falltime = (Rain.globalHeight + 4096) / SNOWSPEED;
|
||||
}
|
||||
|
||||
while (rain_nextspawntime < rain_curtime)
|
||||
{
|
||||
rain_nextspawntime += timeBetweenDrips;
|
||||
if (r_debug->value > 1) debug_attempted++;
|
||||
|
||||
if (dripcounter < MAXDRIPS) // check for overflow
|
||||
{
|
||||
float deathHeight;
|
||||
vec3_t vecStart, vecEnd;
|
||||
|
||||
vecStart[0] = gEngfuncs.pfnRandomFloat(player->origin.x - Rain.distFromPlayer, player->origin.x + Rain.distFromPlayer);
|
||||
vecStart[1] = gEngfuncs.pfnRandomFloat(player->origin.y - Rain.distFromPlayer, player->origin.y + Rain.distFromPlayer);
|
||||
vecStart[2] = Rain.globalHeight;
|
||||
|
||||
float xDelta = Rain.windX + gEngfuncs.pfnRandomFloat(Rain.randX * -1, Rain.randX);
|
||||
float yDelta = Rain.windY + gEngfuncs.pfnRandomFloat(Rain.randY * -1, Rain.randY);
|
||||
|
||||
// find a point at bottom of map
|
||||
vecEnd[0] = falltime * xDelta;
|
||||
vecEnd[1] = falltime * yDelta;
|
||||
vecEnd[2] = -4096;
|
||||
|
||||
pmtrace_t pmtrace;
|
||||
gEngfuncs.pEventAPI->EV_SetTraceHull( 2 );
|
||||
gEngfuncs.pEventAPI->EV_PlayerTrace( vecStart, vecStart + vecEnd, PM_STUDIO_IGNORE, -1, &pmtrace );
|
||||
|
||||
if (pmtrace.startsolid || pmtrace.allsolid)
|
||||
{
|
||||
if (r_debug->value > 1) debug_dropped++;
|
||||
continue; // drip cannot be placed
|
||||
}
|
||||
|
||||
// falling to water?
|
||||
int contents = gEngfuncs.PM_PointContents( pmtrace.endpos, NULL );
|
||||
if (contents == CONTENTS_WATER)
|
||||
{
|
||||
int waterEntity = gEngfuncs.PM_WaterEntity( pmtrace.endpos );
|
||||
if ( waterEntity > 0 )
|
||||
{
|
||||
cl_entity_t *pwater = UTIL_GetClientEntityWithServerIndex( waterEntity );
|
||||
if ( pwater && ( pwater->model != NULL ) )
|
||||
{
|
||||
deathHeight = pwater->curstate.maxs[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
Msg("Rain error: can't get water entity\n");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Msg("Rain error: water is not func_water entity\n");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
deathHeight = pmtrace.endpos[2];
|
||||
}
|
||||
|
||||
// just in case..
|
||||
if (deathHeight > vecStart[2])
|
||||
{
|
||||
Msg("Rain error: can't create drip in water\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
cl_drip *newClDrip = new cl_drip;
|
||||
if (!newClDrip)
|
||||
{
|
||||
Rain.dripsPerSecond = 0; // disable rain
|
||||
Msg( "Rain error: failed to allocate object!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
vecStart[2] -= gEngfuncs.pfnRandomFloat(0, maxDelta); // randomize a bit
|
||||
|
||||
newClDrip->alpha = gEngfuncs.pfnRandomFloat(0.12, 0.2);
|
||||
VectorCopy(vecStart, newClDrip->origin);
|
||||
|
||||
newClDrip->xDelta = xDelta;
|
||||
newClDrip->yDelta = yDelta;
|
||||
|
||||
newClDrip->birthTime = rain_curtime; // store time when it was spawned
|
||||
newClDrip->minHeight = deathHeight;
|
||||
|
||||
if (contents == CONTENTS_WATER)
|
||||
newClDrip->landInWater = 1;
|
||||
else
|
||||
newClDrip->landInWater = 0;
|
||||
|
||||
// add to first place in chain
|
||||
newClDrip->p_Next = FirstChainDrip.p_Next;
|
||||
newClDrip->p_Prev = &FirstChainDrip;
|
||||
if (newClDrip->p_Next != NULL)
|
||||
newClDrip->p_Next->p_Prev = newClDrip;
|
||||
FirstChainDrip.p_Next = newClDrip;
|
||||
|
||||
dripcounter++;
|
||||
}
|
||||
else
|
||||
{
|
||||
Msg( "Rain error: Drip limit overflow!\n" );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (r_debug->value > 1) // print debug info
|
||||
{
|
||||
Msg( "Rain info: Drips exist: %i\n", dripcounter );
|
||||
Msg( "Rain info: FX's exist: %i\n", fxcounter );
|
||||
Msg( "Rain info: Attempted/Dropped: %i, %i\n", debug_attempted, debug_dropped);
|
||||
if (debug_howmany)
|
||||
{
|
||||
float ave = debug_lifetime / (float)debug_howmany;
|
||||
Msg( "Rain info: Average drip life time: %f\n", ave);
|
||||
}
|
||||
else
|
||||
Msg( "Rain info: Average drip life time: --\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
=================================
|
||||
WaterLandingEffect
|
||||
=================================
|
||||
*/
|
||||
void WaterLandingEffect(cl_drip *drip)
|
||||
{
|
||||
if (fxcounter >= MAXFX)
|
||||
{
|
||||
Msg( "Rain error: FX limit overflow!\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
cl_rainfx *newFX = new cl_rainfx;
|
||||
if (!newFX)
|
||||
{
|
||||
Msg( "Rain error: failed to allocate FX object!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
newFX->alpha = gEngfuncs.pfnRandomFloat(0.6, 0.9);
|
||||
VectorCopy(drip->origin, newFX->origin);
|
||||
newFX->origin[2] = drip->minHeight; // correct position
|
||||
|
||||
newFX->birthTime = gEngfuncs.GetClientTime();
|
||||
newFX->life = gEngfuncs.pfnRandomFloat(0.7, 1);
|
||||
|
||||
// add to first place in chain
|
||||
newFX->p_Next = FirstChainFX.p_Next;
|
||||
newFX->p_Prev = &FirstChainFX;
|
||||
if (newFX->p_Next != NULL)
|
||||
newFX->p_Next->p_Prev = newFX;
|
||||
FirstChainFX.p_Next = newFX;
|
||||
|
||||
fxcounter++;
|
||||
}
|
||||
|
||||
/*
|
||||
=================================
|
||||
ProcessFXObjects
|
||||
|
||||
Remove all fx objects with out time to live
|
||||
Call every frame before ProcessRain
|
||||
=================================
|
||||
*/
|
||||
void ProcessFXObjects( void )
|
||||
{
|
||||
float curtime = gEngfuncs.GetClientTime();
|
||||
|
||||
cl_rainfx* curFX = FirstChainFX.p_Next;
|
||||
cl_rainfx* nextFX = NULL;
|
||||
|
||||
while (curFX != NULL) // go through FX objects list
|
||||
{
|
||||
nextFX = curFX->p_Next; // save pointer to next
|
||||
|
||||
// delete current?
|
||||
if ((curFX->birthTime + curFX->life) < curtime)
|
||||
{
|
||||
curFX->p_Prev->p_Next = curFX->p_Next; // link chain
|
||||
if (nextFX != NULL)
|
||||
nextFX->p_Prev = curFX->p_Prev;
|
||||
delete curFX;
|
||||
fxcounter--;
|
||||
}
|
||||
curFX = nextFX; // restore pointer
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=================================
|
||||
ResetRain
|
||||
clear memory, delete all objects
|
||||
=================================
|
||||
*/
|
||||
void ResetRain( void )
|
||||
{
|
||||
// delete all drips
|
||||
cl_drip* delDrip = FirstChainDrip.p_Next;
|
||||
FirstChainDrip.p_Next = NULL;
|
||||
|
||||
while (delDrip != NULL)
|
||||
{
|
||||
cl_drip* nextDrip = delDrip->p_Next; // save pointer to next drip in chain
|
||||
delete delDrip;
|
||||
delDrip = nextDrip; // restore pointer
|
||||
dripcounter--;
|
||||
}
|
||||
|
||||
// delete all FX objects
|
||||
cl_rainfx* delFX = FirstChainFX.p_Next;
|
||||
FirstChainFX.p_Next = NULL;
|
||||
|
||||
while (delFX != NULL)
|
||||
{
|
||||
cl_rainfx* nextFX = delFX->p_Next;
|
||||
delete delFX;
|
||||
delFX = nextFX;
|
||||
fxcounter--;
|
||||
}
|
||||
|
||||
InitRain();
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
=================================
|
||||
InitRain
|
||||
initialze system
|
||||
=================================
|
||||
*/
|
||||
void InitRain( void )
|
||||
{
|
||||
Rain.dripsPerSecond = 0;
|
||||
Rain.distFromPlayer = 0;
|
||||
Rain.windX = 0;
|
||||
Rain.windY = 0;
|
||||
Rain.randX = 0;
|
||||
Rain.randY = 0;
|
||||
Rain.weatherMode = 0;
|
||||
Rain.globalHeight = 0;
|
||||
|
||||
FirstChainDrip.birthTime = 0;
|
||||
FirstChainDrip.minHeight = 0;
|
||||
FirstChainDrip.origin[0]=0;
|
||||
FirstChainDrip.origin[1]=0;
|
||||
FirstChainDrip.origin[2]=0;
|
||||
FirstChainDrip.alpha = 0;
|
||||
FirstChainDrip.xDelta = 0;
|
||||
FirstChainDrip.yDelta = 0;
|
||||
FirstChainDrip.landInWater = 0;
|
||||
FirstChainDrip.p_Next = NULL;
|
||||
FirstChainDrip.p_Prev = NULL;
|
||||
|
||||
FirstChainFX.alpha = 0;
|
||||
FirstChainFX.birthTime = 0;
|
||||
FirstChainFX.life = 0;
|
||||
FirstChainFX.origin[0] = 0;
|
||||
FirstChainFX.origin[1] = 0;
|
||||
FirstChainFX.origin[2] = 0;
|
||||
FirstChainFX.p_Next = NULL;
|
||||
FirstChainFX.p_Prev = NULL;
|
||||
|
||||
rain_oldtime = 0;
|
||||
rain_curtime = 0;
|
||||
rain_nextspawntime = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
===========================
|
||||
ParseRainFile
|
||||
|
||||
List of settings:
|
||||
drips - max raindrips\snowflakes
|
||||
distance - radius of rain\snow
|
||||
windx - wind shift X
|
||||
windy - wind shift Y
|
||||
randx - random shift X
|
||||
randy - random shift Y
|
||||
mode - rain = 0\snow =1
|
||||
height - max height to create raindrips\snowflakes
|
||||
===========================
|
||||
*/
|
||||
void ParseRainFile( void )
|
||||
{
|
||||
if (Rain.distFromPlayer != 0 || Rain.dripsPerSecond != 0 || Rain.globalHeight != 0)
|
||||
return;
|
||||
|
||||
char mapname[64];
|
||||
char token[64];
|
||||
char *pfile;
|
||||
|
||||
strcpy( mapname, gEngfuncs.pfnGetLevelName() );
|
||||
if (strlen(mapname) == 0)
|
||||
{
|
||||
Msg( "Rain error: unable to read map name\n");
|
||||
return;
|
||||
}
|
||||
|
||||
mapname[strlen(mapname)-4] = 0;
|
||||
sprintf(mapname, "%s.pcs", mapname);
|
||||
|
||||
pfile = (char *)gEngfuncs.COM_LoadFile( mapname, 5, NULL);
|
||||
if (!pfile)
|
||||
{
|
||||
if (r_debug->value > 1)
|
||||
Msg("Rain: couldn't open rain settings file %s\n", mapname);
|
||||
return;
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
pfile = gEngfuncs.COM_ParseFile(pfile, token);
|
||||
if (!pfile)
|
||||
break;
|
||||
|
||||
if (!stricmp(token, "drips")) // dripsPerSecond
|
||||
{
|
||||
pfile = gEngfuncs.COM_ParseFile(pfile, token);
|
||||
Rain.dripsPerSecond = atoi(token);
|
||||
}
|
||||
else if (!stricmp(token, "distance")) // distFromPlayer
|
||||
{
|
||||
pfile = gEngfuncs.COM_ParseFile(pfile, token);
|
||||
Rain.distFromPlayer = atof(token);
|
||||
}
|
||||
else if (!stricmp(token, "windx")) // windX
|
||||
{
|
||||
pfile = gEngfuncs.COM_ParseFile(pfile, token);
|
||||
Rain.windX = atof(token);
|
||||
}
|
||||
else if (!stricmp(token, "windy")) // windY
|
||||
{
|
||||
pfile = gEngfuncs.COM_ParseFile(pfile, token);
|
||||
Rain.windY = atof(token);
|
||||
}
|
||||
else if (!stricmp(token, "randx")) // randX
|
||||
{
|
||||
pfile = gEngfuncs.COM_ParseFile(pfile, token);
|
||||
Rain.randX = atof(token);
|
||||
}
|
||||
else if (!stricmp(token, "randy")) // randY
|
||||
{
|
||||
pfile = gEngfuncs.COM_ParseFile(pfile, token);
|
||||
Rain.randY = atof(token);
|
||||
}
|
||||
else if (!stricmp(token, "mode")) // weatherMode
|
||||
{
|
||||
pfile = gEngfuncs.COM_ParseFile(pfile, token);
|
||||
Rain.weatherMode = atoi(token);
|
||||
}
|
||||
else if (!stricmp(token, "height")) // globalHeight
|
||||
{
|
||||
pfile = gEngfuncs.COM_ParseFile(pfile, token);
|
||||
Rain.globalHeight = atof(token);
|
||||
}
|
||||
else
|
||||
Msg("Rain error: unknown token %s in file %s\n", token, mapname);
|
||||
}
|
||||
|
||||
gEngfuncs.COM_FreeFile( pfile );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------
|
||||
|
||||
void SetPoint( float x, float y, float z, float (*matrix)[4])
|
||||
{
|
||||
vec3_t point, result;
|
||||
point[0] = x;
|
||||
point[1] = y;
|
||||
point[2] = z;
|
||||
|
||||
VectorTransform(point, matrix, result);
|
||||
gEngfuncs.pTriAPI->Vertex3f(result[0], result[1], result[2]);
|
||||
}
|
||||
|
||||
/*
|
||||
=================================
|
||||
DrawRain
|
||||
|
||||
draw raindrips and snowflakes
|
||||
=================================
|
||||
*/
|
||||
void DrawRain( void )
|
||||
{
|
||||
if (FirstChainDrip.p_Next == NULL)
|
||||
return; // no drips to draw
|
||||
|
||||
HSPRITE hsprTexture;
|
||||
const model_s *pTexture;
|
||||
float visibleHeight = Rain.globalHeight - SNOWFADEDIST;
|
||||
|
||||
if (Rain.weatherMode == 0)
|
||||
hsprTexture = LoadSprite( "sprites/raindrop.spr" ); // load rain sprite
|
||||
else hsprTexture = LoadSprite( "sprites/snowflake.spr" ); // load snow sprite
|
||||
|
||||
if(!hsprTexture) return;
|
||||
// usual triapi stuff
|
||||
pTexture = gEngfuncs.GetSpritePointer( hsprTexture );
|
||||
gEngfuncs.pTriAPI->SpriteTexture( (struct model_s *)pTexture, 0 );
|
||||
gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd );
|
||||
gEngfuncs.pTriAPI->CullFace( TRI_NONE );
|
||||
|
||||
// go through drips list
|
||||
cl_drip* Drip = FirstChainDrip.p_Next;
|
||||
cl_entity_t *player = gEngfuncs.GetLocalPlayer();
|
||||
|
||||
if ( Rain.weatherMode == 0 ) // draw rain
|
||||
{
|
||||
while (Drip != NULL)
|
||||
{
|
||||
cl_drip* nextdDrip = Drip->p_Next;
|
||||
|
||||
Vector2D toPlayer;
|
||||
toPlayer.x = player->origin[0] - Drip->origin[0];
|
||||
toPlayer.y = player->origin[1] - Drip->origin[1];
|
||||
toPlayer = toPlayer.Normalize();
|
||||
|
||||
toPlayer.x *= DRIP_SPRITE_HALFWIDTH;
|
||||
toPlayer.y *= DRIP_SPRITE_HALFWIDTH;
|
||||
|
||||
float shiftX = (Drip->xDelta / DRIPSPEED) * DRIP_SPRITE_HALFHEIGHT;
|
||||
float shiftY = (Drip->yDelta / DRIPSPEED) * DRIP_SPRITE_HALFHEIGHT;
|
||||
|
||||
gEngfuncs.pTriAPI->Color4f( 1.0, 1.0, 1.0, Drip->alpha );
|
||||
gEngfuncs.pTriAPI->Begin( TRI_TRIANGLES );
|
||||
|
||||
gEngfuncs.pTriAPI->TexCoord2f( 0, 0 );
|
||||
gEngfuncs.pTriAPI->Vertex3f( Drip->origin[0]-toPlayer.y - shiftX, Drip->origin[1]+toPlayer.x - shiftY,Drip->origin[2] + DRIP_SPRITE_HALFHEIGHT );
|
||||
|
||||
gEngfuncs.pTriAPI->TexCoord2f( 0.5, 1 );
|
||||
gEngfuncs.pTriAPI->Vertex3f( Drip->origin[0] + shiftX, Drip->origin[1] + shiftY, Drip->origin[2]-DRIP_SPRITE_HALFHEIGHT );
|
||||
|
||||
gEngfuncs.pTriAPI->TexCoord2f( 1, 0 );
|
||||
gEngfuncs.pTriAPI->Vertex3f( Drip->origin[0]+toPlayer.y - shiftX, Drip->origin[1]-toPlayer.x - shiftY, Drip->origin[2]+DRIP_SPRITE_HALFHEIGHT);
|
||||
|
||||
gEngfuncs.pTriAPI->End();
|
||||
Drip = nextdDrip;
|
||||
}
|
||||
}
|
||||
|
||||
else // draw snow
|
||||
{
|
||||
vec3_t normal;
|
||||
gEngfuncs.GetViewAngles((float*)normal);
|
||||
|
||||
float matrix[3][4];
|
||||
AngleMatrix (normal, matrix); // calc view matrix
|
||||
|
||||
while (Drip != NULL)
|
||||
{
|
||||
cl_drip* nextdDrip = Drip->p_Next;
|
||||
|
||||
matrix[0][3] = Drip->origin[0]; // write origin to matrix
|
||||
matrix[1][3] = Drip->origin[1];
|
||||
matrix[2][3] = Drip->origin[2];
|
||||
|
||||
// apply start fading effect
|
||||
float alpha = (Drip->origin[2] <= visibleHeight) ? Drip->alpha : ((Rain.globalHeight - Drip->origin[2]) / (float)SNOWFADEDIST) * Drip->alpha;
|
||||
|
||||
gEngfuncs.pTriAPI->Color4f( 1.0, 1.0, 1.0, alpha );
|
||||
gEngfuncs.pTriAPI->Begin( TRI_QUADS );
|
||||
|
||||
gEngfuncs.pTriAPI->TexCoord2f( 0, 0 );
|
||||
SetPoint(0, SNOW_SPRITE_HALFSIZE ,SNOW_SPRITE_HALFSIZE, matrix);
|
||||
|
||||
gEngfuncs.pTriAPI->TexCoord2f( 0, 1 );
|
||||
SetPoint(0, SNOW_SPRITE_HALFSIZE ,-SNOW_SPRITE_HALFSIZE, matrix);
|
||||
|
||||
gEngfuncs.pTriAPI->TexCoord2f( 1, 1 );
|
||||
SetPoint(0, -SNOW_SPRITE_HALFSIZE ,-SNOW_SPRITE_HALFSIZE, matrix);
|
||||
|
||||
gEngfuncs.pTriAPI->TexCoord2f( 1, 0 );
|
||||
SetPoint(0, -SNOW_SPRITE_HALFSIZE ,SNOW_SPRITE_HALFSIZE, matrix);
|
||||
|
||||
gEngfuncs.pTriAPI->End();
|
||||
Drip = nextdDrip;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=================================
|
||||
DrawFXObjects
|
||||
=================================
|
||||
*/
|
||||
void DrawFXObjects( void )
|
||||
{
|
||||
if (FirstChainFX.p_Next == NULL)
|
||||
return; // no objects to draw
|
||||
|
||||
float curtime = gEngfuncs.GetClientTime();
|
||||
|
||||
// usual triapi stuff
|
||||
HSPRITE hsprTexture;
|
||||
const model_s *pTexture;
|
||||
hsprTexture = LoadSprite( "sprites/waterring.spr" ); // load water ring sprite
|
||||
if(!hsprTexture) return;
|
||||
pTexture = gEngfuncs.GetSpritePointer( hsprTexture );
|
||||
gEngfuncs.pTriAPI->SpriteTexture( (struct model_s *)pTexture, 0 );
|
||||
gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd );
|
||||
gEngfuncs.pTriAPI->CullFace( TRI_NONE );
|
||||
|
||||
// go through objects list
|
||||
cl_rainfx* curFX = FirstChainFX.p_Next;
|
||||
while (curFX != NULL)
|
||||
{
|
||||
cl_rainfx* nextFX = curFX->p_Next;
|
||||
|
||||
// fadeout
|
||||
float alpha = ((curFX->birthTime + curFX->life - curtime) / curFX->life) * curFX->alpha;
|
||||
float size = (curtime - curFX->birthTime) * MAXRINGHALFSIZE;
|
||||
|
||||
gEngfuncs.pTriAPI->Color4f( 1.0, 1.0, 1.0, alpha );
|
||||
gEngfuncs.pTriAPI->Begin( TRI_QUADS );
|
||||
|
||||
gEngfuncs.pTriAPI->TexCoord2f( 0, 0 );
|
||||
gEngfuncs.pTriAPI->Vertex3f(curFX->origin[0] - size, curFX->origin[1] - size, curFX->origin[2]);
|
||||
|
||||
gEngfuncs.pTriAPI->TexCoord2f( 0, 1 );
|
||||
gEngfuncs.pTriAPI->Vertex3f(curFX->origin[0] - size, curFX->origin[1] + size, curFX->origin[2]);
|
||||
|
||||
gEngfuncs.pTriAPI->TexCoord2f( 1, 1 );
|
||||
gEngfuncs.pTriAPI->Vertex3f(curFX->origin[0] + size, curFX->origin[1] + size, curFX->origin[2]);
|
||||
|
||||
gEngfuncs.pTriAPI->TexCoord2f( 1, 0 );
|
||||
gEngfuncs.pTriAPI->Vertex3f(curFX->origin[0] + size, curFX->origin[1] - size, curFX->origin[2]);
|
||||
|
||||
gEngfuncs.pTriAPI->End();
|
||||
curFX = nextFX;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=================================
|
||||
DrawAll
|
||||
=================================
|
||||
*/
|
||||
|
||||
void R_DrawWeather( void )
|
||||
{
|
||||
ProcessFXObjects();
|
||||
ProcessRain();
|
||||
DrawRain();
|
||||
DrawFXObjects();
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/***
|
||||
*
|
||||
* Copyright (c) 1996-2004, Shambler Team. All rights reserved.
|
||||
*
|
||||
* This product contains software technology licensed from Id
|
||||
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Use, distribution, and modification of this source code and/or resulting
|
||||
* object code is restricted to non-commercial enhancements to products from
|
||||
* Shambler Team. All other use, distribution, or modification is prohibited
|
||||
* without written permission from Shambler Team.
|
||||
*
|
||||
****/
|
||||
/*
|
||||
====== rain.h ========================================================
|
||||
*/
|
||||
#ifndef __RAIN_H__
|
||||
#define __RAIN_H__
|
||||
|
||||
#define DRIPSPEED 900 // speed of raindrips (pixel per secs)
|
||||
#define SNOWSPEED 200 // speed of snowflakes
|
||||
#define SNOWFADEDIST 80
|
||||
|
||||
#define MAXDRIPS 2000 // max raindrops
|
||||
#define MAXFX 3000 // max effects
|
||||
|
||||
#define DRIP_SPRITE_HALFHEIGHT 46
|
||||
#define DRIP_SPRITE_HALFWIDTH 8
|
||||
#define SNOW_SPRITE_HALFSIZE 3
|
||||
|
||||
// radius water rings
|
||||
#define MAXRINGHALFSIZE 25
|
||||
|
||||
typedef struct cl_drip
|
||||
{
|
||||
float birthTime;
|
||||
float minHeight; // minimal height to kill raindrop
|
||||
vec3_t origin;
|
||||
float alpha;
|
||||
|
||||
float xDelta; // side speed
|
||||
float yDelta;
|
||||
int landInWater;
|
||||
|
||||
cl_drip* p_Next; // next drip in chain
|
||||
cl_drip* p_Prev; // previous drip in chain
|
||||
} cl_drip_t;
|
||||
|
||||
typedef struct cl_rainfx
|
||||
{
|
||||
float birthTime;
|
||||
float life;
|
||||
vec3_t origin;
|
||||
float alpha;
|
||||
|
||||
cl_rainfx* p_Next; // next fx in chain
|
||||
cl_rainfx* p_Prev; // previous fx in chain
|
||||
} cl_rainfx_t;
|
||||
|
||||
void ProcessRain( void );
|
||||
void ProcessFXObjects( void );
|
||||
void ResetRain( void );
|
||||
void InitRain( void );
|
||||
|
||||
#endif
|
|
@ -0,0 +1,107 @@
|
|||
client dll readme.txt
|
||||
-------------------------
|
||||
|
||||
This file details the structure of the half-life client dll, and
|
||||
how it communicates with the half-life game engine.
|
||||
|
||||
|
||||
Engine callback functions:
|
||||
|
||||
Drawing functions:
|
||||
HSPRITE SPR_Load( char *picname );
|
||||
Loads a sprite into memory, and returns a handle to it.
|
||||
|
||||
int SPR_Frames( HSPRITE sprite );
|
||||
Returns the number of frames stored in the specified sprite.
|
||||
|
||||
int SPR_Height( HSPRITE x, int frame )
|
||||
Returns the height, in pixels, of a sprite at the specified frame.
|
||||
Returns 0 is the frame number or the sprite handle is invalid.
|
||||
|
||||
int SPR_Width( HSPRITE x, int f )
|
||||
Returns the width, in pixels, of a sprite at the specified frame.
|
||||
Returns 0 is the frame number or the sprite handle is invalid.
|
||||
|
||||
int SPR_Set( HSPRITE sprite, int r, int g, int b );
|
||||
Prepares a sprite about to be drawn. RBG color values are applied to the sprite at this time.
|
||||
|
||||
|
||||
void SPR_Draw( int frame, int x, int y );
|
||||
Precondition: SPR_Set has already been called for a sprite.
|
||||
Draws the currently active sprite to the screen, at position (x,y), where (0,0) is
|
||||
the top left-hand corner of the screen.
|
||||
|
||||
|
||||
void SPR_DrawHoles( int frame, int x, int y );
|
||||
Precondition: SPR_Set has already been called for a sprite.
|
||||
Draws the currently active sprite to the screen. Color index #255 is treated as transparent.
|
||||
|
||||
void SPR_DrawAdditive( int frame, int x, int y );
|
||||
Precondition: SPR_Set has already been called for a sprite.
|
||||
Draws the currently active sprite to the screen, adding it's color values to the background.
|
||||
|
||||
void SPR_EnableScissor( int x, int y, int width, int height );
|
||||
Creates a clipping rectangle. No pixels will be drawn outside the specified area. Will
|
||||
stay in effect until either the next frame, or SPR_DisableScissor is called.
|
||||
|
||||
void SPR_DisableScissor( void );
|
||||
Disables the effect of an SPR_EnableScissor call.
|
||||
|
||||
int IsHighRes( void );
|
||||
returns 1 if the res mode is 640x480 or higher; 0 otherwise.
|
||||
|
||||
int ScreenWidth( void );
|
||||
returns the screen width, in pixels.
|
||||
|
||||
int ScreenHeight( void );
|
||||
returns the screen height, in pixels.
|
||||
|
||||
// Sound functions
|
||||
void PlaySound( char *szSound, int volume )
|
||||
plays the sound 'szSound' at the specified volume. Loads the sound if it hasn't been cached.
|
||||
If it can't find the sound, it displays an error message and plays no sound.
|
||||
|
||||
void PlaySound( int iSound, int volume )
|
||||
Precondition: iSound has been precached.
|
||||
Plays the sound, from the precache list.
|
||||
|
||||
|
||||
// Communication functions
|
||||
void SendClientCmd( char *szCmdString );
|
||||
sends a command to the server, just as if the client had typed the szCmdString at the console.
|
||||
|
||||
char *GetPlayerName( int entity_number );
|
||||
returns a pointer to a string, that contains the name of the specified client.
|
||||
Returns NULL if the entity_number is not a client.
|
||||
|
||||
|
||||
DECLARE_MESSAGE(), HOOK_MESSAGE()
|
||||
These two macros bind the message sending between the entity DLL and the client DLL to
|
||||
the CHud object.
|
||||
|
||||
HOOK_MESSAGE( message_name )
|
||||
This is used inside CHud::Init(). It calls into the engine to hook that message
|
||||
from the incoming message stream.
|
||||
Precondition: There must be a function of name UserMsg_message_name declared
|
||||
for CHud. Eg, CHud::UserMsg_Health() must be declared if you want to
|
||||
use HOOK_MESSAGE( Health );
|
||||
|
||||
DECLARE_MESSAGE( message_name )
|
||||
For each HOOK_MESSAGE you must have an equivalent DECLARE_MESSAGE. This creates
|
||||
a function which passes the hooked messages into the CHud object.
|
||||
|
||||
|
||||
HOOK_COMMAND(), DECLARE_COMMAND()
|
||||
These two functions declare and hook console commands into the client dll.
|
||||
|
||||
HOOK_COMMAND( char *command, command_name )
|
||||
Whenever the user types the 'command' at the console, the function 'command_name'
|
||||
will be called.
|
||||
Precondition: There must be a function of the name UserCmd_command_name declared
|
||||
for CHud. Eg, CHud::UserMsg_ShowScores() must be declared if you want to
|
||||
use HOOK_COMMAND( "+showscores", ShowScores );
|
||||
|
||||
DECLARE_COMMAND( command_name )
|
||||
For each HOOK_COMMAND you must have an equivelant DECLARE_COMMAND. This creates
|
||||
a function which passes the hooked commands into the CHud object.
|
||||
|
|
@ -91,7 +91,7 @@ BSC32=bscmake.exe
|
|||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
|
||||
# ADD LINK32 msvcrt.lib user32.lib /nologo /dll /debug /machine:I386 /nodefaultlib:"msvcrtd.lib" /pdbtype:sept
|
||||
# ADD LINK32 msvcrtd.lib user32.lib /nologo /dll /debug /machine:I386 /nodefaultlib:"libc.lib" /pdbtype:sept
|
||||
# SUBTRACT LINK32 /incremental:no /nodefaultlib
|
||||
# Begin Custom Build
|
||||
TargetDir=\Xash3D\src_main\temp\common\!debug
|
||||
|
|
|
@ -11,6 +11,9 @@ call vcvars32
|
|||
%MSDEV% baserc/baserc.dsp %CONFIG%"baserc - Win32 Debug" %build_target%
|
||||
if errorlevel 1 set BUILD_ERROR=1
|
||||
|
||||
%MSDEV% client/client.dsp %CONFIG%"client - Win32 Debug" %build_target%
|
||||
if errorlevel 1 set BUILD_ERROR=1
|
||||
|
||||
%MSDEV% engine/engine.dsp %CONFIG%"engine - Win32 Debug" %build_target%
|
||||
if errorlevel 1 set BUILD_ERROR=1
|
||||
|
||||
|
@ -26,7 +29,7 @@ if errorlevel 1 set BUILD_ERROR=1
|
|||
%MSDEV% render/render.dsp %CONFIG%"render - Win32 Debug" %build_target%
|
||||
if errorlevel 1 set BUILD_ERROR=1
|
||||
|
||||
%MSDEV% sv_dll/server.dsp %CONFIG%"server - Win32 Debug" %build_target%
|
||||
%MSDEV% server/server.dsp %CONFIG%"server - Win32 Debug" %build_target%
|
||||
if errorlevel 1 set BUILD_ERROR=1
|
||||
|
||||
%MSDEV% vprogs/vprogs.dsp %CONFIG%"vprogs - Win32 Debug" %build_target%
|
||||
|
@ -59,6 +62,7 @@ if exist engine\engine.plg del /f /q engine\engine.plg
|
|||
if exist launch\launch.plg del /f /q launch\launch.plg
|
||||
if exist common\common.plg del /f /q common\common.plg
|
||||
if exist physic\physic.plg del /f /q physic\physic.plg
|
||||
if exist server\server.plg del /f /q server\server.plg
|
||||
if exist render\render.plg del /f /q render\render.plg
|
||||
if exist viewer\viewer.plg del /f /q viewer\viewer.plg
|
||||
if exist vprogs\vprogs.plg del /f /q vprogs\vprogs.plg
|
||||
|
@ -67,5 +71,5 @@ if exist vsound\vsound.plg del /f /q vsound\vsound.plg
|
|||
echo Build succeeded!
|
||||
echo Please wait. Xash is now loading
|
||||
cd D:\Xash3D\
|
||||
quake.exe -game tmpQuArK -log -debug -dev 3 +map qctest
|
||||
quake.exe -game tmpQuArK -log -debug -dev 5 +map qctest
|
||||
:done
|
|
@ -34,7 +34,7 @@ void CL_WriteDemoHeader( const char *name )
|
|||
{
|
||||
char buf_data[MAX_MSGLEN];
|
||||
entity_state_t *state, nullstate;
|
||||
pr_edict_t *ent;
|
||||
edict_t *ent;
|
||||
sizebuf_t buf;
|
||||
int i, len;
|
||||
|
||||
|
@ -69,7 +69,7 @@ void CL_WriteDemoHeader( const char *name )
|
|||
if( buf.cursize + com.strlen(cl.configstrings[i]) + 32 > buf.maxsize )
|
||||
{
|
||||
// write it out
|
||||
len = LittleLong (buf.cursize);
|
||||
len = LittleLong( buf.cursize );
|
||||
FS_Write( cls.demofile, &len, 4 );
|
||||
FS_Write( cls.demofile, buf.data, buf.cursize );
|
||||
buf.cursize = 0;
|
||||
|
@ -81,16 +81,14 @@ void CL_WriteDemoHeader( const char *name )
|
|||
|
||||
}
|
||||
|
||||
CL_VM_Begin();
|
||||
|
||||
// baselines
|
||||
memset(&nullstate, 0, sizeof(nullstate));
|
||||
Mem_Set( &nullstate, 0, sizeof( nullstate ));
|
||||
|
||||
for( i = 0; i < prog->num_edicts; i++ )
|
||||
for( i = 0; i < game.numEntities; i++ )
|
||||
{
|
||||
ent = PRVM_EDICT_NUM( i );
|
||||
state = &ent->priv.cl->baseline;
|
||||
if(!state->model.index) continue;
|
||||
ent = EDICT_NUM( i );
|
||||
state = &ent->pvEngineData->baseline;
|
||||
if( !state->model.index ) continue;
|
||||
|
||||
if( buf.cursize + 64 > buf.maxsize )
|
||||
{
|
||||
|
@ -101,7 +99,7 @@ void CL_WriteDemoHeader( const char *name )
|
|||
buf.cursize = 0;
|
||||
}
|
||||
MSG_WriteByte( &buf, svc_spawnbaseline );
|
||||
MSG_WriteDeltaEntity (&nullstate, &ent->priv.cl->baseline, &buf, true, true );
|
||||
MSG_WriteDeltaEntity( &nullstate, &ent->pvEngineData->baseline, &buf, true, true );
|
||||
}
|
||||
|
||||
MSG_WriteByte( &buf, svc_stufftext );
|
||||
|
@ -111,8 +109,6 @@ void CL_WriteDemoHeader( const char *name )
|
|||
len = LittleLong( buf.cursize );
|
||||
FS_Write( cls.demofile, &len, 4 );
|
||||
FS_Write( cls.demofile, buf.data, buf.cursize );
|
||||
|
||||
CL_VM_End();
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -1,79 +0,0 @@
|
|||
//=======================================================================
|
||||
// Copyright XashXT Group 2008 ©
|
||||
// cl_edict.h - client prvm edict
|
||||
//=======================================================================
|
||||
#ifndef CL_EDICT_H
|
||||
#define CL_EDICT_H
|
||||
|
||||
struct cl_globalvars_s
|
||||
{
|
||||
int pad[34];
|
||||
int pev;
|
||||
int world;
|
||||
string_t mapname;
|
||||
float realtime;
|
||||
float frametime;
|
||||
vec3_t vieworg;
|
||||
vec3_t viewangles;
|
||||
vec3_t v_forward;
|
||||
vec3_t v_right;
|
||||
vec3_t v_up;
|
||||
float onground;
|
||||
float playernum;
|
||||
float waterlevel;
|
||||
float clientflags;
|
||||
vec3_t cl_viewangles;
|
||||
vec3_t simvel;
|
||||
vec3_t simorg;
|
||||
float idealpitch;
|
||||
vec3_t viewheight;
|
||||
float health;
|
||||
float max_entities;
|
||||
float maxclients;
|
||||
float lerpfrac;
|
||||
float intermission;
|
||||
float demoplayback;
|
||||
float paused;
|
||||
vec3_t punchangle;
|
||||
vec3_t crosshairangle;
|
||||
int viewentity;
|
||||
vec3_t blend_color;
|
||||
float blend_alpha;
|
||||
float screen_x;
|
||||
float screen_y;
|
||||
float screen_w;
|
||||
float screen_h;
|
||||
func_t HUD_Init;
|
||||
func_t HUD_StudioEvent;
|
||||
func_t HUD_ParseMessage;
|
||||
func_t HUD_Render;
|
||||
func_t HUD_UpdateEntities;
|
||||
func_t HUD_Shutdown;
|
||||
func_t V_CalcRefdef;
|
||||
};
|
||||
|
||||
struct cl_entvars_s
|
||||
{
|
||||
string_t classname;
|
||||
string_t globalname;
|
||||
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;
|
||||
};
|
||||
|
||||
#define PROG_CRC_CLIENT 3720
|
||||
|
||||
#endif//CL_EDICT_H
|
|
@ -587,8 +587,8 @@ void CL_AddParticles( void )
|
|||
|
||||
if( !cl_particles->integer ) return;
|
||||
|
||||
if( PRVM_EDICT_NUM( cl.frame.ps.number )->priv.cl->current.gravity != 0 )
|
||||
gravity = PRVM_EDICT_NUM( cl.frame.ps.number )->priv.cl->current.gravity / 800.0;
|
||||
if( EDICT_NUM( cl.frame.ps.number )->pvEngineData->current.gravity != 0 )
|
||||
gravity = EDICT_NUM( cl.frame.ps.number )->pvEngineData->current.gravity / 800.0; // FIXME: register CS_GRAVITY
|
||||
else gravity = 1.0f;
|
||||
|
||||
for( p = cl_active_particles; p; p = next )
|
||||
|
@ -682,7 +682,7 @@ void CL_AddParticles( void )
|
|||
|
||||
if( p->flags & PARTICLE_BOUNCE )
|
||||
{
|
||||
pr_edict_t *clent = PRVM_EDICT_NUM( cl.frame.ps.number );
|
||||
edict_t *clent = EDICT_NUM( cl.frame.ps.number );
|
||||
|
||||
// bouncy particle
|
||||
VectorSet(mins, -radius, -radius, -radius);
|
||||
|
|
|
@ -13,15 +13,15 @@ FRAME PARSING
|
|||
|
||||
=========================================================================
|
||||
*/
|
||||
void CL_UpdateEntityFileds( pr_edict_t *ent )
|
||||
void CL_UpdateEntityFields( edict_t *ent )
|
||||
{
|
||||
// copy state to progs
|
||||
ent->progs.cl->classname = cl.edict_classnames[ent->priv.cl->current.classname];
|
||||
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.model.index] );
|
||||
VectorCopy( ent->priv.cl->current.origin, ent->progs.cl->origin );
|
||||
VectorCopy( ent->priv.cl->current.angles, ent->progs.cl->angles );
|
||||
ent->v.classname = cl.edict_classnames[ent->pvEngineData->current.classname];
|
||||
ent->v.modelindex = ent->pvEngineData->current.model.index;
|
||||
ent->v.ambient = ent->pvEngineData->current.soundindex;
|
||||
ent->v.model = MAKE_STRING( cl.configstrings[CS_MODELS+ent->pvEngineData->current.model.index] );
|
||||
VectorCopy( ent->pvEngineData->current.origin, ent->v.origin );
|
||||
VectorCopy( ent->pvEngineData->current.angles, ent->v.angles );
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -34,10 +34,10 @@ to the current frame
|
|||
*/
|
||||
void CL_DeltaEntity( sizebuf_t *msg, frame_t *frame, int newnum, entity_state_t *old, bool unchanged )
|
||||
{
|
||||
pr_edict_t *ent;
|
||||
edict_t *ent;
|
||||
entity_state_t *state;
|
||||
|
||||
ent = PRVM_EDICT_NUM( newnum );
|
||||
ent = EDICT_NUM( newnum );
|
||||
state = &cl_parse_entities[cl.parse_entities & (MAX_PARSE_ENTITIES-1)];
|
||||
|
||||
if( unchanged ) *state = *old;
|
||||
|
@ -49,28 +49,28 @@ 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->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 )
|
||||
if( state->model.index != ent->pvEngineData->current.model.index || state->pmodel.index != ent->pvEngineData->current.pmodel.index || state->model.body != ent->pvEngineData->current.model.body
|
||||
|| state->model.sequence != ent->pvEngineData->current.model.sequence || abs(state->origin[0] - ent->pvEngineData->current.origin[0]) > 512
|
||||
|| abs(state->origin[1] - ent->pvEngineData->current.origin[1]) > 512 || abs(state->origin[2] - ent->pvEngineData->current.origin[2]) > 512 )
|
||||
{
|
||||
ent->priv.cl->serverframe = -99;
|
||||
ent->pvEngineData->serverframe = -99;
|
||||
}
|
||||
|
||||
if( ent->priv.cl->serverframe != cl.frame.serverframe - 1 )
|
||||
if( ent->pvEngineData->serverframe != cl.frame.serverframe - 1 )
|
||||
{
|
||||
// duplicate the current state so lerping doesn't hurt anything
|
||||
ent->priv.cl->prev = *state;
|
||||
ent->pvEngineData->prev = *state;
|
||||
}
|
||||
else
|
||||
{ // shuffle the last state to previous
|
||||
ent->priv.cl->prev = ent->priv.cl->current;
|
||||
ent->pvEngineData->prev = ent->pvEngineData->current;
|
||||
}
|
||||
|
||||
ent->priv.cl->serverframe = cl.frame.serverframe;
|
||||
ent->priv.cl->current = *state;
|
||||
ent->pvEngineData->serverframe = cl.frame.serverframe;
|
||||
ent->pvEngineData->current = *state;
|
||||
|
||||
// update prvm fields
|
||||
CL_UpdateEntityFileds( ent );
|
||||
CL_UpdateEntityFields( ent );
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -154,8 +154,8 @@ void CL_ParsePacketEntities( sizebuf_t *msg, frame_t *oldframe, frame_t *newfram
|
|||
if( oldnum > newnum )
|
||||
{
|
||||
// delta from baseline
|
||||
pr_edict_t *ent = PRVM_EDICT_NUM( newnum );
|
||||
CL_DeltaEntity( msg, newframe, newnum, &ent->priv.cl->baseline, false );
|
||||
edict_t *ent = EDICT_NUM( newnum );
|
||||
CL_DeltaEntity( msg, newframe, newnum, &ent->pvEngineData->baseline, false );
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -188,7 +188,7 @@ CL_ParseFrame
|
|||
void CL_ParseFrame( sizebuf_t *msg )
|
||||
{
|
||||
int cmd, len, idx;
|
||||
pr_edict_t *clent;
|
||||
edict_t *clent;
|
||||
frame_t *old;
|
||||
|
||||
memset( &cl.frame, 0, sizeof(cl.frame));
|
||||
|
@ -243,7 +243,7 @@ void CL_ParseFrame( sizebuf_t *msg )
|
|||
cmd = MSG_ReadByte( msg );
|
||||
if( cmd != svc_playerinfo ) Host_Error( "CL_ParseFrame: not clientindex\n" );
|
||||
idx = MSG_ReadByte( msg );
|
||||
clent = PRVM_EDICT_NUM( idx ); // get client
|
||||
clent = EDICT_NUM( idx ); // get client
|
||||
if((idx-1) != cl.playernum ) Host_Error("CL_ParseFrame: invalid playernum (%d should be %d)\n", idx-1, cl.playernum );
|
||||
}
|
||||
else
|
||||
|
@ -263,8 +263,8 @@ void CL_ParseFrame( sizebuf_t *msg )
|
|||
if( sv_newprotocol->integer )
|
||||
{
|
||||
// now we can reading delta player state
|
||||
if( old ) cl.frame.ps = MSG_ParseDeltaPlayer( &old->ps, &clent->priv.cl->current );
|
||||
else cl.frame.ps = MSG_ParseDeltaPlayer( NULL, &clent->priv.cl->current );
|
||||
if( old ) cl.frame.ps = MSG_ParseDeltaPlayer( &old->ps, &clent->pvEngineData->current );
|
||||
else cl.frame.ps = MSG_ParseDeltaPlayer( NULL, &clent->pvEngineData->current );
|
||||
}
|
||||
|
||||
// FIXME
|
||||
|
@ -304,19 +304,17 @@ CL_AddPacketEntities
|
|||
void CL_AddPacketEntities( frame_t *frame )
|
||||
{
|
||||
entity_state_t *s1;
|
||||
pr_edict_t *ent;
|
||||
edict_t *ent;
|
||||
int pnum;
|
||||
|
||||
for( pnum = 0; pnum < frame->num_entities; pnum++ )
|
||||
{
|
||||
s1 = &cl_parse_entities[(frame->parse_entities + pnum)&(MAX_PARSE_ENTITIES-1)];
|
||||
ent = PRVM_EDICT_NUM( s1->number );
|
||||
re->AddRefEntity( &ent->priv.cl->current, &ent->priv.cl->prev, cl.lerpfrac );
|
||||
ent = EDICT_NUM( s1->number );
|
||||
re->AddRefEntity( &ent->pvEngineData->current, &ent->pvEngineData->prev, cl.lerpfrac );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
CL_AddViewWeapon
|
||||
|
@ -324,7 +322,7 @@ CL_AddViewWeapon
|
|||
*/
|
||||
void CL_AddViewWeapon( entity_state_t *ps )
|
||||
{
|
||||
pr_edict_t *view; // view model
|
||||
edict_t *view; // view model
|
||||
|
||||
// allow the gun to be completely removed
|
||||
if( !cl_gun->value ) return;
|
||||
|
@ -332,12 +330,12 @@ void CL_AddViewWeapon( entity_state_t *ps )
|
|||
// don't draw gun if in wide angle view
|
||||
if( ps->fov > 135 ) return;
|
||||
|
||||
view = PRVM_EDICT_NUM( ps->aiment );
|
||||
VectorCopy( cl.refdef.vieworg, view->priv.cl->current.origin );
|
||||
VectorCopy( cl.refdef.viewangles, view->priv.cl->current.angles );
|
||||
VectorCopy( cl.refdef.vieworg, view->priv.cl->prev.origin );
|
||||
VectorCopy( cl.refdef.viewangles, view->priv.cl->prev.angles );
|
||||
re->AddRefEntity( &view->priv.cl->current, &view->priv.cl->prev, cl.lerpfrac );
|
||||
view = EDICT_NUM( ps->aiment );
|
||||
VectorCopy( cl.refdef.vieworg, view->pvEngineData->current.origin );
|
||||
VectorCopy( cl.refdef.viewangles, view->pvEngineData->current.angles );
|
||||
VectorCopy( cl.refdef.vieworg, view->pvEngineData->prev.origin );
|
||||
VectorCopy( cl.refdef.viewangles, view->pvEngineData->prev.angles );
|
||||
re->AddRefEntity( &view->pvEngineData->current, &view->pvEngineData->prev, cl.lerpfrac );
|
||||
}
|
||||
|
||||
|
||||
|
@ -459,7 +457,7 @@ void CL_AddEntities( void )
|
|||
|
||||
void CL_GetEntitySoundSpatialization( int entnum, vec3_t origin, vec3_t velocity )
|
||||
{
|
||||
pr_edict_t *ent;
|
||||
edict_t *ent;
|
||||
cmodel_t *cmodel;
|
||||
vec3_t midPoint;
|
||||
|
||||
|
@ -471,21 +469,21 @@ void CL_GetEntitySoundSpatialization( int entnum, vec3_t origin, vec3_t velocity
|
|||
return;
|
||||
}
|
||||
|
||||
ent = PRVM_EDICT_NUM( entnum );
|
||||
ent = EDICT_NUM( entnum );
|
||||
|
||||
// calculate origin
|
||||
origin[0] = ent->priv.cl->prev.origin[0] + (ent->priv.cl->current.origin[0] - ent->priv.cl->prev.origin[0]) * cl.lerpfrac;
|
||||
origin[1] = ent->priv.cl->prev.origin[1] + (ent->priv.cl->current.origin[1] - ent->priv.cl->prev.origin[1]) * cl.lerpfrac;
|
||||
origin[2] = ent->priv.cl->prev.origin[2] + (ent->priv.cl->current.origin[2] - ent->priv.cl->prev.origin[2]) * cl.lerpfrac;
|
||||
origin[0] = ent->pvEngineData->prev.origin[0] + (ent->pvEngineData->current.origin[0] - ent->pvEngineData->prev.origin[0]) * cl.lerpfrac;
|
||||
origin[1] = ent->pvEngineData->prev.origin[1] + (ent->pvEngineData->current.origin[1] - ent->pvEngineData->prev.origin[1]) * cl.lerpfrac;
|
||||
origin[2] = ent->pvEngineData->prev.origin[2] + (ent->pvEngineData->current.origin[2] - ent->pvEngineData->prev.origin[2]) * cl.lerpfrac;
|
||||
|
||||
// calculate velocity
|
||||
VectorSubtract( ent->priv.cl->current.origin, ent->priv.cl->prev.origin, velocity);
|
||||
VectorSubtract( ent->pvEngineData->current.origin, ent->pvEngineData->prev.origin, velocity);
|
||||
VectorScale(velocity, 10, velocity);
|
||||
|
||||
// if a brush model, offset the origin
|
||||
if( VectorIsNull( origin ))
|
||||
{
|
||||
cmodel = cl.models[ent->priv.cl->current.model.index];
|
||||
cmodel = cl.models[ent->pvEngineData->current.model.index];
|
||||
if( !cmodel ) return;
|
||||
VectorAverage( cmodel->mins, cmodel->maxs, midPoint );
|
||||
VectorAdd( origin, midPoint, origin );
|
||||
|
|
|
@ -0,0 +1,924 @@
|
|||
//=======================================================================
|
||||
// Copyright XashXT Group 2008 ©
|
||||
// cl_game.c - client dlls interaction
|
||||
//=======================================================================
|
||||
|
||||
#include "common.h"
|
||||
#include "client.h"
|
||||
#include "byteorder.h"
|
||||
#include "matrix_lib.h"
|
||||
#include "com_library.h"
|
||||
#include "const.h"
|
||||
|
||||
/*
|
||||
====================
|
||||
CL_GetClientEntity
|
||||
|
||||
Render callback for studio models
|
||||
====================
|
||||
*/
|
||||
entity_state_t *CL_GetEdictByIndex( int index )
|
||||
{
|
||||
return &EDICT_NUM( index )->pvEngineData->current;
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
CL_GetLocalPlayer
|
||||
|
||||
Render callback for studio models
|
||||
====================
|
||||
*/
|
||||
entity_state_t *CL_GetLocalPlayer( void )
|
||||
{
|
||||
return &EDICT_NUM( cl.playernum + 1 )->pvEngineData->current;
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
CL_GetMaxlients
|
||||
|
||||
Render callback for studio models
|
||||
====================
|
||||
*/
|
||||
int CL_GetMaxClients( void )
|
||||
{
|
||||
return com.atoi( cl.configstrings[CS_MAXCLIENTS] );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
CL_FadeColor
|
||||
================
|
||||
*/
|
||||
float *CL_FadeColor( float starttime, float endtime )
|
||||
{
|
||||
static vec4_t color;
|
||||
float time, fade_time;
|
||||
|
||||
if( starttime == 0 ) return NULL;
|
||||
time = (cls.realtime * 0.001f) - starttime;
|
||||
if( time >= endtime ) return NULL;
|
||||
|
||||
// fade time is 1/4 of endtime
|
||||
fade_time = endtime / 4;
|
||||
fade_time = bound( 0.3f, fade_time, 10.0f );
|
||||
|
||||
// fade out
|
||||
if((endtime - time) < fade_time)
|
||||
color[3] = (endtime - time) * 1.0f / fade_time;
|
||||
else color[3] = 1.0;
|
||||
color[0] = color[1] = color[2] = 1.0f;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
void CL_DrawHUD( void )
|
||||
{
|
||||
}
|
||||
|
||||
void CL_CopyTraceResult( TraceResult *out, trace_t trace )
|
||||
{
|
||||
if( !out ) return;
|
||||
|
||||
out->fAllSolid = trace.allsolid;
|
||||
out->fStartSolid = trace.startsolid;
|
||||
out->fStartStuck = trace.startstuck;
|
||||
out->flFraction = trace.fraction;
|
||||
out->iStartContents = trace.startcontents;
|
||||
out->iContents = trace.contents;
|
||||
out->iHitgroup = trace.hitgroup;
|
||||
out->flPlaneDist = trace.plane.dist;
|
||||
VectorCopy( trace.endpos, out->vecEndPos );
|
||||
VectorCopy( trace.plane.normal, out->vecPlaneNormal );
|
||||
|
||||
if( trace.surface )
|
||||
out->pTexName = trace.surface->name;
|
||||
else out->pTexName = NULL;
|
||||
out->pHit = trace.ent;
|
||||
}
|
||||
|
||||
void CL_PrepUserMessage( char *pszName, const int svc_num )
|
||||
{
|
||||
user_message_t *msg;
|
||||
char *end;
|
||||
|
||||
if( !pszName || !*pszName ) return; // ignore blank names
|
||||
|
||||
if( game.numMessages == MAX_USER_MESSAGES )
|
||||
{
|
||||
MsgDev( D_ERROR, "CL_PrepUserMessage: user messages limit is out\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
// clear existing or allocate new one
|
||||
msg = game.msg[game.numMessages];
|
||||
if( msg ) Mem_Set( msg, 0, sizeof( *msg ));
|
||||
else msg = Mem_Alloc( cls.mempool, sizeof( *msg ));
|
||||
|
||||
end = com.strchr( pszName, '@' );
|
||||
if( !end )
|
||||
{
|
||||
MsgDev( D_ERROR, "CL_PrepUserMessage: can't register message %s\n", pszName );
|
||||
return;
|
||||
}
|
||||
|
||||
msg->size = com.atoi( end + 1 );
|
||||
pszName[end-pszName] = '\0'; // remove size description from MsgName
|
||||
msg->name = pszName;
|
||||
msg->number = svc_num;
|
||||
game.numMessages++;
|
||||
|
||||
// debug
|
||||
Msg("name %s [%i][svc_%i]\n", msg->name, msg->size, msg->number );
|
||||
}
|
||||
|
||||
void CL_ParseUserMessage( sizebuf_t *net_buffer, int svc_num )
|
||||
{
|
||||
user_message_t *msg;
|
||||
int iSize;
|
||||
byte *pbuf;
|
||||
|
||||
// NOTE: any user message parse on engine, not in client.dll
|
||||
if( svc_num >= game.numMessages || !game.msg[svc_num] )
|
||||
{
|
||||
// unregister message can't be parsed
|
||||
Host_Error( "CL_ParseUserMessage: illegible server message %d\n", svc_num );
|
||||
return;
|
||||
}
|
||||
|
||||
if( svc_num != game.msg[svc_num]->number )
|
||||
{
|
||||
int i;
|
||||
|
||||
// search for right number
|
||||
for( i = 0; i < game.numMessages; i++ )
|
||||
{
|
||||
msg = game.msg[i];
|
||||
if( !msg || msg->number == svc_num )
|
||||
break;
|
||||
}
|
||||
|
||||
// throw warn
|
||||
MsgDev( D_WARN, "CL_ParseUserMessage: wrong message num %i\n", svc_num );
|
||||
|
||||
if( i == game.numMessages || !msg )
|
||||
{
|
||||
// this never happens
|
||||
Host_Error( "CL_ParseUserMessage: illegible server message %d\n", svc_num );
|
||||
return;
|
||||
}
|
||||
}
|
||||
else msg = game.msg[svc_num];
|
||||
|
||||
iSize = msg->size;
|
||||
pbuf = NULL;
|
||||
|
||||
// message with variable sizes receive actual size as first byte
|
||||
// FIXME: replace with short for support messages more than 255 bytes ?
|
||||
if( iSize == -1 ) iSize = MSG_ReadByte( net_buffer );
|
||||
if( iSize > 0 ) pbuf = Mem_Alloc( cls.private, iSize );
|
||||
|
||||
// parse user message into buffer
|
||||
MSG_ReadData( net_buffer, pbuf, iSize );
|
||||
|
||||
if( msg->func ) msg->func( msg->name, iSize, pbuf );
|
||||
else MsgDev( D_WARN, "CL_ParseUserMessage: message %s doesn't have execute function\n", msg->name );
|
||||
if( pbuf ) Mem_Free( pbuf );
|
||||
}
|
||||
|
||||
void CL_InitEdict( edict_t *pEdict )
|
||||
{
|
||||
Com_Assert( pEdict == NULL );
|
||||
|
||||
pEdict->v.pContainingEntity = pEdict; // make cross-links for consistency
|
||||
pEdict->pvEngineData = (ed_priv_t *)Mem_Alloc( cls.mempool, sizeof( ed_priv_t ));
|
||||
pEdict->serialnumber = NUM_FOR_EDICT( pEdict ); // merged on first update
|
||||
pEdict->free = false;
|
||||
}
|
||||
|
||||
void CL_FreeEdict( edict_t *pEdict )
|
||||
{
|
||||
Com_Assert( pEdict == NULL );
|
||||
Com_Assert( pEdict->free );
|
||||
|
||||
// unlink from world
|
||||
// CL_UnlinkEdict( pEdict );
|
||||
|
||||
if( pEdict->pvEngineData ) Mem_Free( pEdict->pvEngineData );
|
||||
Mem_Set( &pEdict->v, 0, sizeof( entvars_t ));
|
||||
|
||||
pEdict->pvEngineData = NULL;
|
||||
|
||||
// mark edict as freed
|
||||
pEdict->freetime = cl.time * 0.001f;
|
||||
pEdict->serialnumber = 0;
|
||||
pEdict->free = true;
|
||||
}
|
||||
|
||||
edict_t *CL_AllocEdict( void )
|
||||
{
|
||||
edict_t *pEdict;
|
||||
int i;
|
||||
|
||||
for( i = 0; i < game.numEntities; i++ )
|
||||
{
|
||||
pEdict = EDICT_NUM( i );
|
||||
// the first couple seconds of server time can involve a lot of
|
||||
// freeing and allocating, so relax the replacement policy
|
||||
if( pEdict->free && ( pEdict->freetime < 2.0f || ((cl.time * 0.001f) - pEdict->freetime) > 0.5f ))
|
||||
{
|
||||
CL_InitEdict( pEdict );
|
||||
return pEdict;
|
||||
}
|
||||
}
|
||||
|
||||
if( i == game.maxEntities )
|
||||
Host_Error( "CL_AllocEdict: no free edicts\n" );
|
||||
|
||||
game.numEntities++;
|
||||
pEdict = EDICT_NUM( i );
|
||||
CL_InitEdict( pEdict );
|
||||
|
||||
return pEdict;
|
||||
}
|
||||
|
||||
void CL_FreeEdicts( void )
|
||||
{
|
||||
int i;
|
||||
edict_t *ent;
|
||||
|
||||
for( i = 0; game.numEntities; i++ )
|
||||
{
|
||||
ent = EDICT_NUM( i );
|
||||
if( ent->free ) continue;
|
||||
CL_FreeEdict( ent );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
CGame Builtin Functions
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
=========
|
||||
pfnMemAlloc
|
||||
|
||||
=========
|
||||
*/
|
||||
static void *pfnMemAlloc( size_t cb, const char *filename, const int fileline )
|
||||
{
|
||||
return com.malloc( cls.private, cb, filename, fileline );
|
||||
}
|
||||
|
||||
/*
|
||||
=========
|
||||
pfnMemFree
|
||||
|
||||
=========
|
||||
*/
|
||||
static void pfnMemFree( void *mem, const char *filename, const int fileline )
|
||||
{
|
||||
com.free( mem, filename, fileline );
|
||||
}
|
||||
/*
|
||||
=============
|
||||
pfnLoadShader
|
||||
|
||||
=============
|
||||
*/
|
||||
shader_t pfnLoadShader( const char *szShaderName )
|
||||
{
|
||||
if( !re ) return 0; // render not initialized
|
||||
if( !szShaderName || !*szShaderName )
|
||||
{
|
||||
MsgDev( D_ERROR, "CL_LoadShader: invalid shadername\n" );
|
||||
return -1;
|
||||
}
|
||||
|
||||
return re->RegisterShader( szShaderName, SHADER_NOMIP );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnFillRGBA
|
||||
|
||||
=============
|
||||
*/
|
||||
void pfnFillRGBA( int x, int y, int width, int height, const float *color, float alpha )
|
||||
{
|
||||
SCR_FillRect( x, y, width, height, GetRGBA( color[0], color[1], color[2], alpha ));
|
||||
if( re ) re->SetColor( NULL );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnDrawImage
|
||||
|
||||
=============
|
||||
*/
|
||||
void pfnDrawImage( shader_t shader, int x, int y, int width, int height, int frame )
|
||||
{
|
||||
if( shader == -1 )
|
||||
{
|
||||
MsgDev( D_ERROR, "CL_DrawImage: invalid shader handle\n" );
|
||||
return;
|
||||
}
|
||||
SCR_DrawPic( x, y, width, height, shader );
|
||||
if( re ) re->SetColor( NULL );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnSetColor
|
||||
|
||||
=============
|
||||
*/
|
||||
void pfnSetColor( float r, float g, float b, float a )
|
||||
{
|
||||
if( !re ) return; // render not initialized
|
||||
re->SetColor( GetRGBA( r, g, b, a ));
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnRegisterVariable
|
||||
|
||||
=============
|
||||
*/
|
||||
void pfnRegisterVariable( const char *szName, const char *szValue, int flags, const char *szDesc )
|
||||
{
|
||||
// FIXME: translate client.dll flags to real cvar flags
|
||||
Cvar_Get( szName, szValue, flags, szDesc );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnCvarSetValue
|
||||
|
||||
=============
|
||||
*/
|
||||
void pfnCvarSetValue( const char *cvar, float value )
|
||||
{
|
||||
Cvar_SetValue( cvar, value );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnGetCvarFloat
|
||||
|
||||
=============
|
||||
*/
|
||||
float pfnGetCvarFloat( const char *szName )
|
||||
{
|
||||
return Cvar_VariableValue( szName );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnGetCvarString
|
||||
|
||||
=============
|
||||
*/
|
||||
char* pfnGetCvarString( const char *szName )
|
||||
{
|
||||
return Cvar_VariableString( szName );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnGetCvarString
|
||||
|
||||
=============
|
||||
*/
|
||||
void pfnAddCommand( const char *cmd_name, xcommand_t func, const char *cmd_desc )
|
||||
{
|
||||
// NOTE: if( func == NULL ) cmd will be forwarded to a server
|
||||
Cmd_AddCommand( cmd_name, func, cmd_desc );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnHookUserMsg
|
||||
|
||||
=============
|
||||
*/
|
||||
void pfnHookUserMsg( char *szMsgName, pfnUserMsgHook pfn )
|
||||
{
|
||||
user_message_t *msg;
|
||||
int i;
|
||||
|
||||
// ignore blank names
|
||||
if( !szMsgName || !*szMsgName ) return;
|
||||
for( i = 0; game.numMessages; i++ )
|
||||
{
|
||||
msg = game.msg[i];
|
||||
if( !msg ) break;
|
||||
|
||||
if( !com.strcmp( szMsgName, msg->name ))
|
||||
{
|
||||
// msg registration is complete
|
||||
msg->func = pfn;
|
||||
return;
|
||||
}
|
||||
}
|
||||
MsgDev( D_ERROR, "CL_HookMessage: can't hook message %s\n", szMsgName );
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnServerCmd
|
||||
|
||||
=============
|
||||
*/
|
||||
void pfnServerCmd( const char *szCmdString )
|
||||
{
|
||||
// server command adding in cmds queue
|
||||
Cbuf_AddText( va( "cmd %s", szCmdString ));
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnClientCmd
|
||||
|
||||
=============
|
||||
*/
|
||||
void pfnClientCmd( const char *szCmdString )
|
||||
{
|
||||
// client command executes immediately
|
||||
Cmd_ExecuteString( szCmdString );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnTextMessageGet
|
||||
|
||||
=============
|
||||
*/
|
||||
void pfnGetPlayerInfo( int player_num, hud_player_info_t *pinfo )
|
||||
{
|
||||
// FIXME: implement
|
||||
static hud_player_info_t null_info;
|
||||
|
||||
Mem_Copy( pinfo, &null_info, sizeof( null_info ));
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnGetPlayerInfo
|
||||
|
||||
=============
|
||||
*/
|
||||
client_textmessage_t *pfnTextMessageGet( const char *pName )
|
||||
{
|
||||
// FIXME: implement
|
||||
static client_textmessage_t null_msg;
|
||||
|
||||
return &null_msg;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnCmdArgc
|
||||
|
||||
=============
|
||||
*/
|
||||
int pfnCmdArgc( void )
|
||||
{
|
||||
return Cmd_Argc();
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnCmdArgv
|
||||
|
||||
=============
|
||||
*/
|
||||
char *pfnCmdArgv( int argc )
|
||||
{
|
||||
if( argc >= 0 && argc < Cmd_Argc())
|
||||
return Cmd_Argv( argc );
|
||||
return "";
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnAlertMessage
|
||||
|
||||
=============
|
||||
*/
|
||||
static void pfnAlertMessage( ALERT_TYPE type, char *szFmt, ... )
|
||||
{
|
||||
char buffer[2048]; // must support > 1k messages
|
||||
va_list args;
|
||||
|
||||
va_start( args, szFmt );
|
||||
com.vsnprintf( buffer, 2048, szFmt, args );
|
||||
va_end( args );
|
||||
|
||||
// FIXME: implement message filter
|
||||
com.print( buffer );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnPlaySoundByName
|
||||
|
||||
=============
|
||||
*/
|
||||
void pfnPlaySoundByName( const char *szSound, float volume, const float *org )
|
||||
{
|
||||
S_StartLocalSound( szSound, volume, org );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnPlaySoundByIndex
|
||||
|
||||
=============
|
||||
*/
|
||||
void pfnPlaySoundByIndex( int iSound, float volume, const float *org )
|
||||
{
|
||||
// make sure what we in-bounds
|
||||
iSound = bound( 0, iSound, MAX_SOUNDS );
|
||||
|
||||
if( cl.sound_precache[iSound] == 0 )
|
||||
{
|
||||
MsgDev( D_ERROR, "CL_PlaySoundByIndex: invalid sound handle %i\n", iSound );
|
||||
return;
|
||||
}
|
||||
S_StartSound( org, cl.playernum + 1, CHAN_AUTO, cl.sound_precache[iSound], volume, ATTN_NORM, PITCH_NORM );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnDrawCenterPrint
|
||||
|
||||
called each frame
|
||||
=============
|
||||
*/
|
||||
void pfnDrawCenterPrint( void )
|
||||
{
|
||||
char *start;
|
||||
int l, x, y, w;
|
||||
float *color;
|
||||
|
||||
if( !cl.centerPrintTime ) return;
|
||||
color = CL_FadeColor( cl.centerPrintTime * 0.001f, scr_centertime->value );
|
||||
if( !color )
|
||||
{
|
||||
cl.centerPrintTime = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
re->SetColor( color );
|
||||
start = cl.centerPrint;
|
||||
y = cl.centerPrintY - cl.centerPrintLines * BIGCHAR_HEIGHT / 2;
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
char linebuffer[1024];
|
||||
|
||||
for ( l = 0; l < 50; l++ )
|
||||
{
|
||||
if ( !start[l] || start[l] == '\n' )
|
||||
break;
|
||||
linebuffer[l] = start[l];
|
||||
}
|
||||
linebuffer[l] = 0;
|
||||
|
||||
w = cl.centerPrintCharWidth * com.cstrlen( linebuffer );
|
||||
x = ( SCREEN_WIDTH - w )>>1;
|
||||
|
||||
SCR_DrawStringExt( x, y, cl.centerPrintCharWidth, BIGCHAR_HEIGHT, linebuffer, color, false );
|
||||
|
||||
y += cl.centerPrintCharWidth * 1.5;
|
||||
while( *start && ( *start != '\n' )) start++;
|
||||
if( !*start ) break;
|
||||
start++;
|
||||
}
|
||||
if( re ) re->SetColor( NULL );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnCenterPrint
|
||||
|
||||
called once from message
|
||||
=============
|
||||
*/
|
||||
void pfnCenterPrint( const char *text, int y, int charWidth )
|
||||
{
|
||||
char *s;
|
||||
|
||||
com.strncpy( cl.centerPrint, text, sizeof( cl.centerPrint ));
|
||||
cl.centerPrintTime = cls.realtime;
|
||||
cl.centerPrintY = y;
|
||||
cl.centerPrintCharWidth = charWidth;
|
||||
|
||||
// count the number of lines for centering
|
||||
cl.centerPrintLines = 1;
|
||||
s = cl.centerPrint;
|
||||
while( *s )
|
||||
{
|
||||
if( *s == '\n' )
|
||||
cl.centerPrintLines++;
|
||||
s++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnDrawCharacter
|
||||
|
||||
=============
|
||||
*/
|
||||
int pfnDrawCharacter( int x, int y, int width, int height, int number )
|
||||
{
|
||||
if( number < 32 || number > 255 )
|
||||
{
|
||||
MsgDev( D_WARN, "SCR_DrawChar: passed non-printable character %c\n", (char )number );
|
||||
return false;
|
||||
}
|
||||
|
||||
SCR_DrawChar( x, y, width, height, number );
|
||||
if( re ) re->SetColor( NULL );
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnDrawString
|
||||
|
||||
=============
|
||||
*/
|
||||
void pfnDrawString( int x, int y, int width, int height, const char *text )
|
||||
{
|
||||
if( !text || !*text )
|
||||
{
|
||||
MsgDev( D_ERROR, "SCR_DrawStringExt: passed null string!\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
SCR_DrawStringExt( x, y, width, height, text, g_color_table[7], false );
|
||||
if( re ) re->SetColor( NULL );
|
||||
}
|
||||
|
||||
void pfnGetImageSize( int *w, int *h, shader_t shader )
|
||||
{
|
||||
if( re ) re->DrawGetPicSize( w, h, shader );
|
||||
else
|
||||
{
|
||||
if( w ) *w = -1;
|
||||
if( h ) *h = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnGetViewAngles
|
||||
|
||||
return interpolated angles from previous frame
|
||||
=============
|
||||
*/
|
||||
void pfnGetViewAngles( float *angles )
|
||||
{
|
||||
if( angles == NULL ) return;
|
||||
VectorCopy( cl.refdef.viewangles, angles );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnGetEntityByIndex
|
||||
|
||||
=============
|
||||
*/
|
||||
edict_t* pfnGetEntityByIndex( int idx )
|
||||
{
|
||||
if( idx < 0 || idx > game.numEntities )
|
||||
{
|
||||
MsgDev( D_ERROR, "CL_GetEntityByIndex: invalid entindex %i\n", idx );
|
||||
return EDICT_NUM( 0 );
|
||||
}
|
||||
return EDICT_NUM( idx );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnGetLocalPlayer
|
||||
|
||||
=============
|
||||
*/
|
||||
edict_t* pfnGetLocalPlayer( void )
|
||||
{
|
||||
return EDICT_NUM( cl.playernum + 1 );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnIsSpectateOnly
|
||||
|
||||
=============
|
||||
*/
|
||||
int pfnIsSpectateOnly( void )
|
||||
{
|
||||
// FIXME: implement
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnGetClientTime
|
||||
|
||||
=============
|
||||
*/
|
||||
float pfnGetClientTime( void )
|
||||
{
|
||||
return cl.time * 0.001f;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnGetMaxClients
|
||||
|
||||
=============
|
||||
*/
|
||||
int pfnGetMaxClients( void )
|
||||
{
|
||||
return com.atoi( cl.configstrings[CS_MAXCLIENTS] );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnGetViewModel
|
||||
|
||||
can return NULL
|
||||
=============
|
||||
*/
|
||||
edict_t* pfnGetViewModel( void )
|
||||
{
|
||||
return EDICT_NUM( cl.playernum + 1 )->v.aiment;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnPointContents
|
||||
|
||||
=============
|
||||
*/
|
||||
static int pfnPointContents( const float *rgflVector )
|
||||
{
|
||||
return CL_PointContents( rgflVector );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnTraceLine
|
||||
|
||||
=============
|
||||
*/
|
||||
static void pfnTraceLine( const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr )
|
||||
{
|
||||
trace_t trace;
|
||||
int move;
|
||||
|
||||
move = (fNoMonsters) ? MOVE_NOMONSTERS : MOVE_NORMAL;
|
||||
|
||||
if( IS_NAN(v1[0]) || IS_NAN(v1[1]) || IS_NAN(v1[2]) || IS_NAN(v2[0]) || IS_NAN(v1[2]) || IS_NAN(v2[2] ))
|
||||
Host_Error( "CL_Trace: NAN errors detected ('%f %f %f', '%f %f %f'\n", v1[0], v1[1], v1[2], v2[0], v2[1], v2[2] );
|
||||
|
||||
trace = CL_Trace( v1, vec3_origin, vec3_origin, v2, move, pentToSkip, CL_ContentsMask( pentToSkip ));
|
||||
CL_CopyTraceResult( ptr, trace );
|
||||
}
|
||||
|
||||
static triapi_t gTriApi =
|
||||
{
|
||||
sizeof( triapi_t ),
|
||||
};
|
||||
|
||||
// engine callbacks
|
||||
static cl_enginefuncs_t gEngfuncs =
|
||||
{
|
||||
sizeof( cl_enginefuncs_t ),
|
||||
pfnMemAlloc,
|
||||
pfnMemFree,
|
||||
pfnLoadShader,
|
||||
pfnFillRGBA,
|
||||
pfnDrawImage,
|
||||
pfnSetColor,
|
||||
pfnRegisterVariable,
|
||||
pfnCvarSetValue,
|
||||
pfnGetCvarFloat,
|
||||
pfnGetCvarString,
|
||||
pfnAddCommand,
|
||||
pfnHookUserMsg,
|
||||
pfnServerCmd,
|
||||
pfnClientCmd,
|
||||
pfnGetPlayerInfo,
|
||||
pfnTextMessageGet,
|
||||
pfnCmdArgc,
|
||||
pfnCmdArgv,
|
||||
pfnAlertMessage,
|
||||
pfnPlaySoundByName,
|
||||
pfnPlaySoundByIndex,
|
||||
AngleVectors,
|
||||
pfnDrawCenterPrint,
|
||||
pfnCenterPrint,
|
||||
pfnDrawCharacter,
|
||||
pfnDrawString,
|
||||
pfnGetImageSize,
|
||||
pfnGetViewAngles,
|
||||
pfnGetEntityByIndex,
|
||||
pfnGetLocalPlayer,
|
||||
pfnIsSpectateOnly,
|
||||
pfnGetClientTime,
|
||||
pfnGetMaxClients,
|
||||
pfnGetViewModel,
|
||||
pfnPointContents,
|
||||
pfnTraceLine,
|
||||
pfnRandomLong,
|
||||
pfnRandomFloat,
|
||||
pfnLoadFile,
|
||||
pfnFreeFile,
|
||||
pfnGetGameDir,
|
||||
Host_Error,
|
||||
&gTriApi
|
||||
};
|
||||
|
||||
/*
|
||||
====================
|
||||
StudioEvent
|
||||
|
||||
Event callback for studio models
|
||||
====================
|
||||
*/
|
||||
void CL_StudioEvent( dstudioevent_t *event, entity_state_t *ent )
|
||||
{
|
||||
// do upcast
|
||||
edict_t *pEdict = EDICT_NUM( ent->number );
|
||||
|
||||
cls.dllFuncs.pfnStudioEvent( event, pEdict );
|
||||
}
|
||||
|
||||
void CL_UnloadProgs( void )
|
||||
{
|
||||
// initialize game
|
||||
cls.dllFuncs.pfnShutdown();
|
||||
|
||||
StringTable_Delete( game.hStringTable );
|
||||
Com_FreeLibrary( cls.game );
|
||||
Mem_FreePool( &cls.mempool );
|
||||
Mem_FreePool( &cls.private );
|
||||
}
|
||||
|
||||
bool CL_LoadProgs( const char *name )
|
||||
{
|
||||
static CLIENTAPI GetClientAPI;
|
||||
string libname;
|
||||
edict_t *e;
|
||||
int i;
|
||||
|
||||
if( cls.game ) CL_UnloadProgs();
|
||||
|
||||
// fill it in
|
||||
com.snprintf( libname, MAX_STRING, "bin/%s.dll", name );
|
||||
cls.mempool = Mem_AllocPool( "Client Edicts Zone" );
|
||||
cls.private = Mem_AllocPool( "Client Private Zone" );
|
||||
|
||||
cls.game = Com_LoadLibrary( libname );
|
||||
if( !cls.game ) return false;
|
||||
|
||||
GetClientAPI = (CLIENTAPI)Com_GetProcAddress( cls.game, "CreateAPI" );
|
||||
|
||||
if( !GetClientAPI )
|
||||
{
|
||||
MsgDev( D_ERROR, "CL_LoadProgs: failed to get address of CreateAPI proc\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( !GetClientAPI( &cls.dllFuncs, &gEngfuncs, INTERFACE_VERSION ))
|
||||
{
|
||||
MsgDev( D_ERROR, "CL_LoadProgs: can't init client API\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
// 65535 unique strings should be enough ...
|
||||
game.hStringTable = StringTable_Create( "Client Strings", 0x10000 );
|
||||
StringTable_SetString( game.hStringTable, "" ); // make NULL string
|
||||
game.maxEntities = host.max_edicts; // FIXME: must come from CS_MAXENTITIES
|
||||
game.maxClients = Host_MaxClients();
|
||||
game.edicts = Mem_Alloc( cls.mempool, sizeof( edict_t ) * game.maxEntities );
|
||||
game.numMessages = 1; // message with index 0 it's svc_bad
|
||||
|
||||
for( i = 0, e = game.edicts; i < game.maxEntities; i++, e++ )
|
||||
e->free = true; // mark all edicts as freed
|
||||
|
||||
// initialize game
|
||||
cls.dllFuncs.pfnInit();
|
||||
|
||||
return true;
|
||||
}
|
|
@ -869,8 +869,6 @@ void CL_PacketEvent( netadr_t from, sizebuf_t *msg )
|
|||
if( host.type == HOST_DEDICATED || cls.demoplayback )
|
||||
return;
|
||||
|
||||
CL_VM_Begin();
|
||||
|
||||
if( msg->cursize >= 4 && *(int *)msg->data == -1 )
|
||||
{
|
||||
cls.netchan.last_received = cls.realtime;
|
||||
|
@ -906,7 +904,6 @@ void CL_PacketEvent( netadr_t from, sizebuf_t *msg )
|
|||
if( cls.demorecording && !cls.demowaiting )
|
||||
CL_WriteDemoMessage( msg, headerBytes );
|
||||
}
|
||||
CL_VM_End();
|
||||
}
|
||||
|
||||
void CL_ReadPackets( void )
|
||||
|
@ -1203,9 +1200,6 @@ void CL_Frame( dword time )
|
|||
// if in the debugger last frame, don't timeout
|
||||
if( time > 5000 ) cls.netchan.last_received = Sys_Milliseconds();
|
||||
|
||||
// setup the VM frame
|
||||
CL_VM_Begin();
|
||||
|
||||
// fetch results from server
|
||||
CL_ReadPackets();
|
||||
|
||||
|
@ -1235,9 +1229,6 @@ void CL_Frame( dword time )
|
|||
SCR_RunCinematic();
|
||||
Con_RunConsole();
|
||||
|
||||
// end the client VM frame
|
||||
CL_VM_End();
|
||||
|
||||
cls.framecount++;
|
||||
}
|
||||
|
||||
|
@ -1259,7 +1250,10 @@ void CL_Init( void )
|
|||
|
||||
Con_Init();
|
||||
VID_Init();
|
||||
CL_InitClientProgs();
|
||||
if( !CL_LoadProgs( "client" ))
|
||||
{
|
||||
Host_Error( "CL_InitGame: can't initialize client.dll\n" );
|
||||
}
|
||||
UI_Init();
|
||||
SCR_Init();
|
||||
CL_InitLocal();
|
||||
|
@ -1283,7 +1277,7 @@ void CL_Shutdown( void )
|
|||
if( !cls.initialized ) return;
|
||||
|
||||
CL_WriteConfiguration();
|
||||
CL_FreeClientProgs();
|
||||
CL_UnloadProgs();
|
||||
UI_Shutdown();
|
||||
S_Shutdown();
|
||||
SCR_Shutdown();
|
||||
|
|
|
@ -275,17 +275,16 @@ void CL_ParseBaseline( sizebuf_t *msg )
|
|||
{
|
||||
int newnum;
|
||||
entity_state_t nullstate;
|
||||
pr_edict_t *ent;
|
||||
edict_t *ent;
|
||||
|
||||
CL_VM_Begin();
|
||||
memset( &nullstate, 0, sizeof(nullstate));
|
||||
Mem_Set( &nullstate, 0, sizeof( nullstate ));
|
||||
newnum = MSG_ReadBits( msg, NET_WORD );
|
||||
|
||||
// increase edicts
|
||||
while( newnum >= prog->num_edicts ) PRVM_ED_Alloc();
|
||||
ent = PRVM_EDICT_NUM( newnum );
|
||||
while( newnum >= game.numEntities ) CL_AllocEdict();
|
||||
ent = EDICT_NUM( newnum );
|
||||
|
||||
MSG_ReadDeltaEntity( msg, &nullstate, &ent->priv.cl->baseline, newnum );
|
||||
MSG_ReadDeltaEntity( msg, &nullstate, &ent->pvEngineData->baseline, newnum );
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -301,7 +300,6 @@ void CL_ParseConfigString( sizebuf_t *msg )
|
|||
if( i < 0 || i >= MAX_CONFIGSTRINGS )
|
||||
Host_Error("configstring > MAX_CONFIGSTRINGS\n");
|
||||
com.strcpy( cl.configstrings[i], MSG_ReadString( msg ));
|
||||
CL_VM_Begin();
|
||||
|
||||
// do something apropriate
|
||||
if( i == CS_SKYNAME && cl.video_prepped )
|
||||
|
@ -327,13 +325,12 @@ void CL_ParseConfigString( sizebuf_t *msg )
|
|||
}
|
||||
else if( i >= CS_USER_MESSAGES && i < CS_USER_MESSAGES+MAX_USER_MESSAGES )
|
||||
{
|
||||
// FIXME: register user message here
|
||||
// Msg("PrepUserMessage: %s[svc_%i]\n", cl.configstrings[i], i - CS_USER_MESSAGES );
|
||||
CL_PrepUserMessage( cl.configstrings[i], i - CS_USER_MESSAGES );
|
||||
}
|
||||
else if( i >= CS_CLASSNAMES && i < CS_CLASSNAMES+MAX_CLASSNAMES )
|
||||
{
|
||||
// prvm classnames for search by classname on client vm
|
||||
cl.edict_classnames[i-CS_CLASSNAMES] = PRVM_SetEngineString( cl.configstrings[i] );
|
||||
// edicts classnames for search by classname on client
|
||||
cl.edict_classnames[i-CS_CLASSNAMES] = MAKE_STRING( cl.configstrings[i] );
|
||||
}
|
||||
else if( i >= CS_LIGHTSTYLES && i < CS_LIGHTSTYLES+MAX_LIGHTSTYLES )
|
||||
{
|
||||
|
@ -372,9 +369,6 @@ void CL_ParseServerMessage( sizebuf_t *msg )
|
|||
char *s;
|
||||
int cmd;
|
||||
|
||||
// client progs can recivied messages too
|
||||
cls.multicast = msg;
|
||||
|
||||
// parse the message
|
||||
while( 1 )
|
||||
{
|
||||
|
@ -442,9 +436,7 @@ void CL_ParseServerMessage( sizebuf_t *msg )
|
|||
Host_Error( "CL_ParseServerMessage: svc_bad\n" );
|
||||
break;
|
||||
default:
|
||||
// parse user messages
|
||||
if(!CL_ParseUserMessage( cmd ))
|
||||
Host_Error("CL_ParseServerMessage: illegible server message %d\n", cmd );
|
||||
CL_ParseUserMessage( msg, cmd );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,22 +1,7 @@
|
|||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
//=======================================================================
|
||||
// Copyright XashXT Group 2008 ©
|
||||
// cl_physics.c - client physic and prediction
|
||||
//=======================================================================
|
||||
|
||||
#include "common.h"
|
||||
#include "client.h"
|
||||
|
@ -62,18 +47,39 @@ void CL_CheckPredictionError (void)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
LINE TESTING IN HULLS
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
int CL_ContentsMask( const edict_t *passedict )
|
||||
{
|
||||
if( passedict )
|
||||
{
|
||||
if( passedict->v.flags & FL_MONSTER )
|
||||
return MASK_MONSTERSOLID;
|
||||
else if( passedict->v.flags & FL_CLIENT )
|
||||
return MASK_PLAYERSOLID;
|
||||
else if( passedict->v.solid == SOLID_TRIGGER )
|
||||
return CONTENTS_SOLID|CONTENTS_BODY;
|
||||
return MASK_SOLID;
|
||||
}
|
||||
return MASK_SOLID;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
CL_Trace
|
||||
==================
|
||||
*/
|
||||
trace_t CL_Trace( const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, pr_edict_t *passedict, int contentsmask )
|
||||
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;
|
||||
pr_edict_t *traceowner, *touch;
|
||||
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
|
||||
|
@ -83,7 +89,7 @@ trace_t CL_Trace( const vec3_t start, const vec3_t mins, const vec3_t maxs, cons
|
|||
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
|
||||
pr_edict_t *touchedicts[MAX_EDICTS];
|
||||
edict_t *touchedicts[MAX_EDICTS];
|
||||
|
||||
VectorCopy( start, clipstart );
|
||||
VectorCopy( end, clipend );
|
||||
|
@ -96,7 +102,7 @@ trace_t CL_Trace( const vec3_t start, const vec3_t mins, const vec3_t maxs, cons
|
|||
pe->ClipToWorld( &cliptrace, cl.worldmodel, clipstart, clipmins, clipmaxs, clipend, contentsmask );
|
||||
cliptrace.startstuck = cliptrace.startsolid;
|
||||
if( cliptrace.startsolid || cliptrace.fraction < 1 )
|
||||
cliptrace.ent = prog ? (edict_t *)prog->edicts : NULL;
|
||||
cliptrace.ent = (edict_t *)EDICT_NUM( 0 );
|
||||
if( type == MOVE_WORLDONLY ) return cliptrace;
|
||||
|
||||
if( type == MOVE_MISSILE )
|
||||
|
@ -120,21 +126,18 @@ trace_t CL_Trace( const vec3_t start, const vec3_t mins, const vec3_t maxs, cons
|
|||
}
|
||||
|
||||
// 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;
|
||||
if( passedict == EDICT_NUM( 0 )) passedict = NULL;
|
||||
// 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;
|
||||
if( passedict && passedict->v.owner )
|
||||
traceowner = passedict->v.owner;
|
||||
else traceowner = 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 );
|
||||
numtouchedicts = 0;// FIXME: CL_AreaEdicts( clipboxmins, clipboxmaxs, touchedicts, host.max_edicts );
|
||||
if( numtouchedicts > host.max_edicts )
|
||||
{
|
||||
// this never happens
|
||||
|
@ -144,9 +147,8 @@ trace_t CL_Trace( const vec3_t start, const vec3_t mins, const vec3_t maxs, cons
|
|||
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 )
|
||||
if( touch->v.solid < SOLID_BBOX ) continue;
|
||||
if( type == MOVE_NOMONSTERS && touch->v.solid != SOLID_BSP )
|
||||
continue;
|
||||
|
||||
if( passedict )
|
||||
|
@ -156,9 +158,9 @@ trace_t CL_Trace( const vec3_t start, const vec3_t mins, const vec3_t maxs, cons
|
|||
// 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;
|
||||
if( passedict == touch->v.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)))
|
||||
if( pointtrace && VectorCompare( touch->v.mins, touch->v.maxs ) && (type != MOVE_MISSILE || !(touch->v.flags & FL_MONSTER)))
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -166,20 +168,20 @@ trace_t CL_Trace( const vec3_t start, const vec3_t mins, const vec3_t maxs, cons
|
|||
|
||||
// might interact, so do an exact clip
|
||||
model = NULL;
|
||||
if((int)touch->progs.cl->solid == SOLID_BSP || type == MOVE_HITMODEL )
|
||||
if( touch->v.solid == SOLID_BSP || type == MOVE_HITMODEL )
|
||||
{
|
||||
uint modelindex = (uint)touch->progs.cl->modelindex;
|
||||
uint modelindex = (uint)touch->v.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];
|
||||
model = cl.models[touch->v.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] );
|
||||
if( model ) Matrix4x4_CreateFromEntity( matrix, touch->v.origin[0], touch->v.origin[1], touch->v.origin[2], touch->v.angles[0], touch->v.angles[1], touch->v.angles[2], 1 );
|
||||
else Matrix4x4_CreateTranslate( matrix, touch->v.origin[0], touch->v.origin[1], touch->v.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, (edict_t *)touch, touch->progs.cl->solid == SOLID_BSP );
|
||||
if( touch->v.flags & FL_MONSTER )
|
||||
pe->ClipToGenericEntity(&trace, model, touch->v.mins, touch->v.maxs, bodycontents, matrix, imatrix, clipstart, clipmins2, clipmaxs2, clipend, contentsmask );
|
||||
else pe->ClipToGenericEntity(&trace, model, touch->v.mins, touch->v.maxs, bodycontents, matrix, imatrix, clipstart, clipmins, clipmaxs, clipend, contentsmask );
|
||||
pe->CombineTraces( &cliptrace, &trace, (edict_t *)touch, touch->v.solid == SOLID_BSP );
|
||||
}
|
||||
return cliptrace;
|
||||
}
|
|
@ -6,222 +6,6 @@
|
|||
#include "common.h"
|
||||
#include "client.h"
|
||||
|
||||
/*
|
||||
================
|
||||
CL_FadeColor
|
||||
================
|
||||
*/
|
||||
float *CL_FadeColor( float starttime, float endtime )
|
||||
{
|
||||
static vec4_t color;
|
||||
float time, fade_time;
|
||||
|
||||
if( starttime == 0 ) return NULL;
|
||||
time = (cls.realtime * 0.001f) - starttime;
|
||||
if( time >= endtime ) return NULL;
|
||||
|
||||
// fade time is 1/4 of endtime
|
||||
fade_time = endtime / 4;
|
||||
fade_time = bound( 0.3f, fade_time, 10.0f );
|
||||
|
||||
// fade out
|
||||
if((endtime - time) < fade_time)
|
||||
color[3] = (endtime - time) * 1.0f / fade_time;
|
||||
else color[3] = 1.0;
|
||||
color[0] = color[1] = color[2] = 1.0f;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
void CL_DrawHUD( void )
|
||||
{
|
||||
CL_VM_Begin();
|
||||
|
||||
// setup pparms
|
||||
prog->globals.cl->health = cl.frame.ps.health;
|
||||
prog->globals.cl->maxclients = com.atoi(cl.configstrings[CS_MAXCLIENTS]);
|
||||
prog->globals.cl->max_entities = host.max_edicts;
|
||||
prog->globals.cl->realtime = cls.realtime * 0.001f;
|
||||
prog->globals.cl->paused = cl_paused->integer;
|
||||
|
||||
// setup args
|
||||
PRVM_G_FLOAT(OFS_PARM0) = (float)cls.state;
|
||||
PRVM_ExecuteProgram (prog->globals.cl->HUD_Render, "HUD_Render");
|
||||
}
|
||||
|
||||
bool CL_ParseUserMessage( int svc_number )
|
||||
{
|
||||
bool msg_parsed = false;
|
||||
|
||||
// setup pparms
|
||||
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;
|
||||
|
||||
// setup args
|
||||
PRVM_G_FLOAT(OFS_PARM0) = (float)svc_number;
|
||||
PRVM_ExecuteProgram (prog->globals.cl->HUD_ParseMessage, "HUD_ParseMessage");
|
||||
msg_parsed = (bool)PRVM_G_FLOAT(OFS_RETURN);
|
||||
|
||||
return msg_parsed;
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
StudioEvent
|
||||
|
||||
Event callback for studio models
|
||||
====================
|
||||
*/
|
||||
void CL_StudioEvent ( dstudioevent_t *event, entity_state_t *ent )
|
||||
{
|
||||
// setup args
|
||||
PRVM_G_FLOAT(OFS_PARM0) = (float)event->event;
|
||||
PRVM_G_INT(OFS_PARM1) = PRVM_SetEngineString( event->options );
|
||||
VectorCopy( ent->origin, PRVM_G_VECTOR(OFS_PARM2));
|
||||
VectorCopy( ent->angles, PRVM_G_VECTOR(OFS_PARM3));
|
||||
PRVM_ExecuteProgram( prog->globals.cl->HUD_StudioEvent, "HUD_StudioEvent");
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
GetClientEntity
|
||||
|
||||
Render callback for studio models
|
||||
====================
|
||||
*/
|
||||
entity_state_t *CL_GetEdictByIndex( int index )
|
||||
{
|
||||
return &PRVM_EDICT_NUM( index )->priv.cl->current;
|
||||
}
|
||||
|
||||
entity_state_t *CL_GetLocalPlayer( void )
|
||||
{
|
||||
return &PRVM_EDICT_NUM( cl.playernum + 1 )->priv.cl->current;
|
||||
}
|
||||
|
||||
int CL_GetMaxClients( void )
|
||||
{
|
||||
return com.atoi(cl.configstrings[CS_MAXCLIENTS]);
|
||||
}
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
Client Builtin Functions
|
||||
|
||||
mathlib, debugger, and various misc helpers
|
||||
===============================================================================
|
||||
*/
|
||||
void CL_BeginIncreaseEdicts( void )
|
||||
{
|
||||
int i;
|
||||
pr_edict_t *ent;
|
||||
|
||||
// links don't survive the transition, so unlink everything
|
||||
for (i = 0, ent = prog->edicts; i < prog->max_edicts; i++, ent++)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
void CL_EndIncreaseEdicts( void )
|
||||
{
|
||||
int i;
|
||||
pr_edict_t *ent;
|
||||
|
||||
for (i = 0, ent = prog->edicts; i < prog->max_edicts; i++, ent++)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
void CL_InitEdict( pr_edict_t *e )
|
||||
{
|
||||
e->priv.cl->serialnumber = PRVM_NUM_FOR_EDICT(e);
|
||||
e->priv.cl->free = false;
|
||||
}
|
||||
|
||||
void CL_FreeEdict( pr_edict_t *ed )
|
||||
{
|
||||
ed->priv.cl->freetime = cl.time * 0.001f;
|
||||
ed->priv.cl->free = true;
|
||||
|
||||
ed->progs.cl->model = 0;
|
||||
ed->progs.cl->modelindex = 0;
|
||||
ed->progs.cl->soundindex = 0;
|
||||
ed->progs.cl->skin = 0;
|
||||
ed->progs.cl->frame = 0;
|
||||
VectorClear(ed->progs.cl->origin);
|
||||
VectorClear(ed->progs.cl->angles);
|
||||
}
|
||||
|
||||
void CL_FreeEdicts( void )
|
||||
{
|
||||
int i;
|
||||
pr_edict_t *ent;
|
||||
|
||||
CL_VM_Begin();
|
||||
for( i = 1; prog && i < prog->num_edicts; i++ )
|
||||
{
|
||||
ent = PRVM_EDICT_NUM(i);
|
||||
CL_FreeEdict( ent );
|
||||
}
|
||||
CL_VM_End();
|
||||
}
|
||||
|
||||
void CL_CountEdicts( void )
|
||||
{
|
||||
pr_edict_t *ent;
|
||||
int i, active = 0, models = 0;
|
||||
|
||||
for (i = 0; i < prog->num_edicts; i++)
|
||||
{
|
||||
ent = PRVM_EDICT_NUM(i);
|
||||
if (ent->priv.cl->free) continue;
|
||||
active++;
|
||||
if (ent->progs.cl->model) models++;
|
||||
}
|
||||
|
||||
Msg("num_edicts:%3i\n", prog->num_edicts);
|
||||
Msg("active :%3i\n", active);
|
||||
Msg("view :%3i\n", models);
|
||||
}
|
||||
|
||||
void CL_VM_Begin( void )
|
||||
{
|
||||
PRVM_Begin;
|
||||
PRVM_SetProg( PRVM_CLIENTPROG );
|
||||
|
||||
if( prog ) *prog->time = cl.time * 0.001f;
|
||||
}
|
||||
|
||||
void CL_VM_End( void )
|
||||
{
|
||||
PRVM_End;
|
||||
}
|
||||
|
||||
bool CL_LoadEdict( pr_edict_t *ent )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static void PF_BeginRead( void )
|
||||
{
|
||||
}
|
||||
|
||||
static void PF_EndRead( void )
|
||||
{
|
||||
}
|
||||
|
||||
static void PF_ReadChar (void){ PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadChar( cls.multicast ); }
|
||||
static void PF_ReadByte (void){ PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadByte( cls.multicast ); }
|
||||
static void PF_ReadShort (void){ PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadShort( cls.multicast ); }
|
||||
static void PF_ReadLong (void){ PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadLong( cls.multicast ); }
|
||||
static void PF_ReadFloat (void){ PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadFloat( cls.multicast ); }
|
||||
static void PF_ReadAngle (void){ PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadBits( cls.multicast, NET_FLOAT ); }
|
||||
static void PF_ReadCoord (void){ PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadBits( cls.multicast, NET_FLOAT ); }
|
||||
static void PF_ReadString (void){ PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString( MSG_ReadString( cls.multicast) ); }
|
||||
static void PF_ReadEntity (void){ VM_RETURN_EDICT( PRVM_PROG_TO_EDICT( MSG_ReadShort( cls.multicast ))); } // entindex
|
||||
|
||||
/*
|
||||
=========
|
||||
PF_drawnet
|
||||
|
@ -294,96 +78,6 @@ static void PF_drawfps( void )
|
|||
SCR_DrawBigStringColor(pos[0], pos[1], fpsstring, color );
|
||||
}
|
||||
|
||||
/*
|
||||
=========
|
||||
PF_drawcenterprint
|
||||
|
||||
void DrawCenterPrint( void )
|
||||
=========
|
||||
*/
|
||||
static void PF_drawcenterprint( void )
|
||||
{
|
||||
char *start;
|
||||
int l, x, y, w;
|
||||
float *color;
|
||||
|
||||
if(!cl.centerPrintTime ) return;
|
||||
if(!VM_ValidateArgs( "DrawCenterPrint", 0 ))
|
||||
return;
|
||||
|
||||
color = CL_FadeColor( cl.centerPrintTime * 0.001f, scr_centertime->value );
|
||||
if( !color )
|
||||
{
|
||||
cl.centerPrintTime = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
re->SetColor( color );
|
||||
start = cl.centerPrint;
|
||||
y = cl.centerPrintY - cl.centerPrintLines * BIGCHAR_HEIGHT/2;
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
char linebuffer[1024];
|
||||
|
||||
for ( l = 0; l < 50; l++ )
|
||||
{
|
||||
if ( !start[l] || start[l] == '\n' )
|
||||
break;
|
||||
linebuffer[l] = start[l];
|
||||
}
|
||||
linebuffer[l] = 0;
|
||||
|
||||
w = cl.centerPrintCharWidth * com.cstrlen( linebuffer );
|
||||
x = ( SCREEN_WIDTH - w )>>1;
|
||||
|
||||
SCR_DrawStringExt( x, y, cl.centerPrintCharWidth, BIGCHAR_HEIGHT, linebuffer, color, false );
|
||||
|
||||
y += cl.centerPrintCharWidth * 1.5;
|
||||
while ( *start && ( *start != '\n' )) start++;
|
||||
if( !*start ) break;
|
||||
start++;
|
||||
}
|
||||
re->SetColor( NULL );
|
||||
}
|
||||
|
||||
/*
|
||||
=========
|
||||
PF_centerprint
|
||||
|
||||
void HUD_CenterPrint( string text, float y, float charwidth )
|
||||
=========
|
||||
*/
|
||||
static void PF_centerprint( void )
|
||||
{
|
||||
float y, width;
|
||||
const char *text;
|
||||
char *s;
|
||||
|
||||
if(!VM_ValidateArgs( "HUD_CenterPrint", 3 ))
|
||||
return;
|
||||
|
||||
text = PRVM_G_STRING(OFS_PARM0);
|
||||
y = PRVM_G_FLOAT(OFS_PARM1);
|
||||
width = PRVM_G_FLOAT(OFS_PARM2);
|
||||
VM_ValidateString( text );
|
||||
|
||||
com.strncpy( cl.centerPrint, text, sizeof(cl.centerPrint));
|
||||
|
||||
cl.centerPrintTime = cls.realtime;
|
||||
cl.centerPrintY = y;
|
||||
cl.centerPrintCharWidth = width;
|
||||
|
||||
// count the number of lines for centering
|
||||
cl.centerPrintLines = 1;
|
||||
s = cl.centerPrint;
|
||||
while( *s )
|
||||
{
|
||||
if (*s == '\n') cl.centerPrintLines++;
|
||||
s++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=========
|
||||
PF_levelshot
|
||||
|
@ -408,96 +102,6 @@ static void PF_levelshot( void )
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=========
|
||||
PF_setcolor
|
||||
|
||||
void HUD_SetColor( vector rgb, float alpha )
|
||||
=========
|
||||
*/
|
||||
static void PF_setcolor( void )
|
||||
{
|
||||
float *rgb, alpha;
|
||||
|
||||
if(!VM_ValidateArgs( "HUD_SetColor", 2 ))
|
||||
return;
|
||||
|
||||
rgb = PRVM_G_VECTOR(OFS_PARM0);
|
||||
alpha = PRVM_G_FLOAT(OFS_PARM1);
|
||||
re->SetColor( GetRGBA( rgb[0], rgb[1], rgb[2], alpha ));
|
||||
}
|
||||
|
||||
/*
|
||||
=========
|
||||
PF_startsound
|
||||
|
||||
void CL_StartSound( vector pos, entity e, float chan, float sfx, float vol, float attn, float pitch, float localsound )
|
||||
=========
|
||||
*/
|
||||
static void PF_startsound( void )
|
||||
{
|
||||
float volume;
|
||||
int channel;
|
||||
sound_t sound_num;
|
||||
int attenuation;
|
||||
float *pos = NULL;
|
||||
bool client_sound;
|
||||
int ent = 0;
|
||||
float pitch;
|
||||
|
||||
if( !VM_ValidateArgs( "CL_StartSound", 8 ))
|
||||
return;
|
||||
|
||||
pos = PRVM_G_VECTOR(OFS_PARM0);
|
||||
ent = PRVM_G_EDICTNUM(OFS_PARM1);
|
||||
channel = (int)PRVM_G_FLOAT(OFS_PARM2);
|
||||
sound_num = (sound_t)PRVM_G_FLOAT(OFS_PARM3);
|
||||
volume = PRVM_G_FLOAT(OFS_PARM4);
|
||||
attenuation = (int)PRVM_G_FLOAT(OFS_PARM5);
|
||||
pitch = (int)PRVM_G_FLOAT(OFS_PARM6);
|
||||
client_sound = (bool)PRVM_G_FLOAT(OFS_PARM7);
|
||||
|
||||
if( client_sound )
|
||||
{
|
||||
S_StartSound( pos, ent, channel, sound_num, volume, attenuation, pitch );
|
||||
}
|
||||
else if( cl.sound_precache[sound_num] )
|
||||
{
|
||||
S_StartSound( pos, ent, channel, cl.sound_precache[sound_num], volume, attenuation, pitch );
|
||||
}
|
||||
else VM_Warning( "CL_StartSound: can't play sound with index %i\n", sound_num );
|
||||
}
|
||||
|
||||
/*
|
||||
=========
|
||||
PF_pointcontents
|
||||
|
||||
float CL_PointContents( vector point )
|
||||
=========
|
||||
*/
|
||||
static void PF_pointcontents( void )
|
||||
{
|
||||
if( !VM_ValidateArgs( "CL_PointContents", 1 ))
|
||||
return;
|
||||
PRVM_G_FLOAT(OFS_RETURN) = CL_PointContents(PRVM_G_VECTOR(OFS_PARM0));
|
||||
}
|
||||
|
||||
/*
|
||||
=========
|
||||
PF_startsound
|
||||
|
||||
sound_t CL_PrecacheSound( string samp )
|
||||
=========
|
||||
*/
|
||||
static void PF_precachesound( void )
|
||||
{
|
||||
if( !VM_ValidateArgs( "CL_PrecacheSound", 1 ))
|
||||
return;
|
||||
|
||||
VM_ValidateString(PRVM_G_STRING(OFS_PARM0));
|
||||
PRVM_G_FLOAT(OFS_RETURN) = S_RegisterSound(PRVM_G_STRING(OFS_PARM0));
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
PF_findexplosionplane
|
||||
|
@ -537,197 +141,3 @@ static void PF_findexplosionplane( void )
|
|||
}
|
||||
VectorCopy( dir, PRVM_G_VECTOR( OFS_RETURN ));
|
||||
}
|
||||
|
||||
// NOTE: intervals between various "interfaces" was leave for future expansions
|
||||
prvm_builtin_t vm_cl_builtins[] =
|
||||
{
|
||||
NULL, // #0 (leave blank as default, but can include easter egg )
|
||||
|
||||
// system events
|
||||
VM_ConPrintf, // #1 void Con_Printf( ... )
|
||||
VM_ConDPrintf, // #2 void Con_DPrintf( float level, ... )
|
||||
VM_HostError, // #3 void Com_Error( ... )
|
||||
VM_SysExit, // #4 void Sys_Exit( void )
|
||||
VM_CmdArgv, // #5 string Cmd_Argv( float arg )
|
||||
VM_CmdArgc, // #6 float Cmd_Argc( void )
|
||||
NULL, // #7 -- reserved --
|
||||
NULL, // #8 -- reserved --
|
||||
NULL, // #9 -- reserved --
|
||||
NULL, // #10 -- reserved --
|
||||
|
||||
// common tools
|
||||
VM_ComTrace, // #11 void Com_Trace( float enable )
|
||||
VM_ComFileExists, // #12 float Com_FileExists( string filename )
|
||||
VM_ComFileSize, // #13 float Com_FileSize( string filename )
|
||||
VM_ComFileTime, // #14 float Com_FileTime( string filename )
|
||||
VM_ComLoadScript, // #15 float Com_LoadScript( string filename )
|
||||
VM_ComResetScript, // #16 void Com_ResetScript( void )
|
||||
VM_ComReadToken, // #17 string Com_ReadToken( float newline )
|
||||
VM_Random, // #18 float Random( void )
|
||||
VM_ComSearchFiles, // #19 float Com_Search( string mask, float casecmp )
|
||||
VM_ComSearchNames, // #20 string Com_SearchFilename( float num )
|
||||
VM_RandomLong, // #21 float RandomLong( float min, float max )
|
||||
VM_RandomFloat, // #22 float RandomFloat( float min, float max )
|
||||
VM_RandomVector, // #23 vector RandomVector( vector min, vector max )
|
||||
VM_CvarRegister, // #24 void Cvar_Register( string name, string value, float flags )
|
||||
VM_CvarSetValue, // #25 void Cvar_SetValue( string name, float value )
|
||||
VM_CvarGetValue, // #26 float Cvar_GetValue( string name )
|
||||
VM_CvarSetString, // #27 void Cvar_SetString( string name, string value )
|
||||
VM_CvarGetString, // #28 void VM_CvarGetString( void )
|
||||
VM_ComVA, // #29 string va( ... )
|
||||
VM_ComStrlen, // #30 float strlen( string text )
|
||||
VM_TimeStamp, // #31 string Com_TimeStamp( float format )
|
||||
VM_LocalCmd, // #32 void LocalCmd( ... )
|
||||
VM_SubString, // #33 string substring( string s, float start, float length )
|
||||
VM_AddCommand, // #34 void Add_Command( string s )
|
||||
VM_atof, // #35 float atof( string s )
|
||||
VM_atoi, // #36 float atoi( string s )
|
||||
VM_atov, // #37 vector atov( string s )
|
||||
NULL, // #38 -- reserved --
|
||||
NULL, // #39 -- reserved --
|
||||
NULL, // #40 -- reserved --
|
||||
|
||||
// quakec intrinsics ( compiler will be lookup this functions, don't remove or rename )
|
||||
VM_SpawnEdict, // #41 entity spawn( void )
|
||||
VM_RemoveEdict, // #42 void remove( entity ent )
|
||||
VM_NextEdict, // #43 entity nextent( entity ent )
|
||||
VM_CopyEdict, // #44 void copyentity( entity src, entity dst )
|
||||
NULL, // #45 -- reserved --
|
||||
NULL, // #46 -- reserved --
|
||||
NULL, // #47 -- reserved --
|
||||
NULL, // #48 -- reserved --
|
||||
NULL, // #49 -- reserved --
|
||||
NULL, // #50 -- reserved --
|
||||
|
||||
// filesystem
|
||||
VM_FS_Open, // #51 float fopen( string filename, float mode )
|
||||
VM_FS_Close, // #52 void fclose( float handle )
|
||||
VM_FS_Gets, // #53 string fgets( float handle )
|
||||
VM_FS_Puts, // #54 void fputs( float handle, string s )
|
||||
NULL, // #55 -- reserved --
|
||||
NULL, // #56 -- reserved --
|
||||
NULL, // #57 -- reserved --
|
||||
NULL, // #58 -- reserved --
|
||||
NULL, // #59 -- reserved --
|
||||
NULL, // #60 -- reserved --
|
||||
|
||||
// mathlib
|
||||
VM_min, // #61 float min(float a, float b )
|
||||
VM_max, // #62 float max(float a, float b )
|
||||
VM_bound, // #63 float bound(float min, float val, float max)
|
||||
VM_pow, // #64 float pow(float x, float y)
|
||||
VM_sin, // #65 float sin(float f)
|
||||
VM_cos, // #66 float cos(float f)
|
||||
VM_tan, // #67 float tan(float f)
|
||||
VM_asin, // #68 float asin(float f)
|
||||
VM_acos, // #69 float acos(float f)
|
||||
VM_atan, // #70 float atan(float f)
|
||||
VM_sqrt, // #71 float sqrt(float f)
|
||||
VM_rint, // #72 float rint (float v)
|
||||
VM_floor, // #73 float floor(float v)
|
||||
VM_ceil, // #74 float ceil (float v)
|
||||
VM_fabs, // #75 float fabs (float f)
|
||||
VM_abs, // #76 float abs (float f)
|
||||
NULL, // #77 -- reserved --
|
||||
NULL, // #78 -- reserved --
|
||||
VM_VectorNormalize, // #79 vector VectorNormalize( vector v )
|
||||
VM_VectorLength, // #80 float VectorLength( vector v )
|
||||
e10, e10, // #81 - #100 are reserved for future expansions
|
||||
|
||||
// network messaging
|
||||
PF_BeginRead, // #101 void MsgBegin( void )
|
||||
PF_ReadByte, // #102 float ReadByte( void )
|
||||
PF_ReadChar, // #103 float ReadChar( void )
|
||||
PF_ReadShort, // #104 float ReadShort( void )
|
||||
PF_ReadLong, // #105 float ReadLong( void )
|
||||
PF_ReadFloat, // #106 float ReadFloat( void )
|
||||
PF_ReadAngle, // #107 float ReadAngle( void )
|
||||
PF_ReadCoord, // #108 float ReadCoord( void )
|
||||
PF_ReadString, // #109 string ReadString( void )
|
||||
PF_ReadEntity, // #110 entity ReadEntity( void )
|
||||
PF_EndRead, // #111 void MsgEnd( void )
|
||||
|
||||
// clientfuncs_t
|
||||
VM_precache_pic, // #112 float precache_pic( string pic )
|
||||
VM_drawcharacter, // #113 float DrawChar( vector pos, float char, vector scale, vector rgb, float alpha )
|
||||
VM_drawstring, // #114 float DrawString( vector pos, string text, vector scale, vector rgb, float alpha )
|
||||
VM_drawpic, // #115 float DrawPic( vector pos, string pic, vector size, vector rgb, float alpha )
|
||||
VM_drawfill, // #116 void DrawFill( vector pos, vector size, vector rgb, float alpha )
|
||||
VM_drawmodel, // #117 void DrawModel( vector pos, vector size, string mod, vector org, vector ang, float seq )
|
||||
NULL, // #118 -- reserved --
|
||||
VM_getimagesize, // #119 vector getimagesize( string pic )
|
||||
PF_drawnet, // #120 void DrawNet( vector pos, string image )
|
||||
PF_drawfps, // #121 void DrawFPS( vector pos )
|
||||
PF_drawcenterprint, // #122 void DrawCenterPrint( void )
|
||||
PF_centerprint, // #123 void HUD_CenterPrint( string text, float y, float charwidth )
|
||||
PF_levelshot, // #124 float HUD_MakeLevelShot( void )
|
||||
PF_setcolor, // #125 void HUD_SetColor( vector rgb, float alpha )
|
||||
VM_localsound, // #126 void HUD_PlaySound( string sample )
|
||||
PF_startsound, // #127 void CL_StartSound( vector, entity, float, float, float, float, float, float )
|
||||
PF_addparticle, // #128 float AddParticle(vector, vector, vector, vector, vector, vector, vector, string, float)
|
||||
PF_pointcontents, // #129 float CL_PointContents( vector point )
|
||||
PF_precachesound, // #130 sound_t CL_PrecacheSound( string samp )
|
||||
PF_adddecal, // #131 void AddDecal( vector, vector, vector, float, float, float, float, string, float )
|
||||
PF_addlight, // #132 void AddLight( vector pos, vector col, float rad, float decay, float time, float key )
|
||||
NULL, // #133
|
||||
NULL, // #134
|
||||
NULL, // #135
|
||||
NULL, // #136
|
||||
NULL, // #137
|
||||
PF_findexplosionplane, // #138 vector CL_FindExplosionPlane( vector org, float radius )
|
||||
};
|
||||
|
||||
const int vm_cl_numbuiltins = sizeof(vm_cl_builtins) / sizeof(prvm_builtin_t); //num of builtins
|
||||
|
||||
void CL_InitClientProgs( void )
|
||||
{
|
||||
Msg("\n");
|
||||
PRVM_Begin;
|
||||
|
||||
PRVM_InitProg( PRVM_CLIENTPROG );
|
||||
if( !prog->loaded )
|
||||
{
|
||||
prog->progs_mempool = Mem_AllocPool( "Client Progs" );
|
||||
prog->name = "client";
|
||||
prog->builtins = vm_cl_builtins;
|
||||
prog->numbuiltins = vm_cl_numbuiltins;
|
||||
prog->edictprivate_size = sizeof(cl_edict_t);
|
||||
prog->max_edicts = host.max_edicts<<2;
|
||||
prog->limit_edicts = host.max_edicts;
|
||||
prog->begin_increase_edicts = CL_BeginIncreaseEdicts;
|
||||
prog->end_increase_edicts = CL_EndIncreaseEdicts;
|
||||
prog->init_edict = CL_InitEdict;
|
||||
prog->free_edict = CL_FreeEdict;
|
||||
prog->count_edicts = CL_CountEdicts;
|
||||
prog->load_edict = CL_LoadEdict;
|
||||
prog->filecrc = PROG_CRC_CLIENT;
|
||||
|
||||
// using default builtins
|
||||
prog->init_cmd = VM_Cmd_Init;
|
||||
prog->reset_cmd = VM_Cmd_Reset;
|
||||
prog->error_cmd = VM_Error;
|
||||
PRVM_LoadProgs( va("%s/client.dat", GI->vprogs_dir ));
|
||||
}
|
||||
|
||||
// init some globals
|
||||
prog->globals.cl->realtime = cls.realtime * 0.001f;
|
||||
prog->globals.cl->pev = 0;
|
||||
prog->globals.cl->mapname = PRVM_SetEngineString( cls.servername );
|
||||
prog->globals.cl->playernum = cl.playernum;
|
||||
|
||||
// call the prog init
|
||||
PRVM_ExecuteProgram( prog->globals.cl->HUD_Init, "HUD_Init" );
|
||||
PRVM_End;
|
||||
}
|
||||
|
||||
void CL_FreeClientProgs( void )
|
||||
{
|
||||
CL_VM_Begin();
|
||||
|
||||
prog->globals.cl->realtime = cls.realtime * 0.001f;
|
||||
prog->globals.cl->pev = 0;
|
||||
PRVM_ExecuteProgram(prog->globals.cl->HUD_Shutdown, "HUD_Shutdown");
|
||||
PRVM_ResetProg();
|
||||
|
||||
CL_VM_End();
|
||||
}
|
|
@ -177,9 +177,9 @@ void SCR_DrawStringExt( int x, int y, float w, float h, const char *string, floa
|
|||
re->SetColor( setColor );
|
||||
while ( *s )
|
||||
{
|
||||
if(IsColorString( s ))
|
||||
if( IsColorString( s ))
|
||||
{
|
||||
if ( !forceColor )
|
||||
if( !forceColor )
|
||||
{
|
||||
Mem_Copy( color, g_color_table[ColorIndex(*(s+1))], sizeof( color ));
|
||||
color[3] = setColor[3];
|
||||
|
@ -343,8 +343,6 @@ SCR_Init
|
|||
*/
|
||||
void SCR_Init( void )
|
||||
{
|
||||
cls.mempool = Mem_AllocPool( "Client Static" );
|
||||
|
||||
scr_showpause = Cvar_Get("scr_showpause", "1", 0, "show pause picture" );
|
||||
scr_centertime = Cvar_Get("scr_centertime", "2.5", 0, "centerprint hold time" );
|
||||
scr_printspeed = Cvar_Get("scr_printspeed", "8", 0, "centerprint speed of print" );
|
||||
|
@ -368,5 +366,4 @@ void SCR_Init( void )
|
|||
|
||||
void SCR_Shutdown( void )
|
||||
{
|
||||
Mem_FreePool( &cls.mempool );
|
||||
}
|
|
@ -157,7 +157,6 @@ void V_RenderView( void )
|
|||
// build a refresh entity list and calc cl.sim*
|
||||
// this also calls CL_CalcViewValues which loads
|
||||
// v_forward, etc.
|
||||
CL_VM_Begin();
|
||||
CL_AddEntities ();
|
||||
|
||||
if( cl_testentities->value ) V_TestEntities();
|
||||
|
|
|
@ -23,7 +23,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#define CLIENT_H
|
||||
|
||||
#include "mathlib.h"
|
||||
#include "cl_edict.h"
|
||||
#include "entity_def.h"
|
||||
#include "clgame_api.h"
|
||||
#include "render_api.h"
|
||||
|
||||
#define MAX_EDIT_LINE 256
|
||||
|
@ -31,6 +32,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#define MAX_SERVERS 64
|
||||
#define ColorIndex(c) (((c) - '0') & 7)
|
||||
|
||||
#define NUM_FOR_EDICT(e) ((int)((edict_t *)(e) - game.edicts))
|
||||
#define EDICT_NUM( num ) _EDICT_NUM( num, __FILE__, __LINE__ )
|
||||
|
||||
//=============================================================================
|
||||
typedef struct frame_s
|
||||
{
|
||||
|
@ -163,15 +167,11 @@ typedef enum
|
|||
dl_generic,
|
||||
} dltype_t; // download type
|
||||
|
||||
struct cl_edict_s
|
||||
// cl_private_edict_t
|
||||
struct ed_priv_s
|
||||
{
|
||||
// generic_edict_t (don't move these fields!)
|
||||
bool free;
|
||||
float freetime; // cl.time when the object was freed
|
||||
int serverframe; // if not current, this ent isn't in the frame
|
||||
int serialnumber; // client serialnumber
|
||||
|
||||
// cl_private_edict_t
|
||||
entity_state_t baseline; // delta from this if not from a previous frame
|
||||
entity_state_t current;
|
||||
entity_state_t prev; // will always be valid, but might just be a copy of current
|
||||
|
@ -195,7 +195,32 @@ typedef struct serverinfo_s
|
|||
|
||||
} serverinfo_t;
|
||||
|
||||
typedef enum {key_game, key_console, key_message, key_menu} keydest_t;
|
||||
typedef enum { key_game, key_console, key_message, key_menu } keydest_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *name;
|
||||
int number; // svc_ number
|
||||
int size; // if size == -1, size come from first byte after svcnum
|
||||
pfnUserMsgHook func; // user-defined function
|
||||
} user_message_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int maxClients;
|
||||
int numEntities;
|
||||
int maxEntities;
|
||||
user_message_t *msg[MAX_USER_MESSAGES];
|
||||
int numMessages; // actual count of user messages
|
||||
|
||||
union
|
||||
{
|
||||
edict_t *edicts; // acess by edict number
|
||||
void *vp; // acess by offset in bytes
|
||||
};
|
||||
|
||||
int hStringTable; // stringtable handle
|
||||
} clgame_static_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
@ -203,7 +228,11 @@ typedef struct
|
|||
bool initialized;
|
||||
|
||||
keydest_t key_dest;
|
||||
byte *mempool;
|
||||
|
||||
void *game; // pointer to client.dll
|
||||
HUD_FUNCTIONS dllFuncs; // dll exported funcs
|
||||
byte *mempool; // edicts pool
|
||||
byte *private; // client.dll private pool
|
||||
|
||||
int framecount;
|
||||
dword realtime; // always increasing, no clamping, etc
|
||||
|
@ -214,7 +243,6 @@ typedef struct
|
|||
float connect_time; // for connection retransmits
|
||||
|
||||
netchan_t netchan;
|
||||
sizebuf_t *multicast; // ptr for current message buffer (net or demo flow)
|
||||
int serverProtocol; // in case we are doing some kind of version hack
|
||||
|
||||
int challenge; // from the server to use for connecting
|
||||
|
@ -245,6 +273,7 @@ typedef struct
|
|||
} client_static_t;
|
||||
|
||||
extern client_static_t cls;
|
||||
extern clgame_static_t game;
|
||||
|
||||
/*
|
||||
==============================================================
|
||||
|
@ -253,20 +282,6 @@ SCREEN CONSTS
|
|||
|
||||
==============================================================
|
||||
*/
|
||||
// all drawing is done to a 640*480 virtual screen size
|
||||
// and will be automatically scaled to the real resolution
|
||||
#define SCREEN_WIDTH 640
|
||||
#define SCREEN_HEIGHT 480
|
||||
|
||||
#define TINYCHAR_WIDTH (SMALLCHAR_WIDTH)
|
||||
#define TINYCHAR_HEIGHT (SMALLCHAR_HEIGHT/2)
|
||||
#define SMALLCHAR_WIDTH 8
|
||||
#define SMALLCHAR_HEIGHT 16
|
||||
#define BIGCHAR_WIDTH 16
|
||||
#define BIGCHAR_HEIGHT 24
|
||||
#define GIANTCHAR_WIDTH 32
|
||||
#define GIANTCHAR_HEIGHT 48
|
||||
|
||||
extern vrect_t scr_vrect; // position of render window
|
||||
extern vec4_t g_color_table[8];
|
||||
|
||||
|
@ -446,12 +461,34 @@ void CL_InitClientProgs( void );
|
|||
void CL_FreeClientProgs( void );
|
||||
int CL_GetMaxClients( void );
|
||||
void CL_DrawHUD( void );
|
||||
pr_edict_t *CL_GetEdict( int entnum );
|
||||
edict_t *CL_GetEdict( int entnum );
|
||||
float *CL_FadeColor( float starttime, float endtime );
|
||||
bool CL_ParseUserMessage( int svc_number );
|
||||
void CL_FreeEdicts( void );
|
||||
void CL_VM_Begin( void );
|
||||
void CL_VM_End( void );
|
||||
|
||||
//
|
||||
// cl_game.c
|
||||
//
|
||||
void CL_UnloadProgs( void );
|
||||
bool CL_LoadProgs( const char *name );
|
||||
void CL_ParseUserMessage( sizebuf_t *msg, int svc_num );
|
||||
void CL_PrepUserMessage( char *pszName, const int svc_num );
|
||||
edict_t *CL_AllocEdict( void );
|
||||
void CL_FreeEdict( edict_t *pEdict );
|
||||
string_t pfnAllocString( const char *szValue );
|
||||
const char *pfnGetString( string_t iString );
|
||||
void pfnGetGameDir( char *szGetGameDir );
|
||||
long pfnRandomLong( long lLow, long lHigh );
|
||||
float pfnRandomFloat( float flLow, float flHigh );
|
||||
byte* pfnLoadFile( const char *filename, int *pLength );
|
||||
void pfnFreeFile( void *buffer );
|
||||
|
||||
_inline edict_t *_EDICT_NUM( int n, const char *file, const int line )
|
||||
{
|
||||
if((n >= 0) && (n < game.maxEntities))
|
||||
return game.edicts + n;
|
||||
Host_Error( "EDICT_NUM: bad number %i (called at %s:%i)\n", n, file, line );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//
|
||||
// cl_sound.c
|
||||
|
@ -461,7 +498,7 @@ void CL_VM_End( void );
|
|||
// if origin is NULL, the sound will be dynamically sourced from the entity
|
||||
#define S_StartStreaming if( se ) se->StartStreaming
|
||||
#define S_StartSound( a,b,c,d,e,f,g ) if( se ) se->StartSound( a, b, c, d, e, f, g, true );
|
||||
#define S_StartLocalSound( name ) ( se && se->StartLocalSound( name ))
|
||||
#define S_StartLocalSound( a, b, c ) if( se ) se->StartLocalSound( a, b, c )
|
||||
#define S_StartBackgroundTrack if( se ) se->StartBackgroundTrack
|
||||
#define S_StopBackgroundTrack if( se ) se->StopBackgroundTrack
|
||||
#define S_RawSamples if( se ) se->StreamRawSamples
|
||||
|
@ -525,14 +562,15 @@ void V_RenderSplash( void );
|
|||
float V_CalcFov( float fov_x, float width, float height );
|
||||
|
||||
//
|
||||
// cl_pred.c
|
||||
// cl_phys.c
|
||||
//
|
||||
void CL_InitPrediction (void);
|
||||
void CL_PredictMove (void);
|
||||
void CL_CheckPredictionError (void);
|
||||
int CL_PointContents( const vec3_t point );
|
||||
int CL_ContentsMask( const edict_t *passedict );
|
||||
bool CL_AmbientLevel( const vec3_t point, float *volumes );
|
||||
trace_t CL_Trace(const vec3_t s1, const vec3_t m1, const vec3_t m2, const vec3_t s2, int type, pr_edict_t *e, int mask);
|
||||
trace_t CL_Trace( const vec3_t s1, const vec3_t m1, const vec3_t m2, const vec3_t s2, int type, edict_t *e, int mask );
|
||||
|
||||
//
|
||||
// cl_ents.c
|
||||
|
@ -590,8 +628,6 @@ extern field_t chatField;
|
|||
// cl_menu.c
|
||||
//
|
||||
extern bool ui_active;
|
||||
extern const int vm_ui_numbuiltins;
|
||||
extern prvm_builtin_t vm_ui_builtins[];
|
||||
|
||||
void UI_Init( void );
|
||||
void UI_DrawCredits( void );
|
||||
|
|
|
@ -145,6 +145,13 @@ PRVM INTERACTIONS
|
|||
*/
|
||||
char *ED_NewString( const char *string, byte *mempool );
|
||||
|
||||
#define NUM_FOR_EDICT(e) ((int)((edict_t *)(e) - game.edicts))
|
||||
#define EDICT_NUM( num ) _EDICT_NUM( num, __FILE__, __LINE__ )
|
||||
|
||||
// for constant strings
|
||||
#define STRING( offset ) pfnGetString( offset )
|
||||
#define MAKE_STRING(str) pfnAllocString( str )
|
||||
|
||||
#define prog vm->prog // global callback to vprogs.dll
|
||||
#define PRVM_EDICT_NUM( num ) _PRVM_EDICT_NUM( num, __FILE__, __LINE__ )
|
||||
|
||||
|
@ -317,13 +324,6 @@ enum e_trace
|
|||
MOVE_HITMODEL,
|
||||
};
|
||||
|
||||
// client printf level
|
||||
enum e_clprint
|
||||
{
|
||||
PRINT_CONSOLE = 0, // normal messages
|
||||
PRINT_CENTER, // centerprint
|
||||
PRINT_CHAT, // chat messages (with sound)
|
||||
};
|
||||
extern byte *zonepool;
|
||||
|
||||
#define Z_Malloc(size) Mem_Alloc( zonepool, size )
|
||||
|
|
|
@ -171,7 +171,7 @@ Con_CheckResize
|
|||
If the line width has changed, reformat the buffer.
|
||||
================
|
||||
*/
|
||||
void Con_CheckResize (void)
|
||||
void Con_CheckResize( void )
|
||||
{
|
||||
int i, j, width, oldwidth, oldtotallines, numlines, numchars;
|
||||
short tbuf[CON_TEXTSIZE];
|
||||
|
|
|
@ -9,6 +9,84 @@
|
|||
#include "const.h"
|
||||
#include "client.h"
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnAllocString
|
||||
|
||||
=============
|
||||
*/
|
||||
string_t pfnAllocString( const char *szValue )
|
||||
{
|
||||
return StringTable_SetString( game.hStringTable, szValue );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnGetString
|
||||
|
||||
=============
|
||||
*/
|
||||
const char *pfnGetString( string_t iString )
|
||||
{
|
||||
return StringTable_GetString( game.hStringTable, iString );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnLoadFile
|
||||
|
||||
=============
|
||||
*/
|
||||
byte* pfnLoadFile( const char *filename, int *pLength )
|
||||
{
|
||||
return FS_LoadFile( filename, pLength );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnFreeFile
|
||||
|
||||
=============
|
||||
*/
|
||||
void pfnFreeFile( void *buffer )
|
||||
{
|
||||
if( buffer ) Mem_Free( buffer );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnRandomLong
|
||||
|
||||
=============
|
||||
*/
|
||||
long pfnRandomLong( long lLow, long lHigh )
|
||||
{
|
||||
return Com_RandomLong( lLow, lHigh );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnRandomFloat
|
||||
|
||||
=============
|
||||
*/
|
||||
float pfnRandomFloat( float flLow, float flHigh )
|
||||
{
|
||||
return Com_RandomFloat( flLow, flHigh );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnGetGameDir
|
||||
|
||||
=============
|
||||
*/
|
||||
void pfnGetGameDir( char *szGetGameDir )
|
||||
{
|
||||
// FIXME: potentially crashpoint
|
||||
com.strcpy( szGetGameDir, FS_Gamedir );
|
||||
}
|
||||
|
||||
/*
|
||||
=======================================================================
|
||||
|
||||
|
@ -804,7 +882,8 @@ void VM_localsound( void )
|
|||
return;
|
||||
s = PRVM_G_STRING( OFS_PARM0 );
|
||||
|
||||
if(!S_StartLocalSound( s ))
|
||||
S_StartLocalSound( s, 1.0f, NULL );
|
||||
else
|
||||
{
|
||||
VM_Warning( "localsound: can't play %s!\n", s );
|
||||
PRVM_G_FLOAT(OFS_RETURN) = 0;
|
||||
|
|
|
@ -102,8 +102,6 @@ void UI_KeyEvent( int key )
|
|||
prog->globals.ui->time = cls.realtime * 0.001f;
|
||||
PRVM_G_INT(OFS_PARM1) = PRVM_SetEngineString(ascii);
|
||||
PRVM_ExecuteProgram (prog->globals.ui->m_keydown, "m_keydown");
|
||||
|
||||
CL_VM_Begin(); // restore clvm state
|
||||
}
|
||||
|
||||
void UI_Draw( void )
|
||||
|
@ -115,8 +113,6 @@ void UI_Draw( void )
|
|||
prog->globals.ui->time = cls.realtime * 0.001f;
|
||||
PRVM_ExecuteProgram (prog->globals.ui->m_draw, "m_draw");
|
||||
UI_DrawCredits(); // display game credits
|
||||
|
||||
CL_VM_Begin(); // restore clvm state
|
||||
}
|
||||
|
||||
void UI_DrawCredits( void )
|
||||
|
@ -160,7 +156,6 @@ void UI_ShowMenu( void )
|
|||
ui_active = true;
|
||||
prog->globals.ui->time = cls.realtime * 0.001f;
|
||||
PRVM_ExecuteProgram (prog->globals.ui->m_show, "m_show");
|
||||
CL_VM_Begin(); // restore clvm state
|
||||
}
|
||||
|
||||
void UI_HideMenu( void )
|
||||
|
@ -173,7 +168,6 @@ void UI_HideMenu( void )
|
|||
ui_active = false;
|
||||
prog->globals.ui->time = cls.realtime * 0.001f;
|
||||
PRVM_ExecuteProgram (prog->globals.ui->m_hide, "m_hide");
|
||||
CL_VM_Begin(); // restore clvm state
|
||||
}
|
||||
|
||||
void UI_Shutdown( void )
|
||||
|
|
|
@ -134,6 +134,10 @@ SOURCE=.\client\cl_frame.c
|
|||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\client\cl_game.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\client\cl_input.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
@ -146,7 +150,7 @@ SOURCE=.\client\cl_parse.c
|
|||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\client\cl_pred.c
|
||||
SOURCE=.\client\cl_phys.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
|
@ -262,10 +266,6 @@ SOURCE=.\server\sv_world.c
|
|||
# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\client\cl_edict.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\client\client.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
|
|
@ -529,7 +529,7 @@ void Host_Error( const char *error, ... )
|
|||
|
||||
if( host.framecount < 3 || host.state == HOST_SHUTDOWN )
|
||||
{
|
||||
Msg( "Host_InitError:" );
|
||||
Msg( "Host_InitError: " );
|
||||
com.error( hosterror1 );
|
||||
}
|
||||
else if( host.framecount == host.errorframe )
|
||||
|
|
|
@ -22,13 +22,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#define SERVER_H
|
||||
|
||||
#include "mathlib.h"
|
||||
#include "svprog_def.h"
|
||||
#include "entity_def.h"
|
||||
#include "svgame_api.h"
|
||||
|
||||
//=============================================================================
|
||||
#define NUM_FOR_EDICT(e) ((int)((edict_t *)(e) - game.edicts))
|
||||
#define EDICT_NUM( num ) _EDICT_NUM( num, __FILE__, __LINE__ )
|
||||
|
||||
#define AREA_SOLID 1
|
||||
#define AREA_TRIGGERS 2
|
||||
|
||||
|
@ -215,7 +212,7 @@ typedef struct
|
|||
dword funcBase; // base offset
|
||||
|
||||
int hStringTable; // stringtable handle
|
||||
} game_static_t;
|
||||
} svgame_static_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
@ -254,7 +251,7 @@ typedef struct
|
|||
extern netadr_t master_adr[MAX_MASTERS]; // address of the master server
|
||||
extern const char *ed_name[];
|
||||
extern server_static_t svs; // persistant server info
|
||||
extern game_static_t game; // persistant game info
|
||||
extern svgame_static_t game; // persistant game info
|
||||
extern server_t sv; // local server
|
||||
|
||||
extern cvar_t *sv_paused;
|
||||
|
@ -384,6 +381,11 @@ float SV_AngleMod( float ideal, float current, float speed );
|
|||
void SV_SpawnEntities( const char *mapname, script_t *entities );
|
||||
string_t pfnAllocString( const char *szValue );
|
||||
const char *pfnGetString( string_t iString );
|
||||
void pfnGetGameDir( char *szGetGameDir );
|
||||
long pfnRandomLong( long lLow, long lHigh );
|
||||
float pfnRandomFloat( float flLow, float flHigh );
|
||||
byte* pfnLoadFile( const char *filename, int *pLength );
|
||||
void pfnFreeFile( void *buffer );
|
||||
|
||||
_inline edict_t *_EDICT_NUM( int n, const char * file, const int line )
|
||||
{
|
||||
|
@ -393,10 +395,6 @@ _inline edict_t *_EDICT_NUM( int n, const char * file, const int line )
|
|||
return NULL;
|
||||
}
|
||||
|
||||
// for constant strings
|
||||
#define STRING( offset ) pfnGetString( offset )
|
||||
#define MAKE_STRING(str) pfnAllocString( str )
|
||||
|
||||
//
|
||||
// sv_studio.c
|
||||
//
|
||||
|
|
|
@ -302,7 +302,7 @@ void SV_FlushRedirect( netadr_t adr, int dest, char *buf )
|
|||
case RD_CLIENT:
|
||||
if( !sv_client ) return; // client not set
|
||||
MSG_WriteByte( &sv_client->netchan.message, svc_print );
|
||||
MSG_WriteByte( &sv_client->netchan.message, PRINT_CONSOLE );
|
||||
MSG_WriteByte( &sv_client->netchan.message, HUD_PRINTCONSOLE );
|
||||
MSG_WriteString( &sv_client->netchan.message, buf );
|
||||
break;
|
||||
case RD_NONE:
|
||||
|
|
|
@ -370,9 +370,9 @@ void SV_Kick_f( void )
|
|||
}
|
||||
if(!SV_SetPlayer()) return;
|
||||
|
||||
SV_BroadcastPrintf( PRINT_CONSOLE, "%s was kicked\n", sv_client->name );
|
||||
SV_ClientPrintf(sv_client, PRINT_CONSOLE, "You were kicked from the game\n");
|
||||
SV_DropClient(sv_client);
|
||||
SV_BroadcastPrintf( HUD_PRINTCONSOLE, "%s was kicked\n", sv_client->name );
|
||||
SV_ClientPrintf( sv_client, HUD_PRINTCONSOLE, "You were kicked from the game\n" );
|
||||
SV_DropClient( sv_client );
|
||||
sv_client->lastmessage = svs.realtime; // min case there is a funny zombie
|
||||
}
|
||||
|
||||
|
@ -454,7 +454,7 @@ void SV_ConSay_f( void )
|
|||
for (i = 0, client = svs.clients; i < Host_MaxClients(); i++, client++)
|
||||
{
|
||||
if( client->state != cs_spawned ) continue;
|
||||
SV_ClientPrintf( client, PRINT_CHAT, "%s\n", text );
|
||||
SV_ClientPrintf( client, HUD_PRINTTALK, "%s\n", text );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -626,7 +626,7 @@ void SV_SendClientMessages( void )
|
|||
{
|
||||
MSG_Clear( &cl->netchan.message );
|
||||
MSG_Clear( &cl->datagram );
|
||||
SV_BroadcastPrintf( PRINT_CONSOLE, "%s overflowed\n", cl->name );
|
||||
SV_BroadcastPrintf( HUD_PRINTCONSOLE, "%s overflowed\n", cl->name );
|
||||
SV_DropClient( cl );
|
||||
}
|
||||
|
||||
|
|
|
@ -994,12 +994,24 @@ bool SV_ReadComment( char *comment, int savenum )
|
|||
===============================================================================
|
||||
*/
|
||||
|
||||
void *pfnMemAlloc( size_t cb, const char *filename, const int fileline )
|
||||
/*
|
||||
=========
|
||||
pfnMemAlloc
|
||||
|
||||
=========
|
||||
*/
|
||||
static void *pfnMemAlloc( size_t cb, const char *filename, const int fileline )
|
||||
{
|
||||
return com.malloc( svs.mempool, cb, filename, fileline );
|
||||
return com.malloc( svs.private, cb, filename, fileline );
|
||||
}
|
||||
|
||||
void pfnMemFree( void *mem, const char *filename, const int fileline )
|
||||
/*
|
||||
=========
|
||||
pfnMemFree
|
||||
|
||||
=========
|
||||
*/
|
||||
static void pfnMemFree( void *mem, const char *filename, const int fileline )
|
||||
{
|
||||
com.free( mem, filename, fileline );
|
||||
}
|
||||
|
@ -1482,18 +1494,6 @@ void pfnMakeVectors( const float *rgflVector )
|
|||
AngleVectors( rgflVector, svs.globals->v_forward, svs.globals->v_right, svs.globals->v_up );
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
pfnAngleVectors
|
||||
|
||||
can receive NULL output args
|
||||
==============
|
||||
*/
|
||||
void pfnAngleVectors( const float *rgflVector, float *forward, float *right, float *up )
|
||||
{
|
||||
AngleVectors( rgflVector, forward, right, up );
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
pfnCreateEntity
|
||||
|
@ -1835,7 +1835,7 @@ pfnTraceLine
|
|||
|
||||
=================
|
||||
*/
|
||||
void pfnTraceLine( const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr )
|
||||
static void pfnTraceLine( const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr )
|
||||
{
|
||||
trace_t trace;
|
||||
int move;
|
||||
|
@ -2100,7 +2100,7 @@ pfnPointContents
|
|||
|
||||
=============
|
||||
*/
|
||||
int pfnPointContents( const float *rgflVector )
|
||||
static int pfnPointContents( const float *rgflVector )
|
||||
{
|
||||
return SV_PointContents( rgflVector );
|
||||
}
|
||||
|
@ -2225,6 +2225,18 @@ void pfnWriteCoord( float flValue )
|
|||
if( game.msg_leftsize != 0xFFFF ) game.msg_leftsize -= 4;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnWriteFloat
|
||||
|
||||
=============
|
||||
*/
|
||||
void pfnWriteFloat( float flValue )
|
||||
{
|
||||
MSG_WriteFloat( &sv.multicast, flValue );
|
||||
if( game.msg_leftsize != 0xFFFF ) game.msg_leftsize -= 4;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnWriteString
|
||||
|
@ -2320,7 +2332,7 @@ pfnAlertMessage
|
|||
|
||||
=============
|
||||
*/
|
||||
void pfnAlertMessage( ALERT_TYPE level, char *szFmt, ... )
|
||||
static void pfnAlertMessage( ALERT_TYPE level, char *szFmt, ... )
|
||||
{
|
||||
char buffer[2048]; // must support > 1k messages
|
||||
va_list args;
|
||||
|
@ -2362,28 +2374,6 @@ void pfnFreeEntPrivateData( edict_t *pEdict )
|
|||
pEdict->pvServerData = NULL; // freed
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnAllocString
|
||||
|
||||
=============
|
||||
*/
|
||||
string_t pfnAllocString( const char *szValue )
|
||||
{
|
||||
return StringTable_SetString( game.hStringTable, szValue );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnGetString
|
||||
|
||||
=============
|
||||
*/
|
||||
const char *pfnGetString( string_t iString )
|
||||
{
|
||||
return StringTable_GetString( game.hStringTable, iString );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnPEntityOfEntOffset
|
||||
|
@ -2481,8 +2471,18 @@ int pfnRegUserMsg( const char *pszName, int iSize )
|
|||
{
|
||||
// register message first
|
||||
int msg_index;
|
||||
string msg_name;
|
||||
|
||||
msg_index = SV_UserMessageIndex( pszName );
|
||||
// scan name for reserved symbol
|
||||
if( com.strchr( pszName, '@' ))
|
||||
{
|
||||
MsgDev( D_ERROR, "SV_RegisterUserMessage: invalid name %s\n", pszName );
|
||||
return svc_bad; // force error
|
||||
}
|
||||
|
||||
// build message name, fmt: MsgName@size
|
||||
com.snprintf( msg_name, MAX_STRING, "%s@%i", pszName, iSize );
|
||||
msg_index = SV_UserMessageIndex( msg_name );
|
||||
if( iSize == -1 )
|
||||
game.msg_sizes[msg_index] = 0xFFFF;
|
||||
else game.msg_sizes[msg_index] = iSize;
|
||||
|
@ -2578,17 +2578,16 @@ void pfnClientPrintf( edict_t* pEdict, int ptype, const char *szMsg )
|
|||
|
||||
switch( ptype )
|
||||
{
|
||||
case PRINT_CONSOLE:
|
||||
SV_ClientPrintf (client, PRINT_CONSOLE, (char *)szMsg );
|
||||
case HUD_PRINTTALK:
|
||||
case HUD_PRINTNOTIFY: // don't leave message in console history
|
||||
case HUD_PRINTCONSOLE:
|
||||
SV_ClientPrintf( client, ptype, (char *)szMsg );
|
||||
break;
|
||||
case PRINT_CENTER:
|
||||
case HUD_PRINTCENTER:
|
||||
MSG_Begin( svc_centerprint );
|
||||
MSG_WriteString( &sv.multicast, szMsg );
|
||||
MSG_Send( MSG_ONE_R, NULL, pEdict );
|
||||
break;
|
||||
case PRINT_CHAT:
|
||||
SV_ClientPrintf( client, PRINT_CHAT, (char *)szMsg );
|
||||
break;
|
||||
default:
|
||||
MsgDev( D_ERROR, "SV_ClientPrintf: invalid destination\n" );
|
||||
break;
|
||||
|
@ -2608,7 +2607,7 @@ void pfnServerPrint( const char *szMsg )
|
|||
// while loading in-progress we can sending message
|
||||
com.print( szMsg ); // only for local client
|
||||
}
|
||||
else SV_BroadcastPrintf( PRINT_CONSOLE, (char *)szMsg );
|
||||
else SV_BroadcastPrintf( HUD_PRINTCONSOLE, (char *)szMsg );
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2710,28 +2709,6 @@ word pfnCRC_Final( word pulCRC )
|
|||
return pulCRC ^ 0x0000;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnRandomLong
|
||||
|
||||
=============
|
||||
*/
|
||||
long pfnRandomLong( long lLow, long lHigh )
|
||||
{
|
||||
return Com_RandomLong( lLow, lHigh );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnRandomFloat
|
||||
|
||||
=============
|
||||
*/
|
||||
float pfnRandomFloat( float flLow, float flHigh )
|
||||
{
|
||||
return Com_RandomFloat( flLow, flHigh );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnSetView
|
||||
|
@ -2754,28 +2731,6 @@ void pfnCrosshairAngle( const edict_t *pClient, float pitch, float yaw )
|
|||
// FIXME: implement
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnLoadFile
|
||||
|
||||
=============
|
||||
*/
|
||||
byte* pfnLoadFile( const char *filename, int *pLength )
|
||||
{
|
||||
return FS_LoadFile( filename, pLength );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnFreeFile
|
||||
|
||||
=============
|
||||
*/
|
||||
void pfnFreeFile( void *buffer )
|
||||
{
|
||||
if( buffer ) Mem_Free( buffer );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnCompareFileTime
|
||||
|
@ -2800,19 +2755,7 @@ int pfnCompareFileTime( const char *filename1, const char *filename2, int *iComp
|
|||
|
||||
/*
|
||||
=============
|
||||
pfnGetGameDir
|
||||
|
||||
=============
|
||||
*/
|
||||
void pfnGetGameDir( char *szGetGameDir )
|
||||
{
|
||||
// FIXME: potentially crashpoint
|
||||
com.strcpy( szGetGameDir, FS_Gamedir );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnGetGameDir
|
||||
pfnStaticDecal
|
||||
|
||||
=============
|
||||
*/
|
||||
|
@ -3001,7 +2944,7 @@ static enginefuncs_t gEngfuncs =
|
|||
pfnEntitiesInPVS,
|
||||
pfnEntitiesInPHS,
|
||||
pfnMakeVectors,
|
||||
pfnAngleVectors,
|
||||
AngleVectors,
|
||||
pfnCreateEntity,
|
||||
pfnRemoveEntity,
|
||||
pfnCreateNamedEntity,
|
||||
|
@ -3034,6 +2977,7 @@ static enginefuncs_t gEngfuncs =
|
|||
pfnWriteLong,
|
||||
pfnWriteAngle,
|
||||
pfnWriteCoord,
|
||||
pfnWriteFloat,
|
||||
pfnWriteString,
|
||||
pfnWriteEntity,
|
||||
pfnCVarRegister,
|
||||
|
|
|
@ -22,7 +22,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#include "server.h"
|
||||
|
||||
server_static_t svs; // persistant server info
|
||||
game_static_t game; // persistant game info
|
||||
svgame_static_t game; // persistant game info
|
||||
server_t sv; // local server
|
||||
|
||||
/*
|
||||
|
|
|
@ -164,7 +164,7 @@ void SV_CheckTimeouts( void )
|
|||
}
|
||||
if(( cl->state == cs_connected || cl->state == cs_spawned) && cl->lastmessage < droppoint )
|
||||
{
|
||||
SV_BroadcastPrintf( PRINT_CONSOLE, "%s timed out\n", cl->name );
|
||||
SV_BroadcastPrintf( HUD_PRINTCONSOLE, "%s timed out\n", cl->name );
|
||||
SV_DropClient( cl );
|
||||
cl->state = cs_free; // don't bother with zombie state
|
||||
}
|
||||
|
@ -394,9 +394,9 @@ void SV_FinalMessage( char *message, bool reconnect )
|
|||
sizebuf_t msg;
|
||||
int i;
|
||||
|
||||
MSG_Init( &msg, msg_buf, sizeof(msg_buf));
|
||||
MSG_Init( &msg, msg_buf, sizeof( msg_buf ));
|
||||
MSG_WriteByte( &msg, svc_print );
|
||||
MSG_WriteByte( &msg, PRINT_CONSOLE );
|
||||
MSG_WriteByte( &msg, HUD_PRINTCONSOLE );
|
||||
MSG_WriteString( &msg, message );
|
||||
|
||||
if( reconnect )
|
||||
|
|
|
@ -154,7 +154,7 @@ trace_t SV_Trace( const vec3_t start, const vec3_t mins, const vec3_t maxs, cons
|
|||
uint modelindex = (uint)touch->v.modelindex;
|
||||
// if the modelindex is 0, it shouldn't be SOLID_BSP!
|
||||
if( modelindex > 0 && modelindex < MAX_MODELS )
|
||||
model = sv.models[(int)touch->v.modelindex];
|
||||
model = sv.models[touch->v.modelindex];
|
||||
}
|
||||
if( model ) Matrix4x4_CreateFromEntity( matrix, touch->v.origin[0], touch->v.origin[1], touch->v.origin[2], touch->v.angles[0], touch->v.angles[1], touch->v.angles[2], 1 );
|
||||
else Matrix4x4_CreateTranslate( matrix, touch->v.origin[0], touch->v.origin[1], touch->v.origin[2] );
|
||||
|
|
|
@ -40,13 +40,13 @@ static long Cvar_GetHashValue( const char *fname )
|
|||
Cvar_InfoValidate
|
||||
============
|
||||
*/
|
||||
static bool Cvar_ValidateString(const char *s, bool isvalue )
|
||||
static bool Cvar_ValidateString( const char *s, bool isvalue )
|
||||
{
|
||||
if ( !s ) return false;
|
||||
if (strstr(s, "\\") && !isvalue)
|
||||
if( !s ) return false;
|
||||
if( com.strstr( s, "\\" ) && !isvalue )
|
||||
return false;
|
||||
if (strstr(s, "\"")) return false;
|
||||
if (strstr(s, ";")) return false;
|
||||
if( com.strstr( s, "\"" )) return false;
|
||||
if( com.strstr( s, ";" )) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,235 @@
|
|||
//=======================================================================
|
||||
// Copyright XashXT Group 2008 ©
|
||||
// clgame_api.h - entity interface between engine and clgame
|
||||
//=======================================================================
|
||||
#ifndef CLGAME_API_H
|
||||
#define CLGAME_API_H
|
||||
|
||||
typedef int HSPRITE; // handle to a graphic
|
||||
typedef int (*pfnUserMsgHook)( const char *pszName, int iSize, void *pbuf ); // user message handle
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TRI_FRONT = 0,
|
||||
TRI_BACK,
|
||||
TRI_NONE,
|
||||
} TRI_CULL;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TRI_TRIANGLES = 0,
|
||||
TRI_TRIANGLE_FAN,
|
||||
TRI_TRIANGLE_STRIP,
|
||||
TRI_POLYGON,
|
||||
TRI_QUADS,
|
||||
TRI_LINES,
|
||||
} TRI_DRAW;
|
||||
|
||||
typedef struct triapi_s
|
||||
{
|
||||
size_t api_size; // must match with sizeof( triapi_t );
|
||||
|
||||
void (*Bind)( HSPRITE shader ); // use handle that return pfnLoadShader
|
||||
void (*Begin)( TRI_DRAW mode );
|
||||
void (*End)( void );
|
||||
|
||||
void (*Vertex2f)( float x, float y );
|
||||
void (*Vertex3f)( float x, float y, float z );
|
||||
void (*Vertex2fv)( const float *v );
|
||||
void (*Vertex3fv)( const float *v );
|
||||
void (*Color3f)( float r, float g, float b );
|
||||
void (*Color4f)( float r, float g, float b, float a );
|
||||
void (*Color4ub)( byte r, byte g, byte b, byte a );
|
||||
void (*TexCoord2f)( float u, float v );
|
||||
void (*TexCoord2fv)( const float *v );
|
||||
void (*CullFace)( TRI_CULL mode );
|
||||
} triapi_t;
|
||||
|
||||
// FIXME: get rid of this
|
||||
typedef struct
|
||||
{
|
||||
char *name;
|
||||
short ping;
|
||||
byte thisplayer; // TRUE if this is the calling player
|
||||
|
||||
// stuff that's unused at the moment, but should be done
|
||||
byte spectator;
|
||||
byte packetloss;
|
||||
|
||||
char *model;
|
||||
short topcolor;
|
||||
short bottomcolor;
|
||||
|
||||
} hud_player_info_t;
|
||||
|
||||
// FIXME: get rid of this
|
||||
typedef struct client_textmessage_s
|
||||
{
|
||||
int effect;
|
||||
byte r1, g1, b1, a1; // 2 colors for effects
|
||||
byte r2, g2, b2, a2;
|
||||
float x;
|
||||
float y;
|
||||
float fadein;
|
||||
float fadeout;
|
||||
float holdtime;
|
||||
float fxtime;
|
||||
const char *pName;
|
||||
const char *pMessage;
|
||||
} client_textmessage_t;
|
||||
|
||||
// NOTE: engine trace struct not matched with clgame trace
|
||||
typedef struct
|
||||
{
|
||||
BOOL fAllSolid; // if true, plane is not valid
|
||||
BOOL fStartSolid; // if true, the initial point was in a solid area
|
||||
BOOL fStartStuck; // if true, trace started from solid entity
|
||||
float flFraction; // time completed, 1.0 = didn't hit anything
|
||||
vec3_t vecEndPos; // final position
|
||||
int iStartContents; // start pos conetnts
|
||||
int iContents; // final pos contents
|
||||
int iHitgroup; // 0 == generic, non zero is specific body part
|
||||
float flPlaneDist; // planes distance
|
||||
vec3_t vecPlaneNormal; // surface normal at impact
|
||||
const char *pTexName; // texture name that we hitting (brushes and studiomodels)
|
||||
edict_t *pHit; // entity the surface is on
|
||||
} TraceResult;
|
||||
|
||||
typedef struct ref_params_s
|
||||
{
|
||||
// output
|
||||
vec3_t vieworg;
|
||||
vec3_t viewangles;
|
||||
float fov;
|
||||
|
||||
vec3_t forward;
|
||||
vec3_t right;
|
||||
vec3_t up;
|
||||
|
||||
float frametime; // client frametime
|
||||
float lerpfrac; // interp value
|
||||
float time; // client time
|
||||
|
||||
// misc
|
||||
BOOL intermission;
|
||||
BOOL demoplayback;
|
||||
BOOL demorecord;
|
||||
BOOL spectator;
|
||||
BOOL paused;
|
||||
qword iWeaponBits; // pev->weapon
|
||||
dword iKeyBits; // pev->button
|
||||
edict_t *onground; // pointer to onground entity
|
||||
int waterlevel;
|
||||
|
||||
// input
|
||||
vec3_t velocity;
|
||||
vec3_t angles; // input viewangles
|
||||
vec3_t origin; // origin + viewheight = vieworg
|
||||
|
||||
vec3_t viewheight;
|
||||
float idealpitch;
|
||||
float v_idlescale; // used for concussion effect
|
||||
float mouse_sensitivity;
|
||||
|
||||
int health;
|
||||
vec3_t crosshairangle; // pfnCrosshairAngle values from server
|
||||
vec3_t punchangle; // recivied from server
|
||||
edict_t *viewentity;
|
||||
int clientnum;
|
||||
int num_entities;
|
||||
int max_entities;
|
||||
int max_clients;
|
||||
} ref_params_t;
|
||||
|
||||
typedef struct cl_enginefuncs_s
|
||||
{
|
||||
// interface validator
|
||||
size_t api_size; // must matched with sizeof(cl_enginefuncs_t)
|
||||
|
||||
// engine memory manager
|
||||
void* (*pfnMemAlloc)( size_t cb, const char *filename, const int fileline );
|
||||
void (*pfnMemFree)( void *mem, const char *filename, const int fileline );
|
||||
|
||||
// screen handlers
|
||||
HSPRITE (*pfnLoadShader)( const char *szShaderName );
|
||||
void (*pfnFillRGBA)( int x, int y, int width, int height, const float *color, float alpha );
|
||||
void (*pfnDrawImage)( HSPRITE shader, int x, int y, int width, int height, int frame );
|
||||
void (*pfnSetColor)( float r, float g, float b, float a );
|
||||
|
||||
// cvar handlers
|
||||
void (*pfnRegisterVariable)( const char *szName, const char *szValue, int flags, const char *szDesc );
|
||||
void (*pfnCvarSetValue)( const char *cvar, float value );
|
||||
float (*pfnGetCvarFloat)( const char *szName );
|
||||
char* (*pfnGetCvarString)( const char *szName );
|
||||
|
||||
// command handlers
|
||||
void (*pfnAddCommand)( const char *cmd_name, void (*function)(void), const char *cmd_desc );
|
||||
void (*pfnHookUserMsg)( char *szMsgName, pfnUserMsgHook pfn );
|
||||
void (*pfnServerCmd)( const char *szCmdString );
|
||||
void (*pfnClientCmd)( const char *szCmdString );
|
||||
void (*pfnGetPlayerInfo)( int player_num, hud_player_info_t *pinfo );
|
||||
client_textmessage_t *(*pfnTextMessageGet)( const char *pName );
|
||||
|
||||
int (*pfnCmdArgc)( void );
|
||||
char *(*pfnCmdArgv)( int argc );
|
||||
void (*pfnAlertMessage)( ALERT_TYPE, char *szFmt, ... );
|
||||
|
||||
// sound handlers (NULL origin == play at current client origin)
|
||||
void (*pfnPlaySoundByName)( const char *szSound, float volume, const float *org );
|
||||
void (*pfnPlaySoundByIndex)( int iSound, float volume, const float *org );
|
||||
|
||||
// vector helpers
|
||||
void (*pfnAngleVectors)( const float *rgflVector, float *forward, float *right, float *up );
|
||||
|
||||
void (*pfnDrawCenterPrint)( void );
|
||||
void (*pfnCenterPrint)( const char *text, int y, int charWidth );
|
||||
int (*pfnDrawCharacter)( int x, int y, int width, int height, int number );
|
||||
void (*pfnDrawString)( int x, int y, int width, int height, const char *text );
|
||||
void (*pfnGetImageSize)( int *w, int *h, shader_t shader );
|
||||
|
||||
// local client handlers
|
||||
void (*pfnGetViewAngles)( float *angles );
|
||||
edict_t* (*pfnGetEntityByIndex)( int idx ); // matched with entity serialnumber
|
||||
edict_t* (*pfnGetLocalPlayer)( void );
|
||||
int (*pfnIsSpectateOnly)( void ); // returns 1 if the client is a spectator only
|
||||
float (*pfnGetClientTime)( void );
|
||||
int (*pfnGetMaxClients)( void );
|
||||
edict_t* (*pfnGetViewModel)( void );
|
||||
|
||||
int (*pfnPointContents)( const float *rgflVector );
|
||||
void (*pfnTraceLine)( const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr );
|
||||
|
||||
long (*pfnRandomLong)( long lLow, long lHigh );
|
||||
float (*pfnRandomFloat)( float flLow, float flHigh );
|
||||
byte* (*pfnLoadFile)( const char *filename, int *pLength );
|
||||
void (*pfnFreeFile)( void *buffer );
|
||||
void (*pfnGetGameDir)( char *szGetGameDir );
|
||||
void (*pfnHostError)( const char *szFmt, ... ); // invoke host error
|
||||
|
||||
triapi_t *pTriAPI;
|
||||
|
||||
} cl_enginefuncs_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// interface validator
|
||||
size_t api_size; // must matched with sizeof(HUD_FUNCTIONS)
|
||||
|
||||
int (*pfnVidInit)( void );
|
||||
void (*pfnInit)( void );
|
||||
int (*pfnRedraw)( float flTime, int intermission );
|
||||
int (*pfnUpdateClientData)( ref_params_t *parms, float flTime );
|
||||
void (*pfnReset)( void );
|
||||
void (*pfnFrame)( double time );
|
||||
void (*pfnShutdown)( void );
|
||||
void (*pfnDrawNormalTriangles)( void );
|
||||
void (*pfnDrawTransparentTriangles)( void );
|
||||
void (*pfnCreateEntities)( void );
|
||||
void (*pfnStudioEvent)( const dstudioevent_t *event, edict_t *entity );
|
||||
void (*pfnCalcRefdef)( ref_params_t *parms );
|
||||
|
||||
} HUD_FUNCTIONS;
|
||||
|
||||
typedef int (*CLIENTAPI)( HUD_FUNCTIONS *pFunctionTable, cl_enginefuncs_t* pEngfuncsFromEngine, int interfaceVersion );
|
||||
|
||||
#endif//CLGAME_API_H
|
|
@ -5,6 +5,14 @@
|
|||
#ifndef CONST_H
|
||||
#define CONST_H
|
||||
|
||||
// shared typedefs
|
||||
typedef unsigned __int64 qword;
|
||||
typedef unsigned long dword;
|
||||
typedef unsigned int uint;
|
||||
typedef unsigned short word;
|
||||
typedef unsigned char byte;
|
||||
typedef int shader_t;
|
||||
|
||||
// euler angle order
|
||||
#define PITCH 0
|
||||
#define YAW 1
|
||||
|
@ -102,6 +110,16 @@
|
|||
#define DAMAGE_YES 1
|
||||
#define DAMAGE_AIM 2
|
||||
|
||||
typedef enum
|
||||
{
|
||||
at_console = 1, // format: [msg]
|
||||
at_warning, // format: Warning: [msg]
|
||||
at_error, // format: Error: [msg]
|
||||
at_loading, // print messages during loading
|
||||
at_aiconsole, // same as at_console, but only shown if developer level is 5!
|
||||
at_logged // server print to console ( only in multiplayer games ).
|
||||
} ALERT_TYPE;
|
||||
|
||||
// engine edict types
|
||||
typedef enum
|
||||
{
|
||||
|
@ -210,4 +228,53 @@ typedef enum
|
|||
kRenderFxNoReflect, // don't reflecting in mirrors
|
||||
} kRenderFx_t;
|
||||
|
||||
// all drawing is done to a 640*480 virtual screen size
|
||||
// and will be automatically scaled to the real resolution
|
||||
#define SCREEN_WIDTH 640
|
||||
#define SCREEN_HEIGHT 480
|
||||
|
||||
#define TINYCHAR_WIDTH (SMALLCHAR_WIDTH)
|
||||
#define TINYCHAR_HEIGHT (SMALLCHAR_HEIGHT/2)
|
||||
#define SMALLCHAR_WIDTH 8
|
||||
#define SMALLCHAR_HEIGHT 16
|
||||
#define BIGCHAR_WIDTH 16
|
||||
#define BIGCHAR_HEIGHT 24
|
||||
#define GIANTCHAR_WIDTH 32
|
||||
#define GIANTCHAR_HEIGHT 48
|
||||
|
||||
#define HUD_PRINTNOTIFY 1
|
||||
#define HUD_PRINTCONSOLE 2
|
||||
#define HUD_PRINTTALK 3
|
||||
#define HUD_PRINTCENTER 4
|
||||
|
||||
#define INTERFACE_VERSION 1 // both the client and server iface version
|
||||
|
||||
//=======================================================================
|
||||
//
|
||||
// server.dll - client.dll definitions only
|
||||
//
|
||||
//=======================================================================
|
||||
#define MAX_WEAPONS 32
|
||||
#define MAX_AMMO_SLOTS 32
|
||||
|
||||
#define HIDEHUD_WEAPONS BIT( 0 )
|
||||
#define HIDEHUD_FLASHLIGHT BIT( 1 )
|
||||
#define HIDEHUD_ALL BIT( 2 )
|
||||
#define HIDEHUD_HEALTH BIT( 3 )
|
||||
#define ITEM_SUIT BIT( 4 )
|
||||
|
||||
enum ShakeCommand_t
|
||||
{
|
||||
SHAKE_START = 0, // Starts the screen shake for all players within the radius.
|
||||
SHAKE_STOP, // Stops the screen shake for all players within the radius.
|
||||
SHAKE_AMPLITUDE, // Modifies the amplitude of an active screen shake for all players within the radius.
|
||||
SHAKE_FREQUENCY, // Modifies the frequency of an active screen shake for all players within the radius.
|
||||
};
|
||||
|
||||
#define FFADE_IN 0x0000 // Just here so we don't pass 0 into the function
|
||||
#define FFADE_OUT 0x0001 // Fade out (not in)
|
||||
#define FFADE_MODULATE 0x0002 // Modulate (don't blend)
|
||||
#define FFADE_STAYOUT 0x0004 // ignores the duration, stays faded out until new ScreenFade message received
|
||||
#define FFADE_CUSTOMVIEW 0x0008 // fading only at custom viewing (don't sending this to engine )
|
||||
|
||||
#endif//CONST_H
|
|
@ -1,57 +1,15 @@
|
|||
//=======================================================================
|
||||
// Copyright XashXT Group 2008 ©
|
||||
// svprog_def.h - engine <-> svgame communications
|
||||
// entity_def.h - generic engine edict
|
||||
//=======================================================================
|
||||
#ifndef SVDEFS_API_H
|
||||
#define SVDEFS_API_H
|
||||
#ifndef ENTITY_DEF_H
|
||||
#define ENTITY_DEF_H
|
||||
|
||||
typedef struct ed_priv_s ed_priv_t; // engine private data
|
||||
typedef struct edict_s edict_t;
|
||||
|
||||
typedef struct globalvars_s
|
||||
{
|
||||
float time;
|
||||
float frametime;
|
||||
string_t mapname;
|
||||
string_t startspot;
|
||||
vec3_t spotOffset; // landmark offset
|
||||
|
||||
BOOL deathmatch;
|
||||
BOOL coop;
|
||||
BOOL teamplay;
|
||||
|
||||
int serverflags;
|
||||
int maxClients;
|
||||
int numClients; // actual clients count
|
||||
int maxEntities;
|
||||
int numEntities; // actual ents count
|
||||
|
||||
vec3_t v_forward;
|
||||
vec3_t v_right;
|
||||
vec3_t v_up;
|
||||
|
||||
BOOL trace_allsolid;
|
||||
BOOL trace_startsolid;
|
||||
BOOL trace_startstuck;
|
||||
float trace_fraction;
|
||||
vec3_t trace_endpos;
|
||||
vec3_t trace_plane_normal;
|
||||
float trace_plane_dist;
|
||||
int trace_start_contents;
|
||||
int trace_contents;
|
||||
int trace_hitgroup;
|
||||
const char *trace_texture; // texture name that we hitting (brushes and studiomodels)
|
||||
edict_t *trace_ent;
|
||||
|
||||
int total_secrets;
|
||||
int found_secrets; // number of secrets found
|
||||
int total_monsters;
|
||||
int killed_monsters; // number of monsters killed
|
||||
|
||||
void *pSaveData; // savedata base offset
|
||||
} globalvars_t;
|
||||
|
||||
// NOT FINALIZED!
|
||||
// TODO: move to CBaseEntity all fields which doesn't existing on client side
|
||||
// TODO: generic edict must have all fields as valid on client side too
|
||||
typedef struct entvars_s
|
||||
{
|
||||
string_t classname;
|
||||
|
@ -119,7 +77,7 @@ typedef struct entvars_s
|
|||
|
||||
float health;
|
||||
float frags;
|
||||
int weapons; // bit mask for available weapons
|
||||
qword weapons; // bit mask for available weapons
|
||||
float takedamage;
|
||||
|
||||
int deadflag;
|
||||
|
@ -197,4 +155,4 @@ struct edict_s
|
|||
// other fields from progs come immediately after
|
||||
};
|
||||
|
||||
#endif//SVDEFS_API_H
|
||||
#endif//ENTITY_DEF_H
|
|
@ -5,26 +5,6 @@
|
|||
#ifndef SVGAME_API_H
|
||||
#define SVGAME_API_H
|
||||
|
||||
#define INTERFACE_VERSION 138
|
||||
|
||||
typedef enum
|
||||
{
|
||||
at_console = 1, // format: [msg]
|
||||
at_warning, // format: Warning: [msg]
|
||||
at_error, // format: Error: [msg]
|
||||
at_loading, // print messages during loading
|
||||
at_aiconsole, // same as at_console, but only shown if developer level is 5!
|
||||
at_logged // server print to console ( only in multiplayer games ).
|
||||
} ALERT_TYPE;
|
||||
|
||||
// Client_Printf modes
|
||||
enum
|
||||
{
|
||||
print_console = 0,
|
||||
print_center,
|
||||
print_chat
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
WALKMOVE_NORMAL = 0,
|
||||
|
@ -54,6 +34,49 @@ typedef struct
|
|||
edict_t *pHit; // entity the surface is on
|
||||
} TraceResult;
|
||||
|
||||
typedef struct globalvars_s
|
||||
{
|
||||
float time;
|
||||
float frametime;
|
||||
string_t mapname;
|
||||
string_t startspot;
|
||||
vec3_t spotOffset; // landmark offset
|
||||
|
||||
BOOL deathmatch;
|
||||
BOOL coop;
|
||||
BOOL teamplay;
|
||||
|
||||
int serverflags;
|
||||
int maxClients;
|
||||
int numClients; // actual clients count
|
||||
int maxEntities;
|
||||
int numEntities; // actual ents count
|
||||
|
||||
vec3_t v_forward;
|
||||
vec3_t v_right;
|
||||
vec3_t v_up;
|
||||
|
||||
BOOL trace_allsolid;
|
||||
BOOL trace_startsolid;
|
||||
BOOL trace_startstuck;
|
||||
float trace_fraction;
|
||||
vec3_t trace_endpos;
|
||||
vec3_t trace_plane_normal;
|
||||
float trace_plane_dist;
|
||||
int trace_start_contents;
|
||||
int trace_contents;
|
||||
int trace_hitgroup;
|
||||
const char *trace_texture; // texture name that we hitting (brushes and studiomodels)
|
||||
edict_t *trace_ent;
|
||||
|
||||
int total_secrets;
|
||||
int found_secrets; // number of secrets found
|
||||
int total_monsters;
|
||||
int killed_monsters; // number of monsters killed
|
||||
|
||||
void *pSaveData; // savedata base offset
|
||||
} globalvars_t;
|
||||
|
||||
// engine hands this to DLLs for functionality callbacks
|
||||
typedef struct enginefuncs_s
|
||||
{
|
||||
|
@ -115,6 +138,7 @@ typedef struct enginefuncs_s
|
|||
void (*pfnWriteLong)( int iValue );
|
||||
void (*pfnWriteAngle)( float flValue );
|
||||
void (*pfnWriteCoord)( float flValue );
|
||||
void (*pfnWriteFloat)( float flValue );
|
||||
void (*pfnWriteString)( const char *sz );
|
||||
void (*pfnWriteEntity)( int iValue );
|
||||
void (*pfnCVarRegister)( const char *name, const char *value, int flags, const char *desc );
|
||||
|
@ -148,7 +172,7 @@ typedef struct enginefuncs_s
|
|||
void (*pfnCRC_Init)( word *pulCRC );
|
||||
void (*pfnCRC_ProcessBuffer)( word *pulCRC, void *p, int len );
|
||||
word (*pfnCRC_Final)( word pulCRC );
|
||||
long (*pfnRandomLong)( long lLow, long lHigh );
|
||||
long (*pfnRandomLong)( long lLow, long lHigh );
|
||||
float (*pfnRandomFloat)( float flLow, float flHigh );
|
||||
void (*pfnSetView)( const edict_t *pClient, const edict_t *pViewent );
|
||||
void (*pfnCrosshairAngle)( const edict_t *pClient, float pitch, float yaw );
|
||||
|
@ -317,8 +341,6 @@ typedef struct
|
|||
|
||||
// returns string describing current .dll. E.g., TeamFotrress 2, Half-Life
|
||||
const char *(*pfnGetGameDescription)( void );
|
||||
// notify game .dll that engine is going to shut down. Allows mod authors to set a breakpoint.
|
||||
void (*pfnHostError)( const char *error_string );
|
||||
} DLL_FUNCTIONS;
|
||||
|
||||
// TODO: create single func
|
||||
|
|
|
@ -31,7 +31,7 @@ typedef struct vsound_exp_s
|
|||
void (*StartSound)( const vec3_t pos, int ent, int chan, sound_t sfx, float vol, float attn, float pitch, bool loop );
|
||||
void (*StreamRawSamples)( int samples, int rate, int width, int channels, const byte *data );
|
||||
bool (*AddLoopingSound)( int entnum, sound_t handle, float volume, float attn );
|
||||
bool (*StartLocalSound)( const char *name );
|
||||
bool (*StartLocalSound)( const char *name, float volume, const float *origin );
|
||||
void (*StartBackgroundTrack)( const char *introTrack, const char *loopTrack );
|
||||
void (*StopBackgroundTrack)( void );
|
||||
|
||||
|
|
|
@ -11,6 +11,9 @@ call vcvars32
|
|||
%MSDEV% baserc/baserc.dsp %CONFIG%"baserc - Win32 Release" %build_target%
|
||||
if errorlevel 1 set BUILD_ERROR=1
|
||||
|
||||
%MSDEV% client/client.dsp %CONFIG%"client - Win32 Release" %build_target%
|
||||
if errorlevel 1 set BUILD_ERROR=1
|
||||
|
||||
%MSDEV% engine/engine.dsp %CONFIG%"engine - Win32 Release" %build_target%
|
||||
if errorlevel 1 set BUILD_ERROR=1
|
||||
|
||||
|
@ -26,7 +29,7 @@ if errorlevel 1 set BUILD_ERROR=1
|
|||
%MSDEV% render/render.dsp %CONFIG%"render - Win32 Release" %build_target%
|
||||
if errorlevel 1 set BUILD_ERROR=1
|
||||
|
||||
%MSDEV% sv_dll/server.dsp %CONFIG%"server - Win32 Release" %build_target%
|
||||
%MSDEV% server/server.dsp %CONFIG%"server - Win32 Release" %build_target%
|
||||
if errorlevel 1 set BUILD_ERROR=1
|
||||
|
||||
%MSDEV% vprogs/vprogs.dsp %CONFIG%"vprogs - Win32 Release" %build_target%
|
||||
|
@ -60,7 +63,7 @@ if exist launch\launch.plg del /f /q launch\launch.plg
|
|||
if exist common\common.plg del /f /q common\common.plg
|
||||
if exist physic\physic.plg del /f /q physic\physic.plg
|
||||
if exist render\render.plg del /f /q render\render.plg
|
||||
if exist sv_dll\server.plg del /f /q sv_dll\server.plg
|
||||
if exist server\server.plg del /f /q server\server.plg
|
||||
if exist vprogs\vprogs.plg del /f /q vprogs\vprogs.plg
|
||||
if exist vsound\vsound.plg del /f /q vsound\vsound.plg
|
||||
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
//=======================================================================
|
||||
// Copyright (C) XashXT Group 2006
|
||||
//=======================================================================
|
||||
|
||||
#ifndef BASEBEAMS_H
|
||||
#define BASEBEAMS_H
|
||||
|
||||
#define SF_BEAM_TRIPPED 0x80000 //bit who indicated "trip" action
|
||||
|
||||
class CBeam : public CBaseLogic
|
||||
{
|
||||
public:
|
||||
void Spawn( void );
|
||||
void Precache( void );
|
||||
int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION); }
|
||||
void Touch( CBaseEntity *pOther );
|
||||
|
||||
// These functions are here to show the way beams are encoded as entities.
|
||||
// Encoding beams as entities simplifies their management in the client/server architecture
|
||||
inline void SetType( int type ) { pev->rendermode = (pev->rendermode & 0xF0) | (type&0x0F); }
|
||||
inline void SetFlags( int flags ) { pev->rendermode = (pev->rendermode & 0x0F) | (flags&0xF0); }
|
||||
inline void SetStartPos( const Vector& pos ) { pev->origin = pos; }
|
||||
inline void SetEndPos( const Vector& pos ) { pev->angles = pos; }
|
||||
void SetStartEntity( int entityIndex );
|
||||
void SetEndEntity( int entityIndex );
|
||||
|
||||
inline void SetStartAttachment( int attachment ) { pev->sequence = (pev->sequence & 0x0FFF) | ((attachment&0xF)<<12); }
|
||||
inline void SetEndAttachment( int attachment ) { pev->skin = (pev->skin & 0x0FFF) | ((attachment&0xF)<<12); }
|
||||
|
||||
inline void SetTexture( int spriteIndex ) { pev->modelindex = spriteIndex; }
|
||||
inline void SetWidth( int width ) { pev->scale = width; }
|
||||
inline void SetNoise( int amplitude ) { pev->body = amplitude; }
|
||||
inline void SetColor( int r, int g, int b ) { pev->rendercolor.x = r; pev->rendercolor.y = g; pev->rendercolor.z = b; }
|
||||
inline void SetBrightness( int brightness ) { pev->renderamt = brightness; }
|
||||
inline void SetFrame( float frame ) { pev->frame = frame; }
|
||||
inline void SetScrollRate( int speed ) { pev->animtime = speed; }
|
||||
|
||||
inline int GetType( void ) { return pev->rendermode & 0x0F; }
|
||||
inline int GetFlags( void ) { return pev->rendermode & 0xF0; }
|
||||
inline int GetStartEntity( void ) { return pev->sequence & 0xFFF; }
|
||||
inline int GetEndEntity( void ) { return pev->skin & 0xFFF; }
|
||||
|
||||
const Vector &GetStartPos( void );
|
||||
const Vector &GetEndPos( void );
|
||||
|
||||
Vector Center( void ) { return (GetStartPos() + GetEndPos()) * 0.5; }; // center point of beam
|
||||
|
||||
inline int GetTexture( void ) { return pev->modelindex; }
|
||||
inline int GetWidth( void ) { return pev->scale; }
|
||||
inline int GetNoise( void ) { return pev->body; }
|
||||
inline Vector GetColor( void ) { return Vector(pev->rendercolor.x, pev->rendercolor.y, pev->rendercolor.z ); }
|
||||
inline int GetBrightness( void ) { return pev->renderamt; }
|
||||
inline int GetFrame( void ) { return pev->frame; }
|
||||
inline int GetScrollRate( void ) { return pev->animtime; }
|
||||
|
||||
CBaseEntity* GetTripEntity( TraceResult *ptr );
|
||||
|
||||
// Call after you change start/end positions
|
||||
void RelinkBeam( void );
|
||||
void SetObjectCollisionBox( void );
|
||||
|
||||
void DoSparks( const Vector &start, const Vector &end );
|
||||
CBaseEntity *RandomTargetname( const char *szName );
|
||||
void BeamDamage( TraceResult *ptr );
|
||||
// Init after BeamCreate()
|
||||
void BeamInit( const char *pSpriteName, int width );
|
||||
void PointsInit( const Vector &start, const Vector &end );
|
||||
void PointEntInit( const Vector &start, int endIndex );
|
||||
void EntsInit( int startIndex, int endIndex );
|
||||
void HoseInit( const Vector &start, const Vector &direction );
|
||||
|
||||
static CBeam *BeamCreate( const char *pSpriteName, int width );
|
||||
|
||||
inline void LiveForTime( float time ) { SetThink( Remove ); SetNextThink( time ); }
|
||||
inline void BeamDamageInstant( TraceResult *ptr, float damage )
|
||||
{
|
||||
pev->dmg = damage;
|
||||
pev->dmgtime = gpGlobals->time - 1;
|
||||
BeamDamage(ptr);
|
||||
}
|
||||
};
|
||||
|
||||
class CLaser : public CBeam
|
||||
{
|
||||
public:
|
||||
void Spawn( void );
|
||||
void PostSpawn( void );
|
||||
void Precache( void );
|
||||
void KeyValue( KeyValueData *pkvd );
|
||||
void Activate( void );
|
||||
void SetObjectCollisionBox( void );
|
||||
void TurnOn( void );
|
||||
void TurnOff( void );
|
||||
void FireAtPoint( Vector startpos, TraceResult &point );
|
||||
|
||||
void Think( void );
|
||||
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
||||
virtual int Save( CSave &save );
|
||||
virtual int Restore( CRestore &restore );
|
||||
static TYPEDESCRIPTION m_SaveData[];
|
||||
|
||||
CSprite *m_pStartSprite;
|
||||
CSprite *m_pEndSprite;
|
||||
};
|
||||
|
||||
#endif //BASEBEAMS_H
|
|
@ -0,0 +1,846 @@
|
|||
//=======================================================================
|
||||
// Copyright (C) Shambler Team 2004
|
||||
// basebreak.cpp - base for all brush
|
||||
// entities.
|
||||
//=======================================================================
|
||||
|
||||
#include "extdll.h"
|
||||
#include "utils.h"
|
||||
#include "sfx.h"
|
||||
#include "cbase.h"
|
||||
#include "decals.h"
|
||||
#include "client.h"
|
||||
#include "soundent.h"
|
||||
#include "saverestore.h"
|
||||
#include "gamerules.h"
|
||||
#include "basebrush.h"
|
||||
#include "defaults.h"
|
||||
#include "player.h"
|
||||
|
||||
//=======================================================================
|
||||
// STATIC BREACABLE BRUSHES
|
||||
//=======================================================================
|
||||
#define DAMAGE_SOUND(x, y, z)EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, x[RANDOM_LONG(0, ARRAYSIZE(x)-1)], y, ATTN_NORM, 0, z)
|
||||
|
||||
//spawn objects
|
||||
const char *CBaseBrush::pSpawnObjects[] =
|
||||
{
|
||||
NULL, // 0
|
||||
"item_battery", // 1
|
||||
"item_healthkit", // 2
|
||||
"weapon_9mmhandgun", // 3
|
||||
"ammo_9mmclip", // 4
|
||||
"weapon_9mmAR", // 5
|
||||
"ammo_9mmAR", // 6
|
||||
"ammo_m203", // 7
|
||||
"weapon_shotgun", // 8
|
||||
"ammo_buckshot", // 9
|
||||
"weapon_crossbow", // 10
|
||||
"ammo_crossbow", // 11
|
||||
"weapon_357", // 12
|
||||
"ammo_357", // 13
|
||||
"weapon_rpg", // 14
|
||||
"ammo_rpgclip", // 15
|
||||
"ammo_gaussclip", // 16
|
||||
"weapon_handgrenade", // 17
|
||||
"weapon_gauss", // 18
|
||||
};
|
||||
|
||||
//material sounds
|
||||
const char *CBaseBrush::pSoundsWood[] =
|
||||
{
|
||||
"materials/wood/wood1.wav",
|
||||
"materials/wood/wood2.wav",
|
||||
"materials/wood/wood3.wav",
|
||||
"materials/wood/wood4.wav",
|
||||
};
|
||||
|
||||
const char *CBaseBrush::pSoundsFlesh[] =
|
||||
{
|
||||
"materials/flesh/flesh1.wav",
|
||||
"materials/flesh/flesh2.wav",
|
||||
"materials/flesh/flesh3.wav",
|
||||
"materials/flesh/flesh4.wav",
|
||||
"materials/flesh/flesh5.wav",
|
||||
"materials/flesh/flesh6.wav",
|
||||
"materials/flesh/flesh7.wav",
|
||||
"materials/flesh/flesh8.wav",
|
||||
};
|
||||
|
||||
const char *CBaseBrush::pSoundsMetal[] =
|
||||
{
|
||||
"materials/metal/metal1.wav",
|
||||
"materials/metal/metal2.wav",
|
||||
"materials/metal/metal3.wav",
|
||||
"materials/metal/metal4.wav",
|
||||
"materials/metal/metal5.wav",
|
||||
};
|
||||
|
||||
const char *CBaseBrush::pSoundsCrete[] =
|
||||
{
|
||||
"materials/crete/concrete1.wav",
|
||||
"materials/crete/concrete2.wav",
|
||||
"materials/crete/concrete3.wav",
|
||||
"materials/crete/concrete4.wav",
|
||||
"materials/crete/concrete5.wav",
|
||||
"materials/crete/concrete6.wav",
|
||||
"materials/crete/concrete7.wav",
|
||||
"materials/crete/concrete8.wav",
|
||||
};
|
||||
|
||||
const char *CBaseBrush::pSoundsGlass[] =
|
||||
{
|
||||
"materials/glass/glass1.wav",
|
||||
"materials/glass/glass2.wav",
|
||||
"materials/glass/glass3.wav",
|
||||
"materials/glass/glass4.wav",
|
||||
"materials/glass/glass5.wav",
|
||||
"materials/glass/glass6.wav",
|
||||
"materials/glass/glass7.wav",
|
||||
"materials/glass/glass8.wav",
|
||||
};
|
||||
|
||||
const char *CBaseBrush::pSoundsCeil[] =
|
||||
{
|
||||
"materials/ceil/ceiling1.wav",
|
||||
"materials/ceil/ceiling2.wav",
|
||||
"materials/ceil/ceiling3.wav",
|
||||
"materials/ceil/ceiling4.wav",
|
||||
};
|
||||
|
||||
const char **CBaseBrush::MaterialSoundList( Materials precacheMaterial, int &soundCount )
|
||||
{
|
||||
const char **pSoundList = NULL;
|
||||
|
||||
switch ( precacheMaterial )
|
||||
{
|
||||
case None:
|
||||
soundCount = 0;
|
||||
break;
|
||||
case Bones:
|
||||
case Flesh:
|
||||
pSoundList = pSoundsFlesh;
|
||||
soundCount = ARRAYSIZE(pSoundsFlesh);
|
||||
break;
|
||||
case CinderBlock:
|
||||
case Concrete:
|
||||
case Rocks:
|
||||
pSoundList = pSoundsCrete;
|
||||
soundCount = ARRAYSIZE(pSoundsCrete);
|
||||
break;
|
||||
case Glass:
|
||||
case Computer:
|
||||
case UnbreakableGlass:
|
||||
pSoundList = pSoundsGlass;
|
||||
soundCount = ARRAYSIZE(pSoundsGlass);
|
||||
break;
|
||||
case MetalPlate:
|
||||
case AirDuct:
|
||||
case Metal:
|
||||
pSoundList = pSoundsMetal;
|
||||
soundCount = ARRAYSIZE(pSoundsMetal);
|
||||
break;
|
||||
case CeilingTile:
|
||||
pSoundList = pSoundsCeil;
|
||||
soundCount = ARRAYSIZE(pSoundsCeil);
|
||||
break;
|
||||
case Wood:
|
||||
pSoundList = pSoundsWood;
|
||||
soundCount = ARRAYSIZE(pSoundsWood);
|
||||
break;
|
||||
default:
|
||||
soundCount = 0;
|
||||
break;
|
||||
}
|
||||
return pSoundList;
|
||||
}
|
||||
|
||||
void CBaseBrush::MaterialSoundPrecache( Materials precacheMaterial )
|
||||
{
|
||||
const char **pSoundList;
|
||||
int i, soundCount = 0;
|
||||
|
||||
pSoundList = MaterialSoundList( precacheMaterial, soundCount );
|
||||
for ( i = 0; i < soundCount; i++ ) UTIL_PrecacheSound( (char *)pSoundList[i] );
|
||||
}
|
||||
|
||||
void CBaseBrush::PlayRandomSound( edict_t *pEdict, Materials soundMaterial, float volume )
|
||||
{
|
||||
const char **pSoundList;
|
||||
int soundCount = 0;
|
||||
|
||||
pSoundList = MaterialSoundList( soundMaterial, soundCount );
|
||||
if ( soundCount ) EMIT_SOUND( pEdict, CHAN_BODY, pSoundList[ RANDOM_LONG(0, soundCount-1) ], volume, 1.0 );
|
||||
}
|
||||
|
||||
void CBaseBrush :: AxisDir( void )
|
||||
{
|
||||
//make backward compatibility
|
||||
if ( pev->movedir != g_vecZero) return;
|
||||
|
||||
//Don't change this!
|
||||
if ( FBitSet(pev->spawnflags, SF_BRUSH_ROTATE_Z_AXIS))
|
||||
pev->movedir = Vector ( 0, 0, 1 ); // around z-axis
|
||||
else if ( FBitSet(pev->spawnflags, SF_BRUSH_ROTATE_X_AXIS))
|
||||
pev->movedir = Vector ( 1, 0, 0 ); // around x-axis
|
||||
else pev->movedir = Vector ( 0, 1, 0 ); // around y-axis
|
||||
}
|
||||
|
||||
void CBaseBrush::KeyValue( KeyValueData* pkvd )
|
||||
{
|
||||
//as default all brushes can select material
|
||||
//and set strength (0 = unbreakable)
|
||||
if (FStrEq(pkvd->szKeyName, "material"))
|
||||
{
|
||||
int i = atoi( pkvd->szValue);
|
||||
|
||||
if ((i < 0) || (i >= LastMaterial))
|
||||
m_Material = Wood;
|
||||
else m_Material = (Materials)i;
|
||||
pkvd->fHandled = TRUE;
|
||||
}
|
||||
else if (FStrEq(pkvd->szKeyName, "strength") )
|
||||
{
|
||||
pev->health = atof(pkvd->szValue);
|
||||
pkvd->fHandled = TRUE;
|
||||
}
|
||||
else if (FStrEq(pkvd->szKeyName, "spawnobject") )
|
||||
{
|
||||
int namelen = strlen(pkvd->szValue) - 1;
|
||||
int obj = atoi( pkvd->szValue );
|
||||
|
||||
//custom spawn object
|
||||
if(namelen > 2) m_iSpawnObject = ALLOC_STRING( pkvd->szValue );
|
||||
else if ( obj > 0 && obj < ARRAYSIZE(pSpawnObjects))
|
||||
m_iSpawnObject = MAKE_STRING( pSpawnObjects[obj] );
|
||||
pkvd->fHandled = TRUE;
|
||||
}
|
||||
else if (FStrEq(pkvd->szKeyName, "gibmodel"))
|
||||
{
|
||||
m_iGibModel = ALLOC_STRING(pkvd->szValue);
|
||||
pkvd->fHandled = TRUE;
|
||||
}
|
||||
else if (FStrEq(pkvd->szKeyName, "volume"))
|
||||
{
|
||||
//0.0 - silence, 1.0 - loudest( obsolete )
|
||||
m_flVolume = atof(pkvd->szValue);
|
||||
if (m_flVolume > 1.0) m_flVolume = 1.0;
|
||||
if (m_flVolume < 0.0) m_flVolume = 0.0;
|
||||
pkvd->fHandled = TRUE;
|
||||
}
|
||||
else if (FStrEq(pkvd->szKeyName, "movesound") || FStrEq(pkvd->szKeyName, "movesnd"))
|
||||
{
|
||||
m_iMoveSound = ALLOC_STRING(pkvd->szValue);
|
||||
pkvd->fHandled = TRUE;
|
||||
}
|
||||
else if (FStrEq(pkvd->szKeyName, "stopsound") || FStrEq(pkvd->szKeyName, "stopsnd"))
|
||||
{
|
||||
m_iStopSound = ALLOC_STRING(pkvd->szValue);
|
||||
pkvd->fHandled = TRUE;
|
||||
}
|
||||
else if (FStrEq(pkvd->szKeyName, "contents"))
|
||||
{
|
||||
pev->skin = atoi(pkvd->szValue);
|
||||
pkvd->fHandled = TRUE;
|
||||
}
|
||||
else CBaseLogic::KeyValue( pkvd );
|
||||
}
|
||||
|
||||
//Base functions
|
||||
TYPEDESCRIPTION CBaseBrush::m_SaveData[] =
|
||||
{
|
||||
DEFINE_FIELD( CBaseBrush, m_flVolume, FIELD_FLOAT ), //volume of sounds
|
||||
DEFINE_FIELD( CBaseBrush, m_pitch, FIELD_FLOAT ), //pitch of sound
|
||||
DEFINE_FIELD( CBaseBrush, m_Material, FIELD_INTEGER ), //brush material
|
||||
DEFINE_FIELD( CBaseBrush, m_iMagnitude, FIELD_INTEGER ), //explosion magnitude
|
||||
DEFINE_FIELD( CBaseBrush, m_iMoveSound, FIELD_STRING ), //sound scheme like Quake
|
||||
DEFINE_FIELD( CBaseBrush, m_iStartSound, FIELD_STRING ), //sound scheme like Quake
|
||||
DEFINE_FIELD( CBaseBrush, m_iStopSound, FIELD_STRING ), //sound scheme like Quake
|
||||
DEFINE_FIELD( CBaseBrush, m_iSpawnObject, FIELD_STRING ), //spawnobject index
|
||||
DEFINE_FIELD( CBaseBrush, m_iGibModel, FIELD_STRING ), //custom gibname
|
||||
DEFINE_FIELD( CBaseBrush, m_vecPlayerPos, FIELD_VECTOR ), //for controllable entity like tank
|
||||
DEFINE_FIELD( CBaseBrush, m_pController, FIELD_CLASSPTR ), //for controllable entity like tank
|
||||
};
|
||||
IMPLEMENT_SAVERESTORE( CBaseBrush, CBaseLogic );
|
||||
|
||||
void CBaseBrush::Spawn( void )
|
||||
{
|
||||
Precache();
|
||||
|
||||
if (!m_flVolume)m_flVolume = 1.0;//just enable full volume
|
||||
|
||||
//breacable brush (if mapmaker just set material - just play material sound)
|
||||
if(IsBreakable())
|
||||
pev->takedamage = DAMAGE_YES;
|
||||
else pev->takedamage = DAMAGE_NO;
|
||||
|
||||
pev->solid = SOLID_BSP;
|
||||
pev->movetype = MOVETYPE_PUSH;
|
||||
if (!m_pParent)pev->flags |= FL_WORLDBRUSH;
|
||||
}
|
||||
|
||||
void CBaseBrush::Precache( void )
|
||||
{
|
||||
const char *pGibName = "";
|
||||
|
||||
switch (m_Material)
|
||||
{
|
||||
case Bones:
|
||||
pGibName = "models/gibs/bones.mdl";
|
||||
break;
|
||||
case Flesh:
|
||||
pGibName = "models/gibs/flesh.mdl";
|
||||
UTIL_PrecacheSound("materials/flesh/bustflesh1.wav");
|
||||
UTIL_PrecacheSound("materials/flesh/bustflesh2.wav");
|
||||
break;
|
||||
case Concrete:
|
||||
pGibName = "models/gibs/concrete.mdl";
|
||||
UTIL_PrecacheSound("materials/crete/bustcrete1.wav");
|
||||
UTIL_PrecacheSound("materials/crete/bustcrete2.wav");
|
||||
break;
|
||||
case Rocks:
|
||||
pGibName = "models/gibs/rock.mdl";
|
||||
UTIL_PrecacheSound("materials/crete/bustcrete1.wav");
|
||||
UTIL_PrecacheSound("materials/crete/bustcrete2.wav");
|
||||
break;
|
||||
case CinderBlock:
|
||||
pGibName = "models/gibs/cinder.mdl";
|
||||
UTIL_PrecacheSound("materials/crete/bustcrete1.wav");
|
||||
UTIL_PrecacheSound("materials/crete/bustcrete2.wav");
|
||||
break;
|
||||
case Computer:
|
||||
pGibName = "models/gibs/computer.mdl";
|
||||
UTIL_PrecacheSound("materials/metal/bustmetal1.wav");
|
||||
UTIL_PrecacheSound("materials/metal/bustmetal2.wav");
|
||||
break;
|
||||
case Glass:
|
||||
case UnbreakableGlass:
|
||||
pGibName = "models/gibs/glass.mdl";
|
||||
UTIL_PrecacheSound("materials/glass/bustglass1.wav");
|
||||
UTIL_PrecacheSound("materials/glass/bustglass2.wav");
|
||||
break;
|
||||
case MetalPlate:
|
||||
pGibName = "models/gibs/metalplate.mdl";
|
||||
UTIL_PrecacheSound("materials/metal/bustmetal1.wav");
|
||||
UTIL_PrecacheSound("materials/metal/bustmetal2.wav");
|
||||
break;
|
||||
case Metal:
|
||||
pGibName = "models/gibs/metal.mdl";
|
||||
UTIL_PrecacheSound("materials/metal/bustmetal1.wav");
|
||||
UTIL_PrecacheSound("materials/metal/bustmetal2.wav");
|
||||
break;
|
||||
case AirDuct:
|
||||
pGibName = "models/gibs/vent.mdl";
|
||||
UTIL_PrecacheSound("materials/metal/bustmetal1.wav");
|
||||
UTIL_PrecacheSound("materials/metal/bustmetal2.wav");
|
||||
break;
|
||||
case CeilingTile:
|
||||
pGibName = "models/gibs/ceiling.mdl";
|
||||
UTIL_PrecacheSound("materials/ceil/bustceiling1.wav");
|
||||
UTIL_PrecacheSound("materials/ceil/bustceiling2.wav");
|
||||
break;
|
||||
case Wood:
|
||||
pGibName = "models/gibs/wood.mdl";
|
||||
UTIL_PrecacheSound("materials/wood/bustcrate1.wav");
|
||||
UTIL_PrecacheSound("materials/wood/bustcrate2.wav");
|
||||
break;
|
||||
case None:
|
||||
default:
|
||||
if(pev->health > 0)//mapmaker forget set material ?
|
||||
{
|
||||
DevMsg("\n======/Xash SmartFiled System/======\n\n");
|
||||
DevMsg("Please set material for %s,\n", STRING(pev->classname));
|
||||
DevMsg("if we want make this breakable\n");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
MaterialSoundPrecache( m_Material );
|
||||
if(IsBreakable())
|
||||
{
|
||||
m_idShard = UTIL_PrecacheModel( m_iGibModel, (char*)pGibName );//precache model
|
||||
if(m_iSpawnObject)UTIL_PrecacheEntity( m_iSpawnObject );
|
||||
}
|
||||
UTIL_PrecacheModel( pev->model );//can use *.mdl for any brush
|
||||
}
|
||||
|
||||
void CBaseBrush :: DamageSound( void )
|
||||
{
|
||||
float fvol;
|
||||
int pitch;
|
||||
|
||||
if (RANDOM_LONG(0,2)) pitch = PITCH_NORM;
|
||||
else pitch = 95 + RANDOM_LONG(0,34);
|
||||
|
||||
fvol = RANDOM_FLOAT(m_flVolume/1.5, m_flVolume);
|
||||
|
||||
switch (m_Material)
|
||||
{
|
||||
case None: break;
|
||||
case Bones:
|
||||
case Flesh:
|
||||
DAMAGE_SOUND(pSoundsFlesh, fvol, pitch );
|
||||
break;
|
||||
case CinderBlock:
|
||||
case Concrete:
|
||||
case Rocks:
|
||||
DAMAGE_SOUND(pSoundsCrete, fvol, pitch );
|
||||
break;
|
||||
case Computer:
|
||||
case Glass:
|
||||
case UnbreakableGlass:
|
||||
DAMAGE_SOUND(pSoundsGlass, fvol, pitch );
|
||||
break;
|
||||
case MetalPlate:
|
||||
case AirDuct:
|
||||
case Metal:
|
||||
DAMAGE_SOUND(pSoundsMetal, fvol, pitch );
|
||||
break;
|
||||
case CeilingTile:
|
||||
DAMAGE_SOUND(pSoundsCeil, fvol, pitch );
|
||||
break;
|
||||
case Wood:
|
||||
DAMAGE_SOUND(pSoundsWood, fvol, pitch );
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
void CBaseBrush::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType )
|
||||
{
|
||||
switch( m_Material )//apply effects for some materials (may be extended in future)
|
||||
{
|
||||
case Computer:
|
||||
{
|
||||
if(RANDOM_LONG(0,1))UTIL_Sparks( ptr->vecEndPos );
|
||||
|
||||
float flVolume = RANDOM_FLOAT ( 0.7 , 1.0 );//random volume range
|
||||
switch ( RANDOM_LONG(0,1) )
|
||||
{
|
||||
case 0: EMIT_SOUND(ENT(pev), CHAN_VOICE, "materials/spark5.wav", flVolume, ATTN_NORM); break;
|
||||
case 1: EMIT_SOUND(ENT(pev), CHAN_VOICE, "materials/spark6.wav", flVolume, ATTN_NORM); break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Glass:
|
||||
{
|
||||
if(pev->health == 0)//unbreakable glass
|
||||
{
|
||||
if( RANDOM_LONG(0,1))UTIL_Ricochet( ptr->vecEndPos, RANDOM_FLOAT(0.5,1.5) );
|
||||
UTIL_DecalTrace(ptr, DECAL_BPROOF1);
|
||||
}
|
||||
else UTIL_DecalTrace(ptr, DECAL_GLASSBREAK1 + RANDOM_LONG(0, 2));//breakable glass
|
||||
}
|
||||
break;
|
||||
case UnbreakableGlass:
|
||||
UTIL_Ricochet( ptr->vecEndPos, RANDOM_FLOAT(0.5,1.5) );
|
||||
break;
|
||||
}
|
||||
CBaseLogic::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType );
|
||||
}
|
||||
|
||||
int CBaseBrush :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType )
|
||||
{
|
||||
Vector vecTemp;
|
||||
|
||||
if ( pevAttacker == pevInflictor )
|
||||
{
|
||||
vecTemp = pevInflictor->origin - ( pev->absmin + ( pev->size * 0.5 ) );
|
||||
if((pevAttacker->flags & FL_CLIENT) && (pev->spawnflags & SF_BREAK_CROWBAR) && (bitsDamageType & DMG_CLUB))
|
||||
flDamage = pev->health; //old valve flag
|
||||
}
|
||||
else vecTemp = pevInflictor->origin - ( pev->absmin + ( pev->size * 0.5 ) );
|
||||
|
||||
if (!IsBreakable())
|
||||
{
|
||||
DamageSound();
|
||||
return 0;
|
||||
}
|
||||
// Breakables take double damage from the crowbar
|
||||
if ( bitsDamageType & DMG_CLUB ) flDamage *= 1.2;
|
||||
else if( bitsDamageType & DMG_CRUSH ) flDamage *= 2;
|
||||
else if( bitsDamageType & DMG_BLAST ) flDamage *= 3;
|
||||
else if( bitsDamageType & DMG_BULLET && m_Material == Glass )flDamage *= 0.5;
|
||||
else if( bitsDamageType & DMG_BULLET && m_Material == Wood )flDamage *= 0.7;
|
||||
else flDamage = 0; //don't give any other damage
|
||||
|
||||
DmgType = bitsDamageType;//member damage type
|
||||
|
||||
g_vecAttackDir = vecTemp.Normalize();
|
||||
pev->health -= flDamage;
|
||||
|
||||
if (pev->health <= 0)
|
||||
{
|
||||
Killed( pevAttacker, GIB_NORMAL );
|
||||
Die();
|
||||
return 0;
|
||||
}
|
||||
DamageSound();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void CBaseBrush :: Blocked( CBaseEntity *pOther )
|
||||
{
|
||||
if(m_pParent && m_pParent->edict() && pFlags & PF_PARENTMOVE)//tell parent
|
||||
m_pParent->Blocked( pOther );
|
||||
|
||||
if(!pOther->IsPlayer() && !pOther->IsMonster())//crash breakable
|
||||
{
|
||||
if(IsBreakable())TakeDamage( pev, pev, 5, DMG_CRUSH );
|
||||
}
|
||||
}
|
||||
|
||||
BOOL CBaseBrush :: IsBreakable( void )
|
||||
{
|
||||
return (pev->health > 0 && m_Material != UnbreakableGlass);
|
||||
}
|
||||
|
||||
void CBaseBrush::Die( void )
|
||||
{
|
||||
Vector vecSpot, vecVelocity;
|
||||
char cFlag = 0;
|
||||
int pitch, soundbits = NULL;
|
||||
float fvol;
|
||||
|
||||
pitch = 95 + RANDOM_LONG(0, 29);
|
||||
if(pitch > 97 && pitch < 103)pitch = 100;
|
||||
|
||||
fvol = RANDOM_FLOAT(0.85, 1.0) + (abs(pev->health) / 100.0);
|
||||
if(fvol > 1.0)fvol = 1.0;
|
||||
|
||||
switch (m_Material)
|
||||
{
|
||||
case None: break; //just in case
|
||||
case Bones:
|
||||
case Flesh:
|
||||
if(RANDOM_LONG(0,1) )
|
||||
EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "materials/flesh/bustflesh1.wav", fvol, ATTN_NORM, 0, pitch);
|
||||
else EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "materials/flesh/bustflesh2.wav", fvol, ATTN_NORM, 0, pitch);
|
||||
cFlag = BREAK_FLESH;
|
||||
soundbits = bits_SOUND_MEAT;
|
||||
break;
|
||||
case CinderBlock:
|
||||
case Concrete:
|
||||
case Rocks:
|
||||
if(RANDOM_LONG(0,1) )
|
||||
EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "materials/crete/bustcrete1.wav", fvol, ATTN_NORM, 0, pitch);
|
||||
else EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "materials/crete/bustcrete2.wav", fvol, ATTN_NORM, 0, pitch);
|
||||
cFlag = BREAK_CONCRETE;
|
||||
soundbits = bits_SOUND_WORLD;
|
||||
break;
|
||||
case Computer:
|
||||
case Metal:
|
||||
case AirDuct:
|
||||
case MetalPlate:
|
||||
if(RANDOM_LONG(0,1) )
|
||||
EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "materials/metal/bustmetal1.wav", fvol, ATTN_NORM, 0, pitch);
|
||||
else EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "materials/metal/bustmetal2.wav", fvol, ATTN_NORM, 0, pitch);
|
||||
cFlag = BREAK_METAL;
|
||||
soundbits = bits_SOUND_WORLD;
|
||||
break;
|
||||
case Glass:
|
||||
if( RANDOM_LONG(0,1) )
|
||||
EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "materials/glass/bustglass1.wav", fvol, ATTN_NORM, 0, pitch);
|
||||
else EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "materials/glass/bustglass2.wav", fvol, ATTN_NORM, 0, pitch);
|
||||
cFlag = BREAK_GLASS;
|
||||
soundbits = bits_SOUND_WORLD;
|
||||
break;
|
||||
|
||||
case Wood:
|
||||
if( RANDOM_LONG(0,1) )
|
||||
EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "materials/wood/bustcrate1.wav", fvol, ATTN_NORM, 0, pitch);
|
||||
else EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "materials/wood/bustcrate2.wav", fvol, ATTN_NORM, 0, pitch);
|
||||
cFlag = BREAK_WOOD;
|
||||
soundbits = bits_SOUND_WORLD;
|
||||
break;
|
||||
case CeilingTile:
|
||||
if( RANDOM_LONG(0,1) )
|
||||
EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "materials/ceil/bustceiling1.wav",fvol, ATTN_NORM, 0, pitch);
|
||||
else EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "materials/ceil/bustceiling1.wav",fvol, ATTN_NORM, 0, pitch);
|
||||
cFlag = BREAK_CONCRETE;
|
||||
soundbits = bits_SOUND_GARBAGE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (DmgType & DMG_CLUB)//direction from crowbar
|
||||
vecVelocity = g_vecAttackDir * clamp(pev->dmg * -10, -1024, 1024);
|
||||
else vecVelocity = UTIL_RandomVector() * clamp(pev->dmg * 10, 1, 240);
|
||||
|
||||
vecSpot = pev->origin + (pev->mins + pev->maxs) * 0.5;
|
||||
float time = RANDOM_FLOAT(25, 100);
|
||||
|
||||
if(soundbits) CSoundEnt::InsertSound(soundbits, pev->origin, 128, 0.5);//make noise for ai
|
||||
SFX_MakeGibs( m_idShard, vecSpot, pev->size, vecVelocity, time, cFlag);
|
||||
|
||||
//what the hell does this ?
|
||||
UTIL_FindBreakable( this );
|
||||
|
||||
// If I'm getting removed, don't fire something that could fire myself
|
||||
pev->targetname = 0;
|
||||
|
||||
pev->solid = SOLID_NOT;
|
||||
UTIL_FireTargets( pev->target, NULL, NULL, USE_TOGGLE );
|
||||
pev->target = 0;
|
||||
Msg("Fire!\n");
|
||||
SetThink( Remove );
|
||||
SetNextThink( 0.1 );
|
||||
|
||||
//pev->effects |= EF_NODRAW;
|
||||
//pev->takedamage = DAMAGE_NO;
|
||||
|
||||
//make explosion
|
||||
if(m_iMagnitude) UTIL_Explode( Center(), edict(), m_iMagnitude );
|
||||
if(m_iSpawnObject) CBaseEntity::Create( (char *)STRING(m_iSpawnObject), Center(), pev->angles, edict() );
|
||||
|
||||
// Fire targets on break
|
||||
|
||||
//UTIL_Remove( this );
|
||||
}
|
||||
|
||||
int CBaseBrush :: DamageDecal( int bitsDamageType )
|
||||
{
|
||||
if ( m_Material == Glass )
|
||||
return DECAL_GLASSBREAK1 + RANDOM_LONG(0,2);
|
||||
if ( m_Material == Glass && pev->health <= 0)
|
||||
return DECAL_BPROOF1;
|
||||
if ( m_Material == UnbreakableGlass )
|
||||
return DECAL_BPROOF1;
|
||||
if ( m_Material == Wood )
|
||||
return DECAL_GUNSHOT1 + RANDOM_LONG(0,4);
|
||||
if ( m_Material == Computer )
|
||||
return DECAL_BIGSHOT1 + RANDOM_LONG(0,4);
|
||||
return CBaseEntity::DamageDecal( bitsDamageType );
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// moving breakable brushes
|
||||
//=======================================================================
|
||||
//material moving sounds
|
||||
const char *CPushable::pPushWood[] =
|
||||
{
|
||||
"materials/wood/pushwood1.wav",
|
||||
"materials/wood/pushwood2.wav",
|
||||
"materials/wood/pushwood3.wav",
|
||||
};
|
||||
|
||||
const char *CPushable::pPushFlesh[] =
|
||||
{
|
||||
"materials/flesh/pushflesh1.wav",
|
||||
"materials/flesh/pushflesh2.wav",
|
||||
"materials/flesh/pushflesh3.wav",
|
||||
};
|
||||
const char *CPushable::pPushMetal[] =
|
||||
{
|
||||
"materials/metal/pushmetal1.wav",
|
||||
"materials/metal/pushmetal2.wav",
|
||||
"materials/metal/pushmetal3.wav",
|
||||
};
|
||||
const char *CPushable::pPushCrete[] =
|
||||
{
|
||||
"materials/crete/pushstone1.wav",
|
||||
"materials/crete/pushstone2.wav",
|
||||
"materials/crete/pushstone3.wav",
|
||||
};
|
||||
const char *CPushable::pPushGlass[] =
|
||||
{
|
||||
"materials/glass/pushglass1.wav",
|
||||
"materials/glass/pushglass2.wav",
|
||||
"materials/glass/pushglass3.wav",
|
||||
};
|
||||
const char *CPushable::pPushCeil[] =
|
||||
{
|
||||
"materials/ceil/ceiling1.wav",
|
||||
"materials/ceil/ceiling2.wav",
|
||||
"materials/ceil/ceiling3.wav",
|
||||
};
|
||||
|
||||
void CPushable :: Spawn( void )
|
||||
{
|
||||
Precache();
|
||||
|
||||
pev->movetype = MOVETYPE_PUSHSTEP;
|
||||
pev->solid = SOLID_BBOX;
|
||||
UTIL_SetModel( ENT(pev), pev->model );
|
||||
UTIL_SetSize( pev, pev->absmin, pev->absmax );
|
||||
|
||||
if (!m_flVolume)m_flVolume = 1.0;//just enable full volume
|
||||
|
||||
//breacable brush (if mapmaker just set material - just play material sound)
|
||||
if(m_Material != None)
|
||||
pev->takedamage = DAMAGE_YES;
|
||||
else pev->takedamage = DAMAGE_NO;
|
||||
|
||||
pev->speed = MatFrictionTable( m_Material );
|
||||
SetBits( pev->flags, FL_FLOAT );
|
||||
pev->origin.z += 1; // Pick up off of the floor
|
||||
UTIL_SetOrigin( this, pev->origin );
|
||||
|
||||
// Multiply by area of the box's cross-section (assume 1000 units^3 standard volume)
|
||||
pev->skin = MatByoancyTable( pev, m_Material );
|
||||
pev->frags = 0;
|
||||
}
|
||||
|
||||
void CPushable :: Precache( void )
|
||||
{
|
||||
CBaseBrush::Precache();
|
||||
PushSoundPrecache( m_Material );
|
||||
}
|
||||
|
||||
const char **CPushable::PushSoundList( Materials precacheMaterial, int &soundCount )
|
||||
{
|
||||
const char **pSoundList = NULL;
|
||||
|
||||
switch ( precacheMaterial )
|
||||
{
|
||||
case None:
|
||||
soundCount = 0;
|
||||
break;
|
||||
case Bones:
|
||||
case Flesh:
|
||||
pSoundList = pPushFlesh;
|
||||
soundCount = ARRAYSIZE(pPushFlesh);
|
||||
break;
|
||||
case CinderBlock:
|
||||
case Concrete:
|
||||
case Rocks:
|
||||
pSoundList = pPushCrete;
|
||||
soundCount = ARRAYSIZE(pPushCrete);
|
||||
break;
|
||||
case Computer:
|
||||
case Glass:
|
||||
pSoundList = pPushGlass;
|
||||
soundCount = ARRAYSIZE(pPushGlass);
|
||||
break;
|
||||
case MetalPlate:
|
||||
case AirDuct:
|
||||
case Metal:
|
||||
pSoundList = pPushMetal;
|
||||
soundCount = ARRAYSIZE(pPushMetal);
|
||||
break;
|
||||
case CeilingTile:
|
||||
pSoundList = pPushCeil;
|
||||
soundCount = ARRAYSIZE(pPushCeil);
|
||||
break;
|
||||
case Wood:
|
||||
pSoundList = pPushWood;
|
||||
soundCount = ARRAYSIZE(pPushWood);
|
||||
break;
|
||||
default:
|
||||
soundCount = 0;
|
||||
break;
|
||||
}
|
||||
return pSoundList;
|
||||
}
|
||||
|
||||
void CPushable::PushSoundPrecache( Materials precacheMaterial )
|
||||
{
|
||||
const char **pPushList;
|
||||
int i, soundCount = 0;
|
||||
|
||||
pPushList = PushSoundList( precacheMaterial, soundCount );
|
||||
for ( i = 0; i < soundCount; i++ ) UTIL_PrecacheSound( (char *)pPushList[i] );
|
||||
}
|
||||
|
||||
int CPushable::PlayPushSound( edict_t *pEdict, Materials soundMaterial, float volume )
|
||||
{
|
||||
const char **pPushList;
|
||||
int soundCount = 0;
|
||||
int m_lastPushSnd = 0;
|
||||
|
||||
pPushList = PushSoundList( soundMaterial, soundCount );
|
||||
if ( soundCount )
|
||||
{
|
||||
m_lastPushSnd = RANDOM_LONG(0, soundCount-1);
|
||||
EMIT_SOUND( pEdict, CHAN_WEAPON, pPushList[ m_lastPushSnd ], volume, 1.0 );
|
||||
}
|
||||
return m_lastPushSnd;
|
||||
}
|
||||
|
||||
void CPushable::StopPushSound( edict_t *pEdict, Materials soundMaterial, int m_lastPushSnd )
|
||||
{
|
||||
const char **pPushList;
|
||||
int soundCount = 0;
|
||||
|
||||
pPushList = PushSoundList( soundMaterial, soundCount );
|
||||
if ( soundCount ) STOP_SOUND( pEdict, CHAN_WEAPON, pPushList[ m_lastPushSnd ] );
|
||||
}
|
||||
|
||||
void CPushable :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
||||
{
|
||||
if(useType == USE_SHOWINFO)
|
||||
{
|
||||
DEBUGHEAD;
|
||||
}
|
||||
else if ( pActivator && pActivator->IsPlayer() && pActivator->pev->velocity != g_vecZero )
|
||||
Move( pActivator, 0 );
|
||||
}
|
||||
|
||||
void CPushable :: Touch( CBaseEntity *pOther )
|
||||
{
|
||||
if ( pOther == g_pWorld ) return;
|
||||
Move( pOther, 1 );
|
||||
}
|
||||
|
||||
void CPushable :: Move( CBaseEntity *pOther, int push )
|
||||
{
|
||||
entvars_t* pevToucher = pOther->pev;
|
||||
int playerTouch = 0;
|
||||
|
||||
// Is entity standing on this pushable ?
|
||||
if ( FBitSet(pevToucher->flags, FL_ONGROUND) && pevToucher->groundentity && VARS(pevToucher->groundentity) == pev )
|
||||
{
|
||||
// Only push if floating
|
||||
if ( pev->waterlevel > 0 && pev->watertype & MASK_WATER )
|
||||
pev->velocity.z += pevToucher->velocity.z * 0.1;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if ( pOther->IsPlayer() )
|
||||
{
|
||||
// Don't push unless the player is pushing forward and NOT use (pull)
|
||||
if ( push && !(pevToucher->button & (IN_FORWARD|IN_USE)) ) return;
|
||||
playerTouch = 1;
|
||||
}
|
||||
|
||||
float factor;
|
||||
|
||||
if ( playerTouch )
|
||||
{
|
||||
// Don't push away from jumping/falling players unless in water
|
||||
if( !(pevToucher->flags & FL_ONGROUND) )
|
||||
{
|
||||
if( pev->waterlevel < 1 || !(pev->watertype & MASK_WATER) )
|
||||
return;
|
||||
else factor = 0.1;
|
||||
}
|
||||
else factor = 1;
|
||||
}
|
||||
else factor = 0.25;
|
||||
|
||||
if (!push) factor = factor*0.5;
|
||||
|
||||
pev->velocity.x += pevToucher->velocity.x * factor;
|
||||
pev->velocity.y += pevToucher->velocity.y * factor;
|
||||
|
||||
float length = sqrt( pev->velocity.x * pev->velocity.x + pev->velocity.y * pev->velocity.y );
|
||||
if ( push && (length > MaxSpeed()) )
|
||||
{
|
||||
pev->velocity.x = (pev->velocity.x * MaxSpeed() / length );
|
||||
pev->velocity.y = (pev->velocity.y * MaxSpeed() / length );
|
||||
}
|
||||
if ( playerTouch )
|
||||
{
|
||||
pevToucher->velocity.x = pev->velocity.x;
|
||||
pevToucher->velocity.y = pev->velocity.y;
|
||||
if ( (gpGlobals->time - pev->frags) > 0.7 )
|
||||
{
|
||||
pev->frags = gpGlobals->time;
|
||||
if ( length > 0 && FBitSet(pev->flags, FL_ONGROUND) )
|
||||
m_lastSound = PlayPushSound( edict(), m_Material, m_flVolume );
|
||||
else StopPushSound( edict(), m_Material, m_lastSound );
|
||||
}
|
||||
}
|
||||
}
|
||||
LINK_ENTITY_TO_CLASS( func_pushable, CPushable );
|
|
@ -0,0 +1,207 @@
|
|||
//=======================================================================
|
||||
// Copyright (C) Shambler Team 2004
|
||||
// basebrush.h - base for all brush
|
||||
// entities.
|
||||
//=======================================================================
|
||||
#ifndef BASEBRUSH_H
|
||||
#define BASEBRUSH_H
|
||||
|
||||
//ANY BRUSH MAY BE SET MATERIAL
|
||||
typedef enum {
|
||||
Glass = 0, //glass.mdl
|
||||
Wood, //wood.mdl
|
||||
Metal, //metal.mdl
|
||||
Flesh, //flesh.mdl
|
||||
CinderBlock, //cinder.mdl
|
||||
CeilingTile, //ceiling.mdl
|
||||
Computer, //computer.mdl
|
||||
UnbreakableGlass, //galss.mdl
|
||||
Rocks, //rock.mdl
|
||||
Bones, //bones.mdl
|
||||
Concrete, //concrete.mdl
|
||||
MetalPlate, //metalplate.mdl
|
||||
AirDuct, //vent.mdl
|
||||
None, //very strange pos
|
||||
LastMaterial, //just in case
|
||||
}Materials;
|
||||
|
||||
//gibs physics
|
||||
typedef enum {
|
||||
Bounce = 0, // bounce at collision
|
||||
Noclip, // no collisions
|
||||
Sticky, // sticky physic
|
||||
Fly, // fly
|
||||
Toss, // toss
|
||||
WalkStep, // monsters walk
|
||||
} Physics;
|
||||
|
||||
static float MatFrictionTable( Materials mat)
|
||||
{
|
||||
float friction = 0;
|
||||
|
||||
switch(mat)
|
||||
{
|
||||
case CinderBlock:
|
||||
case Concrete:
|
||||
case Rocks: friction = 300; break;
|
||||
case Glass: friction = 200; break;
|
||||
case MetalPlate:
|
||||
case Metal: friction = 60; break;
|
||||
case Wood: friction = 250; break;
|
||||
case None:
|
||||
default: friction = 100; break;
|
||||
}
|
||||
return friction;
|
||||
}
|
||||
|
||||
static float MatByoancyTable( entvars_t *pev, Materials mat)
|
||||
{
|
||||
float byoancy = 0;
|
||||
|
||||
switch(mat)
|
||||
{
|
||||
case CinderBlock:
|
||||
case Concrete:
|
||||
case Rocks: byoancy = 0; break;
|
||||
case Glass: byoancy = 5; break;
|
||||
case MetalPlate:
|
||||
case Metal: byoancy = 1; break;
|
||||
case Wood: byoancy = 30; break;
|
||||
case None:
|
||||
default: byoancy = 100; break;
|
||||
}
|
||||
return ( byoancy * (pev->maxs.x - pev->mins.x) * (pev->maxs.y - pev->mins.y) ) * 0.0005;
|
||||
}
|
||||
|
||||
static float MatMassTable( entvars_t *pev, Materials mat)
|
||||
{
|
||||
float mass = 0;
|
||||
|
||||
switch(mat)
|
||||
{
|
||||
case CinderBlock:
|
||||
case Concrete:
|
||||
case Rocks: mass = 2; break;
|
||||
case Glass: mass = 1.2; break;
|
||||
case MetalPlate:
|
||||
case Metal: mass = 1.5; break;
|
||||
case Wood: mass = 0.8; break;
|
||||
case None:
|
||||
default: mass = 1; break;
|
||||
}
|
||||
return (pev->size.Length() * mass);
|
||||
}
|
||||
|
||||
static float MatVolume( Materials mat )
|
||||
{
|
||||
float volume = 0;
|
||||
switch(mat)
|
||||
{
|
||||
case None: volume = 0.9; //unbreakable
|
||||
case Bones: //bones.mdl
|
||||
case Flesh: volume = 0.2; break; //flesh.mdl
|
||||
case CinderBlock: //cinder.mdl
|
||||
case Concrete: //concrete.mdl
|
||||
case Rocks: volume = 0.25; break; //rock.mdl
|
||||
case Computer: //computer.mdl
|
||||
case Glass: volume = 0.3; break; //glass.mdl
|
||||
case MetalPlate: //metalplate.mdl
|
||||
case Metal: //metal.mdl
|
||||
case AirDuct: volume = 0.1; break; //vent.mdl
|
||||
case CeilingTile: //ceiling.mdl
|
||||
case Wood: volume = 0.15; break; //wood.mdl
|
||||
default: volume = 0.2; break;
|
||||
}
|
||||
|
||||
return volume;
|
||||
}
|
||||
|
||||
extern DLL_GLOBAL Vector g_vecAttackDir;
|
||||
#define SetMoveDone( a ) m_pfnCallWhenMoveDone = static_cast <void (CBaseMover::*)(void)> (a)
|
||||
|
||||
class CBaseBrush : public CBaseLogic
|
||||
{
|
||||
public:
|
||||
void Spawn( void );
|
||||
void Precache( void );
|
||||
void KeyValue( KeyValueData* pkvd);
|
||||
|
||||
void Blocked( CBaseEntity *pOther );
|
||||
virtual void AxisDir( void );
|
||||
virtual int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType );
|
||||
void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType );
|
||||
int DamageDecal( int bitsDamageType );
|
||||
|
||||
BOOL IsBreakable( void );
|
||||
|
||||
void EXPORT Die( void );
|
||||
virtual CBaseBrush *MyBrushPointer( void ) { return this; }
|
||||
virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION); }
|
||||
static TYPEDESCRIPTION m_SaveData[];
|
||||
virtual int Save( CSave &save );
|
||||
virtual int Restore( CRestore &restore );
|
||||
|
||||
static void MaterialSoundPrecache( Materials precacheMaterial );
|
||||
static void PlayRandomSound( edict_t *pEdict, Materials soundMaterial, float volume );
|
||||
static const char **MaterialSoundList( Materials precacheMaterial, int &soundCount );
|
||||
|
||||
static const char *pSoundsWood[];
|
||||
static const char *pSoundsFlesh[];
|
||||
static const char *pSoundsMetal[];
|
||||
static const char *pSoundsCrete[];
|
||||
static const char *pSoundsGlass[];
|
||||
static const char *pSoundsCeil[];
|
||||
|
||||
//spawnobject name
|
||||
static const char *pSpawnObjects[];
|
||||
|
||||
void DamageSound( void );
|
||||
|
||||
Materials m_Material;
|
||||
CBasePlayer* m_pController; //player pointer
|
||||
Vector m_vecPlayerPos; //player position
|
||||
int m_iMoveSound; //move sound or preset
|
||||
int m_iStartSound; //start sound or preset
|
||||
int m_iStopSound; //stop sound or preset
|
||||
int m_idShard; //index of gibs
|
||||
int m_iMagnitude; //explosion magnitude
|
||||
int m_iSpawnObject; //spawnobject name
|
||||
int m_iGibModel; //custom gib model
|
||||
int DmgType; //temp container for right calculate damage
|
||||
float m_flVolume; //moving brushes has volume of move sound
|
||||
float m_flBlockedTime; //don't save this
|
||||
int m_pitch; //sound pitch
|
||||
};
|
||||
|
||||
class CPushable : public CBaseBrush
|
||||
{
|
||||
public:
|
||||
void Spawn ( void );
|
||||
void Precache( void );
|
||||
void Touch ( CBaseEntity *pOther );
|
||||
void Move( CBaseEntity *pMover, int push );
|
||||
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
||||
|
||||
virtual int ObjectCaps( void ) { return (CBaseBrush :: ObjectCaps() | FCAP_CONTINUOUS_USE); }
|
||||
virtual BOOL IsPushable( void ) { return TRUE; }
|
||||
|
||||
inline float MaxSpeed( void ) { return pev->speed; }
|
||||
|
||||
static const char *pPushWood[];
|
||||
static const char *pPushFlesh[];
|
||||
static const char *pPushMetal[];
|
||||
static const char *pPushCrete[];
|
||||
static const char *pPushGlass[];
|
||||
static const char *pPushCeil[]; //fixme
|
||||
|
||||
static void PushSoundPrecache( Materials precacheMaterial );
|
||||
static int PlayPushSound( edict_t *pEdict, Materials soundMaterial, float volume );
|
||||
static void StopPushSound( edict_t *pEdict, Materials soundMaterial, int m_lastPushSnd );
|
||||
static const char **PushSoundList( Materials precacheMaterial, int &soundCount );
|
||||
|
||||
int m_lastSound; // no need to save/restore, just keeps the same sound from playing twice in a row
|
||||
};
|
||||
|
||||
#include "basemover.h"
|
||||
|
||||
#endif // BASEBRUSH_H
|
|
@ -0,0 +1,959 @@
|
|||
//=======================================================================
|
||||
// Copyright (C) Shambler Team 2005
|
||||
// baseentity.cpp - base class
|
||||
//=======================================================================
|
||||
|
||||
#include "extdll.h"
|
||||
#include "utils.h"
|
||||
#include "cbase.h"
|
||||
#include "saverestore.h"
|
||||
#include "client.h"
|
||||
#include "nodes.h"
|
||||
#include "decals.h"
|
||||
#include "gamerules.h"
|
||||
#include "game.h"
|
||||
#include "damage.h"
|
||||
#include "defaults.h"
|
||||
#include "bullets.h"
|
||||
|
||||
extern Vector VecBModelOrigin( entvars_t* pevBModel );
|
||||
extern DLL_GLOBAL Vector g_vecAttackDir;
|
||||
extern void SetObjectCollisionBox( entvars_t *pev );
|
||||
extern BOOL NewLevel;
|
||||
extern CGraph WorldGraph;
|
||||
|
||||
//=======================================================================
|
||||
// decent mechanisms
|
||||
//=======================================================================
|
||||
void CBaseEntity::DontThink( void )
|
||||
{
|
||||
m_fNextThink = 0;
|
||||
if (m_pParent == NULL && m_pChild == NULL)
|
||||
{
|
||||
pev->nextthink = 0;
|
||||
m_fPevNextThink = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void CBaseEntity :: SetEternalThink( void )
|
||||
{
|
||||
if (pev->movetype == MOVETYPE_PUSH)
|
||||
{
|
||||
pev->nextthink = pev->ltime + 1E6;
|
||||
m_fPevNextThink = pev->nextthink;
|
||||
}
|
||||
CBaseEntity *pChild;
|
||||
for (pChild = m_pChild; pChild != NULL; pChild = pChild->m_pNextChild)
|
||||
pChild->SetEternalThink( );
|
||||
}
|
||||
|
||||
void CBaseEntity :: SetNextThink( float delay, BOOL correctSpeed )
|
||||
{
|
||||
if (m_pParent || m_pChild )
|
||||
{
|
||||
if (pev->movetype == MOVETYPE_PUSH)
|
||||
m_fNextThink = pev->ltime + delay;
|
||||
else m_fNextThink = gpGlobals->time + delay;
|
||||
|
||||
SetEternalThink( );
|
||||
UTIL_MarkChild( this, correctSpeed, FALSE );
|
||||
}
|
||||
else
|
||||
{
|
||||
// set nextthink as normal.
|
||||
if (pev->movetype == MOVETYPE_PUSH)pev->nextthink = pev->ltime + delay;
|
||||
else pev->nextthink = gpGlobals->time + delay;
|
||||
m_fPevNextThink = m_fNextThink = pev->nextthink;
|
||||
}
|
||||
}
|
||||
|
||||
void CBaseEntity :: AbsoluteNextThink( float time, BOOL correctSpeed )
|
||||
{
|
||||
if (m_pParent || m_pChild)
|
||||
{
|
||||
m_fNextThink = time;
|
||||
SetEternalThink( );
|
||||
UTIL_MarkChild( this, correctSpeed, FALSE );
|
||||
}
|
||||
else
|
||||
{
|
||||
// set nextthink as normal.
|
||||
pev->nextthink = time;
|
||||
m_fPevNextThink = m_fNextThink = pev->nextthink;
|
||||
}
|
||||
}
|
||||
|
||||
void CBaseEntity :: ThinkCorrection( void )
|
||||
{
|
||||
if (pev->nextthink != m_fPevNextThink)
|
||||
{
|
||||
m_fNextThink += pev->nextthink - m_fPevNextThink;
|
||||
m_fPevNextThink = pev->nextthink;
|
||||
}
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// set parent (void ) dinamically link parents
|
||||
//=======================================================================
|
||||
void CBaseEntity :: SetParent( int m_iNewParent, int m_iAttachment )
|
||||
{
|
||||
if(!m_iNewParent) //unlink entity from chain
|
||||
{
|
||||
ResetParent();
|
||||
return;//disable
|
||||
}
|
||||
|
||||
CBaseEntity* pParent;
|
||||
|
||||
if(!m_iAttachment) //try to extract aiment from name
|
||||
{
|
||||
char *name = (char*)STRING(m_iNewParent);
|
||||
for (char *c = name; *c; c++)
|
||||
{
|
||||
if (*c == '.')
|
||||
{
|
||||
m_iAttachment = atoi(c+1);
|
||||
name[strlen(name)-2] = 0;
|
||||
pParent = UTIL_FindEntityByTargetname( NULL, name);
|
||||
SetParent( pParent, m_iAttachment);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
pParent = UTIL_FindEntityByTargetname( NULL, STRING(m_iNewParent));
|
||||
SetParent( pParent, m_iAttachment );
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// set parent main function
|
||||
//=======================================================================
|
||||
void CBaseEntity :: SetParent( CBaseEntity* pParent, int m_iAttachment )
|
||||
{
|
||||
m_pParent = pParent;
|
||||
|
||||
if(!m_pParent)
|
||||
{
|
||||
Msg("=========/Xash Parent System Info:/=========\n");
|
||||
if(pev->targetname) Msg("Warning! Not found parent for %s with name %s\n", STRING(pev->classname), STRING(pev->targetname) );
|
||||
else Msg("Warning! Not found parent for %s\n", STRING(pev->classname) );
|
||||
SHIFT;
|
||||
ResetParent();//lose parent or not found parent
|
||||
return;
|
||||
}
|
||||
|
||||
//check for himself parent
|
||||
if(m_pParent == this)
|
||||
{
|
||||
ALERT(at_console, "=========/Xash Parent System Info:/=========\n");
|
||||
if(pev->targetname) Msg( "ERROR! %s with name %s has illegal parent\n", STRING(pev->classname), STRING(pev->targetname) );
|
||||
else Msg( "ERROR! %s has illegal parent\n", STRING(pev->classname) );
|
||||
SHIFT;
|
||||
ResetParent();//clear parent
|
||||
return;
|
||||
}
|
||||
|
||||
CBaseEntity *pCurChild = m_pParent->m_pChild;
|
||||
while (pCurChild) //check that this entity isn't already in the list of children
|
||||
{
|
||||
if (pCurChild == this) break;
|
||||
pCurChild = pCurChild->m_pNextChild;
|
||||
}
|
||||
if(!pCurChild)
|
||||
{
|
||||
m_pNextChild = m_pParent->m_pChild; // may be null: that's fine by me.
|
||||
m_pParent->m_pChild = this;
|
||||
|
||||
if(m_iAttachment)
|
||||
{
|
||||
if(pev->flags & FL_POINTENTITY || pev->flags & FL_MONSTER)
|
||||
{
|
||||
pev->skin = ENTINDEX(m_pParent->edict());
|
||||
pev->body = m_iAttachment;
|
||||
pev->aiment = m_pParent->edict();
|
||||
pev->movetype = MOVETYPE_FOLLOW;
|
||||
}
|
||||
else //error
|
||||
{
|
||||
ALERT(at_console, "=========/Xash Parent System Info:/=========\n");
|
||||
if(pev->targetname) Msg("ERROR! %s with name %s not following with aiment %d!(yet)\n", STRING(pev->classname), STRING(pev->targetname), m_iAttachment );
|
||||
else Msg("ERROR! %s not following with aiment %d!(yet)\n", STRING(pev->classname), m_iAttachment );
|
||||
SHIFT;
|
||||
}
|
||||
return;
|
||||
}
|
||||
else//appllayed to origin
|
||||
{
|
||||
if (pev->movetype == MOVETYPE_NONE)
|
||||
{
|
||||
if (pev->solid == SOLID_BSP)
|
||||
pev->movetype = MOVETYPE_PUSH;
|
||||
else pev->movetype = MOVETYPE_NOCLIP;
|
||||
SetBits (pFlags, PF_MOVENONE);//member movetype
|
||||
}
|
||||
if(m_pParent->pev->movetype == MOVETYPE_WALK)//parent is walking monster?
|
||||
{
|
||||
SetBits (pFlags, PF_POSTORG);//copy pos from parent every frame
|
||||
pev->solid = SOLID_NOT;//set non solid
|
||||
}
|
||||
pParentOrigin = m_pParent->pev->origin;
|
||||
pParentAngles = m_pParent->pev->angles;
|
||||
}
|
||||
|
||||
if (m_pParent->m_vecSpawnOffset != g_vecZero)
|
||||
{
|
||||
UTIL_AssignOrigin(this, pev->origin + m_pParent->m_vecSpawnOffset);
|
||||
m_vecSpawnOffset = m_vecSpawnOffset + m_pParent->m_vecSpawnOffset;
|
||||
}
|
||||
OffsetOrigin = pev->origin - pParentOrigin;
|
||||
OffsetAngles = pev->angles - pParentAngles;
|
||||
|
||||
if((m_pParent->pFlags & PF_ANGULAR && OffsetOrigin != g_vecZero) || m_pParent->pev->flags & FL_POINTENTITY)
|
||||
{
|
||||
SetBits (pFlags, PF_POSTORG);//magic stuff
|
||||
//GetPInfo( this );
|
||||
}
|
||||
|
||||
if(g_serveractive)//maybe parent is moving ?
|
||||
{
|
||||
pev->velocity += m_pParent->pev->velocity;
|
||||
pev->avelocity += m_pParent->pev->avelocity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// reset parent (void ) dinamically unlink parents
|
||||
//=======================================================================
|
||||
void CBaseEntity :: ResetParent( void )
|
||||
{
|
||||
if(pFlags & PF_MOVENONE)//this entity was static e.g. func_wall
|
||||
{
|
||||
ClearBits (pFlags, PF_MOVENONE);
|
||||
pev->movetype = MOVETYPE_NONE;
|
||||
}
|
||||
|
||||
if ( !g_pWorld )return; //???
|
||||
|
||||
CBaseEntity* pTemp;
|
||||
|
||||
for (pTemp = g_pWorld; pTemp->m_pLinkList != NULL; pTemp = pTemp->m_pLinkList)
|
||||
{
|
||||
if (this == pTemp->m_pLinkList)
|
||||
{
|
||||
pTemp->m_pLinkList = this->m_pLinkList;//save pointer
|
||||
this->m_pLinkList = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_pParent)
|
||||
{
|
||||
pTemp = m_pParent->m_pChild;
|
||||
|
||||
if (pTemp == this)m_pParent->m_pChild = this->m_pNextChild;
|
||||
else
|
||||
{
|
||||
while (pTemp->m_pNextChild)
|
||||
{
|
||||
if (pTemp->m_pNextChild == this)
|
||||
{
|
||||
pTemp->m_pNextChild = this->m_pNextChild;
|
||||
break;
|
||||
}
|
||||
pTemp = pTemp->m_pNextChild;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_pNextChild)
|
||||
{
|
||||
CBaseEntity* pCur = m_pChild;
|
||||
CBaseEntity* pNext;
|
||||
while (pCur != NULL)
|
||||
{
|
||||
pNext = pCur->m_pNextChild;
|
||||
//bring children to a stop
|
||||
UTIL_SetChildVelocity (pCur, g_vecZero, MAX_CHILDS);
|
||||
UTIL_SetChildAvelocity(pCur, g_vecZero, MAX_CHILDS);
|
||||
pCur->m_pParent = NULL;
|
||||
pCur->m_pNextChild = NULL;
|
||||
pCur = pNext;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// setup physics (execute once at spawn)
|
||||
//=======================================================================
|
||||
void CBaseEntity :: SetupPhysics( void )
|
||||
{
|
||||
//rebuild all parents
|
||||
if(pFlags & PF_LINKCHILD) LinkChild( this );
|
||||
if(m_physinit) return;
|
||||
SetParent(); //set all parents
|
||||
m_physinit = true;
|
||||
PostSpawn();//post spawn
|
||||
}
|
||||
|
||||
void CBaseEntity :: RestorePhysics( void )
|
||||
{
|
||||
if(m_iParent) SetParent();
|
||||
}
|
||||
|
||||
void CBaseEntity :: ClearPointers( void )
|
||||
{
|
||||
m_pChild = NULL;
|
||||
m_pNextChild = NULL;
|
||||
m_pLinkList = NULL;
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
// FVisible - returns true if a line can be traced from
|
||||
// the caller's eyes to the target vector
|
||||
//=========================================================
|
||||
BOOL CBaseEntity :: FVisible ( const Vector &vecOrigin )
|
||||
{
|
||||
TraceResult tr;
|
||||
Vector vecLookerOrigin;
|
||||
|
||||
vecLookerOrigin = EyePosition();//look through the caller's 'eyes'
|
||||
|
||||
UTIL_TraceLine(vecLookerOrigin, vecOrigin, ignore_monsters, ignore_glass, ENT(pev)/*pentIgnore*/, &tr);
|
||||
|
||||
if (tr.flFraction != 1.0)
|
||||
return FALSE;
|
||||
return TRUE;// line of sight is valid.
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
// FVisible - returns true if a line can be traced from
|
||||
// the caller's eyes to the target
|
||||
//=========================================================
|
||||
BOOL CBaseEntity :: FVisible ( CBaseEntity *pEntity )
|
||||
{
|
||||
TraceResult tr;
|
||||
Vector vecLookerOrigin;
|
||||
Vector vecTargetOrigin;
|
||||
|
||||
if( FBitSet( pEntity->pev->flags, FL_NOTARGET ))
|
||||
return FALSE;
|
||||
|
||||
// don't look through water
|
||||
if ((pev->waterlevel != 3 && pEntity->pev->waterlevel == 3) || (pev->waterlevel == 3 && pEntity->pev->waterlevel == 0))
|
||||
return FALSE;
|
||||
|
||||
vecLookerOrigin = pev->origin + pev->view_ofs;//look through the caller's 'eyes'
|
||||
vecTargetOrigin = pEntity->EyePosition();
|
||||
|
||||
UTIL_TraceLine(vecLookerOrigin, vecTargetOrigin, ignore_monsters, ignore_glass, ENT(pev)/*pentIgnore*/, &tr);
|
||||
|
||||
if (tr.flFraction != 1.0 && tr.pHit != ENT(pEntity->pev))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// fire bullets
|
||||
//=======================================================================
|
||||
void CBaseEntity::FireBullets(ULONG cShots, Vector vecSrc, Vector vecDirShooting, Vector vecSpread, float flDistance, int iBulletType, int iTracerFreq, int iDamage, entvars_t *pevAttacker )
|
||||
{
|
||||
static int tracerCount;
|
||||
int tracer;
|
||||
TraceResult tr;
|
||||
Vector vecRight = gpGlobals->v_right;
|
||||
Vector vecUp = gpGlobals->v_up;
|
||||
|
||||
if ( pevAttacker == NULL )
|
||||
pevAttacker = pev; // the default attacker is ourselves
|
||||
|
||||
ClearMultiDamage();
|
||||
gMultiDamage.type = DMG_BULLET | DMG_NEVERGIB;
|
||||
|
||||
for (ULONG iShot = 1; iShot <= cShots; iShot++)
|
||||
{
|
||||
// get circular gaussian spread
|
||||
float x, y, z;
|
||||
do {
|
||||
x = RANDOM_FLOAT(-0.5,0.5) + RANDOM_FLOAT(-0.5,0.5);
|
||||
y = RANDOM_FLOAT(-0.5,0.5) + RANDOM_FLOAT(-0.5,0.5);
|
||||
z = x*x+y*y;
|
||||
} while (z > 1);
|
||||
|
||||
Vector vecDir = vecDirShooting +
|
||||
x * vecSpread.x * vecRight +
|
||||
y * vecSpread.y * vecUp;
|
||||
Vector vecEnd;
|
||||
|
||||
vecEnd = vecSrc + vecDir * flDistance;
|
||||
UTIL_TraceLine(vecSrc, vecEnd, dont_ignore_monsters, ENT(pev)/*pentIgnore*/, &tr);
|
||||
|
||||
tracer = 0;
|
||||
if (iTracerFreq != 0 && (tracerCount++ % iTracerFreq) == 0)
|
||||
{
|
||||
Vector vecTracerSrc;
|
||||
|
||||
if ( IsPlayer() )
|
||||
{// adjust tracer position for player
|
||||
vecTracerSrc = vecSrc + Vector ( 0 , 0 , -4 ) + gpGlobals->v_right * 2 + gpGlobals->v_forward * 16;
|
||||
}
|
||||
else
|
||||
{
|
||||
vecTracerSrc = vecSrc;
|
||||
}
|
||||
|
||||
if ( iTracerFreq != 1 ) // guns that always trace also always decal
|
||||
tracer = 1;
|
||||
switch( iBulletType )
|
||||
{
|
||||
case BULLET_MP5:
|
||||
case BULLET_9MM:
|
||||
case BULLET_12MM:
|
||||
case BULLET_357:
|
||||
case BULLET_556:
|
||||
case BULLET_762:
|
||||
case BULLET_BUCKSHOT:
|
||||
default:
|
||||
MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, vecTracerSrc );
|
||||
WRITE_BYTE( TE_TRACER );
|
||||
WRITE_COORD( vecTracerSrc.x );
|
||||
WRITE_COORD( vecTracerSrc.y );
|
||||
WRITE_COORD( vecTracerSrc.z );
|
||||
WRITE_COORD( tr.vecEndPos.x );
|
||||
WRITE_COORD( tr.vecEndPos.y );
|
||||
WRITE_COORD( tr.vecEndPos.z );
|
||||
MESSAGE_END();
|
||||
break;
|
||||
}
|
||||
}
|
||||
// do damage, paint decals
|
||||
if (tr.flFraction != 1.0)
|
||||
{
|
||||
CBaseEntity *pEntity = CBaseEntity::Instance(tr.pHit);
|
||||
|
||||
if ( iDamage )
|
||||
{
|
||||
pEntity->TraceAttack(pevAttacker, iDamage, vecDir, &tr, DMG_BULLET | ((iDamage > 16) ? DMG_ALWAYSGIB : DMG_NEVERGIB) );
|
||||
|
||||
TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
|
||||
DecalGunshot( &tr, iBulletType );
|
||||
}
|
||||
else switch(iBulletType)
|
||||
{
|
||||
default:
|
||||
case BULLET_9MM:
|
||||
pEntity->TraceAttack(pevAttacker, _9MM_DMG, vecDir, &tr, DMG_BULLET);
|
||||
|
||||
TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
|
||||
DecalGunshot( &tr, iBulletType );
|
||||
|
||||
break;
|
||||
|
||||
case BULLET_MP5:
|
||||
pEntity->TraceAttack(pevAttacker, _MP5_DMG, vecDir, &tr, DMG_BULLET);
|
||||
|
||||
TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
|
||||
DecalGunshot( &tr, iBulletType );
|
||||
|
||||
break;
|
||||
|
||||
case BULLET_12MM:
|
||||
pEntity->TraceAttack(pevAttacker, _12MM_DMG, vecDir, &tr, DMG_BULLET);
|
||||
if ( !tracer )
|
||||
{
|
||||
TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
|
||||
DecalGunshot( &tr, iBulletType );
|
||||
}
|
||||
break;
|
||||
|
||||
case BULLET_556:
|
||||
pEntity->TraceAttack(pevAttacker, _556_DMG, vecDir, &tr, DMG_BULLET);
|
||||
if ( !tracer )
|
||||
{
|
||||
TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
|
||||
DecalGunshot( &tr, iBulletType );
|
||||
}
|
||||
break;
|
||||
|
||||
case BULLET_762:
|
||||
pEntity->TraceAttack(pevAttacker, _762_DMG, vecDir, &tr, DMG_BULLET);
|
||||
if ( !tracer )
|
||||
{
|
||||
TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
|
||||
DecalGunshot( &tr, iBulletType );
|
||||
}
|
||||
break;
|
||||
|
||||
case BULLET_BUCKSHOT:
|
||||
pEntity->TraceAttack(pevAttacker, BUCKSHOT_DMG, vecDir, &tr, DMG_BULLET);
|
||||
if ( !tracer )
|
||||
{
|
||||
TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
|
||||
DecalGunshot( &tr, iBulletType );
|
||||
}
|
||||
break;
|
||||
|
||||
case BULLET_357:
|
||||
pEntity->TraceAttack(pevAttacker, _357_DMG, vecDir, &tr, DMG_BULLET);
|
||||
if ( !tracer )
|
||||
{
|
||||
TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
|
||||
DecalGunshot( &tr, iBulletType );
|
||||
}
|
||||
break;
|
||||
|
||||
case BULLET_NONE: // FIX
|
||||
pEntity->TraceAttack(pevAttacker, 50, vecDir, &tr, DMG_CLUB);
|
||||
TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType);
|
||||
// only decal glass
|
||||
if ( !FNullEnt(tr.pHit) && VARS(tr.pHit)->rendermode != 0)
|
||||
{
|
||||
UTIL_DecalTrace( &tr, DECAL_GLASSBREAK1 + RANDOM_LONG(0,2) );
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
// make bullet trails
|
||||
UTIL_BubbleTrail( vecSrc, tr.vecEndPos, (flDistance * tr.flFraction) / 64.0 );
|
||||
}
|
||||
ApplyMultiDamage(pev, pevAttacker);
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// traceing operations
|
||||
//=======================================================================
|
||||
void CBaseEntity :: TraceBleed( float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType )
|
||||
{
|
||||
if (BloodColor() == DONT_BLEED)
|
||||
return;
|
||||
|
||||
if (flDamage == 0)
|
||||
return;
|
||||
|
||||
if (!(bitsDamageType & (DMG_CRUSH | DMG_BULLET | DMG_SLASH | DMG_BLAST | DMG_CLUB | DMG_MORTAR)))
|
||||
return;
|
||||
|
||||
// make blood decal on the wall!
|
||||
TraceResult Bloodtr;
|
||||
Vector vecTraceDir;
|
||||
float flNoise;
|
||||
int cCount;
|
||||
int i;
|
||||
|
||||
if (flDamage < 10)
|
||||
{
|
||||
flNoise = 0.1;
|
||||
cCount = 1;
|
||||
}
|
||||
else if (flDamage < 25)
|
||||
{
|
||||
flNoise = 0.2;
|
||||
cCount = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
flNoise = 0.3;
|
||||
cCount = 4;
|
||||
}
|
||||
|
||||
for ( i = 0 ; i < cCount ; i++ )
|
||||
{
|
||||
vecTraceDir = vecDir * -1;// trace in the opposite direction the shot came from (the direction the shot is going)
|
||||
|
||||
vecTraceDir.x += RANDOM_FLOAT( -flNoise, flNoise );
|
||||
vecTraceDir.y += RANDOM_FLOAT( -flNoise, flNoise );
|
||||
vecTraceDir.z += RANDOM_FLOAT( -flNoise, flNoise );
|
||||
|
||||
UTIL_TraceLine( ptr->vecEndPos, ptr->vecEndPos + vecTraceDir * -172, ignore_monsters, ENT(pev), &Bloodtr);
|
||||
|
||||
if ( Bloodtr.flFraction != 1.0 )
|
||||
{
|
||||
UTIL_BloodDecalTrace( &Bloodtr, BloodColor() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CBaseEntity::TraceAttack(entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType)
|
||||
{
|
||||
Vector vecOrigin = ptr->vecEndPos - vecDir * 4;
|
||||
|
||||
if ( pev->takedamage )
|
||||
{
|
||||
AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType );
|
||||
|
||||
int blood = BloodColor();
|
||||
|
||||
if ( blood != DONT_BLEED )
|
||||
{
|
||||
SpawnBlood(vecOrigin, blood, flDamage);// a little surface blood.
|
||||
TraceBleed( flDamage, vecDir, ptr, bitsDamageType );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// take damage\health
|
||||
//=======================================================================
|
||||
int CBaseEntity :: TakeHealth( float flHealth, int bitsDamageType )
|
||||
{
|
||||
if(!pev->takedamage) return 0;
|
||||
if ( pev->health >= pev->max_health ) return 0;
|
||||
|
||||
pev->health += flHealth;
|
||||
pev->health = min(pev->health, pev->max_health);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CBaseEntity :: TakeArmor( float flArmor, int suit )
|
||||
{
|
||||
if(!pev->takedamage) return 0;
|
||||
if (pev->armorvalue >= MAX_NORMAL_BATTERY) return 0;
|
||||
|
||||
pev->armorvalue += flArmor;
|
||||
pev->armorvalue = min(pev->armorvalue, MAX_NORMAL_BATTERY);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CBaseEntity :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType )
|
||||
{
|
||||
Vector vecTemp;
|
||||
|
||||
if (!pev->takedamage) return 0;
|
||||
|
||||
// if Attacker == Inflictor, the attack was a melee or other instant-hit attack.
|
||||
// (that is, no actual entity projectile was involved in the attack so use the shooter's origin).
|
||||
if ( pevAttacker == pevInflictor )
|
||||
{
|
||||
vecTemp = pevInflictor->origin - ( VecBModelOrigin(pev) );
|
||||
}
|
||||
else // an actual missile was involved.
|
||||
{
|
||||
vecTemp = pevInflictor->origin - ( VecBModelOrigin(pev) );
|
||||
}
|
||||
|
||||
// this global is still used for glass and other non-monster killables, along with decals.
|
||||
g_vecAttackDir = vecTemp.Normalize();
|
||||
|
||||
// save damage based on the target's armor level
|
||||
|
||||
// figure momentum add (don't let hurt brushes or other triggers move player)
|
||||
if ((!FNullEnt(pevInflictor)) && (pev->movetype == MOVETYPE_WALK || pev->movetype == MOVETYPE_STEP) && (pevAttacker->solid != SOLID_TRIGGER) )
|
||||
{
|
||||
Vector vecDir = pev->origin - (pevInflictor->absmin + pevInflictor->absmax) * 0.5;
|
||||
vecDir = vecDir.Normalize();
|
||||
|
||||
float flForce = flDamage * ((32 * 32 * 72.0) / (pev->size.x * pev->size.y * pev->size.z)) * 5;
|
||||
|
||||
if (flForce > 1000.0) flForce = 1000.0;
|
||||
pev->velocity = pev->velocity + vecDir * flForce;
|
||||
}
|
||||
|
||||
// do the damage
|
||||
pev->health -= flDamage;
|
||||
if (pev->health <= 0)
|
||||
{
|
||||
Killed( pevAttacker, GIB_NORMAL );
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CBaseEntity :: DamageDecal( int bitsDamageType )
|
||||
{
|
||||
if ( pev->rendermode == kRenderTransAlpha )
|
||||
return -1;
|
||||
|
||||
if ( pev->rendermode != kRenderNormal )
|
||||
return DECAL_BPROOF1;
|
||||
|
||||
return DECAL_GUNSHOT1 + RANDOM_LONG(0, 4);
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// killed/create operations
|
||||
//=======================================================================
|
||||
CBaseEntity * CBaseEntity::Create( char *szName, const Vector &vecOrigin, const Vector &vecAngles, edict_t *pentOwner )
|
||||
{
|
||||
edict_t *pent;
|
||||
int istr = ALLOC_STRING(szName);
|
||||
CBaseEntity *pEntity;
|
||||
|
||||
// check for virtual entities
|
||||
if( FUNCTION_FROM_NAME( szName ) != 0 )
|
||||
{
|
||||
pent = CREATE_NAMED_ENTITY( istr );
|
||||
if ( FNullEnt( pent )) return NULL;
|
||||
}
|
||||
else if(!strncmp( szName, "weapon_", 7))
|
||||
{
|
||||
//may be this a weapon_generic entity?
|
||||
pent = CREATE_NAMED_ENTITY(MAKE_STRING("weapon_generic"));
|
||||
if ( FNullEnt( pent )) return NULL; // this never gonna called anymore. just in case
|
||||
pent->v.netname = istr;
|
||||
}
|
||||
else if(!strncmp( szName, "item_", 5))
|
||||
{
|
||||
//may be this a weapon_generic entity?
|
||||
pent = CREATE_NAMED_ENTITY(MAKE_STRING("item_generic"));
|
||||
if ( FNullEnt( pent )) return NULL; // this never gonna called anymore. just in case
|
||||
pent->v.netname = istr;
|
||||
}
|
||||
else if(!strncmp( szName, "ammo_", 5))
|
||||
{
|
||||
//may be this a weapon_generic entity?
|
||||
pent = CREATE_NAMED_ENTITY(MAKE_STRING("item_generic"));
|
||||
if ( FNullEnt( pent )) return NULL; // this never gonna called anymore. just in case
|
||||
pent->v.netname = istr;
|
||||
}
|
||||
else //unknown error
|
||||
{
|
||||
Msg("can't create %s\n", szName );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pEntity = Instance( pent );
|
||||
pEntity->pev->owner = pentOwner;
|
||||
pEntity->pev->origin = vecOrigin;
|
||||
pEntity->pev->angles = vecAngles;
|
||||
DispatchSpawn( pEntity->edict() );
|
||||
return pEntity;
|
||||
}
|
||||
|
||||
CBaseEntity * CBaseEntity::CreateGib( char *szName, char *szModel )
|
||||
{
|
||||
edict_t *pent;
|
||||
CBaseEntity *pEntity;
|
||||
string_t model = MAKE_STRING( szModel );
|
||||
int istr = ALLOC_STRING(szName);
|
||||
|
||||
//check for virtual entities
|
||||
if(GetProcAddress( GetModuleHandle("server"), szName ))
|
||||
{
|
||||
pent = CREATE_NAMED_ENTITY(istr);
|
||||
if ( FNullEnt( pent )) return NULL;
|
||||
}
|
||||
else if(!strncmp( szName, "weapon_", 7))
|
||||
{
|
||||
//may be this a weapon_generic entity?
|
||||
pent = CREATE_NAMED_ENTITY(MAKE_STRING("weapon_generic"));
|
||||
if ( FNullEnt( pent )) return NULL; //this never gonna called anymore. just in case
|
||||
pent->v.netname = istr;
|
||||
}
|
||||
else if(!strncmp( szName, "item_", 5))
|
||||
{
|
||||
//may be this a weapon_generic entity?
|
||||
pent = CREATE_NAMED_ENTITY(MAKE_STRING("item_generic"));
|
||||
if ( FNullEnt( pent )) return NULL;//this never gonna called anymore. just in case
|
||||
pent->v.netname = istr;
|
||||
}
|
||||
else if(!strncmp( szName, "ammo_", 5))
|
||||
{
|
||||
//may be this a weapon_generic entity?
|
||||
pent = CREATE_NAMED_ENTITY(MAKE_STRING("item_generic"));
|
||||
if ( FNullEnt( pent )) return NULL;//this never gonna called anymore. just in case
|
||||
pent->v.netname = istr;
|
||||
}
|
||||
else //unknown error
|
||||
{
|
||||
Msg("can't create %s\n", szName );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pEntity = Instance( pent );
|
||||
DispatchSpawn( pEntity->edict() );
|
||||
|
||||
if(!FStringNull( model ))
|
||||
{
|
||||
UTIL_SetModel( pEntity->edict(), szModel );
|
||||
Msg("szModel %s\n", szModel );
|
||||
}
|
||||
return pEntity;
|
||||
}
|
||||
|
||||
void CBaseEntity :: Killed( entvars_t *pevAttacker, int iGib )
|
||||
{
|
||||
pev->takedamage = DAMAGE_NO;
|
||||
pev->deadflag = DEAD_DEAD;
|
||||
UTIL_Remove( this );
|
||||
}
|
||||
|
||||
void CBaseEntity::UpdateOnRemove( void )
|
||||
{
|
||||
ResetParent();
|
||||
|
||||
if ( FBitSet( pev->flags, FL_GRAPHED ) )
|
||||
{
|
||||
for (int i = 0 ; i < WorldGraph.m_cLinks ; i++ )
|
||||
{
|
||||
if ( WorldGraph.m_pLinkPool [ i ].m_pLinkEnt == pev )
|
||||
WorldGraph.m_pLinkPool [ i ].m_pLinkEnt = NULL;
|
||||
}
|
||||
}
|
||||
if ( pev->globalname ) gGlobalState.EntitySetState( pev->globalname, GLOBAL_DEAD );
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// three methods of remove entity
|
||||
//=======================================================================
|
||||
void CBaseEntity :: Remove( void )
|
||||
{
|
||||
UpdateOnRemove();
|
||||
if (pev->health > 0)pev->health = 0;
|
||||
REMOVE_ENTITY(ENT(pev));
|
||||
}
|
||||
|
||||
void CBaseEntity :: PVSRemove( void )
|
||||
{
|
||||
if ( FNullEnt( FIND_CLIENT_IN_PVS( edict()))) SetThink( Remove );
|
||||
SetNextThink( 0.1 );
|
||||
}
|
||||
|
||||
void CBaseEntity :: Fadeout( void )
|
||||
{
|
||||
if (pev->rendermode == kRenderNormal)
|
||||
{
|
||||
pev->renderamt = 255;
|
||||
pev->rendermode = kRenderTransTexture;
|
||||
}
|
||||
|
||||
pev->solid = SOLID_NOT;
|
||||
pev->avelocity = g_vecZero;
|
||||
|
||||
if ( pev->renderamt > 7 )
|
||||
{
|
||||
pev->renderamt -= 7;
|
||||
SetNextThink( 0.1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
pev->renderamt = 0;
|
||||
SetNextThink( 0.2 );
|
||||
SetThink( Remove );
|
||||
}
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// global save\restore data
|
||||
//=======================================================================
|
||||
TYPEDESCRIPTION CBaseEntity::m_SaveData[] =
|
||||
{
|
||||
DEFINE_FIELD( CBaseEntity, m_pGoalEnt, FIELD_CLASSPTR ),
|
||||
|
||||
//parent system saves
|
||||
DEFINE_FIELD( CBaseEntity, m_iParent, FIELD_STRING ),
|
||||
DEFINE_FIELD( CBaseEntity, m_pParent, FIELD_CLASSPTR ),
|
||||
DEFINE_FIELD( CBaseEntity, m_pChild, FIELD_CLASSPTR ),
|
||||
DEFINE_FIELD( CBaseEntity, m_pNextChild, FIELD_CLASSPTR ),
|
||||
DEFINE_FIELD( CBaseEntity, OffsetOrigin, FIELD_VECTOR ),
|
||||
DEFINE_FIELD( CBaseEntity, OffsetAngles, FIELD_VECTOR ),
|
||||
DEFINE_FIELD( CBaseEntity, pFlags, FIELD_INTEGER ),
|
||||
DEFINE_FIELD( CBaseEntity, m_physinit, FIELD_BOOLEAN ),
|
||||
|
||||
//local child coordinates
|
||||
DEFINE_FIELD( CBaseEntity, PostOrigin, FIELD_VECTOR ),
|
||||
DEFINE_FIELD( CBaseEntity, PostAngles, FIELD_VECTOR ),
|
||||
DEFINE_FIELD( CBaseEntity, PostVelocity, FIELD_VECTOR ),
|
||||
DEFINE_FIELD( CBaseEntity, PostAvelocity, FIELD_VECTOR ),
|
||||
|
||||
//think time
|
||||
DEFINE_FIELD( CBaseEntity, m_fNextThink, FIELD_TIME ),
|
||||
DEFINE_FIELD( CBaseEntity, m_fPevNextThink, FIELD_TIME ),
|
||||
|
||||
DEFINE_FIELD( CBaseEntity, m_iStyle, FIELD_INTEGER ),
|
||||
DEFINE_FIELD( CBaseEntity, m_iAcessLevel, FIELD_INTEGER ),
|
||||
|
||||
DEFINE_FIELD( CBaseEntity, m_pfnThink, FIELD_FUNCTION ),
|
||||
DEFINE_FIELD( CBaseEntity, m_pfnTouch, FIELD_FUNCTION ),
|
||||
DEFINE_FIELD( CBaseEntity, m_pfnUse, FIELD_FUNCTION ),
|
||||
DEFINE_FIELD( CBaseEntity, m_pfnBlocked, FIELD_FUNCTION ),
|
||||
};
|
||||
|
||||
int CBaseEntity::Save( CSave &save )
|
||||
{
|
||||
ThinkCorrection();
|
||||
|
||||
if ( save.WriteEntVars( "ENTVARS", pev ) )
|
||||
{
|
||||
if (pev->targetname)
|
||||
return save.WriteFields( STRING(pev->targetname), "BASE", this, m_SaveData, ARRAYSIZE(m_SaveData) );
|
||||
else return save.WriteFields( STRING(pev->classname ), "BASE", this, m_SaveData, ARRAYSIZE(m_SaveData) );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CBaseEntity::Restore( CRestore &restore )
|
||||
{
|
||||
int status;
|
||||
|
||||
status = restore.ReadEntVars( "ENTVARS", pev );
|
||||
if ( status ) status = restore.ReadFields( "BASE", this, m_SaveData, ARRAYSIZE(m_SaveData) );
|
||||
|
||||
if ( pev->modelindex != 0 && !FStringNull(pev->model) )
|
||||
{
|
||||
Vector mins = pev->mins, maxs = pev->maxs; // Set model is about to destroy these
|
||||
|
||||
UTIL_PrecacheModel( pev->model );
|
||||
UTIL_SetModel(ENT(pev), pev->model);
|
||||
UTIL_SetSize(pev, mins, maxs);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// collisoin boxes
|
||||
//=======================================================================
|
||||
void CBaseEntity::SetObjectCollisionBox( void )
|
||||
{
|
||||
::SetObjectCollisionBox( pev );
|
||||
}
|
||||
|
||||
int CBaseEntity :: Intersects( CBaseEntity *pOther )
|
||||
{
|
||||
if ( pOther->pev->absmin.x > pev->absmax.x ||
|
||||
pOther->pev->absmin.y > pev->absmax.y ||
|
||||
pOther->pev->absmin.z > pev->absmax.z ||
|
||||
pOther->pev->absmax.x < pev->absmin.x ||
|
||||
pOther->pev->absmax.y < pev->absmin.y ||
|
||||
pOther->pev->absmax.z < pev->absmin.z )
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// Dormant operations
|
||||
//=======================================================================
|
||||
void CBaseEntity :: MakeDormant( void )
|
||||
{
|
||||
SetBits( pev->flags, FL_DORMANT );
|
||||
|
||||
pev->solid = SOLID_NOT;
|
||||
pev->movetype = MOVETYPE_NONE;
|
||||
SetBits( pev->effects, EF_NODRAW );
|
||||
DontThink();
|
||||
UTIL_SetOrigin( this, pev->origin );
|
||||
}
|
||||
|
||||
int CBaseEntity :: IsDormant( void )
|
||||
{
|
||||
return FBitSet( pev->flags, FL_DORMANT );
|
||||
}
|
||||
|
||||
BOOL CBaseEntity :: IsInWorld( void )
|
||||
{
|
||||
if (pev->origin.x >= MAP_HALFSIZE) return FALSE;
|
||||
if (pev->origin.y >= MAP_HALFSIZE) return FALSE;
|
||||
if (pev->origin.z >= MAP_HALFSIZE) return FALSE;
|
||||
if (pev->origin.x <= -MAP_HALFSIZE) return FALSE;
|
||||
if (pev->origin.y <= -MAP_HALFSIZE) return FALSE;
|
||||
if (pev->origin.z <= -MAP_HALFSIZE) return FALSE;
|
||||
if (pev->velocity.x >= MAX_VELOCITY) return FALSE;
|
||||
if (pev->velocity.y >= MAX_VELOCITY) return FALSE;
|
||||
if (pev->velocity.z >= MAX_VELOCITY) return FALSE;
|
||||
if (pev->velocity.x <= -MAX_VELOCITY) return FALSE;
|
||||
if (pev->velocity.y <= -MAX_VELOCITY) return FALSE;
|
||||
if (pev->velocity.z <= -MAX_VELOCITY) return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
|
@ -0,0 +1,324 @@
|
|||
//=======================================================================
|
||||
// Copyright (C) XashXT Group 2006
|
||||
//=======================================================================
|
||||
|
||||
|
||||
#ifndef BASEENTITY_H
|
||||
#define BASEENTITY_H
|
||||
|
||||
class CBaseEntity
|
||||
{
|
||||
public:
|
||||
// Constructor. Set engine to use C/C++ callback functions
|
||||
// pointers to engine data
|
||||
entvars_t *pev; // Don't need to save/restore this pointer, the engine resets it
|
||||
|
||||
// path corners
|
||||
CBaseEntity *m_pGoalEnt;// path corner we are heading towards
|
||||
CBaseEntity *m_pLink;// used for temporary link-list operations.
|
||||
|
||||
float m_fNextThink;
|
||||
float m_fPevNextThink;
|
||||
float flTravelTime; //time to moving brushes
|
||||
int m_iStyle;
|
||||
int m_iAcessLevel;//acess level for retinal sacners
|
||||
|
||||
//===================================================================================================
|
||||
// Xash BaseEntity
|
||||
//===================================================================================================
|
||||
|
||||
// Gets the interface to the collideable representation of the entity
|
||||
virtual void SetModelIndex( int index );
|
||||
virtual int GetModelIndex( void ) const;
|
||||
|
||||
// Returns a CBaseAnimating if the entity is derived from CBaseAnimating.
|
||||
virtual CBaseAnimating* GetBaseAnimating() { return NULL; }
|
||||
|
||||
void SetName( string_t newTarget );
|
||||
void SetParent( string_t newParent, CBaseEntity *pActivator );
|
||||
virtual void ChangeCamera( string_t newcamera ) {}
|
||||
|
||||
public:
|
||||
unsigned char m_iParentAttachment; // 0 if we're relative to the parent's absorigin and absangles.
|
||||
EHANDLE m_hParent;
|
||||
EHANDLE m_hMoveParent;
|
||||
EHANDLE m_hMoveChild;
|
||||
EHANDLE m_hMovePeer;
|
||||
|
||||
//===================================================================================================
|
||||
// Xash Parent System 0.2 beta
|
||||
//===================================================================================================
|
||||
|
||||
Vector PostOrigin; //child postorigin
|
||||
Vector PostAngles; //child postangles
|
||||
Vector PostVelocity; //child postvelocity
|
||||
Vector PostAvelocity; //child postavelocity
|
||||
Vector OffsetOrigin; //spawn offset origin
|
||||
Vector OffsetAngles; //spawn offset angles
|
||||
Vector pParentAngles; //temp container
|
||||
Vector pParentOrigin; //temp container
|
||||
Vector m_vecSpawnOffset; //temp container
|
||||
int pFlags; //xash flags
|
||||
BOOL m_physinit; //physics initializator
|
||||
|
||||
virtual void SetParent ( void ) { SetParent(m_iParent); }
|
||||
void SetParent ( int m_iNewParent, int m_iAttachment = 0 );
|
||||
void SetParent ( CBaseEntity* pParent, int m_iAttachment = 0 );
|
||||
void ResetParent( void );
|
||||
|
||||
virtual void SetupPhysics( void );//setup parent system and physics
|
||||
|
||||
CBaseEntity *m_pParent; //pointer to parent entity
|
||||
CBaseEntity *m_pChild; //pointer to children(may be this)
|
||||
CBaseEntity *m_pNextChild; //link to next chlidren
|
||||
CBaseEntity *m_pLinkList; //list of linked childrens
|
||||
|
||||
string_t m_iParent;//name of parent
|
||||
virtual void SetNextThink( float delay, BOOL correctSpeed = FALSE );
|
||||
virtual void AbsoluteNextThink( float time, BOOL correctSpeed = FALSE );
|
||||
void SetEternalThink( void );
|
||||
void DontThink( void );
|
||||
virtual void ThinkCorrection( void );
|
||||
|
||||
//phys metods
|
||||
virtual void SetAngularImpulse( float impulse ){}
|
||||
virtual void SetLinearImpulse( float impulse ) {}
|
||||
|
||||
// initialization functions
|
||||
virtual void Spawn( void ) { return; }
|
||||
virtual void Precache( void ) { return; }
|
||||
virtual void KeyValue( KeyValueData* pkvd)
|
||||
{
|
||||
if (FStrEq(pkvd->szKeyName, "parent"))
|
||||
{
|
||||
m_iParent = ALLOC_STRING(pkvd->szValue);
|
||||
pkvd->fHandled = TRUE;
|
||||
}
|
||||
else if (FStrEq(pkvd->szKeyName, "style"))
|
||||
{
|
||||
m_iStyle = atoi(pkvd->szValue);
|
||||
pkvd->fHandled = TRUE;
|
||||
}
|
||||
else pkvd->fHandled = FALSE;
|
||||
}
|
||||
virtual int Save( CSave &save );
|
||||
virtual int Restore( CRestore &restore );
|
||||
virtual int ObjectCaps( void ) { return m_pParent?m_pParent->ObjectCaps()&FCAP_ACROSS_TRANSITION:FCAP_ACROSS_TRANSITION; }
|
||||
virtual void Activate( void ) {}
|
||||
virtual void PostActivate( void ) {}
|
||||
virtual void PostSpawn( void ) {}
|
||||
virtual void DesiredAction( void ) {}
|
||||
virtual void StartMessage( CBasePlayer *pPlayer ) {}
|
||||
|
||||
// Setup the object->object collision box (pev->mins / pev->maxs is the object->world collision box)
|
||||
virtual void SetObjectCollisionBox( void );
|
||||
|
||||
void UTIL_AutoSetSize( void )//automatically set collision box
|
||||
{
|
||||
dstudiohdr_t *pstudiohdr;
|
||||
pstudiohdr = (dstudiohdr_t*)GET_MODEL_PTR( ENT(pev) );
|
||||
|
||||
if (pstudiohdr == NULL)
|
||||
{
|
||||
ALERT(at_console,"Unable to fetch model pointer!\n");
|
||||
return;
|
||||
}
|
||||
dstudioseqdesc_t *pseqdesc;
|
||||
pseqdesc = (dstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex);
|
||||
UTIL_SetSize(pev,pseqdesc[ pev->sequence ].bbmin,pseqdesc[ pev->sequence ].bbmax);
|
||||
}
|
||||
|
||||
// Classify - returns the type of group (e.g., "alien monster", or "human military" so that monsters
|
||||
// on the same side won't attack each other, even if they have different classnames.
|
||||
virtual int Classify ( void ) { return CLASS_NONE; };
|
||||
virtual void DeathNotice ( entvars_t *pevChild ) {}// monster maker children use this to tell the monster maker that they have died.
|
||||
|
||||
|
||||
// global concept of "entities with states", so that state_watchers and
|
||||
// mastership (mastery? masterhood?) can work universally.
|
||||
virtual STATE GetState ( void ) { return STATE_OFF; };
|
||||
|
||||
// For team-specific doors in multiplayer, etc: a master's state depends on who wants to know.
|
||||
virtual STATE GetState ( CBaseEntity* pEnt ) { return GetState(); };
|
||||
|
||||
static TYPEDESCRIPTION m_SaveData[];
|
||||
|
||||
virtual void ClearPointers( void );
|
||||
virtual void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType);
|
||||
virtual int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType );
|
||||
virtual int TakeHealth( float flHealth, int bitsDamageType );
|
||||
virtual int TakeArmor( float flArmor, int suit = 0 );
|
||||
virtual int TakeItem( int iItem ) { return 0; }
|
||||
virtual void Killed( entvars_t *pevAttacker, int iGib );
|
||||
virtual int BloodColor( void ) { return DONT_BLEED; }
|
||||
virtual void TraceBleed( float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType );
|
||||
virtual CBaseMonster *MyMonsterPointer( void ) { return NULL;}
|
||||
virtual CSquadMonster *MySquadMonsterPointer( void ) { return NULL;}
|
||||
virtual CBaseBrush *MyBrushPointer( void ) { return NULL; }
|
||||
virtual void AddPoints( int score, BOOL bAllowNegativeScore ) {}
|
||||
virtual void AddPointsToTeam( int score, BOOL bAllowNegativeScore ) {}
|
||||
virtual BOOL AddPlayerItem( CBasePlayerWeapon *pItem ) { return 0; }
|
||||
virtual BOOL RemovePlayerItem( CBasePlayerWeapon *pItem ) { return 0; }
|
||||
virtual int GiveAmmo( int iAmount, char *szName, int iMax ) { return -1; };
|
||||
virtual float GetDelay( void ) { return 0; }
|
||||
virtual int IsMoving( void ) { return pev->velocity != g_vecZero; }
|
||||
virtual void RestorePhysics( void );
|
||||
virtual void OverrideReset( void ) {}
|
||||
virtual int DamageDecal( int bitsDamageType );
|
||||
// This is ONLY used by the node graph to test movement through a door
|
||||
virtual void SetToggleState( int state ) {}
|
||||
virtual void StartSneaking( void ) {}
|
||||
virtual void StopSneaking( void ) {}
|
||||
virtual BOOL OnControls( entvars_t *pev ) { return FALSE; }
|
||||
virtual BOOL IsSneaking( void ) { return FALSE; }
|
||||
virtual BOOL IsAlive( void ) { return (pev->deadflag == DEAD_NO) && pev->health > 0; }
|
||||
virtual BOOL IsBSPModel( void ) { return pev->solid == SOLID_BSP || pev->movetype == MOVETYPE_PUSHSTEP; }
|
||||
virtual BOOL ReflectGauss( void ) { return ( IsBSPModel() && !pev->takedamage ); }
|
||||
virtual BOOL HasTarget( string_t targetname ) { return FStrEq(STRING(targetname), STRING(pev->targetname) ); }
|
||||
virtual BOOL IsInWorld( void );
|
||||
virtual BOOL IsPlayer( void ) { return FALSE; }
|
||||
virtual BOOL IsPushable( void ) { return FALSE; }
|
||||
virtual BOOL IsMonster( void ) { return (pev->flags & FL_MONSTER ? TRUE : FALSE); }
|
||||
virtual BOOL IsNetClient( void ) { return FALSE; }
|
||||
virtual BOOL IsFuncScreen( void ) { return FALSE; }
|
||||
virtual const char *TeamID( void ) { return ""; }
|
||||
|
||||
virtual CBaseEntity *GetNext( void ) { return NULL; }
|
||||
virtual CBaseEntity *GetPrev( void ) { return NULL; }
|
||||
|
||||
// fundamental callbacks
|
||||
void (CBaseEntity ::*m_pfnThink)(void);
|
||||
void (CBaseEntity ::*m_pfnTouch)( CBaseEntity *pOther );
|
||||
void (CBaseEntity ::*m_pfnUse)( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
||||
void (CBaseEntity ::*m_pfnBlocked)( CBaseEntity *pOther );
|
||||
|
||||
virtual void Think( void ) { if (m_pfnThink) (this->*m_pfnThink)(); };
|
||||
virtual void Touch( CBaseEntity *pOther ) { if (m_pfnTouch) (this->*m_pfnTouch)( pOther ); };
|
||||
virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
||||
{
|
||||
if (m_pfnUse) (this->*m_pfnUse)( pActivator, pCaller, useType, value );
|
||||
}
|
||||
virtual void Blocked( CBaseEntity *pOther ) { if (m_pfnBlocked) (this->*m_pfnBlocked)( pOther ); };
|
||||
|
||||
// allow engine to allocate instance data
|
||||
void *operator new( size_t stAllocateBlock, entvars_t *pev )
|
||||
{
|
||||
return (void *)ALLOC_PRIVATE(ENT(pev), stAllocateBlock);
|
||||
};
|
||||
|
||||
// don't use this.
|
||||
#if _MSC_VER >= 1200 // only build this code if MSVC++ 6.0 or higher
|
||||
void operator delete(void *pMem, entvars_t *pev)
|
||||
{
|
||||
pev->flags |= FL_KILLME;
|
||||
};
|
||||
#endif
|
||||
|
||||
void UpdateOnRemove( void );
|
||||
|
||||
// common member functions
|
||||
void EXPORT Remove( void );
|
||||
void EXPORT Fadeout( void );
|
||||
void EXPORT PVSRemove( void );
|
||||
void EXPORT SUB_CallUseToggle( void ) { this->Use( this, this, USE_TOGGLE, 0 ); }
|
||||
|
||||
void FireBullets( ULONG cShots, Vector vecSrc, Vector vecDirShooting, Vector vecSpread, float flDistance, int iBulletType, int iTracerFreq = 4, int iDamage = 0, entvars_t *pevAttacker = NULL );
|
||||
|
||||
virtual CBaseEntity *Respawn( void ) { return NULL; }
|
||||
|
||||
// Do the bounding boxes of these two intersect?
|
||||
int Intersects( CBaseEntity *pOther );
|
||||
void MakeDormant( void );
|
||||
int IsDormant( void );
|
||||
BOOL IsLockedByMaster( void ) { return FALSE; }
|
||||
|
||||
static CBaseEntity *Instance( edict_t *pent )
|
||||
{
|
||||
if ( !pent ) pent = ENT(0);
|
||||
CBaseEntity *pEnt = (CBaseEntity *)GET_PRIVATE(pent);
|
||||
return pEnt;
|
||||
}
|
||||
|
||||
static CBaseEntity *Instance( entvars_t *pev ) { return Instance( ENT( pev ) ); }
|
||||
static CBaseEntity *Instance( int eoffset) { return Instance( ENT( eoffset) ); }
|
||||
|
||||
CBaseMonster *GetMonsterPointer( entvars_t *pevMonster )
|
||||
{
|
||||
CBaseEntity *pEntity = Instance( pevMonster );
|
||||
if ( pEntity ) return pEntity->MyMonsterPointer();
|
||||
return NULL;
|
||||
}
|
||||
CBaseMonster *GetMonsterPointer( edict_t *pentMonster )
|
||||
{
|
||||
CBaseEntity *pEntity = Instance( pentMonster );
|
||||
if ( pEntity ) return pEntity->MyMonsterPointer();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// Ugly code to lookup all functions to make sure they are exported when set.
|
||||
#ifdef _DEBUG
|
||||
void FunctionCheck( void *pFunction, char *name )
|
||||
{
|
||||
if (pFunction && !NAME_FOR_FUNCTION((unsigned long)(pFunction)) )
|
||||
ALERT( at_error, "No EXPORT: %s:%s (%08lx)\n", STRING(pev->classname), name, (unsigned long)pFunction );
|
||||
}
|
||||
|
||||
BASEPTR ThinkSet( BASEPTR func, char *name )
|
||||
{
|
||||
m_pfnThink = func;
|
||||
FunctionCheck( (void *)*((int *)((char *)this + ( offsetof(CBaseEntity,m_pfnThink)))), name );
|
||||
return func;
|
||||
}
|
||||
ENTITYFUNCPTR TouchSet( ENTITYFUNCPTR func, char *name )
|
||||
{
|
||||
m_pfnTouch = func;
|
||||
FunctionCheck( (void *)*((int *)((char *)this + ( offsetof(CBaseEntity,m_pfnTouch)))), name );
|
||||
return func;
|
||||
}
|
||||
USEPTR UseSet( USEPTR func, char *name )
|
||||
{
|
||||
m_pfnUse = func;
|
||||
FunctionCheck( (void *)*((int *)((char *)this + ( offsetof(CBaseEntity,m_pfnUse)))), name );
|
||||
return func;
|
||||
}
|
||||
ENTITYFUNCPTR BlockedSet( ENTITYFUNCPTR func, char *name )
|
||||
{
|
||||
m_pfnBlocked = func;
|
||||
FunctionCheck( (void *)*((int *)((char *)this + ( offsetof(CBaseEntity,m_pfnBlocked)))), name );
|
||||
return func;
|
||||
}
|
||||
|
||||
#endif
|
||||
// used by monsters that are created by the MonsterMaker
|
||||
virtual void UpdateOwner( void ) { return; };
|
||||
static CBaseEntity *Create( char *szName, const Vector &vecOrigin, const Vector &vecAngles, edict_t *pentOwner = NULL );
|
||||
static CBaseEntity *CBaseEntity::CreateGib( char *szName, char *szModel );
|
||||
|
||||
virtual BOOL FBecomeProne( void ) {return FALSE;};
|
||||
edict_t *edict() { return ENT( pev ); };
|
||||
EOFFSET eoffset( ) { return OFFSET( pev ); };
|
||||
int entindex( ) { return ENTINDEX( edict() ); };
|
||||
|
||||
virtual Vector Center( ) { return (pev->absmax + pev->absmin) * 0.5; }; // center point of entity
|
||||
virtual Vector EyePosition( ) { return pev->origin + pev->view_ofs; }; // position of eyes
|
||||
virtual Vector EarPosition( ) { return pev->origin + pev->view_ofs; }; // position of ears
|
||||
virtual Vector BodyTarget( const Vector &posSrc ) { return Center( ); }; // position to shoot at
|
||||
|
||||
virtual int Illumination( ) { return GETENTITYILLUM( ENT( pev ) ); };
|
||||
|
||||
virtual BOOL FVisible ( CBaseEntity *pEntity );
|
||||
virtual BOOL FVisible ( const Vector &vecOrigin );
|
||||
};
|
||||
|
||||
inline void CBaseEntity::SetModelIndex( int index )
|
||||
{
|
||||
pev->modelindex = index;
|
||||
}
|
||||
|
||||
inline int CBaseEntity::GetModelIndex( void ) const
|
||||
{
|
||||
return pev->modelindex;
|
||||
}
|
||||
|
||||
#endif //BASEENTITY_H
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,229 @@
|
|||
//=======================================================================
|
||||
// Copyright (C) Shambler Team 2004
|
||||
// baseinfo.cpp - point info entities.
|
||||
// e.g. info_target
|
||||
//=======================================================================
|
||||
|
||||
#include "extdll.h"
|
||||
#include "utils.h"
|
||||
#include "cbase.h"
|
||||
#include "player.h"
|
||||
|
||||
//=======================================================================
|
||||
// info_target (target entity)
|
||||
//=======================================================================
|
||||
|
||||
class CInfoTarget : public CPointEntity
|
||||
{
|
||||
public:
|
||||
void Spawn( void )
|
||||
{
|
||||
pev->solid = SOLID_NOT;
|
||||
UTIL_SetModel(ENT(pev),"models/common/null.mdl");
|
||||
UTIL_SetSize(pev, g_vecZero, g_vecZero);
|
||||
SetBits( pev->flags, FL_POINTENTITY );
|
||||
}
|
||||
};
|
||||
|
||||
void CBaseDMStart::KeyValue( KeyValueData *pkvd )
|
||||
{
|
||||
if (FStrEq(pkvd->szKeyName, "master"))
|
||||
{
|
||||
pev->netname = ALLOC_STRING(pkvd->szValue);
|
||||
pkvd->fHandled = TRUE;
|
||||
}
|
||||
else
|
||||
CPointEntity::KeyValue( pkvd );
|
||||
}
|
||||
|
||||
STATE CBaseDMStart::GetState( CBaseEntity *pEntity )
|
||||
{
|
||||
if (UTIL_IsMasterTriggered( pev->netname, pEntity ))
|
||||
return STATE_ON;
|
||||
else return STATE_OFF;
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
// static infodecal
|
||||
//=========================================================
|
||||
class CDecal : public CBaseEntity
|
||||
{
|
||||
public:
|
||||
void KeyValue( KeyValueData *pkvd )
|
||||
{
|
||||
if (FStrEq(pkvd->szKeyName, "texture"))
|
||||
{
|
||||
pev->skin = DECAL_INDEX( pkvd->szValue );
|
||||
if ( pev->skin >= 0 ) return;
|
||||
Msg( "Can't find decal %s\n", pkvd->szValue );
|
||||
}
|
||||
}
|
||||
void PostSpawn( void ) { if(FStringNull(pev->targetname))MakeDecal(); }
|
||||
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { MakeDecal(); }
|
||||
void MakeDecal( void )
|
||||
{
|
||||
if ( pev->skin < 0 ) { REMOVE_ENTITY(ENT(pev)); return; }
|
||||
TraceResult trace;
|
||||
int entityIndex, modelIndex;
|
||||
UTIL_TraceLine( pev->origin - Vector(5,5,5), pev->origin + Vector(5,5,5), ignore_monsters, ENT(pev), &trace );
|
||||
entityIndex = (short)ENTINDEX(trace.pHit);
|
||||
if ( entityIndex ) modelIndex = (int)VARS(trace.pHit)->modelindex;
|
||||
else modelIndex = 0;
|
||||
|
||||
if(FStringNull(pev->targetname)) g_engfuncs.pfnStaticDecal( pev->origin, (int)pev->skin, entityIndex, modelIndex );
|
||||
else
|
||||
{
|
||||
MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY);
|
||||
WRITE_BYTE( TE_BSPDECAL );
|
||||
WRITE_COORD( pev->origin.x );
|
||||
WRITE_COORD( pev->origin.y );
|
||||
WRITE_COORD( pev->origin.z );
|
||||
WRITE_SHORT( (int)pev->skin );
|
||||
WRITE_SHORT( entityIndex );
|
||||
if(entityIndex) WRITE_SHORT( modelIndex );
|
||||
MESSAGE_END();
|
||||
}
|
||||
|
||||
SetThink( Remove );
|
||||
SetNextThink( 0.3 );
|
||||
}
|
||||
};
|
||||
|
||||
//=========================================================
|
||||
// Multiplayer intermission spots.
|
||||
//=========================================================
|
||||
class CInfoIntermission:public CPointEntity
|
||||
{
|
||||
void Spawn( void );
|
||||
void Think( void );
|
||||
void PostActivate( void );
|
||||
CBaseEntity *pTarget;
|
||||
};
|
||||
|
||||
void CInfoIntermission::Spawn( void )
|
||||
{
|
||||
pev->solid = SOLID_NOT;
|
||||
pev->movetype = MOVETYPE_NOCLIP;
|
||||
UTIL_SetOrigin( this, pev->origin );
|
||||
UTIL_SetModel( ENT( pev ), "sprites/null.spr" );
|
||||
|
||||
SetNextThink( 1 );// let targets spawn!
|
||||
}
|
||||
|
||||
void CInfoIntermission::PostActivate( void )
|
||||
{
|
||||
pTarget = UTIL_FindEntityByTargetname( NULL, STRING( pev->target ));
|
||||
if( !pev->speed ) pev->speed = 100;
|
||||
}
|
||||
|
||||
void CInfoIntermission::Think ( void )
|
||||
{
|
||||
if( pTarget )
|
||||
{
|
||||
UTIL_WatchTarget( this, pTarget );
|
||||
SetNextThink( 0 );
|
||||
}
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// multisource
|
||||
//====================================================================
|
||||
|
||||
TYPEDESCRIPTION CMultiSource::m_SaveData[] =
|
||||
{
|
||||
DEFINE_ARRAY( CMultiSource, m_rgEntities, FIELD_EHANDLE, MAX_MULTI_TARGETS ),
|
||||
DEFINE_ARRAY( CMultiSource, m_rgTriggered, FIELD_INTEGER, MAX_MULTI_TARGETS ),
|
||||
DEFINE_FIELD( CMultiSource, m_iTotal, FIELD_INTEGER ),
|
||||
}; IMPLEMENT_SAVERESTORE( CMultiSource, CBaseLogic );
|
||||
LINK_ENTITY_TO_CLASS( multisource, CMultiSource );
|
||||
|
||||
void CMultiSource::Spawn()
|
||||
{
|
||||
pev->solid = SOLID_NOT;
|
||||
pev->movetype = MOVETYPE_NONE;
|
||||
SetNextThink( 0.1 );
|
||||
pev->spawnflags |= SF_START_ON;
|
||||
SetThink( Register );
|
||||
}
|
||||
|
||||
void CMultiSource::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
// Find the entity in our list
|
||||
while (i < m_iTotal) if ( m_rgEntities[i++] == pCaller ) break;
|
||||
|
||||
// if we didn't find it, report error and leave
|
||||
if (i > m_iTotal) return;
|
||||
|
||||
STATE s = GetState();
|
||||
m_rgTriggered[i-1] ^= 1;
|
||||
if ( s == GetState()) return;
|
||||
|
||||
if ( s == STATE_OFF )
|
||||
{
|
||||
USE_TYPE useType = USE_TOGGLE;
|
||||
if ( m_globalstate ) useType = USE_ON;
|
||||
UTIL_FireTargets( pev->target, NULL, this, useType, value );
|
||||
UTIL_FireTargets( m_iszKillTarget, NULL, this, USE_REMOVE );
|
||||
}
|
||||
}
|
||||
|
||||
STATE CMultiSource::GetState( void )
|
||||
{
|
||||
// Is everything triggered?
|
||||
int i = 0;
|
||||
|
||||
// Still initializing?
|
||||
if ( pev->spawnflags & SF_START_ON ) return STATE_OFF;
|
||||
|
||||
while (i < m_iTotal)
|
||||
{
|
||||
if (m_rgTriggered[i] == 0) break;
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i == m_iTotal)
|
||||
{
|
||||
if ( !m_globalstate || gGlobalState.EntityGetState( m_globalstate ) == GLOBAL_ON )
|
||||
return STATE_ON;
|
||||
}
|
||||
return STATE_OFF;
|
||||
}
|
||||
|
||||
void CMultiSource::Register(void)
|
||||
{
|
||||
m_iTotal = 0;
|
||||
memset( m_rgEntities, 0, MAX_MULTI_TARGETS * sizeof(EHANDLE) );
|
||||
|
||||
SetThink(NULL);
|
||||
|
||||
// search for all entities which target this multisource (pev->targetname)
|
||||
|
||||
CBaseEntity *pTarget = UTIL_FindEntityByTarget( NULL, STRING(pev->targetname) );
|
||||
while (pTarget && (m_iTotal < MAX_MULTI_TARGETS))
|
||||
{
|
||||
m_rgEntities[m_iTotal++] = pTarget;
|
||||
pTarget = UTIL_FindEntityByTarget( pTarget, STRING(pev->targetname));
|
||||
}
|
||||
|
||||
pTarget = UTIL_FindEntityByClassname(NULL, "multi_manager");
|
||||
while (pTarget && (m_iTotal < MAX_MULTI_TARGETS))
|
||||
{
|
||||
if ( pTarget->HasTarget(pev->targetname) ) m_rgEntities[m_iTotal++] = pTarget;
|
||||
pTarget = UTIL_FindEntityByClassname( pTarget, "multi_manager" );
|
||||
}
|
||||
pev->spawnflags &= ~SF_START_ON;
|
||||
}
|
||||
|
||||
|
||||
LINK_ENTITY_TO_CLASS( infodecal, CDecal );
|
||||
LINK_ENTITY_TO_CLASS( info_target, CInfoTarget );
|
||||
LINK_ENTITY_TO_CLASS( info_teleport_destination, CPointEntity );
|
||||
LINK_ENTITY_TO_CLASS( info_null, CNullEntity);
|
||||
LINK_ENTITY_TO_CLASS( info_texlights, CNullEntity);
|
||||
LINK_ENTITY_TO_CLASS( info_compile_parameters, CNullEntity);
|
||||
LINK_ENTITY_TO_CLASS( info_intermission, CInfoIntermission );
|
||||
LINK_ENTITY_TO_CLASS( info_player_deathmatch, CBaseDMStart);
|
||||
LINK_ENTITY_TO_CLASS( info_player_start, CPointEntity);
|
||||
LINK_ENTITY_TO_CLASS( info_landmark, CPointEntity);
|
|
@ -0,0 +1,44 @@
|
|||
//=======================================================================
|
||||
// Copyright (C) XashXT Group 2006
|
||||
//=======================================================================
|
||||
|
||||
#ifndef BASEINFO_H
|
||||
#define BASEINFO_H
|
||||
|
||||
class CPointEntity : public CBaseEntity
|
||||
{
|
||||
public:
|
||||
void Spawn( void ){ pev->solid = SOLID_NOT; }
|
||||
virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }
|
||||
};
|
||||
|
||||
class CNullEntity : public CBaseEntity
|
||||
{
|
||||
public:
|
||||
void Spawn( void ){ REMOVE_ENTITY(ENT(pev)); }
|
||||
};
|
||||
|
||||
class CBaseDMStart : public CPointEntity
|
||||
{
|
||||
public:
|
||||
void KeyValue( KeyValueData *pkvd );
|
||||
STATE GetState( CBaseEntity *pEntity );
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
class CLaserSpot : public CBaseEntity//laser spot for different weapons
|
||||
{
|
||||
void Spawn( void );
|
||||
void Precache( void );
|
||||
int ObjectCaps( void ) { return FCAP_DONT_SAVE; }
|
||||
public:
|
||||
void Suspend( float flSuspendTime );
|
||||
void Update( CBasePlayer *m_pPlayer );
|
||||
void EXPORT Revive( void );
|
||||
void Killed( void ){ UTIL_Remove( this ); }
|
||||
|
||||
static CLaserSpot *CreateSpot( void );
|
||||
};
|
||||
|
||||
#endif //BASEINFO_H
|
|
@ -0,0 +1,628 @@
|
|||
//=======================================================================
|
||||
// Copyright (C) Shambler Team 2004
|
||||
// item_.cpp - items entities: suit,
|
||||
// helmet, lighter, etc
|
||||
//=======================================================================
|
||||
|
||||
#include "extdll.h"
|
||||
#include "utils.h"
|
||||
#include "cbase.h"
|
||||
#include "saverestore.h"
|
||||
#include "baseweapon.h"
|
||||
#include "player.h"
|
||||
#include "gamerules.h"
|
||||
#include "defaults.h"
|
||||
|
||||
extern int gEvilImpulse101;
|
||||
extern int gmsgItemPickup;
|
||||
|
||||
//***********************************************************
|
||||
// main functions ()
|
||||
//***********************************************************
|
||||
|
||||
void CItem::Spawn( void )
|
||||
{
|
||||
Precache();
|
||||
pev->movetype = MOVETYPE_TOSS;
|
||||
pev->solid = SOLID_BBOX;
|
||||
|
||||
UTIL_SetOrigin( this, pev->origin );
|
||||
UTIL_SetSize(pev, g_vecZero, g_vecZero );
|
||||
|
||||
SetTouch( ItemTouch );
|
||||
SetThink( ItemFall );
|
||||
|
||||
UTIL_SetModel(ENT(pev), pev->model, (char *)Model() );
|
||||
SetNextThink( 0.1 );
|
||||
}
|
||||
|
||||
void CItem::Precache( void )
|
||||
{
|
||||
UTIL_PrecacheModel( pev->model, (char *)Model() );
|
||||
UTIL_PrecacheSound((char *)PickSound());
|
||||
UTIL_PrecacheSound((char *)FallSound());
|
||||
}
|
||||
|
||||
void CItem::ItemTouch( CBaseEntity *pOther )
|
||||
{
|
||||
//removed this limitation for monsters
|
||||
if ( !pOther->IsPlayer() ) return;
|
||||
CBasePlayer *pPlayer = (CBasePlayer *)pOther;
|
||||
if (!UTIL_IsMasterTriggered(m_sMaster, pPlayer)) return;
|
||||
if (pPlayer->pev->deadflag != DEAD_NO) return;
|
||||
|
||||
if (AddItem( pPlayer ))
|
||||
{
|
||||
UTIL_FireTargets( pev->target, pOther, this, USE_TOGGLE );
|
||||
SetTouch( NULL );
|
||||
|
||||
if (IsItem() && gmsgItemPickup)
|
||||
{
|
||||
//show icon for item
|
||||
MESSAGE_BEGIN( MSG_ONE, gmsgItemPickup, NULL, pPlayer->pev );
|
||||
WRITE_STRING( STRING(pev->classname) );
|
||||
MESSAGE_END();
|
||||
}
|
||||
|
||||
//play pickup sound
|
||||
EMIT_SOUND( pPlayer->edict(), CHAN_ITEM, (char *)PickSound(), 1, ATTN_NORM );
|
||||
|
||||
// tell the owner item was taken
|
||||
if (!FNullEnt( pev->owner )) pev->owner->v.impulse = 0;
|
||||
|
||||
//enable respawn in multiplayer
|
||||
if ( g_pGameRules->IsMultiplayer()) Respawn();
|
||||
else UTIL_Remove( this );
|
||||
}
|
||||
else if (gEvilImpulse101) UTIL_Remove( this );
|
||||
}
|
||||
|
||||
void CItem::ItemFall ( void )
|
||||
{
|
||||
SetNextThink( 0.1 );
|
||||
|
||||
if ( pev->flags & FL_ONGROUND )
|
||||
{
|
||||
// clatter if we have an owner (i.e., dropped by someone)
|
||||
// don't clatter if the item is waiting to respawn (if it's waiting, it is invisible!)
|
||||
if ( !FNullEnt( pev->owner ))
|
||||
{
|
||||
EMIT_SOUND(ENT(pev), CHAN_ITEM, (char *)FallSound(), 1, ATTN_NORM);
|
||||
ItemOnGround(); //do somewhat if needed
|
||||
}
|
||||
|
||||
// lie flat
|
||||
pev->angles.x = 0;
|
||||
pev->angles.z = 0;
|
||||
|
||||
pev->solid = SOLID_TRIGGER;
|
||||
|
||||
if (IsAmmo()) UTIL_SetSize(pev, Vector(-8, -8, -8), Vector(8, 8, 8));
|
||||
if (IsItem()) UTIL_SetSize ( pev, Vector ( -8, -8, 0 ), Vector ( 8, 8, 8 ) );
|
||||
else UTIL_AutoSetSize();
|
||||
|
||||
UTIL_SetOrigin( this, pev->origin );// link into world.
|
||||
|
||||
SetTouch( ItemTouch );
|
||||
SetThink (NULL);
|
||||
}
|
||||
}
|
||||
|
||||
CBaseEntity* CItem::Respawn( void )
|
||||
{
|
||||
SetTouch( NULL );
|
||||
pev->effects |= EF_NODRAW;
|
||||
|
||||
SetThink( Materialize );
|
||||
AbsoluteNextThink( ItemRespawnTime( this ) );
|
||||
return this;
|
||||
}
|
||||
|
||||
float CItem::ItemRespawnTime( CItem *pItem )
|
||||
{
|
||||
//makes different time to respawn for weapons and items
|
||||
float flRespawnTime;
|
||||
|
||||
if (IsAmmo()) flRespawnTime = RESPAWN_TIME_30SEC;
|
||||
if (IsItem()) flRespawnTime = RESPAWN_TIME_120SEC;
|
||||
return gpGlobals->time + flRespawnTime;
|
||||
}
|
||||
|
||||
|
||||
void CItem::Materialize( void )
|
||||
{
|
||||
if ( pev->effects & EF_NODRAW )
|
||||
{
|
||||
// changing from invisible state to visible.
|
||||
pev->effects &= ~EF_NODRAW;
|
||||
pev->renderfx = kRenderFxGlowShell;
|
||||
pev->renderamt = 40;
|
||||
pev->frags = 0;
|
||||
pev->rendercolor.x = RANDOM_LONG(25, 255);
|
||||
pev->rendercolor.y = RANDOM_LONG(25, 255);
|
||||
pev->rendercolor.z = RANDOM_LONG(25, 255);
|
||||
pev->scale = 0.01;
|
||||
SetNextThink (0.001);
|
||||
}
|
||||
if( pev->scale > 1.2 ) pev->frags = 1;
|
||||
if ( pev->frags == 1 )
|
||||
{ //set effects for respawn item
|
||||
if(pev->scale > 1.0) pev->scale -= 0.05;
|
||||
else
|
||||
{
|
||||
pev->renderfx = kRenderFxNone;
|
||||
pev->frags = 0;
|
||||
SetTouch( ItemTouch );
|
||||
EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "items/respawn.wav", 1, ATTN_NORM, 0, 150 );
|
||||
SetThink( NULL );
|
||||
DontThink();
|
||||
}
|
||||
}
|
||||
else pev->scale += 0.05;
|
||||
SetNextThink (0.001);
|
||||
|
||||
}
|
||||
|
||||
//***********************************************************
|
||||
// generic item
|
||||
//***********************************************************
|
||||
class CGenericItem : public CItem
|
||||
{
|
||||
const char *Model( void ){ return "models/w_adrenaline.mdl"; }
|
||||
BOOL AddItem( CBaseEntity *pOther )
|
||||
{
|
||||
CBasePlayer *pPlayer = (CBasePlayer *)pOther;
|
||||
if (pPlayer->pev->deadflag != DEAD_NO) return FALSE;
|
||||
if (pOther->GiveAmmo( AMMO_GLOCKCLIP_GIVE, "9mm", _9MM_MAX_CARRY ) != -1)
|
||||
{
|
||||
EMIT_SOUND(ENT(pev), CHAN_ITEM, "weapons/glock/clip_in.wav", 1, ATTN_NORM);
|
||||
return TRUE;
|
||||
}
|
||||
MESSAGE_BEGIN( MSG_ONE, gmsgItemPickup, NULL, pPlayer->pev );
|
||||
WRITE_STRING( STRING(pev->classname) );
|
||||
MESSAGE_END();
|
||||
return FALSE;
|
||||
}
|
||||
};
|
||||
LINK_ENTITY_TO_CLASS( item_generic, CGenericItem );
|
||||
|
||||
//***********************************************************
|
||||
// items
|
||||
//***********************************************************
|
||||
class CItemSuit : public CItem
|
||||
{
|
||||
const char *Model( void ){ return "models/w_suit.mdl"; }
|
||||
BOOL AddItem( CBaseEntity *pOther )
|
||||
{
|
||||
CBasePlayer *pPlayer = (CBasePlayer *)pOther;
|
||||
if ( pPlayer->pev->deadflag != DEAD_NO ) return FALSE;
|
||||
|
||||
if ( pPlayer->m_iHideHUD & ITEM_SUIT )
|
||||
return FALSE;
|
||||
|
||||
if ( pev->spawnflags & 1 )//SF_SUIT_SHORTLOGON
|
||||
EMIT_SOUND_SUIT(pPlayer->edict(), "!HEV_A0"); // short version of suit logon,
|
||||
else EMIT_SOUND_SUIT(pPlayer->edict(), "!HEV_AAx"); // long version of suit logon
|
||||
|
||||
pPlayer->m_iHideHUD |= ITEM_SUIT;
|
||||
return TRUE;
|
||||
}
|
||||
};
|
||||
LINK_ENTITY_TO_CLASS(item_suit, CItemSuit);
|
||||
|
||||
class CItemLongJump : public CItem
|
||||
{
|
||||
const char *Model( void ){ return "models/w_longjump.mdl"; }
|
||||
const char *PickSound( void ){ return "buttons/bell1.wav"; }
|
||||
BOOL AddItem( CBaseEntity *pOther )
|
||||
{
|
||||
CBasePlayer *pPlayer = (CBasePlayer *)pOther;
|
||||
if ( pPlayer->m_iHideHUD & ITEM_SUIT && !pPlayer->m_fLongJump)
|
||||
{
|
||||
pPlayer->m_fLongJump = TRUE;// player now has longjump module
|
||||
EMIT_SOUND_SUIT( pPlayer->edict(), "!HEV_A1" );
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
};
|
||||
LINK_ENTITY_TO_CLASS( item_longjump, CItemLongJump );
|
||||
|
||||
|
||||
class CItemBattery : public CItem
|
||||
{
|
||||
const char *Model( void ){ return "models/w_battery.mdl"; }
|
||||
const char *PickSound( void ){ return "items/gunpickup2.wav"; }
|
||||
BOOL AddItem( CBaseEntity *pOther ) { return pOther->TakeArmor( BATTERY_CHARGE, TRUE ); }
|
||||
};
|
||||
LINK_ENTITY_TO_CLASS(item_battery, CItemBattery);
|
||||
|
||||
class CHealthKit : public CItem
|
||||
{
|
||||
const char *Model( void ){ return "models/items/w_medkit.mdl"; }
|
||||
const char *PickSound( void ){ return "items/smallmedkit1.wav"; }
|
||||
BOOL AddItem( CBaseEntity *pOther ) { return pOther->TakeHealth( MEDKIT_CAP, DMG_GENERIC ); }
|
||||
};
|
||||
LINK_ENTITY_TO_CLASS( item_healthkit, CHealthKit );
|
||||
|
||||
class CItemSoda : public CItem
|
||||
{
|
||||
public:
|
||||
const char *Model( void ){ return "models/can.mdl"; }
|
||||
const char *FallSound( void ){ return "weapons/g_bounce3.wav"; }
|
||||
BOOL AddItem( CBaseEntity *pOther ) { pOther->TakeHealth( pev->skin * 1, DMG_GENERIC ); return 1; }
|
||||
};
|
||||
LINK_ENTITY_TO_CLASS( item_sodacan, CItemSoda );
|
||||
|
||||
class CItemSecurity : public CItem
|
||||
{
|
||||
const char *Model( void ){ return "models/w_security.mdl"; }
|
||||
const char *PickSound( void ){ return "items/gunpickup2.wav"; }
|
||||
BOOL AddItem( CBaseEntity *pOther ) { return TRUE; }
|
||||
};
|
||||
LINK_ENTITY_TO_CLASS(item_security, CItemSecurity);
|
||||
|
||||
class CItemArmorVest : public CItem
|
||||
{
|
||||
const char *Model( void ){ return "models/w_vest.mdl"; }
|
||||
const char *PickSound( void ){ return "items/gunpickup2.wav"; }
|
||||
BOOL AddItem( CBaseEntity *pOther ) { return pOther->TakeArmor( 60 ); }
|
||||
};
|
||||
LINK_ENTITY_TO_CLASS(item_armorvest, CItemArmorVest);
|
||||
|
||||
class CItemHelmet : public CItem
|
||||
{
|
||||
const char *Model( void ){ return "models/w_helmet.mdl"; }
|
||||
const char *PickSound( void ){ return "items/gunpickup2.wav"; }
|
||||
BOOL AddItem( CBaseEntity *pOther ) { return pOther->TakeArmor( 40 ); }
|
||||
};
|
||||
LINK_ENTITY_TO_CLASS(item_helmet, CItemHelmet);
|
||||
|
||||
//***********************************************************
|
||||
// ammo
|
||||
//***********************************************************
|
||||
class CGlockAmmo : public CItem
|
||||
{
|
||||
const char *Model( void ){ return "models/w_9mmclip.mdl"; }
|
||||
const char *PickSound( void ){ return "weapons/glock/clip_in.wav"; }
|
||||
BOOL AddItem( CBaseEntity *pOther ) { return pOther->GiveAmmo( AMMO_GLOCKCLIP_GIVE, "9mm", 250 ); }
|
||||
};
|
||||
LINK_ENTITY_TO_CLASS( ammo_9mmclip, CGlockAmmo );
|
||||
LINK_ENTITY_TO_CLASS( ammo_glockclip, CGlockAmmo );
|
||||
|
||||
class CPythonAmmo : public CItem
|
||||
{
|
||||
const char *Model( void ){ return "models/w_357ammobox.mdl"; }
|
||||
const char *PickSound( void ){ return "weapons/glock/clip_in.wav"; }
|
||||
BOOL AddItem( CBaseEntity *pOther ) { return pOther->GiveAmmo( AMMO_357BOX_GIVE, "357", 21 ); }
|
||||
};
|
||||
LINK_ENTITY_TO_CLASS( ammo_357, CPythonAmmo );
|
||||
|
||||
class CSniperAmmo : public CItem
|
||||
{
|
||||
const char *Model( void ){ return "models/w_m40a1clip.mdl"; }
|
||||
const char *PickSound( void ){ return "weapons/glock/clip_in.wav"; }
|
||||
BOOL AddItem( CBaseEntity *pOther ) { return pOther->GiveAmmo( AMMO_357BOX_GIVE, "762", 21 ); }
|
||||
};
|
||||
LINK_ENTITY_TO_CLASS( ammo_762, CSniperAmmo );
|
||||
|
||||
class CRpgAmmo : public CItem
|
||||
{
|
||||
const char *Model( void ){ return "models/w_rpgammo.mdl"; }
|
||||
const char *PickSound( void ){ return "weapons/glock/clip_in.wav"; }
|
||||
BOOL AddItem( CBaseEntity *pOther ) { return pOther->GiveAmmo( AMMO_RPGCLIP_GIVE, "rockets", 3 ); }
|
||||
};
|
||||
LINK_ENTITY_TO_CLASS( ammo_rpgclip, CRpgAmmo );
|
||||
|
||||
class CMP5AmmoClip : public CItem
|
||||
{
|
||||
const char *Model( void ){ return "models/w_9mmARclip.mdl"; }
|
||||
const char *PickSound( void ){ return "weapons/glock/clip_in.wav"; }
|
||||
BOOL AddItem( CBaseEntity *pOther ) { return pOther->GiveAmmo( AMMO_MP5CLIP_GIVE, "9mm", 250); }
|
||||
};
|
||||
LINK_ENTITY_TO_CLASS( ammo_9mmAR, CMP5AmmoClip );
|
||||
LINK_ENTITY_TO_CLASS( ammo_mp5clip, CMP5AmmoClip );
|
||||
|
||||
class CSawAmmo : public CItem
|
||||
{
|
||||
const char *Model( void ){ return "models/w_saw_clip.mdl"; }
|
||||
const char *PickSound( void ){ return "weapons/glock/clip_in.wav"; }
|
||||
BOOL AddItem( CBaseEntity *pOther ) { return pOther->GiveAmmo( AMMO_CHAINBOX_GIVE, "556", SAW_MAX_CLIP); }
|
||||
};
|
||||
LINK_ENTITY_TO_CLASS( ammo_556, CSawAmmo );
|
||||
|
||||
class CMP5AmmoGrenade : public CItem
|
||||
{
|
||||
const char *Model( void ){ return "models/w_ARgrenade.mdl"; }
|
||||
const char *PickSound( void ){ return "weapons/glock/clip_in.wav"; }
|
||||
BOOL AddItem( CBaseEntity *pOther ) { return pOther->GiveAmmo( AMMO_M203BOX_GIVE, "m203", 10 ); }
|
||||
};
|
||||
LINK_ENTITY_TO_CLASS( ammo_m203, CMP5AmmoGrenade );
|
||||
|
||||
class CGaussAmmo : public CItem
|
||||
{
|
||||
const char *Model( void ){ return "models/w_gaussammo.mdl"; }
|
||||
const char *PickSound( void ){ return "weapons/glock/clip_in.wav"; }
|
||||
BOOL AddItem( CBaseEntity *pOther ) { return pOther->GiveAmmo( AMMO_URANIUMBOX_GIVE, "uranium", 100 ); }
|
||||
};
|
||||
LINK_ENTITY_TO_CLASS( ammo_gaussclip, CGaussAmmo );
|
||||
|
||||
class CShotgunAmmoBox : public CItem
|
||||
{
|
||||
const char *Model( void ){ return "models/w_shotbox.mdl"; }
|
||||
const char *PickSound( void ){ return "weapons/glock/clip_in.wav"; }
|
||||
BOOL AddItem( CBaseEntity *pOther ) { return pOther->GiveAmmo( 12, "buckshot", 125 ); }
|
||||
};
|
||||
LINK_ENTITY_TO_CLASS( ammo_buckshot, CShotgunAmmoBox );
|
||||
|
||||
class CCrossbowAmmo : public CItem
|
||||
{
|
||||
const char *Model( void ){ return "models/w_crossbow_clip.mdl"; }
|
||||
const char *PickSound( void ){ return "weapons/glock/clip_in.wav"; }
|
||||
BOOL AddItem( CBaseEntity *pOther ) { return pOther->GiveAmmo( 5, "bolts", 50 ); }
|
||||
};
|
||||
LINK_ENTITY_TO_CLASS( ammo_crossbow, CCrossbowAmmo );
|
||||
|
||||
class CShotgunAmmoShell : public CItem
|
||||
{
|
||||
const char *Model( void ){ return "models/shellBuck.mdl"; }
|
||||
const char *PickSound( void ){ return "weapons/glock/clip_in.wav"; }
|
||||
BOOL AddItem( CBaseEntity *pOther ) { return pOther->GiveAmmo( 1, "buckshot", 125 ); }
|
||||
};
|
||||
LINK_ENTITY_TO_CLASS( ammo_buckshell, CShotgunAmmoShell );
|
||||
|
||||
//***********************************************************
|
||||
// item_weaponbox - a single entity that can store weapons
|
||||
// and ammo.
|
||||
//***********************************************************
|
||||
LINK_ENTITY_TO_CLASS( item_weaponbox, CWeaponBox );
|
||||
|
||||
TYPEDESCRIPTION CWeaponBox::m_SaveData[] =
|
||||
{
|
||||
DEFINE_ARRAY( CWeaponBox, m_rgAmmo, FIELD_INTEGER, MAX_AMMO_SLOTS ),
|
||||
DEFINE_ARRAY( CWeaponBox, m_rgiszAmmo, FIELD_STRING, MAX_AMMO_SLOTS ),
|
||||
DEFINE_ARRAY( CWeaponBox, m_rgpPlayerItems, FIELD_CLASSPTR, MAX_ITEM_TYPES ),
|
||||
DEFINE_FIELD( CWeaponBox, m_cAmmoTypes, FIELD_INTEGER ),
|
||||
}; IMPLEMENT_SAVERESTORE( CWeaponBox, CBaseEntity );
|
||||
|
||||
void CWeaponBox::Precache( void )
|
||||
{
|
||||
UTIL_PrecacheModel("models/w_weaponbox.mdl");
|
||||
}
|
||||
|
||||
void CWeaponBox :: KeyValue( KeyValueData *pkvd )
|
||||
{
|
||||
if ( m_cAmmoTypes < MAX_AMMO_SLOTS )
|
||||
{
|
||||
PackAmmo( ALLOC_STRING(pkvd->szKeyName), atoi(pkvd->szValue) );
|
||||
m_cAmmoTypes++;// count this new ammo type.
|
||||
|
||||
pkvd->fHandled = TRUE;
|
||||
}
|
||||
else Msg( "WeaponBox too full! only %d ammotypes allowed\n", MAX_AMMO_SLOTS );
|
||||
}
|
||||
|
||||
void CWeaponBox::Spawn( void )
|
||||
{
|
||||
Precache( );
|
||||
|
||||
pev->movetype = MOVETYPE_TOSS;
|
||||
pev->solid = SOLID_TRIGGER;
|
||||
|
||||
UTIL_SetSize( pev, g_vecZero, g_vecZero );
|
||||
UTIL_SetModel( ENT(pev), "models/w_weaponbox.mdl");
|
||||
}
|
||||
|
||||
void CWeaponBox::Kill( void )
|
||||
{
|
||||
CBasePlayerWeapon *pWeapon;
|
||||
int i;
|
||||
|
||||
// destroy the weapons
|
||||
for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ )
|
||||
{
|
||||
pWeapon = m_rgpPlayerItems[ i ];
|
||||
|
||||
while ( pWeapon )
|
||||
{
|
||||
pWeapon->SetThink( Remove );
|
||||
pWeapon->SetNextThink( 0.1 );
|
||||
pWeapon = pWeapon->m_pNext;
|
||||
}
|
||||
}
|
||||
|
||||
// remove the box
|
||||
UTIL_Remove( this );
|
||||
}
|
||||
|
||||
void CWeaponBox::Touch( CBaseEntity *pOther )
|
||||
{
|
||||
if ( !(pev->flags & FL_ONGROUND ) ) return;
|
||||
if ( !pOther->IsPlayer() ) return;
|
||||
if ( !pOther->IsAlive() ) return;
|
||||
|
||||
CBasePlayer *pPlayer = (CBasePlayer *)pOther;
|
||||
int i;
|
||||
|
||||
// dole out ammo
|
||||
for ( i = 0 ; i < MAX_AMMO_SLOTS ; i++ )
|
||||
{
|
||||
if ( !FStringNull( m_rgiszAmmo[ i ] ) )
|
||||
{
|
||||
// there's some ammo of this type.
|
||||
pPlayer->GiveAmmo( m_rgAmmo[ i ], (char *)STRING( m_rgiszAmmo[ i ] ), MaxAmmoCarry( m_rgiszAmmo[ i ] ) );
|
||||
|
||||
// now empty the ammo from the weaponbox since we just gave it to the player
|
||||
m_rgiszAmmo[ i ] = iStringNull;
|
||||
m_rgAmmo[ i ] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// go through my weapons and try to give the usable ones to the player.
|
||||
// it's important the the player be given ammo first, so the weapons code doesn't refuse
|
||||
// to deploy a better weapon that the player may pick up because he has no ammo for it.
|
||||
|
||||
for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ )
|
||||
{
|
||||
if ( m_rgpPlayerItems[ i ] )
|
||||
{
|
||||
CBasePlayerWeapon *pItem;
|
||||
|
||||
// have at least one weapon in this slot
|
||||
while ( m_rgpPlayerItems[ i ] )
|
||||
{
|
||||
//ALERT ( at_console, "trying to give %s\n", STRING( m_rgpPlayerItems[ i ]->pev->classname ) );
|
||||
|
||||
pItem = m_rgpPlayerItems[ i ];
|
||||
m_rgpPlayerItems[ i ] = m_rgpPlayerItems[ i ]->m_pNext;// unlink this weapon from the box
|
||||
|
||||
if ( pPlayer->AddPlayerItem( pItem ) ) pItem->AttachToPlayer( pPlayer );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EMIT_SOUND( pOther->edict(), CHAN_ITEM, "items/gunpickup2.wav", 1, ATTN_NORM );
|
||||
SetTouch(NULL);
|
||||
UTIL_Remove(this);
|
||||
}
|
||||
|
||||
int CWeaponBox::MaxAmmoCarry( int iszName )
|
||||
{
|
||||
for ( int i = 0; i < MAX_WEAPONS; i++ )
|
||||
{
|
||||
if ( CBasePlayerWeapon::ItemInfoArray[i].pszAmmo1 && !strcmp( STRING(iszName), CBasePlayerWeapon::ItemInfoArray[i].pszAmmo1 ) )
|
||||
return CBasePlayerWeapon::ItemInfoArray[i].iMaxAmmo1;
|
||||
if ( CBasePlayerWeapon::ItemInfoArray[i].pszAmmo2 && !strcmp( STRING(iszName), CBasePlayerWeapon::ItemInfoArray[i].pszAmmo2 ) )
|
||||
return CBasePlayerWeapon::ItemInfoArray[i].iMaxAmmo2;
|
||||
}
|
||||
|
||||
Msg( "MaxAmmoCarry() doesn't recognize '%s'!\n", STRING( iszName ) );
|
||||
return -1;
|
||||
}
|
||||
|
||||
BOOL CWeaponBox::PackWeapon( CBasePlayerWeapon *pWeapon )
|
||||
{
|
||||
// is one of these weapons already packed in this box?
|
||||
if ( HasWeapon( pWeapon ) ) return FALSE;// box can only hold one of each weapon type
|
||||
|
||||
if ( pWeapon->m_pPlayer )
|
||||
{
|
||||
// failed to unhook the weapon from the player!
|
||||
if ( !pWeapon->m_pPlayer->RemovePlayerItem( pWeapon ) ) return FALSE;
|
||||
}
|
||||
|
||||
int iWeaponSlot = pWeapon->iItemSlot();
|
||||
|
||||
if ( m_rgpPlayerItems[ iWeaponSlot ] )
|
||||
{
|
||||
// there's already one weapon in this slot, so link this into the slot's column
|
||||
pWeapon->m_pNext = m_rgpPlayerItems[ iWeaponSlot ];
|
||||
m_rgpPlayerItems[ iWeaponSlot ] = pWeapon;
|
||||
}
|
||||
else
|
||||
{
|
||||
// first weapon we have for this slot
|
||||
m_rgpPlayerItems[ iWeaponSlot ] = pWeapon;
|
||||
pWeapon->m_pNext = NULL;
|
||||
}
|
||||
|
||||
pWeapon->pev->spawnflags |= SF_NORESPAWN;// never respawn
|
||||
pWeapon->pev->movetype = MOVETYPE_NONE;
|
||||
pWeapon->pev->solid = SOLID_NOT;
|
||||
pWeapon->pev->effects = EF_NODRAW;
|
||||
pWeapon->pev->modelindex = 0;
|
||||
pWeapon->pev->model = iStringNull;
|
||||
pWeapon->pev->owner = edict();
|
||||
pWeapon->SetThink( NULL );// crowbar may be trying to swing again, etc.
|
||||
pWeapon->SetTouch( NULL );
|
||||
pWeapon->m_pPlayer = NULL;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CWeaponBox::PackAmmo( int iszName, int iCount )
|
||||
{
|
||||
int iMaxCarry;
|
||||
|
||||
if ( FStringNull( iszName ) )
|
||||
{
|
||||
// error here
|
||||
Msg( "NULL String in PackAmmo!\n" );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
iMaxCarry = MaxAmmoCarry( iszName );
|
||||
|
||||
if ( iMaxCarry != -1 && iCount > 0 )
|
||||
{
|
||||
GiveAmmo( iCount, (char *)STRING( iszName ), iMaxCarry );
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int CWeaponBox::GiveAmmo( int iCount, char *szName, int iMax, int *pIndex/* = NULL*/ )
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 1; i < MAX_AMMO_SLOTS && !FStringNull( m_rgiszAmmo[i] ); i++)
|
||||
{
|
||||
if (stricmp( szName, STRING( m_rgiszAmmo[i])) == 0)
|
||||
{
|
||||
if (pIndex) *pIndex = i;
|
||||
|
||||
int iAdd = min( iCount, iMax - m_rgAmmo[i]);
|
||||
if (iCount == 0 || iAdd > 0)
|
||||
{
|
||||
m_rgAmmo[i] += iAdd;
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (i < MAX_AMMO_SLOTS)
|
||||
{
|
||||
if (pIndex) *pIndex = i;
|
||||
|
||||
m_rgiszAmmo[i] = MAKE_STRING( szName );
|
||||
m_rgAmmo[i] = iCount;
|
||||
return i;
|
||||
}
|
||||
|
||||
Msg("out of named ammo slots\n");
|
||||
return i;
|
||||
}
|
||||
|
||||
BOOL CWeaponBox::HasWeapon( CBasePlayerWeapon *pCheckItem )
|
||||
{
|
||||
CBasePlayerWeapon *pItem = m_rgpPlayerItems[pCheckItem->iItemSlot()];
|
||||
|
||||
while (pItem)
|
||||
{
|
||||
if (FClassnameIs( pItem->pev, STRING( pCheckItem->pev->classname) )) return TRUE;
|
||||
pItem = pItem->m_pNext;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL CWeaponBox::IsEmpty( void )
|
||||
{
|
||||
int i;
|
||||
|
||||
for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ )
|
||||
{
|
||||
if ( m_rgpPlayerItems[ i ] ) return FALSE;
|
||||
}
|
||||
|
||||
for ( i = 0 ; i < MAX_AMMO_SLOTS ; i++ )
|
||||
{
|
||||
if ( !FStringNull( m_rgiszAmmo[ i ] )) return FALSE; // still have a bit of this type of ammo
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void CWeaponBox::SetObjectCollisionBox( void )
|
||||
{
|
||||
pev->absmin = pev->origin + Vector(-16, -16, 0);
|
||||
pev->absmax = pev->origin + Vector(16, 16, 16);
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/***
|
||||
*
|
||||
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
|
||||
*
|
||||
* This product contains software technology licensed from Id
|
||||
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Use, distribution, and modification of this source code and/or resulting
|
||||
* object code is restricted to non-commercial enhancements to products from
|
||||
* Valve LLC. All other use, distribution, or modification is prohibited
|
||||
* without written permission from Valve LLC.
|
||||
*
|
||||
****/
|
||||
#ifndef ITEMS_H
|
||||
#define ITEMS_H
|
||||
|
||||
|
||||
class CItem : public CBaseLogic
|
||||
{
|
||||
public:
|
||||
void Spawn( void );
|
||||
void Precache( void );
|
||||
CBaseEntity* Respawn( void );
|
||||
void EXPORT ItemTouch( CBaseEntity *pOther );
|
||||
void EXPORT Materialize( void );
|
||||
void EXPORT ItemFall( void );
|
||||
virtual BOOL AddItem( CBaseEntity *pOther ) { return TRUE; };
|
||||
virtual void ItemOnGround( void ) {};
|
||||
float ItemRespawnTime( CItem *pItem );
|
||||
|
||||
BOOL IsItem( void ) { return !strncmp( STRING(pev->classname), "item_", 5 ); }
|
||||
BOOL IsAmmo( void ) { return !strncmp( STRING(pev->classname), "ammo_", 5 ); }
|
||||
|
||||
//item_generic
|
||||
virtual const char *Model( void ){ return NULL; }
|
||||
virtual const char *PickSound( void ){ return "common/null.wav"; }
|
||||
virtual const char *FallSound( void ){ return "common/null.wav"; }
|
||||
};
|
||||
|
||||
class CWeaponBox : public CBaseEntity
|
||||
{
|
||||
void Precache( void );
|
||||
void Spawn( void );
|
||||
void Touch( CBaseEntity *pOther );
|
||||
void KeyValue( KeyValueData *pkvd );
|
||||
BOOL IsEmpty( void );
|
||||
int GiveAmmo( int iCount, char *szName, int iMax, int *pIndex = NULL );
|
||||
void SetObjectCollisionBox( void );
|
||||
public:
|
||||
void EXPORT Kill ( void );
|
||||
int Save( CSave &save );
|
||||
int Restore( CRestore &restore );
|
||||
static TYPEDESCRIPTION m_SaveData[];
|
||||
|
||||
BOOL HasWeapon( CBasePlayerWeapon *pCheckItem );
|
||||
BOOL PackWeapon( CBasePlayerWeapon *pWeapon );
|
||||
BOOL PackAmmo( int iszName, int iCount );
|
||||
|
||||
CBasePlayerWeapon *m_rgpPlayerItems[MAX_ITEM_TYPES];// one slot for each
|
||||
|
||||
int MaxAmmoCarry( int iszName );
|
||||
int m_rgiszAmmo[MAX_AMMO_SLOTS];// ammo names
|
||||
int m_rgAmmo[MAX_AMMO_SLOTS];// ammo quantities
|
||||
int m_cAmmoTypes;// how many ammo types packed into this box (if packed by a level designer)
|
||||
};
|
||||
|
||||
#endif // ITEMS_H
|
|
@ -0,0 +1,533 @@
|
|||
//=======================================================================
|
||||
// Copyright (C) Shambler Team 2004
|
||||
// logicentity.cpp - all entities with prefix "logic_"
|
||||
// additional entities for smart system
|
||||
//=======================================================================
|
||||
|
||||
#include "extdll.h"
|
||||
#include "utils.h"
|
||||
#include "cbase.h"
|
||||
#include "defaults.h"
|
||||
|
||||
// Use CBaseDelay as main function (renamed as CBaseLogic, see declaration in cbase.h).
|
||||
//=======================================================================
|
||||
// main functions ()
|
||||
//=======================================================================
|
||||
|
||||
void CBaseLogic :: KeyValue( KeyValueData *pkvd )
|
||||
{
|
||||
if (FStrEq(pkvd->szKeyName, "delay") || FStrEq(pkvd->szKeyName, "MaxDelay"))
|
||||
{
|
||||
m_flDelay = atof( pkvd->szValue );
|
||||
pkvd->fHandled = TRUE;
|
||||
}
|
||||
else if (FStrEq(pkvd->szKeyName, "wait") || FStrEq(pkvd->szKeyName, "MaxWait"))
|
||||
{
|
||||
m_flWait = atof(pkvd->szValue);
|
||||
pkvd->fHandled = TRUE;
|
||||
}
|
||||
else if (FStrEq(pkvd->szKeyName, "master"))
|
||||
{
|
||||
m_sMaster = ALLOC_STRING( pkvd->szValue );
|
||||
pkvd->fHandled = TRUE;
|
||||
}
|
||||
else if (FStrEq(pkvd->szKeyName, "killtarget"))
|
||||
{
|
||||
m_iszKillTarget = ALLOC_STRING( pkvd->szValue );
|
||||
pkvd->fHandled = TRUE;
|
||||
}
|
||||
else if (FStrEq(pkvd->szKeyName, "globalstate"))
|
||||
{
|
||||
m_globalstate = ALLOC_STRING( pkvd->szValue );
|
||||
pkvd->fHandled = TRUE;
|
||||
}
|
||||
else CBaseEntity::KeyValue( pkvd );
|
||||
}
|
||||
|
||||
void CBaseLogic :: FireTargets( USE_TYPE useType, float value )
|
||||
{
|
||||
//fire our targets
|
||||
UTIL_FireTargets( pev->target, m_hActivator, this, useType, value );
|
||||
UTIL_FireTargets( m_iszKillTarget, m_hActivator, this, USE_REMOVE );
|
||||
}
|
||||
|
||||
BOOL CBaseLogic :: IsLockedByMaster( void )
|
||||
{
|
||||
if (UTIL_IsMasterTriggered(m_sMaster, m_hActivator))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CBaseLogic :: IsLockedByMaster( CBaseEntity *pActivator )
|
||||
{
|
||||
if (UTIL_IsMasterTriggered(m_sMaster, pActivator))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CBaseLogic :: IsLockedByMaster( USE_TYPE useType )
|
||||
{
|
||||
if (UTIL_IsMasterTriggered(m_sMaster, m_hActivator))
|
||||
return FALSE;
|
||||
else if (useType == USE_SHOWINFO) return FALSE;//pass to debug info
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
TYPEDESCRIPTION CBaseLogic::m_SaveData[] =
|
||||
{
|
||||
DEFINE_FIELD( CBaseLogic, m_flDelay, FIELD_FLOAT ),
|
||||
DEFINE_FIELD( CBaseLogic, m_hActivator, FIELD_EHANDLE ),
|
||||
DEFINE_FIELD( CBaseLogic, m_hTarget, FIELD_EHANDLE ),
|
||||
DEFINE_FIELD( CBaseLogic, m_iState, FIELD_INTEGER ),
|
||||
DEFINE_FIELD( CBaseLogic, m_sMaster, FIELD_STRING),
|
||||
DEFINE_FIELD( CBaseLogic, m_iszKillTarget, FIELD_STRING ),
|
||||
DEFINE_FIELD( CBaseLogic, m_sSet, FIELD_STRING),
|
||||
DEFINE_FIELD( CBaseLogic, m_sReset, FIELD_STRING),
|
||||
DEFINE_FIELD( CBaseLogic, m_flWait, FIELD_FLOAT ),
|
||||
DEFINE_FIELD( CBaseLogic, m_globalstate, FIELD_STRING ),
|
||||
};IMPLEMENT_SAVERESTORE( CBaseLogic, CBaseEntity );
|
||||
|
||||
//=======================================================================
|
||||
// Logic_generator
|
||||
//=======================================================================
|
||||
#define NORMAL_MODE 0
|
||||
#define RANDOM_MODE 1
|
||||
#define RANDOM_MODE_WITH_DEC 2
|
||||
|
||||
class CGenerator : public CBaseLogic
|
||||
{
|
||||
public:
|
||||
void KeyValue( KeyValueData *pkvd );
|
||||
void Spawn( void );
|
||||
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
||||
void Think (void);
|
||||
|
||||
virtual int Save( CSave &save );
|
||||
virtual int Restore( CRestore &restore );
|
||||
static TYPEDESCRIPTION m_SaveData[];
|
||||
|
||||
private:
|
||||
int m_iFireCount;
|
||||
int m_iMaxFireCount;
|
||||
};
|
||||
LINK_ENTITY_TO_CLASS( logic_generator, CGenerator );
|
||||
|
||||
void CGenerator :: Spawn()
|
||||
{
|
||||
if(pev->button == RANDOM_MODE || pev->button == RANDOM_MODE_WITH_DEC)
|
||||
{ //set delay with decceleration
|
||||
if (!m_flDelay || pev->button == RANDOM_MODE_WITH_DEC) m_flDelay = 0.005;
|
||||
//generate max count automaticallly, if not set on map
|
||||
if (!m_iMaxFireCount) m_iMaxFireCount = RANDOM_LONG(100, 200);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Smart Field System ©
|
||||
if (!m_iMaxFireCount) m_iMaxFireCount = -1;//disable counting for normal mode
|
||||
}
|
||||
if(pev->spawnflags & SF_START_ON)
|
||||
{
|
||||
m_iState = STATE_ON;//initialy off in random mode
|
||||
SetNextThink(m_flDelay);
|
||||
}
|
||||
}
|
||||
|
||||
TYPEDESCRIPTION CGenerator :: m_SaveData[] =
|
||||
{
|
||||
DEFINE_FIELD( CGenerator, m_iMaxFireCount, FIELD_INTEGER ),
|
||||
DEFINE_FIELD( CGenerator, m_iFireCount, FIELD_INTEGER ),
|
||||
};
|
||||
IMPLEMENT_SAVERESTORE( CGenerator, CBaseLogic );
|
||||
|
||||
void CGenerator :: KeyValue( KeyValueData *pkvd )
|
||||
{
|
||||
if (FStrEq(pkvd->szKeyName, "maxcount"))
|
||||
{
|
||||
m_iMaxFireCount = atoi(pkvd->szValue);
|
||||
pkvd->fHandled = TRUE;
|
||||
}
|
||||
if (FStrEq(pkvd->szKeyName, "mode"))
|
||||
{
|
||||
pev->button = atof(pkvd->szValue);
|
||||
pkvd->fHandled = TRUE;
|
||||
}
|
||||
else CBaseLogic::KeyValue( pkvd );
|
||||
}
|
||||
|
||||
void CGenerator :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
||||
{
|
||||
if (useType == USE_TOGGLE)
|
||||
{
|
||||
if(m_iState) useType = USE_OFF;
|
||||
else useType = USE_ON;
|
||||
}
|
||||
if (useType == USE_ON)
|
||||
{
|
||||
if(pev->button == RANDOM_MODE || pev->button == RANDOM_MODE_WITH_DEC)
|
||||
{
|
||||
if(pev->button == RANDOM_MODE_WITH_DEC) m_flDelay = 0.005;
|
||||
m_iFireCount = RANDOM_LONG(0, m_iMaxFireCount/2);
|
||||
}
|
||||
m_iState = STATE_ON;
|
||||
SetNextThink( 0 );//immediately start firing targets
|
||||
}
|
||||
else if (useType == USE_OFF)
|
||||
{
|
||||
m_iState = STATE_OFF;
|
||||
DontThink();
|
||||
}
|
||||
else if (useType == USE_SET) //set max count of impulses
|
||||
m_iMaxFireCount = value;
|
||||
|
||||
else if (useType == USE_RESET) //immediately reset
|
||||
m_iFireCount = 0;
|
||||
|
||||
else if (useType == USE_SHOWINFO)
|
||||
{
|
||||
ALERT(at_console, "======/Xash Debug System/======\n");
|
||||
ALERT(at_console, "classname: %s\n", STRING(pev->classname));
|
||||
ALERT(at_console, "State: %s, Delay time %f\n", GetStringForState( GetState()), m_flDelay);
|
||||
ALERT(at_console, "FireCount: %d, Max FireCount: %d\n", m_iFireCount, m_iMaxFireCount);
|
||||
}
|
||||
}
|
||||
|
||||
void CGenerator :: Think( void )
|
||||
{
|
||||
if(m_iFireCount != -1)//if counter enabled
|
||||
{
|
||||
if(m_iFireCount == m_iMaxFireCount)
|
||||
{
|
||||
m_iFireCount = NULL;
|
||||
DontThink();
|
||||
m_iState = STATE_OFF;
|
||||
return;
|
||||
}
|
||||
else m_iFireCount++;
|
||||
}
|
||||
if(pev->button == RANDOM_MODE_WITH_DEC)
|
||||
{ //deceleration for random mode
|
||||
if(m_iMaxFireCount - m_iFireCount < 40) m_flDelay += 0.005;
|
||||
}
|
||||
UTIL_FireTargets( pev->target, this, this, USE_TOGGLE );
|
||||
SetNextThink(m_flDelay);
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// Logic_switcher
|
||||
//=======================================================================
|
||||
#define MODE_INCREMENT 0
|
||||
#define MODE_DECREMENT 1
|
||||
#define MODE_RANDOM_VALUE 2
|
||||
|
||||
class CSwitcher : public CBaseLogic
|
||||
{
|
||||
public:
|
||||
void KeyValue( KeyValueData *pkvd );
|
||||
void Spawn ( void );
|
||||
void Think ( void );
|
||||
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
||||
|
||||
virtual int Save( CSave &save );
|
||||
virtual int Restore( CRestore &restore );
|
||||
static TYPEDESCRIPTION m_SaveData[];
|
||||
|
||||
int m_cTargets;// the total number of targets in this manager's fire list.
|
||||
int m_index; // Current target
|
||||
int m_iTargetName [ MAX_MULTI_TARGETS ];// list if indexes into global string array
|
||||
};
|
||||
LINK_ENTITY_TO_CLASS( logic_switcher, CSwitcher );
|
||||
|
||||
// Global Savedata for switcher
|
||||
TYPEDESCRIPTION CSwitcher::m_SaveData[] =
|
||||
{ DEFINE_FIELD( CSwitcher, m_cTargets, FIELD_INTEGER ),
|
||||
DEFINE_FIELD( CSwitcher, m_index, FIELD_INTEGER ),
|
||||
DEFINE_ARRAY( CSwitcher, m_iTargetName, FIELD_STRING, MAX_MULTI_TARGETS ),
|
||||
};IMPLEMENT_SAVERESTORE(CSwitcher, CBaseLogic);
|
||||
|
||||
void CSwitcher :: KeyValue( KeyValueData *pkvd )
|
||||
{
|
||||
if (FStrEq(pkvd->szKeyName, "mode"))
|
||||
{
|
||||
pev->button = atoi(pkvd->szValue);
|
||||
pkvd->fHandled = TRUE;
|
||||
}
|
||||
else if ( m_cTargets < MAX_MULTI_TARGETS )
|
||||
{
|
||||
// add this field to the target list
|
||||
// this assumes that additional fields are targetnames and their values are delay values.
|
||||
|
||||
char tmp[128];
|
||||
UTIL_StripToken( pkvd->szKeyName, tmp );
|
||||
m_iTargetName [ m_cTargets ] = ALLOC_STRING( tmp );
|
||||
m_cTargets++;
|
||||
pkvd->fHandled = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
void CSwitcher :: Spawn( void )
|
||||
{
|
||||
int r_index = 0;
|
||||
int w_index = m_cTargets - 1;
|
||||
|
||||
while(r_index < w_index)
|
||||
{
|
||||
//we store target with right index in tempname
|
||||
int name = m_iTargetName [r_index];
|
||||
|
||||
//target with right name is free, record new value from wrong name
|
||||
m_iTargetName [r_index] = m_iTargetName [w_index];
|
||||
|
||||
//ok, we can swap targets
|
||||
m_iTargetName [w_index] = name;
|
||||
r_index++;
|
||||
w_index--;
|
||||
}
|
||||
|
||||
m_iState = STATE_OFF;
|
||||
m_index = 0;
|
||||
if(pev->spawnflags & SF_START_ON)
|
||||
{
|
||||
m_iState = STATE_ON;
|
||||
SetNextThink (m_flDelay);
|
||||
}
|
||||
}
|
||||
|
||||
void CSwitcher :: Think ( void )
|
||||
{
|
||||
if(pev->button == MODE_INCREMENT)//increase target number
|
||||
{
|
||||
m_index++;
|
||||
if(m_index >= m_cTargets) m_index = 0;
|
||||
}
|
||||
else if(pev->button == MODE_DECREMENT)
|
||||
{
|
||||
m_index--;
|
||||
if(m_index < 0) m_index = m_cTargets - 1;
|
||||
}
|
||||
else if(pev->button == MODE_RANDOM_VALUE)
|
||||
{
|
||||
m_index = RANDOM_LONG (0, m_cTargets - 1);
|
||||
}
|
||||
SetNextThink (m_flDelay);
|
||||
}
|
||||
|
||||
void CSwitcher :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
||||
{
|
||||
m_hActivator = pActivator;
|
||||
|
||||
if(IsLockedByMaster( useType )) return;
|
||||
|
||||
if (useType == USE_SET)//set new target for activate (direct choose or increment\decrement)
|
||||
{
|
||||
if(pev->spawnflags & SF_START_ON)
|
||||
{
|
||||
m_iState = STATE_ON;
|
||||
SetNextThink (m_flDelay);
|
||||
return;
|
||||
}
|
||||
//set maximum priority for direct choose
|
||||
if(value)
|
||||
{
|
||||
m_index = (value - 1);
|
||||
if(m_index >= m_cTargets) m_index = -1;
|
||||
return;
|
||||
}
|
||||
if(pev->button == MODE_INCREMENT)
|
||||
{
|
||||
m_index++;
|
||||
if(m_index >= m_cTargets) m_index = 0;
|
||||
}
|
||||
else if(pev->button == MODE_DECREMENT)//increase target number
|
||||
{
|
||||
m_index--;
|
||||
if(m_index < 0) m_index = m_cTargets - 1;
|
||||
}
|
||||
else if(pev->button == MODE_RANDOM_VALUE)
|
||||
{
|
||||
m_index = RANDOM_LONG (0, m_cTargets - 1);
|
||||
}
|
||||
}
|
||||
else if (useType == USE_RESET)
|
||||
{
|
||||
//reset switcher
|
||||
m_iState = STATE_OFF;
|
||||
DontThink();
|
||||
m_index = 0;
|
||||
return;
|
||||
}
|
||||
else if (useType == USE_SHOWINFO)
|
||||
{
|
||||
ALERT(at_console, "======/Xash Debug System/======\n");
|
||||
ALERT(at_console, "classname: %s\n", STRING(pev->classname));
|
||||
ALERT(at_console, "State: %s, number of targets %d\n", GetStringForState( GetState()), m_cTargets - 1);
|
||||
ALERT(at_console, "Current target %s, target number %d\n", STRING(m_iTargetName[ m_index ]), m_index );
|
||||
}
|
||||
else if(m_index != -1)//fire any other USE_TYPE and right index
|
||||
{
|
||||
UTIL_FireTargets( m_iTargetName[ m_index ], m_hActivator, this, useType, value );
|
||||
}
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// Logic_counter
|
||||
//=======================================================================
|
||||
|
||||
class CLogicCounter : public CBaseLogic
|
||||
{
|
||||
public:
|
||||
void Spawn( void );
|
||||
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
||||
void KeyValue( KeyValueData *pkvd );
|
||||
};
|
||||
LINK_ENTITY_TO_CLASS( logic_counter, CLogicCounter );
|
||||
|
||||
void CLogicCounter :: KeyValue( KeyValueData *pkvd )
|
||||
{
|
||||
if (FStrEq(pkvd->szKeyName, "count"))
|
||||
{
|
||||
pev->frags = atof(pkvd->szValue);
|
||||
pkvd->fHandled = TRUE;
|
||||
}
|
||||
if (FStrEq(pkvd->szKeyName, "maxcount"))
|
||||
{
|
||||
pev->body = atoi(pkvd->szValue);
|
||||
pkvd->fHandled = TRUE;
|
||||
}
|
||||
else CBaseLogic::KeyValue( pkvd );
|
||||
}
|
||||
|
||||
void CLogicCounter :: Spawn( void )
|
||||
{
|
||||
//Smart Field System ©
|
||||
if (pev->frags == 0) pev->frags = 2;
|
||||
if (pev->body == 0) pev->body = 100;
|
||||
if (pev->frags == -1) pev->frags = RANDOM_LONG (1, pev->body);
|
||||
|
||||
//save number of impulses
|
||||
pev->impulse = pev->frags;
|
||||
m_iState = STATE_OFF;//always disable
|
||||
}
|
||||
|
||||
void CLogicCounter :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
||||
{
|
||||
if (useType == USE_SET)
|
||||
{
|
||||
if(value) pev->impulse = pev->frags = value; //write new value
|
||||
else pev->impulse = pev->frags = RANDOM_LONG (1, pev->body);//write random value
|
||||
}
|
||||
else if (useType == USE_RESET) pev->frags = pev->impulse; //restore counter to default
|
||||
else if (useType == USE_SHOWINFO)
|
||||
{
|
||||
ALERT(at_console, "======/Xash Debug System/======\n");
|
||||
ALERT(at_console, "classname: %s\n", STRING(pev->classname));
|
||||
ALERT(at_console, "start count %d, current count %.f\n",pev->impulse , pev->impulse - pev->frags );
|
||||
ALERT(at_console, "left activates: %.f\n", pev->frags);
|
||||
}
|
||||
else //any other useType
|
||||
{
|
||||
pev->frags--;
|
||||
if(pev->frags > 0) return;
|
||||
|
||||
pev->frags = 0; //don't reset counter in negative value
|
||||
UTIL_FireTargets( pev->target, pActivator, this, useType, value ); //activate target
|
||||
}
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// Logic_usetype - sorting different usetypes
|
||||
//=======================================================================
|
||||
|
||||
class CLogicUseType : public CBaseLogic
|
||||
{
|
||||
public:
|
||||
void KeyValue( KeyValueData *pkvd );
|
||||
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
||||
};
|
||||
LINK_ENTITY_TO_CLASS( logic_usetype, CLogicUseType );
|
||||
|
||||
void CLogicUseType::KeyValue( KeyValueData *pkvd )
|
||||
{
|
||||
if (FStrEq(pkvd->szKeyName, "toggle"))
|
||||
{
|
||||
pev->target = ALLOC_STRING( pkvd->szValue );
|
||||
pkvd->fHandled = TRUE;
|
||||
}
|
||||
else if (FStrEq(pkvd->szKeyName, "enable"))
|
||||
{
|
||||
pev->message = ALLOC_STRING( pkvd->szValue );
|
||||
pkvd->fHandled = TRUE;
|
||||
}
|
||||
else if (FStrEq(pkvd->szKeyName, "disable"))
|
||||
{
|
||||
pev->netname = ALLOC_STRING( pkvd->szValue );
|
||||
pkvd->fHandled = TRUE;
|
||||
}
|
||||
else if (FStrEq(pkvd->szKeyName, "set"))
|
||||
{
|
||||
m_sSet = ALLOC_STRING( pkvd->szValue );
|
||||
pkvd->fHandled = TRUE;
|
||||
}
|
||||
else if (FStrEq(pkvd->szKeyName, "reset"))
|
||||
{
|
||||
m_sReset = ALLOC_STRING( pkvd->szValue );
|
||||
pkvd->fHandled = TRUE;
|
||||
}
|
||||
else CBaseLogic::KeyValue( pkvd );
|
||||
}
|
||||
|
||||
void CLogicUseType::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
||||
{
|
||||
if(IsLockedByMaster( useType )) return;
|
||||
if(useType == USE_TOGGLE) UTIL_FireTargets(pev->target, pActivator, this, useType, value );
|
||||
else if (useType == USE_ON) UTIL_FireTargets(pev->message, pActivator, this, useType, value );
|
||||
else if (useType == USE_OFF) UTIL_FireTargets(pev->netname, pActivator, this, useType, value );
|
||||
else if (useType == USE_SET) UTIL_FireTargets(m_sSet, pActivator, this, useType, value );
|
||||
else if (useType == USE_RESET)UTIL_FireTargets(m_sReset, pActivator, this, useType, value );
|
||||
else if (useType == USE_SHOWINFO)
|
||||
{
|
||||
ALERT(at_console, "======/Xash Debug System/======\n");
|
||||
ALERT(at_console, "classname: %s\n", STRING(pev->classname));
|
||||
ALERT(at_console, "This entity don't displayed settings!\n" );
|
||||
SHIFT;
|
||||
}
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// Logic_scale - apply scale for value
|
||||
//=======================================================================
|
||||
class CLogicScale : public CBaseLogic
|
||||
{
|
||||
public:
|
||||
void KeyValue( KeyValueData *pkvd )
|
||||
{
|
||||
if (FStrEq(pkvd->szKeyName, "mode"))
|
||||
{
|
||||
pev->impulse = atoi( pkvd->szValue );
|
||||
pkvd->fHandled = TRUE;
|
||||
}
|
||||
else CBaseLogic::KeyValue( pkvd );
|
||||
}
|
||||
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
||||
{
|
||||
if (useType == USE_SHOWINFO)
|
||||
{
|
||||
DEBUGHEAD;
|
||||
ALERT(at_console, "Mode %s. Scale %.3f.\n", pev->impulse ? "Bool" : "Float", pev->scale);
|
||||
SHIFT;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(pev->impulse == 0)//bool logic
|
||||
{
|
||||
if(value >= 0.99)UTIL_FireTargets(pev->target, pActivator, this, USE_ON, 1 );
|
||||
if(value <= 0.01)UTIL_FireTargets(pev->target, pActivator, this, USE_OFF,0 );
|
||||
}
|
||||
if(pev->impulse == 1)//direct scale
|
||||
UTIL_FireTargets(pev->target, pActivator, this, USE_SET, value * pev->scale );
|
||||
if(pev->impulse == 2)//inverse sacle
|
||||
UTIL_FireTargets(pev->target, pActivator, this, USE_SET, pev->scale * (1-value));
|
||||
}
|
||||
}
|
||||
};
|
||||
LINK_ENTITY_TO_CLASS( logic_scale, CLogicScale);
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
//=======================================================================
|
||||
// Copyright (C) XashXT Group 2006
|
||||
//=======================================================================
|
||||
|
||||
#ifndef BASELOGIC_H
|
||||
#define BASELOGIC_H
|
||||
|
||||
#define MAX_MULTI_TARGETS 32 // maximum number of targets that can be added in a list
|
||||
|
||||
class CBaseLogic : public CBaseEntity
|
||||
{
|
||||
public:
|
||||
BOOL IsLockedByMaster( void );
|
||||
BOOL IsLockedByMaster( USE_TYPE useType );
|
||||
BOOL IsLockedByMaster( CBaseEntity *pActivator );
|
||||
void FireTargets( USE_TYPE useType = USE_TOGGLE, float value = 0 );
|
||||
virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }
|
||||
virtual void KeyValue( KeyValueData* pkvd);
|
||||
virtual int Save( CSave &save );
|
||||
virtual int Restore( CRestore &restore );
|
||||
static TYPEDESCRIPTION m_SaveData[];
|
||||
virtual STATE GetState( void ) { return m_iState; };
|
||||
|
||||
float m_flDelay;
|
||||
float m_flWait;
|
||||
EHANDLE m_hActivator;
|
||||
EHANDLE m_hTarget;
|
||||
STATE m_iState;
|
||||
string_t m_sMaster;
|
||||
string_t m_iszKillTarget; //evil stuff. agrhh
|
||||
string_t m_sSet;//used for logic_usetype
|
||||
string_t m_sReset;//used for logic_usetype
|
||||
string_t m_globalstate;
|
||||
float m_flMin, m_flMax;
|
||||
};
|
||||
|
||||
#define SF_CORNER_WAITTRIG 0x001
|
||||
#define SF_CORNER_TELEPORT 0x002
|
||||
#define SF_CORNER_FIREONCE 0x004
|
||||
|
||||
class CPathCorner : public CBaseLogic
|
||||
{
|
||||
public:
|
||||
void Spawn( );
|
||||
void KeyValue( KeyValueData* pkvd );
|
||||
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
||||
float GetDelay( void ){ return pev->spawnflags & SF_CORNER_WAITTRIG ? -1 : m_flWait; }
|
||||
void GetSpeed( float *speed ) { if(pev->speed != 0) *speed = pev->speed; }
|
||||
void UpdateTargets( void );
|
||||
void Link( void );
|
||||
void PostActivate( void ){ Link(); }
|
||||
virtual int Save( CSave &save );
|
||||
virtual int Restore( CRestore &restore );
|
||||
static TYPEDESCRIPTION m_SaveData[];
|
||||
|
||||
CPathCorner *Instance( edict_t *pent )
|
||||
{
|
||||
if ( FClassnameIs( pent, "path_corner" ) )
|
||||
return (CPathCorner *)GET_PRIVATE(pent);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CPathCorner *m_pNextPath1;
|
||||
CPathCorner *m_pNextPath2;
|
||||
CPathCorner *m_pPrevPath;
|
||||
CBaseEntity *ValidPath( CBaseEntity *m_pPath );
|
||||
CBaseEntity *GetNext( void );
|
||||
CBaseEntity *GetPrev( void ){ return ValidPath( m_pPrevPath ); }
|
||||
void SetPrev( CPathCorner *pPrev ) { m_pPrevPath = (CPathCorner *)ValidPath((CPathCorner *)pPrev); }
|
||||
};
|
||||
|
||||
class CPathTrack : public CBaseLogic
|
||||
{
|
||||
public:
|
||||
void Spawn( void );
|
||||
void Activate( void );
|
||||
void KeyValue( KeyValueData* pkvd);
|
||||
|
||||
void SetPrevious( CPathTrack *pprevious );
|
||||
void Link( void );
|
||||
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
||||
|
||||
CBaseEntity *ValidPath( CBaseEntity *ppath, int testFlag ); // Returns ppath if enabled, NULL otherwise
|
||||
void Project( CBaseEntity *pstart, CBaseEntity *pend, Vector *origin, float dist );
|
||||
|
||||
static CPathTrack *Instance( edict_t *pent );
|
||||
|
||||
CBaseEntity *LookAhead( Vector *origin, float dist, int move );
|
||||
CBaseEntity *Nearest( Vector origin ); //notused
|
||||
|
||||
CBaseEntity *GetNext( void );
|
||||
CBaseEntity *GetPrev( void );
|
||||
|
||||
virtual int Save( CSave &save );
|
||||
virtual int Restore( CRestore &restore );
|
||||
|
||||
static TYPEDESCRIPTION m_SaveData[];
|
||||
#if PATH_SPARKLE_DEBUG
|
||||
void EXPORT Sparkle(void);
|
||||
#endif
|
||||
|
||||
float m_length;
|
||||
string_t m_altName;
|
||||
CPathTrack *m_pnext;
|
||||
CPathTrack *m_pprevious;
|
||||
CPathTrack *m_paltpath;
|
||||
};
|
||||
|
||||
class CMultiSource : public CBaseLogic
|
||||
{
|
||||
public:
|
||||
void Spawn( );
|
||||
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
||||
STATE GetState( void );
|
||||
void EXPORT Register( void );
|
||||
virtual int Save( CSave &save );
|
||||
virtual int Restore( CRestore &restore );
|
||||
static TYPEDESCRIPTION m_SaveData[];
|
||||
|
||||
EHANDLE m_rgEntities[MAX_MULTI_TARGETS];
|
||||
int m_rgTriggered[MAX_MULTI_TARGETS];
|
||||
|
||||
int m_iTotal;
|
||||
};
|
||||
|
||||
#include "baseinfo.h"
|
||||
|
||||
class CUtilRainModify : public CPointEntity
|
||||
{
|
||||
public:
|
||||
void Spawn( void );
|
||||
void KeyValue( KeyValueData *pkvd );
|
||||
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
||||
|
||||
virtual int Save( CSave &save );
|
||||
virtual int Restore( CRestore &restore );
|
||||
static TYPEDESCRIPTION m_SaveData[];
|
||||
|
||||
int drips;
|
||||
RandomRange windXY;
|
||||
RandomRange randXY;
|
||||
float fadeTime;
|
||||
};
|
||||
|
||||
#endif //BASELOGIC_H
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,252 @@
|
|||
//=======================================================================
|
||||
// Copyright (C) XashXT Group 2006
|
||||
//=======================================================================
|
||||
#ifndef BASEMOVER_H
|
||||
#define BASEMOVER_H
|
||||
|
||||
//rotating brush flags
|
||||
#define SF_BRUSH_ROTATE_Z_AXIS 4
|
||||
#define SF_BRUSH_ROTATE_X_AXIS 8
|
||||
|
||||
//door flags
|
||||
#define SF_DOOR_START_OPEN 1
|
||||
#define SF_DOOR_ROTATE_BACKWARDS 2
|
||||
#define SF_DOOR_PASSABLE 8
|
||||
#define SF_DOOR_ONEWAY 16
|
||||
#define SF_DOOR_NO_AUTO_RETURN 32
|
||||
#define SF_DOOR_ROTATE_Z 64
|
||||
#define SF_DOOR_ROTATE_X 128
|
||||
#define SF_DOOR_USE_ONLY 256
|
||||
#define SF_DOOR_NOMONSTERS 512
|
||||
|
||||
// Tracktrain spawn flags
|
||||
#define SF_TRACKTRAIN_NOPITCH 0x0001
|
||||
#define SF_TRACKTRAIN_NOCONTROL 0x0002
|
||||
#define SF_TRACKTRAIN_FORWARDONLY 0x0004
|
||||
#define SF_TRACKTRAIN_PASSABLE 0x0008
|
||||
#define SF_TRACKTRAIN_NOYAW 0x0010 //LRC
|
||||
#define SF_TRACKTRAIN_AVELOCITY 0x800000 //LRC - avelocity has been set manually, don't turn.
|
||||
#define SF_TRACKTRAIN_AVEL_GEARS 0x400000 //LRC - avelocity should be scaled up/down when the train changes gear.
|
||||
|
||||
// Spawnflag for CPathTrack
|
||||
#define SF_PATH_DISABLED 0x00000001
|
||||
#define SF_PATH_FIREONCE 0x00000002
|
||||
#define SF_PATH_ALTREVERSE 0x00000004
|
||||
#define SF_PATH_DISABLE_TRAIN 0x00000008
|
||||
#define SF_PATH_ALTERNATE 0x00008000
|
||||
#define SF_PATH_AVELOCITY 0x00080000 //LRC
|
||||
|
||||
//LRC - values in 'armortype'
|
||||
#define PATHSPEED_SET 0
|
||||
#define PATHSPEED_ACCEL 1
|
||||
#define PATHSPEED_TIME 2
|
||||
#define PATHSPEED_SET_MASTER 3
|
||||
|
||||
class CBaseMover : public CBaseBrush
|
||||
{
|
||||
public:
|
||||
void KeyValue( KeyValueData *pkvd );
|
||||
virtual void AxisDir( void );
|
||||
void (CBaseMover::*m_pfnCallWhenMoveDone)(void); //custom movedone function
|
||||
virtual int Save( CSave &save );
|
||||
virtual int Restore( CRestore &restore );
|
||||
static TYPEDESCRIPTION m_SaveData[];
|
||||
float m_flMoveDistance;//rotating distance
|
||||
float m_flBlockedTime; //set blocked refresh time
|
||||
int m_iMode;//style of working
|
||||
float m_flValue;//value to send
|
||||
float m_flHeight;
|
||||
float m_flLip;
|
||||
|
||||
Vector m_vecPosition1; //startpos
|
||||
Vector m_vecPosition2; //endpos
|
||||
Vector m_vecAngle1; //startangle
|
||||
Vector m_vecAngle2; //endangle
|
||||
Vector m_vecFinalDest; //basemover finalpos
|
||||
Vector m_vecFinalAngle; //basemover finalangle
|
||||
Vector m_vecFloor; //basemover dest floor
|
||||
float m_flLinearMoveSpeed;//member linear speed
|
||||
float m_flAngularMoveSpeed;//member angular speed
|
||||
|
||||
// common member functions
|
||||
void LinearMove ( Vector vecInput, float flSpeed );
|
||||
void AngularMove( Vector vecDestAngle, float flSpeed );
|
||||
void ComplexMove( Vector vecInput, Vector vecDestAngle, float flSpeed );
|
||||
void EXPORT LinearMoveNow( void );
|
||||
void EXPORT AngularMoveNow( void );
|
||||
void EXPORT ComplexMoveNow( void );
|
||||
void EXPORT LinearMoveDone( void );
|
||||
void EXPORT AngularMoveDone( void );
|
||||
void EXPORT ComplexMoveDone( void );
|
||||
void EXPORT LinearMoveDoneNow( void );
|
||||
void EXPORT AngularMoveDoneNow( void );
|
||||
void EXPORT ComplexMoveDoneNow( void );
|
||||
};
|
||||
|
||||
class CBaseDoor : public CBaseMover
|
||||
{
|
||||
public:
|
||||
void Spawn( void );
|
||||
void Precache( void );
|
||||
virtual void PostSpawn( void );
|
||||
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
||||
BOOL IsWater( void ){ return pev->skin != 0; };
|
||||
void EXPORT DoorTouch( CBaseEntity *pOther );
|
||||
virtual void Blocked( CBaseEntity *pOther );
|
||||
virtual int ObjectCaps( void )
|
||||
{
|
||||
if ( FBitSet ( pev->spawnflags, SF_DOOR_USE_ONLY ))//door without name player can direct using
|
||||
return (CBaseMover::ObjectCaps() & ~FCAP_ACROSS_TRANSITION | FCAP_IMPULSE_USE );
|
||||
else return (CBaseMover::ObjectCaps() & ~FCAP_ACROSS_TRANSITION);
|
||||
};
|
||||
|
||||
// local functions
|
||||
void EXPORT DoorGoUp( void );
|
||||
void EXPORT DoorGoDown( void );
|
||||
void EXPORT DoorHitTop( void );
|
||||
void EXPORT DoorHitBottom( void );
|
||||
virtual BOOL IsRotatingDoor( void ){ return FALSE; };
|
||||
};
|
||||
|
||||
class CRotDoor : public CBaseDoor
|
||||
{
|
||||
public:
|
||||
virtual void PostSpawn( void ) {}
|
||||
virtual BOOL IsRotatingDoor( void ){ return TRUE; };
|
||||
};
|
||||
|
||||
class CMomentaryDoor : public CBaseMover
|
||||
{
|
||||
public:
|
||||
void Spawn( void );
|
||||
void Precache( void );
|
||||
void PostSpawn( void );
|
||||
void EXPORT MomentaryMoveDone( void );
|
||||
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
||||
virtual int ObjectCaps( void ) { return CBaseMover :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }
|
||||
};
|
||||
|
||||
class CBasePlatform : public CBaseMover
|
||||
{
|
||||
public:
|
||||
void Precache( void );
|
||||
void Spawn( void );
|
||||
void PostSpawn( void );
|
||||
void Setup( void );
|
||||
void PostActivate( void );
|
||||
virtual void Blocked( CBaseEntity *pOther );
|
||||
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
||||
float CalcFloor( void )
|
||||
{
|
||||
float curfloor = ((pev->origin.z - m_vecPosition1.z) / step()) + 1;
|
||||
if (curfloor - floor(curfloor) > 0.5) return ceil(curfloor);
|
||||
else return floor(curfloor);
|
||||
}
|
||||
float step( void ) { return pev->size.z + m_flHeight - 2; }
|
||||
float ftime( void ) { return step() / pev->speed; } //time to moving between floors
|
||||
|
||||
void EXPORT GoUp( void );
|
||||
void EXPORT GoDown( void );
|
||||
void GoToFloor( float floor );
|
||||
void EXPORT HitTop( void );
|
||||
void EXPORT HitBottom( void );
|
||||
void EXPORT HitFloor( void );
|
||||
virtual BOOL IsMovingPlatform( void ) { return m_flHeight != 0 && m_flMoveDistance == 0; }
|
||||
virtual BOOL IsRotatingPlatform( void ){ return m_flHeight == 0 && m_flMoveDistance != 0; }
|
||||
virtual BOOL IsComplexPlatform( void ) { return m_flHeight != 0 && m_flMoveDistance != 0; }
|
||||
};
|
||||
|
||||
class CFuncTrain : public CBasePlatform
|
||||
{
|
||||
public:
|
||||
void Spawn( void );
|
||||
void PostSpawn( void );
|
||||
void OverrideReset( void );
|
||||
void PostActivate( void );
|
||||
void ClearPointers( void );
|
||||
|
||||
BOOL Stop( float flWait = -1 );
|
||||
BOOL Teleport( void );
|
||||
void Blocked( CBaseEntity *pOther );
|
||||
BOOL IsWater( void ){ return pev->skin != 0; };
|
||||
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
||||
|
||||
Vector TrainOrg( void ) { return (pev->mins + pev->maxs) * 0.5; }
|
||||
|
||||
void EXPORT Wait( void );
|
||||
void EXPORT Next( void );
|
||||
|
||||
//path operations
|
||||
CBaseEntity *FindPath( void );
|
||||
CBaseEntity *FindNextPath( void );
|
||||
void Reverse( void );
|
||||
|
||||
virtual int Save( CSave &save );
|
||||
virtual int Restore( CRestore &restore );
|
||||
static TYPEDESCRIPTION m_SaveData[];
|
||||
|
||||
CBaseEntity *pCurPath, *pNextPath;
|
||||
};
|
||||
|
||||
class CFuncTrackTrain : public CBaseMover
|
||||
{
|
||||
public:
|
||||
void Spawn( void );
|
||||
void Precache( void );
|
||||
|
||||
void Blocked( CBaseEntity *pOther );
|
||||
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
||||
void KeyValue( KeyValueData* pkvd );
|
||||
|
||||
void EXPORT DesiredAction( void ); //LRC - used to be called Next!
|
||||
void PostActivate( void );
|
||||
void ClearPointers( void );
|
||||
|
||||
// void EXPORT Next( void );
|
||||
void EXPORT PostponeNext( void );
|
||||
void EXPORT Find( void );
|
||||
void EXPORT NearestPath( void );
|
||||
void EXPORT DeadEnd( void );
|
||||
|
||||
void NextThink( float thinkTime, BOOL alwaysThink );
|
||||
|
||||
void SetTrack( CBaseEntity *track ) { pPath = ((CPathTrack *)track)->Nearest(pev->origin); }
|
||||
void SetControls( entvars_t *pevControls );
|
||||
BOOL OnControls( entvars_t *pev );
|
||||
|
||||
void StopSound ( void );
|
||||
void UpdateSound ( void );
|
||||
|
||||
static CFuncTrackTrain *Instance( edict_t *pent )
|
||||
{
|
||||
if ( FClassnameIs( pent, "func_tracktrain" ) )
|
||||
return (CFuncTrackTrain *)GET_PRIVATE(pent);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
virtual int Save( CSave &save );
|
||||
virtual int Restore( CRestore &restore );
|
||||
|
||||
static TYPEDESCRIPTION m_SaveData[];
|
||||
virtual int ObjectCaps( void ) { return CBaseMover :: ObjectCaps() | FCAP_DIRECTIONAL_USE; }
|
||||
|
||||
virtual void OverrideReset( void );
|
||||
|
||||
CBaseEntity *pPath;
|
||||
float m_length;
|
||||
float m_height;
|
||||
// I get it... this records the train's max speed (as set by the level designer), whereas
|
||||
// pev->speed records the current speed (as set by the player). --LRC
|
||||
// m_speed is also stored, as an int, in pev->impulse.
|
||||
float m_speed;
|
||||
float m_dir;
|
||||
float m_startSpeed;
|
||||
Vector m_controlMins;
|
||||
Vector m_controlMaxs;
|
||||
int m_soundPlaying;
|
||||
float m_flBank;
|
||||
float m_oldSpeed;
|
||||
Vector m_vecBaseAvel; // LRC - the underlying avelocity, superceded by normal turning behaviour where applicable
|
||||
};
|
||||
|
||||
#endif //BASEMOVER_H
|
|
@ -0,0 +1,270 @@
|
|||
//=======================================================================
|
||||
// Copyright (C) XashXT Group 2007
|
||||
// misc temporary entities
|
||||
//=======================================================================
|
||||
|
||||
#include "extdll.h"
|
||||
#include "utils.h"
|
||||
#include "cbase.h"
|
||||
#include "player.h"
|
||||
|
||||
//=======================================================================
|
||||
// sparkleent - explode post sparks
|
||||
//=======================================================================
|
||||
class CEnvShower : public CBaseEntity
|
||||
{
|
||||
void Spawn( void );
|
||||
void Think( void );
|
||||
void Touch( CBaseEntity *pOther );
|
||||
int ObjectCaps( void ) { return FCAP_DONT_SAVE; }
|
||||
};
|
||||
LINK_ENTITY_TO_CLASS( sparkleent, CEnvShower );
|
||||
|
||||
void CEnvShower::Spawn( void )
|
||||
{
|
||||
pev->velocity = RANDOM_FLOAT( 200, 300 ) * pev->angles;
|
||||
pev->velocity.x += RANDOM_FLOAT(-100.f,100.f);
|
||||
pev->velocity.y += RANDOM_FLOAT(-100.f,100.f);
|
||||
if ( pev->velocity.z >= 0 ) pev->velocity.z += 200;
|
||||
else pev->velocity.z -= 200;
|
||||
pev->movetype = MOVETYPE_BOUNCE;
|
||||
pev->gravity = 0.5;
|
||||
SetNextThink( 0.1 );
|
||||
pev->solid = SOLID_NOT;
|
||||
UTIL_SetModel( edict(), "models/common/null.mdl");
|
||||
UTIL_SetSize(pev, g_vecZero, g_vecZero );
|
||||
pev->effects |= EF_NODRAW;
|
||||
pev->speed = RANDOM_FLOAT( 0.5, 1.5 );
|
||||
pev->angles = g_vecZero;
|
||||
}
|
||||
|
||||
void CEnvShower::Think( void )
|
||||
{
|
||||
UTIL_Sparks( pev->origin );
|
||||
|
||||
pev->speed -= 0.1;
|
||||
if ( pev->speed > 0 ) SetNextThink( 0.1 );
|
||||
else UTIL_Remove( this );
|
||||
pev->flags &= ~FL_ONGROUND;
|
||||
}
|
||||
|
||||
void CEnvShower::Touch( CBaseEntity *pOther )
|
||||
{
|
||||
if ( pev->flags & FL_ONGROUND )
|
||||
pev->velocity = pev->velocity * 0.1;
|
||||
else pev->velocity = pev->velocity * 0.6;
|
||||
if ( (pev->velocity.x*pev->velocity.x+pev->velocity.y*pev->velocity.y) < 10.0 ) pev->speed = 0;
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// ChangeLevelFire
|
||||
//====================================================================
|
||||
class ChangeLevelFire : public CBaseLogic
|
||||
{
|
||||
public:
|
||||
void PostActivate( void ) { FireTargets(); UTIL_Remove( this ); }
|
||||
int ObjectCaps( void ) { return CBaseEntity::ObjectCaps() | FCAP_FORCE_TRANSITION; }
|
||||
};
|
||||
LINK_ENTITY_TO_CLASS( fireent, ChangeLevelFire );
|
||||
//=======================================================================
|
||||
// faderent - rendering time effects
|
||||
//=======================================================================
|
||||
class CRenderFxFader : public CBaseLogic
|
||||
{
|
||||
public:
|
||||
void Spawn ( void ) { m_hTarget = CBaseEntity::Instance( pev->owner ); }
|
||||
void Think ( void )
|
||||
{
|
||||
if (((CBaseEntity*)m_hTarget) == NULL)
|
||||
{
|
||||
UTIL_Remove( this );
|
||||
return;
|
||||
}
|
||||
|
||||
float flDegree = (gpGlobals->time - pev->dmgtime)/pev->speed;
|
||||
|
||||
if (flDegree >= 1)
|
||||
{
|
||||
m_hTarget->pev->renderamt = pev->renderamt + pev->health;
|
||||
m_hTarget->pev->rendercolor = pev->rendercolor + pev->movedir;
|
||||
m_hTarget->pev->scale = pev->scale + pev->frags;
|
||||
m_hTarget->pev->framerate = pev->framerate + pev->max_health;
|
||||
UTIL_FireTargets( pev->target, m_hTarget, this, USE_TOGGLE );
|
||||
m_hTarget = NULL;
|
||||
|
||||
SetNextThink( 0.1 );
|
||||
SetThink(Remove);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_hTarget->pev->renderamt = pev->renderamt + pev->health * flDegree;
|
||||
m_hTarget->pev->rendercolor.x = pev->rendercolor.x + pev->movedir.x * flDegree;
|
||||
m_hTarget->pev->rendercolor.y = pev->rendercolor.y + pev->movedir.y * flDegree;
|
||||
m_hTarget->pev->rendercolor.z = pev->rendercolor.z + pev->movedir.z * flDegree;
|
||||
m_hTarget->pev->scale = pev->scale + pev->frags * flDegree;
|
||||
m_hTarget->pev->framerate = pev->framerate + pev->max_health * flDegree;
|
||||
SetNextThink( 0.01 );//fader step
|
||||
}
|
||||
}
|
||||
};
|
||||
LINK_ENTITY_TO_CLASS( faderent, CRenderFxFader );
|
||||
|
||||
//=======================================================================
|
||||
// smokeent - temporary smoke
|
||||
//=======================================================================
|
||||
class CSmokeEnt : public CBaseAnimating
|
||||
{
|
||||
void Spawn( void );
|
||||
void Think( void );
|
||||
};
|
||||
LINK_ENTITY_TO_CLASS( smokeent, CSmokeEnt );
|
||||
|
||||
void CSmokeEnt::Spawn( void )
|
||||
{
|
||||
pev->solid = SOLID_BBOX;
|
||||
pev->movetype = MOVETYPE_NONE;
|
||||
pev->armorvalue = gpGlobals->time;
|
||||
|
||||
if(!pev->team) pev->team = 50;
|
||||
if(pev->team > 250)pev->team = 250;//normalize and remember about random value 0 - 5
|
||||
}
|
||||
|
||||
void CSmokeEnt::Think( void )
|
||||
{
|
||||
if (pev->dmgtime)
|
||||
{
|
||||
if (pev->dmgtime < gpGlobals->time)
|
||||
{
|
||||
UTIL_Remove( this );
|
||||
return;
|
||||
}
|
||||
else if (RANDOM_FLOAT( 0, pev->dmgtime - pev->armorvalue ) > pev->dmgtime - gpGlobals->time)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Vector VecSrc = UTIL_RandomVector( pev->absmin, pev->absmax );
|
||||
|
||||
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, VecSrc );
|
||||
WRITE_BYTE( TE_SMOKE );
|
||||
WRITE_COORD( VecSrc.x );
|
||||
WRITE_COORD( VecSrc.y );
|
||||
WRITE_COORD( VecSrc.z );
|
||||
WRITE_SHORT( g_sModelIndexSmoke );
|
||||
WRITE_BYTE( RANDOM_LONG(0,5) + pev->impulse ); // scale * 10
|
||||
WRITE_BYTE( RANDOM_LONG(0, 3) + 8 ); // framerate
|
||||
MESSAGE_END();
|
||||
|
||||
StudioFrameAdvance( );//animate model if present
|
||||
SetNextThink( 0.2 );
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
// func_platform floor indicator
|
||||
//=========================================================
|
||||
class CFloorEnt:public CPointEntity
|
||||
{
|
||||
void Think( void );
|
||||
void PostActivate( void );
|
||||
CBasePlatform *pElevator; //no need to save - PostActivate will be restore this
|
||||
};
|
||||
|
||||
void CFloorEnt::PostActivate( void )
|
||||
{
|
||||
pElevator = (CBasePlatform*)CBasePlatform::Instance( pev->owner );
|
||||
SetNextThink( 0 );
|
||||
}
|
||||
|
||||
void CFloorEnt::Think ( void )
|
||||
{
|
||||
if(pElevator && (pElevator->GetState() == STATE_TURN_ON || pElevator->GetState() == STATE_TURN_OFF) )
|
||||
{
|
||||
UTIL_FireTargets( pev->target, pElevator, this, USE_SET, pElevator->CalcFloor());
|
||||
SetNextThink( 0.01 );
|
||||
}
|
||||
else UTIL_Remove( this );
|
||||
}
|
||||
LINK_ENTITY_TO_CLASS( floorent, CFloorEnt );
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Laser pointer target
|
||||
//====================================================================
|
||||
CLaserSpot *CLaserSpot::CreateSpot( void )
|
||||
{
|
||||
CLaserSpot *pSpot = GetClassPtr( (CLaserSpot *)NULL );
|
||||
pSpot->Spawn();
|
||||
pSpot->pev->classname = MAKE_STRING("laserspotent");
|
||||
|
||||
return pSpot;
|
||||
}
|
||||
|
||||
void CLaserSpot::Precache( void )
|
||||
{
|
||||
UTIL_PrecacheModel("sprites/glow02.spr");
|
||||
UTIL_PrecacheSound("weapons/spot_on.wav");
|
||||
UTIL_PrecacheSound("weapons/spot_off.wav");
|
||||
}
|
||||
|
||||
void CLaserSpot::Spawn( void )
|
||||
{
|
||||
Precache( );
|
||||
|
||||
//laser dot settings
|
||||
pev->movetype = MOVETYPE_FLY;
|
||||
pev->solid = SOLID_NOT;
|
||||
pev->scale = 1.0;
|
||||
pev->rendermode = kRenderGlow;
|
||||
pev->renderfx = kRenderFxNoDissipation;
|
||||
pev->renderamt = 255;
|
||||
pev->rendercolor = Vector( 200, 12, 12 );
|
||||
UTIL_SetModel(ENT(pev), "sprites/glow02.spr" );
|
||||
UTIL_SetOrigin( this, pev->origin );
|
||||
}
|
||||
|
||||
void CLaserSpot::Suspend( float flSuspendTime )
|
||||
{
|
||||
pev->effects |= EF_NODRAW;
|
||||
|
||||
// -1 means suspend indefinitely
|
||||
if (flSuspendTime == -1) SetThink( NULL );
|
||||
else
|
||||
{
|
||||
SetThink( Revive );
|
||||
SetNextThink( flSuspendTime );
|
||||
}
|
||||
}
|
||||
|
||||
void CLaserSpot::Revive( void )
|
||||
{
|
||||
pev->effects &= ~EF_NODRAW;
|
||||
SetThink( NULL );
|
||||
}
|
||||
|
||||
void CLaserSpot::Update( CBasePlayer *m_pPlayer )
|
||||
{
|
||||
TraceResult tr;
|
||||
|
||||
UTIL_MakeVectors( m_pPlayer->pev->v_angle );
|
||||
UTIL_TraceLine( m_pPlayer->GetGunPosition(), m_pPlayer->GetGunPosition() + gpGlobals->v_forward * 8192, dont_ignore_monsters, ENT(m_pPlayer->pev), &tr );
|
||||
UTIL_SetOrigin( this, tr.vecEndPos );
|
||||
|
||||
if( UTIL_PointContents( tr.vecEndPos ) & CONTENTS_SKY && VARS(tr.pHit)->solid == SOLID_BSP )
|
||||
{
|
||||
pev->renderamt = 33;
|
||||
pev->effects |= EF_NODRAW;
|
||||
}
|
||||
else
|
||||
{
|
||||
pev->effects &= ~EF_NODRAW;
|
||||
|
||||
float SpotDistance = (tr.vecEndPos - m_pPlayer->GetGunPosition()).Length();
|
||||
int brightness = (1 / log(SpotDistance / 0.3)) * 1300;
|
||||
pev->scale = SpotDistance / 2500 + RANDOM_FLOAT(0.01, SpotDistance/2750);
|
||||
|
||||
if(pev->renderamt >= 255) pev->renderamt = brightness + RANDOM_LONG(1, SpotDistance/400);
|
||||
else pev->renderamt += 5;
|
||||
}
|
||||
}
|
||||
LINK_ENTITY_TO_CLASS( laserspotent, CLaserSpot );
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue