Skip to content

Commit d9c3726

Browse files
authored
Multi VoiceAttack (#1796)
Units can customize the attack voice that plays when using more weapons. - 单位可以在使用更多武器时自定义播放的攻击语音。 If you need to assign an attack-voice to `Weapon1`, simply set `VoiceWeapon1Attack`. The same applies to other weapons. - 如果需要给`Weapon1`自定义攻击语音,只需要设置`VoiceWeapon1Attack`即可。其他武器同理。 `VoiceEliteWeaponNAttack` can also be used to specify attack voices for `EliteWeaponN`. The default is `VoiceWeaponNAttack`. - `VoiceEliteWeaponNAttack`也可以用来指定`EliteWeaponN`的攻击语音。默认值为`VoiceWeaponNAttack`。 In `rulesmd.ini`: ```ini [SOMETECHNO] ; TechnoType VoiceWeaponNAttack= ; Sound entry VoiceEliteWeaponNAttack= ; Sound entry ```
1 parent 6a8df9e commit d9c3726

File tree

6 files changed

+137
-2
lines changed

6 files changed

+137
-2
lines changed

CREDITS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,7 @@ This page lists all the individual contributions to the project by their author.
383383
- If `BombDisarm=yes` is not present for all weapon warheads, then the engineer will no longer use the appropriate mouse action
384384
- Fix an unusual use of DeployFireWeapon for InfantryType
385385
- Fix the fact that when the selected unit is in a rearmed state, it can unconditionally use attack mouse on the target
386+
- Units can customize the attack voice that plays when using more weapons
386387
- **NetsuNegi**:
387388
- Forbidding parallel AI queues by type
388389
- Jumpjet crash speed fix when crashing onto building

docs/New-or-Enhanced-Logics.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1706,10 +1706,23 @@ MultiWeapon.IsSecondary= ; List of integers
17061706
MultiWeapon.SelectCount=2 ; integer
17071707
```
17081708

1709+
### Multi VoiceAttack
1710+
1711+
- Units can customize the attack voice that plays when using more weapons.
1712+
- If you need to assign an attack-voice to `Weapon1`, simply set `VoiceWeapon1Attack`. The same applies to other weapons.
1713+
- `VoiceEliteWeaponNAttack` can also be used to specify attack voices for `EliteWeaponN`. The default is `VoiceWeaponNAttack`.
1714+
1715+
In `rulesmd.ini`:
1716+
```ini
1717+
[SOMETECHNO] ; TechnoType
1718+
VoiceWeaponNAttack= ; Sound entry
1719+
VoiceEliteWeaponNAttack= ; Sound entry
1720+
```
1721+
17091722
### No Manual Move
17101723

17111724
- You can now specify whether a TechnoType is unable to receive move command.
1712-
- Set this to `true` on a building with `UndeploysInto` set could prevent it from undeploying when setting the rally point.
1725+
- Set this to `true` on a building with `UndeploysInto` set could prevent it from undeploying when setting the rally point.
17131726

17141727
In `rulesmd.ini`:
17151728
```ini

docs/Whats-New.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,7 @@ New:
425425
- [Damaged aircraft image changes](New-or-Enhanced-Logics.md#damaged-aircraft-image-changes) (by Fryone)
426426
- [Additional attached animation position customizations](Fixed-or-Improved-Logics.md#attached-animation-position-customization) (by Starkku)
427427
- Use `SkipCrushSlowdown=true` to avoid the bug related to `Accelerates=true` and `MovementZone=CrushAll` (by TaranDahl)
428+
- Units can customize the attack voice that plays when using more weapons (by FlyStar)
428429
429430
Vanilla fixes:
430431
- Fixed sidebar not updating queued unit numbers when adding or removing units when the production is on hold (by CrimRecya)

src/Ext/TechnoType/Body.cpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,53 @@ void TechnoTypeExt::ExtData::ParseBurstFLHs(INI_EX& exArtINI, const char* pArtSe
318318
}
319319
}
320320

321+
void TechnoTypeExt::ExtData::ParseVoiceWeaponAttacks(INI_EX& exINI, const char* pSection, ValueableVector<int>& voice, ValueableVector<int>& voiceElite)
322+
{
323+
if (!this->ReadMultiWeapon)
324+
{
325+
voice.clear();
326+
voiceElite.clear();
327+
return;
328+
}
329+
330+
const auto pThis = this->OwnerObject();
331+
const auto weaponCount = Math::max(pThis->WeaponCount, 0);
332+
333+
while (int(voice.size()) > weaponCount)
334+
{
335+
voice.erase(voice.begin() + int(voice.size()) - 1);
336+
}
337+
338+
while (int(voiceElite.size()) > weaponCount)
339+
{
340+
voiceElite.erase(voiceElite.begin() + int(voiceElite.size()) - 1);
341+
}
342+
343+
char tempBuff[64];
344+
for (int index = 0; index < weaponCount; index++)
345+
{
346+
NullableIdx<VocClass> VoiceAttack;
347+
_snprintf_s(tempBuff, sizeof(tempBuff), "VoiceWeapon%dAttack", index + 1);
348+
VoiceAttack.Read(exINI, pSection, tempBuff);
349+
350+
NullableIdx<VocClass> VoiceEliteAttack;
351+
_snprintf_s(tempBuff, sizeof(tempBuff), "VoiceEliteWeapon%dAttack", index + 1);
352+
VoiceAttack.Read(exINI, pSection, tempBuff);
353+
354+
if (int(voice.size()) > index)
355+
{
356+
voice[index] = VoiceAttack.Get(voice[index]);
357+
voiceElite[index] = VoiceEliteAttack.Get(voiceElite[index]);
358+
}
359+
else
360+
{
361+
const int voiceAttack = VoiceAttack.Get(-1);
362+
voice.push_back(voiceAttack);
363+
voiceElite.push_back(VoiceEliteAttack.Get(voiceAttack));
364+
}
365+
}
366+
}
367+
321368
void TechnoTypeExt::ExtData::CalculateSpawnerRange()
322369
{
323370
const auto pThis = this->OwnerObject();
@@ -1142,6 +1189,10 @@ void TechnoTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI)
11421189
Debug::Log("[Developer warning] [%s] has Palette=%s set but no palette file was loaded (missing file or wrong filename). Missing palettes cause issues with lighting recalculations.\n", pArtSection, pThis->PaletteFile);
11431190

11441191
this->LoadFromINIByWhatAmI(exArtINI, pArtSection);
1192+
1193+
// VoiceIFVRepair from Ares 0.2
1194+
this->VoiceIFVRepair.Read(exINI, pSection, "VoiceIFVRepair");
1195+
this->ParseVoiceWeaponAttacks(exINI, pSection, this->VoiceWeaponAttacks, this->VoiceEliteWeaponAttacks);
11451196
}
11461197

11471198
void TechnoTypeExt::ExtData::LoadFromINIByWhatAmI(INI_EX& exArtINI, const char* pArtSection)
@@ -1532,6 +1583,10 @@ void TechnoTypeExt::ExtData::Serialize(T& Stm)
15321583
.Process(this->MultiWeapon_IsSecondary)
15331584
.Process(this->MultiWeapon_SelectCount)
15341585
.Process(this->ReadMultiWeapon)
1586+
1587+
.Process(this->VoiceIFVRepair)
1588+
.Process(this->VoiceWeaponAttacks)
1589+
.Process(this->VoiceEliteWeaponAttacks)
15351590
;
15361591
}
15371592
void TechnoTypeExt::ExtData::LoadFromStream(PhobosStreamReader& Stm)

