mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-28 14:24:43 -04:00
MusicController tweaks and hooks for mood - War and Peace (#5364)
* MusicController tweaks and hooks for mood - War and Peace * MusicController tweaks and hooks for mood - patch1 * MusicController tweaks and hooks for mood - const object * MusicController tweaks and hooks for mood - patch2 Co-authored-by: Yair Morgenstern <yairm210@hotmail.com>
This commit is contained in:
parent
982d739ec8
commit
a0f6596ee8
@ -15,6 +15,7 @@ import com.unciv.models.tilesets.TileSetCache
|
|||||||
import com.unciv.models.translations.Translations
|
import com.unciv.models.translations.Translations
|
||||||
import com.unciv.ui.LanguagePickerScreen
|
import com.unciv.ui.LanguagePickerScreen
|
||||||
import com.unciv.ui.audio.MusicController
|
import com.unciv.ui.audio.MusicController
|
||||||
|
import com.unciv.ui.audio.MusicMood
|
||||||
import com.unciv.ui.utils.*
|
import com.unciv.ui.utils.*
|
||||||
import com.unciv.ui.worldscreen.PlayerReadyScreen
|
import com.unciv.ui.worldscreen.PlayerReadyScreen
|
||||||
import com.unciv.ui.worldscreen.WorldScreen
|
import com.unciv.ui.worldscreen.WorldScreen
|
||||||
@ -111,7 +112,7 @@ class UncivGame(parameters: UncivGameParameters) : Game() {
|
|||||||
|
|
||||||
// This stuff needs to run on the main thread because it needs the GL context
|
// This stuff needs to run on the main thread because it needs the GL context
|
||||||
Gdx.app.postRunnable {
|
Gdx.app.postRunnable {
|
||||||
musicController.chooseTrack()
|
musicController.chooseTrack(suffix = MusicMood.Menu)
|
||||||
|
|
||||||
ImageGetter.ruleset = RulesetCache.getBaseRuleset() // so that we can enter the map editor without having to load a game first
|
ImageGetter.ruleset = RulesetCache.getBaseRuleset() // so that we can enter the map editor without having to load a game first
|
||||||
|
|
||||||
|
@ -16,6 +16,8 @@ import com.unciv.models.ruleset.Difficulty
|
|||||||
import com.unciv.models.ruleset.ModOptionsConstants
|
import com.unciv.models.ruleset.ModOptionsConstants
|
||||||
import com.unciv.models.ruleset.Ruleset
|
import com.unciv.models.ruleset.Ruleset
|
||||||
import com.unciv.models.ruleset.RulesetCache
|
import com.unciv.models.ruleset.RulesetCache
|
||||||
|
import com.unciv.ui.audio.MusicMood
|
||||||
|
import com.unciv.ui.audio.MusicTrackChooserFlags
|
||||||
import com.unciv.models.ruleset.unit.BaseUnit
|
import com.unciv.models.ruleset.unit.BaseUnit
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
@ -199,8 +201,12 @@ class GameInfo {
|
|||||||
currentPlayerCiv = getCivilization(currentPlayer)
|
currentPlayerCiv = getCivilization(currentPlayer)
|
||||||
if (currentPlayerCiv.isSpectator()) currentPlayerCiv.popupAlerts.clear() // no popups for spectators
|
if (currentPlayerCiv.isSpectator()) currentPlayerCiv.popupAlerts.clear() // no popups for spectators
|
||||||
|
|
||||||
|
if (turns % 10 == 0) //todo measuring actual play time might be nicer
|
||||||
|
UncivGame.Current.musicController.chooseTrack(currentPlayerCiv.civName,
|
||||||
|
MusicMood.peaceOrWar(currentPlayerCiv.isAtWar()), MusicTrackChooserFlags.setNextTurn)
|
||||||
|
|
||||||
// Start our turn immediately before the player can made decisions - affects whether our units can commit automated actions and then be attacked immediately etc.
|
// Start our turn immediately before the player can make decisions - affects
|
||||||
|
// whether our units can commit automated actions and then be attacked immediately etc.
|
||||||
notifyOfCloseEnemyUnits(thisPlayer)
|
notifyOfCloseEnemyUnits(thisPlayer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ class MusicController {
|
|||||||
private const val musicHistorySize = 8 // number of names to keep to avoid playing the same in short succession
|
private const val musicHistorySize = 8 // number of names to keep to avoid playing the same in short succession
|
||||||
private val fileExtensions = listOf("mp3", "ogg") // flac, opus, m4a... blocked by Gdx, `wav` we don't want
|
private val fileExtensions = listOf("mp3", "ogg") // flac, opus, m4a... blocked by Gdx, `wav` we don't want
|
||||||
|
|
||||||
internal const val consoleLog = false
|
internal const val consoleLog = true
|
||||||
|
|
||||||
private fun getFile(path: String) =
|
private fun getFile(path: String) =
|
||||||
if (musicLocation == FileType.External && Gdx.files.isExternalStorageAvailable)
|
if (musicLocation == FileType.External && Gdx.files.isExternalStorageAvailable)
|
||||||
@ -98,9 +98,10 @@ class MusicController {
|
|||||||
fireOnChange()
|
fireOnChange()
|
||||||
}
|
}
|
||||||
private fun fireOnChange() {
|
private fun fireOnChange() {
|
||||||
|
if (onTrackChangeListener == null) return
|
||||||
val fileName = currentlyPlaying()
|
val fileName = currentlyPlaying()
|
||||||
if (fileName.isEmpty()) {
|
if (fileName.isEmpty()) {
|
||||||
onTrackChangeListener?.invoke(fileName)
|
fireOnChange(fileName)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val fileNameParts = fileName.split('/')
|
val fileNameParts = fileName.split('/')
|
||||||
@ -108,7 +109,16 @@ class MusicController {
|
|||||||
var trackName = fileNameParts[if (fileNameParts.size > 3 && fileNameParts[2] == "music") 3 else 1]
|
var trackName = fileNameParts[if (fileNameParts.size > 3 && fileNameParts[2] == "music") 3 else 1]
|
||||||
for (extension in fileExtensions)
|
for (extension in fileExtensions)
|
||||||
trackName = trackName.removeSuffix(".$extension")
|
trackName = trackName.removeSuffix(".$extension")
|
||||||
onTrackChangeListener?.invoke(modName + (if (modName.isEmpty()) "" else ": ") + trackName)
|
fireOnChange(modName + (if (modName.isEmpty()) "" else ": ") + trackName)
|
||||||
|
}
|
||||||
|
private fun fireOnChange(trackLabel: String) {
|
||||||
|
try {
|
||||||
|
onTrackChangeListener?.invoke(trackLabel)
|
||||||
|
} catch (ex: Throwable) {
|
||||||
|
if (consoleLog)
|
||||||
|
println("onTrackChange event invoke failed: ${ex.message}")
|
||||||
|
onTrackChangeListener = null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -143,10 +153,13 @@ class MusicController {
|
|||||||
// Next track - if top slot empty and a next exists, move it to top and start
|
// Next track - if top slot empty and a next exists, move it to top and start
|
||||||
current = next
|
current = next
|
||||||
next = null
|
next = null
|
||||||
if (!current!!.play())
|
if (!current!!.play()) {
|
||||||
state = ControllerState.Shutdown
|
// Retry another track if playback start fails, after an extended pause
|
||||||
else
|
ticksOfSilence = -silenceLengthInTicks - 1000
|
||||||
|
state = ControllerState.Silence
|
||||||
|
} else {
|
||||||
fireOnChange()
|
fireOnChange()
|
||||||
|
}
|
||||||
} // else wait for the thread of next.load() to finish
|
} // else wait for the thread of next.load() to finish
|
||||||
} else if (!current!!.isPlaying()) {
|
} else if (!current!!.isPlaying()) {
|
||||||
// normal end of track
|
// normal end of track
|
||||||
@ -201,14 +214,17 @@ class MusicController {
|
|||||||
(!flags.contains(MusicTrackChooserFlags.PrefixMustMatch) || it.nameWithoutExtension().startsWith(prefix))
|
(!flags.contains(MusicTrackChooserFlags.PrefixMustMatch) || it.nameWithoutExtension().startsWith(prefix))
|
||||||
&& (!flags.contains(MusicTrackChooserFlags.SuffixMustMatch) || it.nameWithoutExtension().endsWith(suffix))
|
&& (!flags.contains(MusicTrackChooserFlags.SuffixMustMatch) || it.nameWithoutExtension().endsWith(suffix))
|
||||||
}
|
}
|
||||||
// sort them by prefix match / suffix match / not last played / random
|
// randomize
|
||||||
|
.shuffled()
|
||||||
|
// sort them by prefix match / suffix match / not last played
|
||||||
.sortedWith(compareBy(
|
.sortedWith(compareBy(
|
||||||
{ if (it.nameWithoutExtension().startsWith(prefix)) 0 else 1 }
|
{ if (it.nameWithoutExtension().startsWith(prefix)) 0 else 1 }
|
||||||
, { if (it.nameWithoutExtension().endsWith(suffix)) 0 else 1 }
|
, { if (it.nameWithoutExtension().endsWith(suffix)) 0 else 1 }
|
||||||
, { if (it.path() in musicHistory) 1 else 0 }
|
, { if (it.path() in musicHistory) 1 else 0 }
|
||||||
, { Random().nextInt() }))
|
|
||||||
// Then just pick the first one. Not as wasteful as it looks - need to check all names anyway
|
// Then just pick the first one. Not as wasteful as it looks - need to check all names anyway
|
||||||
.firstOrNull()
|
)).firstOrNull()
|
||||||
|
// Note: shuffled().sortedWith(), ***not*** .sortedWith(.., Random)
|
||||||
|
// the latter worked with older JVM's, current ones *crash* you when a compare is not transitive.
|
||||||
}
|
}
|
||||||
|
|
||||||
//endregion
|
//endregion
|
||||||
@ -216,9 +232,10 @@ class MusicController {
|
|||||||
|
|
||||||
/** This tells the music controller about active mods - all are allowed to provide tracks */
|
/** This tells the music controller about active mods - all are allowed to provide tracks */
|
||||||
fun setModList ( newMods: HashSet<String> ) {
|
fun setModList ( newMods: HashSet<String> ) {
|
||||||
//todo: Ensure this gets updated where appropriate.
|
// This is hooked in most places where ImageGetter.setNewRuleset is called.
|
||||||
// loadGame; newGame: Choose Map with Mods?; map editor...
|
// Changes in permanent audiovisual mods are effective without this notification.
|
||||||
// check against "ImageGetter.ruleset=" ?
|
// Only the map editor isn't hooked, so if we wish to play mod-nation-specific tunes in the
|
||||||
|
// editor when e.g. a starting location is picked, that will have to be added.
|
||||||
mods = newMods
|
mods = newMods
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,14 +244,15 @@ class MusicController {
|
|||||||
* Called without parameters it will choose a new ambient music track and start playing it with fade-in/out.
|
* Called without parameters it will choose a new ambient music track and start playing it with fade-in/out.
|
||||||
* Will do nothing when no music files exist or the master volume is zero.
|
* Will do nothing when no music files exist or the master volume is zero.
|
||||||
*
|
*
|
||||||
* @param prefix file name prefix, meant to represent **Context** - in most cases a Civ name or default "Ambient"
|
* @param prefix file name prefix, meant to represent **Context** - in most cases a Civ name
|
||||||
* @param suffix file name suffix, meant to represent **Mood** - e.g. Peace, War, Theme...
|
* @param suffix file name suffix, meant to represent **Mood** - e.g. Peace, War, Theme, Defeat, Ambient
|
||||||
|
* (Ambient is the default when a track ends and exists so War Peace and the others are not chosen in that case)
|
||||||
* @param flags a set of optional flags to tune the choice and playback.
|
* @param flags a set of optional flags to tune the choice and playback.
|
||||||
* @return `true` = success, `false` = no match, no playback change
|
* @return `true` = success, `false` = no match, no playback change
|
||||||
*/
|
*/
|
||||||
fun chooseTrack (
|
fun chooseTrack (
|
||||||
prefix: String = "",
|
prefix: String = "",
|
||||||
suffix: String = "",
|
suffix: String = "Ambient",
|
||||||
flags: EnumSet<MusicTrackChooserFlags> = EnumSet.noneOf(MusicTrackChooserFlags::class.java)
|
flags: EnumSet<MusicTrackChooserFlags> = EnumSet.noneOf(MusicTrackChooserFlags::class.java)
|
||||||
): Boolean {
|
): Boolean {
|
||||||
if (baseVolume == 0f) return false
|
if (baseVolume == 0f) return false
|
||||||
@ -289,6 +307,17 @@ class MusicController {
|
|||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
/** Variant of [chooseTrack] that tries several moods ([suffixes]) until a match is chosen */
|
||||||
|
fun chooseTrack (
|
||||||
|
prefix: String = "",
|
||||||
|
suffixes: List<String>,
|
||||||
|
flags: EnumSet<MusicTrackChooserFlags> = EnumSet.noneOf(MusicTrackChooserFlags::class.java)
|
||||||
|
): Boolean {
|
||||||
|
for (suffix in suffixes) {
|
||||||
|
if (chooseTrack(prefix, suffix, flags)) return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pause playback with fade-out
|
* Pause playback with fade-out
|
||||||
@ -346,7 +375,7 @@ class MusicController {
|
|||||||
private fun shutdown() {
|
private fun shutdown() {
|
||||||
state = ControllerState.Idle
|
state = ControllerState.Idle
|
||||||
fireOnChange()
|
fireOnChange()
|
||||||
onTrackChangeListener = null
|
// keep onTrackChangeListener! OptionsPopup will want to know when we start up again
|
||||||
if (musicTimer != null) {
|
if (musicTimer != null) {
|
||||||
musicTimer!!.cancel()
|
musicTimer!!.cancel()
|
||||||
musicTimer = null
|
musicTimer = null
|
||||||
|
12
core/src/com/unciv/ui/audio/MusicMood.kt
Normal file
12
core/src/com/unciv/ui/audio/MusicMood.kt
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package com.unciv.ui.audio
|
||||||
|
|
||||||
|
object MusicMood {
|
||||||
|
const val Theme = "Theme"
|
||||||
|
const val Peace = "Peace"
|
||||||
|
const val War = "War"
|
||||||
|
const val Defeat = "Defeat"
|
||||||
|
const val Menu = "Menu"
|
||||||
|
|
||||||
|
val themeOrPeace = listOf(Theme, Peace)
|
||||||
|
fun peaceOrWar(isAtWar: Boolean) = if (isAtWar) War else Peace
|
||||||
|
}
|
@ -1,5 +1,7 @@
|
|||||||
package com.unciv.ui.audio
|
package com.unciv.ui.audio
|
||||||
|
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
enum class MusicTrackChooserFlags {
|
enum class MusicTrackChooserFlags {
|
||||||
/** Makes prefix parameter a mandatory match */
|
/** Makes prefix parameter a mandatory match */
|
||||||
PrefixMustMatch,
|
PrefixMustMatch,
|
||||||
@ -11,4 +13,17 @@ enum class MusicTrackChooserFlags {
|
|||||||
PlaySingle,
|
PlaySingle,
|
||||||
/** directly choose the 'fallback' file for playback */
|
/** directly choose the 'fallback' file for playback */
|
||||||
PlayDefaultFile,
|
PlayDefaultFile,
|
||||||
|
;
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
// EnumSet factories
|
||||||
|
/** EnumSet.of([PlayDefaultFile], [PlaySingle]) */
|
||||||
|
val setPlayDefault: EnumSet<MusicTrackChooserFlags> = EnumSet.of(PlayDefaultFile, PlaySingle)
|
||||||
|
/** EnumSet.of([PrefixMustMatch], [PlaySingle]) */
|
||||||
|
val setSelectNation: EnumSet<MusicTrackChooserFlags> = EnumSet.of(PrefixMustMatch)
|
||||||
|
/** EnumSet.of([PrefixMustMatch], [SuffixMustMatch]) */
|
||||||
|
val setSpecific: EnumSet<MusicTrackChooserFlags> = EnumSet.of(PrefixMustMatch, SuffixMustMatch)
|
||||||
|
/** EnumSet.of([PrefixMustMatch], [SlowFade]) */
|
||||||
|
val setNextTurn: EnumSet<MusicTrackChooserFlags> = EnumSet.of(PrefixMustMatch, SlowFade)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -148,16 +148,24 @@ class MusicTrackController(private var volume: Float) {
|
|||||||
if (!state.canPlay || music == null) {
|
if (!state.canPlay || music == null) {
|
||||||
throw IllegalStateException("MusicTrackController.play called on uninitialized instance")
|
throw IllegalStateException("MusicTrackController.play called on uninitialized instance")
|
||||||
}
|
}
|
||||||
|
// Unexplained observed exception: Gdx.Music.play fails with
|
||||||
|
// "Unable to allocate audio buffers. AL Error: 40964" (AL_INVALID_OPERATION)
|
||||||
|
// Approach: This track dies, parent controller will enter state Silence thus retry after a while.
|
||||||
|
if (tryPlay(music!!)) return true
|
||||||
|
state = State.Error
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun tryPlay(music: Music): Boolean {
|
||||||
return try {
|
return try {
|
||||||
music!!.volume = volume
|
music.volume = volume
|
||||||
if (!music!!.isPlaying) // for fade-over this could be called by the end of the previous track
|
if (!music.isPlaying) // for fade-over this could be called by the end of the previous track
|
||||||
music!!.play()
|
music.play()
|
||||||
true
|
true
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
println("Exception playing music: ${ex.message}")
|
println("Exception playing music: ${ex.message}")
|
||||||
if (MusicController.consoleLog)
|
if (MusicController.consoleLog)
|
||||||
ex.printStackTrace()
|
ex.printStackTrace()
|
||||||
state = State.Error
|
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,8 @@ import com.unciv.models.metadata.BaseRuleset
|
|||||||
import com.unciv.models.metadata.GameSpeed
|
import com.unciv.models.metadata.GameSpeed
|
||||||
import com.unciv.models.ruleset.RulesetCache
|
import com.unciv.models.ruleset.RulesetCache
|
||||||
import com.unciv.models.ruleset.VictoryType
|
import com.unciv.models.ruleset.VictoryType
|
||||||
|
import com.unciv.ui.audio.MusicMood
|
||||||
|
import com.unciv.ui.audio.MusicTrackChooserFlags
|
||||||
import com.unciv.ui.utils.*
|
import com.unciv.ui.utils.*
|
||||||
|
|
||||||
class GameOptionsTable(
|
class GameOptionsTable(
|
||||||
@ -187,9 +189,11 @@ class GameOptionsTable(
|
|||||||
var desiredCiv = ""
|
var desiredCiv = ""
|
||||||
if (gameParameters.mods.contains(it)) {
|
if (gameParameters.mods.contains(it)) {
|
||||||
val modNations = RulesetCache[it]?.nations
|
val modNations = RulesetCache[it]?.nations
|
||||||
if (modNations != null && modNations.size > 0) {
|
if (modNations != null && modNations.size > 0) desiredCiv = modNations.keys.first()
|
||||||
desiredCiv = modNations.keys.first()
|
|
||||||
}
|
val music = UncivGame.Current.musicController
|
||||||
|
if (!music.chooseTrack(it, MusicMood.Theme, MusicTrackChooserFlags.setSelectNation) && desiredCiv.isNotEmpty())
|
||||||
|
music.chooseTrack(desiredCiv, MusicMood.themeOrPeace, MusicTrackChooserFlags.setSelectNation)
|
||||||
}
|
}
|
||||||
|
|
||||||
updatePlayerPickerTable(desiredCiv)
|
updatePlayerPickerTable(desiredCiv)
|
||||||
|
@ -18,6 +18,8 @@ import com.unciv.models.metadata.Player
|
|||||||
import com.unciv.models.ruleset.Nation
|
import com.unciv.models.ruleset.Nation
|
||||||
import com.unciv.models.ruleset.Ruleset
|
import com.unciv.models.ruleset.Ruleset
|
||||||
import com.unciv.models.translations.tr
|
import com.unciv.models.translations.tr
|
||||||
|
import com.unciv.ui.audio.MusicMood
|
||||||
|
import com.unciv.ui.audio.MusicTrackChooserFlags
|
||||||
import com.unciv.ui.mapeditor.GameParametersScreen
|
import com.unciv.ui.mapeditor.GameParametersScreen
|
||||||
import com.unciv.ui.pickerscreens.PickerScreen
|
import com.unciv.ui.pickerscreens.PickerScreen
|
||||||
import com.unciv.ui.utils.*
|
import com.unciv.ui.utils.*
|
||||||
@ -347,6 +349,9 @@ private class NationPickerPopup(
|
|||||||
|
|
||||||
private fun returnSelected() {
|
private fun returnSelected() {
|
||||||
if (selectedNation == null) return
|
if (selectedNation == null) return
|
||||||
|
|
||||||
|
UncivGame.Current.musicController.chooseTrack(selectedNation!!.name, MusicMood.themeOrPeace, MusicTrackChooserFlags.setSelectNation)
|
||||||
|
|
||||||
if (previousScreen is GameParametersScreen)
|
if (previousScreen is GameParametersScreen)
|
||||||
previousScreen.mapEditorScreen.tileMap.switchPlayersNation(
|
previousScreen.mapEditorScreen.tileMap.switchPlayersNation(
|
||||||
player,
|
player,
|
||||||
|
@ -21,15 +21,18 @@ import com.unciv.models.ruleset.tile.ResourceType
|
|||||||
import com.unciv.models.stats.Stat
|
import com.unciv.models.stats.Stat
|
||||||
import com.unciv.models.translations.fillPlaceholders
|
import com.unciv.models.translations.fillPlaceholders
|
||||||
import com.unciv.models.translations.tr
|
import com.unciv.models.translations.tr
|
||||||
|
import com.unciv.ui.audio.MusicMood
|
||||||
|
import com.unciv.ui.audio.MusicTrackChooserFlags
|
||||||
import com.unciv.ui.civilopedia.CivilopediaScreen
|
import com.unciv.ui.civilopedia.CivilopediaScreen
|
||||||
import com.unciv.ui.tilegroups.CityButton
|
import com.unciv.ui.tilegroups.CityButton
|
||||||
import com.unciv.ui.utils.*
|
import com.unciv.ui.utils.*
|
||||||
import com.unciv.ui.utils.UncivTooltip.Companion.addTooltip
|
import com.unciv.ui.utils.UncivTooltip.Companion.addTooltip
|
||||||
|
import kotlin.collections.ArrayList
|
||||||
import kotlin.math.floor
|
import kotlin.math.floor
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
import com.unciv.ui.utils.AutoScrollPane as ScrollPane
|
import com.unciv.ui.utils.AutoScrollPane as ScrollPane
|
||||||
|
|
||||||
class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() {
|
class DiplomacyScreen(val viewingCiv:CivilizationInfo): CameraStageBaseScreen() {
|
||||||
|
|
||||||
private val leftSideTable = Table().apply { defaults().pad(10f) }
|
private val leftSideTable = Table().apply { defaults().pad(10f) }
|
||||||
private val rightSideTable = Table()
|
private val rightSideTable = Table()
|
||||||
@ -694,6 +697,9 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() {
|
|||||||
if (promisesTable != null) diplomacyTable.add(promisesTable).row()
|
if (promisesTable != null) diplomacyTable.add(promisesTable).row()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UncivGame.Current.musicController.chooseTrack(otherCiv.civName,
|
||||||
|
MusicMood.peaceOrWar(viewingCiv.isAtWarWith(otherCiv)), MusicTrackChooserFlags.setSelectNation)
|
||||||
|
|
||||||
return diplomacyTable
|
return diplomacyTable
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -831,6 +837,7 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() {
|
|||||||
diplomacyManager.declareWar()
|
diplomacyManager.declareWar()
|
||||||
setRightSideFlavorText(otherCiv, otherCiv.nation.attacked, "Very well.")
|
setRightSideFlavorText(otherCiv, otherCiv.nation.attacked, "Very well.")
|
||||||
updateLeftSideTable()
|
updateLeftSideTable()
|
||||||
|
UncivGame.Current.musicController.chooseTrack(otherCiv.civName, MusicMood.War, MusicTrackChooserFlags.setSpecific)
|
||||||
}, this).open()
|
}, this).open()
|
||||||
}
|
}
|
||||||
return declareWarButton
|
return declareWarButton
|
||||||
|
@ -4,12 +4,16 @@ import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane
|
|||||||
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
||||||
import com.badlogic.gdx.scenes.scene2d.ui.TextButton
|
import com.badlogic.gdx.scenes.scene2d.ui.TextButton
|
||||||
import com.unciv.Constants
|
import com.unciv.Constants
|
||||||
|
import com.unciv.UncivGame
|
||||||
import com.unciv.logic.civilization.*
|
import com.unciv.logic.civilization.*
|
||||||
import com.unciv.logic.civilization.diplomacy.RelationshipLevel
|
import com.unciv.logic.civilization.diplomacy.RelationshipLevel
|
||||||
import com.unciv.models.translations.fillPlaceholders
|
import com.unciv.models.translations.fillPlaceholders
|
||||||
import com.unciv.models.translations.tr
|
import com.unciv.models.translations.tr
|
||||||
|
import com.unciv.ui.audio.MusicMood
|
||||||
|
import com.unciv.ui.audio.MusicTrackChooserFlags
|
||||||
import com.unciv.ui.trade.LeaderIntroTable
|
import com.unciv.ui.trade.LeaderIntroTable
|
||||||
import com.unciv.ui.utils.*
|
import com.unciv.ui.utils.*
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [Popup] communicating events other than trade offers to the player.
|
* [Popup] communicating events other than trade offers to the player.
|
||||||
@ -47,6 +51,7 @@ class AlertPopup(val worldScreen: WorldScreen, val popupAlert: PopupAlert): Popu
|
|||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
val music = UncivGame.Current.musicController
|
||||||
|
|
||||||
when (popupAlert.type) {
|
when (popupAlert.type) {
|
||||||
AlertType.WarDeclaration -> {
|
AlertType.WarDeclaration -> {
|
||||||
@ -58,12 +63,14 @@ class AlertPopup(val worldScreen: WorldScreen, val popupAlert: PopupAlert): Popu
|
|||||||
responseTable.add(getCloseButton("You'll pay for this!"))
|
responseTable.add(getCloseButton("You'll pay for this!"))
|
||||||
responseTable.add(getCloseButton("Very well."))
|
responseTable.add(getCloseButton("Very well."))
|
||||||
add(responseTable)
|
add(responseTable)
|
||||||
|
music.chooseTrack(civInfo.civName, MusicMood.War, MusicTrackChooserFlags.setSpecific)
|
||||||
}
|
}
|
||||||
AlertType.Defeated -> {
|
AlertType.Defeated -> {
|
||||||
val civInfo = worldScreen.gameInfo.getCivilization(popupAlert.value)
|
val civInfo = worldScreen.gameInfo.getCivilization(popupAlert.value)
|
||||||
addLeaderName(civInfo)
|
addLeaderName(civInfo)
|
||||||
addGoodSizedLabel(civInfo.nation.defeated).row()
|
addGoodSizedLabel(civInfo.nation.defeated).row()
|
||||||
add(getCloseButton("Farewell."))
|
add(getCloseButton("Farewell."))
|
||||||
|
music.chooseTrack(civInfo.civName, MusicMood.Defeat, EnumSet.of(MusicTrackChooserFlags.SuffixMustMatch))
|
||||||
}
|
}
|
||||||
AlertType.FirstContact -> {
|
AlertType.FirstContact -> {
|
||||||
val civInfo = worldScreen.gameInfo.getCivilization(popupAlert.value)
|
val civInfo = worldScreen.gameInfo.getCivilization(popupAlert.value)
|
||||||
@ -75,6 +82,7 @@ class AlertPopup(val worldScreen: WorldScreen, val popupAlert: PopupAlert): Popu
|
|||||||
} else {
|
} else {
|
||||||
addGoodSizedLabel(nation.introduction).row()
|
addGoodSizedLabel(nation.introduction).row()
|
||||||
add(getCloseButton("A pleasure to meet you."))
|
add(getCloseButton("A pleasure to meet you."))
|
||||||
|
music.chooseTrack(civInfo.civName, MusicMood.themeOrPeace, MusicTrackChooserFlags.setSpecific)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AlertType.CityConquered -> {
|
AlertType.CityConquered -> {
|
||||||
|
@ -3,6 +3,7 @@ package com.unciv.ui.worldscreen
|
|||||||
import com.badlogic.gdx.graphics.Color
|
import com.badlogic.gdx.graphics.Color
|
||||||
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
||||||
import com.unciv.Constants
|
import com.unciv.Constants
|
||||||
|
import com.unciv.UncivGame
|
||||||
import com.unciv.logic.civilization.NotificationIcon
|
import com.unciv.logic.civilization.NotificationIcon
|
||||||
import com.unciv.logic.civilization.diplomacy.DiplomacyFlags
|
import com.unciv.logic.civilization.diplomacy.DiplomacyFlags
|
||||||
import com.unciv.logic.trade.TradeEvaluation
|
import com.unciv.logic.trade.TradeEvaluation
|
||||||
@ -10,6 +11,8 @@ import com.unciv.logic.trade.TradeLogic
|
|||||||
import com.unciv.logic.trade.TradeOffer
|
import com.unciv.logic.trade.TradeOffer
|
||||||
import com.unciv.logic.trade.TradeType
|
import com.unciv.logic.trade.TradeType
|
||||||
import com.unciv.models.translations.tr
|
import com.unciv.models.translations.tr
|
||||||
|
import com.unciv.ui.audio.MusicMood
|
||||||
|
import com.unciv.ui.audio.MusicTrackChooserFlags
|
||||||
import com.unciv.ui.trade.DiplomacyScreen
|
import com.unciv.ui.trade.DiplomacyScreen
|
||||||
import com.unciv.ui.trade.LeaderIntroTable
|
import com.unciv.ui.trade.LeaderIntroTable
|
||||||
import com.unciv.ui.utils.*
|
import com.unciv.ui.utils.*
|
||||||
@ -34,22 +37,27 @@ class TradePopup(worldScreen: WorldScreen): Popup(worldScreen){
|
|||||||
val viewingCiv = worldScreen.viewingCiv
|
val viewingCiv = worldScreen.viewingCiv
|
||||||
val tradeRequest = viewingCiv.tradeRequests.first()
|
val tradeRequest = viewingCiv.tradeRequests.first()
|
||||||
|
|
||||||
init{
|
init {
|
||||||
val requestingCiv = worldScreen.gameInfo.getCivilization(tradeRequest.requestingCiv)
|
val requestingCiv = worldScreen.gameInfo.getCivilization(tradeRequest.requestingCiv)
|
||||||
val nation = requestingCiv.nation
|
val nation = requestingCiv.nation
|
||||||
|
val trade = tradeRequest.trade
|
||||||
|
val isPeaceTreaty = trade.ourOffers.any { it.type == TradeType.Treaty && it.name == Constants.peaceTreaty }
|
||||||
|
val ourResources = viewingCiv.getCivResourcesByName()
|
||||||
|
val music = UncivGame.Current.musicController
|
||||||
|
|
||||||
|
if (isPeaceTreaty)
|
||||||
|
music.chooseTrack(nation.name, MusicMood.Peace, MusicTrackChooserFlags.setSpecific)
|
||||||
|
|
||||||
val leaderIntroTable = LeaderIntroTable(requestingCiv)
|
val leaderIntroTable = LeaderIntroTable(requestingCiv)
|
||||||
add(leaderIntroTable)
|
add(leaderIntroTable)
|
||||||
addSeparator()
|
addSeparator()
|
||||||
|
|
||||||
val trade = tradeRequest.trade
|
|
||||||
val tradeOffersTable = Table().apply { defaults().pad(10f) }
|
val tradeOffersTable = Table().apply { defaults().pad(10f) }
|
||||||
tradeOffersTable.add("[${nation.name}]'s trade offer".toLabel())
|
tradeOffersTable.add("[${nation.name}]'s trade offer".toLabel())
|
||||||
// empty column to separate offers columns better
|
// empty column to separate offers columns better
|
||||||
tradeOffersTable.add().pad(0f, 15f)
|
tradeOffersTable.add().pad(0f, 15f)
|
||||||
tradeOffersTable.add("Our trade offer".toLabel())
|
tradeOffersTable.add("Our trade offer".toLabel())
|
||||||
tradeOffersTable.row()
|
tradeOffersTable.row()
|
||||||
val ourResources = viewingCiv.getCivResourcesByName()
|
|
||||||
|
|
||||||
fun getOfferText(offer:TradeOffer): String {
|
fun getOfferText(offer:TradeOffer): String {
|
||||||
var tradeText = offer.getOfferText()
|
var tradeText = offer.getOfferText()
|
||||||
@ -90,12 +98,14 @@ class TradePopup(worldScreen: WorldScreen): Popup(worldScreen){
|
|||||||
|
|
||||||
addButton("Not this time.", 'n') {
|
addButton("Not this time.", 'n') {
|
||||||
val diplomacyManager = requestingCiv.getDiplomacyManager(viewingCiv)
|
val diplomacyManager = requestingCiv.getDiplomacyManager(viewingCiv)
|
||||||
if(trade.ourOffers.all { it.type == TradeType.Luxury_Resource } && trade.theirOffers.all { it.type==TradeType.Luxury_Resource })
|
if (trade.ourOffers.all { it.type == TradeType.Luxury_Resource } && trade.theirOffers.all { it.type==TradeType.Luxury_Resource })
|
||||||
diplomacyManager.setFlag(DiplomacyFlags.DeclinedLuxExchange,20) // offer again in 20 turns
|
diplomacyManager.setFlag(DiplomacyFlags.DeclinedLuxExchange,20) // offer again in 20 turns
|
||||||
if(trade.ourOffers.any { it.name == Constants.researchAgreement })
|
if (trade.ourOffers.any { it.name == Constants.researchAgreement })
|
||||||
diplomacyManager.setFlag(DiplomacyFlags.DeclinedResearchAgreement,20) // offer again in 20 turns
|
diplomacyManager.setFlag(DiplomacyFlags.DeclinedResearchAgreement,20) // offer again in 20 turns
|
||||||
if(trade.ourOffers.any { it.type == TradeType.Treaty && it.name == Constants.peaceTreaty })
|
if (isPeaceTreaty) {
|
||||||
diplomacyManager.setFlag(DiplomacyFlags.DeclinedPeace,5)
|
diplomacyManager.setFlag(DiplomacyFlags.DeclinedPeace, 5)
|
||||||
|
music.chooseTrack(nation.name, MusicMood.War, MusicTrackChooserFlags.setSpecific)
|
||||||
|
}
|
||||||
|
|
||||||
close()
|
close()
|
||||||
requestingCiv.addNotification("[${viewingCiv.civName}] has denied your trade request", viewingCiv.civName, NotificationIcon.Trade)
|
requestingCiv.addNotification("[${viewingCiv.civName}] has denied your trade request", viewingCiv.civName, NotificationIcon.Trade)
|
||||||
@ -126,7 +136,7 @@ class TradePopup(worldScreen: WorldScreen): Popup(worldScreen){
|
|||||||
addSeparator().padBottom(15f)
|
addSeparator().padBottom(15f)
|
||||||
addGoodSizedLabel("Excellent!").row()
|
addGoodSizedLabel("Excellent!").row()
|
||||||
addCloseButton("Farewell.", KeyCharAndCode.SPACE) {
|
addCloseButton("Farewell.", KeyCharAndCode.SPACE) {
|
||||||
worldScreen.shouldUpdate=true
|
worldScreen.shouldUpdate = true
|
||||||
// in all cases, worldScreen.shouldUpdate should be set to true when we remove the last of the popups
|
// in all cases, worldScreen.shouldUpdate should be set to true when we remove the last of the popups
|
||||||
// in order for the next trade to appear immediately
|
// in order for the next trade to appear immediately
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,6 @@ import com.unciv.UncivGame
|
|||||||
import com.unciv.logic.MapSaver
|
import com.unciv.logic.MapSaver
|
||||||
import com.unciv.logic.civilization.PlayerType
|
import com.unciv.logic.civilization.PlayerType
|
||||||
import com.unciv.models.UncivSound
|
import com.unciv.models.UncivSound
|
||||||
import com.unciv.models.metadata.BaseRuleset
|
|
||||||
import com.unciv.models.ruleset.Ruleset
|
import com.unciv.models.ruleset.Ruleset
|
||||||
import com.unciv.models.ruleset.RulesetCache
|
import com.unciv.models.ruleset.RulesetCache
|
||||||
import com.unciv.models.tilesets.TileSetCache
|
import com.unciv.models.tilesets.TileSetCache
|
||||||
@ -420,7 +419,7 @@ class OptionsPopup(val previousScreen: CameraStageBaseScreen) : Popup(previousSc
|
|||||||
val music = previousScreen.game.musicController
|
val music = previousScreen.game.musicController
|
||||||
music.setVolume(it)
|
music.setVolume(it)
|
||||||
if (!music.isPlaying())
|
if (!music.isPlaying())
|
||||||
music.chooseTrack(flags = EnumSet.of(MusicTrackChooserFlags.PlayDefaultFile, MusicTrackChooserFlags.PlaySingle))
|
music.chooseTrack(flags = MusicTrackChooserFlags.setPlayDefault)
|
||||||
}
|
}
|
||||||
add(musicVolumeSlider).pad(5f).row()
|
add(musicVolumeSlider).pad(5f).row()
|
||||||
}
|
}
|
||||||
@ -467,6 +466,7 @@ class OptionsPopup(val previousScreen: CameraStageBaseScreen) : Popup(previousSc
|
|||||||
label.setText("Currently playing: [$it]".tr())
|
label.setText("Currently playing: [$it]".tr())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
label.onClick { previousScreen.game.musicController.chooseTrack(flags = MusicTrackChooserFlags.setNextTurn) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Table.addDownloadMusic() {
|
private fun Table.addDownloadMusic() {
|
||||||
@ -486,7 +486,7 @@ class OptionsPopup(val previousScreen: CameraStageBaseScreen) : Popup(previousSc
|
|||||||
previousScreen.game.musicController.downloadDefaultFile()
|
previousScreen.game.musicController.downloadDefaultFile()
|
||||||
Gdx.app.postRunnable {
|
Gdx.app.postRunnable {
|
||||||
tabs.replacePage("Sound", getSoundTab())
|
tabs.replacePage("Sound", getSoundTab())
|
||||||
previousScreen.game.musicController.chooseTrack(flags = EnumSet.of(MusicTrackChooserFlags.PlayDefaultFile, MusicTrackChooserFlags.PlaySingle))
|
previousScreen.game.musicController.chooseTrack(flags = MusicTrackChooserFlags.setPlayDefault)
|
||||||
}
|
}
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
Gdx.app.postRunnable {
|
Gdx.app.postRunnable {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user