mirror of
https://github.com/yairm210/Unciv.git
synced 2025-01-05 21:11:35 +07:00
Improved Console autocomplete (#10962)
* Console: History remembers only _changed_ command lines * Console: New command sethealth, allow setmovement without argument to set max movement * Console: All object name comparisons on the "CliInput" level so multiword or varying-case input is recognized properly * Console: Autocomplete change so continuation is easier: Don't add space if there were alternatives, output CliInput-style * Console: Autocomplete religions - only from the actually founded ones (but we could easily add ruleset.religions - a '+' would be distinct already) * Console: Intelligent autocomplete promotions in `unit addpromotion` * Console: Treat all warnings * Console: Split off a few classes * Console: Forgot to treat a reminder - fix crash on `unit addp<tab><tab>` * Console: setterrain, setresource, consequences of tile changes * Console: Revert normalizeToRuleset 'safety net' calls
This commit is contained in:
parent
fe111edf30
commit
6fad057ced
@ -0,0 +1,73 @@
|
||||
package com.unciv.ui.screens.devconsole
|
||||
|
||||
class ConsoleCityCommands : ConsoleCommandNode {
|
||||
override val subcommands = hashMapOf<String, ConsoleCommand>(
|
||||
|
||||
"add" to ConsoleAction("city add <civName>") { console, params ->
|
||||
val civ = console.getCivByName(params[0])
|
||||
val selectedTile = console.getSelectedTile()
|
||||
if (selectedTile.isCityCenter())
|
||||
throw ConsoleErrorException("Tile already contains a city center")
|
||||
civ.addCity(selectedTile.position)
|
||||
DevConsoleResponse.OK
|
||||
},
|
||||
|
||||
"remove" to ConsoleAction("city remove") { console, _ ->
|
||||
val city = console.getSelectedCity()
|
||||
city.destroyCity(overrideSafeties = true)
|
||||
DevConsoleResponse.OK
|
||||
},
|
||||
|
||||
"setpop" to ConsoleAction("city setpop <amount>") { console, params ->
|
||||
val city = console.getSelectedCity()
|
||||
val newPop = console.getInt(params[0])
|
||||
if (newPop < 1) throw ConsoleErrorException("Population must be at least 1")
|
||||
city.population.setPopulation(newPop)
|
||||
DevConsoleResponse.OK
|
||||
},
|
||||
|
||||
"setname" to ConsoleAction("city setname <\"name\">") { console, params ->
|
||||
val city = console.getSelectedCity()
|
||||
city.name = params[0]
|
||||
DevConsoleResponse.OK
|
||||
},
|
||||
|
||||
"addtile" to ConsoleAction("city addtile <cityName>") { console, params ->
|
||||
val selectedTile = console.getSelectedTile()
|
||||
val city = console.getCity(params[0])
|
||||
if (selectedTile.neighbors.none { it.getCity() == city })
|
||||
throw ConsoleErrorException("Tile is not adjacent to any tile already owned by the city")
|
||||
if (selectedTile.isCityCenter()) throw ConsoleErrorException("Cannot tranfer city center")
|
||||
city.expansion.takeOwnership(selectedTile)
|
||||
DevConsoleResponse.OK
|
||||
},
|
||||
|
||||
"removetile" to ConsoleAction("city removetile") { console, _ ->
|
||||
val selectedTile = console.getSelectedTile()
|
||||
val city = console.getSelectedCity()
|
||||
city.expansion.relinquishOwnership(selectedTile)
|
||||
DevConsoleResponse.OK
|
||||
},
|
||||
|
||||
"religion" to ConsoleAction("city religion <religionName> <±pressure>") { console, params ->
|
||||
val city = console.getSelectedCity()
|
||||
val religion = city.civ.gameInfo.religions.keys.findCliInput(params[0])
|
||||
?: throw ConsoleErrorException("'${params[0]}' is not a known religion")
|
||||
val pressure = console.getInt(params[1])
|
||||
city.religion.addPressure(religion, pressure.coerceAtLeast(-city.religion.getPressures()[religion]))
|
||||
city.religion.updatePressureOnPopulationChange(0)
|
||||
DevConsoleResponse.OK
|
||||
},
|
||||
|
||||
"sethealth" to ConsoleAction("city sethealth [amount]") { console, params ->
|
||||
val city = console.getSelectedCity()
|
||||
val maxHealth = city.getMaxHealth()
|
||||
val health = params.firstOrNull()?.run {
|
||||
toIntOrNull() ?: throw ConsoleErrorException("Invalid number")
|
||||
} ?: maxHealth
|
||||
if (health !in 1..maxHealth) throw ConsoleErrorException("Number out of range")
|
||||
city.health = health
|
||||
DevConsoleResponse.OK
|
||||
},
|
||||
)
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
package com.unciv.ui.screens.devconsole
|
||||
|
||||
import com.unciv.logic.civilization.PlayerType
|
||||
import com.unciv.models.ruleset.unique.Unique
|
||||
import com.unciv.models.ruleset.unique.UniqueTriggerActivation
|
||||
import com.unciv.models.stats.Stat
|
||||
|
||||
class ConsoleCivCommands : ConsoleCommandNode {
|
||||
override val subcommands = hashMapOf<String, ConsoleCommand>(
|
||||
"addstat" to ConsoleAction("civ addstat <stat> <amount> [civ]") { console, params ->
|
||||
val stat = Stat.safeValueOf(params[0].replaceFirstChar(Char::titlecase))
|
||||
?: throw ConsoleErrorException("\"${params[0]}\" is not an acceptable Stat")
|
||||
if (stat !in Stat.statsWithCivWideField)
|
||||
throw ConsoleErrorException("$stat is not civ-wide")
|
||||
|
||||
val amount = console.getInt(params[1])
|
||||
|
||||
val civ = if (params.size == 2) console.screen.selectedCiv
|
||||
else console.getCivByName(params[2])
|
||||
|
||||
civ.addStat(stat, amount)
|
||||
DevConsoleResponse.OK
|
||||
},
|
||||
|
||||
"setplayertype" to ConsoleAction("civ setplayertype <civName> <ai/human>") { console, params ->
|
||||
val civ = console.getCivByName(params[0])
|
||||
val playerType = PlayerType.values().firstOrNull { it.name.lowercase() == params[1].lowercase() }
|
||||
?: throw ConsoleErrorException("Invalid player type, valid options are 'ai' or 'human'")
|
||||
civ.playerType = playerType
|
||||
DevConsoleResponse.OK
|
||||
},
|
||||
|
||||
"revealmap" to ConsoleAction("civ revealmap <civName>") { console, params ->
|
||||
val civ = console.getCivByName(params[0])
|
||||
civ.gameInfo.tileMap.values.asSequence()
|
||||
.forEach { it.setExplored(civ, true) }
|
||||
DevConsoleResponse.OK
|
||||
},
|
||||
|
||||
"activatetrigger" to ConsoleAction("civ activatetrigger <civName> <\"trigger\">") { console, params ->
|
||||
val civ = console.getCivByName(params[0])
|
||||
val unique = Unique(params[1])
|
||||
if (unique.type == null) throw ConsoleErrorException("Unrecognized trigger")
|
||||
val tile = console.screen.mapHolder.selectedTile
|
||||
val city = tile?.getCity()
|
||||
UniqueTriggerActivation.triggerCivwideUnique(unique, civ, city, tile)
|
||||
DevConsoleResponse.OK
|
||||
}
|
||||
)
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
package com.unciv.ui.screens.devconsole
|
||||
|
||||
import com.unciv.logic.civilization.Civilization
|
||||
import com.unciv.logic.map.tile.RoadStatus
|
||||
import com.unciv.models.ruleset.tile.TerrainType
|
||||
|
||||
class ConsoleTileCommands: ConsoleCommandNode {
|
||||
// Note: We *don't* call `TileInfoNormalizer.normalizeToRuleset(selectedTile, console.gameInfo.ruleset)`
|
||||
// - we want the console to allow invalid tile configurations.
|
||||
|
||||
override val subcommands = hashMapOf<String, ConsoleCommand>(
|
||||
|
||||
"setimprovement" to ConsoleAction("tile setimprovement <improvementName> [civName]") { console, params ->
|
||||
val selectedTile = console.getSelectedTile()
|
||||
val improvement = console.gameInfo.ruleset.tileImprovements.values.findCliInput(params[0])
|
||||
?: throw ConsoleErrorException("Unknown improvement")
|
||||
var civ: Civilization? = null
|
||||
if (params.size == 2) {
|
||||
civ = console.getCivByName(params[1])
|
||||
}
|
||||
selectedTile.improvementFunctions.changeImprovement(improvement.name, civ)
|
||||
selectedTile.getCity()?.reassignPopulation()
|
||||
DevConsoleResponse.OK
|
||||
},
|
||||
|
||||
"removeimprovement" to ConsoleAction("tile removeimprovement") { console, _ ->
|
||||
val selectedTile = console.getSelectedTile()
|
||||
selectedTile.improvementFunctions.changeImprovement(null)
|
||||
selectedTile.getCity()?.reassignPopulation()
|
||||
DevConsoleResponse.OK
|
||||
},
|
||||
|
||||
"removeroad" to ConsoleAction("tile removeroad") { console, _ ->
|
||||
val selectedTile = console.getSelectedTile()
|
||||
selectedTile.roadStatus = RoadStatus.None
|
||||
//todo this covers many cases but not all - do we really need to loop over all civs?
|
||||
selectedTile.getOwner()?.cache?.updateCitiesConnectedToCapital()
|
||||
DevConsoleResponse.OK
|
||||
},
|
||||
|
||||
"addfeature" to ConsoleAction("tile addfeature <featureName>") { console, params ->
|
||||
val selectedTile = console.getSelectedTile()
|
||||
val feature = getTerrainFeature(console, params[0])
|
||||
selectedTile.addTerrainFeature(feature.name)
|
||||
selectedTile.getCity()?.reassignPopulation()
|
||||
DevConsoleResponse.OK
|
||||
},
|
||||
|
||||
"removefeature" to ConsoleAction("tile addfeature <featureName>") { console, params ->
|
||||
val selectedTile = console.getSelectedTile()
|
||||
val feature = getTerrainFeature(console, params[0])
|
||||
selectedTile.removeTerrainFeature(feature.name)
|
||||
selectedTile.getCity()?.reassignPopulation()
|
||||
DevConsoleResponse.OK
|
||||
},
|
||||
|
||||
"setterrain" to ConsoleAction("tile setterrain <terrainName>") { console, params ->
|
||||
val selectedTile = console.getSelectedTile()
|
||||
val terrain = console.gameInfo.ruleset.terrains.values.findCliInput(params[0])
|
||||
?: throw ConsoleErrorException("Unknown terrain")
|
||||
if (terrain.type != selectedTile.getBaseTerrain().type)
|
||||
throw ConsoleErrorException("Changing terrain type is not allowed")
|
||||
selectedTile.baseTerrain = terrain.name
|
||||
selectedTile.setTerrainTransients()
|
||||
selectedTile.getCity()?.reassignPopulation()
|
||||
DevConsoleResponse.OK
|
||||
},
|
||||
|
||||
"setresource" to ConsoleAction("tile setresource <resourceName>") { console, params ->
|
||||
val selectedTile = console.getSelectedTile()
|
||||
val resource = console.gameInfo.ruleset.tileResources.values.findCliInput(params[0])
|
||||
?: throw ConsoleErrorException("Unknown resource")
|
||||
selectedTile.resource = resource.name
|
||||
selectedTile.setTerrainTransients()
|
||||
selectedTile.getCity()?.reassignPopulation()
|
||||
DevConsoleResponse.OK
|
||||
},
|
||||
|
||||
"removeresource" to ConsoleAction("tile removeresource") { console, _ ->
|
||||
val selectedTile = console.getSelectedTile()
|
||||
selectedTile.resource = null
|
||||
selectedTile.setTerrainTransients()
|
||||
selectedTile.getCity()?.reassignPopulation()
|
||||
DevConsoleResponse.OK
|
||||
},
|
||||
|
||||
)
|
||||
|
||||
private fun getTerrainFeature(console: DevConsolePopup, param: String) =
|
||||
console.gameInfo.ruleset.terrains.values.asSequence()
|
||||
.filter { it.type == TerrainType.TerrainFeature }.findCliInput(param)
|
||||
?: throw ConsoleErrorException("Unknown feature")
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
package com.unciv.ui.screens.devconsole
|
||||
|
||||
class ConsoleUnitCommands : ConsoleCommandNode {
|
||||
override val subcommands = hashMapOf<String, ConsoleCommand>(
|
||||
|
||||
"add" to ConsoleAction("unit add <civName> <unitName>") { console, params ->
|
||||
val selectedTile = console.getSelectedTile()
|
||||
val civ = console.getCivByName(params[0])
|
||||
val baseUnit = console.gameInfo.ruleset.units.values.findCliInput(params[1])
|
||||
?: throw ConsoleErrorException("Unknown unit")
|
||||
civ.units.placeUnitNearTile(selectedTile.position, baseUnit)
|
||||
DevConsoleResponse.OK
|
||||
},
|
||||
|
||||
"remove" to ConsoleAction("unit remove") { console, _ ->
|
||||
val unit = console.getSelectedUnit()
|
||||
unit.destroy()
|
||||
DevConsoleResponse.OK
|
||||
},
|
||||
|
||||
"addpromotion" to object : ConsoleAction("unit addpromotion <promotionName>", { console, params ->
|
||||
val unit = console.getSelectedUnit()
|
||||
val promotion = console.gameInfo.ruleset.unitPromotions.values.findCliInput(params[0])
|
||||
?: throw ConsoleErrorException("Unknown promotion")
|
||||
unit.promotions.addPromotion(promotion.name, true)
|
||||
DevConsoleResponse.OK
|
||||
}) {
|
||||
override fun autocomplete(console: DevConsolePopup, params: List<String>): String? {
|
||||
if (params.isEmpty()) return null
|
||||
val promotions = console.getSelectedUnit().promotions.promotions
|
||||
val options = console.gameInfo.ruleset.unitPromotions.keys.asSequence()
|
||||
.filter { it !in promotions }
|
||||
.asIterable()
|
||||
return getAutocompleteString(params.last(), options)
|
||||
}
|
||||
},
|
||||
|
||||
"removepromotion" to ConsoleAction("unit removepromotion <promotionName>") { console, params ->
|
||||
val unit = console.getSelectedUnit()
|
||||
val promotion = unit.promotions.getPromotions().findCliInput(params[0])
|
||||
?: throw ConsoleErrorException("Promotion not found on unit")
|
||||
// No such action in-game so we need to manually update
|
||||
unit.promotions.promotions.remove(promotion.name)
|
||||
unit.updateUniques()
|
||||
unit.updateVisibleTiles()
|
||||
DevConsoleResponse.OK
|
||||
},
|
||||
|
||||
"setmovement" to ConsoleAction("unit setmovement [amount]") { console, params ->
|
||||
// Note amount defaults to maxMovement, but is not limited by it - it's an arbitrary choice to allow that
|
||||
val unit = console.getSelectedUnit()
|
||||
val movement = params.firstOrNull()?.run {
|
||||
toFloatOrNull() ?: throw ConsoleErrorException("Invalid number")
|
||||
} ?: unit.getMaxMovement().toFloat()
|
||||
if (movement < 0f) throw ConsoleErrorException("Number out of range")
|
||||
unit.currentMovement = movement
|
||||
DevConsoleResponse.OK
|
||||
},
|
||||
|
||||
"sethealth" to ConsoleAction("unit sethealth [amount]") { console, params ->
|
||||
val health = params.firstOrNull()?.run {
|
||||
toIntOrNull() ?: throw ConsoleErrorException("Invalid number")
|
||||
} ?: 100
|
||||
if (health !in 1..100) throw ConsoleErrorException("Number out of range")
|
||||
val unit = console.getSelectedUnit()
|
||||
unit.health = health
|
||||
DevConsoleResponse.OK
|
||||
}
|
||||
)
|
||||
}
|
@ -1,20 +1,26 @@
|
||||
package com.unciv.ui.screens.devconsole
|
||||
|
||||
import com.unciv.logic.civilization.Civilization
|
||||
import com.unciv.logic.civilization.PlayerType
|
||||
import com.unciv.logic.map.tile.RoadStatus
|
||||
import com.unciv.models.ruleset.IRulesetObject
|
||||
import com.unciv.models.ruleset.tile.TerrainType
|
||||
import com.unciv.models.ruleset.unique.Unique
|
||||
import com.unciv.models.ruleset.unique.UniqueTriggerActivation
|
||||
import com.unciv.models.stats.Stat
|
||||
|
||||
internal fun String.toCliInput() = this.lowercase().replace(" ","-")
|
||||
|
||||
internal fun Iterable<String>.findCliInput(param: String): String? {
|
||||
val paramCli = param.toCliInput()
|
||||
return firstOrNull { it.toCliInput() == paramCli }
|
||||
}
|
||||
internal fun <T: IRulesetObject> Iterable<T>.findCliInput(param: String): T? {
|
||||
val paramCli = param.toCliInput()
|
||||
return firstOrNull { it.name.toCliInput() == paramCli }
|
||||
}
|
||||
internal fun <T: IRulesetObject> Sequence<T>.findCliInput(param: String) = asIterable().findCliInput(param)
|
||||
|
||||
/** Returns the string to *add* to the existing command */
|
||||
fun getAutocompleteString(lastWord: String, allOptions: Collection<String>):String? {
|
||||
val matchingOptions = allOptions.filter { it.toCliInput().startsWith(lastWord.toCliInput()) }
|
||||
internal fun getAutocompleteString(lastWord: String, allOptions: Iterable<String>):String? {
|
||||
val matchingOptions = allOptions.map { it.toCliInput() }.filter { it.startsWith(lastWord.toCliInput()) }
|
||||
if (matchingOptions.isEmpty()) return null
|
||||
if (matchingOptions.size == 1) return matchingOptions.first().drop(lastWord.length)
|
||||
if (matchingOptions.size == 1) return matchingOptions.first().drop(lastWord.length) + " "
|
||||
|
||||
val firstOption = matchingOptions.first()
|
||||
for ((index, char) in firstOption.withIndex()) {
|
||||
@ -22,19 +28,22 @@ fun getAutocompleteString(lastWord: String, allOptions: Collection<String>):Stri
|
||||
matchingOptions.any { it[index] != char })
|
||||
return firstOption.substring(0, index).drop(lastWord.length)
|
||||
}
|
||||
return firstOption.drop(lastWord.length)
|
||||
return firstOption.drop(lastWord.length) // don't add space, e.g. found drill-i and user might want drill-ii
|
||||
}
|
||||
|
||||
interface ConsoleCommand {
|
||||
fun handle(console: DevConsolePopup, params: List<String>): DevConsoleResponse
|
||||
/** Returns the string to *add* to the existing command */
|
||||
/** Returns the string to *add* to the existing command.
|
||||
* The function should add a space at the end if and only if the "match" is an unambiguous choice!
|
||||
* Returning `null` means there was no match at all, while returning an empty string means the last word is a match as-is.
|
||||
*/
|
||||
fun autocomplete(console: DevConsolePopup, params: List<String>): String? = ""
|
||||
}
|
||||
|
||||
class ConsoleHintException(val hint:String):Exception()
|
||||
class ConsoleErrorException(val error:String):Exception()
|
||||
class ConsoleHintException(val hint: String) : Exception()
|
||||
class ConsoleErrorException(val error: String) : Exception()
|
||||
|
||||
class ConsoleAction(val format: String, val action: (console: DevConsolePopup, params: List<String>) -> DevConsoleResponse) : ConsoleCommand {
|
||||
open class ConsoleAction(val format: String, val action: (console: DevConsolePopup, params: List<String>) -> DevConsoleResponse) : ConsoleCommand {
|
||||
override fun handle(console: DevConsolePopup, params: List<String>): DevConsoleResponse {
|
||||
return try {
|
||||
validateFormat(format, params)
|
||||
@ -62,7 +71,10 @@ class ConsoleAction(val format: String, val action: (console: DevConsolePopup, p
|
||||
"promotionName" -> console.gameInfo.ruleset.unitPromotions.keys
|
||||
"improvementName" -> console.gameInfo.ruleset.tileImprovements.keys
|
||||
"featureName" -> console.gameInfo.ruleset.terrains.values.filter { it.type == TerrainType.TerrainFeature }.map { it.name }
|
||||
"terrainName" -> console.gameInfo.ruleset.terrains.values.filter { it.type.isBaseTerrain }.map { it.name }
|
||||
"resourceName" -> console.gameInfo.ruleset.tileResources.keys
|
||||
"stat" -> Stat.names()
|
||||
"religionName" -> console.gameInfo.religions.keys
|
||||
else -> listOf()
|
||||
}
|
||||
return getAutocompleteString(lastParam, options)
|
||||
@ -104,203 +116,3 @@ class ConsoleCommandRoot : ConsoleCommandNode {
|
||||
"civ" to ConsoleCivCommands()
|
||||
)
|
||||
}
|
||||
|
||||
class ConsoleUnitCommands : ConsoleCommandNode {
|
||||
override val subcommands = hashMapOf<String, ConsoleCommand>(
|
||||
|
||||
"add" to ConsoleAction("unit add <civName> <unitName>") { console, params ->
|
||||
val selectedTile = console.getSelectedTile()
|
||||
val civ = console.getCivByName(params[0])
|
||||
val baseUnit = console.gameInfo.ruleset.units.values.firstOrNull { it.name.toCliInput() == params[1].toCliInput() }
|
||||
?: throw ConsoleErrorException("Unknown unit")
|
||||
civ.units.placeUnitNearTile(selectedTile.position, baseUnit)
|
||||
DevConsoleResponse.OK
|
||||
},
|
||||
|
||||
"remove" to ConsoleAction("unit remove") { console, params ->
|
||||
val unit = console.getSelectedUnit()
|
||||
unit.destroy()
|
||||
DevConsoleResponse.OK
|
||||
},
|
||||
|
||||
"addpromotion" to ConsoleAction("unit addpromotion <promotionName>") { console, params ->
|
||||
val unit = console.getSelectedUnit()
|
||||
val promotion = console.gameInfo.ruleset.unitPromotions.values.firstOrNull { it.name.toCliInput() == params[0] }
|
||||
?: throw ConsoleErrorException("Unknown promotion")
|
||||
unit.promotions.addPromotion(promotion.name, true)
|
||||
DevConsoleResponse.OK
|
||||
},
|
||||
|
||||
"removepromotion" to ConsoleAction("unit removepromotion <promotionName>") { console, params ->
|
||||
val unit = console.getSelectedUnit()
|
||||
val promotion = unit.promotions.getPromotions().firstOrNull { it.name.toCliInput() == params[0] }
|
||||
?: throw ConsoleErrorException("Promotion not found on unit")
|
||||
// No such action in-game so we need to manually update
|
||||
unit.promotions.promotions.remove(promotion.name)
|
||||
unit.updateUniques()
|
||||
unit.updateVisibleTiles()
|
||||
DevConsoleResponse.OK
|
||||
},
|
||||
|
||||
"setmovement" to ConsoleAction("unit setmovement <amount>") { console, params ->
|
||||
val movement = params[0].toFloatOrNull()
|
||||
if (movement == null || movement < 0) throw ConsoleErrorException("Invalid number")
|
||||
val unit = console.getSelectedUnit()
|
||||
unit.currentMovement = movement
|
||||
DevConsoleResponse.OK
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
class ConsoleCityCommands : ConsoleCommandNode {
|
||||
override val subcommands = hashMapOf<String, ConsoleCommand>(
|
||||
|
||||
"add" to ConsoleAction("city add <civName>") { console, params ->
|
||||
val civ = console.getCivByName(params[0])
|
||||
val selectedTile = console.getSelectedTile()
|
||||
if (selectedTile.isCityCenter())
|
||||
throw ConsoleErrorException("Tile already contains a city center")
|
||||
civ.addCity(selectedTile.position)
|
||||
DevConsoleResponse.OK
|
||||
},
|
||||
|
||||
"remove" to ConsoleAction("city remove") { console, params ->
|
||||
val city = console.getSelectedCity()
|
||||
city.destroyCity(overrideSafeties = true)
|
||||
DevConsoleResponse.OK
|
||||
},
|
||||
|
||||
"setpop" to ConsoleAction("city setpop <amount>") { console, params ->
|
||||
val city = console.getSelectedCity()
|
||||
val newPop = console.getInt(params[0])
|
||||
if (newPop < 1) throw ConsoleErrorException("Population must be at least 1")
|
||||
city.population.setPopulation(newPop)
|
||||
DevConsoleResponse.OK
|
||||
},
|
||||
|
||||
"setname" to ConsoleAction("city setname <\"name\">") { console, params ->
|
||||
val city = console.getSelectedCity()
|
||||
city.name = params[0]
|
||||
DevConsoleResponse.OK
|
||||
},
|
||||
|
||||
"addtile" to ConsoleAction("city addtile <cityName>") { console, params ->
|
||||
val selectedTile = console.getSelectedTile()
|
||||
val city = console.getCity(params[0])
|
||||
if (selectedTile.neighbors.none { it.getCity() == city })
|
||||
throw ConsoleErrorException("Tile is not adjacent to any tile already owned by the city")
|
||||
if (selectedTile.isCityCenter()) throw ConsoleErrorException("Cannot tranfer city center")
|
||||
city.expansion.takeOwnership(selectedTile)
|
||||
DevConsoleResponse.OK
|
||||
},
|
||||
|
||||
"removetile" to ConsoleAction("city removetile") { console, params ->
|
||||
val selectedTile = console.getSelectedTile()
|
||||
val city = console.getSelectedCity()
|
||||
city.expansion.relinquishOwnership(selectedTile)
|
||||
DevConsoleResponse.OK
|
||||
},
|
||||
|
||||
"religion" to ConsoleAction("city religion <name> <±pressure>") { console, params ->
|
||||
val city = console.getSelectedCity()
|
||||
val religion = city.civ.gameInfo.religions.keys.firstOrNull { it.toCliInput() == params[0] }
|
||||
?: throw ConsoleErrorException("'${params[0]}' is not a known religion")
|
||||
val pressure = console.getInt(params[1])
|
||||
city.religion.addPressure(religion, pressure.coerceAtLeast(-city.religion.getPressures()[religion]))
|
||||
city.religion.updatePressureOnPopulationChange(0)
|
||||
DevConsoleResponse.OK
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
class ConsoleTileCommands: ConsoleCommandNode {
|
||||
override val subcommands = hashMapOf<String, ConsoleCommand>(
|
||||
|
||||
"setimprovement" to ConsoleAction("tile setimprovement <improvementName> [civName]") { console, params ->
|
||||
val selectedTile = console.getSelectedTile()
|
||||
val improvement = console.gameInfo.ruleset.tileImprovements.values.firstOrNull {
|
||||
it.name.toCliInput() == params[0]
|
||||
} ?: throw ConsoleErrorException("Unknown improvement")
|
||||
var civ: Civilization? = null
|
||||
if (params.size == 2){
|
||||
civ = console.getCivByName(params[1])
|
||||
}
|
||||
selectedTile.improvementFunctions.changeImprovement(improvement.name, civ)
|
||||
DevConsoleResponse.OK
|
||||
},
|
||||
|
||||
"removeimprovement" to ConsoleAction("tile removeimprovement") { console, params ->
|
||||
val selectedTile = console.getSelectedTile()
|
||||
selectedTile.improvementFunctions.changeImprovement(null)
|
||||
DevConsoleResponse.OK
|
||||
},
|
||||
|
||||
"removeroad" to ConsoleAction("tile removeroad") { console, params ->
|
||||
val selectedTile = console.getSelectedTile()
|
||||
selectedTile.roadStatus = RoadStatus.None
|
||||
DevConsoleResponse.OK
|
||||
},
|
||||
|
||||
"addfeature" to ConsoleAction("tile addfeature <featureName>") { console, params ->
|
||||
val selectedTile = console.getSelectedTile()
|
||||
val feature = console.gameInfo.ruleset.terrains.values
|
||||
.firstOrNull { it.type == TerrainType.TerrainFeature && it.name.toCliInput() == params[0] }
|
||||
?: throw ConsoleErrorException("Unknown feature")
|
||||
selectedTile.addTerrainFeature(feature.name)
|
||||
DevConsoleResponse.OK
|
||||
},
|
||||
|
||||
"removefeature" to ConsoleAction("tile addfeature <featureName>") { console, params ->
|
||||
val selectedTile = console.getSelectedTile()
|
||||
val feature = console.gameInfo.ruleset.terrains.values
|
||||
.firstOrNull { it.type == TerrainType.TerrainFeature && it.name.toCliInput() == params[0] }
|
||||
?: throw ConsoleErrorException("Unknown feature")
|
||||
selectedTile.removeTerrainFeature(feature.name)
|
||||
DevConsoleResponse.OK
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
class ConsoleCivCommands : ConsoleCommandNode {
|
||||
override val subcommands = hashMapOf<String, ConsoleCommand>(
|
||||
"addstat" to ConsoleAction("civ addstat <stat> <amount> [civ]") { console, params ->
|
||||
val stat = Stat.safeValueOf(params[0].replaceFirstChar(Char::titlecase))
|
||||
?: throw ConsoleErrorException("\"${params[0]}\" is not an acceptable Stat")
|
||||
if (stat !in Stat.statsWithCivWideField)
|
||||
throw ConsoleErrorException("$stat is not civ-wide")
|
||||
|
||||
val amount = console.getInt(params[1])
|
||||
|
||||
val civ = if (params.size == 2) console.screen.selectedCiv
|
||||
else console.getCivByName(params[2])
|
||||
|
||||
civ.addStat(stat, amount)
|
||||
DevConsoleResponse.OK
|
||||
},
|
||||
|
||||
"setplayertype" to ConsoleAction("civ setplayertype <civName> <ai/human>") { console, params ->
|
||||
val civ = console.getCivByName(params[0])
|
||||
val playerType = PlayerType.values().firstOrNull { it.name.lowercase() == params[1].lowercase() }
|
||||
?: throw ConsoleErrorException("Invalid player type, valid options are 'ai' or 'human'")
|
||||
civ.playerType = playerType
|
||||
DevConsoleResponse.OK
|
||||
},
|
||||
|
||||
"revealmap" to ConsoleAction("civ revealmap <civName>") { console, params ->
|
||||
val civ = console.getCivByName(params[0])
|
||||
civ.gameInfo.tileMap.values.asSequence()
|
||||
.forEach { it.setExplored(civ, true) }
|
||||
DevConsoleResponse.OK
|
||||
},
|
||||
|
||||
"activatetrigger" to ConsoleAction("civ activatetrigger <civName> <\"trigger\">") { console, params ->
|
||||
val civ = console.getCivByName(params[0])
|
||||
val unique = Unique(params[1])
|
||||
if (unique.type == null) throw ConsoleErrorException("Unrecognized trigger")
|
||||
val tile = console.screen.mapHolder.selectedTile
|
||||
val city = tile?.getCity()
|
||||
UniqueTriggerActivation.triggerCivwideUnique(unique, civ, city, tile)
|
||||
DevConsoleResponse.OK
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -64,7 +64,8 @@ class DevConsolePopup(val screen: WorldScreen) : Popup(screen) {
|
||||
val handleCommandResponse = handleCommand()
|
||||
if (handleCommandResponse.isOK) {
|
||||
screen.shouldUpdate = true
|
||||
history.add(textField.text)
|
||||
if (history.isEmpty() || history.last() != textField.text)
|
||||
history.add(textField.text)
|
||||
close()
|
||||
return
|
||||
}
|
||||
@ -85,9 +86,7 @@ class DevConsolePopup(val screen: WorldScreen) : Popup(screen) {
|
||||
|
||||
private fun getAutocomplete(): String {
|
||||
val params = getParams(textField.text)
|
||||
val result = commandRoot.autocomplete(this, params)
|
||||
if (result.isNullOrEmpty()) return ""
|
||||
return "$result "
|
||||
return commandRoot.autocomplete(this, params).orEmpty()
|
||||
}
|
||||
|
||||
internal fun getCivByName(name: String) = gameInfo.civilizations.firstOrNull { it.civName.toCliInput() == name.toCliInput() }
|
||||
|
Loading…
Reference in New Issue
Block a user