mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-03 00:03:50 +00:00
Add player character combat vocals with 60+ voice lines
Implemented player combat vocals for Blood Elf and Draenei races: Player vocal types: - Attack grunts: Multiple variations per race/gender - Wound sounds: Pain reactions when hit - Wound crits: Special sounds for critical hits taken - Death cries: Final sounds when player dies Race coverage (60+ voice lines): - Blood Elf Male: 9 attacks, 8 wounds, 3 crit wounds, 2 deaths - Blood Elf Female: 5 attacks, 7 wounds, 1 death - Draenei Male: 7 attacks, 8 wounds, 3 crit wounds, 2 deaths - Draenei Female: 7 attacks, 4 wounds, 3 crit wounds, 1 death Technical details: - Loads 60+ vocal sound files from Sound\Character\*PC folders - Simple API: playPlayerAttackGrunt(race), playPlayerWound(race, crit), playPlayerDeath(race) - Random variation selection for immersion - Volume at 0.9-1.1 depending on sound type - Crit wounds play 1.1x louder for emphasis - Extensible design ready for other races - Only BC races have dedicated PC vocal folders in WotLK 3.3.5a Usage examples: ```cpp combatSoundManager->playPlayerAttackGrunt(PlayerRace::BLOOD_ELF_MALE); combatSoundManager->playPlayerWound(PlayerRace::DRAENEI_FEMALE, true); // Crit combatSoundManager->playPlayerDeath(PlayerRace::BLOOD_ELF_FEMALE); ``` This adds essential combat immersion with player character reactions!
This commit is contained in:
parent
d35b8eb633
commit
f60848871c
2 changed files with 189 additions and 0 deletions
|
|
@ -50,6 +50,18 @@ public:
|
||||||
// Emote sounds
|
// Emote sounds
|
||||||
void playClap();
|
void playClap();
|
||||||
|
|
||||||
|
// Player character vocals
|
||||||
|
enum class PlayerRace {
|
||||||
|
BLOOD_ELF_MALE,
|
||||||
|
BLOOD_ELF_FEMALE,
|
||||||
|
DRAENEI_MALE,
|
||||||
|
DRAENEI_FEMALE
|
||||||
|
};
|
||||||
|
|
||||||
|
void playPlayerAttackGrunt(PlayerRace race);
|
||||||
|
void playPlayerWound(PlayerRace race, bool isCrit = false);
|
||||||
|
void playPlayerDeath(PlayerRace race);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct CombatSample {
|
struct CombatSample {
|
||||||
std::string path;
|
std::string path;
|
||||||
|
|
@ -83,6 +95,26 @@ private:
|
||||||
// Emote sounds
|
// Emote sounds
|
||||||
std::vector<CombatSample> clapSounds_;
|
std::vector<CombatSample> clapSounds_;
|
||||||
|
|
||||||
|
// Player character vocal libraries
|
||||||
|
std::vector<CombatSample> bloodElfMaleAttackSounds_;
|
||||||
|
std::vector<CombatSample> bloodElfMaleWoundSounds_;
|
||||||
|
std::vector<CombatSample> bloodElfMaleWoundCritSounds_;
|
||||||
|
std::vector<CombatSample> bloodElfMaleDeathSounds_;
|
||||||
|
|
||||||
|
std::vector<CombatSample> bloodElfFemaleAttackSounds_;
|
||||||
|
std::vector<CombatSample> bloodElfFemaleWoundSounds_;
|
||||||
|
std::vector<CombatSample> bloodElfFemaleDeathSounds_;
|
||||||
|
|
||||||
|
std::vector<CombatSample> draeneiMaleAttackSounds_;
|
||||||
|
std::vector<CombatSample> draeneiMaleWoundSounds_;
|
||||||
|
std::vector<CombatSample> draeneiMaleWoundCritSounds_;
|
||||||
|
std::vector<CombatSample> draeneiMaleDeathSounds_;
|
||||||
|
|
||||||
|
std::vector<CombatSample> draeneiFemaleAttackSounds_;
|
||||||
|
std::vector<CombatSample> draeneiFemaleWoundSounds_;
|
||||||
|
std::vector<CombatSample> draeneiFemaleWoundCritSounds_;
|
||||||
|
std::vector<CombatSample> draeneiFemaleDeathSounds_;
|
||||||
|
|
||||||
// State tracking
|
// State tracking
|
||||||
float volumeScale_ = 1.0f;
|
float volumeScale_ = 1.0f;
|
||||||
bool initialized_ = false;
|
bool initialized_ = false;
|
||||||
|
|
|
||||||
|
|
@ -104,12 +104,101 @@ bool CombatSoundManager::initialize(pipeline::AssetManager* assets) {
|
||||||
loadSound("Sound\\Character\\EmoteClap" + std::to_string(i + 1) + ".wav", clapSounds_[i], assets);
|
loadSound("Sound\\Character\\EmoteClap" + std::to_string(i + 1) + ".wav", clapSounds_[i], assets);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load Blood Elf Male PC vocals
|
||||||
|
bloodElfMaleAttackSounds_.resize(9);
|
||||||
|
for (char c = 'A'; c <= 'I'; ++c) {
|
||||||
|
std::string path = "Sound\\Character\\BloodElfMalePC\\BloodElfMalePCAttack" + std::string(1, c) + ".wav";
|
||||||
|
loadSound(path, bloodElfMaleAttackSounds_[c - 'A'], assets);
|
||||||
|
}
|
||||||
|
|
||||||
|
bloodElfMaleWoundSounds_.resize(8);
|
||||||
|
for (char c = 'A'; c <= 'H'; ++c) {
|
||||||
|
std::string path = "Sound\\Character\\BloodElfMalePC\\BloodElfMalePCWound" + std::string(1, c) + ".wav";
|
||||||
|
loadSound(path, bloodElfMaleWoundSounds_[c - 'A'], assets);
|
||||||
|
}
|
||||||
|
|
||||||
|
bloodElfMaleWoundCritSounds_.resize(3);
|
||||||
|
for (char c = 'A'; c <= 'C'; ++c) {
|
||||||
|
std::string path = "Sound\\Character\\BloodElfMalePC\\BloodElfMalePCWoundCrit" + std::string(1, c) + ".wav";
|
||||||
|
loadSound(path, bloodElfMaleWoundCritSounds_[c - 'A'], assets);
|
||||||
|
}
|
||||||
|
|
||||||
|
bloodElfMaleDeathSounds_.resize(2);
|
||||||
|
loadSound("Sound\\Character\\BloodElfMalePC\\BloodElfMalePCDeath.wav", bloodElfMaleDeathSounds_[0], assets);
|
||||||
|
loadSound("Sound\\Character\\BloodElfMalePC\\BloodElfMalePCDeath2.wav", bloodElfMaleDeathSounds_[1], assets);
|
||||||
|
|
||||||
|
// Load Blood Elf Female PC vocals
|
||||||
|
bloodElfFemaleAttackSounds_.resize(5);
|
||||||
|
for (char c = 'A'; c <= 'E'; ++c) {
|
||||||
|
std::string path = "Sound\\Character\\BloodElfFemalePC\\BloodElfFemalePCAttack" + std::string(1, c) + ".wav";
|
||||||
|
loadSound(path, bloodElfFemaleAttackSounds_[c - 'A'], assets);
|
||||||
|
}
|
||||||
|
|
||||||
|
bloodElfFemaleWoundSounds_.resize(7);
|
||||||
|
const char* femaleWoundSuffixes[] = {"A", "B", "D", "E", "F", "G", ""};
|
||||||
|
for (int i = 0; i < 7; ++i) {
|
||||||
|
std::string path = "Sound\\Character\\BloodElfFemalePC\\BloodElfFemalePCWound" + std::string(femaleWoundSuffixes[i]) + ".wav";
|
||||||
|
loadSound(path, bloodElfFemaleWoundSounds_[i], assets);
|
||||||
|
}
|
||||||
|
|
||||||
|
bloodElfFemaleDeathSounds_.resize(1);
|
||||||
|
loadSound("Sound\\Character\\BloodElfFemalePC\\BloodElfFemalePCDeath.wav", bloodElfFemaleDeathSounds_[0], assets);
|
||||||
|
|
||||||
|
// Load Draenei Male PC vocals
|
||||||
|
draeneiMaleAttackSounds_.resize(7);
|
||||||
|
for (char c = 'A'; c <= 'G'; ++c) {
|
||||||
|
std::string path = "Sound\\Character\\DraeneiMalePC\\DraeneiMalePCAttack" + std::string(1, c) + ".wav";
|
||||||
|
loadSound(path, draeneiMaleAttackSounds_[c - 'A'], assets);
|
||||||
|
}
|
||||||
|
|
||||||
|
draeneiMaleWoundSounds_.resize(8);
|
||||||
|
for (char c = 'A'; c <= 'H'; ++c) {
|
||||||
|
std::string path = "Sound\\Character\\DraeneiMalePC\\DraeneiMalePCWound" + std::string(1, c) + ".wav";
|
||||||
|
loadSound(path, draeneiMaleWoundSounds_[c - 'A'], assets);
|
||||||
|
}
|
||||||
|
|
||||||
|
draeneiMaleWoundCritSounds_.resize(3);
|
||||||
|
for (char c = 'A'; c <= 'C'; ++c) {
|
||||||
|
std::string path = "Sound\\Character\\DraeneiMalePC\\DraeneiMalePCWoundCrit" + std::string(1, c) + ".wav";
|
||||||
|
loadSound(path, draeneiMaleWoundCritSounds_[c - 'A'], assets);
|
||||||
|
}
|
||||||
|
|
||||||
|
draeneiMaleDeathSounds_.resize(2);
|
||||||
|
loadSound("Sound\\Character\\DraeneiMalePC\\DraeneiMalePCDeath.wav", draeneiMaleDeathSounds_[0], assets);
|
||||||
|
loadSound("Sound\\Character\\DraeneiMalePC\\DraeneiMalePCDeath2.wav", draeneiMaleDeathSounds_[1], assets);
|
||||||
|
|
||||||
|
// Load Draenei Female PC vocals
|
||||||
|
draeneiFemaleAttackSounds_.resize(7);
|
||||||
|
for (char c = 'A'; c <= 'G'; ++c) {
|
||||||
|
std::string path = "Sound\\Character\\DraeneiFemalePC\\DraeneiFemalePCAttack" + std::string(1, c) + ".wav";
|
||||||
|
loadSound(path, draeneiFemaleAttackSounds_[c - 'A'], assets);
|
||||||
|
}
|
||||||
|
|
||||||
|
draeneiFemaleWoundSounds_.resize(4);
|
||||||
|
for (char c = 'A'; c <= 'D'; ++c) {
|
||||||
|
std::string path = "Sound\\Character\\DraeneiFemalePC\\DraeneiFemalePCWound" + std::string(1, c) + ".wav";
|
||||||
|
loadSound(path, draeneiFemaleWoundSounds_[c - 'A'], assets);
|
||||||
|
}
|
||||||
|
|
||||||
|
draeneiFemaleWoundCritSounds_.resize(3);
|
||||||
|
for (char c = 'A'; c <= 'C'; ++c) {
|
||||||
|
std::string path = "Sound\\Character\\DraeneiFemalePC\\DraeneiFemalePCWoundCrit" + std::string(1, c) + ".wav";
|
||||||
|
loadSound(path, draeneiFemaleWoundCritSounds_[c - 'A'], assets);
|
||||||
|
}
|
||||||
|
|
||||||
|
draeneiFemaleDeathSounds_.resize(1);
|
||||||
|
loadSound("Sound\\Character\\DraeneiFemalePC\\DraeneiFemalePCDeath.wav", draeneiFemaleDeathSounds_[0], assets);
|
||||||
|
|
||||||
LOG_INFO("CombatSoundManager: Weapon swings - Small: ", swingSmallSounds_[0].loaded ? "YES" : "NO",
|
LOG_INFO("CombatSoundManager: Weapon swings - Small: ", swingSmallSounds_[0].loaded ? "YES" : "NO",
|
||||||
", Medium: ", swingMediumSounds_[0].loaded ? "YES" : "NO",
|
", Medium: ", swingMediumSounds_[0].loaded ? "YES" : "NO",
|
||||||
", Large: ", swingLargeSounds_[0].loaded ? "YES" : "NO");
|
", Large: ", swingLargeSounds_[0].loaded ? "YES" : "NO");
|
||||||
LOG_INFO("CombatSoundManager: Impact sounds - Flesh: ", hitFleshSounds_[0].loaded ? "YES" : "NO",
|
LOG_INFO("CombatSoundManager: Impact sounds - Flesh: ", hitFleshSounds_[0].loaded ? "YES" : "NO",
|
||||||
", Chain: ", hitChainSounds_[0].loaded ? "YES" : "NO",
|
", Chain: ", hitChainSounds_[0].loaded ? "YES" : "NO",
|
||||||
", Plate: ", hitPlateSounds_[0].loaded ? "YES" : "NO");
|
", Plate: ", hitPlateSounds_[0].loaded ? "YES" : "NO");
|
||||||
|
LOG_INFO("CombatSoundManager: Player vocals - BE Male: ", bloodElfMaleAttackSounds_[0].loaded ? "YES" : "NO",
|
||||||
|
", BE Female: ", bloodElfFemaleAttackSounds_[0].loaded ? "YES" : "NO",
|
||||||
|
", Draenei Male: ", draeneiMaleAttackSounds_[0].loaded ? "YES" : "NO",
|
||||||
|
", Draenei Female: ", draeneiFemaleAttackSounds_[0].loaded ? "YES" : "NO");
|
||||||
LOG_INFO("CombatSoundManager: Emote sounds - Clap: ", clapSounds_[0].loaded ? "YES" : "NO");
|
LOG_INFO("CombatSoundManager: Emote sounds - Clap: ", clapSounds_[0].loaded ? "YES" : "NO");
|
||||||
|
|
||||||
initialized_ = true;
|
initialized_ = true;
|
||||||
|
|
@ -253,5 +342,73 @@ void CombatSoundManager::playClap() {
|
||||||
playRandomSound(clapSounds_, 0.9f);
|
playRandomSound(clapSounds_, 0.9f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CombatSoundManager::playPlayerAttackGrunt(PlayerRace race) {
|
||||||
|
switch (race) {
|
||||||
|
case PlayerRace::BLOOD_ELF_MALE:
|
||||||
|
playRandomSound(bloodElfMaleAttackSounds_, 0.9f);
|
||||||
|
break;
|
||||||
|
case PlayerRace::BLOOD_ELF_FEMALE:
|
||||||
|
playRandomSound(bloodElfFemaleAttackSounds_, 0.9f);
|
||||||
|
break;
|
||||||
|
case PlayerRace::DRAENEI_MALE:
|
||||||
|
playRandomSound(draeneiMaleAttackSounds_, 0.9f);
|
||||||
|
break;
|
||||||
|
case PlayerRace::DRAENEI_FEMALE:
|
||||||
|
playRandomSound(draeneiFemaleAttackSounds_, 0.9f);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CombatSoundManager::playPlayerWound(PlayerRace race, bool isCrit) {
|
||||||
|
if (isCrit) {
|
||||||
|
switch (race) {
|
||||||
|
case PlayerRace::BLOOD_ELF_MALE:
|
||||||
|
playRandomSound(bloodElfMaleWoundCritSounds_, 1.1f);
|
||||||
|
break;
|
||||||
|
case PlayerRace::BLOOD_ELF_FEMALE:
|
||||||
|
playRandomSound(bloodElfFemaleWoundSounds_, 1.1f); // No separate crit sounds
|
||||||
|
break;
|
||||||
|
case PlayerRace::DRAENEI_MALE:
|
||||||
|
playRandomSound(draeneiMaleWoundCritSounds_, 1.1f);
|
||||||
|
break;
|
||||||
|
case PlayerRace::DRAENEI_FEMALE:
|
||||||
|
playRandomSound(draeneiFemaleWoundCritSounds_, 1.1f);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch (race) {
|
||||||
|
case PlayerRace::BLOOD_ELF_MALE:
|
||||||
|
playRandomSound(bloodElfMaleWoundSounds_, 0.9f);
|
||||||
|
break;
|
||||||
|
case PlayerRace::BLOOD_ELF_FEMALE:
|
||||||
|
playRandomSound(bloodElfFemaleWoundSounds_, 0.9f);
|
||||||
|
break;
|
||||||
|
case PlayerRace::DRAENEI_MALE:
|
||||||
|
playRandomSound(draeneiMaleWoundSounds_, 0.9f);
|
||||||
|
break;
|
||||||
|
case PlayerRace::DRAENEI_FEMALE:
|
||||||
|
playRandomSound(draeneiFemaleWoundSounds_, 0.9f);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CombatSoundManager::playPlayerDeath(PlayerRace race) {
|
||||||
|
switch (race) {
|
||||||
|
case PlayerRace::BLOOD_ELF_MALE:
|
||||||
|
playRandomSound(bloodElfMaleDeathSounds_, 1.0f);
|
||||||
|
break;
|
||||||
|
case PlayerRace::BLOOD_ELF_FEMALE:
|
||||||
|
playRandomSound(bloodElfFemaleDeathSounds_, 1.0f);
|
||||||
|
break;
|
||||||
|
case PlayerRace::DRAENEI_MALE:
|
||||||
|
playRandomSound(draeneiMaleDeathSounds_, 1.0f);
|
||||||
|
break;
|
||||||
|
case PlayerRace::DRAENEI_FEMALE:
|
||||||
|
playRandomSound(draeneiFemaleDeathSounds_, 1.0f);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace audio
|
} // namespace audio
|
||||||
} // namespace wowee
|
} // namespace wowee
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue