Jump to content

Sound replacement possible?


TRekNexus

Recommended Posts

Although AdvanceLanguage appears to be setting a new voice with m_kPawn.SetVoiceSilently(m_kPawn.PossibleVoices[0]) call, for whatever reason actual voice number doesn't get changed until you click the arrow.

Maybe appending AdvanceVoice(0) to the AdvanceLanguage() function could do the trick to refresh the voice selection.

Link to comment
Share on other sites

  • Replies 199
  • Created
  • Last Reply

Top Posters In This Topic

Thanks, XMarksTheSpot!

 

I ended up coding this:

 

    XComContentManager(class'Engine'.static.GetEngine().GetContentManager()).GetPossibleVoices(byte(m_kSoldier.m_kSoldier.kAppearance.iGender), NewLanguage, m_kSoldier.IsAugmented(), m_kPawn.PossibleVoices);
    m_kPawn.SetLanguage(NewLanguage);
    m_kSoldier.m_kSoldier.kAppearance.iLanguage = NewLanguage;
    m_kPawn.SetVoiceSilently(m_kPawn.PossibleVoices[0]);
    AdvanceVoice(0);

 

 

It seems to be working. Patcher code:

 

UPK_FILE=XComStrategyGame.upk
OBJECT=XGCustomizeUI.AdvanceLanguage:AUTO
[BEFORE_CODE]
//m_kPawn.SetVoiceSilently(m_kPawn.PossibleVoices[0])
19 01 <@m_kPawn> 2A 00 <NullRef> 00 1B <SetVoiceSilently>
10 25 19 01 <@m_kPawn> 09 00 <XComGame.XComHumanPawn.PossibleVoices> 00 01 <XComGame.XComHumanPawn.PossibleVoices> 16
//m_kPawn.SetLanguage(NewLanguage)
19 01 <@m_kPawn> 13 00 <NullRef> 00 1B <SetLanguage> 00 <.NewLanguage> 16
//m_kSoldier.m_kSoldier.kAppearance.iLanguage = NewLanguage
0F 35 <XComGame.XGTacticalGameCoreNativeBase.TAppearance.iLanguage> <XComGame.XGTacticalGameCoreNativeBase.TAppearance> 00 00
35 <XComGame.XGTacticalGameCoreNativeBase.TSoldier.kAppearance> <XComGame.XGTacticalGameCoreNativeBase.TSoldier> 00 01
19 01 <@m_kSoldier> 09 00 <XGStrategySoldier.m_kSoldier> 00 01 <XGStrategySoldier.m_kSoldier>
38 3A 00 <.NewLanguage>
[AFTER_CODE]
//m_kPawn.SetLanguage(NewLanguage)
19 01 <@m_kPawn> 13 00 <NullRef> 00 1B <SetLanguage> 00 <.NewLanguage> 16
//m_kSoldier.m_kSoldier.kAppearance.iLanguage = NewLanguage
0F 35 <XComGame.XGTacticalGameCoreNativeBase.TAppearance.iLanguage> <XComGame.XGTacticalGameCoreNativeBase.TAppearance> 00 00
35 <XComGame.XGTacticalGameCoreNativeBase.TSoldier.kAppearance> <XComGame.XGTacticalGameCoreNativeBase.TSoldier> 00 01
19 01 <@m_kSoldier> 09 00 <XGStrategySoldier.m_kSoldier> 00 01 <XGStrategySoldier.m_kSoldier>
38 3A 00 <.NewLanguage>
//m_kPawn.SetVoiceSilently(m_kPawn.PossibleVoices[0])
19 01 <@m_kPawn> 2A 00 <NullRef> 00 1B <SetVoiceSilently>
10 25 19 01 <@m_kPawn> 09 00 <XComGame.XComHumanPawn.PossibleVoices> 00 01 <XComGame.XComHumanPawn.PossibleVoices> 16
//AdvanceVoice(0)
1B <AdvanceVoice> 25 16

 

 

Looks like the bug was caused by SetVoiceSilently not updating kAppearance variable.

Edited by wghost81
Link to comment
Share on other sites

WGhost, fantastic! I think I've seen that bug too, but I had thought it was just my misclicking. I had noticed after setting voice #1 to a custom voice I would sometimes come back to the customization screen and it would show voice 0.

 

So to summarize, I think we have completely working languages for both males and females, with random cues. All we need now is good content :) is there anything else missing?

Link to comment
Share on other sites