src/Ext/TechnoType/Body.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,10 @@ class TechnoTypeExt
412412
Valueable<int> MultiWeapon_SelectCount;
413413
bool ReadMultiWeapon;
414414

415+
ValueableIdx<VocClass> VoiceIFVRepair;
416+
ValueableVector<int> VoiceWeaponAttacks;
417+
ValueableVector<int> VoiceEliteWeaponAttacks;
418+
415419
ExtData(TechnoTypeClass* OwnerObject) : Extension<TechnoTypeClass>(OwnerObject)
416420
, HealthBar_Hide { false }
417421
, UIDescription {}
@@ -773,6 +777,10 @@ class TechnoTypeExt
773777
, MultiWeapon_IsSecondary {}
774778
, MultiWeapon_SelectCount { 2 }
775779
, ReadMultiWeapon { false }
780+
781+
, VoiceIFVRepair { -1 }
782+
, VoiceWeaponAttacks {}
783+
, VoiceEliteWeaponAttacks {}
776784
{ }
777785

778786
virtual ~ExtData() = default;
@@ -801,7 +809,7 @@ class TechnoTypeExt
801809
void Serialize(T& Stm);
802810

803811
void ParseBurstFLHs(INI_EX& exArtINI, const char* pArtSection, std::vector<std::vector<CoordStruct>>& nFLH, std::vector<std::vector<CoordStruct>>& nEFlh, const char* pPrefixTag);
804-
812+
void ParseVoiceWeaponAttacks(INI_EX& exINI, const char* pSection, ValueableVector<int>& n, ValueableVector<int>& nE);
805813
};
806814

