- Added support for damage-specific player pain sounds.

- Removed the constraint that all $playerreserve SNDINFO commands must come
  before the other $player commands.
- Fixed: TArray::Reserve did not construct its newly allocated entries.
- Changed the damage type for drowning from 'Water' to 'Drowning'.


SVN r466 (trunk)
This commit is contained in:
Randy Heit 2007-01-28 04:59:04 +00:00
parent ba5e77e021
commit 72c93b479e
13 changed files with 233 additions and 46 deletions

View file

@ -1,4 +1,9 @@
January 27, 2007
- Added support for damage-specific player pain sounds.
- Removed the constraint that all $playerreserve SNDINFO commands must come
before the other $player commands.
- Fixed: TArray::Reserve did not construct its newly allocated entries.
- Changed the damage type for drowning from 'Water' to 'Drowning'.
- Fixed: Since FMemLump is now implemented on top of FString, it never
contains a NULL point, so the GetMem() method should fake it by
returning NULL when the string is empty. Reverted p_xlat.cpp to its

View file

@ -260,6 +260,8 @@ public:
WORD accuracy, stamina; // [RH] Strife stats
FName LastDamageType; // [RH] For damage-specific pain and death sounds
//Added by MC:
angle_t savedyaw;
int savedpitch;

View file

@ -124,7 +124,7 @@ bool ABasicArmor::HandlePickup (AInventory *item)
void ABasicArmor::AbsorbDamage (int damage, FName damageType, int &newdamage)
{
if (damageType != NAME_Water)
if (damageType != NAME_Drowning)
{
int saved = FixedMul (damage, SavePercent);
if (Amount < saved)
@ -440,7 +440,7 @@ bool AHexenArmor::AddArmorToSlot (AActor *actor, int slot, int amount)
void AHexenArmor::AbsorbDamage (int damage, FName damageType, int &newdamage)
{
if (damageType != NAME_Water)
if (damageType != NAME_Drowning)
{
fixed_t savedPercent = Slots[0] + Slots[1] + Slots[2] + Slots[3] + Slots[4];

View file

@ -722,7 +722,7 @@ END_DEFAULTS
void APowerIronFeet::AbsorbDamage (int damage, FName damageType, int &newdamage)
{
if (damageType == NAME_Water)
if (damageType == NAME_Drowning)
{
newdamage = 0;
if (Owner->player != NULL)

View file

@ -171,7 +171,7 @@ xx(Drop)
//xx(Fire) already defined above
//xx(Ice)
//xx(Disintegrate)
//xx(Water)
xx(Drowning)
xx(Slime)
//xx(Crush)
xx(Telefrag)

View file

@ -2521,18 +2521,39 @@ void A_Pain (AActor *actor)
// [RH] Vary player pain sounds depending on health (ala Quake2)
if (actor->player && actor->player->morphTics == 0)
{
const char *painchoice;
const char *pain_amount;
int sfx_id = 0;
if (actor->health < 25)
painchoice = "*pain25";
pain_amount = "*pain25";
else if (actor->health < 50)
painchoice = "*pain50";
pain_amount = "*pain50";
else if (actor->health < 75)
painchoice = "*pain75";
pain_amount = "*pain75";
else
painchoice = "*pain100";
pain_amount = "*pain100";
S_Sound (actor, CHAN_VOICE, painchoice, 1, ATTN_NORM);
// Try for damage-specific sounds first.
if (actor->player->LastDamageType != NAME_None)
{
FString pain_sound = pain_amount;
pain_sound += '-';
pain_sound += actor->player->LastDamageType;
sfx_id = S_FindSound (pain_sound);
if (sfx_id == 0)
{
// Try again without a specific pain amount.
pain_sound = "*pain-";
pain_sound += actor->player->LastDamageType;
sfx_id = S_FindSound (pain_sound);
}
}
if (sfx_id == 0)
{
sfx_id = S_FindSound (pain_amount);
}
S_SoundID (actor, CHAN_VOICE, sfx_id, 1, ATTN_NORM);
}
else if (actor->PainSound)
{

View file

@ -221,7 +221,7 @@ void ClientObituary (AActor *self, AActor *inflictor, AActor *attacker)
case NAME_Falling: messagename = "OB_FALLING"; break;
case NAME_Crush: messagename = "OB_CRUSH"; break;
case NAME_Exit: messagename = "OB_EXIT"; break;
case NAME_Water: messagename = "OB_WATER"; break;
case NAME_Drowning: messagename = "OB_WATER"; break;
case NAME_Slime: messagename = "OB_SLIME"; break;
case NAME_Fire: if (attacker == NULL) messagename = "OB_LAVA"; break;
}
@ -1024,6 +1024,7 @@ void P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage
{
player->health = 0;
}
player->LastDamageType = mod;
player->attacker = source;
player->damagecount += damage; // add damage after armor / invuln
if (player->damagecount > 100)

View file

@ -69,7 +69,7 @@ FName MODtoDamageType (int mod)
{
default: return NAME_None; break;
case 9: return NAME_BFGSplash; break;
case 12: return NAME_Water; break;
case 12: return NAME_Drowning; break;
case 13: return NAME_Slime; break;
case 14: return NAME_Fire; break;
case 15: return NAME_Crush; break;

View file

@ -2132,7 +2132,7 @@ void P_PlayerThink (player_t *player)
}
else if (player->air_finished <= level.time && !(level.time & 31))
{
P_DamageMobj (player->mo, NULL, NULL, 2 + 2*((level.time-player->air_finished)/TICRATE), NAME_Water);
P_DamageMobj (player->mo, NULL, NULL, 2 + 2*((level.time-player->air_finished)/TICRATE), NAME_Drowning);
}
}
}

View file

@ -3,7 +3,7 @@
** Translate old Doom format maps to the Hexen format
**
**---------------------------------------------------------------------------
** Copyright 1998-2006 Randy Heit
** Copyright 1998-2007 Randy Heit
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without

View file

@ -3,7 +3,7 @@
** Routines for managing SNDINFO lumps and ambient sounds
**
**---------------------------------------------------------------------------
** Copyright 1998-2006 Randy Heit
** Copyright 1998-2007 Randy Heit
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
@ -87,6 +87,33 @@ struct FPlayerClassLookup
WORD ListIndex[3]; // indices into PlayerSounds (0xffff means empty)
};
// Used to lookup a sound like "*grunt". This contains all player sounds for
// a particular class and gender.
class FPlayerSoundHashTable
{
public:
FPlayerSoundHashTable();
FPlayerSoundHashTable(const FPlayerSoundHashTable &other);
~FPlayerSoundHashTable();
void AddSound (int player_sound_id, int sfx_id);
int LookupSound (int player_sound_id);
FPlayerSoundHashTable &operator= (const FPlayerSoundHashTable &other);
protected:
struct Entry
{
Entry *Next;
int PlayerSoundID;
int SfxID;
};
enum { NUM_BUCKETS = 23 };
Entry *Buckets[NUM_BUCKETS];
void Init ();
void Free ();
};
static struct AmbientSound
{
unsigned type; // type of ambient sound
@ -218,11 +245,10 @@ static FMusicVolume *MusicVolumes;
static TArray<FSavedPlayerSoundInfo> SavedPlayerSounds;
static int NumPlayerReserves;
static bool DoneReserving;
static bool PlayerClassesIsSorted;
static TArray<FPlayerClassLookup> PlayerClassLookups;
static TArray<WORD> PlayerSounds;
static TArray<FPlayerSoundHashTable> PlayerSounds;
static char DefPlayerClassName[MAX_SNDNAME+1];
static int DefPlayerClass;
@ -507,21 +533,20 @@ int S_AddPlayerSound (const char *pclass, int gender, int refid,
int S_AddPlayerSound (const char *pclass, int gender, int refid, int lumpnum, bool fromskin)
{
char fakename[MAX_SNDNAME+1];
size_t len;
FString fakename;
int id;
len = strlen (pclass);
memcpy (fakename, pclass, len);
fakename[len] = '|';
fakename[len+1] = gender + '0';
strcpy (&fakename[len+2], S_sfx[refid].name);
fakename = pclass;
fakename += ';';
fakename += '0' + gender;
fakename += ';';
fakename += S_sfx[refid].name;
id = S_AddSoundLump (fakename, lumpnum);
int classnum = S_AddPlayerClass (pclass);
int soundlist = S_AddPlayerGender (classnum, gender);
PlayerSounds[soundlist + S_sfx[refid].link] = id;
PlayerSounds[soundlist].AddSound (S_sfx[refid].link, id);
if (fromskin) S_SavePlayerSound(pclass, gender, refid, lumpnum, false);
@ -541,7 +566,7 @@ int S_AddPlayerSoundExisting (const char *pclass, int gender, int refid,
int classnum = S_AddPlayerClass (pclass);
int soundlist = S_AddPlayerGender (classnum, gender);
PlayerSounds[soundlist + S_sfx[refid].link] = aliasto;
PlayerSounds[soundlist].AddSound (S_sfx[refid].link, aliasto);
if (fromskin) S_SavePlayerSound(pclass, gender, refid, aliasto, true);
@ -561,6 +586,148 @@ int S_DupPlayerSound (const char *pclass, int gender, int refid, int aliasref)
return S_AddPlayerSoundExisting (pclass, gender, refid, aliasto);
}
//==========================================================================
//
// FPlayerSoundHashTable constructor
//
//==========================================================================
FPlayerSoundHashTable::FPlayerSoundHashTable ()
{
Init();
}
//==========================================================================
//
// FPlayerSoundHashTable copy constructor
//
//==========================================================================
FPlayerSoundHashTable::FPlayerSoundHashTable (const FPlayerSoundHashTable &other)
{
Init();
*this = other;
}
//==========================================================================
//
// FPlayerSoundHashTable destructor
//
//==========================================================================
FPlayerSoundHashTable::~FPlayerSoundHashTable ()
{
Free ();
}
//==========================================================================
//
// FPlayerSoundHashTable :: Init
//
//==========================================================================
void FPlayerSoundHashTable::Init ()
{
for (int i = 0; i < NUM_BUCKETS; ++i)
{
Buckets[i] = NULL;
}
}
//==========================================================================
//
// FPlayerSoundHashTable :: Free
//
//==========================================================================
void FPlayerSoundHashTable::Free ()
{
for (int i = 0; i < NUM_BUCKETS; ++i)
{
Entry *entry, *next;
for (entry = Buckets[i]; entry != NULL; )
{
next = entry->Next;
delete entry;
entry = next;
}
Buckets[i] = NULL;
}
}
//==========================================================================
//
// FPlayerSoundHashTable :: operator=
//
//==========================================================================
FPlayerSoundHashTable &FPlayerSoundHashTable::operator= (const FPlayerSoundHashTable &other)
{
Free ();
for (int i = 0; i < NUM_BUCKETS; ++i)
{
Entry *entry;
for (entry = other.Buckets[i]; entry != NULL; entry = entry->Next)
{
AddSound (entry->PlayerSoundID, entry->SfxID);
}
}
return *this;
}
//==========================================================================
//
// FPlayerSoundHashTable :: AddSound
//
//==========================================================================
void FPlayerSoundHashTable::AddSound (int player_sound_id, int sfx_id)
{
Entry *entry;
unsigned bucket_num = (unsigned)player_sound_id % NUM_BUCKETS;
// See if the entry exists already.
for (entry = Buckets[bucket_num];
entry != NULL && entry->PlayerSoundID != player_sound_id;
entry = entry->Next)
{ }
if (entry != NULL)
{ // If the player sound is already present, redefine it.
entry->SfxID = sfx_id;
}
else
{ // Otherwise, add it to the start of its bucket.
entry = new Entry;
entry->Next = Buckets[bucket_num];
entry->PlayerSoundID = player_sound_id;
entry->SfxID = sfx_id;
Buckets[bucket_num] = entry;
}
}
//==========================================================================
//
// FPlayerSoundHashTable :: LookupSound
//
//==========================================================================
int FPlayerSoundHashTable::LookupSound (int player_sound_id)
{
Entry *entry;
unsigned bucket_num = (unsigned)player_sound_id % NUM_BUCKETS;
// See if the entry exists already.
for (entry = Buckets[bucket_num];
entry != NULL && entry->PlayerSoundID != player_sound_id;
entry = entry->Next)
{ }
return entry != NULL ? entry->SfxID : 0;
}
//==========================================================================
//
// S_ClearSoundData
@ -599,7 +766,6 @@ static void S_ClearSoundData()
}
S_rnd.Clear();
DoneReserving = false;
NumPlayerReserves = 0;
PlayerClassesIsSorted = false;
PlayerClassLookups.Clear();
@ -836,11 +1002,6 @@ static void S_AddSNDINFO (int lump)
case SI_PlayerReserve:
// $playerreserve <logical name>
if (DoneReserving)
{
SC_ScriptError ("All $playerreserves must come before any $playersounds or $playeraliases");
}
else
{
SC_MustGetString ();
int id = S_AddSound (sc_String, -1);
@ -1102,7 +1263,6 @@ static void S_AddStrifeVoice (int lumpnum)
static void S_ParsePlayerSoundCommon (char pclass[MAX_SNDNAME+1], int &gender, int &refid)
{
DoneReserving = true;
SC_MustGetString ();
strcpy (pclass, sc_String);
SC_MustGetString ();
@ -1204,19 +1364,13 @@ static int S_FindPlayerClass (const char *name)
static int S_AddPlayerGender (int classnum, int gender)
{
int index;
unsigned int index;
index = PlayerClassLookups[classnum].ListIndex[gender];
if (index == 0xffff)
{
WORD pushee = 0;
index = (int)PlayerSounds.Size ();
index = PlayerSounds.Reserve (1);
PlayerClassLookups[classnum].ListIndex[gender] = (WORD)index;
for (int i = NumPlayerReserves; i != 0; --i)
{
PlayerSounds.Push (pushee);
}
}
return index;
}
@ -1302,7 +1456,7 @@ static int S_LookupPlayerSound (int classidx, int gender, int refid)
gender = g;
}
int sndnum = PlayerSounds[listidx + S_sfx[refid].link];
int sndnum = PlayerSounds[listidx].LookupSound (S_sfx[refid].link);
// If we're not done parsing SNDINFO yet, assume that the target sound is valid
if (PlayerClassesIsSorted &&
@ -1545,9 +1699,9 @@ CCMD (playersounds)
if ((l = PlayerClassLookups[i].ListIndex[j]) != 0xffff)
{
Printf ("\n%s, %s:\n", PlayerClassLookups[i].Name, GenderNames[j]);
for (k = 0; k < NumPlayerReserves; ++l, ++k)
for (k = 0; k < NumPlayerReserves; ++k)
{
Printf (" %-16s%s\n", reserveNames[k], S_sfx[PlayerSounds[l]].name);
Printf (" %-16s%s\n", reserveNames[k], S_sfx[PlayerSounds[l].LookupSound (k)].name);
}
}
}

View file

@ -3,7 +3,7 @@
** Templated, automatically resizing array
**
**---------------------------------------------------------------------------
** Copyright 1998-2006 Randy Heit
** Copyright 1998-2007 Randy Heit
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
@ -214,6 +214,10 @@ public:
Grow (amount);
unsigned int place = Count;
Count += amount;
for (unsigned int i = place; i < Count; ++i)
{
::new((void *)&Array[i]) T;
}
return place;
}
unsigned int Size () const

View file

@ -133,7 +133,7 @@ public:
FMemLump &operator= (const FMemLump &copy);
~FMemLump ();
void *GetMem () { return Block.Len() == 0 ? NULL : (void *)Block.GetChars(); }
unsigned int GetSize () { return Block.Len(); }
size_t GetSize () { return Block.Len(); }
private:
FMemLump (const FString &source);