Skip to content

Commit

Permalink
misc map features
Browse files Browse the repository at this point in the history
- remap trigger_cameratarget to info_target
- add "keep_inventory" to trigger_changelevel
- add monster_handgrenade
- killing an ambient_generic stops its sound
- trigger_setorigin offset fixes
- Materialize() called when weapons first spawns
  • Loading branch information
wootguy committed Jan 8, 2025
1 parent a7b86a0 commit 45dbecd
Show file tree
Hide file tree
Showing 17 changed files with 154 additions and 17 deletions.
1 change: 1 addition & 0 deletions cl_dll/hl/hl_baseentity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,7 @@ Vector CBasePlayer::BodyTarget(const Vector& posSrc) { return Vector(); }
void CBasePlayer::Revive() { }
float CBasePlayer::GetDamageModifier() { return 0; }
float CBasePlayer::GetDamage(float defaultDamage) { return defaultDamage; }
const char* CBasePlayer::GetDeathNoticeWeapon() { return 0; }

void ClearMultiDamage(void) { }
void ApplyMultiDamage(entvars_t *pevInflictor, entvars_t *pevAttacker ) { }
Expand Down
3 changes: 3 additions & 0 deletions dlls/CPointEntity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,6 @@ void CPointEntity::Spawn(void)

// Lightning target, just alias landmark
LINK_ENTITY_TO_CLASS(info_target, CPointEntity)

// TODO: implement. This should allow players to click things in the camera view
LINK_ENTITY_TO_CLASS(trigger_cameratarget, CPointEntity)
17 changes: 17 additions & 0 deletions dlls/env/CAmbientGeneric.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -858,4 +858,21 @@ void CAmbientGeneric::InitSoundForNewJoiner(edict_t* target) {
(vol * 0.01), m_flAttenuation, SND_CHANGE_VOL, pitch, target);
}
// mp3 audio is initiliazed elsewhere, don't play here
}

void CAmbientGeneric::UpdateOnRemove(void) {
char* szSoundFile = (char*)STRING(pev->message);

if (m_fActive) {
// shut sound off now - may be interrupting a long non-looping sound
if (m_isGlobalMp3) {
if (g_lastMp3PlayerEnt.GetEntity() == this)
UTIL_StopGlobalMp3();
}
else {
UTIL_EmitAmbientSound(ENT(pev), pev->origin, szSoundFile, 0, 0, SND_STOP, 0);
}
}

CBaseEntity::UpdateOnRemove();
}
1 change: 1 addition & 0 deletions dlls/env/CAmbientGeneric.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ class EXPORT CAmbientGeneric : public CBaseEntity
void RampThink(void);
void InitModulationParms(void);
void InitSoundForNewJoiner(edict_t* target);
void UpdateOnRemove(void);

virtual int Save(CSave& save);
virtual int Restore(CRestore& restore);
Expand Down
2 changes: 2 additions & 0 deletions dlls/game/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ std::unordered_set<std::string> g_mapWeapons;

std::unordered_map<uint64_t, player_score_t> g_playerScores;
std::unordered_map<uint64_t, player_score_t> g_oldPlayerScores;
std::unordered_map<uint64_t, player_inventory_t> g_playerInventory;
bool g_clearInventoriesNextMap = true;

std::unordered_map<std::string, const char*> g_itemNameRemap = {
{"weapon_9mmar", "weapon_9mmAR"},
Expand Down
9 changes: 9 additions & 0 deletions dlls/game/game.h
Original file line number Diff line number Diff line change
Expand Up @@ -203,4 +203,13 @@ struct player_score_t {
EXPORT extern std::unordered_map<uint64_t, player_score_t> g_playerScores;
EXPORT extern std::unordered_map<uint64_t, player_score_t> g_oldPlayerScores; // state on level load, used in case of map restarts

struct player_inventory_t {
std::unordered_set<std::string> weapons;
int m_rgAmmo[MAX_AMMO_SLOTS];
};

// inventory to keep across map changes
EXPORT extern std::unordered_map<uint64_t, player_inventory_t> g_playerInventory;
EXPORT extern bool g_clearInventoriesNextMap; // true if player inventories should be cleared on the next map

#endif // GAME_H
2 changes: 2 additions & 0 deletions dlls/game/multiplay_gamerules.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,8 @@ void CHalfLifeMultiplay :: PlayerSpawn( CBasePlayer *pPlayer )
}

pPlayer->m_rgAmmo[pPlayer->GetAmmoIndex("health")] = gSkillData.sk_plr_medkit_start_ammo;

pPlayer->LoadInventory();
}