807815
class ExtContainer final : public Container<TechnoTypeExt>

src/Ext/TechnoType/Hooks.MultiWeapon.cpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "Body.h"
2+
#include <Randomizer.h>
23

34
DEFINE_HOOK(0x7128B2, TechnoTypeClass_ReadINI_MultiWeapon, 0x6)
45
{
@@ -78,3 +79,59 @@ DEFINE_HOOK(0x715B10, TechnoTypeClass_ReadINI_MultiWeapon2, 0x7)
7879
R->AL(pThis->HasMultipleTurrets());
7980
return Continue;
8081
}
82+
83+
int GetVoiceAttack(TechnoTypeClass* pType, int weaponIndex, bool isElite, WeaponTypeClass* pWeaponType)
84+
{
85+
const auto pTypeExt = TechnoTypeExt::ExtMap.Find(pType);
86+
int voiceAttack = -1;
87+
88+
if (pWeaponType && pWeaponType->Damage < 0)
89+
{
90+
voiceAttack = pTypeExt->VoiceIFVRepair;
91+
92+
if (voiceAttack < 0)
93+
voiceAttack = !strcmp(pType->ID, "FV") ? RulesClass::Instance->VoiceIFVRepair : -1; // It's hardcoded like this in vanilla
94+
95+
if (voiceAttack >= 0)
96+
return voiceAttack;
97+
}
98+
99+
if (weaponIndex >= 0 && int(pTypeExt->VoiceWeaponAttacks.size()) > weaponIndex)
100+
voiceAttack = isElite ? pTypeExt->VoiceEliteWeaponAttacks[weaponIndex] : pTypeExt->VoiceWeaponAttacks[weaponIndex];
101+
102+
if (voiceAttack < 0)
103+
{
104+
if (pTypeExt->IsSecondary(weaponIndex))
105+
voiceAttack = isElite ? pType->VoiceSecondaryEliteWeaponAttack : pType->VoiceSecondaryWeaponAttack;
106+
else
107+
voiceAttack = isElite ? pType->VoicePrimaryEliteWeaponAttack : pType->VoicePrimaryWeaponAttack;
108+
}
109+
110+
return voiceAttack;
111+
}
112+
113+
DEFINE_HOOK(0x7090A0, TechnoClass_VoiceAttack, 0x7)
114+
{
115+
GET(TechnoClass*, pThis, ECX);
116+
GET_STACK(AbstractClass*, pTarget, 0x4);
117+
118+
const auto pType = pThis->GetTechnoType();
119+
const int weaponIndex = pThis->SelectWeapon(pTarget);
120+
const int voiceAttack = GetVoiceAttack(pType, weaponIndex, pThis->Veterancy.IsElite(), pThis->GetWeapon(weaponIndex)->WeaponType);
121+
122+
if (voiceAttack >= 0)
123+
{
124+
pThis->QueueVoice(voiceAttack);
125+
return 0x7091C7;
126+
}
127+
128+
const auto& voiceList = pType->VoiceAttack;
129+
130+
if (voiceList.Count > 0)
131+
{
132+
const int idx = Randomizer::Global.RandomRanged(0, voiceList.Count - 1);
133+
pThis->QueueVoice(voiceList[idx]);
134+
}
135+
136+
return 0x7091C7;
137+
}

0 commit comments

Comments
 (0)