I have successfully replaced one track with another, yes. As far as adding new music and having one chosen randomly, I'm not sure if its possible or not. I will look into how the music system works. At the very least, if its still based off sound cues, and I think it is, it should be possible to add new music and add a random sound cue to randomize them.
Link to comment
Share on other sites

LiQuiD911: I did some more research today, and it looks like adding/replacing music is doable. Exactly how easy it is to replace what depends on the kind of music you want to replace, since they're implemented differently in the game. There are particular tracks that play for squad loadout, the menu, the memorial, ambient music in missions and in HQ, combat music, etc. As an expriment, I created my own combat music. This was pretty easy to do, as the way combat music is implemented makes it very easily moddable.

 

The combat music is in the packages CombatMusic1_SF.upk through ComatMusic9_SF.upk. These are very simple packages that you can create with the UDK, and contain only a sound node and a corresponding sound cue. I created a custom package in the UDK and imported a sound and created the cue. Instructions on how to do this are in my earlier tutorial post about creating voice banks with the UDK, but these are simpler because there is no need for any archetype. Just import the sound and create the cue, cook it and you're done. In the cue editor, you'll probably want to add a looping node so the track will repeat. It'll sound best if the cut between the end of the track and the beginning is pretty seamless so it loops nicely.

 

To actually get the sound into the game, you can just replace one of the existing sounds by using the same package and cue name as an existing sound and then just swapping the package on disk. What I did is a little fancier, which was make the list of combat music cues customizable so you can put them in the defaultcontent.ini file and add as many as you like. The way the combat music tracks are set up makes this really simple, it just requires four very small hex edits to the XComGame.upk file. I can give you the details of what to change if you're interested in doing this. Basically it just involves making XComGame.XComTacticalSoundManager config(Content), and making the CombatMusicCues array a configurable array. Then you can list all the tracks you want to use in the defaultcontent.ini file, like this:

[XComGame.XComTacticalSoundManager]

CombatMusicCues="CombatMusic1.ActionMusic1Cue"

CombatMusicCues="CombatMusic2.ActionMusic2Cue"

CombatMusicCues="CombatMusic3.ActionMusic3Cue"

CombatMusicCues="CombatMusic4.ActionMusic4Cue"

CombatMusicCues="CombatMusic5.ActionMusic5Cue"

CombatMusicCues="CombatMusic6.ActionMusic6Cue"

CombatMusicCues="CombatMusic7.ActionMusic7Cue"

CombatMusicCues="CombatMusic8.ActionMusic8Cue"

CombatMusicCues="CombatMusic9.ActionMusic9Cue"

This just sets the combat music to the defaults that were already there. Add your own by just adding a line, setting it to the package name and sound cue name inside your package.

Link to comment
Share on other sites

I've managed to enable hunker down soldier speech while also disabling annoying (for me, at least) hunker and OW UI sounds, because they are too loud and mask soldier voice. SHIVs, VIPs and aliens still use UI sounds. Patcher modfile:

 

 

UPK_FILE=XComGame.upk

OBJECT=UITacticalHUD_AbilityContainer.OnAccept
[BEFORE_CODE]
//PlaySound(soundcue'HunkerDownCue', true)
1C <Engine.Actor.PlaySound> 20 <SoundUI.HunkerDownCue> 27 4A 4A 4A 4A 16
[AFTER_CODE]
00 <.kUnit> 00 <.kUnit> 0B 0B 0B 0B 0B 0B

OBJECT=XGUnit.PerformAbility
[BEFORE_CODE]
//UnitSpeak(3)
1B <UnitSpeak> 24 03 4A 16
[AFTER_CODE]
0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B 0B

OBJECT=XGAbilityTree.ApplyEffectsToTarget:AUTO
[BEFORE_CODE]
//if((kAbility.GetType() == 27) || kAbility.GetType() == 70)
07 68 32
84 9A 19 00 <.kAbility> 0A 00 <XGAbility.GetType.ReturnValue> 00 1B <GetType> 16 2C 1B 16
18 24 00
   9A 19 00 <.kAbility> 0A 00 <XGAbility.GetType.ReturnValue> 00 1B <GetType> 16 2C 46 16 16