//=========================================================
Expand Down
6 changes: 6 additions & 0 deletions dlls/hooks/hlds_hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -738,6 +738,12 @@ void ServerActivate( edict_t *pEdictList, int edictCount, int clientMax )
}
g_oldPlayerScores = g_playerScores;

// reset player inventories
if (g_clearInventoriesNextMap) {
g_playerInventory.clear();
}
g_clearInventoriesNextMap = true; // set to false by trigger_changelevel

PrintEntindexStats();

g_engfuncs.pfnServerPrint(UTIL_VarArgs("Precache stats: %d models (%d MDL, %d BSP), %d sounds, %d generic, %d events\n",
Expand Down
41 changes: 40 additions & 1 deletion dlls/player/CBasePlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6352,6 +6352,42 @@ void CBasePlayer::LoadScore() {
}
}

void CBasePlayer::SaveInventory() {
player_inventory_t inv;

for (int i = 0; i < MAX_ITEM_TYPES; i++) {
if (m_rgpPlayerItems[i]) {
CBasePlayerItem* pPlayerItem = (CBasePlayerItem*)m_rgpPlayerItems[i].GetEntity();

while (pPlayerItem) {
inv.weapons.insert(STRING(pPlayerItem->pev->classname));
pPlayerItem = (CBasePlayerItem*)pPlayerItem->m_pNext.GetEntity();
}
}
}

memcpy(inv.m_rgAmmo, m_rgAmmo, MAX_AMMO_SLOTS * sizeof(int));

g_playerInventory[GetSteamID64()] = inv;
}

void CBasePlayer::LoadInventory() {
auto previousInv = g_playerInventory.find(GetSteamID64());
if (previousInv != g_playerInventory.end()) {
player_inventory_t inv = previousInv->second;

for (std::string item : inv.weapons) {
if (!HasNamedPlayerItem(item.c_str())) {
GiveNamedItem(STRING(ALLOC_STRING(item.c_str())));
}
}

for (int i = 0; i < MAX_AMMO_SLOTS; i++) {
m_rgAmmo[i] = V_max(m_rgAmmo[i], inv.m_rgAmmo[i]);
}
}
}

void CBasePlayer::ResolveWeaponSlotConflict(int wepId) {
int mask = g_weaponSlotMasks[wepId];

Expand Down Expand Up @@ -6384,7 +6420,6 @@ void CBasePlayer::ResolveWeaponSlotConflict(int wepId) {
WRITE_BYTE(i); // byte id (bit index into pev->weapons)
WRITE_BYTE(II.iFlags); // byte Flags
MESSAGE_END();
ALERT(at_console, "acktually, ID %d is now for %s\n", i, II.pszName);
}
}
}
Expand All @@ -6408,4 +6443,8 @@ int CBasePlayer::GetCurrentIdForConflictedSlot(int wepId) {
}

return -1;
}

const char* CBasePlayer::GetDeathNoticeWeapon() {
return m_pActiveItem ? m_pActiveItem->GetDeathNoticeWeapon() : "skull";
}
8 changes: 8 additions & 0 deletions dlls/player/CBasePlayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,12 @@ class EXPORT CBasePlayer : public CBaseMonster
// load score from global state, or initialize to 0
void LoadScore();

// save inventory to global state
void SaveInventory();

// equip inventory from global state
void LoadInventory();

// tell the client which weapon belongs in a slot which multiple weapons can fill
void ResolveWeaponSlotConflict(int wepId);

Expand All @@ -544,6 +550,8 @@ class EXPORT CBasePlayer : public CBaseMonster
// that queryWepId fills, then -1 is returned.
// queryWepId can be any weapon that fills the slot in question
int GetCurrentIdForConflictedSlot(int queryWepId);

