Added construction production info to city screen

This commit is contained in:
Yair Morgenstern
2021-04-29 14:02:27 +03:00
parent 464d89298a
commit 4db97dcd1a
11 changed files with 78 additions and 66 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 888 KiB

After

Width:  |  Height:  |  Size: 888 KiB

View File

@ -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)

View File

@ -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

View File

@ -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}"
}
}
}

View File

@ -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()

View File

@ -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
}

View File

@ -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<TextureRegion>
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 = '⚙'
}

View File

@ -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()
)