//kTarget.HunkerDown()
19 00 <.kTarget> 0A 00 <NullRef> 00 1B <HunkerDown> 16
//if(kTarget.IsMine() || kTarget.IsVisibleToTeam(GetALocalPlayerController().m_eTeam))
07 65 32
84 19 00 <.kTarget> 0A 00 <XGUnitNativeBase.IsMine.ReturnValue> 00 1B <IsMine> 16
18 3F 00
   19 00 <.kTarget> 29 00 <Engine.Actor.IsVisibleToTeam.ReturnValue> 00 1B <IsVisibleToTeam> 19 1C <Engine.Actor.GetALocalPlayerController> 16 09 00 <Engine.Actor.m_eTeam> 00 01 <Engine.Actor.m_eTeam> 16 16
//PlaySound(SoundCue(DynamicLoadObject("SoundUI.HunkerDownCue", class'SoundCue')), true)
1C <Engine.Actor.PlaySound> 2E <Engine.SoundCue> 1C <Core.Object.DynamicLoadObject> 1F <%t "SoundUI.HunkerDownCue"> 20 <Engine.SoundCue> 4A 16 27 4A 4A 4A 4A 16
//goto J0x3354
06 54 33
//if(kAbility.GetType() == 22)
07 54 33 9A 19 00 <.kAbility> 0A 00 <XGAbility.GetType.ReturnValue> 00 1B <GetType> 16 2C 16 16
//kTarget.Overwatch()
19 00 <.kTarget> 0A 00 <NullRef> 00 1B <Overwatch> 16
//if(kTarget.IsMine() || kTarget.IsVisibleToTeam(GetALocalPlayerController().m_eTeam))
07 54 33
84 19 00 <.kTarget> 0A 00 <XGUnitNativeBase.IsMine.ReturnValue> 00 1B <IsMine> 16
18 3F 00
   19 00 <.kTarget> 29 00 <Engine.Actor.IsVisibleToTeam.ReturnValue> 00 1B <IsVisibleToTeam> 19 1C <Engine.Actor.GetALocalPlayerController> 16 09 00 <Engine.Actor.m_eTeam> 00 01 <Engine.Actor.m_eTeam> 16 16
//PlaySound(SoundCue(DynamicLoadObject("SoundUI.OverwatchCue", class'SoundCue')), true)
1C <Engine.Actor.PlaySound> 2E <Engine.SoundCue> 1C <Core.Object.DynamicLoadObject> 1F <%t "SoundUI.OverwatchCue"> 20 <Engine.SoundCue> 4A 16 27 4A 4A 4A 4A 16
//if
07 36 34

[AFTER_CODE]
//if((kAbility.GetType() == 27) || kAbility.GetType() == 70)
07 DB 32
84 9A 19 00 <.kAbility> 0A 00 <XGAbility.GetType.ReturnValue> 00 1B <GetType> 16 2C 1B 16
18 24 00
   9A 19 00 <.kAbility> 0A 00 <XGAbility.GetType.ReturnValue> 00 1B <GetType> 16 2C 46 16 16
//kTarget.HunkerDown()
19 00 <.kTarget> 0A 00 <NullRef> 00 1B <HunkerDown> 16
//if (kTarget.GetCharacter().m_kChar.iType == 2)
07 30 32
9A 35 <XGTacticalGameCoreNativeBase.TCharacter.iType> <XGTacticalGameCoreNativeBase.TCharacter> 00 00 19 19 00 <.kTarget> 0A 00 <XGUnit.GetCharacter.ReturnValue> 00 1B <GetCharacter> 16 09 00 <XGCharacter.m_kChar> 00 01 <XGCharacter.m_kChar> 2C 02 16
//kTarget.UnitSpeak(1)
19 00 <.kTarget> 0D 00 <NullRef> 00 1B <UnitSpeak> 24 01 4A 16
// goto
06 D8 32
//if(kTarget.IsMine() || kTarget.IsVisibleToTeam(GetALocalPlayerController().m_eTeam))
07 D8 32
84 19 00 <.kTarget> 0A 00 <XGUnitNativeBase.IsMine.ReturnValue> 00 1B <IsMine> 16
18 3F 00
   19 00 <.kTarget> 29 00 <Engine.Actor.IsVisibleToTeam.ReturnValue> 00 1B <IsVisibleToTeam> 19 1C <Engine.Actor.GetALocalPlayerController> 16 09 00 <Engine.Actor.m_eTeam> 00 01 <Engine.Actor.m_eTeam> 16 16
