Skip to content

Commit

Permalink
Merge branch 'spirit/spirit-1.5' into spirit/spirit-1.8
Browse files Browse the repository at this point in the history
  • Loading branch information
LogicAndTrick committed Jul 7, 2023
2 parents 63c58c7 + 2ccd5b2 commit 65cd9a4
Show file tree
Hide file tree
Showing 14 changed files with 248 additions and 19 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@
* Fixed Human Grunts dropping weapons again if the game is saved and loaded while the grunt is dying (Thanks Oxofemple.)
* Added missing monster state name to ReportAIState (halflife issue [#3220](https://github.com/ValveSoftware/halflife/issues/3220)) (Thanks Shepard)
* Fixed mouse movement during map load affecting initial view angles
* Fixed being able to break scripted_sequence by +using friendly NPCs to make them follow player [#200](https://github.com/SamVanheer/halflife-updated/issues/200) (Thanks Oxofemple. for reporting this and FreeSlave for finding the solution)
* Fixed potential incorrect facing in scripted sequence (Thanks FreeSlave)
* Made the Linux version link statically to the C++ runtime to help avoid problems when running mods on older systems (Thanks a1ba and FreeSlave)
* Fixed Egon not stopping its attack animation if the attack button is held down and ammo runs out (Thanks the man)
* Fixed scientists crashing when speaking fear dialogue when enemy has been removed
* Disabled fall think function for weapons when the player picks it up to prevent possible double-pickup which removes the weapon and crashes the game
* Disabled jump sounds while player is frozen (e.g. trigger_camera, trigger_playerfreeze)
* Fixed node graph code incorrectly flagging node graphs as out of date if an outdated graph exists in a search path other than the mod directory (e.g. a graph in `halflife_updated_addon/map/graphs`)

## Changes in V1.0.0 Beta 014

Expand Down
2 changes: 2 additions & 0 deletions cl_dll/com_weapons.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ bool g_runfuncs = false;
// reset it to NULL as appropriate
struct local_state_s* g_finalstate = NULL;

int g_CurrentWeaponId = WEAPON_NONE;

/*
====================
COM_Log
Expand Down
1 change: 1 addition & 0 deletions cl_dll/com_weapons.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,4 @@ extern Vector v_angles;
extern Vector v_client_aimangles;
extern float g_lastFOV;
extern struct local_state_s* g_finalstate;
extern int g_CurrentWeaponId;
7 changes: 7 additions & 0 deletions cl_dll/ev_hldm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "cbase.h"
#include "weapons.h"

#include "com_weapons.h"
#include "const.h"
#include "entity_state.h"
#include "cl_entity.h"
Expand Down Expand Up @@ -1425,6 +1426,12 @@ void EV_EgonStop(event_args_t* args)

pFlare = NULL;
}

// HACK: only reset animation if the Egon is still equipped.
if (g_CurrentWeaponId == WEAPON_EGON)
{
gEngfuncs.pEventAPI->EV_WeaponAnimation(EGON_IDLE1, 0);
}
}
}
//======================
Expand Down
1 change: 1 addition & 0 deletions cl_dll/hl/hl_weapons.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -941,4 +941,5 @@ void DLLEXPORT HUD_PostRunCmd(struct local_state_s* from, struct local_state_s*

// All games can use FOV state
g_lastFOV = to->client.fov;
g_CurrentWeaponId = to->client.m_iId;
}
6 changes: 6 additions & 0 deletions dlls/egon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@
#include "gamerules.h"
#include "UserMessages.h"

#ifdef CLIENT_DLL
#include "hud.h"
#include "com_weapons.h"
#endif

#define EGON_SWITCH_NARROW_TIME 0.75 // Time it takes to switch fire modes
#define EGON_SWITCH_WIDE_TIME 1.5

Expand Down Expand Up @@ -497,6 +502,7 @@ void CEgon::EndAttack()
static_cast<int>(bMakeNoise), 0, 0, 0);

m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 2.0;

m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5;

m_fireState = FIRE_OFF;
Expand Down
2 changes: 1 addition & 1 deletion dlls/nodes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2612,7 +2612,7 @@ bool CGraph::CheckNODFile(const char* szMapName)
bool retValue = true;

int iCompare;
if (COMPARE_FILE_TIME(bspFileName.c_str(), graphFileName.c_str(), &iCompare))
if (FileSystem_CompareFileTime(bspFileName.c_str(), graphFileName.c_str(), &iCompare))
{
if (iCompare > 0)
{ // BSP file is newer.
Expand Down
17 changes: 9 additions & 8 deletions dlls/scientist.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -461,14 +461,15 @@ void CScientist::StartTask(Task_t* pTask)
case TASK_SAY_FEAR:
// Marphy Fact FIles Fix - This speech check always fails during combat, so removing
//if ( FOkToSpeak() )
//{
Talk(2);
m_hTalkTarget = m_hEnemy;
if (m_hEnemy->IsPlayer())
PlaySentence("SC_PLFEAR", 5, VOL_NORM, ATTN_NORM);
else
PlaySentence("SC_FEAR", 5, VOL_NORM, ATTN_NORM);
//}
if (m_hEnemy)
{
Talk(2);
m_hTalkTarget = m_hEnemy;
if (m_hEnemy->IsPlayer())
PlaySentence("SC_PLFEAR", 5, VOL_NORM, ATTN_NORM);
else
PlaySentence("SC_FEAR", 5, VOL_NORM, ATTN_NORM);
}
TaskComplete();
break;

Expand Down
10 changes: 7 additions & 3 deletions dlls/talkmonster.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -927,8 +927,12 @@ void CTalkMonster::Touch(CBaseEntity* pOther)
float speed = fabs(pOther->pev->velocity.x) + fabs(pOther->pev->velocity.y);
if (speed > 50)
{
SetConditions(bits_COND_CLIENT_PUSH);
MakeIdealYaw(pOther->pev->origin);
// From https://github.com/FreeSlave/halflife-updated/wiki/Fix-potential-incorrect-facing-in-scripted-sequence
if (m_pSchedule != NULL && (m_pSchedule->iInterruptMask & bits_COND_CLIENT_PUSH) != 0)
{
SetConditions(bits_COND_CLIENT_PUSH);
MakeIdealYaw(pOther->pev->origin);
}
}
}
}
Expand Down Expand Up @@ -1435,7 +1439,7 @@ void CTalkMonster::StartFollowing(CBaseEntity* pLeader)
//LRC- redefined, now returns true if following would be physically possible
bool CTalkMonster::CanFollow()
{
if (m_MonsterState == MONSTERSTATE_SCRIPT)
if (m_MonsterState == MONSTERSTATE_SCRIPT || m_IdealMonsterState == MONSTERSTATE_SCRIPT)
{
if (!m_pCine->CanInterrupt())
return false;
Expand Down
1 change: 1 addition & 0 deletions dlls/weapons.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,7 @@ void CBasePlayerItem::AttachToPlayer(CBasePlayer* pPlayer)
pev->owner = pPlayer->edict();
SetNextThink(0.1);
SetTouch(NULL);
SetThink(NULL); // Clear FallThink function so it can't run while attached to player.
}

//LRC
Expand Down
160 changes: 160 additions & 0 deletions game_shared/filesystem_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,106 @@
*
****/

#include <algorithm>
#include <cassert>
#include <limits>
#include <string>

#include "Platform.h"
#include "PlatformHeaders.h"

#ifdef WIN32
#include <sys/types.h>
#include <sys/stat.h>
#endif

#ifdef LINUX
#include <limits.h>
#include <unistd.h>
#include <sys/stat.h>
#endif

#include "extdll.h"
#include "util.h"

#ifdef CLIENT_DLL
#include "hud.h"
#endif

#include "interface.h"

#include "filesystem_utils.h"

static CSysModule* g_pFileSystemModule = nullptr;

// Some methods used to launch the game don't set the working directory.
// This makes using relative paths that point to the game and/or mod directory difficult
// since C and C++ runtime APIs don't know to use the game directory as a base.
// As a workaround we look up the executable directory and use that as a base.
// See https://stackoverflow.com/a/1024937/1306648 for more platform-specific workarounds.
// The engine's filesystem doesn't provide functions to do this so we have to work around it.
static std::string g_GameDirectory;
static std::string g_ModDirectory;

static bool FileSystem_InitializeGameDirectory()
{
std::string gameDirectory;

#ifdef WIN32
const std::size_t BufferSize = MAX_PATH + 1;
gameDirectory.resize(BufferSize);

const DWORD charactersWritten = GetModuleFileNameA(NULL, gameDirectory.data(), BufferSize);

if (charactersWritten == BufferSize)
{
// Path was truncated. Game is installed in the wrong location (Steam shouldn't allow this).
return false;
}
#else
const std::size_t BufferSize = PATH_MAX + 1;
gameDirectory.resize(BufferSize);

const ssize_t charactersWritten = readlink("/proc/self/exe", gameDirectory.data(), BufferSize);

if (charactersWritten < 0 || charactersWritten == BufferSize)
{
// Path was truncated. Game is installed in the wrong location (Steam shouldn't allow this).
return false;
}
#endif

// Resize buffer to actual size.
gameDirectory.resize(std::strlen(gameDirectory.c_str()));

// Truncate to directory name.
const std::size_t directoryEnd = gameDirectory.find_last_of(DefaultPathSeparatorChar);

if (directoryEnd == std::string::npos)
{
return false;
}

gameDirectory.resize(directoryEnd);

gameDirectory.shrink_to_fit();

std::string modDirectory;
modDirectory.resize(BufferSize);

#ifdef CLIENT_DLL
modDirectory = gEngfuncs.pfnGetGameDirectory();
#else
g_engfuncs.pfnGetGameDir(modDirectory.data());
modDirectory.resize(std::strlen(modDirectory.c_str()));
#endif

g_GameDirectory = std::move(gameDirectory);
g_ModDirectory = g_GameDirectory + DefaultPathSeparatorChar + modDirectory;

return true;
}

bool FileSystem_LoadFileSystem()
{
if (nullptr != g_pFileSystem)
Expand Down Expand Up @@ -73,6 +159,11 @@ bool FileSystem_LoadFileSystem()
return false;
}

if (!FileSystem_InitializeGameDirectory())
{
return false;
}

return true;
}

Expand All @@ -90,6 +181,75 @@ void FileSystem_FreeFileSystem()
}
}

