mirror of
https://github.com/yairm210/Unciv.git
synced 2025-02-11 11:28:03 +07:00
StartingLocation-Improvements-be-gone phase 2 (#4975)
This commit is contained in:
parent
b157313bb9
commit
a53cb82034
@ -21,8 +21,8 @@ import kotlin.math.max
|
||||
|
||||
object GameStarter {
|
||||
// temporary instrumentation while tuning/debugging
|
||||
private const val consoleOutput = true
|
||||
private const val consoleTimings = true
|
||||
private const val consoleOutput = false
|
||||
private const val consoleTimings = false
|
||||
|
||||
fun startNewGame(gameSetupInfo: GameSetupInfo): GameInfo {
|
||||
if (consoleOutput || consoleTimings)
|
||||
|
@ -10,7 +10,7 @@ object MapSaver {
|
||||
fun json() = GameSaver.json()
|
||||
|
||||
private const val mapsFolder = "maps"
|
||||
private const val saveZipped = false
|
||||
private const val saveZipped = true
|
||||
|
||||
private fun getMap(mapName:String) = Gdx.files.local("$mapsFolder/$mapName")
|
||||
|
||||
|
@ -158,6 +158,14 @@ class MapParameters {
|
||||
}
|
||||
|
||||
// For debugging and MapGenerator console output
|
||||
override fun toString() = if (name.isNotEmpty()) "\"$name\""
|
||||
else "($mapSize ${if (worldWrap)"wrapped " else ""}$shape $type, Seed $seed, $elevationExponent/$temperatureExtremeness/$resourceRichness/$vegetationRichness/$rareFeaturesRichness/$maxCoastExtension/$tilesPerBiomeArea/$waterThreshold)"
|
||||
override fun toString() = sequence {
|
||||
if (name.isNotEmpty()) yield("\"$name\" ")
|
||||
yield("($mapSize ")
|
||||
if (worldWrap) yield("wrapped ")
|
||||
yield(shape)
|
||||
if (name.isEmpty()) return@sequence
|
||||
yield(" $type, Seed $seed, ")
|
||||
yield("$elevationExponent/$temperatureExtremeness/$resourceRichness/$vegetationRichness/")
|
||||
yield("$rareFeaturesRichness/$maxCoastExtension/$tilesPerBiomeArea/$waterThreshold")
|
||||
}.joinToString("", postfix = ")")
|
||||
}
|
||||
|
@ -757,11 +757,6 @@ open class TileInfo {
|
||||
}
|
||||
|
||||
private fun normalizeTileImprovement(ruleset: Ruleset) {
|
||||
// This runs from map editor too, so the Pseudo-improvements for starting locations need to stay.
|
||||
if (improvement!!.startsWith(TileMap.startingLocationPrefix)) {
|
||||
if (!isLand || getLastTerrain().impassable) improvement = null
|
||||
return
|
||||
}
|
||||
val improvementObject = ruleset.tileImprovements[improvement]
|
||||
if (improvementObject == null) {
|
||||
improvement = null
|
||||
|
@ -17,12 +17,13 @@ import kotlin.math.abs
|
||||
*/
|
||||
class TileMap {
|
||||
companion object {
|
||||
/** Legacy way to store starting locations - now this is used only in [translateStartingLocationsFromMap] */
|
||||
const val startingLocationPrefix = "StartingLocation "
|
||||
|
||||
/**
|
||||
* To be backwards compatible, a json without a startingLocations element will be recognized by an entry with this marker
|
||||
* New saved maps will never have this marker and will always have a serialized startingLocations list even if empty.
|
||||
* New saved maps will also never have "StartingLocation" improvements, these _must_ be converted before use anywhere outside map editor.
|
||||
* New saved maps will also never have "StartingLocation" improvements, these are converted on load in [setTransients].
|
||||
*/
|
||||
private const val legacyMarker = " Legacy "
|
||||
}
|
||||
@ -452,32 +453,41 @@ class TileMap {
|
||||
|
||||
/** Strips all units and starting locations from [TileMap] for specified [Player]
|
||||
* Operation in place
|
||||
*
|
||||
* Currently unreachable code
|
||||
*
|
||||
* @param player units of this player will be removed
|
||||
*/
|
||||
fun stripPlayer(player: Player) {
|
||||
tileList.forEach {
|
||||
if (it.improvement == startingLocationPrefix + player.chosenCiv) {
|
||||
it.improvement = null
|
||||
}
|
||||
for (unit in it.getUnits()) if (unit.owner == player.chosenCiv) unit.removeFromTile()
|
||||
}
|
||||
startingLocations.removeAll(startingLocations.filter { it.nation == player.chosenCiv }) // filter creates a copy, no concurrent modification
|
||||
startingLocationsByNation.remove(player.chosenCiv)
|
||||
}
|
||||
|
||||
/** Finds all units and starting location of [Player] and changes their [Nation]
|
||||
* Operation in place
|
||||
*
|
||||
* Currently unreachable code
|
||||
*
|
||||
* @param player player whose all units will be changed
|
||||
* @param newNation new nation to be set up
|
||||
*/
|
||||
fun switchPlayersNation(player: Player, newNation: Nation) {
|
||||
val newCiv = CivilizationInfo(newNation.name).apply { nation = newNation }
|
||||
tileList.forEach {
|
||||
if (it.improvement == startingLocationPrefix + player.chosenCiv) {
|
||||
it.improvement = startingLocationPrefix + newNation.name
|
||||
}
|
||||
for (unit in it.getUnits()) if (unit.owner == player.chosenCiv) {
|
||||
unit.owner = newNation.name
|
||||
unit.civInfo = CivilizationInfo(newNation.name).apply { nation = newNation }
|
||||
unit.civInfo = newCiv
|
||||
}
|
||||
}
|
||||
for (element in startingLocations.filter { it.nation != player.chosenCiv }) {
|
||||
startingLocations.remove(element)
|
||||
if (startingLocations.none { it.nation == newNation.name && it.position == element.position })
|
||||
startingLocations.add(StartingLocation(element.position, newNation.name))
|
||||
}
|
||||
setStartingLocationsTransients()
|
||||
}
|
||||
|
||||
/**
|
||||
@ -496,7 +506,7 @@ class TileMap {
|
||||
/**
|
||||
* Scan and remove placeholder improvements from map and build startingLocations from them
|
||||
*/
|
||||
fun translateStartingLocationsFromMap() {
|
||||
private fun translateStartingLocationsFromMap() {
|
||||
startingLocations.clear()
|
||||
tileList.asSequence()
|
||||
.filter { it.improvement?.startsWith(startingLocationPrefix) == true }
|
||||
@ -509,25 +519,22 @@ class TileMap {
|
||||
setStartingLocationsTransients()
|
||||
}
|
||||
|
||||
/**
|
||||
* Place placeholder improvements on the map for the startingLocations entries.
|
||||
*
|
||||
* **For use by the map editor only**
|
||||
*
|
||||
* This is a copy, the startingLocations array and transients are untouched.
|
||||
* Any actual improvements on the tiles will be overwritten.
|
||||
*/
|
||||
fun translateStartingLocationsToMap() {
|
||||
for ((position, nationName) in startingLocations) {
|
||||
get(position).improvement = startingLocationPrefix + nationName
|
||||
}
|
||||
}
|
||||
|
||||
/** Adds a starting position, maintaining the transients */
|
||||
fun addStartingLocation(nationName: String, tile: TileInfo) {
|
||||
/** Adds a starting position, maintaining the transients
|
||||
* @return true if the starting position was not already stored as per [Collection]'s add */
|
||||
fun addStartingLocation(nationName: String, tile: TileInfo): Boolean {
|
||||
if (startingLocationsByNation[nationName]?.contains(tile) == true) return false
|
||||
startingLocations.add(StartingLocation(tile.position, nationName))
|
||||
val nationSet = startingLocationsByNation[nationName] ?: hashSetOf<TileInfo>().also { startingLocationsByNation[nationName] = it }
|
||||
nationSet.add(tile)
|
||||
return nationSet.add(tile)
|
||||
}
|
||||
|
||||
/** Removes a starting position, maintaining the transients
|
||||
* @return true if the starting position was removed as per [Collection]'s remove */
|
||||
fun removeStartingLocation(nationName: String, tile: TileInfo): Boolean {
|
||||
if (startingLocationsByNation[nationName]?.contains(tile) != true) return false
|
||||
startingLocations.remove(StartingLocation(tile.position, nationName))
|
||||
return startingLocationsByNation[nationName]!!.remove(tile)
|
||||
// we do not clean up an empty startingLocationsByNation[nationName] set - not worth it
|
||||
}
|
||||
|
||||
/** Clears starting positions, e.g. after GameStarter is done with them. Does not clear the pseudo-improvements. */
|
||||
|
@ -49,23 +49,21 @@ class GameParameters { // Default values are the default new game
|
||||
return parameters
|
||||
}
|
||||
|
||||
// For debugging and MapGenerator console output
|
||||
override fun toString() = "($difficulty $gameSpeed $startingEra, " +
|
||||
"${players.count { it.playerType == PlayerType.Human }} ${PlayerType.Human} " +
|
||||
"${players.count { it.playerType == PlayerType.AI }} ${PlayerType.AI} " +
|
||||
"$numberOfCityStates CS, " +
|
||||
sequence<String> {
|
||||
// For debugging and GameStarter console output
|
||||
override fun toString() = sequence<String> {
|
||||
yield("$difficulty $gameSpeed $startingEra")
|
||||
yield("${players.count { it.playerType == PlayerType.Human }} ${PlayerType.Human}")
|
||||
yield("${players.count { it.playerType == PlayerType.AI }} ${PlayerType.AI}")
|
||||
yield("$numberOfCityStates CS")
|
||||
if (isOnlineMultiplayer) yield("Online Multiplayer")
|
||||
if (noBarbarians) yield("No barbs")
|
||||
if (oneCityChallenge) yield("OCC")
|
||||
if (!nuclearWeaponsEnabled) yield("No nukes")
|
||||
if (religionEnabled) yield("Religion")
|
||||
if (godMode) yield("God mode")
|
||||
if (VictoryType.Cultural !in victoryTypes) yield("No ${VictoryType.Cultural} Victory")
|
||||
if (VictoryType.Diplomatic in victoryTypes) yield("${VictoryType.Diplomatic} Victory")
|
||||
if (VictoryType.Domination !in victoryTypes) yield("No ${VictoryType.Domination} Victory")
|
||||
if (VictoryType.Scientific !in victoryTypes) yield("No ${VictoryType.Scientific} Victory")
|
||||
}.joinToString() +
|
||||
(if (mods.isEmpty()) ", no mods" else mods.joinToString(",", ", mods=(", ")", 6) ) +
|
||||
")"
|
||||
for (victoryType in VictoryType.values()) {
|
||||
if (victoryType !in victoryTypes) yield("No $victoryType Victory")
|
||||
}
|
||||
yield(if (mods.isEmpty()) "no mods" else mods.joinToString(",", "mods=(", ")", 6) )
|
||||
}.joinToString(prefix = "(", postfix = ")")
|
||||
}
|
@ -61,11 +61,9 @@ class MapEditorOptionsTable(val mapEditorScreen: MapEditorScreen): Table(CameraS
|
||||
|
||||
val sliderTab = Table()
|
||||
|
||||
val slider = Slider(1f, 5f, 1f, false, skin)
|
||||
val sliderLabel = "{Brush Size} $brushSize".toLabel()
|
||||
|
||||
slider.onChange {
|
||||
brushSize = slider.value.toInt()
|
||||
val slider = UncivSlider(1f, 5f, 1f, initial = brushSize.toFloat()) {
|
||||
brushSize = it.toInt()
|
||||
sliderLabel.setText("{Brush Size} $brushSize".tr())
|
||||
}
|
||||
|
||||
@ -153,23 +151,20 @@ class MapEditorOptionsTable(val mapEditorScreen: MapEditorScreen): Table(CameraS
|
||||
}
|
||||
editorPickTable.add(AutoScrollPane(improvementsTable).apply { setScrollingDisabled(true, false) }).height(scrollPanelHeight)
|
||||
|
||||
// Menu for the Starting Locations
|
||||
val nationTable = Table()
|
||||
|
||||
/** old way improvements for all civs
|
||||
* */
|
||||
for (nation in ruleset.nations.values) {
|
||||
if (nation.isSpectator()) continue // no improvements for spectator
|
||||
if (nation.isSpectator() || nation.isBarbarian()) continue // no improvements for spectator
|
||||
|
||||
val nationImage = getHex(ImageGetter.getNationIndicator(nation, 40f))
|
||||
nationImage.onClick {
|
||||
val improvementName = TileMap.startingLocationPrefix + nation.name
|
||||
tileAction = {
|
||||
it.improvement = improvementName
|
||||
for ((tileInfo, tileGroups) in mapEditorScreen.mapHolder.tileGroups) {
|
||||
if (tileInfo.improvement == improvementName && tileInfo != it)
|
||||
tileInfo.improvement = null
|
||||
tileInfo.setTerrainTransients()
|
||||
tileGroups.forEach { it.update() }
|
||||
mapEditorScreen.tileMap.apply {
|
||||
// toggle the starting location here, note this allows
|
||||
// both multiple locations per nation and multiple nations per tile
|
||||
if (!addStartingLocation(nation.name, it))
|
||||
removeStartingLocation(nation.name, it)
|
||||
}
|
||||
}
|
||||
|
||||
@ -182,6 +177,7 @@ class MapEditorOptionsTable(val mapEditorScreen: MapEditorScreen): Table(CameraS
|
||||
editorPickTable.add(AutoScrollPane(nationTable).apply { setScrollingDisabled(true, false) }).height(scrollPanelHeight)
|
||||
}
|
||||
|
||||
/** currently unused */
|
||||
fun setUnits() {
|
||||
editorPickTable.clear()
|
||||
|
||||
|
@ -36,7 +36,6 @@ class MapEditorScreen(): CameraStageBaseScreen() {
|
||||
ImageGetter.setNewRuleset(ruleset)
|
||||
tileMap.setTransients(ruleset,false)
|
||||
tileMap.setStartingLocationsTransients()
|
||||
tileMap.translateStartingLocationsToMap()
|
||||
UncivGame.Current.translations.translationActiveMods = ruleset.mods
|
||||
|
||||
mapHolder = EditorMapHolder(this, tileMap)
|
||||
|
@ -182,8 +182,8 @@ class SaveAndLoadMapScreen(mapToSave: TileMap?, save:Boolean = false, previousSc
|
||||
}
|
||||
}
|
||||
|
||||
fun getMapCloneForSave(mapToSave: TileMap) = mapToSave!!.clone().also {
|
||||
it.setTransients(setUnitCivTransients = false)
|
||||
it.translateStartingLocationsFromMap()
|
||||
private fun getMapCloneForSave(mapToSave: TileMap) =
|
||||
mapToSave.clone().apply {
|
||||
setTransients(setUnitCivTransients = false)
|
||||
}
|
||||
}
|
||||
|
@ -332,15 +332,6 @@ open class TileGroup(var tileInfo: TileInfo, var tileSetStrings:TileSetStrings,
|
||||
}
|
||||
|
||||
private fun removeMissingModReferences() {
|
||||
// This runs from map editor too, so the Pseudo-improvements for starting locations need to stay.
|
||||
// The nations can be checked.
|
||||
val improvementName = tileInfo.improvement
|
||||
if (improvementName != null && improvementName.startsWith(TileMap.startingLocationPrefix)) {
|
||||
val nationName = improvementName.removePrefix(TileMap.startingLocationPrefix)
|
||||
if (!tileInfo.ruleset.nations.containsKey(nationName))
|
||||
tileInfo.improvement = null
|
||||
}
|
||||
|
||||
for (unit in tileInfo.getUnits())
|
||||
if (!tileInfo.ruleset.nations.containsKey(unit.owner)) unit.removeFromTile()
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ class TileGroupIcons(val tileGroup: TileGroup) {
|
||||
|
||||
var improvementIcon: Actor? = null
|
||||
var populationIcon: Image? = null //reuse for acquire icon
|
||||
val startingLocationIcons = mutableListOf<Actor>()
|
||||
|
||||
var civilianUnitIcon: UnitGroup? = null
|
||||
var militaryUnitIcon: UnitGroup? = null
|
||||
@ -22,6 +23,7 @@ class TileGroupIcons(val tileGroup: TileGroup) {
|
||||
fun update(showResourcesAndImprovements: Boolean, showTileYields: Boolean, tileIsViewable: Boolean, showMilitaryUnit: Boolean, viewingCiv: CivilizationInfo?) {
|
||||
updateResourceIcon(showResourcesAndImprovements)
|
||||
updateImprovementIcon(showResourcesAndImprovements)
|
||||
updateStartingLocationIcon(showResourcesAndImprovements)
|
||||
|
||||
if (viewingCiv != null) updateYieldIcon(showTileYields, viewingCiv)
|
||||
|
||||
@ -49,7 +51,7 @@ class TileGroupIcons(val tileGroup: TileGroup) {
|
||||
}
|
||||
|
||||
|
||||
fun newUnitIcon(unit: MapUnit?, oldUnitGroup: UnitGroup?, isViewable: Boolean, yFromCenter: Float, viewingCiv: CivilizationInfo?): UnitGroup? {
|
||||
private fun newUnitIcon(unit: MapUnit?, oldUnitGroup: UnitGroup?, isViewable: Boolean, yFromCenter: Float, viewingCiv: CivilizationInfo?): UnitGroup? {
|
||||
var newImage: UnitGroup? = null
|
||||
// The unit can change within one update - for instance, when attacking, the attacker replaces the defender!
|
||||
oldUnitGroup?.unitBaseImage?.remove()
|
||||
@ -101,11 +103,11 @@ class TileGroupIcons(val tileGroup: TileGroup) {
|
||||
}
|
||||
|
||||
|
||||
fun updateImprovementIcon(showResourcesAndImprovements: Boolean) {
|
||||
private fun updateImprovementIcon(showResourcesAndImprovements: Boolean) {
|
||||
improvementIcon?.remove()
|
||||
improvementIcon = null
|
||||
if (tileGroup.tileInfo.improvement == null || !showResourcesAndImprovements) return
|
||||
|
||||
if (tileGroup.tileInfo.improvement != null && showResourcesAndImprovements) {
|
||||
val newImprovementImage = ImageGetter.getImprovementIcon(tileGroup.tileInfo.improvement!!)
|
||||
tileGroup.miscLayerGroup.addActor(newImprovementImage)
|
||||
newImprovementImage.run {
|
||||
@ -113,13 +115,10 @@ class TileGroupIcons(val tileGroup: TileGroup) {
|
||||
center(tileGroup)
|
||||
this.x -= 22 // left
|
||||
this.y -= 10 // bottom
|
||||
color = Color.WHITE.cpy().apply { a = 0.7f }
|
||||
}
|
||||
improvementIcon = newImprovementImage
|
||||
}
|
||||
if (improvementIcon != null) {
|
||||
improvementIcon!!.color = Color.WHITE.cpy().apply { a = 0.7f }
|
||||
}
|
||||
}
|
||||
|
||||
// JN updating display of tile yields
|
||||
private fun updateYieldIcon(showTileYields: Boolean, viewingCiv: CivilizationInfo) {
|
||||
@ -144,7 +143,7 @@ class TileGroupIcons(val tileGroup: TileGroup) {
|
||||
}
|
||||
|
||||
|
||||
fun updateResourceIcon(showResourcesAndImprovements: Boolean) {
|
||||
private fun updateResourceIcon(showResourcesAndImprovements: Boolean) {
|
||||
if (tileGroup.resource != tileGroup.tileInfo.resource) {
|
||||
tileGroup.resource = tileGroup.tileInfo.resource
|
||||
tileGroup.resourceImage?.remove()
|
||||
@ -169,4 +168,39 @@ class TileGroupIcons(val tileGroup: TileGroup) {
|
||||
}
|
||||
|
||||
|
||||
private fun updateStartingLocationIcon(showResourcesAndImprovements: Boolean) {
|
||||
// these are visible in map editor only, but making that bit available here seems overkill
|
||||
|
||||
startingLocationIcons.forEach { it.remove() }
|
||||
startingLocationIcons.clear()
|
||||
if (!showResourcesAndImprovements) return
|
||||
if (tileGroup.forMapEditorIcon) return // the editor options for terrain do not bother to fully initialize, so tileInfo.tileMap would be an uninitialized lateinit
|
||||
|
||||
// Allow display of up to three nations starting locations on the same tile, ignore rest
|
||||
// The sort is just so it shows _some_ deterministic behaviour, otherwise you could get
|
||||
// different stacking order of the same nations in the same editing session
|
||||
val tileInfo = tileGroup.tileInfo
|
||||
val nations = tileInfo.tileMap.startingLocationsByNation.asSequence()
|
||||
.filter { tileInfo in it.value }.map { it.key }.take(3)
|
||||
.sorted().toList()
|
||||
if (nations.isEmpty()) return
|
||||
|
||||
var offsetX = (nations.size - 1) * 4f
|
||||
var offsetY = (nations.size - 1) * 2f
|
||||
for (nation in nations) {
|
||||
val newNationIcon =
|
||||
ImageGetter.getNationIndicator(ImageGetter.ruleset.nations[nation]!!, 20f)
|
||||
tileGroup.miscLayerGroup.addActor(newNationIcon)
|
||||
newNationIcon.run {
|
||||
setSize(20f, 20f)
|
||||
center(tileGroup)
|
||||
x += offsetX
|
||||
y += offsetY
|
||||
color = Color.WHITE.cpy().apply { a = 0.6f }
|
||||
}
|
||||
startingLocationIcons.add(newNationIcon)
|
||||
offsetX -= 8f
|
||||
offsetY -= 4f
|
||||
}
|
||||
}
|
||||
}
|
@ -254,11 +254,6 @@ object ImageGetter {
|
||||
fun getImprovementIcon(improvementName: String, size: Float = 20f): Actor {
|
||||
if (improvementName.startsWith("Remove") || improvementName == Constants.cancelImprovementOrder)
|
||||
return Table().apply { add(getImage("OtherIcons/Stop")).size(size) }
|
||||
if (improvementName.startsWith(TileMap.startingLocationPrefix)) {
|
||||
val nationName = improvementName.removePrefix(TileMap.startingLocationPrefix)
|
||||
val nation = ruleset.nations[nationName]!!
|
||||
return getNationIndicator(nation, size)
|
||||
}
|
||||
|
||||
val iconGroup = getImage("ImprovementIcons/$improvementName").surroundWithCircle(size)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user