const char* GetDeathNoticeWeapon();

// for sven-style monster info
//void UpdateMonsterInfo();
Expand Down
20 changes: 20 additions & 0 deletions dlls/triggers/CChangeLevel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "CBaseTrigger.h"
#include "CFireAndDie.h"
#include "hlds_hooks.h"
#include "CBasePlayer.h"

#define SF_CHANGELEVEL_USEONLY 0x0002

Expand Down Expand Up @@ -38,6 +39,7 @@ class CChangeLevel : public CBaseTrigger
char m_szLandmarkName[cchMapNameMost]; // trigger_changelevel only: landmark on next map
int m_changeTarget;
float m_changeTargetDelay;
bool m_bKeepInventory;
};
LINK_ENTITY_TO_CLASS(trigger_changelevel, CChangeLevel)

Expand Down Expand Up @@ -86,6 +88,11 @@ void CChangeLevel::KeyValue(KeyValueData* pkvd)
m_changeTargetDelay = atof(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "keep_inventory"))
{
m_bKeepInventory = atoi(pkvd->szValue) != 0;
pkvd->fHandled = TRUE;
}
else
CBaseTrigger::KeyValue(pkvd);
}
Expand Down Expand Up @@ -234,6 +241,19 @@ void CChangeLevel::ChangeLevelNow(CBaseEntity* pActivator)
CHANGE_LEVEL(st_szNextMap, st_szNextSpot);
*/

if (m_bKeepInventory) {
for (int i = 1; i <= gpGlobals->maxClients; i++) {
CBasePlayer* plr = (CBasePlayer*)UTIL_PlayerByIndex(i);
if (!plr) {
continue;
}

plr->SaveInventory();
}

g_clearInventoriesNextMap = false;
}

ALERT(at_console, "CHANGE LEVEL: %s\n", st_szNextMap);

if (mp_series_intermission.value == 2) {
Expand Down
9 changes: 7 additions & 2 deletions dlls/triggers/CTriggerSetOrigin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,15 +128,20 @@ void CTriggerSetOrigin::Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_T
// This doesn't apply when "Skip initial set" is active, which causes the offset key
// to be totally ignored, for some reason.

UTIL_MakeVectors(m_hCopyEnt->pev->angles);

for (int i = 0; i < m_targetCount; i++) {
if (pev->spawnflags & SF_TSORI_SKIP_INITIAL_SET) {
m_lockOffsets[i] = m_hTargets[i]->pev->origin - m_hCopyEnt->pev->origin;
Vector offset = m_hTargets[i]->pev->origin - m_hCopyEnt->pev->origin;
m_lockOffsets[i] = (gpGlobals->v_forward * offset.x) + (gpGlobals->v_right * offset.y) + (gpGlobals->v_up * offset.z);
}
else {
m_lockOffsets[i] = Vector(0, 0, 0); // TODO: just guessing after reading docs
}

m_lockOffsetAngles[i] = m_hTargets[i]->pev->angles - m_hCopyEnt->pev->angles;
if (!(pev->spawnflags & SF_TSORI_SKIP_INITIAL_SET)) {
m_lockOffsetAngles[i] = m_hTargets[i]->pev->angles - m_hCopyEnt->pev->angles;
}
}
}

Expand Down
6 changes: 6 additions & 0 deletions dlls/util/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1817,6 +1817,12 @@ bool UTIL_PointInLiquid(const Vector& vec)
return false;
}

bool UTIL_PointInBox(const Vector& vec, Vector mins, Vector maxs) {
return (vec.x >= mins.x && vec.x <= maxs.x) &&
(vec.y >= mins.y && vec.y <= maxs.y) &&
(vec.z >= mins.z && vec.z <= maxs.z);
}

