diff --git a/docs/rh-log.txt b/docs/rh-log.txt index 287da5553..01d801100 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -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 diff --git a/src/d_player.h b/src/d_player.h index ea017287e..68663f8ae 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -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; diff --git a/src/g_shared/a_armor.cpp b/src/g_shared/a_armor.cpp index 9c4da7362..6f0407dc6 100644 --- a/src/g_shared/a_armor.cpp +++ b/src/g_shared/a_armor.cpp @@ -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]; diff --git a/src/g_shared/a_artifacts.cpp b/src/g_shared/a_artifacts.cpp index ec97cc62a..7f45b9611 100644 --- a/src/g_shared/a_artifacts.cpp +++ b/src/g_shared/a_artifacts.cpp @@ -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) diff --git a/src/namedef.h b/src/namedef.h index 7b4c1f9ac..77ce6bafe 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -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) diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 31cb77465..9c21c5934 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -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) { diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index d14392f0f..2be6c4e31 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -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) diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index 9edff9f76..940ebe547 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -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; diff --git a/src/p_user.cpp b/src/p_user.cpp index e6d2a1f5f..6c6cff84f 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -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); } } } diff --git a/src/p_xlat.cpp b/src/p_xlat.cpp index f9d81d945..6bd4017e1 100644 --- a/src/p_xlat.cpp +++ b/src/p_xlat.cpp @@ -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 diff --git a/src/s_advsound.cpp b/src/s_advsound.cpp index c6b9cf7c8..0f2fb8772 100644 --- a/src/s_advsound.cpp +++ b/src/s_advsound.cpp @@ -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 SavedPlayerSounds; static int NumPlayerReserves; -static bool DoneReserving; static bool PlayerClassesIsSorted; static TArray PlayerClassLookups; -static TArray PlayerSounds; +static TArray 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 - 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); } } } diff --git a/src/tarray.h b/src/tarray.h index 3037cf78d..0edf61333 100644 --- a/src/tarray.h +++ b/src/tarray.h @@ -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 diff --git a/src/w_wad.h b/src/w_wad.h index 29177e9fb..befc91174 100644 --- a/src/w_wad.h +++ b/src/w_wad.h @@ -133,7 +133,7 @@ public: FMemLump &operator= (const FMemLump ©); ~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);