Help with multiple dialogs and some lua

Rhcorr

Chieftain
Joined
Feb 21, 2015
Messages
9
Location
Brazil
Hello guys!

I've created this mini mod called "music changer" a few years ago, but I think it's now time to add more features to it.
I've recently realized that the music playing in your game is defined by a XML element called "<SoundtrackTag>", referring to your civ. So my idea was to take my mod, which was basically only a single button that skipped the current song, and add an extra menu avaible trough RIGHT clicking the button, to change <SoundtrackTag> so the player could choose between Europen, Asian, etc etc, music.

Problem is I have no clue about lua and coding languages. I just barely got the XML (buttons, texts, dialogs) right and now I need some help making it work :crazyeye:

So far, I have 4 elements on my mod. MusicButton.xml, MusicButton.lua and Select.xml, Select.lua.
The MusicButton is permanent little button on top of the screen. Left-click skips songs, and now I want to add a right-click feature. The Select would be the new pop-up with various buttons to select a new "continent" for your music.

The problem is, one function in the lua must refer to another file (musicbutton -> select). I know the function is Controls.OK:RegisterCallback(Mouse.eRClick, function() , but I can't figure out the right action. I've tried ContextPtr.Select:SetHide(false) but that doesn't work.



The second problem is, how can I change the <SoundtrackTag> at the click of a button (in the selection menu)? Is there a lua code to do that?
I know it's part of the civilazion's attributes.

Any help would be greatly appreciated, since it's becoming too tricky doing this by myself.

Code in my "MusicButton.lua"
Spoiler :

Controls.OK:RegisterCallback(Mouse.eLClick, function()
Events.AudioDebugChangeMusic(true,false,false);
print("Music changer: current song skipped")
end);

Controls.OK:RegisterCallback(Mouse.eRClick, function()
ContextPtr.Select:SetHide(false)
end);


Current "MusicButton.xml"
Spoiler :

<Context>
<Container Size="80,30" Anchor="R,T" Offset ="290,28" ConsumeMouse="1" Font="TWCenMT18">
<GridButton ID="OK" Size="70,20" Anchor="C,T" Offset="0,0" Style="BaseButton"
ToolTip="Skips the current music playing.">

<ShowOnMouseOver>
<AlphaAnim Anchor="L,C" AnchorSide="O,O" Size="16,26"
TextureOffset="0,0" Texture="buttonsidesglow.dds" Cycle="Bounce"
Speed="1" AlphaStart=".99" AlphaEnd=".25"/>
<Image Anchor="L,C" AnchorSide="O,O" Size="8,16"
TextureOffset="0,0" Texture="buttonsides.dds" />

<AlphaAnim Anchor="R,C" AnchorSide="O,O" Size="16,32"
TextureOffset="16,0" Texture="buttonsidesglow.dds" Cycle="Bounce"
Speed="1" AlphaStart=".99" AlphaEnd=".25"/>
<Image Anchor="R,C" AnchorSide="O,O" Size="8,16"
TextureOffset="8,0" Texture="buttonsides.dds" />
</ShowOnMouseOver>

<Label Anchor="C,C" Offset="0,-2" String="Music" Font="TwCenMT16"
FontStyle="Shadow" ColorSet="Beige_Black_Alpha" />
</GridButton>
</Container>
</Context>


The current "Select.xml"
Spoiler :

<Context>
<Box Style="BGBlock_ClearTopBar" />
<Grid Size="300,500" Anchor="C,C" Style="Grid9DetailFive140" ConsumeMouse="1">

<Image Anchor="C,T" AnchorSide="I,O" Offset="0,-27" Size="256,64" Texture="DecTop256x64.dds">
<Image Anchor="C,C" Offset="0,-6" Size="80,80" Texture="NotificationFrameBase.dds">
<Image ID="DialogTopIcon" Anchor="C,C" Offset="0,0" Size="80,80" Texture="NotificationGeneric.dds" />
</Image>
</Image>

<Label ID="Select" Anchor="C,T" Font="TwCenMT24" FontStyle="Shadow" ColorSet="Beige_Black_Alpha" Offset="0,60" String="Select your music ethnicity:"/>

<Image Anchor="L,C" AnchorSide="O,I" Offset="-17,0" Size="32,64" Texture="Dec32x64Left.dds" />
<Image Anchor="R,C" AnchorSide="O,I" Offset="-17,0" Size="32,64" Texture="Dec32x64Right.dds" />

<AlphaAnim ID="BgImage" Anchor="L,T" Offset="17,43" Size="266,414" TextureOffset="200,55" Texture="ERA_Classical.dds" Cycle="Once" Stopped="1" AlphaStart="0.3" AlphaEnd="0.3" Speed="1"/>

<GridButton ID="CANCEL" Size="180,36" Anchor="C,B" Offset="0,50" Style="BaseButton" ToolTip="Exit">
<ShowOnMouseOver>
<AlphaAnim Anchor="L,C" AnchorSide="O,O" Size="16,32" TextureOffset="0,0" Texture="buttonsidesglow.dds" Cycle="Bounce" Speed="1" AlphaStart=".99" AlphaEnd=".25"/>
<Image Anchor="L,C" AnchorSide="O,O" Size="8,16" TextureOffset="0,0" Texture="buttonsides.dds" />

<AlphaAnim Anchor="R,C" AnchorSide="O,O" Size="16,32" TextureOffset="16,0" Texture="buttonsidesglow.dds" Cycle="Bounce" Speed="1" AlphaStart=".99" AlphaEnd=".25"/>
<Image Anchor="R,C" AnchorSide="O,O" Size="8,16" TextureOffset="8,0" Texture="buttonsides.dds" />
</ShowOnMouseOver>
<Label Anchor="C,C" Offset="0,-2" String="Cancel" Font="TwCenMT24" FontStyle="Shadow" ColorSet="Beige_Black_Alpha" />
</GridButton>

<GridButton ID="EUROPE" Size="180,36" Anchor="C,B" Offset="0,130" Style="BaseButton" ToolTip="TXT_KEY_EUROPE">
<ShowOnMouseOver>
<AlphaAnim Anchor="L,C" AnchorSide="O,O" Size="16,32" TextureOffset="0,0" Texture="buttonsidesglow.dds" Cycle="Bounce" Speed="1" AlphaStart=".99" AlphaEnd=".25"/>
<Image Anchor="L,C" AnchorSide="O,O" Size="8,16" TextureOffset="0,0" Texture="buttonsides.dds" />

<AlphaAnim Anchor="R,C" AnchorSide="O,O" Size="16,32" TextureOffset="16,0" Texture="buttonsidesglow.dds" Cycle="Bounce" Speed="1" AlphaStart=".99" AlphaEnd=".25"/>
<Image Anchor="R,C" AnchorSide="O,O" Size="8,16" TextureOffset="8,0" Texture="buttonsides.dds" />
</ShowOnMouseOver>
<Label Anchor="C,C" Offset="0,-2" String="Europe" Font="TwCenMT24" FontStyle="Shadow" ColorSet="Beige_Black_Alpha" />
</GridButton>

<GridButton ID="ASIA" Size="180,36" Anchor="C,B" Offset="0,180" Style="BaseButton" ToolTip="TXT_KEY_ASIA">
<ShowOnMouseOver>
<AlphaAnim Anchor="L,C" AnchorSide="O,O" Size="16,32" TextureOffset="0,0" Texture="buttonsidesglow.dds" Cycle="Bounce" Speed="1" AlphaStart=".99" AlphaEnd=".25"/>
<Image Anchor="L,C" AnchorSide="O,O" Size="8,16" TextureOffset="0,0" Texture="buttonsides.dds" />

<AlphaAnim Anchor="R,C" AnchorSide="O,O" Size="16,32" TextureOffset="16,0" Texture="buttonsidesglow.dds" Cycle="Bounce" Speed="1" AlphaStart=".99" AlphaEnd=".25"/>
<Image Anchor="R,C" AnchorSide="O,O" Size="8,16" TextureOffset="8,0" Texture="buttonsides.dds" />
</ShowOnMouseOver>
<Label Anchor="C,C" Offset="0,-2" String="Asia" Font="TwCenMT24" FontStyle="Shadow" ColorSet="Beige_Black_Alpha" />

</GridButton>
<GridButton ID="AFRICA" Size="180,36" Anchor="C,B" Offset="0,230" Style="BaseButton" ToolTip="TXT_KEY_AFRICA">
<ShowOnMouseOver>
<AlphaAnim Anchor="L,C" AnchorSide="O,O" Size="16,32" TextureOffset="0,0" Texture="buttonsidesglow.dds" Cycle="Bounce" Speed="1" AlphaStart=".99" AlphaEnd=".25"/>
<Image Anchor="L,C" AnchorSide="O,O" Size="8,16" TextureOffset="0,0" Texture="buttonsides.dds" />

<AlphaAnim Anchor="R,C" AnchorSide="O,O" Size="16,32" TextureOffset="16,0" Texture="buttonsidesglow.dds" Cycle="Bounce" Speed="1" AlphaStart=".99" AlphaEnd=".25"/>
<Image Anchor="R,C" AnchorSide="O,O" Size="8,16" TextureOffset="8,0" Texture="buttonsides.dds" />
</ShowOnMouseOver>
<Label Anchor="C,C" Offset="0,-2" String="Africa" Font="TwCenMT24" FontStyle="Shadow" ColorSet="Beige_Black_Alpha" />

</GridButton>
<GridButton ID="AMERICA" Size="180,36" Anchor="C,B" Offset="0,280" Style="BaseButton" ToolTip="TXT_KEY_AMERICA">
<ShowOnMouseOver>
<AlphaAnim Anchor="L,C" AnchorSide="O,O" Size="16,32" TextureOffset="0,0" Texture="buttonsidesglow.dds" Cycle="Bounce" Speed="1" AlphaStart=".99" AlphaEnd=".25"/>
<Image Anchor="L,C" AnchorSide="O,O" Size="8,16" TextureOffset="0,0" Texture="buttonsides.dds" />

<AlphaAnim Anchor="R,C" AnchorSide="O,O" Size="16,32" TextureOffset="16,0" Texture="buttonsidesglow.dds" Cycle="Bounce" Speed="1" AlphaStart=".99" AlphaEnd=".25"/>
<Image Anchor="R,C" AnchorSide="O,O" Size="8,16" TextureOffset="8,0" Texture="buttonsides.dds" />
</ShowOnMouseOver>
<Label Anchor="C,C" Offset="0,-2" String="America" Font="TwCenMT24" FontStyle="Shadow" ColorSet="Beige_Black_Alpha" />

</GridButton>
<GridButton ID="MIDEASTERN" Size="180,36" Anchor="C,B" Offset="0,330" Style="BaseButton" ToolTip="TXT_KEY_MIDEASTERN">
<ShowOnMouseOver>
<AlphaAnim Anchor="L,C" AnchorSide="O,O" Size="16,32" TextureOffset="0,0" Texture="buttonsidesglow.dds" Cycle="Bounce" Speed="1" AlphaStart=".99" AlphaEnd=".25"/>
<Image Anchor="L,C" AnchorSide="O,O" Size="8,16" TextureOffset="0,0" Texture="buttonsides.dds" />

<AlphaAnim Anchor="R,C" AnchorSide="O,O" Size="16,32" TextureOffset="16,0" Texture="buttonsidesglow.dds" Cycle="Bounce" Speed="1" AlphaStart=".99" AlphaEnd=".25"/>
<Image Anchor="R,C" AnchorSide="O,O" Size="8,16" TextureOffset="8,0" Texture="buttonsides.dds" />
</ShowOnMouseOver>
<Label Anchor="C,C" Offset="0,-2" String="Middle Eastern" Font="TwCenMT24" FontStyle="Shadow" ColorSet="Beige_Black_Alpha" />
</GridButton>

</Grid>
</Context>


*edit: I just wanted to note that I have searched for this in all threads I could find, and read and downloaded the basic and the UI tutorials, but couldn't find one that could do a cross-reference, I mean, the lua from one xml making another xml dialog unhide.. it's always "example A" lua acting upon "example A" xml.
I have though maybe I could include everything in the same xml somehow.. but that would require two different contexts... so one of them could remain hidden and the other not. I am not sure it would work
 
That seems reasonable! Thanks for the reply.

Could you give me a little bit more insight on the matter?
Is there a tag that prevents a specific container from ever being hidden? And how do I hide the other one when the game starts?

If that is solved, all I would need is a lua code to change that SoundTrackTag string and I'd be done!:)
 
To hide it by default just set Hidden="1" in the XML for that container, then unhide it when necessary with control:SetHide(false). Just don't hide the other one.
 
Can the "SetHide" command be issued only to a specific container? Otherwise, when it hides again (after clicking an option and setting SetHide(true) ), both the menu and the button would hide (considering they would be in the same xml). At least so it would seem to me.
 
SetHide() can be used for any individual control, but in this case you'd reference the ID that you assigned to the container.

XML: <Container ID="blahblah" Hidden="1">
Lua: Controls.blahblah:SetHide(false)


EDIT: ...Then anything within that container would hide.
 
That makes perfect sense, and it worked!! Thank you very much, Nutty.

Only issue left with the menu is that when it pops up, about 70% of the screen gets darked out behind it, but not the upper rest of it. I can also select units on the "not-darkened" part of the screen. Weird!


But the only important issue left is: how to change tags with lua code? More specifically, a SoundTrackTag, within <Civilization> :think:
 
Make the container Size="Full,Full"

You can use DB.Query() with SQL statements, but the database is cached already, so I'm pretty sure it's not going to help to change the tag at that point.

Can you do it manually, i.e., subscribe to Events.AudioDebugChangeMusic, check the arguments for whether it's a next track event or a war started event, and invoke Events.AudioPlay2DSound to play the appropriate song?

EDIT: Actually, you don't care about arg1 (war event)... you'd only be checking for whether arg0 = true, then check the Team.IsAtWar state for whether you should be starting a war song or a peace song, since you'll need to continue to play war songs, if so...
EDIT #2: Wait, does it come through arg0 = 1, arg1 = 1 every time war is declared? Probably not... so then I guess it'd be if arg0 = true OR arg1 = true...
EDIT #3: Hell, since the only other condition is the reset flag, I guess you don't care about the state of the arguments.
 
The UI is perfect now. I'm still out of ideas for the custom playlist thing, though. I think the solution you suggested could work if I wanted one song to be played, but to swap the roughly 60 songs playlist from each continent would complicated.

I have thought about including custom XML music playlists in the mod, and replacing them once the player chooses a continent. So, instead of changing the SoundTrackTag from Babylon to Germany (if the player wants european music), change the original Playlist file from Babylon to one identical to germany. The trick would be to do so only when the player chooses, and being able to change freely.

Also, I know that the SoundTrackTag is defined in CivVCivilizations.xml under Gameplay/XML/Civilizations. Seems that the game creates a table with these informations stored, so SQL is probably involved. All the variables are created as columns, and then civilizations are added as rows. I think one sure way to change this would be to create a repeating function that would change the SoundTrackTag in all of the rows (Civs) to a country corresponding to the continent the player chooses. Then, somehow reload these informations and then skip the song.

Could this work? Can it be that I am coming closer to a solution? Would appreciate any help from someone with .lua knowledge!



Also, is there any way the Firaxis live tuner would log or pring ALL scripts, actions, commands etc being processed in the game? I think I could learn a lot of stuff that way. I'm trying to figure out a command to change the current song to a leader's song, in a fluid way, that doesn't require manually stopping the current music and invoking a 2d audio (I heard they don't repeat, and when they finish, the music stops completely).
 