void FileSystem_FixSlashes(std::string& fileName)
{
std::replace(fileName.begin(), fileName.end(), AlternatePathSeparatorChar, DefaultPathSeparatorChar);
}

time_t FileSystem_GetFileTime(const char* fileName)
{
if (nullptr == fileName)
{
return 0;
}

std::string absoluteFileName = g_ModDirectory + DefaultPathSeparatorChar + fileName;

FileSystem_FixSlashes(absoluteFileName);

#ifdef WIN32
struct _stat64i32 buf;

const int result = _stat64i32(absoluteFileName.c_str(), &buf);

if (result != 0)
{
return 0;
}

const time_t value = std::max(buf.st_ctime, buf.st_mtime);

return value;
#else
struct stat buf;

const int result = stat(absoluteFileName.c_str(), &buf);

if (result != 0)
{
return 0;
}

const time_t value = std::max(buf.st_ctim.tv_sec, buf.st_mtim.tv_sec);

return value;
#endif
}

bool FileSystem_CompareFileTime(const char* filename1, const char* filename2, int* iCompare)
{
*iCompare = 0;

if (!filename1 || !filename2)
{
return false;
}

const time_t time1 = FileSystem_GetFileTime(filename1);
const time_t time2 = FileSystem_GetFileTime(filename2);

if (time1 < time2)
{
*iCompare = -1;
}
else if (time1 > time2)
{
*iCompare = 1;
}

return true;
}

