CSound
class:
class CSound
{
public:
void Clear();
void Reset();
Vector m_vecOrigin; // sound's location in space
int m_iType; // what type of sound this is
int m_iVolume; // how loud the sound is
float m_flExpireTime; // when the sound should be purged from the list
int m_iNext; // index of next sound in this list ( Active or Free )
int m_iNextAudible; // temporary link that monsters use to build a list of audible sounds
bool FIsSound();
bool FIsScent();
};
Some information in this class is explicit like the origin of the sound, type and volume. You'll notice the comments refer to something called a "list" involving "active" and "free" things, we will talk about them later. If you read and remember what has been said in the first page correctly, you should be able to answer the "why scent is a sound" question by yourself. If not, it is strongly advised you (re)start reading this chapter from the beginning.CSound::Clear()
and CSound::Reset()
methods both reset the sound/scent values to their default which is "no origin, no volume, no type" and so on, the difference is that is that Clear()
does expire/unlink the sound/scent from the mentioned "list" while Reset()
doesn't thus keeping said sound/scent in said "list".m_iType
possible values are:
#define bits_SOUND_NONE 0
#define bits_SOUND_COMBAT (1 << 0) // gunshots, explosions
#define bits_SOUND_WORLD (1 << 1) // door opening/closing, glass breaking
#define bits_SOUND_PLAYER (1 << 2) // all noises generated by player. walking, shooting, falling, splashing
#define bits_SOUND_CARCASS (1 << 3) // dead body
#define bits_SOUND_MEAT (1 << 4) // gib or pork chop
#define bits_SOUND_DANGER (1 << 5) // pending danger. Grenade that is about to explode, explosive barrel that is damaged, falling crate
#define bits_SOUND_GARBAGE (1 << 6) // trash cans, banana peels, old fast food bags.
Through these values, you'll notice the usage of bitwise operations and you can guess that bool CSound::FIsSound()
would return true
for combat, world, player and danger. bool CSound::FIsScent()
would return true
for the other values being carcass, meat and garbage.
CSoundEnt
.CSound
which is look at the class definition of CSoundEnt
. We're going to "follow the code" instead, just know that the entity is marked as "do not save" (int CBaseEntity::ObjectCaps()
is overriden to return FCAP_DONT_SAVE
) so the contents/state won't be persisted through maps transitions and saved games.m_SoundPool
member which is an array of CSound
with a capacity of 64 as defined by the MAX_WORLD_SOUNDS
constant. In other words, there is a loop which call CSound::Clear()
and set m_iNext
to i + 1
. The last sound/scent's m_iNext
is set to SOUNDLIST_EMPTY
which is equals to "-1". Several methods that will be described below will perform a "is there room for another sound/scent" check to prevent dangerous overflows.gpGlobals->maxClients
). That "reservation" calls int CSoundEnt::IAllocSound()
and set the sound/smell expiration time to SOUND_NEVER_EXPIRE
which is also -1.
Let's dive deeper into that int CSoundEnt::IAllocSound()
method, it "allocate" a sound by moving two indexes in the pool (m_SoundPool
) which are m_iActiveSound
and m_iFreeSound
. We can determine that there is a "linked list" approach being used where m_iActiveSound
act as the index to the "head/first" sound/smell and m_iFreeSound
being the one for the "last" element. Those sounds/scents are linked together through m_iNext
.displaysoundlist
CVAR.CSoundEnt::FreeSound(int iSound, int iPrevious)
) while taking care that new links are made. Remember, we're dealing with a "linked list" so deleting an element implies breaking its link with the previous and next element and the two latter needs to be linked (unless specific scenario like there is only one element).int CSoundEnt::ActiveList()
and int CSoundEnt::FreeList()
, the method that handles listening (CBaseMonster::Listen()
) for monsters uses the first one to skip iterating over the whole pool and avoid unnecessary iterations (optimization).int CSoundEnt::ISoundsInList(int iListType)
, one with SOUNDLIST_ACTIVE
and the other with SOUNDLIST_FREE
. Speaking of amount, it is possible to check if the list of sounds/scents is empty through the bool CSoundEnt::IsEmpty()
method.CSoundEnt::InsertSound(int iType, const Vector& vecOrigin, int iVolume, float flDuration)
.gpGlobals->time
).CSound* CSoundEnt::SoundPointerForIndex(int iIndex)
which basically give you the sound/scent itself at the desired index.
CBasePlayer::UpdatePlayerSound()
, there is a body volume that start at 0 if the player is in the air or the velocity's length with a maximum cap of 512. Jumping add an extra 100 to the body volume (no maximum cap on this one).m_iWeaponVolume
) is higher than the body volume, then that volume is used and the "combat" flag is set on the sound. Otherwise, the body volume is used instead. This is tracked with m_iTargetVolume
and this is also where the weapon volume silence over time. If you have no idea what "weapon volume" is, maybe you should consider read (again) the "Weapons Programming" chapter.impulse 105
) is enabled, the final volume is overriden to 0. Regardless of that cheat's state, the sound's origin is set to the same as the player's and the bits_SOUND_PLAYER
type is added.int m_iExtraSoundTypes
and float m_flStopExtraSoundTime
in CBasePlayer
) for the player, this is used by the 9mmAR's grenade launcher to insert a "combat" sound for the AI to hear. Unrelated to sounds/scents, this is where the weapon's muzzleflash (m_iWeaponFlash
) decays as well.
CSound* CBaseMonster::PBestSound()
) and "best scent" (CSound* CBaseMonster::PBestScent()
), both uses the same code to iterate through the sound pool and retrieve the closest sound/scent.bits_COND_HEAR_SOUND
condition bit is set. If it smells something, the bits_COND_SMELL
is set. An additional bits_COND_SMELL_FOOD
is set for "meat" and "carcass" smell types. Talkative monsters have a CTalkMonster::TrySmellTalk()
method where they can comment every minute (timer and "said bits") on smells by doing an if (HasConditions(bits_COND_SMELL))
check.
You must log in to post a comment. You can login or register a new account.