Like I said before, the database is cached, so it doesn't go back to look at any changes you might have made until the game is reloaded (I believe there are a few rare exceptions, but it probably doesn't apply here). You might be able to accomplish something by putting the music choices in Advanced Startup, where you'd make your choice before the game started. Even if you would prefer your mod to be able to make on-the-fly choices, I think that idea would be an interesting suggestion for General Tso's Really Advanced Setup mod.

I don't think my method is as complicated as you think...
It's not a one-time thing. By subscribing to the Events.AudioDebugChangeMusic event (i.e., Events.AudioDebugChangeMusic.Add(YourFunction)), the game will call YourFunction() each time the music is changed. You simply start your own song instead of the one the game was going to play. At the end of your song, the event is triggered [hopefully], and your function is called, ad infinitum.

You will need to persist data so you can remember the player's choice of music and the current song.

YourFunction() would check the player's choice of music, loop through the appropriate database entries, and check the at-war status. If we've changed at-war status, pick a random one from the appropriate playlist. Otherwise, play the next song in the list.

If bIsMusic is set true for the 2DSound in question, then the current music is stopped when the next one starts, i.e., only one can play at a time. However, if Events.AudioDebugChangeMusic isn't called at the end of the 2DSound that's been manually initiated, then you're right, that would mean this method doesn't work.