std::vector<std::byte> FileSystem_LoadFileIntoBuffer(const char* fileName, FileContentFormat format, const char* pathID)
{
assert(nullptr != g_pFileSystem);
Expand Down
34 changes: 34 additions & 0 deletions game_shared/filesystem_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,50 @@
*/

#include <cstddef>
#include <ctime>
#include <string>
#include <vector>

#include "Platform.h"
#include "FileSystem.h"

#ifdef WIN32
constexpr char DefaultPathSeparatorChar = '\\';
constexpr char AlternatePathSeparatorChar = '/';
#else
constexpr char DefaultPathSeparatorChar = '/';
constexpr char AlternatePathSeparatorChar = '\\';
#endif

inline IFileSystem* g_pFileSystem = nullptr;

bool FileSystem_LoadFileSystem();
void FileSystem_FreeFileSystem();

/**
* @brief Replaces occurrences of ::AlternatePathSeparatorChar with ::DefaultPathSeparatorChar.
*/
void FileSystem_FixSlashes(std::string& fileName);

/**
* @brief Returns the last modification time of the given file.
* Filenames are relative to the game directory.
*/
time_t FileSystem_GetFileTime(const char* fileName);

/**
* @brief Compares the file time of the given files located in the mod directory.
* @details Needed because IFileSystem::GetFileTime() does not provide a path ID parameter.
* @param filename1 First file to compare.
* @param filename2 Second file to compare.
* @param[out] iCompare Stores the result of the comparison.
* -@c 0 if equal
* -@c -1 if @p filename2 is newer than @p filename1
* -@c 1 if @p filename1 is newer than @p filename2
* @return @c true if filetimes were retrieved, false otherwise.
*/
bool FileSystem_CompareFileTime(const char* filename1, const char* filename2, int* iCompare);

enum class FileContentFormat
{
Binary = 0,
Expand Down
2 changes: 1 addition & 1 deletion linux/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ ifeq "$(COMPILER)" ""
endif

CPLUS="$(COMPILER) -m32"
CPP_LIB:=-L$(shell g++ -m32 -print-file-name=libstdc++.so | xargs dirname) -lstdc++ -ldl -lpthread
CPP_LIB:=-L$(shell g++ -m32 -print-file-name=libstdc++.so | xargs dirname) -lstdc++ -ldl -lpthread -static-libstdc++ -static-libgcc

ARCH_CFLAGS=-march=pentium-m -mfpmath=387 -mno-sse

Expand Down
Loading

0 comments on commit 65cd9a4

Please sign in to comment.