From d668c5dceb214c0851a3c845baa01ff246e30f65 Mon Sep 17 00:00:00 2001 From: Oskar Niesen Date: Mon, 21 Aug 2023 14:42:14 -0500 Subject: [PATCH] General Starting locations in map editor (#9920) * Added an Any Civ starting location brush. * Fixed the Remove starting locations brush from being too long. * Civs without a specific starting location given to them now use the spectator starting locations before finding a free tile. * Removed spectator from civilizations to give a starting location. * Added comments * Removed accidentally added import statements. * Added new display text to template.properties * Replaced an inline when statement with an if statement. * Fixed not having a space after a translation. * Moved finding a starting location to a new function. * Fixed GameStarter.getCivStartingLocation to return a null if it couldn't find a tile to start on. --- .../jsons/translations/template.properties | 2 ++ core/src/com/unciv/logic/GameStarter.kt | 36 ++++++++++++++----- .../tabs/MapEditorEditSubTabs.kt | 14 +++++--- 3 files changed, 39 insertions(+), 13 deletions(-) diff --git a/android/assets/jsons/translations/template.properties b/android/assets/jsons/translations/template.properties index 1ac5768867..e6a8f816d2 100644 --- a/android/assets/jsons/translations/template.properties +++ b/android/assets/jsons/translations/template.properties @@ -546,6 +546,8 @@ Spread Resources = Create ancient ruins = Floodfill = [nation] starting location = +Any Civ starting locations = +Any Civ = Remove features = Remove improvement = Remove resource = diff --git a/core/src/com/unciv/logic/GameStarter.kt b/core/src/com/unciv/logic/GameStarter.kt index 3aa52f3bad..570af24928 100644 --- a/core/src/com/unciv/logic/GameStarter.kt +++ b/core/src/com/unciv/logic/GameStarter.kt @@ -384,7 +384,8 @@ object GameStarter { // First we get start locations for the major civs, on the second pass the city states (without predetermined starts) can squeeze in wherever val civNamesWithStartingLocations = tileMap.startingLocationsByNation.keys - val bestCivs = allCivs.filter { !it.isCityState() || it.civName in civNamesWithStartingLocations } + val bestCivs = allCivs.filter { (!it.isCityState() || it.civName in civNamesWithStartingLocations) + && !it.isSpectator()} val bestLocations = getStartingLocations(bestCivs, tileMap, landTilesInBigEnoughGroup, startScores) for ((civ, tile) in bestLocations) { // A nation can have multiple marked starting locations, of which the first pass may have chosen one @@ -538,7 +539,7 @@ object GameStarter { ): HashMap { val civsOrderedByAvailableLocations = getCivsOrderedByAvailableLocations(civs, tileMap) - + for (minimumDistanceBetweenStartingLocations in tileMap.tileMatrix.size / 6 downTo 0) { val freeTiles = getFreeTiles(tileMap, landTilesInBigEnoughGroup, minimumDistanceBetweenStartingLocations) @@ -580,21 +581,38 @@ object GameStarter { ): HashMap? { val startingLocations = HashMap() for (civ in civsOrderedByAvailableLocations) { + + val startingLocation = getCivStartingLocation(civ, tileMap, freeTiles, startScores) + startingLocation ?: break + + startingLocations[civ] = startingLocation + val distanceToNext = minimumDistanceBetweenStartingLocations / (if (civ.isCityState()) 2 else 1) // We allow city states to squeeze in tighter - val presetStartingLocation = tileMap.startingLocationsByNation[civ.civName]?.randomOrNull() - val startingLocation = if (presetStartingLocation != null) presetStartingLocation - else { - if (freeTiles.isEmpty()) break // we failed to get all the starting tiles with this minimum distance - getOneStartingLocation(civ, tileMap, freeTiles, startScores) - } - startingLocations[civ] = startingLocation freeTiles.removeAll(tileMap.getTilesInDistance(startingLocation.position, distanceToNext) .toSet()) } return if (startingLocations.size < civsOrderedByAvailableLocations.size) null else startingLocations } + private fun getCivStartingLocation( + civ: Civilization, + tileMap: TileMap, + freeTiles: MutableList, + startScores: HashMap, + ): Tile? { + var startingLocation = tileMap.startingLocationsByNation[civ.civName]?.randomOrNull() + if (startingLocation == null) { + startingLocation = tileMap.startingLocationsByNation[Constants.spectator]?.randomOrNull() + if (startingLocation != null) { + tileMap.startingLocationsByNation[Constants.spectator]?.remove(startingLocation) + } + } + if (startingLocation == null && freeTiles.isNotEmpty()) + startingLocation = getOneStartingLocation(civ, tileMap, freeTiles, startScores) + // If startingLocation is null we failed to get all the starting tiles with this minimum distance + return startingLocation + } private fun getOneStartingLocation( civ: Civilization, diff --git a/core/src/com/unciv/ui/screens/mapeditorscreen/tabs/MapEditorEditSubTabs.kt b/core/src/com/unciv/ui/screens/mapeditorscreen/tabs/MapEditorEditSubTabs.kt index 933dccfd80..c529ac0278 100644 --- a/core/src/com/unciv/ui/screens/mapeditorscreen/tabs/MapEditorEditSubTabs.kt +++ b/core/src/com/unciv/ui/screens/mapeditorscreen/tabs/MapEditorEditSubTabs.kt @@ -281,18 +281,24 @@ class MapEditorEditStartsTab( val eraserIcon = "Nation/${firstNation.name}" val eraser = FormattedLine("Remove starting locations", icon = eraserIcon, size = 24, iconCrossed = true) add(eraser.render(0f).apply { onClick { - editTab.setBrush(BrushHandlerType.Direct, "Remove starting locations", eraserIcon, true) { tile -> + editTab.setBrush(BrushHandlerType.Direct, "Remove", eraserIcon, true) { tile -> tile.tileMap.removeStartingLocations(tile.position) } } }).padBottom(0f).row() - + // Create the nation list with the spectator nation included + // We use Nation/Spectator because it hasn't been used yet and we need an icon within the Nation. + val anyCiv = FormattedLine("Any Civ starting location", Constants.spectator, "Nation/Spectator", size = 24) + val nations = getNations().toList() + val nationsToAdd = ArrayList(1 + nations.count()) + nationsToAdd.add((anyCiv)) // An Civ starting location should be first + nationsToAdd.addAll(nations) add( MarkupRenderer.render( - getNations(), + nationsToAdd, iconDisplay = FormattedLine.IconDisplay.NoLink ) { UncivGame.Current.musicController.chooseTrack(it, MusicMood.Theme, MusicTrackChooserFlags.setSpecific) - editTab.setBrush(BrushHandlerType.Direct, it, "Nation/$it") { tile -> + editTab.setBrush(BrushHandlerType.Direct, if (it ==Constants.spectator) "Any Civ" else it, "Nation/$it") { tile -> // toggle the starting location here, note this allows // both multiple locations per nation and multiple nations per tile if (!tile.tileMap.addStartingLocation(it, tile))