Either way, it's worth a try. I'm not a Lua expert, but if you upload what you have so far, then I would be happy to run an experiment.
 
Well, I have almost zero knowledge about lua, so the best I can do is experiment with code that is already there... I wish I could make these functions from scrach!

But my idea for the mod changed. Too much trouble with the whole "changing playlists" thing. Instead of changing the whole playlist, I just want the menu to display a list of leader music, so the player can play one of them when he chooses. For example, you really like the Greece peace theme, so you can listen to it when you want. After it is done, the game returns to the normal music, which you still can skip with the button.

I figured this much:
Events.AudioPlay2DSound("AS2D_LEADER_MUSIC_ALEXANDER_PEACE");
This command successfully plays the music, but its no ordinary 2d sound, for some reason. It plays together with the music, doesn't loop, but even after you EXIT the game (to the main menu) it keeps playing. Start a new game, that music is still playing. It just goes on and on for several minutes, so that's a problem.
I have noticed you referred to "bIsMusic", how can I use it in the lua? I've seen it is a xml value specified in each playlist.

Also, I discovered this event: Event.AudioChangeMusic
It is in the Civ V API and exists in the game, but there is no entry for in in the wiki. It seems to be an obsolete function, no longer used, but can one be sure of this?
Also, if I just add it to the fuction, the code breaks. Despite being an event (seemingly), you cannot add a field to it, and without a field, the code breaks. If I add a field the mod can be built but there is a Runtime error in the lua when pressing the button that calls for that event:
Attempt to call field 'AudioChangeMusic' (a nil value)
Don't know what to think of it.