//PlaySound(SoundCue(DynamicLoadObject("SoundUI.HunkerDownCue", class'SoundCue')), true)
1C <Engine.Actor.PlaySound> 2E <Engine.SoundCue> 1C <Core.Object.DynamicLoadObject> 1F <%t "SoundUI.HunkerDownCue"> 20 <Engine.SoundCue> 4A 16 27 4A 4A 4A 4A 16
//goto J0x3354
06 3A 34
//if(kAbility.GetType() == 22)
07 3A 34 9A 19 00 <.kAbility> 0A 00 <XGAbility.GetType.ReturnValue> 00 1B <GetType> 16 2C 16 16
//kTarget.Overwatch()
19 00 <.kTarget> 0A 00 <NullRef> 00 1B <Overwatch> 16
//if (kTarget.GetCharacter().m_kChar.iType == 2)
07 93 33
9A 35 <XGTacticalGameCoreNativeBase.TCharacter.iType> <XGTacticalGameCoreNativeBase.TCharacter> 00 00 19 19 00 <.kTarget> 0A 00 <XGUnit.GetCharacter.ReturnValue> 00 1B <GetCharacter> 16 09 00 <XGCharacter.m_kChar> 00 01 <XGCharacter.m_kChar> 2C 02 16
//kTarget.UnitSpeak(3)
19 00 <.kTarget> 0D 00 <NullRef> 00 1B <UnitSpeak> 24 03 4A 16
// goto
06 3A 34
//if(kTarget.IsMine() || kTarget.IsVisibleToTeam(GetALocalPlayerController().m_eTeam))
07 3A 34
84 19 00 <.kTarget> 0A 00 <XGUnitNativeBase.IsMine.ReturnValue> 00 1B <IsMine> 16
18 3F 00
   19 00 <.kTarget> 29 00 <Engine.Actor.IsVisibleToTeam.ReturnValue> 00 1B <IsVisibleToTeam> 19 1C <Engine.Actor.GetALocalPlayerController> 16 09 00 <Engine.Actor.m_eTeam> 00 01 <Engine.Actor.m_eTeam> 16 16
//PlaySound(SoundCue(DynamicLoadObject("SoundUI.OverwatchCue", class'SoundCue')), true)
1C <Engine.Actor.PlaySound> 2E <Engine.SoundCue> 1C <Core.Object.DynamicLoadObject> 1F <%t "SoundUI.OverwatchCue"> 20 <Engine.SoundCue> 4A 16 27 4A 4A 4A 4A 16
//if
07 1C 35

 

 

BTW, in vanilla hunker down UI sound is played twice, that's why it sounds so weird.

Edited by wghost81
Link to comment
Share on other sites

 

I went through the voice banks for male soldier english #1 and pulled out the number of unique sound node names listed throughout all the banks. The only really interesting things that I found were that the "run" and "dash" events actually have two sounds in most banks, for a total of 26 and 27 unique sounds for those two events, respectively. All other events have exactly 1 sound per bank, but most start to periodically recycle sounds from previous banks. For example, there are only 3 distinct StabilizingAlly sounds for this voice, and they repeat throughout the 15 banks.

The distributions aren't exactly the same across the other voices, but they're fairly close. There are gaps in the numbering scheme on the sounds for some of them, which could be just clips they recorded from the voice actors but omitted for whatever reason.

Here's the raw data for the first voice. Some of these seem really over-represented (really, 13 combat stim voices?), but I think the main takeaway is have lots of move/dash options, and the rest look to average somewhere around 10 except for the really rare events.

 

TrackTwo,

 

I'm getting around to working up the script requirements and had a question.

 

Will you still need to duplicate some voice segments to 'fill out' each eCharSpeech entry? That is, if you get 10 "LowAmmo" wavs, will you need to duplicate 5 or some other number of them? If that's the case, does that mean the duplicated ones will ultimately play more often?

 

ADDENDUM:

 

 

The existing sounds use the convention like this: SM01HunkerDown01. "SM" or "SF" is soldier male/female. Then the name of the event, and a two digit counter starting at 01 for each variant. The packages themselves are named "MaleVoice1_English_bank0", for the first (0th) bank of the english male voice #1. So a similar convention would be useful. E.g. a folder named as the package, and inside files with the convention of the sound node names.

 

In the example SM01HunkerDown01

 

What is the first "01?" Is that a distinct index for the voice, or does it repeat the counter for each voice segment?

Edited by johnnylump
Link to comment
Share on other sites

No duplication is needed and object names are unimportant. We can have any number of random samples and voice banks, those are not hard-coded. The game can also handle an empty sample - it plays no sound in this case.

 

only problem we have is that 6 different voice types are hard-coded for females. But still, we don't need to fill all 6, as we can have, say, 3 voices and the other 3 will be just empty.

Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.

×
×
  • Create New...