void UTIL_BloodStream( const Vector &origin, const Vector &direction, int color, int amount )
{
if ( !UTIL_ShouldShowBlood( color ) )
Expand Down
1 change: 1 addition & 0 deletions dlls/util/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,7 @@ EXPORT void UTIL_TraceModel (const Vector &vecStart, const Vector &vecEnd, i
EXPORT Vector UTIL_GetAimVector (edict_t* pent, float flSpeed);
EXPORT int UTIL_PointContents (const Vector &vec);
EXPORT bool UTIL_PointInLiquid(const Vector& vec);
EXPORT bool UTIL_PointInBox(const Vector& vec, Vector mins, Vector maxs);

EXPORT int UTIL_IsMasterTriggered (string_t sMaster, CBaseEntity *pActivator);
EXPORT void UTIL_BloodStream( const Vector &origin, const Vector &direction, int color, int amount );
Expand Down
12 changes: 2 additions & 10 deletions dlls/weapon/CBasePlayerItem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,8 @@ void CBasePlayerItem::FallInit(void)
{
if (pev->movetype == 0)
pev->movetype = MOVETYPE_TOSS;
pev->solid = SOLID_TRIGGER;

UTIL_SetOrigin(pev, pev->origin);
UTIL_SetSize(pev, Vector(0, 0, 0), Vector(0, 0, 0));//pointsize until it lands on the ground.

if (!(pev->spawnflags & SF_ITEM_USE_ONLY))
SetTouch(&CBasePlayerItem::DefaultTouch);

if (!(pev->spawnflags & SF_ITEM_TOUCH_ONLY))
SetUse(&CBasePlayerItem::DefaultUse);

Materialize();

pev->nextthink = gpGlobals->time + 0.1;
}
Expand Down
2 changes: 1 addition & 1 deletion dlls/weapon/CBasePlayerItem.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class EXPORT CBasePlayerItem : public CBaseAnimating
void DefaultTouch( CBaseEntity *pOther ); // default weapon touch
void DefaultUse(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value);
void FallThink ( void );// when an item is first spawned, this think is run to determine when the object has hit the ground.
void Materialize( void );// make a weapon visible and tangible
virtual void Materialize( void );// make a weapon visible and tangible
void AttemptToMaterialize( void ); // the weapon desires to become visible and tangible, if the game rules allow for it
virtual CBaseEntity* Respawn ( void );// copy a weapon
void FallInit( void );
Expand Down
31 changes: 28 additions & 3 deletions dlls/weapon/CGrenade.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,13 @@ void CGrenade::PreDetonate( void )

void CGrenade::Detonate( void )
{
FCheckAITrigger();
// tell owner ( if any ) that we're dead.This is mostly for MonsterMaker functionality.
CBaseEntity* pOwner = CBaseEntity::Instance(pev->owner);
if (pOwner) {
pOwner->DeathNotice(pev);
}

TraceResult tr;
Vector vecSpot;// trace starts here!

Expand Down Expand Up @@ -377,16 +384,32 @@ void CGrenade :: TumbleThink( void )
void CGrenade:: Spawn( void )
{
pev->movetype = MOVETYPE_BOUNCE;
pev->classname = MAKE_STRING( "grenade" );

pev->solid = SOLID_BBOX;

m_defaultModel = "models/w_grenade.mdl";
SET_MODEL(ENT(pev), GetModel());
UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0));

pev->dmg = 100;
pev->dmg = GetDamage(100);
m_fRegisteredSound = FALSE;

if (FClassnameIs(pev, "monster_handgrenade")) {
SetTouch(&CGrenade::BounceTouch); // Bounce if touched

float time = 3.5f;
pev->dmgtime = gpGlobals->time + time;
SetThink(&CGrenade::TumbleThink);
pev->nextthink = gpGlobals->time + 0.1;

pev->sequence = RANDOM_LONG(3, 6);
pev->framerate = 1.0;

pev->gravity = 0.5;
pev->friction = 0.8;
}
else {
pev->classname = MAKE_STRING("grenade");
}
}


Expand Down Expand Up @@ -524,5 +547,7 @@ void CGrenade :: UseSatchelCharges( entvars_t *pevOwner, SATCHELCODE code )
}
}

LINK_ENTITY_TO_CLASS(monster_handgrenade, CGrenade)

//======================end grenade

0 comments on commit 45dbecd

Please sign in to comment.