So basically, if I now figure out how to play a 2d sound that behaves just like music in the game, I'd be set.
 
So, I have thought of a workaround for this.

I have created a new xml file and defined custom 2d audio files in the mod, according to tutorials on how to create your own Civ playlist in this forum.
But instead of adding custom sound files, I just added a new ID for the music from the game (leader music). With this new ID I created a reference that I could use how I wanted. I wanted to make sure those audio files would be loaded as music, and would play exactly like the normal music (I compared to the existing AudioDefines.xml and Audio2DScripts.xml)

This is the file that defines my "custom" audio IDs
Spoiler :
<GameData>
<Audio_Sounds>
<Row>
<SoundID>SND_GREECE_PEACE</SoundID>
<Filename>Alexander_Peace</Filename>
<LoadType>STREAMED</LoadType>
</Row>
<Row>
<SoundID>SND_GREECE_WAR</SoundID>
<Filename>Alexander_War</Filename>
<LoadType>STREAMED</LoadType>
</Row>
<Row>
<SoundID>SND_TEST_VOICE</SoundID>
<Filename>AlexanderAttacked</Filename>
<LoadType>DynamicResident</LoadType>
</Row>
</Audio_Sounds>
<Audio_2DSounds>
<Row>
<ScriptID>AS2D_GREECE_PEACE</ScriptID>
<SoundID>SND_GREECE_PEACE</SoundID>
<SoundType>GAME_MUSIC</SoundType>
<MinVolume>100</MinVolume>
<MaxVolume>100</MaxVolume>
<IsMusic>true</IsMusic>
</Row>
<Row>
<ScriptID>AS2D_GREECE_WAR</ScriptID>
<SoundID>SND_GREECE_WAR</SoundID>
<SoundType>GAME_MUSIC</SoundType>
<MinVolume>100</MinVolume>
<MaxVolume>100</MaxVolume>
<IsMusic>true</IsMusic>
</Row>
<Row>
<ScriptID>AS2D_TEST_VOICE</ScriptID>
<SoundID>SND_TEST_VOICE</SoundID>
<SoundType>GAME_SFX</SoundType>
<MinVolume>80</MinVolume>
<MaxVolume>80</MaxVolume>
</Row>
</Audio_2DSounds>
</GameData>


