From 640a5b17bf6f2a32f496c748e66fc5fe7b17940b Mon Sep 17 00:00:00 2001 From: Rob Loach Date: Sat, 30 Aug 2025 13:48:28 -0400 Subject: [PATCH] Add a Play Sound unique (#13867) --- .../jsons/Civ V - Gods & Kings/Ruins.json | 39 ++++++++++++++----- .../ruleset/unique/UniqueTriggerActivation.kt | 13 +++++++ .../unciv/models/ruleset/unique/UniqueType.kt | 4 +- docs/Modders/uniques.md | 9 +++++ 4 files changed, 55 insertions(+), 10 deletions(-) diff --git a/android/assets/jsons/Civ V - Gods & Kings/Ruins.json b/android/assets/jsons/Civ V - Gods & Kings/Ruins.json index 85c212161d..78b4e2ec6e 100644 --- a/android/assets/jsons/Civ V - Gods & Kings/Ruins.json +++ b/android/assets/jsons/Civ V - Gods & Kings/Ruins.json @@ -2,7 +2,10 @@ { "name": "discover cultural artifacts", "notification": "We have discovered cultural artifacts in the ruins! (+20 culture)", - "uniques": ["Gain [20] [Culture] <(modified by game speed)>"], + "uniques": [ + "Gain [20] [Culture] <(modified by game speed)>", + "Play [policy] sound" + ], "color": "#cf8ff7" }, { @@ -14,24 +17,36 @@ { "name": "squatters wishing to settle under your rule", "notification": "A [Settler] has joined us!", - "uniques": ["Free [Settler] found in the ruins", "Unavailable "], + "uniques": [ + "Free [Settler] found in the ruins", "Unavailable ", + "Play [wagon] sound" + ], "excludedDifficulties": ["Warlord","Prince","King","Emperor","Immortal","Deity"] }, { "name": "your exploring unit receives training", "notification": "An ancient tribe trained us in their ways of combat!", - "uniques": ["[This Unit] gains [10] XP", "Only available "] + "uniques": [ + "[This Unit] gains [10] XP", "Only available ", + "Play [promote] sound" + ] }, { "name": "survivors (adds population to a city)", "notification": "We have found survivors in the ruins! Population added to [cityName].", - "uniques": ["[+1] population in a random city"], // This can't be easily added to cityFilter, as it is non-deterministic - "color": "#81c784" + "uniques": [ + "[+1] population in a random city", // This can't be easily added to cityFilter, as it is non-deterministic + "Play [wagon] sound" + ], + "color": "#81c784" }, { "name": "a stash of gold", "notification": "", // trigger notification only - "uniques": ["Gain [50]-[100] [Gold] <(modified by game speed)>"], + "uniques": [ + "Gain [50]-[100] [Gold] <(modified by game speed)>", + "Play [coin] sound" + ], "color": "#ffeb7f" }, { @@ -58,14 +73,20 @@ { "name": "discover holy symbols", "notification": "We have found holy symbols in the ruins, giving us a deeper understanding of religion! (+[faithAmount] Faith)", - "uniques": ["Only available ", "Gain enough Faith for a Pantheon", "Only available ", "Only available "], + "uniques": [ + "Only available ", "Gain enough Faith for a Pantheon", "Only available ", "Only available ", + "Play [choir] sound" + ], "color": "#CDDDF4" }, { "name": "an ancient prophecy", "notification": "We have found an ancient prophecy in the ruins, greatly increasing our spiritual connection! (+[faithAmount] Faith)", - "uniques": ["Only available ", "Gain enough Faith for [33]% of a Great Prophet", "Unavailable ", - "Only available ", "Only available "], + "uniques": [ + "Only available ", "Gain enough Faith for [33]% of a Great Prophet", "Unavailable ", + "Only available ", "Only available ", + "Play [choir] sound" + ], "color": "#CDDDF4" } ] diff --git a/core/src/com/unciv/models/ruleset/unique/UniqueTriggerActivation.kt b/core/src/com/unciv/models/ruleset/unique/UniqueTriggerActivation.kt index 55beac4381..6b894ade8a 100644 --- a/core/src/com/unciv/models/ruleset/unique/UniqueTriggerActivation.kt +++ b/core/src/com/unciv/models/ruleset/unique/UniqueTriggerActivation.kt @@ -31,10 +31,12 @@ import com.unciv.models.ruleset.tile.TerrainType import com.unciv.models.ruleset.tile.TileResource import com.unciv.models.stats.Stat import com.unciv.models.stats.Stats +import com.unciv.models.UncivSound import com.unciv.models.translations.fillPlaceholders import com.unciv.models.translations.hasPlaceholderParameters import com.unciv.models.translations.tr import com.unciv.ui.screens.worldscreen.unit.actions.UnitActionsUpgrade +import com.unciv.ui.audio.SoundPlayer import com.unciv.utils.addToMapOfSets import com.unciv.utils.randomWeighted import kotlin.math.roundToInt @@ -143,6 +145,17 @@ object UniqueTriggerActivation { true } + UniqueType.PlaySound -> { + val soundName = unique.params[0] + if (soundName.isEmpty()) return null + var sound = UncivSound(soundName) + SoundPlayer.get(sound) ?: return null + return { + SoundPlayer.play(sound) + true + } + } + UniqueType.OneTimeFreeUnit -> { val unitName = unique.params[0] val baseUnit = ruleset.units[unitName] ?: return null diff --git a/core/src/com/unciv/models/ruleset/unique/UniqueType.kt b/core/src/com/unciv/models/ruleset/unique/UniqueType.kt index b4e0704def..2e19b02fba 100644 --- a/core/src/com/unciv/models/ruleset/unique/UniqueType.kt +++ b/core/src/com/unciv/models/ruleset/unique/UniqueType.kt @@ -878,7 +878,9 @@ enum class UniqueType( FreeSpecificBuildings("Provides a [buildingName] in your first [positiveAmount] cities for free", UniqueTarget.Triggerable), // used in Policy TriggerEvent("Triggers a [event] event", UniqueTarget.Triggerable), MarkTutorialComplete("Mark tutorial [comment] complete", UniqueTarget.Triggerable, flags = UniqueFlag.setOfHiddenNoConditionals), - + PlaySound("Play [comment] sound", UniqueTarget.Triggerable, flags = UniqueFlag.setOfHiddenToUsers, + docDescription = "See [Images and Audio](Images-and-Audio.md#sounds) for a list of available sounds."), + //endregion ///////////////////////////////////////// region 09 UNIT TRIGGERABLES ///////////////////////////////////////// diff --git a/docs/Modders/uniques.md b/docs/Modders/uniques.md index 280517fb68..4100c52f5d 100644 --- a/docs/Modders/uniques.md +++ b/docs/Modders/uniques.md @@ -232,6 +232,15 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl Applicable to: Triggerable +??? example "Play [comment] sound" + See [Images and Audio](Images-and-Audio.md#sounds) for a list of available sounds. + + Example: "Play [comment] sound" + + This unique is automatically hidden from users. + + Applicable to: Triggerable + ??? example "Suppress warning [validationWarning]" Allows suppressing specific validation warnings. Errors, deprecation warnings, or warnings about untyped and non-filtering uniques should be heeded, not suppressed, and are therefore not accepted. Note that this can be used in ModOptions, in the uniques a warning is about, or as modifier on the unique triggering a warning - but you still need to be specific. Even in the modifier case you will need to specify a sufficiently selective portion of the warning text as parameter.