diff --git a/Credits.md b/Credits.md index c4eb248008..18abbe00e2 100644 --- a/Credits.md +++ b/Credits.md @@ -389,3 +389,10 @@ All the following are from [the Noun Project](https://thenounproject.com) licenc * [Replace](https://thenounproject.com/search/?q=replace&i=17858) By Mike Rowe, AU * [Resistance](https://thenounproject.com/term/revolution/1315305/) By By HeadsOfBirds, GB + +# Sound credits + +Sounds are from FreeSound.org + +* [Click 01_Minimal UI Sounds](https://freesound.org/people/cabled_mess/sounds/370962/) By cabled_mess for most clicks +* [SawInOut01](https://freesound.org/people/kingof_thelab/sounds/340243/) By kingof_thelab for construction picking? \ No newline at end of file diff --git a/android/assets/sounds/click.mp3 b/android/assets/sounds/click.mp3 new file mode 100644 index 0000000000..6938cea6c2 Binary files /dev/null and b/android/assets/sounds/click.mp3 differ diff --git a/core/src/com/unciv/GameSettings.kt b/core/src/com/unciv/GameSettings.kt index aeeb829960..4b998b8094 100644 --- a/core/src/com/unciv/GameSettings.kt +++ b/core/src/com/unciv/GameSettings.kt @@ -9,6 +9,7 @@ class GameSettings { var resolution: String = "1050x700" var tutorialsShown = ArrayList() var hasCrashedRecently = false + var soundEffectsVolume = 1.0f fun save(){ GameSaver().setGeneralSettings(this) diff --git a/core/src/com/unciv/ui/utils/CameraStageBaseScreen.kt b/core/src/com/unciv/ui/utils/CameraStageBaseScreen.kt index 00c43dc932..b790a567ad 100644 --- a/core/src/com/unciv/ui/utils/CameraStageBaseScreen.kt +++ b/core/src/com/unciv/ui/utils/CameraStageBaseScreen.kt @@ -122,9 +122,11 @@ fun Label.setFontSize(size:Int): Label { return this // for chaining } +// If there are other buttons that require special clicks then we'll have an onclick that will accept a string parameter, no worries fun Actor.onClick(function: () -> Unit) { this.addListener(object : ClickListener() { override fun clicked(event: InputEvent?, x: Float, y: Float) { + Sounds.play("click") function() } } ) diff --git a/core/src/com/unciv/ui/utils/ImageGetter.kt b/core/src/com/unciv/ui/utils/ImageGetter.kt index 89326f3c50..d6f6062a04 100644 --- a/core/src/com/unciv/ui/utils/ImageGetter.kt +++ b/core/src/com/unciv/ui/utils/ImageGetter.kt @@ -190,4 +190,5 @@ object ImageGetter { return line } -} \ No newline at end of file +} + diff --git a/core/src/com/unciv/ui/utils/Sounds.kt b/core/src/com/unciv/ui/utils/Sounds.kt new file mode 100644 index 0000000000..f512afd956 --- /dev/null +++ b/core/src/com/unciv/ui/utils/Sounds.kt @@ -0,0 +1,20 @@ +package com.unciv.ui.utils + +import com.badlogic.gdx.Gdx +import com.badlogic.gdx.audio.Sound +import com.unciv.UnCivGame + +object Sounds{ + val soundMap = HashMap() + + fun get(name:String):Sound{ + if(!soundMap.containsKey(name)) + soundMap[name] = Gdx.audio.newSound(Gdx.files.internal("sounds/$name.mp3")); + return soundMap[name]!! + } + + + fun play(name:String){ + get(name).play(UnCivGame.Current.settings.soundEffectsVolume) + } +} \ No newline at end of file diff --git a/core/src/com/unciv/ui/worldscreen/TileMapHolder.kt b/core/src/com/unciv/ui/worldscreen/TileMapHolder.kt index a22ff36b1a..f6781ba238 100644 --- a/core/src/com/unciv/ui/worldscreen/TileMapHolder.kt +++ b/core/src/com/unciv/ui/worldscreen/TileMapHolder.kt @@ -93,20 +93,20 @@ class TileMapHolder(internal val worldScreen: WorldScreen, internal val tileMap: }) } - private fun onTileClicked(tileInfo: TileInfo, tileGroup: WorldTileGroup){ - worldScreen.displayTutorials("TileClicked") - if (moveToOverlay != null) moveToOverlay!!.remove() - selectedTile = tileInfo + private fun onTileClicked(tileInfo: TileInfo, tileGroup: WorldTileGroup) { + worldScreen.displayTutorials("TileClicked") + if (moveToOverlay != null) moveToOverlay!!.remove() + selectedTile = tileInfo - val selectedUnit = worldScreen.bottomBar.unitTable.selectedUnit - if (selectedUnit != null && selectedUnit.getTile() != tileInfo - && selectedUnit.canMoveTo(tileInfo) && selectedUnit.movementAlgs().canReach(tileInfo)) { - // this can take a long time, because of the unit-to-tile calculation needed, so we put it in a different thread - queueAddMoveHereButton(selectedUnit, tileInfo) - } + val selectedUnit = worldScreen.bottomBar.unitTable.selectedUnit + if (selectedUnit != null && selectedUnit.getTile() != tileInfo + && selectedUnit.canMoveTo(tileInfo) && selectedUnit.movementAlgs().canReach(tileInfo)) { + // this can take a long time, because of the unit-to-tile calculation needed, so we put it in a different thread + queueAddMoveHereButton(selectedUnit, tileInfo) + } - worldScreen.bottomBar.unitTable.tileSelected(tileInfo) - worldScreen.shouldUpdate=true + worldScreen.bottomBar.unitTable.tileSelected(tileInfo) + worldScreen.shouldUpdate = true } private fun queueAddMoveHereButton(selectedUnit: MapUnit, tileInfo: TileInfo) { diff --git a/core/src/com/unciv/ui/worldscreen/optionstable/WorldScreenDisplayOptionsTable.kt b/core/src/com/unciv/ui/worldscreen/optionstable/WorldScreenDisplayOptionsTable.kt index b0a9f2bcac..015dcb8ccc 100644 --- a/core/src/com/unciv/ui/worldscreen/optionstable/WorldScreenDisplayOptionsTable.kt +++ b/core/src/com/unciv/ui/worldscreen/optionstable/WorldScreenDisplayOptionsTable.kt @@ -5,13 +5,17 @@ import com.badlogic.gdx.graphics.g2d.Batch import com.badlogic.gdx.scenes.scene2d.Actor import com.badlogic.gdx.scenes.scene2d.ui.Label import com.badlogic.gdx.scenes.scene2d.ui.SelectBox +import com.badlogic.gdx.scenes.scene2d.ui.Slider import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener +import com.badlogic.gdx.utils.Array import com.unciv.UnCivGame import com.unciv.models.gamebasics.GameBasics import com.unciv.ui.utils.CameraStageBaseScreen import com.unciv.ui.utils.Fonts +import com.unciv.ui.utils.Sounds import com.unciv.ui.utils.center import com.unciv.ui.worldscreen.WorldScreen +import kotlin.concurrent.thread class Language(val language:String){ val percentComplete:Int @@ -27,7 +31,7 @@ class Language(val language:String){ } class WorldScreenDisplayOptionsTable : PopupTable(){ - val languageSelectBox = SelectBox(CameraStageBaseScreen.skin) + val languageSelectBox = SelectBox(skin) init { update() @@ -48,55 +52,9 @@ class WorldScreenDisplayOptionsTable : PopupTable(){ else addButton("{Show} {resources and improvements}") { settings.showResourcesAndImprovements = true; update() } - val languageArray = com.badlogic.gdx.utils.Array() - GameBasics.Translations.getLanguages().map { Language(it) }.sortedByDescending { it.percentComplete } - .forEach { languageArray.add(it) } - languageSelectBox.items = languageArray - languageSelectBox.selected = languageArray.first { it.language== UnCivGame.Current.settings.language} - add(languageSelectBox).pad(10f).row() + addLanguageSelectBox() - languageSelectBox.addListener(object : ChangeListener() { - override fun changed(event: ChangeEvent?, actor: Actor?) { - val selectedLanguage = languageSelectBox.selected.language - if (Fonts().containsFont(Fonts().getFontForLanguage(selectedLanguage))) - selectLanguage() - else { - val spaceSplitLang = selectedLanguage.replace("_"," ") - YesNoPopupTable("This language requires you to download fonts.\n" + - "Do you want to download fonts for $spaceSplitLang?", - { - - val downloading = PopupTable() - downloading.add(Label("Downloading...", CameraStageBaseScreen.skin)) - downloading.pack() - downloading.center(stage) - stage.addActor(downloading) - Gdx.input.inputProcessor = null // no interaction until download is over - - kotlin.concurrent.thread { - Fonts().downloadFontForLanguage(selectedLanguage) - // The language selection must be done on the render thread, because it requires a GL context. - // This means that we have to tell the table to create it on render. - shouldSelectLanguage=true - } - - }) - } - } - }) - - if(languageSelectBox.selected.percentComplete!=100) { - add(Label("Missing translations:", CameraStageBaseScreen.skin)).pad(5f).row() - val missingTextSelectBox = SelectBox(CameraStageBaseScreen.skin) - val missingTextArray = com.badlogic.gdx.utils.Array() - val currentLanguage = UnCivGame.Current.settings.language - GameBasics.Translations.filter { !it.value.containsKey(currentLanguage) }.forEach { missingTextArray.add(it.key) } - missingTextSelectBox.items = missingTextArray - missingTextSelectBox.selected = "Untranslated texts" - add(missingTextSelectBox).pad(10f).width(UnCivGame.Current.worldScreen.stage.width / 2).row() - } - - val resolutionSelectBox= SelectBox(CameraStageBaseScreen.skin) + val resolutionSelectBox= SelectBox(skin) val resolutionArray = com.badlogic.gdx.utils.Array() resolutionArray.addAll("900x600","1050x700","1200x800","1500x1000") resolutionSelectBox.items = resolutionArray @@ -113,6 +71,18 @@ class WorldScreenDisplayOptionsTable : PopupTable(){ } }) + val soundEffectsVolumeSlider = Slider(0f,1.0f,0.1f,false,skin) + soundEffectsVolumeSlider.value = UnCivGame.Current.settings.soundEffectsVolume + soundEffectsVolumeSlider.addListener(object: ChangeListener(){ + override fun changed(event: ChangeEvent?, actor: Actor?) { + UnCivGame.Current.settings.soundEffectsVolume= soundEffectsVolumeSlider.value + UnCivGame.Current.settings.save() + Sounds.play("click") + } + }) + add("Sound effects volume").row() + add(soundEffectsVolumeSlider).row() + addButton("Close"){ remove() } pack() // Needed to show the background. @@ -120,6 +90,56 @@ class WorldScreenDisplayOptionsTable : PopupTable(){ UnCivGame.Current.worldScreen.shouldUpdate=true } + private fun addLanguageSelectBox() { + val languageArray = Array() + GameBasics.Translations.getLanguages().map { Language(it) }.sortedByDescending { it.percentComplete } + .forEach { languageArray.add(it) } + languageSelectBox.items = languageArray + languageSelectBox.selected = languageArray.first { it.language == UnCivGame.Current.settings.language } + add(languageSelectBox).pad(10f).row() + + languageSelectBox.addListener(object : ChangeListener() { + override fun changed(event: ChangeEvent?, actor: Actor?) { + val selectedLanguage = languageSelectBox.selected.language + if (Fonts().containsFont(Fonts().getFontForLanguage(selectedLanguage))) + selectLanguage() + else { + val spaceSplitLang = selectedLanguage.replace("_", " ") + YesNoPopupTable("This language requires you to download fonts.\n" + + "Do you want to download fonts for $spaceSplitLang?", + { + + val downloading = PopupTable() + downloading.add(Label("Downloading...", skin)) + downloading.pack() + downloading.center(stage) + stage.addActor(downloading) + Gdx.input.inputProcessor = null // no interaction until download is over + + thread { + Fonts().downloadFontForLanguage(selectedLanguage) + // The language selection must be done on the render thread, because it requires a GL context. + // This means that we have to tell the table to create it on render. + shouldSelectLanguage = true + } + + }) + } + } + }) + + if (languageSelectBox.selected.percentComplete != 100) { + add(Label("Missing translations:", skin)).pad(5f).row() + val missingTextSelectBox = SelectBox(skin) + val missingTextArray = Array() + val currentLanguage = UnCivGame.Current.settings.language + GameBasics.Translations.filter { !it.value.containsKey(currentLanguage) }.forEach { missingTextArray.add(it.key) } + missingTextSelectBox.items = missingTextArray + missingTextSelectBox.selected = "Untranslated texts" + add(missingTextSelectBox).pad(10f).width(UnCivGame.Current.worldScreen.stage.width / 2).row() + } + } + fun selectLanguage(){ UnCivGame.Current.settings.language = languageSelectBox.selected.language