And this is the menu that "plays" it:
Spoiler :

Controls.OK:RegisterCallback(Mouse.eLClick, function()
Events.AudioDebugChangeMusic(true,false,false);
print("Music changer: current song skipped")
end);

Controls.OK:RegisterCallback(Mouse.eRClick, function()
Controls.menu:SetHide(false)
end);

Controls.OPTION1:RegisterCallback(Mouse.eLClick, function()
--Controls.menu:SetHide(true)
print("Music changer: This button does nothing")
end);

Controls.OPTION2:RegisterCallback(Mouse.eLClick, function()
--Controls.menu:SetHide(true)
Events.AudioPlay2DSound("AS2D_GREECE_PEACE")
print("Music changer: Playing greece peace")
end);

Controls.OPTION3:RegisterCallback(Mouse.eLClick, function()
--Controls.menu:SetHide(true)
Events.AudioPlay2DSound("AS2D_GREECE_WAR")
print("Music changer: Playing greece war")
end);

Controls.OPTION4:RegisterCallback(Mouse.eLClick, function()
--Controls.menu:SetHide(true)
Events.AudioPlay2DSound("AS2D_IF_MP_CHAT_DING")
print("Music changer: test sound")
end);

Controls.OPTION5:RegisterCallback(Mouse.eLClick, function()
--Controls.menu:SetHide(true)
Events.AudioPlay2DSound("AS2D_TEST_VOICE")
print("Music changer: test voice")
end);

