diff --git a/android/Images/EmojiIcons/Production.png b/android/Images/EmojiIcons/Production.png new file mode 100644 index 0000000000..4c1ca2e89f Binary files /dev/null and b/android/Images/EmojiIcons/Production.png differ diff --git a/android/Images/EmojiIcons/TurnOld.png b/android/Images/EmojiIcons/TurnOld.png deleted file mode 100644 index 560af9135c..0000000000 Binary files a/android/Images/EmojiIcons/TurnOld.png and /dev/null differ diff --git a/android/assets/game.atlas b/android/assets/game.atlas index 8c9a90c980..ad5cc333f6 100644 --- a/android/assets/game.atlas +++ b/android/assets/game.atlas @@ -4,14 +4,14 @@ size: 2048, 2048 format: RGBA8888 filter: MipMapLinearLinear, MipMapLinearLinear repeat: none -EmojiIcons/Turn +EmojiIcons/Production rotate: false - xy: 1890, 1214 + xy: 1532, 706 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 -EmojiIcons/TurnOld +EmojiIcons/Turn rotate: false xy: 1890, 1162 size: 50, 50 @@ -797,77 +797,77 @@ PolicyIcons/Populism index: -1 PolicyIcons/Professional Army rotate: false - xy: 1532, 706 + xy: 1532, 654 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Protectionism rotate: false - xy: 1532, 654 + xy: 1584, 810 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Reformation rotate: false - xy: 1584, 706 + xy: 1584, 654 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Representation rotate: false - xy: 1532, 602 + xy: 1584, 602 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Republic rotate: false - xy: 1584, 602 + xy: 1940, 1318 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Scientific Revolution rotate: false - xy: 1940, 1318 + xy: 1992, 1318 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Secularism rotate: false - xy: 1940, 1266 + xy: 1992, 1266 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Sovereignty rotate: false - xy: 1736, 960 + xy: 1788, 960 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Theocracy rotate: false - xy: 1838, 1166 + xy: 1838, 1114 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Total War rotate: false - xy: 1838, 1114 + xy: 1634, 912 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Trade Unions rotate: false - xy: 1634, 912 + xy: 1890, 1214 size: 50, 50 orig: 50, 50 offset: 0, 0 @@ -1168,14 +1168,14 @@ StatIcons/Production index: -1 StatIcons/Range rotate: false - xy: 1584, 810 + xy: 1584, 758 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 StatIcons/RangedStrength rotate: false - xy: 1584, 758 + xy: 1584, 706 size: 50, 50 orig: 50, 50 offset: 0, 0 @@ -1203,7 +1203,7 @@ StatIcons/Specialist index: -1 StatIcons/Strength rotate: false - xy: 1788, 960 + xy: 1838, 1218 size: 50, 50 orig: 50, 50 offset: 0, 0 @@ -6334,56 +6334,56 @@ UnitPromotionIcons/Morale index: -1 UnitPromotionIcons/Rejuvenation rotate: false - xy: 1584, 654 + xy: 1532, 602 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 UnitPromotionIcons/Scouting rotate: false - xy: 1992, 1318 + xy: 1940, 1266 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 UnitPromotionIcons/Sentry rotate: false - xy: 1992, 1318 + xy: 1940, 1266 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 UnitPromotionIcons/Shock rotate: false - xy: 1992, 1266 + xy: 1736, 1012 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 UnitPromotionIcons/Slinger Withdraw rotate: false - xy: 1736, 1012 + xy: 1788, 1012 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 UnitPromotionIcons/Sortie rotate: false - xy: 1788, 1012 + xy: 1736, 960 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 UnitPromotionIcons/Targeting rotate: false - xy: 1838, 1218 + xy: 1838, 1166 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 UnitPromotionIcons/Targeting I (air) rotate: false - xy: 1838, 1218 + xy: 1838, 1166 size: 50, 50 orig: 50, 50 offset: 0, 0 diff --git a/android/assets/game.png b/android/assets/game.png index 5f299341d1..eee4211511 100644 Binary files a/android/assets/game.png and b/android/assets/game.png differ diff --git a/android/src/com/unciv/app/AndroidLauncher.kt b/android/src/com/unciv/app/AndroidLauncher.kt index b734d9db0a..eb14d9ec50 100644 --- a/android/src/com/unciv/app/AndroidLauncher.kt +++ b/android/src/com/unciv/app/AndroidLauncher.kt @@ -10,7 +10,7 @@ import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration import com.unciv.UncivGame import com.unciv.UncivGameParameters import com.unciv.logic.GameSaver -import com.unciv.ui.utils.ORIGINAL_FONT_SIZE +import com.unciv.ui.utils.Fonts import java.io.File open class AndroidLauncher : AndroidApplication() { @@ -33,7 +33,7 @@ open class AndroidLauncher : AndroidApplication() { val androidParameters = UncivGameParameters( version = BuildConfig.VERSION_NAME, crashReportSender = CrashReportSenderAndroid(this), - fontImplementation = NativeFontAndroid(ORIGINAL_FONT_SIZE.toInt()), + fontImplementation = NativeFontAndroid(Fonts.ORIGINAL_FONT_SIZE.toInt()), customSaveLocationHelper = customSaveLocationHelper ) val game = UncivGame(androidParameters) diff --git a/core/src/com/unciv/logic/city/CityConstructions.kt b/core/src/com/unciv/logic/city/CityConstructions.kt index d8ae985e6b..b92e399672 100644 --- a/core/src/com/unciv/logic/city/CityConstructions.kt +++ b/core/src/com/unciv/logic/city/CityConstructions.kt @@ -1,6 +1,5 @@ package com.unciv.logic.city -import com.badlogic.gdx.graphics.Color import com.unciv.logic.automation.ConstructionAutomation import com.unciv.logic.civilization.AlertType import com.unciv.logic.civilization.NotificationIcon @@ -115,9 +114,12 @@ class CityConstructions { if (currentConstructionSnapshot != "") { val construction = PerpetualConstruction.perpetualConstructionsMap[currentConstructionSnapshot] if (construction == null) { - val turnsLeft = turnsToConstruction(currentConstructionSnapshot) - result += ("\r\n" + "Cost".tr() + " " + getConstruction(currentConstructionFromQueue).getProductionCost(cityInfo.civInfo).toString()).tr() - result += ConstructionInfoTable.turnOrTurns(turnsLeft) +// val workDone = getWorkDone(currentConstructionSnapshot) +// val turnsLeft = +// result += ("\r\n" + "Cost".tr() + " " + getConstruction(currentConstructionFromQueue).getProductionCost(cityInfo.civInfo).toString()).tr() + result += ConstructionInfoTable.turnOrTurns(turnsToConstruction(currentConstructionSnapshot), + getConstruction(currentConstructionFromQueue).getProductionCost(cityInfo.civInfo), + getWorkDone(currentConstructionSnapshot)) } else { result += construction.getProductionTooltip(cityInfo) } @@ -384,7 +386,7 @@ class CityConstructions { if (!buildableCultureBuildings.any()) return null - val cultureBuildingToBuild = buildableCultureBuildings.minBy { it.cost }!!.name + val cultureBuildingToBuild = buildableCultureBuildings.minByOrNull { it.cost }!!.name constructionComplete(getConstruction(cultureBuildingToBuild)) return cultureBuildingToBuild diff --git a/core/src/com/unciv/ui/cityscreen/ConstructionInfoTable.kt b/core/src/com/unciv/ui/cityscreen/ConstructionInfoTable.kt index 35a39b5805..9c551b55bf 100644 --- a/core/src/com/unciv/ui/cityscreen/ConstructionInfoTable.kt +++ b/core/src/com/unciv/ui/cityscreen/ConstructionInfoTable.kt @@ -12,7 +12,6 @@ import com.unciv.ui.utils.Fonts import com.unciv.ui.utils.ImageGetter import com.unciv.ui.utils.surroundWithCircle import com.unciv.ui.utils.toLabel -import com.unciv.ui.utils.AutoScrollPane as ScrollPane class ConstructionInfoTable(val city: CityInfo): Table() { val selectedConstructionTable = Table() @@ -54,8 +53,8 @@ class ConstructionInfoTable(val city: CityInfo): Table() { val specialConstruction = PerpetualConstruction.perpetualConstructionsMap[construction.name] if (specialConstruction == null) { val turnsToComplete = cityConstructions.turnsToConstruction(construction.name) - buildingText += ("\r\n" + "Cost".tr() + " " + construction.getProductionCost(city.civInfo).toString()).tr() - buildingText += turnOrTurns(turnsToComplete) +// buildingText += ("\r\n" + "Cost".tr() + " " + construction.getProductionCost(city.civInfo).toString()).tr() + buildingText += turnOrTurns(turnsToComplete, construction.getProductionCost(city.civInfo), cityConstructions.getWorkDone(construction.name)) } else { buildingText += specialConstruction.getProductionTooltip(city) } @@ -76,6 +75,9 @@ class ConstructionInfoTable(val city: CityInfo): Table() { } companion object { - internal fun turnOrTurns(turns: Int): String = "\r\n$turns${Fonts.turn}" + internal fun turnOrTurns(turns: Int, cost:Int, currentProgress:Int=0): String { + if (currentProgress == 0) return "\n$cost${Fonts.production} $turns${Fonts.turn}" + else return "\n$currentProgress/$cost${Fonts.production}\n$turns${Fonts.turn}" + } } } \ No newline at end of file diff --git a/core/src/com/unciv/ui/cityscreen/ConstructionsTable.kt b/core/src/com/unciv/ui/cityscreen/ConstructionsTable.kt index a1bd6ef425..9fb9209b79 100644 --- a/core/src/com/unciv/ui/cityscreen/ConstructionsTable.kt +++ b/core/src/com/unciv/ui/cityscreen/ConstructionsTable.kt @@ -123,7 +123,7 @@ class ConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBaseScre for (unit in city.getRuleset().units.values.filter { it.shouldBeDisplayed(cityConstructions) }) { val useStoredProduction = !cityConstructions.isBeingConstructedOrEnqueued(unit.name) val turnsToUnit = cityConstructions.turnsToConstruction(unit.name, useStoredProduction) - var buttonText = unit.name.tr() + turnOrTurns(turnsToUnit) + var buttonText = unit.name.tr() + turnOrTurns(turnsToUnit, unit.getProductionCost(city.civInfo), cityConstructions.getWorkDone(unit.name)) for ((resource, amount) in unit.getResourceRequirements()) { if (amount == 1) buttonText += "\n" + "Consumes 1 [$resource]".tr() else buttonText += "\n" + "Consumes [$amount] [$resource]".tr() @@ -137,7 +137,7 @@ class ConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBaseScre for (building in city.getRuleset().buildings.values.filter { it.shouldBeDisplayed(cityConstructions) }) { val turnsToBuilding = cityConstructions.turnsToConstruction(building.name) - var buttonText = building.name.tr() + turnOrTurns(turnsToBuilding) + var buttonText = building.name.tr() + turnOrTurns(turnsToBuilding, building.getProductionCost(city.civInfo), cityConstructions.getWorkDone(building.name)) for ((resource, amount) in building.getResourceRequirements()) { if (amount == 1) buttonText += "\n" + "Consumes 1 [$resource]".tr() else buttonText += "\n" + "Consumes [$amount] [$resource]".tr() @@ -210,7 +210,7 @@ class ConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBaseScre } } - private fun getQueueEntry(constructionQueueIndex: Int, name: String): Table { + private fun getQueueEntry(constructionQueueIndex: Int, constructionName: String): Table { val city = cityScreen.city val cityConstructions = city.cityConstructions @@ -221,35 +221,37 @@ class ConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBaseScre if (constructionQueueIndex == selectedQueueEntry) table.background = ImageGetter.getBackground(Color.GREEN.cpy().lerp(Color.BLACK, 0.5f)) - val isFirstConstructionOfItsKind = cityConstructions.isFirstConstructionOfItsKind(constructionQueueIndex, name) - val turnsToComplete = cityConstructions.turnsToConstruction(name, isFirstConstructionOfItsKind) - var text = name.tr() + - if (name in PerpetualConstruction.perpetualConstructionsMap) "\n∞" - else turnOrTurns(turnsToComplete) + val isFirstConstructionOfItsKind = cityConstructions.isFirstConstructionOfItsKind(constructionQueueIndex, constructionName) + val turnsToComplete = cityConstructions.turnsToConstruction(constructionName, isFirstConstructionOfItsKind) - val constructionResource = cityConstructions.getConstruction(name).getResourceRequirements() + val construction = cityConstructions.getConstruction(constructionName) + var text = constructionName.tr() + + if (constructionName in PerpetualConstruction.perpetualConstructionsMap) "\n∞" + else turnOrTurns(turnsToComplete, construction.getProductionCost(city.civInfo), cityConstructions.getWorkDone(constructionName)) + + val constructionResource = construction.getResourceRequirements() for ((resource, amount) in constructionResource) if (amount == 1) text += "\n" + "Consumes 1 [$resource]".tr() else text += "\n" + "Consumes [$amount] [$resource]".tr() table.defaults().pad(2f).minWidth(40f) - if (isFirstConstructionOfItsKind) table.add(getProgressBar(name)).minWidth(5f) + if (isFirstConstructionOfItsKind) table.add(getProgressBar(constructionName)).minWidth(5f) else table.add().minWidth(5f) - table.add(ImageGetter.getConstructionImage(name).surroundWithCircle(40f)).padRight(10f) + table.add(ImageGetter.getConstructionImage(constructionName).surroundWithCircle(40f)).padRight(10f) table.add(text.toLabel()).expandX().fillX().left() - if (constructionQueueIndex > 0) table.add(getRaisePriorityButton(constructionQueueIndex, name, city)).right() + if (constructionQueueIndex > 0) table.add(getRaisePriorityButton(constructionQueueIndex, constructionName, city)).right() else table.add().right() if (constructionQueueIndex != cityConstructions.constructionQueue.lastIndex) - table.add(getLowerPriorityButton(constructionQueueIndex, name, city)).right() + table.add(getLowerPriorityButton(constructionQueueIndex, constructionName, city)).right() else table.add().right() table.add(getRemoveFromQueueButton(constructionQueueIndex, city)).right() table.touchable = Touchable.enabled table.onClick { - cityScreen.selectedConstruction = cityConstructions.getConstruction(name) + cityScreen.selectedConstruction = cityConstructions.getConstruction(constructionName) cityScreen.selectedTile = null selectedQueueEntry = constructionQueueIndex cityScreen.update() diff --git a/core/src/com/unciv/ui/utils/CameraStageBaseScreen.kt b/core/src/com/unciv/ui/utils/CameraStageBaseScreen.kt index c0db1d1d21..0d3a934067 100644 --- a/core/src/com/unciv/ui/utils/CameraStageBaseScreen.kt +++ b/core/src/com/unciv/ui/utils/CameraStageBaseScreen.kt @@ -100,14 +100,14 @@ open class CameraStageBaseScreen : Screen { addRegions(TextureAtlas("skin/flat-earth-ui.atlas")) load(Gdx.files.internal("skin/flat-earth-ui.json")) } - skin.get(TextButton.TextButtonStyle::class.java).font = Fonts.font.apply { data.setScale(20 / ORIGINAL_FONT_SIZE) } - skin.get(CheckBox.CheckBoxStyle::class.java).font = Fonts.font.apply { data.setScale(20 / ORIGINAL_FONT_SIZE) } + skin.get(TextButton.TextButtonStyle::class.java).font = Fonts.font.apply { data.setScale(20 / Fonts.ORIGINAL_FONT_SIZE) } + skin.get(CheckBox.CheckBoxStyle::class.java).font = Fonts.font.apply { data.setScale(20 / Fonts.ORIGINAL_FONT_SIZE) } skin.get(CheckBox.CheckBoxStyle::class.java).fontColor = Color.WHITE - skin.get(Label.LabelStyle::class.java).font = Fonts.font.apply { data.setScale(18 / ORIGINAL_FONT_SIZE) } + skin.get(Label.LabelStyle::class.java).font = Fonts.font.apply { data.setScale(18 / Fonts.ORIGINAL_FONT_SIZE) } skin.get(Label.LabelStyle::class.java).fontColor = Color.WHITE - skin.get(TextField.TextFieldStyle::class.java).font = Fonts.font.apply { data.setScale(18 / ORIGINAL_FONT_SIZE) } - skin.get(SelectBox.SelectBoxStyle::class.java).font = Fonts.font.apply { data.setScale(20 / ORIGINAL_FONT_SIZE) } - skin.get(SelectBox.SelectBoxStyle::class.java).listStyle.font = Fonts.font.apply { data.setScale(20 / ORIGINAL_FONT_SIZE) } + skin.get(TextField.TextFieldStyle::class.java).font = Fonts.font.apply { data.setScale(18 / Fonts.ORIGINAL_FONT_SIZE) } + skin.get(SelectBox.SelectBoxStyle::class.java).font = Fonts.font.apply { data.setScale(20 / Fonts.ORIGINAL_FONT_SIZE) } + skin.get(SelectBox.SelectBoxStyle::class.java).listStyle.font = Fonts.font.apply { data.setScale(20 / Fonts.ORIGINAL_FONT_SIZE) } skin } internal var batch: Batch = SpriteBatch() @@ -262,10 +262,7 @@ fun String.toTextButton() = TextButton(this.tr(), CameraStageBaseScreen.skin) fun String.toLabel() = Label(this.tr(),CameraStageBaseScreen.skin) fun Int.toLabel() = this.toString().toLabel() -/** All text is originally rendered in 50px, and thn scaled to fit the size of the text we need now. - * This has several advantages: It means we only render each character once (good for both runtime and RAM), - * AND it means that our 'custom' emojis only need to be once size (50px) and they'll be rescaled for what's needed. */ -const val ORIGINAL_FONT_SIZE = 50f + // We don't want to use setFontSize and setFontColor because they set the font, // which means we need to rebuild the font cache which means more memory allocation. @@ -276,7 +273,7 @@ fun String.toLabel(fontColor:Color= Color.WHITE, fontSize:Int=18): Label { labelStyle.fontColor = fontColor if (fontSize != 18) labelStyle.font = Fonts.font } - return Label(this.tr(), labelStyle).apply { setFontScale(fontSize/ORIGINAL_FONT_SIZE) } + return Label(this.tr(), labelStyle).apply { setFontScale(fontSize/Fonts.ORIGINAL_FONT_SIZE) } } @@ -286,7 +283,7 @@ fun Label.setFontSize(size:Int): Label { style = Label.LabelStyle(style) style.font = Fonts.font style = style // because we need it to call the SetStyle function. Yuk, I know. - return this.apply { setFontScale(size/ORIGINAL_FONT_SIZE) } // for chaining + return this.apply { setFontScale(size/Fonts.ORIGINAL_FONT_SIZE) } // for chaining } diff --git a/core/src/com/unciv/ui/utils/Fonts.kt b/core/src/com/unciv/ui/utils/Fonts.kt index fd3abeac0d..e29aad04b4 100644 --- a/core/src/com/unciv/ui/utils/Fonts.kt +++ b/core/src/com/unciv/ui/utils/Fonts.kt @@ -22,6 +22,7 @@ interface NativeFontImplementation { // This class is loosely based on libgdx's FreeTypeBitmapFontData class NativeBitmapFontData(val fontImplementation: NativeFontImplementation) : BitmapFontData(), Disposable { + val regions: Array private var dirty = false @@ -82,12 +83,14 @@ class NativeBitmapFontData(val fontImplementation: NativeFontImplementation) : B } private fun getPixmapFromChar(ch: Char): Pixmap { + // Images must be 50*50px so they're rendered at the same height as the text - see Fonts.ORIGINAL_FONT_SIZE return when (ch) { Fonts.strength -> Fonts.extractPixmapFromTextureRegion(ImageGetter.getDrawable("StatIcons/Strength").region) Fonts.rangedStrength -> Fonts.extractPixmapFromTextureRegion(ImageGetter.getDrawable("StatIcons/RangedStrength").region) Fonts.range -> Fonts.extractPixmapFromTextureRegion(ImageGetter.getDrawable("StatIcons/Range").region) Fonts.movement -> Fonts.extractPixmapFromTextureRegion(ImageGetter.getDrawable("StatIcons/Movement").region) Fonts.turn -> Fonts.extractPixmapFromTextureRegion(ImageGetter.getDrawable("EmojiIcons/Turn").region) + Fonts.production -> Fonts.extractPixmapFromTextureRegion(ImageGetter.getDrawable("EmojiIcons/Production").region) else -> fontImplementation.getCharPixmap(ch) } } @@ -104,9 +107,16 @@ class NativeBitmapFontData(val fontImplementation: NativeFontImplementation) : B override fun dispose() { packer.dispose() } + } object Fonts { + + /** All text is originally rendered in 50px (set in AndroidLauncher and DesktopLauncher), and thn scaled to fit the size of the text we need now. + * This has several advantages: It means we only render each character once (good for both runtime and RAM), + * AND it means that our 'custom' emojis only need to be once size (50px) and they'll be rescaled for what's needed. */ + const val ORIGINAL_FONT_SIZE = 50f + lateinit var font:BitmapFont fun resetFont() { val fontData = NativeBitmapFontData(UncivGame.Current.fontImplementation!!) @@ -143,6 +153,5 @@ object Fonts { const val rangedStrength = '‡' const val movement = '➡' const val range = '…' - -// const val production = '⚙' + const val production = '⚙' } diff --git a/desktop/src/com/unciv/app/desktop/DesktopLauncher.kt b/desktop/src/com/unciv/app/desktop/DesktopLauncher.kt index 41600b9cb0..ec2ba68c78 100644 --- a/desktop/src/com/unciv/app/desktop/DesktopLauncher.kt +++ b/desktop/src/com/unciv/app/desktop/DesktopLauncher.kt @@ -12,7 +12,7 @@ import com.badlogic.gdx.tools.texturepacker.TexturePackerFileProcessor import com.unciv.UncivGame import com.unciv.UncivGameParameters import com.unciv.models.translations.tr -import com.unciv.ui.utils.ORIGINAL_FONT_SIZE +import com.unciv.ui.utils.Fonts import io.ktor.application.* import io.ktor.http.* import io.ktor.request.* @@ -46,7 +46,7 @@ internal object DesktopLauncher { val desktopParameters = UncivGameParameters( versionFromJar, cancelDiscordEvent = { discordTimer?.cancel() }, - fontImplementation = NativeFontDesktop(ORIGINAL_FONT_SIZE.toInt()), + fontImplementation = NativeFontDesktop(Fonts.ORIGINAL_FONT_SIZE.toInt()), customSaveLocationHelper = CustomSaveLocationHelperDesktop() )