Merge pull request #3803 from shawns-valve/master

SDK changes to match Half-Life 25th Anniversary update
This commit is contained in:
shawns-valve 2024-08-26 22:41:28 -07:00 committed by GitHub
commit b59688c56d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
359 changed files with 44526 additions and 24224 deletions

View file

@ -1,7 +1,7 @@
Half Life 1 SDK LICENSE
======================
Half Life 1 SDK Copyright© Valve Corp.
Half Life 1 SDK Copyright © Valve Corp.
THIS DOCUMENT DESCRIBES A CONTRACT BETWEEN YOU AND VALVE CORPORATION (“Valve”). PLEASE READ IT BEFORE DOWNLOADING OR USING THE HALF LIFE 1 SDK (“SDK”). BY DOWNLOADING AND/OR USING THE SOURCE ENGINE SDK YOU ACCEPT THIS LICENSE. IF YOU DO NOT AGREE TO THE TERMS OF THIS LICENSE PLEASE DONT DOWNLOAD OR USE THE SDK.
@ -37,7 +37,7 @@ If it has not been reported, create a new issue with at least the following info
- a detailed description of the issue, including any output from the command line;
- steps for reproducing the issue;
- your system information.\*; and
- the `version` output from the ingame console.
- the `version` output from the in-game console.
Please place logs either in a code block (press `M` in your browser for a GFM cheat sheet) or a [gist](https://gist.github.com).
@ -55,3 +55,13 @@ There are basic rules of conduct that should be followed at all times by everyon
- Do not repeatedly update an open issue remarking that the issue persists.
Remember: Just because the issue you reported was reported here does not mean that it is an issue with Half-Life. As well, should your issue not be resolved immediately, it does not mean that a resolution is not being researched or tested. Patience is always appreciated.
Building the SDK code
-------
Visual Studio 2019 is required to build mod DLLs on Windows. In the Visual Studio installer, install "Desktop development with C++" under "Workloads" and "C++ MFC for latest v142 build tools (x86 & x64)" under "Individual components". VS2019 projects can be found in the `projects\vs2019` folder.
Tools have not yet been updated for VS2019, but can be built using the VS2010 projects in the `projects\vs2010` folder. See the `readme.txt` file there.
Linux binaries are built using Makefiles found in the `linux` folder, and are expected to be built / run in the Steam Runtime "scout" environment. You will need to set the environment variables VALVE_NO_AUTO_P4=1 and USE_STEAM_RUNTIME=1 while building.

View file

@ -74,10 +74,15 @@ void WeaponsResource :: LoadWeaponSprites( WEAPON *pWeapon )
{
int i, iRes;
if (ScreenWidth < 640)
iRes = 320;
else
if (ScreenWidth > 2560 && ScreenHeight > 1600)
iRes = 2560;
else if (ScreenWidth >= 1280 && ScreenHeight > 720)
iRes = 1280;
else if (ScreenWidth >= 640)
iRes = 640;
else
iRes = 320;
char sz[128];
@ -325,16 +330,17 @@ int CHudAmmo::VidInit(void)
// If we've already loaded weapons, let's get new sprites
gWR.LoadAllWeaponSprites();
if (ScreenWidth >= 640)
{
giABWidth = 20;
giABHeight = 4;
}
else
{
giABWidth = 10;
giABHeight = 2;
}
int nScale = 1;
if (ScreenWidth > 2560 && ScreenHeight > 1600)
nScale = 4;
else if (ScreenWidth >= 1280 && ScreenHeight > 720)
nScale = 3;
else if (ScreenWidth >= 640)
nScale = 2;
giABWidth = 10 * nScale;
giABHeight = 2 * nScale;
return 1;
}
@ -641,7 +647,9 @@ int CHudAmmo::MsgFunc_WeaponList(const char *pszName, int iSize, void *pbuf )
WEAPON Weapon;
strcpy( Weapon.szName, READ_STRING() );
strncpy( Weapon.szName, READ_STRING(), MAX_WEAPON_NAME );
Weapon.szName[ sizeof(Weapon.szName) - 1 ] = '\0';
Weapon.iAmmoType = (int)READ_CHAR();
Weapon.iMax1 = READ_BYTE();
@ -659,6 +667,27 @@ int CHudAmmo::MsgFunc_WeaponList(const char *pszName, int iSize, void *pbuf )
Weapon.iFlags = READ_BYTE();
Weapon.iClip = 0;
if (Weapon.iId < 0 || Weapon.iId >= MAX_WEAPONS)
return 0;
if (Weapon.iSlot < 0 || Weapon.iSlot >= MAX_WEAPON_SLOTS+1)
return 0;
if (Weapon.iSlotPos < 0 || Weapon.iSlotPos >= MAX_WEAPON_POSITIONS+1)
return 0;
if (Weapon.iAmmoType < -1 || Weapon.iAmmoType >= MAX_AMMO_TYPES)
return 0;
if (Weapon.iAmmo2Type < -1 || Weapon.iAmmo2Type >= MAX_AMMO_TYPES)
return 0;
if (Weapon.iAmmoType >= 0 && Weapon.iMax1 == 0)
return 0;
if (Weapon.iAmmo2Type >= 0 && Weapon.iMax2 == 0)
return 0;
gWR.AddWeapon( &Weapon );
return 1;
@ -862,7 +891,7 @@ int CHudAmmo::Draw(float flTime)
AmmoWidth = gHUD.GetSpriteRect(gHUD.m_HUD_number_0).right - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).left;
a = (int) max( MIN_ALPHA, m_fFade );
a = max<int>( MIN_ALPHA, m_fFade );
if (m_fFade > 0)
m_fFade -= (gHUD.m_flTimeDelta * 20);
@ -871,8 +900,8 @@ int CHudAmmo::Draw(float flTime)
ScaleColors(r, g, b, a );
// Does this weapon have a clip?
y = ScreenHeight - gHUD.m_iFontHeight - gHUD.m_iFontHeight/2;
y += (int)(gHUD.m_iFontHeight * 0.2f);
// Does weapon have any ammo at all?
if (m_pWeapon->iAmmoType > 0)
@ -1188,10 +1217,10 @@ client_sprite_t *GetSpriteList(client_sprite_t *pList, const char *psz, int iRes
int i = iCount;
client_sprite_t *p = pList;
while(i--)
{
if ((!strcmp(psz, p->szName)) && (p->iRes == iRes))
if ((p->iRes == iRes) && (!strcmp(psz, p->szName)))
return p;
p++;
}

View file

@ -61,7 +61,7 @@ int CHudAmmoSecondary :: Draw(float flTime)
// draw secondary ammo icons above normal ammo readout
int a, x, y, r, g, b, AmmoWidth;
UnpackRGB( r, g, b, RGB_YELLOWISH );
a = (int) max( MIN_ALPHA, m_fFade );
a = max<int>( MIN_ALPHA, m_fFade );
if (m_fFade > 0)
m_fFade -= (gHUD.m_flTimeDelta * 20); // slowly lower alpha to fade out icons
ScaleColors( r, g, b, a );

View file

@ -126,11 +126,11 @@ int HistoryResource :: DrawAmmoHistory( float flTime )
int r, g, b;
UnpackRGB(r,g,b, RGB_YELLOWISH);
float scale = (rgAmmoHistory[i].DisplayTime - flTime) * 80;
ScaleColors(r, g, b, min(scale, 255) );
ScaleColors(r, g, b, min<int>(scale, 255) );
// Draw the pic
int ypos = ScreenHeight - (AMMO_PICKUP_PICK_HEIGHT + (AMMO_PICKUP_GAP * i));
int xpos = ScreenWidth - 24;
int xpos = ScreenWidth - (rcPic.right - rcPic.left) - 4;
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 );
@ -154,7 +154,7 @@ int HistoryResource :: DrawAmmoHistory( float flTime )
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) );
ScaleColors(r, g, b, min<int>(scale, 255) );
int ypos = ScreenHeight - (AMMO_PICKUP_PICK_HEIGHT + (AMMO_PICKUP_GAP * i));
int xpos = ScreenWidth - (weap->rcInactive.right - weap->rcInactive.left);
@ -172,7 +172,7 @@ int HistoryResource :: DrawAmmoHistory( float flTime )
UnpackRGB(r,g,b, RGB_YELLOWISH);
float scale = (rgAmmoHistory[i].DisplayTime - flTime) * 80;
ScaleColors(r, g, b, min(scale, 255) );
ScaleColors(r, g, b, min<int>(scale, 255) );
int ypos = ScreenHeight - (AMMO_PICKUP_PICK_HEIGHT + (AMMO_PICKUP_GAP * i));
int xpos = ScreenWidth - (rect.right - rect.left) - 10;

View file

@ -134,7 +134,11 @@ int CHudBattery::Draw(float flTime)
int iOffset = (m_prc1->bottom - m_prc1->top)/6;
y = ScreenHeight - gHUD.m_iFontHeight - gHUD.m_iFontHeight / 2;
x = ScreenWidth/5;
int width = (m_prc1->right - m_prc1->left);
// this used to just be ScreenWidth/5 but that caused real issues at higher resolutions. Instead, base it on the width of this sprite.
x = 3 * width;
// make sure we have the right sprite handles
if ( !m_hSprite1 )
@ -151,7 +155,8 @@ int CHudBattery::Draw(float flTime)
SPR_DrawAdditive( 0, x, y - iOffset + (rc.top - m_prc2->top), &rc);
}
x += (m_prc1->right - m_prc1->left);
x += width;
y += (int)(gHUD.m_iFontHeight * 0.2f);
x = gHUD.DrawHudNumber(x, y, DHN_3DIGITS | DHN_DRAWZERO, m_iBat, r, g, b);
return 1;

View file

@ -1,648 +0,0 @@
# Microsoft Developer Studio Project File - Name="cl_dll" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
CFG=cl_dll - 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 "cl_dll.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 "cl_dll.mak" CFG="cl_dll - Win32 Release"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "cl_dll - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE "cl_dll - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
CPP=cl.exe
MTL=midl.exe
RSC=rc.exe
!IF "$(CFG)" == "cl_dll - 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 ".\Release"
# PROP Intermediate_Dir ".\Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
# ADD CPP /nologo /W3 /GR /GX /Zi /O2 /I "..\dlls" /I "." /I "..\tfc" /I "..\public" /I "..\common" /I "..\pm_shared" /I "..\engine" /I "..\utils\vgui\include" /I "..\game_shared" /I "..\external" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "CLIENT_DLL" /D "CLIENT_WEAPONS" /D "HL_DLL" /FR /YX /FD /c
# 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 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib winmm.lib ..\utils\vgui\lib\win32_vc6\vgui.lib wsock32.lib ..\lib\public\sdl2.lib /nologo /base:"0x01900000" /subsystem:windows /dll /map /debug /machine:I386 /nodefaultlib:"LIBCMTD" /nodefaultlib:"LIBCD" /out:".\Release\client.dll"
# SUBTRACT LINK32 /pdb:none
# Begin Custom Build
InputDir=.\Release
ProjDir=.
InputPath=.\Release\client.dll
InputName=client
SOURCE="$(InputPath)"
BuildCmds= \
call ..\filecopy.bat $(InputDir)\$(InputName).dll $(ProjDir)\..\..\game\mod\cl_dlls\$(InputName).dll \
call ..\filecopy.bat $(InputDir)\$(InputName).pdb $(ProjDir)\..\..\game\mod\cl_dlls\$(InputName).pdb \
"$(ProjDir)\..\..\game\mod\cl_dlls\$(InputName).dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
$(BuildCmds)
"$(ProjDir)\..\..\game\mod\cl_dlls\$(InputName).pdb" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
$(BuildCmds)
# End Custom Build
!ELSEIF "$(CFG)" == "cl_dll - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir ".\Debug"
# PROP BASE Intermediate_Dir ".\Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir ".\Debug"
# PROP Intermediate_Dir ".\Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
# ADD CPP /nologo /G5 /MTd /W3 /Gm /GR /GX /ZI /Od /I "..\dlls" /I "." /I "..\tfc" /I "..\public" /I "..\common" /I "..\pm_shared" /I "..\engine" /I "..\utils\vgui\include" /I "..\game_shared" /I "..\external" /D "_DEBUG" /D "_MBCS" /D "WIN32" /D "_WINDOWS" /D "CLIENT_DLL" /D "CLIENT_WEAPONS" /D "_WINDLL" /D "HL_DLL" /FR /YX /FD /c
# ADD BASE MTL /nologo /D "_DEBUG" /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
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 /debug /machine:I386
# ADD LINK32 oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib winmm.lib ..\utils\vgui\lib\win32_vc6\vgui.lib wsock32.lib ..\lib\public\sdl2.lib /nologo /base:"0x01900000" /subsystem:windows /dll /debug /machine:I386 /out:".\Debug\client.dll"
# SUBTRACT LINK32 /pdb:none
# Begin Custom Build
InputDir=.\Debug
ProjDir=.
InputPath=.\Debug\client.dll
InputName=client
SOURCE="$(InputPath)"
BuildCmds= \
call ..\filecopy.bat $(InputDir)\$(InputName).dll $(ProjDir)\..\..\game\mod\cl_dlls\$(InputName).dll \
call ..\filecopy.bat $(InputDir)\$(InputName).pdb $(ProjDir)\..\..\game\mod\cl_dlls\$(InputName).pdb \
"$(ProjDir)\..\..\game\mod\cl_dlls\$(InputName).dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
$(BuildCmds)
"$(ProjDir)\..\..\game\mod\cl_dlls\$(InputName).pdb" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
$(BuildCmds)
# End Custom Build
!ENDIF
# Begin Target
# Name "cl_dll - Win32 Release"
# Name "cl_dll - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;for;f90"
# Begin Group "hl"
# PROP Default_Filter "*.cpp"
# Begin Source File
SOURCE=..\dlls\crossbow.cpp
# End Source File
# Begin Source File
SOURCE=..\dlls\crowbar.cpp
# End Source File
# Begin Source File
SOURCE=..\dlls\egon.cpp
# End Source File
# Begin Source File
SOURCE=.\ev_hldm.cpp
# End Source File
# Begin Source File
SOURCE=..\dlls\gauss.cpp
# End Source File
# Begin Source File
SOURCE=..\dlls\handgrenade.cpp
# End Source File
# Begin Source File
SOURCE=.\hl\hl_baseentity.cpp
# End Source File
# Begin Source File
SOURCE=.\hl\hl_events.cpp
# End Source File
# Begin Source File
SOURCE=.\hl\hl_objects.cpp
# End Source File
# Begin Source File
SOURCE=.\hl\hl_weapons.cpp
# End Source File
# Begin Source File
SOURCE=..\dlls\wpn_shared\hl_wpn_glock.cpp
# End Source File
# Begin Source File
SOURCE=..\dlls\hornetgun.cpp
# End Source File
# Begin Source File
SOURCE=..\dlls\mp5.cpp
# End Source File
# Begin Source File
SOURCE=..\dlls\python.cpp
# End Source File
# Begin Source File
SOURCE=..\dlls\rpg.cpp
# End Source File
# Begin Source File
SOURCE=..\dlls\satchel.cpp
# End Source File
# Begin Source File
SOURCE=..\dlls\shotgun.cpp
# End Source File
# Begin Source File
SOURCE=..\dlls\squeakgrenade.cpp
# End Source File
# Begin Source File
SOURCE=..\dlls\tripmine.cpp
# End Source File
# End Group
# Begin Source File
SOURCE=.\ammo.cpp
# End Source File
# Begin Source File
SOURCE=.\ammo_secondary.cpp
# End Source File
# Begin Source File
SOURCE=.\ammohistory.cpp
# End Source File
# Begin Source File
SOURCE=.\battery.cpp
# End Source File
# Begin Source File
SOURCE=.\cdll_int.cpp
# End Source File
# Begin Source File
SOURCE=.\com_weapons.cpp
# End Source File
# Begin Source File
SOURCE=.\death.cpp
# End Source File
# Begin Source File
SOURCE=.\demo.cpp
# End Source File
# Begin Source File
SOURCE=.\entity.cpp
!IF "$(CFG)" == "cl_dll - Win32 Release"
!ELSEIF "$(CFG)" == "cl_dll - Win32 Debug"
# ADD CPP /MT
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\ev_common.cpp
# End Source File
# Begin Source File
SOURCE=.\events.cpp
# End Source File
# Begin Source File
SOURCE=.\flashlight.cpp
# End Source File
# Begin Source File
SOURCE=.\GameStudioModelRenderer.cpp
# End Source File
# Begin Source File
SOURCE=.\geiger.cpp
# End Source File
# Begin Source File
SOURCE=.\health.cpp
# End Source File
# Begin Source File
SOURCE=.\hud.cpp
# End Source File
# Begin Source File
SOURCE=.\hud_bench.cpp
# End Source File
# Begin Source File
SOURCE=.\hud_benchtrace.cpp
# End Source File
# Begin Source File
SOURCE=.\hud_msg.cpp
# End Source File
# Begin Source File
SOURCE=.\hud_redraw.cpp
# End Source File
# Begin Source File
SOURCE=.\hud_servers.cpp
# End Source File
# Begin Source File
SOURCE=.\hud_spectator.cpp
# End Source File
# Begin Source File
SOURCE=.\hud_update.cpp
# End Source File
# Begin Source File
SOURCE=.\in_camera.cpp
# End Source File
# Begin Source File
SOURCE=.\input.cpp
# End Source File
# Begin Source File
SOURCE=.\inputw32.cpp
# End Source File
# Begin Source File
SOURCE=..\public\interface.cpp
# End Source File
# Begin Source File
SOURCE=.\interpolation.cpp
# End Source File
# Begin Source File
SOURCE=.\menu.cpp
# End Source File
# Begin Source File
SOURCE=.\message.cpp
# End Source File
# Begin Source File
SOURCE=..\common\parsemsg.cpp
# End Source File
# Begin Source File
SOURCE=..\pm_shared\pm_debug.c
# End Source File
# Begin Source File
SOURCE=..\pm_shared\pm_math.c
# End Source File
# Begin Source File
SOURCE=..\pm_shared\pm_shared.c
# End Source File
# Begin Source File
SOURCE=.\saytext.cpp
# End Source File
# Begin Source File
SOURCE=.\status_icons.cpp
# End Source File
# Begin Source File
SOURCE=.\statusbar.cpp
# End Source File
# Begin Source File
SOURCE=.\studio_util.cpp
# End Source File
# Begin Source File
SOURCE=.\StudioModelRenderer.cpp
# End Source File
# Begin Source File
SOURCE=.\text_message.cpp
# End Source File
# Begin Source File
SOURCE=.\train.cpp
# End Source File
# Begin Source File
SOURCE=.\tri.cpp
# End Source File
# Begin Source File
SOURCE=.\util.cpp
# End Source File
# Begin Source File
SOURCE=..\game_shared\vgui_checkbutton2.cpp
# End Source File
# Begin Source File
SOURCE=.\vgui_ClassMenu.cpp
# End Source File
# Begin Source File
SOURCE=.\vgui_ControlConfigPanel.cpp
# End Source File
# Begin Source File
SOURCE=.\vgui_CustomObjects.cpp
# End Source File
# Begin Source File
SOURCE=..\game_shared\vgui_grid.cpp
# End Source File
# Begin Source File
SOURCE=..\game_shared\vgui_helpers.cpp
# End Source File
# Begin Source File
SOURCE=.\vgui_int.cpp
# End Source File
# Begin Source File
SOURCE=..\game_shared\vgui_listbox.cpp
# End Source File
# Begin Source File
SOURCE=..\game_shared\vgui_loadtga.cpp
# End Source File
# Begin Source File
SOURCE=.\vgui_MOTDWindow.cpp
# End Source File
# Begin Source File
SOURCE=.\vgui_SchemeManager.cpp
# End Source File
# Begin Source File
SOURCE=.\vgui_ScorePanel.cpp
# End Source File
# Begin Source File
SOURCE=..\game_shared\vgui_scrollbar2.cpp
# End Source File
# Begin Source File
SOURCE=.\vgui_ServerBrowser.cpp
# End Source File
# Begin Source File
SOURCE=..\game_shared\vgui_slider2.cpp
# End Source File
# Begin Source File
SOURCE=.\vgui_SpectatorPanel.cpp
# End Source File
# Begin Source File
SOURCE=.\vgui_TeamFortressViewport.cpp
# End Source File
# Begin Source File
SOURCE=.\vgui_TeamMenu.cpp
# End Source File
# Begin Source File
SOURCE=.\view.cpp
# End Source File
# Begin Source File
SOURCE=..\game_shared\voice_banmgr.cpp
# End Source File
# Begin Source File
SOURCE=.\voice_status.cpp
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
# Begin Source File
SOURCE=.\ammo.h
# End Source File
# Begin Source File
SOURCE=.\ammohistory.h
# End Source File
# Begin Source File
SOURCE=.\camera.h
# End Source File
# Begin Source File
SOURCE=.\cl_dll.h
# End Source File
# Begin Source File
SOURCE=.\cl_util.h
# End Source File
# Begin Source File
SOURCE=.\com_weapons.h
# End Source File
# Begin Source File
SOURCE=.\demo.h
# End Source File
# Begin Source File
SOURCE=.\ev_hldm.h
# End Source File
# Begin Source File
SOURCE=.\eventscripts.h
# End Source File
# Begin Source File
SOURCE=.\GameStudioModelRenderer.h
# End Source File
# Begin Source File
SOURCE=.\health.h
# End Source File
# Begin Source File
SOURCE=.\hud.h
# End Source File
# Begin Source File
SOURCE=.\hud_servers.h
# End Source File
# Begin Source File
SOURCE=.\hud_servers_priv.h
# End Source File
# Begin Source File
SOURCE=.\hud_spectator.h
# End Source File
# Begin Source File
SOURCE=.\in_defs.h
# End Source File
# Begin Source File
SOURCE=.\interpolation.h
# End Source File
# Begin Source File
SOURCE=.\kbutton.h
# End Source File
# Begin Source File
SOURCE=..\common\parsemsg.h
# End Source File
# Begin Source File
SOURCE=..\pm_shared\pm_debug.h
# End Source File
# Begin Source File
SOURCE=..\pm_shared\pm_defs.h
# End Source File
# Begin Source File
SOURCE=..\pm_shared\pm_info.h
# End Source File
# Begin Source File
SOURCE=..\pm_shared\pm_materials.h
# End Source File
# Begin Source File
SOURCE=..\pm_shared\pm_movevars.h
# End Source File
# Begin Source File
SOURCE=..\pm_shared\pm_shared.h
# End Source File
# Begin Source File
SOURCE=.\StudioModelRenderer.h
# End Source File
# Begin Source File
SOURCE=.\tri.h
# End Source File
# Begin Source File
SOURCE=.\util_vector.h
# End Source File
# Begin Source File
SOURCE=.\vgui_ControlConfigPanel.h
# End Source File
# Begin Source File
SOURCE=.\vgui_int.h
# End Source File
# Begin Source File
SOURCE=.\vgui_SchemeManager.h
# End Source File
# Begin Source File
SOURCE=.\vgui_ScorePanel.h
# End Source File
# Begin Source File
SOURCE=..\game_shared\vgui_scrollbar2.h
# End Source File
# Begin Source File
SOURCE=.\vgui_ServerBrowser.h
# End Source File
# Begin Source File
SOURCE=..\game_shared\vgui_slider2.h
# End Source File
# Begin Source File
SOURCE=.\vgui_SpectatorPanel.h
# End Source File
# Begin Source File
SOURCE=.\view.h
# End Source File
# Begin Source File
SOURCE=..\game_shared\voice_banmgr.h
# End Source File
# Begin Source File
SOURCE=..\game_shared\voice_status.h
# End Source File
# Begin Source File
SOURCE=.\wrect.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe"
# End Group
# Begin Source File
SOURCE=..\lib\public\game_controls.lib
# End Source File
# End Target
# End Project