Controls.CANCEL:RegisterCallback(Mouse.eLClick, function()
Controls.menu:SetHide(true)
end);


In this menu you could choose to start to play Greece peace music, Greece war or play test sounds to see if things are working.
In the beginning, all sounds worked, but the music played, again, as a separate instance, on top of the current music, and would not stop even upon exiting the game. Also you could press play and hear the song beginning and playing multiple times untill the music bugged. Then I put in the tag "is music". I believe that after that, none of the custom defined sounds worked for me anymore, but I can't be sure that was it, because I couldn't get it to work again.
For a while all I got was runtime errors (sound file not found), but eventually I finally optimized the XML and now it seems to be working (no errors), but has no effect.
I mean, I put a print('playing song now') kind of command with the buttons, which prints that to the LiveTuner console, and we can see it printing with no errors. But regarding music, nothing changes whatsoever.

So the problem is, the code seems to be running fine, but does nothing despite it clearly being only a code to play a 2d audio file.
I've attached the mod, if someone would be so kind to analyze it...


Checklist:
added UpdateDatabase on activating the mod: CHECK
ticked the "reload sound system" on mod properties: CHECK
made sure there were no XML errors: CHECK
used load type = DynamicResident for ALL the sounds and tried that out: CHECK
searched google for a solution: CHECK
 

Attachments

  • Music Changer (v 3) 23 feb 2015.zip
    3.5 KB · Views: 22
I did some experiments yesterday. FWIW, I was able to resolve the issue with multiple music tracks playing with Events.AudioDebugChangeMusic(true, false, true).

However it does appear that Events.AudioPlay2DSound doesn't respect the IsMusic database field, so I think that the rest of the thing is a bust. I wanted to play around some more tonight before I said definitively that what you want is impossible, but that's what it looks like.

There's still the idea of adding a menu to Really Advanced Setup...
 
However it does appear that Events.AudioPlay2DSound doesn't respect the IsMusic database field, so I think that the rest of the thing is a bust. I wanted to play around some more tonight before I said definitively that what you want is impossible, but that's what it looks like.

Well, that settles it, then. Maybe someday a patch will change this! Thanks for your help!
 
Top Bottom