Show a preview of custom maps on new game screen (#9234)

* Show a preview of custom maps on new game screen

* Show a preview of custom maps on new game screen - step 2

* Show a preview of custom maps on new game screen V2
This commit is contained in:
SomeTroglodyte
2023-05-04 08:31:43 +02:00
committed by GitHub
parent 43b044740c
commit b0876935f5
6 changed files with 302 additions and 124 deletions

View File

@ -0,0 +1,175 @@
package com.unciv.ui.screens.newgamescreen
import com.badlogic.gdx.files.FileHandle
import com.badlogic.gdx.scenes.scene2d.Group
import com.badlogic.gdx.scenes.scene2d.actions.Actions
import com.badlogic.gdx.scenes.scene2d.ui.Container
import com.badlogic.gdx.scenes.scene2d.ui.SelectBox
import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.badlogic.gdx.utils.Array as GdxArray
import com.unciv.UncivGame
import com.unciv.logic.UncivShowableException
import com.unciv.logic.files.MapSaver
import com.unciv.logic.map.MapParameters
import com.unciv.models.ruleset.RulesetCache
import com.unciv.ui.components.extensions.onChange
import com.unciv.ui.components.extensions.pad
import com.unciv.ui.components.extensions.toLabel
import com.unciv.ui.popups.Popup
import com.unciv.ui.screens.basescreen.BaseScreen
import com.unciv.ui.screens.victoryscreen.LoadMapPreview
import com.unciv.utils.concurrency.Concurrency
import kotlinx.coroutines.Job
import kotlinx.coroutines.isActive
class MapFileSelectTable(
private val newGameScreen: NewGameScreen,
private val mapParameters: MapParameters
) : Table() {
private val mapFileSelectBox = SelectBox<FileHandleWrapper>(BaseScreen.skin)
private val miniMapWrapper = Container<Group?>()
private var mapPreviewJob: Job? = null
private val mapFilesSequence = sequence<FileHandle> {
yieldAll(MapSaver.getMaps().asSequence())
for (modFolder in RulesetCache.values.mapNotNull { it.folderLocation }) {
val mapsFolder = modFolder.child(MapSaver.mapsFolder)
if (mapsFolder.exists())
yieldAll(mapsFolder.list().asSequence())
}
}.map { FileHandleWrapper(it) }
private val columnWidth = newGameScreen.getColumnWidth()
init {
defaults().pad(5f, 10f) // Must stay same as in MapParametersTable
val mapFileLabel = "{Map file}:".toLabel()
add(mapFileLabel).left()
add(mapFileSelectBox)
// because SOME people gotta give the hugest names to their maps
.maxWidth((columnWidth - mapFileLabel.prefWidth).coerceAtLeast(120f))
.right().row()
add(miniMapWrapper)
.pad(15f)
.colspan(2).center().row()
mapFileSelectBox.onChange { onSelectBoxChange() }
}
// The SelectBox auto displays the text a object.toString(), which on the FileHandle itself includes the folder path.
// So we wrap it in another object with a custom toString()
private class FileHandleWrapper(val fileHandle: FileHandle) {
override fun toString(): String = fileHandle.name()
}
fun isNotEmpty() = mapFilesSequence.any()
fun recentlySavedMapExists() = mapFilesSequence.any {
it.fileHandle.lastModified() > System.currentTimeMillis() - 900000
}
fun fillMapFileSelectBox() {
if (!mapFileSelectBox.items.isEmpty) return
val mapFiles = GdxArray<FileHandleWrapper>()
mapFilesSequence
.sortedWith(compareBy(UncivGame.Current.settings.getCollatorFromLocale()) { it.toString() })
.forEach { mapFiles.add(it) }
mapFileSelectBox.items = mapFiles
// Pre-select: a) map saved within last 15min or b) map named in mapParameters or c) alphabetically first
// This is a kludge - the better way would be to have a "play this map now" menu button in the editor
// (which would ideally not even require a save file - which makes implementation non-trivial)
val selectedItem =
mapFiles.maxByOrNull { it.fileHandle.lastModified() }
?.takeIf { it.fileHandle.lastModified() > System.currentTimeMillis() - 900000 }
?: mapFiles.firstOrNull { it.fileHandle.name() == mapParameters.name }
?: mapFiles.firstOrNull()
?: return
mapFileSelectBox.selected = selectedItem
mapParameters.name = selectedItem.toString()
newGameScreen.gameSetupInfo.mapFile = selectedItem.fileHandle
}
private fun onSelectBoxChange() {
cancelBackgroundJobs()
val mapFile = mapFileSelectBox.selected.fileHandle
val mapParams = try {
MapSaver.loadMapParameters(mapFile)
} catch (ex:Exception){
ex.printStackTrace()
Popup(newGameScreen).apply {
addGoodSizedLabel("Could not load map!").row()
if (ex is UncivShowableException)
addGoodSizedLabel(ex.message).row()
addCloseButton()
open()
}
return
}
mapParameters.name = mapFile.name()
newGameScreen.gameSetupInfo.mapFile = mapFile
val mapMods = mapParams.mods.partition { RulesetCache[it]?.modOptions?.isBaseRuleset == true }
newGameScreen.gameSetupInfo.gameParameters.mods = LinkedHashSet(mapMods.second)
newGameScreen.gameSetupInfo.gameParameters.baseRuleset = mapMods.first.firstOrNull() ?: mapParams.baseRuleset
newGameScreen.updateRuleset()
newGameScreen.updateTables()
hideMiniMap()
startMapPreview(mapFile)
}
private fun startMapPreview(mapFile: FileHandle) {
mapPreviewJob = Concurrency.run {
try {
val map = MapSaver.loadMap(mapFile)
if (!isActive) return@run
map.setTransients(newGameScreen.ruleset, false)
if (!isActive) return@run
// ReplyMap still paints outside its bounds - so we subtract padding and a little extra
val size = (columnWidth - 40f).coerceAtMost(500f)
val miniMap = LoadMapPreview(map, size, size)
if (!isActive) return@run
Concurrency.runOnGLThread {
showMinimap(miniMap)
}
} catch (_: Throwable) {}
}.apply {
invokeOnCompletion {
mapPreviewJob = null
}
}
}
internal fun cancelBackgroundJobs() {
mapPreviewJob?.cancel()
mapPreviewJob = null
miniMapWrapper.clearActions()
}
private fun showMinimap(miniMap: LoadMapPreview) {
if (miniMapWrapper.actor == miniMap) return
miniMapWrapper.clearActions()
miniMapWrapper.color.a = 0f
miniMapWrapper.actor = miniMap
miniMapWrapper.invalidateHierarchy()
miniMapWrapper.addAction(Actions.fadeIn(0.2f))
}
private fun hideMiniMap() {
if (miniMapWrapper.actor !is LoadMapPreview) return
miniMapWrapper.clearActions()
miniMapWrapper.addAction(
Actions.sequence(
Actions.fadeOut(0.4f),
Actions.run {
// in portrait, simply removing the map preview will cause the layout to "jump".
// with a dummy holding the empty space, it jumps later and not as far.
val dummy = Group().apply {
setSize(miniMapWrapper.actor!!.width, miniMapWrapper.actor!!.height)
}
miniMapWrapper.actor = dummy
}
)
)
}
}

View File

@ -1,66 +1,35 @@
package com.unciv.ui.screens.newgamescreen package com.unciv.ui.screens.newgamescreen
import com.badlogic.gdx.files.FileHandle
import com.badlogic.gdx.scenes.scene2d.ui.SelectBox
import com.badlogic.gdx.scenes.scene2d.ui.Table import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.badlogic.gdx.utils.Array
import com.unciv.UncivGame
import com.unciv.logic.files.MapSaver
import com.unciv.logic.UncivShowableException
import com.unciv.logic.map.MapGeneratedMainType import com.unciv.logic.map.MapGeneratedMainType
import com.unciv.models.ruleset.RulesetCache
import com.unciv.ui.popups.Popup
import com.unciv.ui.screens.basescreen.BaseScreen
import com.unciv.ui.components.extensions.onChange import com.unciv.ui.components.extensions.onChange
import com.unciv.ui.components.extensions.toLabel import com.unciv.ui.components.extensions.toLabel
import com.unciv.ui.screens.basescreen.BaseScreen
class MapOptionsTable(private val newGameScreen: NewGameScreen): Table() { class MapOptionsTable(private val newGameScreen: NewGameScreen): Table() {
private val mapParameters = newGameScreen.gameSetupInfo.mapParameters private val mapParameters = newGameScreen.gameSetupInfo.mapParameters
private var mapTypeSpecificTable = Table() private var mapTypeSpecificTable = Table()
val generatedMapOptionsTable = MapParametersTable(newGameScreen, mapParameters, MapGeneratedMainType.generated) internal val generatedMapOptionsTable = MapParametersTable(newGameScreen, mapParameters, MapGeneratedMainType.generated)
private val randomMapOptionsTable = MapParametersTable(newGameScreen, mapParameters, MapGeneratedMainType.randomGenerated) private val randomMapOptionsTable = MapParametersTable(newGameScreen, mapParameters, MapGeneratedMainType.randomGenerated)
private val savedMapOptionsTable = Table() private val savedMapOptionsTable = MapFileSelectTable(newGameScreen, mapParameters)
lateinit var mapTypeSelectBox: TranslatedSelectBox internal val mapTypeSelectBox: TranslatedSelectBox
private val mapFileSelectBox = createMapFileSelectBox()
private val mapFilesSequence = sequence<FileHandle> {
yieldAll(MapSaver.getMaps().asSequence())
for (modFolder in RulesetCache.values.mapNotNull { it.folderLocation }) {
val mapsFolder = modFolder.child(MapSaver.mapsFolder)
if (mapsFolder.exists())
yieldAll(mapsFolder.list().asSequence())
}
}.map { FileHandleWrapper(it) }
init { init {
//defaults().pad(5f) - each nested table having the same can give 'stairs' effects, //defaults().pad(5f) - each nested table having the same can give 'stairs' effects,
// better control directly. Besides, the first Labels/Buttons should have 10f to look nice // better control directly. Besides, the first Labels/Buttons should have 10f to look nice
addMapTypeSelection()
background = BaseScreen.skinStrings.getUiBackground("NewGameScreen/MapOptionsTable", tintColor = BaseScreen.skinStrings.skinConfig.clearColor) background = BaseScreen.skinStrings.getUiBackground("NewGameScreen/MapOptionsTable", tintColor = BaseScreen.skinStrings.skinConfig.clearColor)
}
private fun addMapTypeSelection() {
val mapTypes = arrayListOf(MapGeneratedMainType.generated, MapGeneratedMainType.randomGenerated) val mapTypes = arrayListOf(MapGeneratedMainType.generated, MapGeneratedMainType.randomGenerated)
if (mapFilesSequence.any()) mapTypes.add(MapGeneratedMainType.custom) if (savedMapOptionsTable.isNotEmpty()) mapTypes.add(MapGeneratedMainType.custom)
mapTypeSelectBox = TranslatedSelectBox(mapTypes, "Generated", BaseScreen.skin) mapTypeSelectBox = TranslatedSelectBox(mapTypes, "Generated", BaseScreen.skin)
savedMapOptionsTable.defaults().pad(5f)
savedMapOptionsTable.add("{Map file}:".toLabel()).left()
// because SOME people gotta give the hugest names to their maps
val columnWidth = newGameScreen.stage.width / (if (newGameScreen.isNarrowerThan4to3()) 1 else 3)
savedMapOptionsTable.add(mapFileSelectBox)
.maxWidth((columnWidth - 120f).coerceAtLeast(120f))
.right().row()
fun updateOnMapTypeChange() { fun updateOnMapTypeChange() {
mapTypeSpecificTable.clear() mapTypeSpecificTable.clear()
when (mapTypeSelectBox.selected.value) { when (mapTypeSelectBox.selected.value) {
MapGeneratedMainType.custom -> { MapGeneratedMainType.custom -> {
fillMapFileSelectBox() savedMapOptionsTable.fillMapFileSelectBox()
mapParameters.type = MapGeneratedMainType.custom mapParameters.type = MapGeneratedMainType.custom
mapParameters.name = mapFileSelectBox.selected.toString()
mapTypeSpecificTable.add(savedMapOptionsTable) mapTypeSpecificTable.add(savedMapOptionsTable)
newGameScreen.unlockTables() newGameScreen.unlockTables()
} }
@ -82,7 +51,7 @@ class MapOptionsTable(private val newGameScreen: NewGameScreen): Table() {
} }
// Pre-select custom if any map saved within last 15 minutes // Pre-select custom if any map saved within last 15 minutes
if (mapFilesSequence.any { it.fileHandle.lastModified() > System.currentTimeMillis() - 900000 }) if (savedMapOptionsTable.recentlySavedMapExists())
mapTypeSelectBox.selected = mapTypeSelectBox.selected =
TranslatedSelectBox.TranslatedString(MapGeneratedMainType.custom) TranslatedSelectBox.TranslatedString(MapGeneratedMainType.custom)
@ -98,59 +67,5 @@ class MapOptionsTable(private val newGameScreen: NewGameScreen): Table() {
add(mapTypeSpecificTable).row() add(mapTypeSpecificTable).row()
} }
private fun createMapFileSelectBox(): SelectBox<FileHandleWrapper> { internal fun cancelBackgroundJobs() = savedMapOptionsTable.cancelBackgroundJobs()
val mapFileSelectBox = SelectBox<FileHandleWrapper>(BaseScreen.skin)
mapFileSelectBox.onChange {
val mapFile = mapFileSelectBox.selected.fileHandle
val mapParams = try {
MapSaver.loadMapParameters(mapFile)
} catch (ex:Exception){
ex.printStackTrace()
Popup(newGameScreen).apply {
addGoodSizedLabel("Could not load map!").row()
if (ex is UncivShowableException)
addGoodSizedLabel(ex.message).row()
addCloseButton()
open()
}
return@onChange
}
mapParameters.name = mapFile.name()
newGameScreen.gameSetupInfo.mapFile = mapFile
val mapMods = mapParams.mods.partition { RulesetCache[it]?.modOptions?.isBaseRuleset == true }
newGameScreen.gameSetupInfo.gameParameters.mods = LinkedHashSet(mapMods.second)
newGameScreen.gameSetupInfo.gameParameters.baseRuleset = mapMods.first.firstOrNull() ?: mapParams.baseRuleset
newGameScreen.updateRuleset()
newGameScreen.updateTables()
}
return mapFileSelectBox
}
private fun fillMapFileSelectBox() {
if (!mapFileSelectBox.items.isEmpty) return
val mapFiles = Array<FileHandleWrapper>()
mapFilesSequence
.sortedWith(compareBy(UncivGame.Current.settings.getCollatorFromLocale()) { it.toString() })
.forEach { mapFiles.add(it) }
mapFileSelectBox.items = mapFiles
// Pre-select: a) map saved within last 15min or b) map named in mapParameters or c) alphabetically first
// This is a kludge - the better way would be to have a "play this map now" menu button in the editor
// (which would ideally not even require a save file - which makes implementation non-trivial)
val selectedItem =
mapFiles.maxByOrNull { it.fileHandle.lastModified() }
?.takeIf { it.fileHandle.lastModified() > System.currentTimeMillis() - 900000 }
?: mapFiles.firstOrNull { it.fileHandle.name() == mapParameters.name }
?: mapFiles.firstOrNull()
?: return
mapFileSelectBox.selected = selectedItem
newGameScreen.gameSetupInfo.mapFile = selectedItem.fileHandle
}
// The SelectBox auto displays the text a object.toString(), which on the FileHandle itself includes the folder path.
// So we wrap it in another object with a custom toString()
class FileHandleWrapper(val fileHandle: FileHandle) {
override fun toString(): String = fileHandle.name()
}
} }

View File

@ -80,7 +80,12 @@ class MapParametersTable(
skin = BaseScreen.skin skin = BaseScreen.skin
defaults().pad(5f, 10f) defaults().pad(5f, 10f)
if (mapGeneratedMainType == MapGeneratedMainType.randomGenerated) { if (mapGeneratedMainType == MapGeneratedMainType.randomGenerated) {
add("{Which options should be available to the random selection?}".toLabel()).colspan(2).grow().row() val prompt = "Which options should be available to the random selection?"
val width = (previousScreen as? NewGameScreen)?.getColumnWidth() ?: 200f
val label = WrappableLabel(prompt, width - 20f) // 20 is the defaults() padding
label.setAlignment(Align.center)
label.wrap = true
add(label).colspan(2).grow().row()
} }
addMapShapeSelectBox() addMapShapeSelectBox()
addMapTypeSelectBox() addMapTypeSelectBox()

View File

@ -20,10 +20,13 @@ import com.unciv.models.metadata.GameSetupInfo
import com.unciv.models.ruleset.RulesetCache import com.unciv.models.ruleset.RulesetCache
import com.unciv.models.translations.tr import com.unciv.models.translations.tr
import com.unciv.ui.components.ExpanderTab import com.unciv.ui.components.ExpanderTab
import com.unciv.ui.components.KeyCharAndCode
import com.unciv.ui.components.extensions.addSeparator import com.unciv.ui.components.extensions.addSeparator
import com.unciv.ui.components.extensions.addSeparatorVertical import com.unciv.ui.components.extensions.addSeparatorVertical
import com.unciv.ui.components.extensions.disable import com.unciv.ui.components.extensions.disable
import com.unciv.ui.components.extensions.enable import com.unciv.ui.components.extensions.enable
import com.unciv.ui.components.extensions.keyShortcuts
import com.unciv.ui.components.extensions.onActivation
import com.unciv.ui.components.extensions.onClick import com.unciv.ui.components.extensions.onClick
import com.unciv.ui.components.extensions.pad import com.unciv.ui.components.extensions.pad
import com.unciv.ui.components.extensions.toLabel import com.unciv.ui.components.extensions.toLabel
@ -76,7 +79,11 @@ class NewGameScreen(
updatePlayerPickerRandomLabel = { playerPickerTable.updateRandomNumberLabel() } updatePlayerPickerRandomLabel = { playerPickerTable.updateRandomNumberLabel() }
) )
mapOptionsTable = MapOptionsTable(this) mapOptionsTable = MapOptionsTable(this)
setDefaultCloseAction() pickerPane.closeButton.onActivation {
mapOptionsTable.cancelBackgroundJobs()
game.popScreen()
}
pickerPane.closeButton.keyShortcuts.add(KeyCharAndCode.BACK)
if (isPortrait) initPortrait() if (isPortrait) initPortrait()
else initLandscape() else initLandscape()
@ -104,6 +111,7 @@ class NewGameScreen(
} }
private fun onStartGameClicked() { private fun onStartGameClicked() {
mapOptionsTable.cancelBackgroundJobs()
if (gameSetupInfo.gameParameters.isOnlineMultiplayer) { if (gameSetupInfo.gameParameters.isOnlineMultiplayer) {
if (!checkConnectionToMultiplayerServer()) { if (!checkConnectionToMultiplayerServer()) {
val noInternetConnectionPopup = Popup(this) val noInternetConnectionPopup = Popup(this)
@ -206,6 +214,10 @@ class NewGameScreen(
} }
} }
/** Subtables may need an upper limit to their width - they can ask this function. */
// In sync with isPortrait in init, here so UI details need not know about 3-column vs 1-column layout
internal fun getColumnWidth() = stage.width / (if (isNarrowerThan4to3()) 1 else 3)
private fun initLandscape() { private fun initLandscape() {
scrollPane.setScrollingDisabled(true,true) scrollPane.setScrollingDisabled(true,true)

View File

@ -2,55 +2,126 @@ package com.unciv.ui.screens.victoryscreen
import com.badlogic.gdx.scenes.scene2d.Group import com.badlogic.gdx.scenes.scene2d.Group
import com.unciv.logic.civilization.Civilization import com.unciv.logic.civilization.Civilization
import com.unciv.logic.map.MapShape
import com.unciv.logic.map.TileMap import com.unciv.logic.map.TileMap
import com.unciv.logic.map.tile.Tile
import com.unciv.ui.screens.worldscreen.minimap.MinimapTile import com.unciv.ui.screens.worldscreen.minimap.MinimapTile
import com.unciv.ui.screens.worldscreen.minimap.MinimapTileUtil import com.unciv.ui.screens.worldscreen.minimap.MinimapTileUtil
import kotlin.math.min import kotlin.math.min
import kotlin.math.sqrt import kotlin.math.sqrt
// Mostly copied from MiniMap // Mostly copied from MiniMap
class ReplayMap(
val tileMap: TileMap, @Suppress("LeakingThis")
val viewingCiv: Civilization, /**
private val replayMapWidth: Float, * Base for a MiniMap not intertwined with a WorldScreen.
private val replayMapHeight: Float * For a _minimal_ implementation see [LoadMapPreview]
*
* TODO: Analyze why MiniMap needs the tight WorldScreen integration and clean up / merge
*/
abstract class IndependentMiniMap(
val tileMap: TileMap
) : Group() { ) : Group() {
private val tileLayer = Group() protected lateinit var minimapTiles: List<MinimapTile>
private val minimapTiles: List<MinimapTile>
init { /** Call this in the init of derived classes.
val tileSize = calcTileSize() *
* Needs to be deferred only to allow [calcTileSize] or [includeTileFilter] to use class parameters added in the derived class. */
protected open fun deferredInit(maxWidth: Float, maxHeight: Float) {
val tileSize = calcTileSize(maxWidth, maxHeight)
minimapTiles = createReplayMap(tileSize) minimapTiles = createReplayMap(tileSize)
val tileExtension = MinimapTileUtil.spreadOutMinimapTiles(tileLayer, minimapTiles, tileSize) val tileExtension = MinimapTileUtil.spreadOutMinimapTiles(this, minimapTiles, tileSize)
for (group in tileLayer.children) { for (group in children) {
group.moveBy(-tileExtension.x, -tileExtension.y) group.moveBy(-tileExtension.x, -tileExtension.y)
} }
// there are tiles "below the zero", setSize(tileExtension.width, tileExtension.height)
// so we zero out the starting position of the whole board so they will be displayed as well
tileLayer.setSize(tileExtension.width, tileExtension.height)
setSize(tileLayer.width, tileLayer.height)
addActor(tileLayer)
} }
private fun calcTileSize(): Float { /** Calculate a tile radius in screen coordinates so that the resulting map, after distributimg
* the tiles using spreadOutMinimapTiles, will not exceed the bounds ([maxWidth],[maxHeight]) */
protected abstract fun calcTileSize(maxWidth: Float, maxHeight: Float): Float
/** Controls which tiles are included */
protected open fun includeTileFilter(tile: Tile): Boolean = true
private fun createReplayMap(tileSize: Float): List<MinimapTile> {
val doNothing = fun(){}
val tiles = ArrayList<MinimapTile>(tileMap.values.size)
for (tile in tileMap.values.filter(::includeTileFilter) ) {
val minimapTile = MinimapTile(tile, tileSize, doNothing)
minimapTile.updateColor(false, null)
tiles.add(minimapTile)
}
tiles.trimToSize()
return tiles
}
}
/**
* A minimap with no WorldScreen dependencies, always shows the entire map.
*
* @param tileMap Map to display minimap-style
* @param maxWidth Resulting Group will not exceed this width
* @param maxHeight Resulting Group will not exceed this height
*/
class LoadMapPreview(
tileMap: TileMap,
maxWidth: Float,
maxHeight: Float
) : IndependentMiniMap(tileMap) {
init {
deferredInit(maxWidth, maxHeight)
}
override fun calcTileSize(maxWidth: Float, maxHeight: Float): Float {
val height: Float
val width: Float
val mapSize = tileMap.mapParameters.mapSize
if (tileMap.mapParameters.shape != MapShape.rectangular) {
height = mapSize.radius * 2 + 1f
width = height
} else {
height = mapSize.height.toFloat()
width = mapSize.width.toFloat()
}
// See HexMath.worldFromLatLong, the 0.6 is empiric to avoid rounding to cause the map to spill over
return min(
maxWidth / (width + 0.6f) / 1.5f * 2f,
maxHeight / (height + 0.6f) / sqrt(3f) * 2f,
)
}
}
/**
* A minimap with no WorldScreen dependencies, with the ability to show historical states.
*
* @param tileMap Map to display minimap-style
* @param viewingCiv used to determine tile visibility and explored area
* @param maxWidth Resulting Group should not exceed this width
* @param maxHeight Resulting Group should not exceed this height
*/
class ReplayMap(
tileMap: TileMap,
val viewingCiv: Civilization,
maxWidth: Float,
maxHeight: Float
) : IndependentMiniMap(tileMap) {
init {
deferredInit(maxWidth, maxHeight)
}
override fun calcTileSize(maxWidth: Float, maxHeight: Float): Float {
val height = viewingCiv.exploredRegion.getHeight().toFloat() val height = viewingCiv.exploredRegion.getHeight().toFloat()
val width = viewingCiv.exploredRegion.getWidth().toFloat() val width = viewingCiv.exploredRegion.getWidth().toFloat()
return min ( return min (
replayMapHeight / (height + 1.5f) / sqrt(3f) * 4f, // 1.5 - padding, hex height = sqrt(3) / 2 * d / 2 -> d = height / sqrt(3) * 2 * 2 maxHeight / (height + 1.5f) / sqrt(3f) * 4f, // 1.5 - padding, hex height = sqrt(3) / 2 * d / 2 -> d = height / sqrt(3) * 2 * 2
replayMapWidth / (width + 0.5f) / 0.75f // 0.5 - padding, hex width = 0.75 * d -> d = width / 0.75 maxWidth / (width + 0.5f) / 0.75f // 0.5 - padding, hex width = 0.75 * d -> d = width / 0.75
) )
} }
private fun createReplayMap(tileSize: Float): List<MinimapTile> { override fun includeTileFilter(tile: Tile) = tile.isExplored(viewingCiv)
val tiles = ArrayList<MinimapTile>()
for (tile in tileMap.values.filter { it.isExplored(viewingCiv) }) {
val minimapTile = MinimapTile(tile, tileSize) {}
tiles.add(minimapTile)
}
return tiles
}
fun update(turn: Int) { fun update(turn: Int) {
val viewingCivIsDefeated = viewingCiv.gameInfo.victoryData != null || !viewingCiv.isAlive() val viewingCivIsDefeated = viewingCiv.gameInfo.victoryData != null || !viewingCiv.isAlive()

View File

@ -51,7 +51,7 @@ class VictoryScreenReplay(
gameInfo.tileMap, gameInfo.tileMap,
worldScreen.viewingCiv, worldScreen.viewingCiv,
worldScreen.stage.width - 50, worldScreen.stage.width - 50,
worldScreen.stage.height - 250 worldScreen.stage.height - 250 // Empiric: `stage.height - pager.contentScroll_field.height` after init is 244.
) )
playImage.setSize(24f) playImage.setSize(24f)