View file

@ -83,6 +83,7 @@ inline struct cvar_s *CVAR_CREATE( const char *cv, const char *val, const int fl
#define GetScreenInfo (*gEngfuncs.pfnGetScreenInfo)
#define ServerCmd (*gEngfuncs.pfnServerCmd)
#define EngineClientCmd (*gEngfuncs.pfnClientCmd)
#define EngineFilteredClientCmd (*gEngfuncs.pfnFilteredClientCmd)
#define SetCrosshair (*gEngfuncs.pfnSetCrosshair)
#define AngleVectors (*gEngfuncs.pfnAngleVectors)
@ -162,8 +163,6 @@ inline int safe_sprintf( char *dst, int len_dst, const char *format, ...)
inline void PlaySound( char *szSound, float vol ) { gEngfuncs.pfnPlaySoundByName( szSound, vol ); }
inline void PlaySound( int iSound, float vol ) { gEngfuncs.pfnPlaySoundByIndex( iSound, vol ); }
#define max(a, b) (((a) > (b)) ? (a) : (b))
#define min(a, b) (((a) < (b)) ? (a) : (b))
#define fabs(x) ((x) > 0 ? (x) : 0 - (x))
void ScaleColors( int &r, int &g, int &b, int a );

View file

@ -73,7 +73,7 @@ int CHudDeathNotice :: Init( void )
HOOK_MESSAGE( DeathMsg );
CVAR_CREATE( "hud_deathnotice_time", "6", 0 );
CVAR_CREATE( "hud_deathnotice_time", "6", FCVAR_ARCHIVE );
return 1;
}
@ -94,7 +94,12 @@ int CHudDeathNotice :: VidInit( void )
int CHudDeathNotice :: Draw( float flTime )
{
int x, y, r, g, b;
int x, y, r, g, b, texty;
int gap = 20;
wrect_t& sprite = gHUD.GetSpriteRect(m_HUD_d_skull);
gap = sprite.bottom - sprite.top;
for ( int i = 0; i < MAX_DEATHNOTICES; i++ )
{
@ -115,10 +120,12 @@ int CHudDeathNotice :: Draw( float flTime )
if ( gViewPort && gViewPort->AllowedToPrintText() )
{
// Draw the death notice
y = DEATHNOTICE_TOP + 2 + (20 * i); //!!!
y = DEATHNOTICE_TOP + 2 + (gap * i);
texty = y + 4;
int id = (rgDeathNoticeList[i].iId == -1) ? m_HUD_d_skull : rgDeathNoticeList[i].iId;
x = ScreenWidth - ConsoleStringLen(rgDeathNoticeList[i].szVictim) - (gHUD.GetSpriteRect(id).right - gHUD.GetSpriteRect(id).left);
x = ScreenWidth - ConsoleStringLen(rgDeathNoticeList[i].szVictim) - (gHUD.GetSpriteRect(id).right - gHUD.GetSpriteRect(id).left) - 4;
if ( !rgDeathNoticeList[i].iSuicide )
{
@ -127,7 +134,7 @@ int CHudDeathNotice :: Draw( float flTime )
// Draw killers name
if ( rgDeathNoticeList[i].KillerColor )
gEngfuncs.pfnDrawSetTextColor( rgDeathNoticeList[i].KillerColor[0], rgDeathNoticeList[i].KillerColor[1], rgDeathNoticeList[i].KillerColor[2] );
x = 5 + DrawConsoleString( x, y, rgDeathNoticeList[i].szKiller );
x = 5 + DrawConsoleString( x, texty, rgDeathNoticeList[i].szKiller );
}
r = 255; g = 80; b = 0;
@ -147,7 +154,7 @@ int CHudDeathNotice :: Draw( float flTime )
{
if ( rgDeathNoticeList[i].VictimColor )
gEngfuncs.pfnDrawSetTextColor( rgDeathNoticeList[i].VictimColor[0], rgDeathNoticeList[i].VictimColor[1], rgDeathNoticeList[i].VictimColor[2] );
x = DrawConsoleString( x, y, rgDeathNoticeList[i].szVictim );
x = DrawConsoleString( x, texty, rgDeathNoticeList[i].szVictim );
}
}
}

View file

@ -97,6 +97,7 @@ float EV_HLDM_PlayTextureSound( int idx, pmtrace_t *ptr, float *vecSrc, float *v
{
// hit the world, try to play sound based on texture material type
char chTextureType = CHAR_TEX_CONCRETE;
cl_entity_t *cl_entity = NULL;
float fvol;
float fvolbar;
char *rgsz[4];
@ -115,12 +116,7 @@ float EV_HLDM_PlayTextureSound( int idx, pmtrace_t *ptr, float *vecSrc, float *v
chTextureType = 0;
// Player
if ( entity >= 1 && entity <= gEngfuncs.GetMaxClients() )
{
// hit body
chTextureType = CHAR_TEX_FLESH;
}
else if ( entity == 0 )
if ( entity == 0 )
{
// get texture from entity or world (world is ent(0))
pTextureName = (char *)gEngfuncs.pEventAPI->EV_TraceTexture( ptr->ent, vecSrc, vecEnd );
@ -149,6 +145,20 @@ float EV_HLDM_PlayTextureSound( int idx, pmtrace_t *ptr, float *vecSrc, float *v
chTextureType = PM_FindTextureType( szbuffer );
}
}
else
{
// JoshA: Look up the entity and find the EFLAG_FLESH_SOUND flag.
// This broke at some point then TF:C added prediction.
//
// It used to use Classify of pEntity->Classify() != CLASS_NONE && pEntity->Classify() != CLASS_MACHINE
// to determine what sound to play, but that's server side and isn't available on the client
// and got lost in the translation to that.
// Now the server will replicate that state via an eflag.
cl_entity = gEngfuncs.GetEntityByIndex( entity );
if ( cl_entity && !!( cl_entity->curstate.eflags & EFLAG_FLESH_SOUND ) )
chTextureType = CHAR_TEX_FLESH;
}
switch (chTextureType)
{
@ -400,7 +410,16 @@ void EV_HLDM_FireBullets( int idx, float *forward, float *right, float *up, int
gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 );
gEngfuncs.pEventAPI->EV_SetTraceHull( 2 );
gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecEnd, PM_STUDIO_BOX, -1, &tr );
// JoshA: Changed from PM_STUDIO_BOX to PM_NORMAL in prediction code as otherwise if you hit an NPC or player's
// bounding box but not one of their hitboxes, the shot won't hit on the server but it will
// play a hit sound on the client and not make a decal (as if it hit the NPC/player).
// We should mirror the way the server does the test here as close as possible.
//
// I initially thought I was just fixing some stupid Half-Life bug but no,
// this is *the* root cause of all the ghost shot bad prediction bugs in Half-Life Deathmatch!
//
// Also... CStrike was always using PM_NORMAL for all of these so it didn't have the problem.
gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecEnd, PM_NORMAL, -1, &tr );
tracer = EV_HLDM_CheckTracer( idx, vecSrc, tr.endpos, forward, right, iBulletType, iTracerFreq, tracerCount );
@ -912,7 +931,7 @@ void EV_FireGauss( event_args_t *args )
gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 );
gEngfuncs.pEventAPI->EV_SetTraceHull( 2 );
gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecDest, PM_STUDIO_BOX, -1, &tr );
gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecDest, PM_NORMAL, -1, &tr );
gEngfuncs.pEventAPI->EV_PopPMStates();
@ -1034,7 +1053,7 @@ void EV_FireGauss( event_args_t *args )
gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 );
gEngfuncs.pEventAPI->EV_SetTraceHull( 2 );
gEngfuncs.pEventAPI->EV_PlayerTrace( start, vecDest, PM_STUDIO_BOX, -1, &beam_tr );
gEngfuncs.pEventAPI->EV_PlayerTrace( start, vecDest, PM_NORMAL, -1, &beam_tr );
if ( !beam_tr.allsolid )
{
@ -1043,7 +1062,7 @@ void EV_FireGauss( event_args_t *args )
// trace backwards to find exit point
gEngfuncs.pEventAPI->EV_PlayerTrace( beam_tr.endpos, tr.endpos, PM_STUDIO_BOX, -1, &beam_tr );
gEngfuncs.pEventAPI->EV_PlayerTrace( beam_tr.endpos, tr.endpos, PM_NORMAL, -1, &beam_tr );
VectorSubtract( beam_tr.endpos, tr.endpos, delta );
@ -1239,7 +1258,7 @@ void EV_FireCrossbow2( event_args_t *args )
// Now add in all of the players.
gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 );
gEngfuncs.pEventAPI->EV_SetTraceHull( 2 );
gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecEnd, PM_STUDIO_BOX, -1, &tr );
gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecEnd, PM_NORMAL, -1, &tr );
//We hit something
if ( tr.fraction < 1.0 )
@ -1444,7 +1463,7 @@ void EV_EgonFire( event_args_t *args )
gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 );
gEngfuncs.pEventAPI->EV_SetTraceHull( 2 );
gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecEnd, PM_STUDIO_BOX, -1, &tr );
gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecEnd, PM_NORMAL, -1, &tr );
gEngfuncs.pEventAPI->EV_PopPMStates();

View file

@ -68,10 +68,14 @@ int CHudGeiger::Draw (float flTime)
int rg[3];
int i;
if (m_iGeigerRange <= 800 && m_iGeigerRange > 0)
if (m_iGeigerRange < 1000 && m_iGeigerRange > 0)
{
// peicewise linear is better than continuous formula for this
if (m_iGeigerRange > 600)
if (m_iGeigerRange > 800)
{
pct = 0; //Con_Printf ( "range > 800\n");
}
else if (m_iGeigerRange > 600)
{
pct = 2;
flvol = 0.4; //Con_Printf ( "range > 600\n");

View file

@ -217,6 +217,7 @@ int CHudHealth::Draw(float flTime)
SPR_DrawAdditive(0, x, y, &gHUD.GetSpriteRect(m_HUD_cross));
x = CrossWidth + HealthWidth / 2;
y += (int)(gHUD.m_iFontHeight * 0.2f);
x = gHUD.DrawHudNumber(x, y, DHN_3DIGITS | DHN_DRAWZERO, m_iHealth, r, g, b);
@ -307,49 +308,49 @@ int CHudHealth::DrawPain(float flTime)
if (m_fAttackFront > 0.4)
{
GetPainColor(r,g,b);
shade = a * max( m_fAttackFront, 0.5 );
shade = a * max( m_fAttackFront, 0.5f );
ScaleColors(r, g, b, shade);
SPR_Set(m_hSprite, r, g, b );
x = ScreenWidth/2 - SPR_Width(m_hSprite, 0)/2;
y = ScreenHeight/2 - SPR_Height(m_hSprite,0) * 3;
SPR_DrawAdditive(0, x, y, NULL);
m_fAttackFront = max( 0, m_fAttackFront - fFade );
m_fAttackFront = max( 0.0f, m_fAttackFront - fFade );
} else
m_fAttackFront = 0;
if (m_fAttackRight > 0.4)
{
GetPainColor(r,g,b);
shade = a * max( m_fAttackRight, 0.5 );
shade = a * max( m_fAttackRight, 0.5f );
ScaleColors(r, g, b, shade);
SPR_Set(m_hSprite, r, g, b );
x = ScreenWidth/2 + SPR_Width(m_hSprite, 1) * 2;
y = ScreenHeight/2 - SPR_Height(m_hSprite,1)/2;
SPR_DrawAdditive(1, x, y, NULL);
m_fAttackRight = max( 0, m_fAttackRight - fFade );
m_fAttackRight = max( 0.0f, m_fAttackRight - fFade );
} else
m_fAttackRight = 0;
if (m_fAttackRear > 0.4)
{
GetPainColor(r,g,b);
shade = a * max( m_fAttackRear, 0.5 );
shade = a * max( m_fAttackRear, 0.5f );
ScaleColors(r, g, b, shade);
SPR_Set(m_hSprite, r, g, b );
x = ScreenWidth/2 - SPR_Width(m_hSprite, 2)/2;
y = ScreenHeight/2 + SPR_Height(m_hSprite,2) * 2;
SPR_DrawAdditive(2, x, y, NULL);
m_fAttackRear = max( 0, m_fAttackRear - fFade );
m_fAttackRear = max( 0.0f, m_fAttackRear - fFade );
} else
m_fAttackRear = 0;
if (m_fAttackLeft > 0.4)
{
GetPainColor(r,g,b);
shade = a * max( m_fAttackLeft, 0.5 );
shade = a * max( m_fAttackLeft, 0.5f );
ScaleColors(r, g, b, shade);
SPR_Set(m_hSprite, r, g, b );
@ -357,7 +358,7 @@ int CHudHealth::DrawPain(float flTime)
y = ScreenHeight/2 - SPR_Height(m_hSprite,3)/2;
SPR_DrawAdditive(3, x, y, NULL);
m_fAttackLeft = max( 0, m_fAttackLeft - fFade );
m_fAttackLeft = max( 0.0f, m_fAttackLeft - fFade );
} else
m_fAttackLeft = 0;

View file

@ -86,7 +86,9 @@ void ClientPrint( entvars_t *client, int msg_dest, const char *msg_name, const c
int CBaseToggle::Restore( class CRestore & ) { return 1; }
int CBaseToggle::Save( class CSave & ) { return 1; }
void CBaseToggle :: KeyValue( struct KeyValueData_s * ) { }
void CBaseToggle::PlaySentence( const char *pszSentence, float duration, float volume, float attenuation ) { }
void CBaseToggle::PlayScriptedSentence( const char *pszSentence, float duration, float volume, float attenuation, BOOL bConcurrent, CBaseEntity *pListener ) { }
void CBaseToggle::SentenceStop( void ) { }
// CGrenade Stubs
void CGrenade::BounceSound( void ) { }
void CGrenade::Explode( Vector, Vector ) { }
@ -206,9 +208,6 @@ BOOL CBaseMonster :: FindLateralCover ( const Vector &vecThreat, const Vector &v
Vector CBaseMonster :: ShootAtEnemy( const Vector &shootOrigin ) { return g_vecZero; }
BOOL CBaseMonster :: FacingIdeal( void ) { return FALSE; }
BOOL CBaseMonster :: FCanActiveIdle ( void ) { return FALSE; }
void CBaseMonster::PlaySentence( const char *pszSentence, float duration, float volume, float attenuation ) { }
void CBaseMonster::PlayScriptedSentence( const char *pszSentence, float duration, float volume, float attenuation, BOOL bConcurrent, CBaseEntity *pListener ) { }
void CBaseMonster::SentenceStop( void ) { }
void CBaseMonster::CorpseFallThink( void ) { }
void CBaseMonster :: MonsterInitDead( void ) { }
BOOL CBaseMonster :: BBoxFlat ( void ) { return TRUE; }

View file

@ -1,4 +1,4 @@
/***
/***
*
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
*
@ -811,6 +811,8 @@ void HUD_WeaponsPostThink( local_state_s *from, local_state_s *to, usercmd_t *cm
player.m_afButtonPressed = buttonsChanged & cmd->buttons;
// The ones not down are "released"
player.m_afButtonReleased = buttonsChanged & (~cmd->buttons);
player.pev->v_angle = cmd->viewangles;
player.pev->origin = from->client.origin;
// Set player variables that weapons code might check/alter
player.pev->button = cmd->buttons;

View file

@ -81,7 +81,8 @@ static CHLVoiceStatusHelper g_VoiceStatusHelper;
extern client_sprite_t *GetSpriteList(client_sprite_t *pList, const char *psz, int iRes, int iCount);
extern cvar_t *sensitivity;
extern float IN_GetMouseSensitivity();
cvar_t *cl_lw = NULL;
void ShutdownInput (void);
@ -326,8 +327,9 @@ void CHud :: Init( void )
m_iLogo = 0;
m_iFOV = 0;
CVAR_CREATE( "zoom_sensitivity_ratio", "1.2", 0 );
default_fov = CVAR_CREATE( "default_fov", "90", 0 );
CVAR_CREATE( "zoom_sensitivity_ratio", "1.2", FCVAR_ARCHIVE );
CVAR_CREATE( "cl_autowepswitch", "1", FCVAR_USERINFO|FCVAR_ARCHIVE );
default_fov = CVAR_CREATE( "default_fov", "90", FCVAR_ARCHIVE );
m_pCvarStealMouse = CVAR_CREATE( "hud_capturemouse", "1", FCVAR_ARCHIVE );
m_pCvarDraw = CVAR_CREATE( "hud_draw", "1", FCVAR_ARCHIVE );
cl_lw = gEngfuncs.pfnGetCvarPointer( "cl_lw" );
@ -371,6 +373,9 @@ void CHud :: Init( void )
ServersInit();
MsgFunc_ResetHUD(0, 0, NULL );
gEngfuncs.pfnClientCmd("richpresence_gamemode\n"); // reset
gEngfuncs.pfnClientCmd("richpresence_update\n");
}
// CHud destructor
@ -425,10 +430,15 @@ void CHud :: VidInit( void )
m_hsprLogo = 0;
m_hsprCursor = 0;
if (ScreenWidth < 640)
m_iRes = 320;
else
if (ScreenWidth > 2560 && ScreenHeight > 1600)
m_iRes = 2560;
else if (ScreenWidth >= 1280 && ScreenHeight > 720)
m_iRes = 1280;
else if (ScreenWidth >= 640)
m_iRes = 640;
else
m_iRes = 320;
// Only load this once
if ( !m_pSpriteList )
@ -653,7 +663,7 @@ int CHud::MsgFunc_SetFOV(const char *pszName, int iSize, void *pbuf)
else
{
// set a new sensitivity that is proportional to the change from the FOV default
m_flMouseSensitivity = sensitivity->value * ((float)newfov / (float)def_fov) * CVAR_GET_FLOAT("zoom_sensitivity_ratio");
m_flMouseSensitivity = IN_GetMouseSensitivity() * ((float)newfov / (float)def_fov) * CVAR_GET_FLOAT("zoom_sensitivity_ratio");
}
return 1;

View file

@ -438,6 +438,7 @@ private:
int m_HUD_title_life;
int m_HUD_title_half;
bool m_bEndAfterMessage;
};
//

View file

@ -146,8 +146,8 @@ int CHudBenchmark::MsgFunc_Bench(const char *pszName, int iSize, void *pbuf)
m_fReceiveTime = gHUD.m_flTime;
m_StoredLatency = ( m_fReceiveTime - m_fSendTime );
m_StoredLatency = min( 1.0, m_StoredLatency );
m_StoredLatency = max( 0.0, m_StoredLatency );
m_StoredLatency = min( 1.0f, m_StoredLatency );
m_StoredLatency = max( 0.0f, m_StoredLatency );
m_StoredPacketLoss = 0.0;
@ -286,8 +286,8 @@ void CHudBenchmark::Think( void )
float switch_time;
float total_time;
latency = max( 0.0, latency );
latency = min( 1.0, latency );
latency = max( 0.0f, latency );
latency = min( 1.0f, latency );
total_time = Bench_GetSwitchTime();
total_time -= 2.0;
@ -341,8 +341,8 @@ void CHudBenchmark::Think( void )
// Only takes 1/2 time to get up to maximum speed
frac *= 2.0;
frac = max( 0.0, frac );
frac = min( 1.0, frac );
frac = max( 0.0f, frac );
frac = min( 1.0f, frac );
m_nObjects = (int)(NUM_BENCH_OBJ * frac);
}

View file

@ -101,6 +101,13 @@ int CHud :: MsgFunc_GameMode(const char *pszName, int iSize, void *pbuf )
BEGIN_READ( pbuf, iSize );
m_Teamplay = READ_BYTE();
if ( m_Teamplay )
gEngfuncs.pfnClientCmd("richpresence_gamemode Teamplay\n");
else
gEngfuncs.pfnClientCmd("richpresence_gamemode\n"); // reset
gEngfuncs.pfnClientCmd("richpresence_update\n");
return 1;
}

View file

@ -36,7 +36,7 @@ extern int g_iVisibleMouse;
float HUD_GetFOV( void );
extern cvar_t *sensitivity;
extern float IN_GetMouseSensitivity();
// Think
void CHud::Think(void)
@ -75,13 +75,13 @@ void CHud::Think(void)
else
{
// set a new sensitivity that is proportional to the change from the FOV default
m_flMouseSensitivity = sensitivity->value * ((float)newfov / (float)default_fov->value) * CVAR_GET_FLOAT("zoom_sensitivity_ratio");
m_flMouseSensitivity = IN_GetMouseSensitivity() * ( (float)newfov / (float) max<int>( default_fov->value, 90 ) ) * CVAR_GET_FLOAT("zoom_sensitivity_ratio");
}
// 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( default_fov->value, 90 );
m_iFOV = max<int>( default_fov->value, 90 );
}
if ( gEngfuncs.IsSpectateOnly() )

View file

@ -1,4 +1,4 @@
//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============
//========= Copyright <EFBFBD> 1996-2001, Valve LLC, All rights reserved. ============
//
// Purpose:
//
@ -210,7 +210,8 @@ void UTIL_StringToVector( float * pVector, const char *pString )
char *pstr, *pfront, tempString[128];
int j;
strcpy( tempString, pString );
strncpy( tempString, pString, sizeof( tempString ) );
tempString[ sizeof( tempString ) - 1 ] = '\0';
pstr = pfront = tempString;
for ( j = 0; j < 3; j++ )
@ -812,7 +813,7 @@ void CHudSpectator::DirectorMessage( int iSize, void *pbuf )
break;
case DRC_CMD_STUFFTEXT:
EngineClientCmd( READ_STRING() );
EngineFilteredClientCmd( READ_STRING() );
break;
case DRC_CMD_CAMPATH:

View file

@ -23,6 +23,7 @@
#include "view.h"
#include "Exports.h"
#include <SDL2/SDL_events.h>
#include <SDL2/SDL_mouse.h>
#include <SDL2/SDL_gamecontroller.h>
@ -55,8 +56,6 @@ extern cvar_t *cl_pitchspeed;
extern cvar_t *cl_movespeedkey;
static double s_flRawInputUpdateTime = 0.0f;
static bool m_bRawInput = false;
static bool m_bMouseThread = false;
extern globalvars_t *gpGlobals;
@ -78,6 +77,13 @@ static cvar_t *m_customaccel_exponent;
// if threaded mouse is enabled then the time to sleep between polls
static cvar_t *m_mousethread_sleep;
static cvar_t* m_rawinput = nullptr;
static bool IN_UseRawInput()
{
return m_rawinput ? ( m_rawinput->value != 0 ) : false;
}
int mouse_buttons;
int mouse_oldbuttonstate;
POINT current_pos;
@ -138,6 +144,7 @@ cvar_t *joy_advaxisz;
cvar_t *joy_advaxisr;
cvar_t *joy_advaxisu;
cvar_t *joy_advaxisv;
cvar_t *joy_supported;
cvar_t *joy_forwardthreshold;
cvar_t *joy_sidethreshold;
cvar_t *joy_pitchthreshold;
@ -149,7 +156,7 @@ cvar_t *joy_yawsensitivity;
cvar_t *joy_wwhack1;
cvar_t *joy_wwhack2;
int joy_avail, joy_advancedinit, joy_haspov;
int joy_avail = 0, joy_advancedinit, joy_haspov;
#ifdef _WIN32
DWORD s_hMouseThreadId = 0;
@ -158,6 +165,7 @@ HANDLE s_hMouseQuitEvent = 0;
HANDLE s_hMouseDoneQuitEvent = 0;
#endif
/*
===========
Force_CenterView_f
@ -344,6 +352,28 @@ void IN_GetMousePos( int *mx, int *my )
gEngfuncs.GetMousePosition( mx, my );
}
/*
===========
IN_GetMouseSensitivity
Get mouse sensitivity with sanitization
===========
*/
float IN_GetMouseSensitivity()
{
// Absurdly high sensitivity values can cause the game to hang, so clamp
if ( sensitivity->value > 10000.0 )
{
gEngfuncs.Cvar_SetValue( "sensitivity", 10000.0 );
}
else if ( sensitivity->value < 0.01 )
{
gEngfuncs.Cvar_SetValue( "sensitivity", 0.01 );
}
return sensitivity->value;
}
/*
===========
IN_ResetMouse
@ -355,22 +385,33 @@ void IN_ResetMouse( void )
{
// no work to do in SDL
#ifdef _WIN32
if ( !m_bRawInput && mouseactive && gEngfuncs.GetWindowCenterX && gEngfuncs.GetWindowCenterY )
if ( !IN_UseRawInput() && mouseactive && gEngfuncs.GetWindowCenterX && gEngfuncs.GetWindowCenterY )
{
SetCursorPos ( gEngfuncs.GetWindowCenterX(), gEngfuncs.GetWindowCenterY() );
ThreadInterlockedExchange( &old_mouse_pos.x, gEngfuncs.GetWindowCenterX() );
ThreadInterlockedExchange( &old_mouse_pos.y, gEngfuncs.GetWindowCenterY() );
}
if ( gpGlobals && gpGlobals->time - s_flRawInputUpdateTime > 1.0f )
{
s_flRawInputUpdateTime = gpGlobals->time;
m_bRawInput = CVAR_GET_FLOAT( "m_rawinput" ) != 0;
}
#endif
}
/*
===========
IN_ResetRelativeMouseState
===========
*/
void IN_ResetRelativeMouseState(void)
{
if ( IN_UseRawInput() )
{
SDL_PumpEvents();
int deltaX, deltaY;
SDL_GetRelativeMouseState(&deltaX, &deltaY);
}
}
/*
===========
IN_MouseEvent
@ -414,7 +455,7 @@ void IN_ScaleMouse( float *x, float *y )
float my = *y;
// This is the default sensitivity
float mouse_senstivity = ( gHUD.GetSensitivity() != 0 ) ? gHUD.GetSensitivity() : sensitivity->value;
float mouse_senstivity = ( gHUD.GetSensitivity() != 0 ) ? gHUD.GetSensitivity() : IN_GetMouseSensitivity();
// Using special accleration values
if ( m_customaccel->value != 0 )
@ -474,7 +515,7 @@ void IN_MouseMove ( float frametime, usercmd_t *cmd)
{
int deltaX, deltaY;
#ifdef _WIN32
if ( !m_bRawInput )
if ( !IN_UseRawInput() )
{
if ( m_bMouseThread )
{
@ -497,7 +538,7 @@ void IN_MouseMove ( float frametime, usercmd_t *cmd)
}
#ifdef _WIN32
if ( !m_bRawInput )
if ( !IN_UseRawInput() )
{
if ( m_bMouseThread )
{
@ -598,7 +639,7 @@ void CL_DLLEXPORT IN_Accumulate (void)
if (mouseactive)
{
#ifdef _WIN32
if ( !m_bRawInput )
if ( !IN_UseRawInput() )
{
if ( !m_bMouseThread )
{
@ -649,41 +690,56 @@ void IN_StartupJoystick (void)
// abort startup if user requests no joystick
if ( gEngfuncs.CheckParm ("-nojoy", NULL ) )
return;
// assume no joystick
joy_avail = 0;
static float flLastCheck = 0.0f;
if ( flLastCheck > 0.0f && (gEngfuncs.GetAbsoluteTime()-flLastCheck) < 1.0f )
return;
//gEngfuncs.Con_Printf("IN_StartupJoystick, %f\n", flLastCheck);
flLastCheck = gEngfuncs.GetAbsoluteTime();
int nJoysticks = SDL_NumJoysticks();
if ( nJoysticks > 0 )
{
for ( int i = 0; i < nJoysticks; i++ )
if ( s_pJoystick == NULL )
{
if ( SDL_IsGameController( i ) )
for ( int i = 0; i < nJoysticks; i++ )
{
s_pJoystick = SDL_GameControllerOpen( i );
if ( s_pJoystick )
if ( SDL_IsGameController( i ) )
{
//save the joystick's number of buttons and POV status
joy_numbuttons = SDL_CONTROLLER_BUTTON_MAX;
joy_haspov = 0;
// old button and POV states default to no buttons pressed
joy_oldbuttonstate = joy_oldpovstate = 0;
// mark the joystick as available and advanced initialization not completed
// this is needed as cvars are not available during initialization
gEngfuncs.Con_Printf ("joystick found\n\n", SDL_GameControllerName(s_pJoystick));
joy_avail = 1;
joy_advancedinit = 0;
break;
}
s_pJoystick = SDL_GameControllerOpen( i );
if ( s_pJoystick )
{
//save the joystick's number of buttons and POV status
joy_numbuttons = SDL_CONTROLLER_BUTTON_MAX;
joy_haspov = 0;
// old button and POV states default to no buttons pressed
joy_oldbuttonstate = joy_oldpovstate = 0;
// mark the joystick as available and advanced initialization not completed
// this is needed as cvars are not available during initialization
gEngfuncs.Con_Printf ("joystick found %s\n\n", SDL_GameControllerName(s_pJoystick));
joy_avail = 1;
joy_advancedinit = 0;
break;
}
}
}
}
}
else
{
gEngfuncs.Con_DPrintf ("joystick not found -- driver not present\n\n");
if ( s_pJoystick )
SDL_GameControllerClose( s_pJoystick );
s_pJoystick = NULL;
if ( joy_avail )
{
joy_avail = 0;
gEngfuncs.Con_DPrintf ("joystick not found -- driver not present\n\n");
}
}
}
@ -806,12 +862,14 @@ void IN_Commands (void)
{
key_index = (i < 4) ? K_JOY1 : K_AUX1;
gEngfuncs.Key_Event (key_index + i, 1);
//gEngfuncs.Con_Printf ("Button %d pressed\n", i);
}
if ( !(buttonstate & (1<<i)) && (joy_oldbuttonstate & (1<<i)) )
{
key_index = (i < 4) ? K_JOY1 : K_AUX1;
gEngfuncs.Key_Event (key_index + i, 0);
//gEngfuncs.Con_Printf ("Button %d released\n", i);
}
}
joy_oldbuttonstate = buttonstate;
@ -875,6 +933,9 @@ void IN_JoyMove ( float frametime, usercmd_t *cmd )
joy_advancedinit = 1;
}
// re-scan for joystick presence
IN_StartupJoystick();
// verify joystick is available and that the user wants to use it
if (!joy_avail || !in_joystick->value)
{
@ -1062,7 +1123,7 @@ IN_Init
void IN_Init (void)
{
m_filter = gEngfuncs.pfnRegisterVariable ( "m_filter","0", FCVAR_ARCHIVE );
sensitivity = gEngfuncs.pfnRegisterVariable ( "sensitivity","3", FCVAR_ARCHIVE ); // user mouse sensitivity setting.
sensitivity = gEngfuncs.pfnRegisterVariable ( "sensitivity","3", FCVAR_ARCHIVE | FCVAR_FILTERSTUFFTEXT ); // user mouse sensitivity setting.
in_joystick = gEngfuncs.pfnRegisterVariable ( "joystick","0", FCVAR_ARCHIVE );
joy_name = gEngfuncs.pfnRegisterVariable ( "joyname", "joystick", 0 );
@ -1073,6 +1134,7 @@ void IN_Init (void)
joy_advaxisr = gEngfuncs.pfnRegisterVariable ( "joyadvaxisr", "0", 0 );
joy_advaxisu = gEngfuncs.pfnRegisterVariable ( "joyadvaxisu", "0", 0 );
joy_advaxisv = gEngfuncs.pfnRegisterVariable ( "joyadvaxisv", "0", 0 );
joy_supported = gEngfuncs.pfnRegisterVariable ( "joysupported", "1", 0 );
joy_forwardthreshold = gEngfuncs.pfnRegisterVariable ( "joyforwardthreshold", "0.15", 0 );
joy_sidethreshold = gEngfuncs.pfnRegisterVariable ( "joysidethreshold", "0.15", 0 );
joy_pitchthreshold = gEngfuncs.pfnRegisterVariable ( "joypitchthreshold", "0.15", 0 );
@ -1089,12 +1151,13 @@ void IN_Init (void)
m_customaccel_max = gEngfuncs.pfnRegisterVariable ( "m_customaccel_max", "0", FCVAR_ARCHIVE );
m_customaccel_exponent = gEngfuncs.pfnRegisterVariable ( "m_customaccel_exponent", "1", FCVAR_ARCHIVE );
m_rawinput = gEngfuncs.pfnGetCvarPointer("m_rawinput");
#ifdef _WIN32
m_bRawInput = CVAR_GET_FLOAT( "m_rawinput" ) > 0;
m_bMouseThread = gEngfuncs.CheckParm ("-mousethread", NULL ) != NULL;
m_mousethread_sleep = gEngfuncs.pfnRegisterVariable ( "m_mousethread_sleep", "10", FCVAR_ARCHIVE );
if ( !m_bRawInput && m_bMouseThread && m_mousethread_sleep )
if ( !IN_UseRawInput() && m_bMouseThread && m_mousethread_sleep )
{
s_mouseDeltaX = s_mouseDeltaY = 0;

View file

@ -143,6 +143,10 @@ int CHudMenu :: Draw( float flTime )
if ( gViewPort && gViewPort->IsScoreBoardVisible() )
return 1;
SCREENINFO screenInfo;
screenInfo.iSize = sizeof( SCREENINFO );
gEngfuncs.pfnGetScreenInfo( &screenInfo );
// draw the menu, along the left-hand side of the screen
// count the number of newlines
@ -154,8 +158,10 @@ int CHudMenu :: Draw( float flTime )
nlc++;
}
int nFontHeight = max(12, screenInfo.iCharHeight);
// center it
int y = (ScreenHeight/2) - ((nlc/2)*12) - 40; // make sure it is above the say text
int y = (ScreenHeight/2) - ((nlc/2)* nFontHeight) - (3 * nFontHeight + nFontHeight / 3); // make sure it is above the say text
menu_r = 255;
menu_g = 255;
@ -175,7 +181,7 @@ int CHudMenu :: Draw( float flTime )
{
menu_ralign = FALSE;
menu_x = 20;
y += (12);
y += nFontHeight;
sptr++;
}

View file

@ -20,6 +20,7 @@
#include "hud.h"
#include "cl_util.h"
#include "commonmacros.h"
#include <string.h>
#include <stdio.h>
#include "parsemsg.h"
@ -58,6 +59,7 @@ void CHudMessage::Reset( void )
memset( m_pMessages, 0, sizeof( m_pMessages[0] ) * maxHUDMessages );
memset( m_startTime, 0, sizeof( m_startTime[0] ) * maxHUDMessages );
m_bEndAfterMessage = false;
m_gameTitleTime = 0;
m_pGameTitle = NULL;
}
@ -147,13 +149,13 @@ void CHudMessage::MessageScanNextChar( void )
srcGreen = m_parms.pMessage->g1;
srcBlue = m_parms.pMessage->b1;
blend = 0; // Pure source
destRed = destGreen = destBlue = 0;
switch( m_parms.pMessage->effect )
{
// Fade-in / Fade-out
case 0:
case 1:
destRed = destGreen = destBlue = 0;
blend = m_parms.fadeBlend;
break;
@ -168,6 +170,7 @@ void CHudMessage::MessageScanNextChar( void )
{
float deltaTime = m_parms.time - m_parms.charTime;
destRed = destGreen = destBlue = 0;
if ( m_parms.time > m_parms.fadeTime )
{
blend = m_parms.fadeBlend;
@ -285,7 +288,7 @@ void CHudMessage::MessageDrawScan( client_textmessage_t *pMessage, float time )
{
m_parms.lineLength = 0;
m_parms.width = 0;
while ( *pText && *pText != '\n' )
while ( *pText && *pText != '\n' && m_parms.lineLength < ARRAYSIZE( line ) - 1 )
{
unsigned char c = *pText;
line[m_parms.lineLength] = c;
@ -402,6 +405,12 @@ int CHudMessage::Draw( float fTime )
{
// The message is over
m_pMessages[i] = NULL;
if (m_bEndAfterMessage)
{
// leave game
gEngfuncs.pfnClientCmd("wait\nwait\nwait\nwait\nwait\nwait\nwait\ndisconnect\n");
}
}
}
}
@ -487,6 +496,14 @@ int CHudMessage::MsgFunc_HudText( const char *pszName, int iSize, void *pbuf )
char *pString = READ_STRING();
bool bIsEnding = false;
const char *HL1_ENDING_STR = "END3";
if (strlen(pString) == strlen(HL1_ENDING_STR) && strcmp(HL1_ENDING_STR, pString) == 0)
{
m_bEndAfterMessage = true;
}
MessageAdd( pString, gHUD.m_flTime );
// Remember the time -- to fix up level transitions
m_parms.time = gHUD.m_flTime;

View file

@ -46,6 +46,7 @@ int CHudTextMessage::Init(void)
// the new value is pushed into dst_buffer
char *CHudTextMessage::LocaliseTextString( const char *msg, char *dst_buffer, int buffer_size )
{
int len = buffer_size;
char *dst = dst_buffer;
for ( char *src = (char*)msg; *src != 0 && buffer_size > 0; buffer_size-- )
{
@ -85,7 +86,7 @@ char *CHudTextMessage::LocaliseTextString( const char *msg, char *dst_buffer, in
}
}
dst_buffer[buffer_size-1] = 0; // ensure null termination
dst_buffer[len-1] = 0; // ensure null termination
return dst_buffer;
}
@ -195,7 +196,7 @@ int CHudTextMessage::MsgFunc_TextMsg( const char *pszName, int iSize, void *pbuf
case HUD_PRINTNOTIFY:
psz[0] = 1; // mark this message to go into the notify buffer
safe_sprintf( psz+1, MSG_BUF_SIZE, msg_text, sstr1, sstr2, sstr3, sstr4 );
safe_sprintf( psz+1, MSG_BUF_SIZE - 1, msg_text, sstr1, sstr2, sstr3, sstr4 );
ConsolePrint( ConvertCRtoNL( psz ) );
break;

View file

@ -118,15 +118,19 @@ void VectorMA (const float *veca, float scale, const float *vecb, float *vecc)
HSPRITE LoadSprite(const char *pszName)
{
int i;
int iRes;
char sz[256];
if (ScreenWidth < 640)
i = 320;
if (ScreenWidth > 2560 && ScreenHeight > 1600)
iRes = 2560;
else if (ScreenWidth >= 1280 && ScreenHeight > 720)
iRes = 1280;
else if (ScreenWidth >= 640)
iRes = 640;
else
i = 640;
iRes = 320;
sprintf(sz, pszName, i);
sprintf(sz, pszName, iRes);
return SPR_Load(sz);
}

View file

@ -78,6 +78,7 @@ int g_iUser3 = 0;
#define SBOARD_INDENT_Y_400 20
void IN_ResetMouse( void );
void IN_ResetRelativeMouseState( void );
extern CMenuPanel *CMessageWindowPanel_Create( const char *szMOTD, const char *szTitle, int iShadeFullscreen, int iRemoveMe, int x, int y, int wide, int tall );
extern float * GetClientColor( int clientIndex );
@ -817,8 +818,7 @@ try
// Get the button text
pfile = gEngfuncs.COM_ParseFile(pfile, token);
strncpy( cText, token, 32 );
cText[31] = '\0';
CHudTextMessage::LocaliseTextString( token, cText, sizeof( cText ) );
// save off the last button text we've come across (for error reporting)
strcpy( szLastButtonText, cText );
@ -2081,6 +2081,12 @@ void TeamFortressViewport::UpdateCursorState()
IN_ResetMouse();
}
if ( g_iVisibleMouse )
{
//Clear any residual input so our camera doesn't jerk when dismissing the UI
IN_ResetRelativeMouseState();
}
g_iVisibleMouse = false;
App::getInstance()->setCursorOveride( App::getInstance()->getScheme()->getCursor(Scheme::scu_none) );
}

View file

@ -199,8 +199,8 @@ float V_CalcBob ( struct ref_params_s *pparams )
bob = sqrt( vel[0] * vel[0] + vel[1] * vel[1] ) * cl_bob->value;
bob = bob * 0.3 + bob * 0.7 * sin(cycle);
bob = min( bob, 4 );
bob = max( bob, -7 );
bob = min( bob, 4.0f );
bob = max( bob, -7.0f );
return bob;
}
@ -374,9 +374,6 @@ void V_CalcGunAngle ( struct ref_params_s *pparams )
// don't apply all of the v_ipitch to prevent normally unseen parts of viewmodel from coming into view.
viewent->angles[PITCH] -= v_idlescale * sin(pparams->time*v_ipitch_cycle.value) * (v_ipitch_level.value * 0.5);
viewent->angles[YAW] -= v_idlescale * sin(pparams->time*v_iyaw_cycle.value) * v_iyaw_level.value;
VectorCopy( viewent->angles, viewent->curstate.angles );
VectorCopy( viewent->angles, viewent->latched.prevangles );
}
/*
@ -827,6 +824,15 @@ void V_CalcNormalRefdef ( struct ref_params_s *pparams )
}
}
// Update the latched view origin/angles here, this was
// previously done in V_CalcGunAngle but that happens
// before a bunch of other stuff happens, which nukes
// a bunch of the viewbob fx.
VectorCopy( view->origin, view->curstate.origin );
VectorCopy( view->origin, view->latched.prevorigin );
VectorCopy( view->angles, view->curstate.angles );
VectorCopy( view->angles, view->latched.prevangles );
lasttime = pparams->time;
v_origin = pparams->vieworg;
@ -1679,7 +1685,7 @@ void V_DropPunchAngle ( float frametime, float *ev_punchangle )
len = VectorNormalize ( ev_punchangle );
len -= (10.0 + len * 0.5) * frametime;
len = max( len, 0.0 );
len = max( len, 0.0f );
VectorScale ( ev_punchangle, len, ev_punchangle );
}
@ -1712,7 +1718,7 @@ void V_Init (void)
v_centerspeed = gEngfuncs.pfnRegisterVariable( "v_centerspeed","500", 0 );
cl_bobcycle = gEngfuncs.pfnRegisterVariable( "cl_bobcycle","0.8", 0 );// best default for my experimental gun wag (sjb)
cl_bob = gEngfuncs.pfnRegisterVariable( "cl_bob","0.01", 0 );// best default for my experimental gun wag (sjb)
cl_bob = gEngfuncs.pfnRegisterVariable( "cl_bob","0.01", FCVAR_ARCHIVE );// best default for my experimental gun wag (sjb)
cl_bobup = gEngfuncs.pfnRegisterVariable( "cl_bobup","0.5", 0 );
cl_waterdist = gEngfuncs.pfnRegisterVariable( "cl_waterdist","4", 0 );
cl_chasedist = gEngfuncs.pfnRegisterVariable( "cl_chasedist","112", 0 );

View file

@ -116,6 +116,7 @@
// entity flags
#define EFLAG_SLERP 1 // do studio interpolation of this entity
#define EFLAG_FLESH_SOUND 2 // JoshA: Whether this entity should sound like flesh. (ie. pEntity->Classify() != CLASS_NONE && pEntity->Classify() != CLASS_MACHINE)
//
// temp entity events

View file

@ -25,6 +25,10 @@
#define FCVAR_PRINTABLEONLY (1<<7) // This cvar's string cannot contain unprintable characters ( e.g., used for player name etc ).
#define FCVAR_UNLOGGED (1<<8) // If this is a FCVAR_SERVER, don't log changes to the log file / console if we are creating a log
#define FCVAR_NOEXTRAWHITEPACE (1<<9) // strip trailing/leading white space from this cvar
#define FCVAR_PRIVILEGED (1<<10) // Not queryable/settable by unprivileged sources
#define FCVAR_FILTERSTUFFTEXT (1<<11) // Not queryable/settable if unprivileged and filterstufftext is enabled
#define FCVAR_FILTERCHARS (1<<12) // This cvar's string will be filtered for 'bad' characters (e.g. ';', '\n')
#define FCVAR_NOBADPATHS (1<<13) // This cvar's string cannot contain file paths that are above the current directory
typedef struct cvar_s
{

View file

@ -108,8 +108,8 @@ void __inline restore_fpu_cw(void)
_asm fldcw old_cw
}
#else
#define quick_ftol(f) ((int)(f))
#define set_fpu_cw() /* */
#define quick_ftol(f) ftol(f)
#define restore_fpu_cw() /* */
#endif

View file

@ -19,21 +19,26 @@
#pragma once
#endif
// JoshA: Unfortunately netadr_s is passed to clients for connectionless packets.
// No Valve mod uses them, but custom mods *might*, so not changing the start of this struct layout.
// It's very unlikely they touch this, but I'd like to play as safe as possible with all ABI etc for mod compat.
// If we want to add IPv6 someday, bung it at the end of netadr_s and leave ip + ipx alone.
typedef enum
{
NA_UNUSED,
NA_LOOPBACK,
NA_BROADCAST,
NA_IP,
NA_IPX,
NA_BROADCAST_IPX,
NA_IPX, // deprecated
NA_BROADCAST_IPX, // deprecated
} netadrtype_t;
typedef struct netadr_s
{
netadrtype_t type;
unsigned char ip[4];
unsigned char ipx[10];
unsigned char ipx[10]; // deprecated
unsigned short port;
} netadr_t;

View file

@ -21,7 +21,7 @@
// Font stuff
#define NUM_GLYPHS 256
// does not exist: // #include "basetypes.h"
#include "basetypes.h"
typedef struct
{
@ -35,7 +35,7 @@ typedef struct qfont_s
int rowcount;
int rowheight;
charinfo fontinfo[ NUM_GLYPHS ];
unsigned char data[4];
byte data[4];
} qfont_t;
#endif // qfont.h

View file

@ -0,0 +1,86 @@
from PIL import Image
import sys
import os
def convert_to_tiles(input_file, output_folder, tile_size=(256, 256)):
# Open the image
img = Image.open(input_file)
width, height = img.size
# Create the output folder if it doesn't exist
if not os.path.exists(output_folder):
os.makedirs(output_folder)
output_img_folder = os.path.join(output_folder, "background")
if not os.path.exists(output_img_folder):
os.makedirs(output_img_folder)
row = 0
col = 0
prefix = "21_9"
# background txt file should look like:
#
# resolution 800 600
#
# resource/background/800_1_a_loading.tga fit 0 0
# resource/background/800_1_b_loading.tga fit 256 0
# etc
layout_file = f"resolution\t{width}\t{height}\n\n"
# Loop through the image and extract tiles
for j in range(0, height, tile_size[1]):
row = row + 1
col = 0
for i in range(0, width, tile_size[0]):
# Calculate the boundaries for the tile, making sure it doesn't exceed the image dimensions
right_bound = min(i + tile_size[0], width)
bottom_bound = min(j + tile_size[1], height)
box = (i, j, right_bound, bottom_bound)
tile = img.crop(box)
tile_char = chr(ord('a')+col)
target_file = f"{prefix}_{row}_{tile_char}_loading.tga"
tile_filename = os.path.join(output_img_folder, target_file)
tile.save(tile_filename)
print(f"Saved {tile_filename}")
line = f"resource/background/{target_file}\tfit\t{i}\t{j}\n"
layout_file += line
col = col + 1
print("------------------------------------------")
print(layout_file)
print("------------------------------------------")
out_txt = os.path.join(output_folder, "BackgroundLayout.txt")
with open(out_txt, 'w') as f:
f.write(layout_file)
out_txt = os.path.join(output_folder, "BackgroundLoadingLayout.txt")
with open(out_txt, 'w') as f:
f.write(layout_file)
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: python image_to_background.py path_to_image (psd/png/tga)")
sys.exit(1)
img_path = sys.argv[1]
img_dir = os.path.dirname(img_path)
img_dir = os.path.join(img_dir, "Background")
print(f"out dir: {img_dir}")
convert_to_tiles(img_path, img_dir)
#width, height, palette, data = read_spr(spr_path)
#save_as_png(spr_path + "__.png", width, height, palette, data)
print(f"Converted {img_path}")

238
devtools/image_to_spr.py Normal file
View file

@ -0,0 +1,238 @@
import os
import sys
import struct
from PIL import Image
import math
# Sprite type:
# 0 = VP_PARALLEL_UPRIGHT,
# 1 = FACING_UPRIGHT,
# 2 = VP_PARALLEL,
# 3 = ORIENTED,
# 4 = VP_PARALLEL_ORIENTED
# Texture format:
# 0 = SPR_NORMAL
# 1 = SPR_ADDITIVE
# 2 = SPR_INDEXALPHA
# 3 = SPR_ALPHTEST
#TODO: original width / height preservation throughout, use that for offsets and bounding radii
def write_spr_header(spr_file, width, height, numframes, sprite_type=2, texture_format=1, synctype=0):
bounding_radius = 32
if width > 0 and height > 0:
bounding_radius = math.sqrt( ( (width / 2) ** 2 ) + ( ( height / 2) ** 2 ) )
spr_file.write(b'IDSP') # Identifier
spr_file.write(struct.pack('<i', 2)) # Version (2 for Half-Life)
spr_file.write(struct.pack('<i', sprite_type)) # Sprite type
spr_file.write(struct.pack('<i', texture_format)) #Texture Format (0 = SPR_NORMAL)
spr_file.write(struct.pack('<f', bounding_radius))
spr_file.write(struct.pack('<i', width)) # Width
spr_file.write(struct.pack('<i', height)) # Height
spr_file.write(struct.pack('<i', numframes)) # Number of frames
spr_file.write(struct.pack('<f', 0.0)) # Beamlength (not used)
spr_file.write(struct.pack('<i', synctype)) # Synctype (0 for synchronized)
def write_palette_data(spr_file, image, palette):
spr_file.write(struct.pack('<h', 256))
#palette = image.getpalette()#[:768] # 256 colors * 3 (R, G, B)
spr_file.write(bytearray(palette))
def closest_color_index(rgb, color_list):
"""Find the index of the closest color in the list."""
distances = [euclidean_distance(rgb, color) for color in color_list]
return distances.index(min(distances))
def euclidean_distance(c1, c2):
"""Calculate the Euclidean distance between two colors."""
return sum((a - b) ** 2 for a, b in zip(c1, c2)) ** 0.5
def write_indexed_data(spr_file, image, palette):
img_data = list( image.getdata() )
indexed_data = []
palette_colors = []
for i in range(0, len(palette)-4, 3):
palette_colors.append( palette[i:i+3] )
img_colors = []
for i in range(0, len(img_data), 1):
col = img_data[i]
img_colors.append( list(col) )
#print(f"palette_colors: {palette_colors}\n\n")
num_prints = 0
for p in img_colors:
idx = 0
if p in palette_colors:
#print(f"found {p} in palette_colors")
idx = palette_colors.index(p)
else:
num_prints = num_prints + 1
if num_prints < 30:
print(f"couldn't find {p}")
indexed_data.append(idx)
spr_file.write(bytearray(indexed_data))
# for index in indexed_data:
# spr_file.write(struct.pack('<B', index))
def next_power_of_two(n):
"""Return the next power of two for given n."""
return 2 ** (n - 1).bit_length()
def pad_image_to_power_of_two(image):
"""Pad image dimensions to the next power of two."""
width, height = image.size
new_width = next_power_of_two(width)
new_height = next_power_of_two(height)
# Create a new blank image with the padded size
padded_image = Image.new("RGB", (new_width, new_height), 0)
padded_image.paste(image, (0, 0))
return padded_image
def create_palette(img):
"""Extract unique colors from the image and create a palette."""
# Get the list of all colors in the image
colors = list(img.getdata())
# Deduplicate the colors
unique_colors = sorted(list(set(colors)))
#print( f"unique_colors: {unique_colors}" )
# Create a palette
palette = []
for color in unique_colors:
palette.extend(color[:3]) # We only want RGB, not RGBA
# Fill the rest of the 256-color palette with black
while len(palette) < 256 * 3:
palette.extend((0, 0, 0))
#print( f"palette: {palette}" )
return unique_colors, palette
def palettize_image(img, unique_colors, palette):
# Create a palette image whose size does not matter
arbitrary_size = 16, 16
palimage = Image.new('P', arbitrary_size)
palimage.putpalette(palette)
img_p = img.convert("P", 0, palimage.im)
img_p.putpalette(palette)
return img_p
def img_to_spr(img_path, spr_path):
# 1. Read the image file and convert to indexed color
image = Image.open(img_path).convert("RGBA")
# 1.1. Pad image to power of two dimensions
image = pad_image_to_power_of_two(image)
width, height = image.size
# Extract unique colors and create a palette
unique_colors, palette = create_palette(image)
# Palettize the image
# image.save(spr_path + "_PALETTETIME.png")
#print("\n\n\n")
with open(spr_path, 'wb') as spr_file:
# 2. Write SPR header
write_spr_header(spr_file, width, height, 1)
# 3. Write the palette data
write_palette_data(spr_file, image, palette)
# 4. Write the frame header
spr_file.write(struct.pack('<i', 0)) # frame group
spr_file.write(struct.pack('<i', int(-width/2)) ) # frame_origin_x
spr_file.write(struct.pack('<i', int(-height/2)) ) # frame_origin_y
spr_file.write(struct.pack('<i', width)) # frame_width
spr_file.write(struct.pack('<i', height)) # frame_height
# 4.1 Write the indexed data
write_indexed_data(spr_file, image, palette)
def read_spr(filename):
with open(filename, 'rb') as f:
# Read the SPR header
id = f.read(4).decode()
if id != 'IDSP':
raise ValueError("Not a valid SPR file")
version, = struct.unpack('<i', f.read(4))
type, = struct.unpack('<i', f.read(4))
if type != 2: # 2 = VP_PARALLEL
raise ValueError(f"Only VP_PARALLEL type supported, got {type}")
# other header info...
format, = struct.unpack('<i', f.read(4))
bounding_radius, = struct.unpack('<f', f.read(4))
width, = struct.unpack('<i', f.read(4))
height, = struct.unpack('<i', f.read(4))
num_frames, = struct.unpack('<i', f.read(4))
beam_len, = struct.unpack('<f', f.read(4))
sync_type, = struct.unpack('<i', f.read(4))
#print(f"format: {format}\nbounding_radius: {bounding_radius}\nwidth: {width}\nheight: {height}\nnum_frames: {num_frames}\nbeam_len: {beam_len}\nsync_type: {sync_type}\n")
# For simplicity, assume a single frame
if num_frames != 1:
raise ValueError(f"Only single frame SPRs supported, got {num_frames}")
palette_len, = struct.unpack('<h', f.read(2))
# Read the palette (256 RGB entries)
palette = [(ord(f.read(1)), ord(f.read(1)), ord(f.read(1))) for _ in range(256)]
#print( f"palette: {palette}" )
# Read the frame
frame_group, = struct.unpack('<i', f.read(4))
frame_origin_x, = struct.unpack('<i', f.read(4))
frame_origin_y, = struct.unpack('<i', f.read(4))
frame_width, = struct.unpack('<i', f.read(4))
frame_height, = struct.unpack('<i', f.read(4))
#print(f"frame_group: {frame_group} frame_origin_x: {frame_origin_x} frame_origin_y: {frame_origin_y} frame_width: {frame_width} frame_height: {frame_height}")
data = f.read(width * height)
return width, height, palette, data
def save_as_png(filename, width, height, palette, data):
img_data = [palette[byte] for byte in data]
img = Image.new('RGB', (width, height))
img.putdata(img_data)
img.save(filename)
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: python image_to_spr.py path_to_image (psd/png)")
sys.exit(1)
img_path = sys.argv[1]
spr_path = img_path.rsplit('.', 1)[0] + ".spr" # Replace .png with .spr for output
print(f"{img_path} -> {spr_path}")
img_to_spr(img_path, spr_path)
width, height, palette, data = read_spr(spr_path)
save_as_png(spr_path + "__.png", width, height, palette, data)
print(f"Converted {img_path} to {spr_path}")
#spr_path = 'content/materialsrc/Sprites/1280/test.spr'
#width, height, palette, data = read_spr(spr_path)
#save_as_png(spr_path + "__.png", width, height, palette, data)

View file

@ -111,6 +111,7 @@ public:
LINK_ENTITY_TO_CLASS( monster_flyer, CFlockingFlyer );
LINK_ENTITY_TO_CLASS( monster_flyer_flock, CFlockingFlyerFlock );
TYPEDESCRIPTION CFlockingFlyer::m_SaveData[] =
{
DEFINE_FIELD( CFlockingFlyer, m_pSquadLeader, FIELD_CLASSPTR ),

View file

@ -25,7 +25,7 @@
#include "weapons.h"
#include "soundent.h"
#include "hornet.h"
//=========================================================
// monster-specific schedule types
//=========================================================

View file

@ -20,7 +20,7 @@
#include "nodes.h"
#include "player.h"
class CAirtank : public CGrenade
class CAirtank : public CGrenade
{
void Spawn( void );
void Precache( void );

View file

@ -154,7 +154,7 @@ void CApache :: Spawn( void )
void CApache::Precache( void )
{
PRECACHE_MODEL("models/apache.mdl");
PRECACHE_MODEL("models/apache.mdl");
PRECACHE_SOUND("apache/ap_rotor1.wav");
PRECACHE_SOUND("apache/ap_rotor2.wav");

View file

@ -84,7 +84,7 @@ int CBarnacle :: Classify ( void )
//
// Returns number of events handled, 0 if none.
//=========================================================
void CBarnacle :: HandleAnimEvent( MonsterEvent_t *pEvent )
void CBarnacle :: HandleAnimEvent( MonsterEvent_t *pEvent )
{
switch( pEvent->event )
{

View file

@ -791,7 +791,7 @@ class CDeadBarney : public CBaseMonster
{
public:
void Spawn( void );
int Classify ( void ) { return CLASS_PLAYER_ALLY; }
int Classify ( void ) { return CLASS_PLAYER_ALLY; }
void KeyValue( KeyValueData *pkvd );

View file

@ -108,6 +108,8 @@ public:
SCRIPTSTATE m_scriptState; // internal cinematic state
CCineMonster *m_pCine;
float m_flLastYawTime; // Last time yaw change was computed
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
@ -190,11 +192,8 @@ public:
virtual void ScheduleChange( void ) {}
// virtual int CanPlaySequence( void ) { return ((m_pCine == NULL) && (m_MonsterState == MONSTERSTATE_NONE || m_MonsterState == MONSTERSTATE_IDLE || m_IdealMonsterState == MONSTERSTATE_IDLE)); }
virtual int CanPlaySequence( BOOL fDisregardState, int interruptLevel );
virtual int CanPlaySentence( BOOL fDisregardState ) { return IsAlive(); }
virtual void PlaySentence( const char *pszSentence, float duration, float volume, float attenuation );
virtual void PlayScriptedSentence( const char *pszSentence, float duration, float volume, float attenuation, BOOL bConcurrent, CBaseEntity *pListener );
virtual void SentenceStop( void );
virtual int CanPlaySentence( BOOL fDisregardState ) { return IsAllowedToSpeak(); }
virtual BOOL IsAllowedToSpeak() { return IsAlive(); }
Task_t *GetTask ( void );
virtual MONSTERSTATE GetIdealState ( void );

View file

@ -582,7 +582,7 @@ void CBigMomma :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector ve
int CBigMomma :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType )
{
// Don't take any acid damage -- BigMomma's mortar is acid
// Don't take any acid damage -- BigMomma's mortar is acid
if ( bitsDamageType & DMG_ACID )
flDamage = 0;

View file

@ -166,7 +166,7 @@ void CBloater :: AttackSnd( void )
// HandleAnimEvent - catches the monster-specific messages
// that occur when tagged animation frames are played.
//=========================================================
void CBloater :: HandleAnimEvent( MonsterEvent_t *pEvent )
void CBloater :: HandleAnimEvent( MonsterEvent_t *pEvent )
{
switch( pEvent->event )
{

View file

@ -44,7 +44,7 @@ enum
SCHED_SQUID_SNIFF_AND_EAT,
SCHED_SQUID_WALLOW,
};
//=========================================================
// monster-specific tasks
//=========================================================

View file

@ -60,6 +60,10 @@ CBaseEntity
#endif
#endif
#if defined EXPORT
#undef EXPORT
#endif
#define EXPORT CBASE_DLLEXPORT
extern "C" CBASE_DLLEXPORT int GetEntityAPI( DLL_FUNCTIONS *pFunctionTable, int interfaceVersion );
@ -105,7 +109,10 @@ typedef void (CBaseEntity::*USEPTR)( CBaseEntity *pActivator, CBaseEntity *pCall
#define CLASS_ALIEN_BIOWEAPON 13 // hornets and snarks.launched by the alien menace
#define CLASS_BARNACLE 99 // special because no one pays attention to it, and it eats a wide cross-section of creatures.
#define CLASS_VEHICLE 14
class CBaseEntity;
class CBaseToggle;
class CBaseMonster;
class CBasePlayerItem;
class CSquadMonster;
@ -175,6 +182,7 @@ public:
virtual int BloodColor( void ) { return DONT_BLEED; }
virtual void TraceBleed( float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType );
virtual BOOL IsTriggered( CBaseEntity *pActivator ) {return TRUE;}
virtual CBaseToggle* MyTogglePointer(void) { return NULL; }
virtual CBaseMonster *MyMonsterPointer( void ) { return NULL;}
virtual CSquadMonster *MySquadMonsterPointer( void ) { return NULL;}
virtual int GetToggleState( void ) { return TS_AT_TOP; }
@ -546,6 +554,14 @@ public:
void EXPORT AngularMoveDone( void );
BOOL IsLockedByMaster( void );
virtual CBaseToggle* MyTogglePointer(void) { return this; }
// monsters use this, but so could buttons for instance
virtual void PlaySentence(const char* pszSentence, float duration, float volume, float attenuation);
virtual void PlayScriptedSentence(const char* pszSentence, float duration, float volume, float attenuation, BOOL bConcurrent, CBaseEntity* pListener);
virtual void SentenceStop(void);
virtual BOOL IsAllowedToSpeak() { return FALSE; }
static float AxisValue( int flags, const Vector &angles );
static void AxisDir( entvars_t *pev );
static float AxisDelta( int flags, const Vector &angle1, const Vector &angle2 );
@ -698,13 +714,14 @@ public:
virtual int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType );
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
enum BUTTON_CODE { BUTTON_NOTHING, BUTTON_ACTIVATE, BUTTON_RETURN };
BUTTON_CODE ButtonResponseToTouch( void );
static TYPEDESCRIPTION m_SaveData[];
// Buttons that don't take damage can be IMPULSE used
virtual int ObjectCaps( void ) { return (CBaseToggle:: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | (pev->takedamage?0:FCAP_IMPULSE_USE); }
virtual BOOL IsAllowedToSpeak() { return TRUE; }
BOOL m_fStayPushed; // button stays pushed in until touched again?
BOOL m_fRotating; // a rotating button? default is a sliding button.

View file

@ -495,8 +495,6 @@ ClientCommand
called each time a player uses a "cmd" command
============
*/
extern float g_flWeaponCheat;
// Use CMD_ARGV, CMD_ARGV, and CMD_ARGC to get pointers the character string command.
void ClientCommand( edict_t *pEntity )
{
@ -523,7 +521,7 @@ void ClientCommand( edict_t *pEntity )
}
else if ( FStrEq(pcmd, "give" ) )
{
if ( g_flWeaponCheat != 0.0)
if ( CVAR_GET_FLOAT( "sv_cheats" ) != 0.0)
{
int iszItem = ALLOC_STRING( CMD_ARGV(1) ); // Make a copy of the classname
GetClassPtr((CBasePlayer *)pev)->GiveNamedItem( STRING(iszItem) );
@ -537,7 +535,7 @@ void ClientCommand( edict_t *pEntity )
}
else if ( FStrEq(pcmd, "fov" ) )
{
if ( g_flWeaponCheat && CMD_ARGC() > 1)
if ( CVAR_GET_FLOAT( "sv_cheats" ) && CMD_ARGC() > 1)
{
GetClassPtr((CBasePlayer *)pev)->m_iFOV = atoi( CMD_ARGV(1) );
}
@ -607,6 +605,13 @@ void ClientCommand( edict_t *pEntity )
// max total length is 192 ...and we're adding a string below ("Unknown command: %s\n")
strncpy( command, pcmd, 127 );
command[127] = '\0';
// First parse the name and remove any %'s
for ( char *pApersand = command; pApersand != NULL && *pApersand != 0; pApersand++ )
{
// Replace it with a space
if ( *pApersand == '%' )
*pApersand = ' ';
}
// tell the user they entered an unknown command
ClientPrint( &pEntity->v, HUD_PRINTCONSOLE, UTIL_VarArgs( "Unknown command: %s\n", command ) );
@ -870,6 +875,7 @@ void ClientPrecache( void )
PRECACHE_SOUND("debris/wood3.wav");
PRECACHE_SOUND("plats/train_use1.wav"); // use a train
PRECACHE_SOUND("plats/vehicle_ignition.wav");
PRECACHE_SOUND("buttons/spark5.wav"); // hit computer texture
PRECACHE_SOUND("buttons/spark6.wav");
@ -1268,6 +1274,12 @@ int AddToFullPack( struct entity_state_s *state, int e, edict_t *ent, edict_t *h
state->health = ent->v.health;
}
CBaseEntity *pEntity = static_cast<CBaseEntity*>( GET_PRIVATE( ent ) );
if ( pEntity && pEntity->Classify() != CLASS_NONE && pEntity->Classify() != CLASS_MACHINE )
state->eflags |= EFLAG_FLESH_SOUND;
else
state->eflags &= ~EFLAG_FLESH_SOUND;
return 1;
}
@ -1622,12 +1634,12 @@ int GetWeaponData( struct edict_s *player, struct weapon_data_s *info )
item->m_iId = II.iId;
item->m_iClip = gun->m_iClip;
item->m_flTimeWeaponIdle = max( gun->m_flTimeWeaponIdle, -0.001 );
item->m_flNextPrimaryAttack = max( gun->m_flNextPrimaryAttack, -0.001 );
item->m_flNextSecondaryAttack = max( gun->m_flNextSecondaryAttack, -0.001 );
item->m_flTimeWeaponIdle = max( gun->m_flTimeWeaponIdle, -0.001f );
item->m_flNextPrimaryAttack = max( gun->m_flNextPrimaryAttack, -0.001f );
item->m_flNextSecondaryAttack = max( gun->m_flNextSecondaryAttack, -0.001f );
item->m_fInReload = gun->m_fInReload;
item->m_fInSpecialReload = gun->m_fInSpecialReload;
item->fuser1 = max( gun->pev->fuser1, -0.001 );
item->fuser1 = max( gun->pev->fuser1, -0.001f );
item->fuser2 = gun->m_flStartThrow;
item->fuser3 = gun->m_flReleaseThrow;
item->iuser1 = gun->m_chargeReady;
@ -1635,7 +1647,7 @@ int GetWeaponData( struct edict_s *player, struct weapon_data_s *info )
item->iuser3 = gun->m_fireState;
// item->m_flPumpTime = max( gun->m_flPumpTime, -0.001 );
// item->m_flPumpTime = max( gun->m_flPumpTime, -0.001f );
}
}
pPlayerItem = pPlayerItem->m_pNext;

View file

@ -38,7 +38,7 @@
#define CONTROLLER_FLINCH_DELAY 2 // at most one flinch every n secs
class CController : public CSquadMonster
class CController : public CSquadMonster
{
public:
virtual int Save( CSave &save );

View file

@ -193,9 +193,12 @@ int CCrowbar::Swing( int fFirst )
}
#endif
PLAYBACK_EVENT_FULL( FEV_NOTHOST, m_pPlayer->edict(), m_usCrowbar,
0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0, 0, 0,
0.0, 0, 0.0 );
if ( fFirst )
{
PLAYBACK_EVENT_FULL( FEV_NOTHOST, m_pPlayer->edict(), m_usCrowbar,
0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0, 0, 0,
0.0, 0, 0.0 );
}
if ( tr.flFraction >= 1.0 )
@ -232,7 +235,9 @@ int CCrowbar::Swing( int fFirst )
ClearMultiDamage( );
if ( (m_flNextPrimaryAttack + 1 < UTIL_WeaponTimeBase() ) || g_pGameRules->IsMultiplayer() )
// JoshA: Changed from < -> <= to fix the full swing logic since client weapon prediction.
// -1.0f + 1.0f = 0.0f. UTIL_WeaponTimeBase is always 0 with client weapon prediction (0 time base vs curtime base)
if ( ( m_flNextPrimaryAttack + 1.0f <= UTIL_WeaponTimeBase() ) || g_pGameRules->IsMultiplayer() )
{
// first swing does full damage
pEntity->TraceAttack(m_pPlayer->pev, gSkillData.plrDmgCrowbar, gpGlobals->v_forward, &tr, DMG_CLUB );
@ -307,7 +312,7 @@ int CCrowbar::Swing( int fFirst )
m_flNextPrimaryAttack = GetNextAttackDelay(0.25);
SetThink( &CCrowbar::Smack );
pev->nextthink = UTIL_WeaponTimeBase() + 0.2;
pev->nextthink = gpGlobals->time + 0.2;
}

View file

@ -427,7 +427,7 @@ LINK_ENTITY_TO_CLASS( trip_beam, CTripBeam );
void CTripBeam::Spawn( void )
{
CLightning::Spawn();
SetTouch( &CTripBeam::TriggerTouch );
SetTouch( &CBeam::TriggerTouch );
pev->solid = SOLID_TRIGGER;
RelinkBeam();
}

View file

@ -35,6 +35,10 @@
#define EGON_SWITCH_NARROW_TIME 0.75 // Time it takes to switch fire modes
#define EGON_SWITCH_WIDE_TIME 1.5
#ifndef CLIENT_DLL
extern bool IsBustingGame();
#endif
enum egon_e {
EGON_IDLE1 = 0,
EGON_FIDGET1,
@ -51,11 +55,11 @@ enum egon_e {
LINK_ENTITY_TO_CLASS( weapon_egon, CEgon );
void CEgon::Spawn( )
void CEgon::Spawn()
{
Precache( );
Precache();
m_iId = WEAPON_EGON;
SET_MODEL(ENT(pev), "models/w_egon.mdl");
SET_MODEL( ENT( pev ), "models/w_egon.mdl" );
m_iDefaultAmmo = EGON_DEFAULT_GIVE;
@ -102,6 +106,7 @@ int CEgon::AddToPlayer( CBasePlayer *pPlayer )
MESSAGE_END();
return TRUE;
}
return FALSE;
}
@ -155,6 +160,12 @@ BOOL CEgon::HasAmmo( void )
void CEgon::UseAmmo( int count )
{
#ifndef CLIENT_DLL
if ( IsBustingGame() )
return;
#endif
if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] >= count )
m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= count;
else
@ -440,7 +451,9 @@ void CEgon::CreateEffect( void )
m_pSprite->pev->scale = 1.0;
m_pSprite->SetTransparency( kRenderGlow, 255, 255, 255, 255, kRenderFxNoDissipation );
m_pSprite->pev->spawnflags |= SF_SPRITE_TEMPORARY;
m_pSprite->pev->flags |= FL_SKIPLOCALHOST;
// Josh: This sprite is not predicted o the client, so was missing
// for many years after it got broken in an update.
//m_pSprite->pev->flags |= FL_SKIPLOCALHOST;
m_pSprite->pev->owner = m_pPlayer->edict();
if ( m_fireMode == FIRE_WIDE )
@ -519,7 +532,17 @@ void CEgon::WeaponIdle( void )
m_deployed = TRUE;
}
BOOL CEgon::CanHolster( void )
{
#ifndef CLIENT_DLL
if ( IsBustingGame() )
{
return FALSE;
}
#endif
return TRUE;
}
void CEgon::EndAttack( void )
{

View file

@ -32,7 +32,7 @@ class CShower : public CBaseEntity
void Think( void );
void Touch( CBaseEntity *pOther );
int ObjectCaps( void ) { return FCAP_DONT_SAVE; }
};
};
LINK_ENTITY_TO_CLASS( spark_shower, CShower );

View file

@ -54,9 +54,6 @@ typedef int BOOL;
#include <limits.h>
#include <stdarg.h>
#include <string.h> // memset
#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
#ifndef max
#define max(a,b) (((a) > (b)) ? (a) : (b))
#define _vsnprintf(a,b,c,d) vsnprintf(a,b,c,d)
@ -66,6 +63,10 @@ typedef int BOOL;
// Misc C-runtime library headers
#include "stdio.h"
#include "stdlib.h"
#include "minmax.h"
#ifndef _WIN32
# define _vsnprintf(a,b,c,d) vsnprintf(a,b,c,d)
#endif
#include "math.h"
// Header file containing definition of globalvars_t and entvars_t

View file

@ -33,7 +33,7 @@ int CFlyingMonster :: CheckLocalMove ( const Vector &vecStart, const Vector &vec
// ALERT(at_aiconsole, "can't swim out of water\n");
return FALSE;
}
TraceResult tr;
UTIL_TraceHull( vecStart + Vector( 0, 0, 32 ), vecEnd + Vector( 0, 0, 32 ), dont_ignore_monsters, large_hull, edict(), &tr );
@ -87,13 +87,18 @@ void CFlyingMonster :: Stop( void )
}
float CFlyingMonster :: ChangeYaw( int speed )
float CFlyingMonster :: ChangeYaw( int yawSpeed )
{
if ( pev->movetype == MOVETYPE_FLY )
{
float diff = FlYawDiff();
float target = 0;
if ( m_flLastZYawTime == 0.f )
{
m_flLastZYawTime = gpGlobals->time - gpGlobals->frametime;
}
if ( m_IdealActivity != GetStoppedActivity() )
{
if ( diff < -20 )
@ -101,9 +106,18 @@ float CFlyingMonster :: ChangeYaw( int speed )
else if ( diff > 20 )
target = -90;
}
pev->angles.z = UTIL_Approach( target, pev->angles.z, 220.0 * gpGlobals->frametime );
float delta = gpGlobals->time - m_flLastZYawTime;
m_flLastZYawTime = gpGlobals->time;
// Clamp delta like the engine does with frametime
if ( delta > 0.25f )
delta = 0.25f;
float speed = 220.f * delta;
pev->angles.z = UTIL_Approach( target, pev->angles.z, speed );
}
return CBaseMonster::ChangeYaw( speed );
return CBaseMonster::ChangeYaw( yawSpeed );
}

View file

@ -25,7 +25,7 @@ public:
Activity GetStoppedActivity( void );
void Killed( entvars_t *pevAttacker, int iGib );
void Stop( void );
float ChangeYaw( int speed );
float ChangeYaw( int yawSpeed );
void HandleAnimEvent( MonsterEvent_t *pEvent );
void MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, float flInterval );
void Move( float flInterval = 0.1 );
@ -46,6 +46,7 @@ protected:
float m_stopTime; // Last time we stopped (to avoid switching states too soon)
float m_momentum; // Weight for desired vs. momentum velocity
const char *m_pFlapSound;
float m_flLastZYawTime; // Last frame time Z was changed when yaw was changed
};

View file

@ -934,7 +934,11 @@ void CPushable :: Move( CBaseEntity *pOther, int push )
if ( pOther->IsPlayer() )
{
if ( push && !(pevToucher->button & (IN_FORWARD|IN_USE)) ) // Don't push unless the player is pushing forward and NOT use (pull)
// JoshA: Used to check for FORWARD too and logic was inverted
// from comment which seems wrong.
// Fixed to just check for USE being not set for PUSH.
// Should have the right effect.
if ( push && !!(pevToucher->button & IN_USE) ) // Don't push unless the player is not useing (pull)
return;
playerTouch = 1;
}
@ -956,19 +960,39 @@ void CPushable :: Move( CBaseEntity *pOther, int push )
else
factor = 0.25;
pev->velocity.x += pevToucher->velocity.x * factor;
pev->velocity.y += pevToucher->velocity.y * factor;
// This used to be added every 'frame', but to be consistent at high fps,
// now act as if it's added at a constant rate with a fudge factor.
extern cvar_t sv_pushable_fixed_tick_fudge;
if ( !push && sv_pushable_fixed_tick_fudge.value >= 0.0f )
{
factor *= gpGlobals->frametime * sv_pushable_fixed_tick_fudge.value;
}
// JoshA: Always apply this if pushing, or if under the player's velocity.
if ( push || ( abs(pev->velocity.x) < abs(pevToucher->velocity.x - pevToucher->velocity.x * factor) ) )
pev->velocity.x += pevToucher->velocity.x * factor;
if ( push || ( abs(pev->velocity.y) < abs(pevToucher->velocity.y - pevToucher->velocity.y * 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()) )
if ( 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;
// JoshA: Match the player to our pushable's velocity.
// Previously this always happened, but it should only
// happen if the player is pushing (or rather, being pushed.)
// This either stops the player in their tracks or nudges them along.
if ( push )
{
pevToucher->velocity.x = pev->velocity.x;
pevToucher->velocity.y = pev->velocity.y;
}
if ( (gpGlobals->time - m_soundTime) > 0.7 )
{
m_soundTime = gpGlobals->time;

View file

@ -46,6 +46,7 @@ cvar_t mp_chattime = {"mp_chattime","10", FCVAR_SERVER };
// Engine Cvars
cvar_t *g_psv_gravity = NULL;
cvar_t *g_psv_aim = NULL;
cvar_t *g_psv_allow_autoaim = NULL;
cvar_t *g_footsteps = NULL;
//CVARS FOR SKILL LEVEL SETTINGS
@ -450,6 +451,10 @@ cvar_t sk_player_leg3 = { "sk_player_leg3","1" };
// END Cvars for Skill Level settings
cvar_t sv_pushable_fixed_tick_fudge = { "sv_pushable_fixed_tick_fudge", "15" };
cvar_t sv_busters = { "sv_busters", "0" };
// Register your console variables here
// This gets called one time when the game is initialied
void GameDLLInit( void )
@ -458,6 +463,7 @@ void GameDLLInit( void )
g_psv_gravity = CVAR_GET_POINTER( "sv_gravity" );
g_psv_aim = CVAR_GET_POINTER( "sv_aim" );
g_psv_allow_autoaim = CVAR_GET_POINTER( "sv_allow_autoaim" );
g_footsteps = CVAR_GET_POINTER( "mp_footsteps" );
CVAR_REGISTER (&displaysoundlist);
@ -484,6 +490,8 @@ void GameDLLInit( void )
CVAR_REGISTER (&mp_chattime);
CVAR_REGISTER( &sv_busters );
// REGISTER CVARS FOR SKILL LEVEL STUFF
// Agrunt
CVAR_REGISTER ( &sk_agrunt_health1 );// {"sk_agrunt_health1","0"};
@ -885,6 +893,8 @@ void GameDLLInit( void )
CVAR_REGISTER ( &sk_player_leg3 );
// END REGISTER CVARS FOR SKILL LEVEL STUFF
CVAR_REGISTER ( &sv_pushable_fixed_tick_fudge );
SERVER_COMMAND( "exec skill.cfg\n" );
}

View file

@ -40,6 +40,7 @@ extern cvar_t allowmonsters;
// Engine Cvars
extern cvar_t *g_psv_gravity;
extern cvar_t *g_psv_aim;
extern cvar_t *g_psv_allow_autoaim;
extern cvar_t *g_footsteps;
#endif // GAME_H

View file

@ -34,6 +34,7 @@ extern int gmsgDeathMsg; // client dll messages
extern int gmsgMOTD;
int g_teamplay = 0;
extern cvar_t sv_busters;
//=========================================================
//=========================================================
@ -328,7 +329,13 @@ CGameRules *InstallGameRules( void )
g_teamplay = 1;
return new CHalfLifeTeamplay;
}
if ((int)gpGlobals->deathmatch == 1)
if ( sv_busters.value == 1 )
{
g_teamplay = 0;
return new CMultiplayBusters;
}
else if ((int)gpGlobals->deathmatch == 1)
{
// vanilla deathmatch
g_teamplay = 0;

View file

@ -293,6 +293,7 @@ public:
virtual BOOL AllowAutoTargetCrosshair( void );
virtual BOOL ClientCommand( CBasePlayer *pPlayer, const char *pcmd );
virtual void ClientUserInfoChanged( CBasePlayer *pPlayer, char *infobuffer );
// Client kills/scoring
virtual int IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled );
@ -357,4 +358,32 @@ protected:
void SendMOTDToClient( edict_t *client );
};
//=========================================================
// CMultiplayBusters
// Rules for a multiplayer mode that makes you feel good
//=========================================================
class CMultiplayBusters : public CHalfLifeMultiplay
{
public:
CMultiplayBusters();
virtual void Think( void );
virtual int IPointsForKill( CBasePlayer* pAttacker, CBasePlayer* pKilled );
virtual void PlayerKilled( CBasePlayer* pVictim, entvars_t* pKiller, entvars_t* pInflictor );
virtual void DeathNotice( CBasePlayer* pVictim, entvars_t* pKiller, entvars_t* pInflictor );
virtual int WeaponShouldRespawn( CBasePlayerItem* pWeapon );
virtual BOOL CanHavePlayerItem( CBasePlayer* pPlayer, CBasePlayerItem* pWeapon );
virtual BOOL CanHaveItem( CBasePlayer* pPlayer, CItem* pItem );
virtual void PlayerGotWeapon( CBasePlayer* pPlayer, CBasePlayerItem* pWeapon );
virtual void ClientUserInfoChanged( CBasePlayer* pPlayer, char* infobuffer );
virtual void PlayerSpawn( CBasePlayer* pPlayer );
void SetPlayerModel( CBasePlayer* pPlayer );
protected:
float m_flEgonBustingCheckTime = -1.0f;
void CheckForEgons( void );
};
extern DLL_GLOBAL CGameRules* g_pGameRules;

View file

@ -12,7 +12,7 @@
* use or distribution of this code by or to any unlicensed person is illegal.
*
****/
#ifndef OEM_BUILD
#ifndef OEM_BUILD
//=========================================================
// Gargantua

View file

@ -171,6 +171,10 @@ void CGauss::PrimaryAttack()
void CGauss::SecondaryAttack()
{
// JoshA: Sanitize this so it's not total garbage on level transition
// and we end up ear blasting the player!
m_pPlayer->m_flStartCharge = min( m_pPlayer->m_flStartCharge, gpGlobals->time );
// don't fire underwater
if ( m_pPlayer->pev->waterlevel == 3 )
{
@ -308,6 +312,10 @@ void CGauss::SecondaryAttack()
void CGauss::StartFire( void )
{
float flDamage;
// JoshA: Sanitize this so it's not total garbage on level transition
// and we end up ear blasting the player!
m_pPlayer->m_flStartCharge = min( m_pPlayer->m_flStartCharge, gpGlobals->time );
UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle );
Vector vecAiming = gpGlobals->v_forward;
@ -375,7 +383,7 @@ void CGauss::Fire( Vector vecOrigSrc, Vector vecDir, float flDamage )
int fFirstBeam = 1;
int nMaxHits = 10;
pentIgnore = ENT( m_pPlayer->pev );
pentIgnore = m_pPlayer->edict();
#ifdef CLIENT_DLL
if ( m_fPrimaryFire == false )
@ -426,6 +434,13 @@ void CGauss::Fire( Vector vecOrigSrc, Vector vecDir, float flDamage )
if (pEntity->pev->takedamage)
{
ClearMultiDamage();
// if you hurt yourself clear the headshot bit
if (m_pPlayer->pev == pEntity->pev)
{
tr.iHitgroup = 0;
}
pEntity->TraceAttack( m_pPlayer->pev, flDamage, vecDir, &tr, DMG_BULLET );
ApplyMultiDamage(m_pPlayer->pev, m_pPlayer->pev);
}

View file

@ -20,7 +20,7 @@
#include "cbase.h"
#include "monsters.h"
#include "schedule.h"
// For holograms, make them not solid so the player can walk through them
#define SF_GENERICMONSTER_NOTSOLID 4

View file

@ -13,7 +13,7 @@
*
****/
/*
===== generic grenade.cpp ========================================================
*/
@ -454,7 +454,7 @@ CGrenade * CGrenade :: ShootSatchelCharge( entvars_t *pevOwner, Vector vecStart,
void CGrenade :: UseSatchelCharges( entvars_t *pevOwner, SATCHELCODE code )
void CGrenade :: UseSatchelCharges( entvars_t *pevOwner, SATCHELCODE code )
{
edict_t *pentFind;
edict_t *pentOwner;

View file

@ -228,13 +228,7 @@ void CGlock::GlockFire( float flSpread , float flCycleTime, BOOL fUseAutoAim )
void CGlock::Reload( void )
{
int iResult;
if (m_iClip == 0)
iResult = DefaultReload( 17, GLOCK_RELOAD, 1.5 );
else
iResult = DefaultReload( 18, GLOCK_RELOAD_NOT_EMPTY, 1.5 );
int iResult = DefaultReload( GLOCK_MAX_CLIP, m_iClip > 0 ? GLOCK_RELOAD_NOT_EMPTY : GLOCK_RELOAD, 1.5 );
if (iResult)
{
m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 );

View file

@ -4,7 +4,7 @@
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
* All Rights Reserved.
*
* This source code contains proprietary and confidential information of
* Valve LLC and its suppliers. Access to this code is restricted to

View file

@ -1,6 +1,6 @@
/***
*
* Copyright (c) 1996-2001, Valve LLC. All rights reserved.
* Copyright (c) 1996-2001, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.

View file

@ -1,6 +1,6 @@
/***
*
* Copyright (c) 1996-2001, Valve LLC. All rights reserved.
* Copyright (c) 1996-2001, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
@ -45,6 +45,7 @@ public:
// Don't treat as a live target
virtual BOOL IsAlive( void ) { return FALSE; }
virtual BOOL IsAllowedToSpeak() { return TRUE; }
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );

View file

@ -130,7 +130,7 @@ void CHandGrenade::WeaponIdle( void )
if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() )
return;
if ( m_flStartThrow )
{
Vector angThrow = m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle;
@ -140,9 +140,10 @@ void CHandGrenade::WeaponIdle( void )
else
angThrow.x = -10 + angThrow.x * ( ( 90 + 10 ) / 90.0 );
float flVel = ( 90 - angThrow.x ) * 4;
if ( flVel > 500 )
flVel = 500;
static float flMultiplier = 6.5f;
float flVel = ( 90 - angThrow.x ) * flMultiplier;
if ( flVel > 1000 )
flVel = 1000;
UTIL_MakeVectors( angThrow );

View file

@ -1,4 +1,4 @@
/***
/***
*
* Copyright (c) 1996-2001, Valve LLC. All rights reserved.
*
@ -728,12 +728,12 @@ void CHAssassin :: RunAI( void )
EMIT_SOUND (ENT(pev), CHAN_BODY, "debris/beamstart1.wav", 0.2, ATTN_NORM );
}
pev->renderamt = max( pev->renderamt - 50, m_iTargetRanderamt );
pev->renderamt = max<float>( pev->renderamt - 50, m_iTargetRanderamt );
pev->rendermode = kRenderTransTexture;
}
else if (pev->renderamt < m_iTargetRanderamt)
{
pev->renderamt = min( pev->renderamt + 50, m_iTargetRanderamt );
pev->renderamt = min<float>( pev->renderamt + 50, m_iTargetRanderamt );
if (pev->renderamt == 255)
pev->rendermode = kRenderNormal;
}

View file

@ -1,4 +1,4 @@
/***
/***
*
* Copyright (c) 1996-2001, Valve LLC. All rights reserved.
*

View file

@ -2377,7 +2377,7 @@ Schedule_t* CHGrunt :: GetScheduleOfType ( int Type )
// repelling down a line.
//=========================================================
class CHGruntRepel : public CBaseMonster
class CHGruntRepel : public CBaseMonster
{
public:
void Spawn( void );

File diff suppressed because it is too large Load diff

View file

@ -188,7 +188,7 @@ void CHornet :: StartDart ( void )
pev->nextthink = gpGlobals->time + 4;
}
void CHornet::IgniteTrail( void )
void CHornet::IgniteTrail( void )
{
/*

View file

@ -24,6 +24,14 @@
#include "hornet.h"
#include "gamerules.h"
static float GetRechargeTime()
{
if (gpGlobals->maxClients > 1)
{
return 0.3f;
}
return 0.5f;
}
enum hgun_e {
HGUN_IDLE1 = 0,
@ -144,7 +152,7 @@ void CHgun::PrimaryAttack()
CBaseEntity *pHornet = CBaseEntity::Create( "hornet", m_pPlayer->GetGunPosition( ) + gpGlobals->v_forward * 16 + gpGlobals->v_right * 8 + gpGlobals->v_up * -12, m_pPlayer->pev->v_angle, m_pPlayer->edict() );
pHornet->pev->velocity = gpGlobals->v_forward * 300;
m_flRechargeTime = gpGlobals->time + 0.5;
m_flRechargeTime = gpGlobals->time + GetRechargeTime();
#endif
m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--;
@ -173,6 +181,10 @@ void CHgun::PrimaryAttack()
{
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.25;
}
if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] == 0)
{
m_flNextPrimaryAttack += GetRechargeTime();
}
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );
}
@ -237,7 +249,7 @@ void CHgun::SecondaryAttack( void )
pHornet->SetThink( &CHornet::StartDart );
m_flRechargeTime = gpGlobals->time + 0.5;
m_flRechargeTime = gpGlobals->time + GetRechargeTime();
#endif
int flags;
@ -257,7 +269,14 @@ void CHgun::SecondaryAttack( void )
// player "shoot" animation
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.1;
if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] == 0)
{
m_flRechargeTime = gpGlobals->time + 0.5;
m_flNextSecondaryAttack += 0.5;
m_flNextPrimaryAttack += 0.5;
}
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );
}
@ -270,7 +289,7 @@ void CHgun::Reload( void )
while (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] < HORNET_MAX_CARRY && m_flRechargeTime < gpGlobals->time)
{
m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]++;
m_flRechargeTime += 0.5;
m_flRechargeTime += GetRechargeTime();
}
}

View file

@ -1,4 +1,4 @@
/***
/***
*
* Copyright (c) 1996-2001, Valve LLC. All rights reserved.
*

View file

@ -1,4 +1,4 @@
/***
/***
*
* Copyright (c) 1996-2001, Valve LLC. All rights reserved.
*
@ -78,7 +78,7 @@ public:
BOOL CheckMeleeAttack1 ( float flDot, float flDist );
BOOL CheckRangeAttack1 ( float flDot, float flDist );
float ChangeYaw( int speed );
float ChangeYaw( int yawSpeed );
Activity GetStoppedActivity( void );
void Move( float flInterval );
@ -90,7 +90,7 @@ public:
float VectorToPitch( const Vector &vec);
float FlPitchDiff( void );
float ChangePitch( int speed );
float ChangePitch( int pitchSpeed );
Vector m_SaveVelocity;
float m_idealDist;
@ -108,6 +108,9 @@ public:
float m_flNextAlert;
float m_flLastPitchTime; // Last frame time pitch was changed
float m_flLastZYawTime; // Last frame time Z was changed when yaw was changed
static const char *pIdleSounds[];
static const char *pAlertSounds[];
static const char *pAttackSounds[];
@ -795,12 +798,18 @@ float CIchthyosaur::FlPitchDiff( void )
return flPitchDiff;
}
float CIchthyosaur :: ChangePitch( int speed )
float CIchthyosaur :: ChangePitch( int pitchSpeed )
{
if ( pev->movetype == MOVETYPE_FLY )
{
float diff = FlPitchDiff();
float target = 0;
if ( m_flLastPitchTime == 0.f )
{
m_flLastPitchTime = gpGlobals->time - gpGlobals->frametime;
}
if ( m_IdealActivity != GetStoppedActivity() )
{
if (diff < -20)
@ -808,18 +817,32 @@ float CIchthyosaur :: ChangePitch( int speed )
else if (diff > 20)
target = -45;
}
pev->angles.x = UTIL_Approach(target, pev->angles.x, 220.0 * 0.1 );
float delta = gpGlobals->time - m_flLastPitchTime;
m_flLastPitchTime = gpGlobals->time;
// Clamp delta like the engine does with frametime
if ( delta > 0.25f )
delta = 0.25f;
float speed = 220.f * delta;
pev->angles.x = UTIL_Approach(target, pev->angles.x, speed );
}
return 0;
}
float CIchthyosaur::ChangeYaw( int speed )
float CIchthyosaur::ChangeYaw( int yawSpeed )
{
if ( pev->movetype == MOVETYPE_FLY )
{
float diff = FlYawDiff();
float target = 0;
if ( m_flLastZYawTime == 0.f )
{
m_flLastZYawTime = gpGlobals->time - gpGlobals->frametime;
}
if ( m_IdealActivity != GetStoppedActivity() )
{
if ( diff < -20 )
@ -827,9 +850,18 @@ float CIchthyosaur::ChangeYaw( int speed )
else if ( diff > 20 )
target = -20;
}
pev->angles.z = UTIL_Approach( target, pev->angles.z, 220.0 * 0.1 );
float delta = gpGlobals->time - m_flLastZYawTime;
m_flLastZYawTime = gpGlobals->time;
// Clamp delta like the engine does with frametime
if ( delta > 0.25f )
delta = 0.25f;
float speed = 220.f * delta;
pev->angles.z = UTIL_Approach( target, pev->angles.z, speed );
}
return CFlyingMonster::ChangeYaw( speed );
return CFlyingMonster::ChangeYaw( yawSpeed );
}

View file

@ -12,7 +12,7 @@
* use or distribution of this code by or to any unlicensed person is illegal.
*
****/
//=========================================================
//=========================================================
// Alien slave monster
//=========================================================

View file

@ -229,7 +229,7 @@ class CItemBattery : public CItem
char szcharge[64];
pPlayer->pev->armorvalue += gSkillData.batteryCapacity;
pPlayer->pev->armorvalue = min(pPlayer->pev->armorvalue, MAX_NORMAL_BATTERY);
pPlayer->pev->armorvalue = min<float>(pPlayer->pev->armorvalue, MAX_NORMAL_BATTERY);
EMIT_SOUND( pPlayer->edict(), CHAN_ITEM, "items/gunpickup2.wav", 1, ATTN_NORM );

View file

@ -557,7 +557,7 @@ void CLeech::UpdateMotion( void )
void CLeech::SwimThink( void )
{
TraceResult tr;
float flLeftSide;
float flLeftSide;
float flRightSide;
float targetSpeed;
float targetYaw = 0;

View file

@ -799,7 +799,7 @@ void CGamePlayerEquip::KeyValue( KeyValueData *pkvd )
{
char tmp[128];
UTIL_StripToken( pkvd->szKeyName, tmp );
UTIL_StripToken( pkvd->szKeyName, tmp, sizeof( tmp ) );
m_weaponNames[i] = ALLOC_STRING(tmp);
m_weaponCount[i] = atoi(pkvd->szValue);

View file

@ -31,7 +31,7 @@
//=========================================================
// MonsterMaker - this ent creates monsters during the game.
//=========================================================
class CMonsterMaker : public CBaseMonster
class CMonsterMaker : public CBaseMonster
{
public:
void Spawn( void );

View file

@ -1989,7 +1989,7 @@ void CBaseMonster::MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, f
while (flTotal > 0.001)
{
// don't walk more than 16 units or stairs stop working
flStep = min( 16.0, flTotal );
flStep = min( 16.0f, flTotal );
UTIL_MoveToOrigin ( ENT(pev), m_Route[ m_iRouteIndex ].vecLocation, flStep, MOVE_NORMAL );
flTotal -= flStep;
}
@ -2537,7 +2537,19 @@ float CBaseMonster::ChangeYaw ( int yawSpeed )
ideal = pev->ideal_yaw;
if (current != ideal)
{
speed = (float)yawSpeed * gpGlobals->frametime * 10;
if ( m_flLastYawTime == 0.f )
{
m_flLastYawTime = gpGlobals->time - gpGlobals->frametime;
}
float delta = gpGlobals->time - m_flLastYawTime;
m_flLastYawTime = gpGlobals->time;
// Clamp delta like the engine does with frametime
if ( delta > 0.25f )
delta = 0.25f;
speed = (float)yawSpeed * delta * 2;
move = ideal - current;
if (ideal > current)
@ -2561,7 +2573,7 @@ float CBaseMonster::ChangeYaw ( int yawSpeed )
if (move < -speed)
move = -speed;
}
pev->angles.y = UTIL_AngleMod (current + move);
// turn head in desired direction only if they have a turnable head
@ -3231,30 +3243,6 @@ BOOL CBaseMonster :: FCanActiveIdle ( void )
}
void CBaseMonster::PlaySentence( const char *pszSentence, float duration, float volume, float attenuation )
{
if ( pszSentence && IsAlive() )
{
if ( pszSentence[0] == '!' )
EMIT_SOUND_DYN( edict(), CHAN_VOICE, pszSentence, volume, attenuation, 0, PITCH_NORM );
else
SENTENCEG_PlayRndSz( edict(), pszSentence, volume, attenuation, 0, PITCH_NORM );
}
}
void CBaseMonster::PlayScriptedSentence( const char *pszSentence, float duration, float volume, float attenuation, BOOL bConcurrent, CBaseEntity *pListener )
{
PlaySentence( pszSentence, duration, volume, attenuation );
}
void CBaseMonster::SentenceStop( void )
{
EMIT_SOUND( edict(), CHAN_VOICE, "common/null.wav", 1.0, ATTN_IDLE );
}
void CBaseMonster::CorpseFallThink( void )
{
if ( pev->flags & FL_ONGROUND )

View file

@ -1,4 +1,4 @@
/***
/***
*
* Copyright (c) 1996-2001, Valve LLC. All rights reserved.
*

View file

@ -55,7 +55,7 @@ void CMP5::Spawn( )
SET_MODEL(ENT(pev), "models/w_9mmAR.mdl");
m_iId = WEAPON_MP5;
m_iDefaultAmmo = MP5_DEFAULT_GIVE;
m_iDefaultAmmo = gpGlobals->maxClients > 1 ? MP5_MAX_CLIP : MP5_DEFAULT_GIVE;
FallInit();// get ready to fall down.
}
@ -158,9 +158,9 @@ void CMP5::PrimaryAttack()
Vector vecDir;
#ifdef CLIENT_DLL
if ( !bIsMultiplayer() )
if ( bIsMultiplayer() )
#else
if ( !g_pGameRules->IsMultiplayer() )
if ( g_pGameRules->IsMultiplayer() )
#endif
{
// optimized multiplayer. Widened to make it easier to hit a moving player

View file

@ -27,6 +27,7 @@
#include "items.h"
#include "voice_gamemgr.h"
#include "hltv.h"
#include "trains.h"
#if !defined ( _WIN32 )
#include <ctype.h>
@ -47,6 +48,15 @@ extern int g_teamplay;
float g_flIntermissionStartTime = 0;
// longest the intermission can last, in seconds
#define MAX_INTERMISSION_TIME 120
extern cvar_t timeleft, fragsleft, sv_busters;
extern cvar_t mp_chattime;
CVoiceGameMgr g_VoiceGameMgr;
class CMultiplayGameMgrHelper : public IVoiceGameMgrHelper
@ -135,7 +145,7 @@ void CHalfLifeMultiplay::RefreshSkillData( void )
gSkillData.plrDmg9MM = 12;
// 357 Round
gSkillData.plrDmg357 = 40;
gSkillData.plrDmg357 = 50;
// MP5 Round
gSkillData.plrDmgMP5 = 12;
@ -169,19 +179,12 @@ void CHalfLifeMultiplay::RefreshSkillData( void )
gSkillData.plrDmgHornet = 10;
}
// longest the intermission can last, in seconds
#define MAX_INTERMISSION_TIME 120
extern cvar_t timeleft, fragsleft;
extern cvar_t mp_chattime;
//=========================================================
//=========================================================
void CHalfLifeMultiplay :: Think ( void )
{
g_VoiceGameMgr.Update(gpGlobals->frametime);
///// Check game rules /////
static int last_frags;
static int last_time;
@ -306,6 +309,18 @@ BOOL CHalfLifeMultiplay::FShouldSwitchWeapon( CBasePlayer *pPlayer, CBasePlayerI
return TRUE;
}
if ( pPlayer->m_iAutoWepSwitch == 0 )
{
return FALSE;
}
else if ( pPlayer->m_iAutoWepSwitch == 2 )
{
if ( pPlayer->m_afButtonLast & ( IN_ATTACK | IN_ATTACK2 ) )
{
return FALSE;
}
}
if ( !pPlayer->m_pActiveItem->CanHolster() )
{
// can't put away the active item.
@ -320,71 +335,11 @@ BOOL CHalfLifeMultiplay::FShouldSwitchWeapon( CBasePlayer *pPlayer, CBasePlayerI
return FALSE;
}
extern BOOL HLGetNextBestWeapon( CBasePlayer* pPlayer, CBasePlayerItem* pCurrentWeapon );
BOOL CHalfLifeMultiplay :: GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon )
{
CBasePlayerItem *pCheck;
CBasePlayerItem *pBest;// this will be used in the event that we don't find a weapon in the same category.
int iBestWeight;
int i;
iBestWeight = -1;// no weapon lower than -1 can be autoswitched to
pBest = NULL;
if ( !pCurrentWeapon->CanHolster() )
{
// can't put this gun away right now, so can't switch.
return FALSE;
}
for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ )
{
pCheck = pPlayer->m_rgpPlayerItems[ i ];
while ( pCheck )
{
if ( pCheck->iWeight() > -1 && pCheck->iWeight() == pCurrentWeapon->iWeight() && pCheck != pCurrentWeapon )
{
// this weapon is from the same category.
if ( pCheck->CanDeploy() )
{
if ( pPlayer->SwitchWeapon( pCheck ) )
{
return TRUE;
}
}
}
else if ( pCheck->iWeight() > iBestWeight && pCheck != pCurrentWeapon )// don't reselect the weapon we're trying to get rid of
{
//ALERT ( at_console, "Considering %s\n", STRING( pCheck->pev->classname ) );
// we keep updating the 'best' weapon just in case we can't find a weapon of the same weight
// that the player was using. This will end up leaving the player with his heaviest-weighted
// weapon.
if ( pCheck->CanDeploy() )
{
// if this weapon is useable, flag it as the best
iBestWeight = pCheck->iWeight();
pBest = pCheck;
}
}
pCheck = pCheck->m_pNext;
}
}
// if we make it here, we've checked all the weapons and found no useable
// weapon in the same catagory as the current weapon.
// if pBest is null, we didn't find ANYTHING. Shouldn't be possible- should always
// at least get the crowbar, but ya never know.
if ( !pBest )
{
return FALSE;
}
pPlayer->SwitchWeapon( pBest );
return TRUE;
return HLGetNextBestWeapon( pPlayer, pCurrentWeapon );
}
//=========================================================
@ -553,6 +508,9 @@ void CHalfLifeMultiplay :: PlayerSpawn( CBasePlayer *pPlayer )
BOOL addDefault;
CBaseEntity *pWeaponEntity = NULL;
int iAutoWepSwitch = pPlayer->m_iAutoWepSwitch;
pPlayer->m_iAutoWepSwitch = 1;
pPlayer->pev->weapons |= (1<<WEAPON_SUIT);
addDefault = TRUE;
@ -569,6 +527,8 @@ void CHalfLifeMultiplay :: PlayerSpawn( CBasePlayer *pPlayer )
pPlayer->GiveNamedItem( "weapon_9mmhandgun" );
pPlayer->GiveAmmo( 68, "9mm", _9MM_MAX_CARRY );// 4 full reloads
}
pPlayer->m_iAutoWepSwitch = iAutoWepSwitch;
}
//=========================================================
@ -605,16 +565,27 @@ int CHalfLifeMultiplay :: IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *p
//=========================================================
void CHalfLifeMultiplay :: PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor )
{
CBasePlayer* peKiller = NULL;
CBaseEntity* ktmp = CBaseEntity::Instance( pKiller );
if ( ktmp && ( ktmp->Classify() == CLASS_PLAYER ) )
peKiller = (CBasePlayer*)ktmp;
else if ( ktmp && ( ktmp->Classify() == CLASS_VEHICLE ) )
{
CBasePlayer* pDriver = ( (CFuncVehicle*)ktmp )->m_pDriver;
if ( pDriver != NULL )
{
peKiller = pDriver;
ktmp = pDriver;
pKiller = pDriver->pev;
}
}
DeathNotice( pVictim, pKiller, pInflictor );
pVictim->m_iDeaths += 1;
FireTargets( "game_playerdie", pVictim, pVictim, USE_TOGGLE, 0 );
CBasePlayer *peKiller = NULL;
CBaseEntity *ktmp = CBaseEntity::Instance( pKiller );
if ( ktmp && (ktmp->Classify() == CLASS_PLAYER) )
peKiller = (CBasePlayer*)ktmp;
if ( pVictim->pev == pKiller )
{ // killed self
@ -819,6 +790,7 @@ void CHalfLifeMultiplay::DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller,
WRITE_LONG( 7 | DRC_FLAG_DRAMATIC); // eventflags (priority and flags)
MESSAGE_END();
// Print a standard message
// TODO: make this go direct to console
return; // just remove for now
@ -1332,7 +1304,8 @@ int ReloadMapCycleFile( char *filename, mapcycle_t *cycle )
if ( strlen( com_token ) <= 0 )
break;
strcpy( szMap, com_token );
strncpy( szMap, com_token, sizeof( szMap ) );
szMap[ sizeof( szMap ) - 1 ] = '\0';
// Any more tokens on this line?
if ( COM_TokenWaiting( pFileList ) )
@ -1341,7 +1314,8 @@ int ReloadMapCycleFile( char *filename, mapcycle_t *cycle )
if ( strlen( com_token ) > 0 )
{
hasbuffer = 1;
strcpy( szBuffer, com_token );
strncpy( szBuffer, com_token, sizeof( szBuffer ) );
szBuffer[ sizeof( szBuffer ) - 1 ] = '\0';
}
}
@ -1689,4 +1663,291 @@ void CHalfLifeMultiplay :: SendMOTDToClient( edict_t *client )
FREE_FILE( aFileList );
}
void CHalfLifeMultiplay :: ClientUserInfoChanged( CBasePlayer *pPlayer, char *infobuffer )
{
// Set preferences
pPlayer->SetPrefsFromUserinfo( infobuffer );
}
//=========================================================
//=========================================================
// Busters Gamerules
//=========================================================
//=========================================================
#define EGON_BUSTING_TIME 10
bool IsBustingGame()
{
return sv_busters.value == 1;
}
bool IsPlayerBusting( CBaseEntity* pPlayer )
{
if ( !pPlayer || !pPlayer->IsPlayer() || !IsBustingGame() )
return FALSE;
return ( (CBasePlayer*)pPlayer )->HasPlayerItemFromID( WEAPON_EGON );
}
BOOL BustingCanHaveItem( CBasePlayer* pPlayer, CBaseEntity* pItem )
{
BOOL bIsWeaponOrAmmo = FALSE;
if ( strstr( STRING( pItem->pev->classname ), "weapon_" ) || strstr( STRING( pItem->pev->classname ), "ammo_" ) )
{
bIsWeaponOrAmmo = TRUE;
}
//Busting players can't have ammo nor weapons
if ( IsPlayerBusting( pPlayer ) && bIsWeaponOrAmmo )
return FALSE;
return TRUE;
}
//=========================================================
CMultiplayBusters::CMultiplayBusters()
{
m_flEgonBustingCheckTime = -1;
}
//=========================================================
void CMultiplayBusters::Think()
{
CheckForEgons();
CHalfLifeMultiplay::Think();
}
//=========================================================
int CMultiplayBusters::IPointsForKill( CBasePlayer* pAttacker, CBasePlayer* pKilled )
{
//If the attacker is busting, they get a point per kill
if ( IsPlayerBusting( pAttacker ) )
return 1;
//If the victim is busting, then the attacker gets a point
if ( IsPlayerBusting( pKilled ) )
return 2;
return 0;
}
//=========================================================
void CMultiplayBusters::PlayerKilled( CBasePlayer* pVictim, entvars_t* pKiller, entvars_t* pInflictor )
{
if ( IsPlayerBusting( pVictim ) )
{
UTIL_ClientPrintAll( HUD_PRINTCENTER, "The Buster is dead!!" );
//Reset egon check time
m_flEgonBustingCheckTime = -1;
CBasePlayer *peKiller = NULL;
CBaseEntity *ktmp = CBaseEntity::Instance( pKiller );
if ( ktmp && ( ktmp->Classify() == CLASS_PLAYER ) )
{
peKiller = (CBasePlayer*)ktmp;
}
else if ( ktmp && ( ktmp->Classify() == CLASS_VEHICLE ) )
{
CBasePlayer *pDriver = ( (CFuncVehicle*)ktmp )->m_pDriver;
if ( pDriver != NULL )
{
peKiller = pDriver;
ktmp = pDriver;
pKiller = pDriver->pev;
}
}
if ( peKiller )
{
UTIL_ClientPrintAll( HUD_PRINTTALK, UTIL_VarArgs( "%s has has killed the Buster!\n", STRING( (CBasePlayer*)peKiller->pev->netname ) ) );
}
pVictim->pev->renderfx = kRenderFxNone;
pVictim->pev->rendercolor = g_vecZero;
//pVictim->pev->effects &= ~EF_BRIGHTFIELD;
}
CHalfLifeMultiplay::PlayerKilled( pVictim, pKiller, pInflictor );
}
//=========================================================
void CMultiplayBusters::DeathNotice( CBasePlayer* pVictim, entvars_t* pKiller, entvars_t* pevInflictor )
{
//Only death notices that the Buster was involved in in Busting game mode
if ( !IsPlayerBusting( pVictim ) && !IsPlayerBusting( CBaseEntity::Instance( pKiller ) ) )
return;
CHalfLifeMultiplay::DeathNotice( pVictim, pKiller, pevInflictor );
}
//=========================================================
int CMultiplayBusters::WeaponShouldRespawn( CBasePlayerItem* pWeapon )
{
if ( pWeapon->m_iId == WEAPON_EGON )
return GR_WEAPON_RESPAWN_NO;
return CHalfLifeMultiplay::WeaponShouldRespawn( pWeapon );
}
//=========================================================
// CheckForEgons:
//Check to see if any player has an egon
//If they don't then get the lowest player on the scoreboard and give them one
//Then check to see if any weapon boxes out there has an egon, and delete it
//=========================================================
void CMultiplayBusters::CheckForEgons()
{
if ( m_flEgonBustingCheckTime <= 0.0f )
{
m_flEgonBustingCheckTime = gpGlobals->time + EGON_BUSTING_TIME;
return;
}
if ( m_flEgonBustingCheckTime <= gpGlobals->time )
{
m_flEgonBustingCheckTime = -1.0f;
for ( int i = 1; i <= gpGlobals->maxClients; i++ )
{
CBasePlayer* pPlayer = (CBasePlayer*)UTIL_PlayerByIndex( i );
//Someone is busting, no need to continue
if ( IsPlayerBusting( pPlayer ) )
return;
}
int bBestFrags = 9999;
CBasePlayer* pBestPlayer = NULL;
for ( int i = 1; i <= gpGlobals->maxClients; i++ )
{
CBasePlayer* pPlayer = (CBasePlayer*)UTIL_PlayerByIndex( i );
if ( pPlayer && pPlayer->pev->frags <= bBestFrags )
{
bBestFrags = pPlayer->pev->frags;
pBestPlayer = pPlayer;
}
}
if ( pBestPlayer )
{
pBestPlayer->GiveNamedItem( "weapon_egon" );
CBaseEntity* pEntity = NULL;
//Find a weaponbox that includes an Egon, then destroy it
while ( ( pEntity = UTIL_FindEntityByClassname( pEntity, "weaponbox" ) ) != NULL )
{
CWeaponBox* pWeaponBox = (CWeaponBox*)pEntity;
if ( pWeaponBox )
{
CBasePlayerItem* pWeapon;
for ( int i = 0; i < MAX_ITEM_TYPES; i++ )
{
pWeapon = pWeaponBox->m_rgpPlayerItems[i];
while ( pWeapon )
{
//There you are, bye box
if ( pWeapon->m_iId == WEAPON_EGON )
{
pWeaponBox->Kill();
break;
}
pWeapon = pWeapon->m_pNext;
}
}
}
}
}
}
}
//=========================================================
BOOL CMultiplayBusters::CanHavePlayerItem( CBasePlayer* pPlayer, CBasePlayerItem* pItem )
{
//Buster cannot have more weapons nor ammo
if ( BustingCanHaveItem( pPlayer, pItem ) == FALSE )
{
return FALSE;
}
return CHalfLifeMultiplay::CanHavePlayerItem( pPlayer, pItem );
}
//=========================================================
BOOL CMultiplayBusters::CanHaveItem( CBasePlayer* pPlayer, CItem* pItem )
{
//Buster cannot have more weapons nor ammo
if (BustingCanHaveItem( pPlayer, pItem ) == FALSE )
{
return FALSE;
}
return CHalfLifeMultiplay::CanHaveItem( pPlayer, pItem );
}
//=========================================================
void CMultiplayBusters::PlayerGotWeapon( CBasePlayer* pPlayer, CBasePlayerItem* pWeapon )
{
if ( pWeapon->m_iId == WEAPON_EGON )
{
pPlayer->RemoveAllItems( false );
UTIL_ClientPrintAll( HUD_PRINTCENTER, "Long live the new Buster!" );
UTIL_ClientPrintAll( HUD_PRINTTALK, UTIL_VarArgs( "%s is busting!\n", STRING( (CBasePlayer*)pPlayer->pev->netname ) ) );
SetPlayerModel( pPlayer );
pPlayer->pev->health = pPlayer->pev->max_health;
pPlayer->pev->armorvalue = 100;
pPlayer->pev->renderfx = kRenderFxGlowShell;
pPlayer->pev->renderamt = 25;
pPlayer->pev->rendercolor = Vector( 0, 75, 250 );
CBasePlayerWeapon *pEgon = (CBasePlayerWeapon*)pWeapon;
pEgon->m_iDefaultAmmo = 100;
pPlayer->m_rgAmmo[pEgon->m_iPrimaryAmmoType] = pEgon->m_iDefaultAmmo;
g_engfuncs.pfnSetClientKeyValue( pPlayer->entindex(), g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "model", "ivan" );
}
}
void CMultiplayBusters::ClientUserInfoChanged( CBasePlayer* pPlayer, char* infobuffer )
{
SetPlayerModel( pPlayer );
// Set preferences
pPlayer->SetPrefsFromUserinfo( infobuffer );
}
void CMultiplayBusters::PlayerSpawn( CBasePlayer* pPlayer )
{
CHalfLifeMultiplay::PlayerSpawn( pPlayer );
SetPlayerModel( pPlayer );
}
void CMultiplayBusters::SetPlayerModel( CBasePlayer* pPlayer )
{
if ( IsPlayerBusting( pPlayer ) )
{
g_engfuncs.pfnSetClientKeyValue( pPlayer->entindex(), g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "model", "ivan" );
}
else
{
g_engfuncs.pfnSetClientKeyValue( pPlayer->entindex(), g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "model", "skeleton" );
}
}

View file

@ -28,7 +28,7 @@
class CNihilanth : public CBaseMonster
{
public:
int Save( CSave &save );
int Save( CSave &save );
int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
@ -462,7 +462,7 @@ void CNihilanth :: DyingThink( void )
{
if (m_pBall->pev->renderamt > 0)
{
m_pBall->pev->renderamt = max( 0, m_pBall->pev->renderamt - 2);
m_pBall->pev->renderamt = max<float>( 0, m_pBall->pev->renderamt - 2);
}
else
{
@ -884,7 +884,7 @@ void CNihilanth :: HuntThink( void )
}
else
{
m_flAdj = min( m_flAdj + 10, 1000 );
m_flAdj = min( m_flAdj + 10.0f, 1000.0f );
}
}

View file

@ -1433,7 +1433,7 @@ int CGraph :: RejectInlineLinks ( CLink *pLinkPool, FILE *file )
// TestHull is a modelless clip hull that verifies reachable
// nodes by walking from every node to each of it's connections
//=========================================================
class CTestHull : public CBaseMonster
class CTestHull : public CBaseMonster
{
public:

View file

@ -223,7 +223,7 @@ void CBasePlayer::Observer_CheckProperties()
}
// Attempt to change the observer mode
void CBasePlayer::Observer_SetMode( int iMode )
void CBasePlayer::Observer_SetMode( int iMode )
{
// Just abort if we're changing to the mode we're already in

View file

@ -37,7 +37,7 @@ typedef struct
#define MAX_CARRY 24
class COsprey : public CBaseMonster
class COsprey : public CBaseMonster
{
public:
int Save( CSave &save );

View file

@ -2103,7 +2103,7 @@ void CFuncTrackAuto :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_T
#define FGUNTARGET_START_ON 0x0001
class CGunTarget : public CBaseMonster
class CGunTarget : public CBaseMonster
{
public:
void Spawn( void );

View file

@ -44,15 +44,17 @@ extern DLL_GLOBAL BOOL g_fGameOver;
extern DLL_GLOBAL BOOL g_fDrawLines;
int gEvilImpulse101;
extern DLL_GLOBAL int g_iSkillLevel, gDisplayTitle;
BOOL gInitHUD = TRUE;
BOOL gInitHUD = TRUE;
extern void CopyToBodyQue(entvars_t* pev);
extern void respawn(entvars_t *pev, BOOL fCopyCorpse);
extern Vector VecBModelOrigin(entvars_t *pevBModel );
extern edict_t *EntSelectSpawnPoint( CBaseEntity *pPlayer );
extern bool IsBustingGame();
// the world node graph
extern CGraph WorldGraph;
@ -718,8 +720,20 @@ void CBasePlayer::PackDeadPlayerItems( void )
case GR_PLR_DROP_GUN_ACTIVE:
if ( m_pActiveItem && pPlayerItem == m_pActiveItem )
{
CBasePlayerWeapon *pWeapon = (CBasePlayerWeapon*)pPlayerItem;
int nIndex = iPW++;
// this is the active item. Pack it.
rgpPackWeapons[ iPW++ ] = (CBasePlayerWeapon *)pPlayerItem;
rgpPackWeapons[nIndex] = pWeapon;
//Reload the weapon before dropping it if we have ammo
int j = min( pWeapon->iMaxClip() - pWeapon->m_iClip, m_rgAmmo[pWeapon->m_iPrimaryAmmoType] );
// Add them to the clip
pWeapon->m_iClip += j;
m_rgAmmo[pWeapon->m_iPrimaryAmmoType] -= j;
TabulateAmmo();
}
break;
@ -783,24 +797,69 @@ void CBasePlayer::PackDeadPlayerItems( void )
iPA = 0;
iPW = 0;
// pack the ammo
while ( iPackAmmo[ iPA ] != -1 )
if ( IsBustingGame() )
{
pWeaponBox->PackAmmo( MAKE_STRING( CBasePlayerItem::AmmoInfoArray[ iPackAmmo[ iPA ] ].pszName ), m_rgAmmo[ iPackAmmo[ iPA ] ] );
iPA++;
}
if ( HasNamedPlayerItem( "weapon_egon" ) )
{
for ( i = 0; i < MAX_ITEM_TYPES; i++ )
{
CBasePlayerItem *pItem = m_rgpPlayerItems[i];
// now pack all of the items in the lists
while ( rgpPackWeapons[ iPW ] )
if ( pItem )
{
if ( !strcmp( "weapon_egon", STRING( pItem->pev->classname ) ) )
{
pWeaponBox->PackWeapon( pItem );
SET_MODEL( ENT( pWeaponBox->pev ), "models/w_egon.mdl" );
pWeaponBox->pev->velocity = vec3_t( 0, 0, 0 );
pWeaponBox->pev->renderfx = kRenderFxGlowShell;
pWeaponBox->pev->renderamt = 25;
pWeaponBox->pev->rendercolor = Vector( 0, 75, 250 );
break;
}
}
}
}
}
else
{
// weapon unhooked from the player. Pack it into der box.
pWeaponBox->PackWeapon( rgpPackWeapons[ iPW ] );
bool bPackItems = TRUE;
iPW++;
if ( iAmmoRules == GR_PLR_DROP_AMMO_ACTIVE && iWeaponRules == GR_PLR_DROP_GUN_ACTIVE )
{
if ( FClassnameIs( rgpPackWeapons[0]->pev, "weapon_satchel" ) && ( iPackAmmo[0] == -1 || ( m_rgAmmo[iPackAmmo[0]] == 0 ) ) )
{
bPackItems = FALSE;
}
}
if ( bPackItems )
{
// pack the ammo
while ( iPackAmmo[iPA] != -1 )
{
pWeaponBox->PackAmmo( MAKE_STRING( CBasePlayerItem::AmmoInfoArray[iPackAmmo[iPA]].pszName ), m_rgAmmo[iPackAmmo[iPA]] );
iPA++;
}
// now pack all of the items in the lists
while ( rgpPackWeapons[iPW] )
{
// weapon unhooked from the player. Pack it into der box.
pWeaponBox->PackWeapon( rgpPackWeapons[iPW] );
iPW++;
}
}
pWeaponBox->pev->velocity = pev->velocity * 1.2;// weaponbox has player's velocity, then some.
}
pWeaponBox->pev->velocity = pev->velocity * 1.2;// weaponbox has player's velocity, then some.
RemoveAllItems( TRUE );// now strip off everything that wasn't handled by the code above.
}
@ -891,7 +950,7 @@ void CBasePlayer::Killed( entvars_t *pevAttacker, int iGib )
SetAnimation( PLAYER_DIE );
m_iRespawnFrames = 0;
m_flRespawnTimer = 0.0f;
pev->modelindex = g_ulModelIndexPlayer; // don't use eyes
@ -924,13 +983,19 @@ void CBasePlayer::Killed( entvars_t *pevAttacker, int iGib )
WRITE_BYTE(0);
MESSAGE_END();
//Adrian: always make the players non-solid in multiplayer when they die
if ( g_pGameRules->IsMultiplayer() )
{
pev->solid = SOLID_NOT;
}
// UNDONE: Put this in, but add FFADE_PERMANENT and make fade time 8.8 instead of 4.12
// UTIL_ScreenFade( edict(), Vector(128,0,0), 6, 15, 255, FFADE_OUT | FFADE_MODULATE );
if ( ( pev->health < -40 && iGib != GIB_NEVER ) || iGib == GIB_ALWAYS )
{
pev->solid = SOLID_NOT;
pev->solid = SOLID_NOT;
GibMonster(); // This clears pev->model
pev->effects |= EF_NODRAW;
return;
@ -1028,6 +1093,9 @@ void CBasePlayer::SetAnimation( PLAYER_ANIM playerAnim )
if (pev->sequence == animDesired)
return;
//ALERT(at_console, "Set die animation to %d\n", animDesired);
pev->gaitsequence = 0;
pev->sequence = animDesired;
pev->frame = 0;
@ -1111,6 +1179,7 @@ void CBasePlayer::SetAnimation( PLAYER_ANIM playerAnim )
return;
//ALERT( at_console, "Set animation to %d\n", animDesired );
// Reset to first frame of desired animation
pev->sequence = animDesired;
pev->frame = 0;
@ -1292,18 +1361,29 @@ void CBasePlayer::PlayerDeathThink(void)
{
StudioFrameAdvance( );
m_iRespawnFrames++; // Note, these aren't necessarily real "frames", so behavior is dependent on # of client movement commands
if ( m_iRespawnFrames < 120 ) // Animations should be no longer than this
m_flRespawnTimer += gpGlobals->frametime;
if ( m_flRespawnTimer < 4.0f ) // 120 frames at 30fps -- animations should be no longer than this
return;
}
if ( pev->deadflag == DEAD_DYING )
{
//Once we finish animating, if we're in multiplayer just make a copy of our body right away.
if ( m_fSequenceFinished && g_pGameRules->IsMultiplayer() && pev->movetype == MOVETYPE_NONE )
{
CopyToBodyQue( pev );
pev->modelindex = 0;
}
pev->deadflag = DEAD_DEAD;
}
// once we're done animating our death and we're on the ground, we want to set movetype to None so our dead body won't do collisions and stuff anymore
// this prevents a bug where the dead body would go to a player's head if he walked over it while the dead player was clicking their button to respawn
if ( pev->movetype != MOVETYPE_NONE && FBitSet(pev->flags, FL_ONGROUND) )
pev->movetype = MOVETYPE_NONE;
if (pev->deadflag == DEAD_DYING)
pev->deadflag = DEAD_DEAD;
StopAnimation();
@ -1330,7 +1410,7 @@ void CBasePlayer::PlayerDeathThink(void)
// if the player has been dead for one second longer than allowed by forcerespawn,
// forcerespawn isn't on. Send the player off to an intermission camera until they
// choose to respawn.
if ( g_pGameRules->IsMultiplayer() && ( gpGlobals->time > (m_fDeadTime + 6) ) && !(m_afPhysicsFlags & PFLAG_OBSERVER) )
if ( g_pGameRules->IsMultiplayer() && ( gpGlobals->time > (m_fDeadTime + 6) ) && !(m_afPhysicsFlags & PFLAG_OBSERVER) )
{
// go to dead camera.
StartDeathCam();
@ -1345,7 +1425,7 @@ void CBasePlayer::PlayerDeathThink(void)
return;
pev->button = 0;
m_iRespawnFrames = 0;
m_flRespawnTimer = 0.0f;
//ALERT(at_console, "Respawn\n");
@ -1515,6 +1595,9 @@ void CBasePlayer::PlayerUse ( void )
{
m_afPhysicsFlags &= ~PFLAG_ONTRAIN;
m_iTrain = TRAIN_NEW|TRAIN_OFF;
CBaseEntity *pTrain = CBaseEntity::Instance( pev->groundentity );
if (pTrain && (pTrain->Classify() == CLASS_VEHICLE))
((CFuncVehicle*)pTrain)->m_pDriver = NULL;
return;
}
else
@ -1526,7 +1609,13 @@ void CBasePlayer::PlayerUse ( void )
m_afPhysicsFlags |= PFLAG_ONTRAIN;
m_iTrain = TrainSpeed(pTrain->pev->speed, pTrain->pev->impulse);
m_iTrain |= TRAIN_NEW;
EMIT_SOUND( ENT(pev), CHAN_ITEM, "plats/train_use1.wav", 0.8, ATTN_NORM);
if (pTrain->Classify() == CLASS_VEHICLE)
{
EMIT_SOUND( ENT(pev), CHAN_ITEM, "plats/vehicle_ignition.wav", 0.8, ATTN_NORM);
((CFuncVehicle*)pTrain)->m_pDriver = this;
}
else
EMIT_SOUND( ENT(pev), CHAN_ITEM, "plats/train_use1.wav", 0.8, ATTN_NORM);
return;
}
}
@ -1646,6 +1735,16 @@ void CBasePlayer::Jump()
{
pev->velocity = pev->velocity + pev->basevelocity;
}
// JoshA: CS behaviour does this for tracktrain + train as well,
// but let's just do this for func_vehicle to avoid breaking existing content.
//
// If you're standing on a moving train... then add the velocity of the train to yours.
if ( pevGround && ( /*(!strcmp( "func_tracktrain", STRING(pevGround->classname))) ||
(!strcmp( "func_train", STRING(pevGround->classname))) ) ||*/
(!strcmp( "func_vehicle", STRING(pevGround->classname)))) )
pev->velocity = pev->velocity + pevGround->velocity;
}
@ -1923,28 +2022,59 @@ void CBasePlayer::PreThink(void)
//ALERT( at_error, "In train mode with no train!\n" );
m_afPhysicsFlags &= ~PFLAG_ONTRAIN;
m_iTrain = TRAIN_NEW|TRAIN_OFF;
if (pTrain->Classify() == CLASS_VEHICLE)
((CFuncVehicle*)pTrain)->m_pDriver = NULL;
return;
}
}
else if ( !FBitSet( pev->flags, FL_ONGROUND ) || FBitSet( pTrain->pev->spawnflags, SF_TRACKTRAIN_NOCONTROL ) || (pev->button & (IN_MOVELEFT|IN_MOVERIGHT) ) )
else if ( !FBitSet( pev->flags, FL_ONGROUND ) || FBitSet( pTrain->pev->spawnflags, SF_TRACKTRAIN_NOCONTROL ) || ((pev->button & (IN_MOVELEFT|IN_MOVERIGHT) ) && pTrain->Classify() != CLASS_VEHICLE) )
{
// Turn off the train if you jump, strafe, or the train controls go dead
// and it isn't a func_vehicle.
m_afPhysicsFlags &= ~PFLAG_ONTRAIN;
m_iTrain = TRAIN_NEW|TRAIN_OFF;
if (pTrain->Classify() == CLASS_VEHICLE)
((CFuncVehicle*)pTrain)->m_pDriver = NULL;
return;
}
pev->velocity = g_vecZero;
vel = 0;
if ( m_afButtonPressed & IN_FORWARD )
if (pTrain->Classify() == CLASS_VEHICLE)
{
vel = 1;
pTrain->Use( this, this, USE_SET, (float)vel );
if ( pev->button & IN_FORWARD )
{
vel = 1;
pTrain->Use( this, this, USE_SET, (float)vel );
}
if ( pev->button & IN_BACK )
{
vel = -1;
pTrain->Use( this, this, USE_SET, (float)vel );
}
if ( pev->button & IN_MOVELEFT)
{
vel = 20;
pTrain->Use( this, this, USE_SET, (float)vel );
}
if ( pev->button & IN_MOVERIGHT)
{
vel = 30;
pTrain->Use( this, this, USE_SET, (float)vel );
}
}
else if ( m_afButtonPressed & IN_BACK )
else
{
vel = -1;
pTrain->Use( this, this, USE_SET, (float)vel );
if ( m_afButtonPressed & IN_FORWARD )
{
vel = 1;
pTrain->Use( this, this, USE_SET, (float)vel );
}
else if ( m_afButtonPressed & IN_BACK )
{
vel = -1;
pTrain->Use( this, this, USE_SET, (float)vel );
}
}
if (vel)
@ -2674,23 +2804,23 @@ pt_end:
if ( gun && gun->UseDecrement() )
{
gun->m_flNextPrimaryAttack = max( gun->m_flNextPrimaryAttack - gpGlobals->frametime, -1.0 );
gun->m_flNextSecondaryAttack = max( gun->m_flNextSecondaryAttack - gpGlobals->frametime, -0.001 );
gun->m_flNextPrimaryAttack = max( gun->m_flNextPrimaryAttack - gpGlobals->frametime, -1.0f );
gun->m_flNextSecondaryAttack = max( gun->m_flNextSecondaryAttack - gpGlobals->frametime, -0.001f );
if ( gun->m_flTimeWeaponIdle != 1000 )
{
gun->m_flTimeWeaponIdle = max( gun->m_flTimeWeaponIdle - gpGlobals->frametime, -0.001 );
gun->m_flTimeWeaponIdle = max( gun->m_flTimeWeaponIdle - gpGlobals->frametime, -0.001f );
}
if ( gun->pev->fuser1 != 1000 )
{
gun->pev->fuser1 = max( gun->pev->fuser1 - gpGlobals->frametime, -0.001 );
gun->pev->fuser1 = max( gun->pev->fuser1 - gpGlobals->frametime, -0.001f );
}
// Only decrement if not flagged as NO_DECREMENT
// if ( gun->m_flPumpTime != 1000 )
// {
// gun->m_flPumpTime = max( gun->m_flPumpTime - gpGlobals->frametime, -0.001 );
// gun->m_flPumpTime = max( gun->m_flPumpTime - gpGlobals->frametime, -0.001f );
// }
}
@ -2764,6 +2894,8 @@ edict_t *EntSelectSpawnPoint( CBaseEntity *pPlayer )
CBaseEntity *pSpot;
edict_t *player;
int nNumRandomSpawnsToTry = 10;
player = pPlayer->edict();
// choose a info_player_deathmatch point
@ -2778,9 +2910,21 @@ edict_t *EntSelectSpawnPoint( CBaseEntity *pPlayer )
}
else if ( g_pGameRules->IsDeathmatch() )
{
if (NULL == g_pLastSpawn)
{
int nNumSpawnPoints = 0;
CBaseEntity* pEnt = UTIL_FindEntityByClassname(NULL, "info_player_deathmatch");
while (NULL != pEnt)
{
nNumSpawnPoints++;
pEnt = UTIL_FindEntityByClassname(pEnt, "info_player_deathmatch");
}
nNumRandomSpawnsToTry = nNumSpawnPoints;
}
pSpot = g_pLastSpawn;
// Randomize the start spot
for ( int i = RANDOM_LONG(1,5); i > 0; i-- )
for ( int i = RANDOM_LONG(1, nNumRandomSpawnsToTry - 1); i > 0; i-- )
pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_deathmatch" );
if ( FNullEnt( pSpot ) ) // skip over the null point
pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_deathmatch" );
@ -2849,6 +2993,8 @@ ReturnSpot:
void CBasePlayer::Spawn( void )
{
m_flStartCharge = gpGlobals->time;
pev->classname = MAKE_STRING("player");
pev->health = 100;
pev->armorvalue = 0;
@ -3056,6 +3202,9 @@ int CBasePlayer::Restore( CRestore &restore )
RenewItems();
//Resync ammo data so you can reload - Solokiller
TabulateAmmo();
#if defined( CLIENT_WEAPONS )
// HACK: This variable is saved/restored in CBaseMonster as a time variable, but we're using it
// as just a counter. Ideally, this needs its own variable that's saved as a plain float.
@ -3063,6 +3212,12 @@ int CBasePlayer::Restore( CRestore &restore )
m_flNextAttack = UTIL_WeaponTimeBase();
#endif
// Force a flashlight update for the HUD
if ( m_flFlashLightTime == 0 )
{
m_flFlashLightTime = 1;
}
return status;
}
@ -3424,8 +3579,6 @@ void CBasePlayer :: ForceClientDllUpdate( void )
ImpulseCommands
============
*/
extern float g_flWeaponCheat;
void CBasePlayer::ImpulseCommands( )
{
TraceResult tr;// UNDONE: kill me! This is temporary for PreAlpha CDs
@ -3507,7 +3660,7 @@ void CBasePlayer::ImpulseCommands( )
void CBasePlayer::CheatImpulseCommands( int iImpulse )
{
#if !defined( HLDEMO_BUILD )
if ( g_flWeaponCheat == 0.0 )
if ( CVAR_GET_FLOAT( "sv_cheats" ) == 0.0 )
{
return;
}
@ -3755,7 +3908,7 @@ int CBasePlayer::RemovePlayerItem( CBasePlayerItem *pItem )
pev->viewmodel = 0;
pev->weaponmodel = 0;
}
else if ( m_pLastItem == pItem )
if ( m_pLastItem == pItem )
m_pLastItem = NULL;
CBasePlayerItem *pPrev = m_rgpPlayerItems[pItem->iItemSlot()];
@ -4180,6 +4333,22 @@ void CBasePlayer :: UpdateClientData( void )
}
}
void CBasePlayer :: SetPrefsFromUserinfo( char * infobuffer )
{
const char * pszKeyVal;
// Set autoswitch preference
pszKeyVal = g_engfuncs.pfnInfoKeyValue( infobuffer, "cl_autowepswitch" );
if ( FStrEq( pszKeyVal, "" ) )
{
m_iAutoWepSwitch = 1;
}
else
{
m_iAutoWepSwitch = atoi( pszKeyVal );
}
}
//=========================================================
// FBecomeProne - Overridden for the player to set the proper
@ -4317,7 +4486,7 @@ Vector CBasePlayer :: GetAutoaimVector( float flDelta )
// m_vecAutoAim = m_vecAutoAim * 0.99;
// Don't send across network if sv_aim is 0
if ( g_psv_aim->value != 0 )
if ( g_psv_aim->value != 0 && g_psv_allow_autoaim->value != 0 )
{
if ( m_vecAutoAim.x != m_lastx ||
m_vecAutoAim.y != m_lasty )
@ -4345,7 +4514,7 @@ Vector CBasePlayer :: AutoaimDeflection( Vector &vecSrc, float flDist, float flD
edict_t *bestent;
TraceResult tr;
if ( g_psv_aim->value == 0 )
if ( g_psv_aim->value == 0 || g_psv_allow_autoaim->value == 0 )
{
m_fOnTarget = FALSE;
return g_vecZero;
@ -4642,6 +4811,33 @@ BOOL CBasePlayer::HasNamedPlayerItem( const char *pszItemName )
return FALSE;
}
//=========================================================
// HasPlayerItemFromID
// Just compare IDs, rather than classnames
//=========================================================
BOOL CBasePlayer::HasPlayerItemFromID( int nID )
{
CBasePlayerItem* pItem;
int i;
for ( i = 0; i < MAX_ITEM_TYPES; i++ )
{
pItem = m_rgpPlayerItems[i];
while ( pItem )
{
if ( pItem->m_iId == nID )
{
return TRUE;
}
pItem = pItem->m_pNext;
}
}
return FALSE;
}
//=========================================================
//
//=========================================================
@ -4668,7 +4864,7 @@ BOOL CBasePlayer :: SwitchWeapon( CBasePlayerItem *pWeapon )
//=========================================================
// Dead HEV suit prop
//=========================================================
class CDeadHEV : public CBaseMonster
class CDeadHEV : public CBaseMonster
{
public:
void Spawn( void );

View file

@ -189,7 +189,7 @@ public:
Vector m_vecAutoAim;
BOOL m_fOnTarget;
int m_iDeaths;
float m_iRespawnFrames; // used in PlayerDeathThink() to make sure players can always respawn
float m_flRespawnTimer; // used in PlayerDeathThink() to make sure players can always respawn
int m_lastx, m_lasty; // These are the previous update's crosshair angles, DON"T SAVE/RESTORE
@ -232,6 +232,8 @@ public:
// JOHN: sends custom messages if player HUD data has changed (eg health, ammo)
virtual void UpdateClientData( void );
void SetPrefsFromUserinfo( char * infobuffer );
static TYPEDESCRIPTION m_playerSaveData[];
@ -265,6 +267,7 @@ public:
void DropPlayerItem ( char *pszItemName );
BOOL HasPlayerItem( CBasePlayerItem *pCheckItem );
BOOL HasNamedPlayerItem( const char *pszItemName );
BOOL HasPlayerItemFromID( int nID );
BOOL HasWeapons( void );// do I have ANY weapons?
void SelectPrevItem( int iItem );
void SelectNextItem( int iItem );
@ -323,6 +326,7 @@ public:
float m_flNextChatTime;
int m_iAutoWepSwitch;
};
#define AUTOAIM_2DEGREES 0.0348994967025

View file

@ -171,7 +171,7 @@ void CPython::PrimaryAttack()
Reload( );
else
{
EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/357_cock1.wav", 0.8, ATTN_NORM);
PlayEmptySound();
m_flNextPrimaryAttack = 0.15;
}
@ -306,4 +306,4 @@ class CPythonAmmo : public CBasePlayerAmmo
LINK_ENTITY_TO_CLASS( ammo_357, CPythonAmmo );
#endif
#endif

View file

@ -26,7 +26,7 @@
// Monster's Anim Events Go Here
//=========================================================
class CRat : public CBaseMonster
class CRat : public CBaseMonster
{
public:
void Spawn( void );

View file

@ -38,7 +38,7 @@ class CRoach : public CBaseMonster
{
public:
void Spawn( void );
void Precache( void );
void Precache( void );
void SetYawSpeed( void );
void EXPORT MonsterThink ( void );
void Move ( float flInterval );

View file

@ -111,8 +111,9 @@ CRpgRocket *CRpgRocket::CreateRpgRocket( Vector vecOrigin, Vector vecAngles, CBa
pRocket->pev->angles = vecAngles;
pRocket->Spawn();
pRocket->SetTouch( &CRpgRocket::RocketTouch );
pRocket->m_pLauncher = pLauncher;// remember what RPG fired me.
pRocket->m_pLauncher->m_cActiveRockets++;// register this missile as active for the launcher
pLauncher->m_cActiveRockets++;
pRocket->m_hLauncher = pLauncher;// remember what RPG fired me.
pRocket->pev->owner = pOwner->edict();
return pRocket;
@ -152,16 +153,36 @@ void CRpgRocket :: Spawn( void )
//=========================================================
void CRpgRocket :: RocketTouch ( CBaseEntity *pOther )
{
if ( m_pLauncher )
//ALERT( at_console, "RpgRocket RocketTouch, m_pLauncher: %u\n", GetLauncher() );
if ( GetLauncher() )
{
// my launcher is still around, tell it I'm dead.
m_pLauncher->m_cActiveRockets--;
}
GetLauncher()->m_cActiveRockets--;
m_hLauncher = NULL;
}
STOP_SOUND( edict(), CHAN_VOICE, "weapons/rocket1.wav" );
ExplodeTouch( pOther );
}
//=========================================================
void CRpgRocket::Explode( TraceResult *pTrace, int bitsDamageType )
{
//ALERT( at_console, "RpgRocket Explode, m_pLauncher: %u\n", GetLauncher() );
STOP_SOUND( edict(), CHAN_VOICE, "weapons/rocket1.wav");
if ( GetLauncher() )
{
// my launcher is still around, tell it I'm dead.
GetLauncher()->m_cActiveRockets--;
m_hLauncher = NULL;
}
CGrenade::Explode( pTrace, bitsDamageType );
}
//=========================================================
//=========================================================
void CRpgRocket :: Precache( void )
@ -205,6 +226,14 @@ void CRpgRocket :: IgniteThink( void )
}
CRpg* CRpgRocket::GetLauncher()
{
if ( !m_hLauncher )
return NULL;
return (CRpg*)( (CBaseEntity*)m_hLauncher );
}
void CRpgRocket :: FollowThink( void )
{
CBaseEntity *pOther = NULL;
@ -217,16 +246,25 @@ void CRpgRocket :: FollowThink( void )
vecTarget = gpGlobals->v_forward;
flMax = 4096;
// Examine all entities within a reasonable radius
while ((pOther = UTIL_FindEntityByClassname( pOther, "laser_spot" )) != NULL)
{
UTIL_TraceLine ( pev->origin, pOther->pev->origin, dont_ignore_monsters, ENT(pev), &tr );
// ALERT( at_console, "%f\n", tr.flFraction );
Vector vSpotLocation = pOther->pev->origin;
if( UTIL_PointContents( vSpotLocation ) == CONTENTS_SKY )
{
//ALERT( at_console, "laser spot is in the sky...\n");
}
UTIL_TraceLine ( pev->origin, vSpotLocation, dont_ignore_monsters, ENT(pev), &tr );
//ALERT( at_console, "fraction: %f\n", tr.flFraction );
if (tr.flFraction >= 0.90)
{
vecDir = pOther->pev->origin - pev->origin;
flDist = vecDir.Length( );
flDist = vecDir.Length( );
vecDir = vecDir.Normalize( );
flDot = DotProduct( gpGlobals->v_forward, vecDir );
if ((flDot > 0) && (flDist * (1 - flDot) < flMax))
@ -274,7 +312,27 @@ void CRpgRocket :: FollowThink( void )
Detonate( );
}
}
// ALERT( at_console, "%.0f\n", flSpeed );
if( GetLauncher() )
{
float flDistance = ( pev->origin - GetLauncher()->pev->origin ).Length();
// if we've travelled more than max distance the player can send a spot, stop tracking the original launcher (allow it to reload)
if( flDistance > 8192.0f || gpGlobals->time - m_flIgniteTime > 6.0f )
{
//ALERT( at_console, "RPG too far (%f)!\n", flDistance );
GetLauncher()->m_cActiveRockets--;
m_hLauncher = NULL;
}
//ALERT( at_console, "%.0f, m_pLauncher: %u, flDistance: %f\n", flSpeed, GetLauncher(), flDistance );
}
if( (UTIL_PointContents(pev->origin) == CONTENTS_SKY ) )
{
//ALERT( at_console, "Rocket is in the sky, detonating...\n");
Detonate();
}
pev->nextthink = gpGlobals->time + 0.1;
}
@ -284,6 +342,8 @@ void CRpgRocket :: FollowThink( void )
void CRpg::Reload( void )
{
//ALERT( at_console, "RPG Reload, m_cActiveRockets: %d, m_fSpotActive: %d\n", m_cActiveRockets, m_fSpotActive );
int iResult;
if ( m_iClip == 1 )
@ -309,6 +369,8 @@ void CRpg::Reload( void )
if ( m_cActiveRockets && m_fSpotActive )
{
//ALERT( at_console, "RPG reload failed, m_cActiveRockets: %d, m_fSpotActive: %d\n", m_cActiveRockets, m_fSpotActive );
// no reloading when there are active missiles tracking the designator.
// ward off future autoreload attempts by setting next attack time into the future for a bit.
return;
@ -385,7 +447,7 @@ int CRpg::GetItemInfo(ItemInfo *p)
p->iSlot = 3;
p->iPosition = 0;
p->iId = m_iId = WEAPON_RPG;
p->iFlags = 0;
p->iFlags = ITEM_FLAG_NOAUTOSWITCHTO;
p->iWeight = RPG_WEIGHT;
return 1;
@ -481,6 +543,8 @@ void CRpg::PrimaryAttack()
m_flNextPrimaryAttack = GetNextAttackDelay(1.5);
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.5;
ResetEmptySound();
}
else
{
@ -510,8 +574,6 @@ void CRpg::WeaponIdle( void )
{
UpdateSpot( );
ResetEmptySound( );
if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() )
return;
@ -538,6 +600,7 @@ void CRpg::WeaponIdle( void )
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3.0;
}
ResetEmptySound( );
SendWeaponAnim( iAnim );
}
else

View file

@ -1,4 +1,4 @@
/***
/***
*
* Copyright (c) 1996-2001, Valve LLC. All rights reserved.
*
@ -176,7 +176,7 @@ LINK_ENTITY_TO_CLASS( weapon_satchel, CSatchel );
//=========================================================
int CSatchel::AddDuplicate( CBasePlayerItem *pOriginal )
{
CSatchel *pSatchel;
CSatchel* pSatchel = NULL;
#ifdef CLIENT_DLL
if ( bIsMultiplayer() )
@ -186,7 +186,26 @@ int CSatchel::AddDuplicate( CBasePlayerItem *pOriginal )
{
pSatchel = (CSatchel *)pOriginal;
if ( pSatchel->m_chargeReady != 0 )
if ( pOriginal->m_pPlayer == NULL )
return TRUE;
int nSatchelsInPocket = pSatchel->m_pPlayer->m_rgAmmo[ pSatchel->PrimaryAmmoIndex() ];
int nNumSatchels = 0;
CBaseEntity* pLiveSatchel = NULL;
while ( ( pLiveSatchel = UTIL_FindEntityInSphere( pLiveSatchel, pOriginal->m_pPlayer->pev->origin, 4096 ) ) != NULL )
{
if ( FClassnameIs( pLiveSatchel->pev, "monster_satchel" ) )
{
if ( pLiveSatchel->pev->owner == pOriginal->m_pPlayer->edict() )
{
nNumSatchels++;
}
}
}
if ( pSatchel->m_chargeReady != 0 && ( nSatchelsInPocket + nNumSatchels ) >= SATCHEL_MAX_CARRY )
{
// player has some satchels deployed. Refuse to add more.
return FALSE;
@ -331,15 +350,18 @@ void CSatchel::Holster( int skiplocal /* = 0 */ )
void CSatchel::PrimaryAttack()
{
switch (m_chargeReady)
// we're reloading, don't allow fire
if( m_chargeReady != 2 )
{
Throw();
}
}
void CSatchel::SecondaryAttack( void )
{
if ( m_chargeReady == 1 )
{
case 0:
{
Throw( );
}
break;
case 1:
{
SendWeaponAnim( SATCHEL_RADIO_FIRE );
edict_t *pPlayer = m_pPlayer->edict( );
@ -362,23 +384,6 @@ void CSatchel::PrimaryAttack()
m_flNextPrimaryAttack = GetNextAttackDelay(0.5);
m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.5;
break;
}
case 2:
// we're reloading, don't allow fire
{
}
break;
}
}
void CSatchel::SecondaryAttack( void )
{
if ( m_chargeReady != 2 )
{
Throw( );
}
}

View file

@ -99,6 +99,8 @@ public:
void TalkInit( void );
char* GetScientistModel() const;
void Killed( entvars_t *pevAttacker, int iGib );
virtual int Save( CSave &save );
@ -424,6 +426,17 @@ DEFINE_CUSTOM_SCHEDULES( CScientist )
IMPLEMENT_CUSTOM_SCHEDULES( CScientist, CTalkMonster );
char* CScientist::GetScientistModel() const
{
char* pszOverride = (char*)CVAR_GET_STRING("_sv_override_scientist_mdl");
if (pszOverride && strlen(pszOverride) > 5) // at least requires ".mdl"
{
return pszOverride;
}
return "models/scientist.mdl";
}
void CScientist::DeclineFollowing( void )
{
Talk( 10 );
@ -658,7 +671,7 @@ void CScientist :: Spawn( void )
{
Precache( );
SET_MODEL(ENT(pev), "models/scientist.mdl");
SET_MODEL(ENT(pev), GetScientistModel());
UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
pev->solid = SOLID_SLIDEBOX;
@ -694,7 +707,7 @@ void CScientist :: Spawn( void )
//=========================================================
void CScientist :: Precache( void )
{
PRECACHE_MODEL("models/scientist.mdl");
PRECACHE_MODEL(GetScientistModel());
PRECACHE_SOUND("scientist/sci_pain1.wav");
PRECACHE_SOUND("scientist/sci_pain2.wav");
PRECACHE_SOUND("scientist/sci_pain3.wav");
@ -1098,18 +1111,32 @@ int CScientist::FriendNumber( int arrayNumber )
//=========================================================
// Dead Scientist PROP
//=========================================================
class CDeadScientist : public CBaseMonster
class CDeadScientist : public CBaseMonster
{
public:
void Spawn( void );
int Classify ( void ) { return CLASS_HUMAN_PASSIVE; }
// passed into Precache which is non-const
char* GetScientistModel() const;
void KeyValue( KeyValueData *pkvd );
int m_iPose;// which sequence to display
static char *m_szPoses[7];
};
char *CDeadScientist::m_szPoses[] = { "lying_on_back", "lying_on_stomach", "dead_sitting", "dead_hang", "dead_table1", "dead_table2", "dead_table3" };
char* CDeadScientist::GetScientistModel() const
{
char* pszOverride = (char*)CVAR_GET_STRING("_sv_override_scientist_mdl");
if (pszOverride && strlen(pszOverride) > 5) // at least requires ".mdl"
{
return pszOverride;
}
return "models/scientist.mdl";
}
void CDeadScientist::KeyValue( KeyValueData *pkvd )
{
if (FStrEq(pkvd->szKeyName, "pose"))
@ -1127,8 +1154,8 @@ LINK_ENTITY_TO_CLASS( monster_scientist_dead, CDeadScientist );
//
void CDeadScientist :: Spawn( )
{
PRECACHE_MODEL("models/scientist.mdl");
SET_MODEL(ENT(pev), "models/scientist.mdl");
PRECACHE_MODEL(GetScientistModel());
SET_MODEL(ENT(pev), GetScientistModel());
pev->effects = 0;
pev->sequence = 0;
@ -1209,8 +1236,8 @@ SITTING_ANIM_sitting3
//
void CSittingScientist :: Spawn( )
{
PRECACHE_MODEL("models/scientist.mdl");
SET_MODEL(ENT(pev), "models/scientist.mdl");
PRECACHE_MODEL(GetScientistModel());
SET_MODEL(ENT(pev), GetScientistModel());
Precache();
InitBoneControllers();

View file

@ -934,9 +934,9 @@ public:
static TYPEDESCRIPTION m_SaveData[];
CBaseMonster *FindEntity( void );
BOOL AcceptableSpeaker( CBaseMonster *pMonster );
BOOL StartSentence( CBaseMonster *pTarget );
CBaseToggle *FindEntity( void );
BOOL AcceptableSpeaker( CBaseToggle *pTarget );
BOOL StartSentence( CBaseToggle *pTarget );
private:
@ -1072,10 +1072,10 @@ void CScriptedSentence :: Spawn( void )
void CScriptedSentence :: FindThink( void )
{
CBaseMonster *pMonster = FindEntity();
if ( pMonster )
CBaseToggle *pEnt = FindEntity();
if (pEnt)
{
StartSentence( pMonster );
StartSentence(pEnt);
if ( pev->spawnflags & SF_SENTENCE_ONCE )
UTIL_Remove( this );
SetThink( &CScriptedSentence::DelayThink );
@ -1100,8 +1100,16 @@ void CScriptedSentence :: DelayThink( void )
}
BOOL CScriptedSentence :: AcceptableSpeaker( CBaseMonster *pMonster )
BOOL CScriptedSentence :: AcceptableSpeaker( CBaseToggle *pTarget )
{
CBaseMonster *pMonster;
pMonster = NULL;
if (pTarget)
{
pMonster = pTarget->MyMonsterPointer();
}
if ( pMonster )
{
if ( pev->spawnflags & SF_SENTENCE_FOLLOWERS )
@ -1117,27 +1125,40 @@ BOOL CScriptedSentence :: AcceptableSpeaker( CBaseMonster *pMonster )
if ( pMonster->CanPlaySentence( override ) )
return TRUE;
}
else
{
// targeting something other than a monster, sure it can speak
if( pTarget && pTarget->IsAllowedToSpeak() )
return TRUE;
}
return FALSE;
}
CBaseMonster *CScriptedSentence :: FindEntity( void )
CBaseToggle *CScriptedSentence :: FindEntity( void )
{
edict_t *pentTarget;
CBaseMonster *pMonster;
CBaseToggle *pSpeakingEnt;
pentTarget = FIND_ENTITY_BY_TARGETNAME(NULL, STRING(m_iszEntity));
pMonster = NULL;
pSpeakingEnt = NULL;
while (!FNullEnt(pentTarget))
{
pMonster = GetMonsterPointer( pentTarget );
if ( pMonster != NULL )
CBaseEntity *pEnt = Instance(pentTarget);
pSpeakingEnt = pEnt ? pEnt->MyTogglePointer() : NULL;
if (pSpeakingEnt != NULL )
{
if ( AcceptableSpeaker( pMonster ) )
return pMonster;
// ALERT( at_console, "%s (%s), not acceptable\n", STRING(pMonster->pev->classname), STRING(pMonster->pev->targetname) );
if (AcceptableSpeaker(pSpeakingEnt))
{
//ALERT(at_console, "acceptable speaker\n");
return pSpeakingEnt;
}
//ALERT(at_console, "found unacceptable speaker\n");
}
pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, STRING(m_iszEntity));
}
@ -1149,9 +1170,9 @@ CBaseMonster *CScriptedSentence :: FindEntity( void )
{
if ( FBitSet( pEntity->pev->flags, FL_MONSTER ))
{
pMonster = pEntity->MyMonsterPointer( );
if ( AcceptableSpeaker( pMonster ) )
return pMonster;
pSpeakingEnt = pEntity->MyTogglePointer( );
if ( AcceptableSpeaker( pSpeakingEnt ) )
return pSpeakingEnt;
}
}
}
@ -1160,7 +1181,7 @@ CBaseMonster *CScriptedSentence :: FindEntity( void )
}
BOOL CScriptedSentence :: StartSentence( CBaseMonster *pTarget )
BOOL CScriptedSentence :: StartSentence( CBaseToggle *pTarget )
{
if ( !pTarget )
{
@ -1201,7 +1222,7 @@ BOOL CScriptedSentence :: StartSentence( CBaseMonster *pTarget )
//=========================================================
// Furniture - this is the cool comment I cut-and-pasted
//=========================================================
class CFurniture : public CBaseMonster
class CFurniture : public CBaseMonster
{
public:
void Spawn ( void );

View file

@ -175,8 +175,7 @@ void CShotgun::PrimaryAttack()
// HEV suit - indicate out of ammo condition
m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0);
if (m_iClip != 0)
m_flPumpTime = gpGlobals->time + 0.5;
m_flPumpTime = gpGlobals->time + 0.5;
m_flNextPrimaryAttack = GetNextAttackDelay(0.75);
m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.75;
@ -249,8 +248,7 @@ void CShotgun::SecondaryAttack( void )
// HEV suit - indicate out of ammo condition
m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0);
if (m_iClip != 0)
m_flPumpTime = gpGlobals->time + 0.95;
m_flPumpTime = gpGlobals->time + 0.95;
m_flNextPrimaryAttack = GetNextAttackDelay(1.5);
m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.5;
@ -317,13 +315,6 @@ void CShotgun::WeaponIdle( void )
m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES );
if ( m_flPumpTime && m_flPumpTime < gpGlobals->time )
{
// play pumping sound
EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/scock1.wav", 1, ATTN_NORM, 0, 95 + RANDOM_LONG(0,0x1f));
m_flPumpTime = 0;
}
if (m_flTimeWeaponIdle < UTIL_WeaponTimeBase() )
{
if (m_iClip == 0 && m_fInSpecialReload == 0 && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType])
@ -371,6 +362,18 @@ void CShotgun::WeaponIdle( void )
}
}
void CShotgun::ItemPostFrame( void )
{
if ( m_flPumpTime && m_flPumpTime < gpGlobals->time )
{
// play pumping sound
EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/scock1.wav", 1, ATTN_NORM, 0, 95 + RANDOM_LONG(0,0x1f));
m_flPumpTime = 0;
}
CBasePlayerWeapon::ItemPostFrame();
}
class CShotgunAmmo : public CBasePlayerAmmo

View file

@ -34,6 +34,8 @@ extern int gmsgMOTD;
//=========================================================
CHalfLifeRules::CHalfLifeRules( void )
{
SERVER_COMMAND( "exec spserver.cfg\n" );
RefreshSkillData();
}
@ -83,10 +85,88 @@ BOOL CHalfLifeRules::FShouldSwitchWeapon( CBasePlayer *pPlayer, CBasePlayerItem
return TRUE;
}
BOOL HLGetNextBestWeapon( CBasePlayer* pPlayer, CBasePlayerItem* pCurrentWeapon )
{
CBasePlayerItem* pCheck;
CBasePlayerItem* pBest;// this will be used in the event that we don't find a weapon in the same category.
int iBestWeight;
int i;
iBestWeight = -1;// no weapon lower than -1 can be autoswitched to
pBest = NULL;
if ( !pCurrentWeapon->CanHolster() )
{
// can't put this gun away right now, so can't switch.
return FALSE;
}
for ( i = 0; i < MAX_ITEM_TYPES; i++ )
{
pCheck = pPlayer->m_rgpPlayerItems[i];
while ( pCheck )
{
if ( (pCheck->iFlags() & ITEM_FLAG_NOAUTOSWITCHTO ) != 0 )
{
pCheck = pCheck->m_pNext;
continue;
}
if ( pCheck->iWeight() > -1 && pCheck->iWeight() == pCurrentWeapon->iWeight() && pCheck != pCurrentWeapon )
{
// this weapon is from the same category.
if ( pCheck->CanDeploy() )
{
if ( pPlayer->SwitchWeapon( pCheck ) )
{
return TRUE;
}
}
}
else if ( pCheck->iWeight() > iBestWeight && pCheck != pCurrentWeapon )// don't reselect the weapon we're trying to get rid of
{
//ALERT ( at_console, "Considering %s\n", STRING( pCheck->pev->classname ) );
// we keep updating the 'best' weapon just in case we can't find a weapon of the same weight
// that the player was using. This will end up leaving the player with his heaviest-weighted
// weapon.
if ( pCheck->CanDeploy() )
{
// if this weapon is useable, flag it as the best
iBestWeight = pCheck->iWeight();
pBest = pCheck;
}
}
pCheck = pCheck->m_pNext;
}
}
// if we make it here, we've checked all the weapons and found no useable
// weapon in the same catagory as the current weapon.
// if pBest is null, we didn't find ANYTHING. Shouldn't be possible- should always
// at least get the crowbar, but ya never know.
if ( !pBest )
{
return FALSE;
}
pPlayer->SwitchWeapon( pBest );
return TRUE;
}
//=========================================================
//=========================================================
BOOL CHalfLifeRules :: GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon )
{
if ( pCurrentWeapon && pCurrentWeapon->iFlags() & ITEM_FLAG_EXHAUSTIBLE )
{
return HLGetNextBestWeapon( pPlayer, pCurrentWeapon );
}
return FALSE;
}

Some files were not shown because too many files have changed in this diff Show more