mirror of
https://github.com/yairm210/Unciv.git
synced 2025-07-14 01:39:40 +07:00
G&K Neutral Tile Road Maintenance (#8138)
* Redo * New parameterized and actually used Road Unique * Remove unneeded * Update CURRENT_COMPATIBILITY_NUMBER since adding new serialization data * Make neutralRoads for CivilizationInfo.kt Transient
This commit is contained in:
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "Global uniques",
|
"name": "Global uniques",
|
||||||
"uniques": [
|
"uniques": [
|
||||||
"[-75]% growth [in all cities] <when between [-10] and [0] Happiness>",
|
"[-75]% growth [in all cities] <when between [-10] and [0] Happiness>",
|
||||||
"Nullifies Growth [in all cities] <when below [-10] Happiness>",
|
"Nullifies Growth [in all cities] <when below [-10] Happiness>",
|
||||||
@ -7,19 +7,19 @@
|
|||||||
"[-33]% Strength <for [All] units> <when below [-10] Happiness>",
|
"[-33]% Strength <for [All] units> <when below [-10] Happiness>",
|
||||||
"Cannot build [Settler] units <when below [-10] Happiness>",
|
"Cannot build [Settler] units <when below [-10] Happiness>",
|
||||||
"Rebel units may spawn <when below [-20] Happiness>"
|
"Rebel units may spawn <when below [-20] Happiness>"
|
||||||
|
|
||||||
// TODO: Implement the uniques below
|
// TODO: Implement the uniques below
|
||||||
// "[+20]% [Culture] [in all cities] <during a golden age>",
|
// "[+20]% [Culture] [in all cities] <during a golden age>",
|
||||||
// "[+20]% [Production] [in all cities] <during a golden age>",
|
// "[+20]% [Production] [in all cities] <during a golden age>",
|
||||||
|
|
||||||
// "[+10]% growth [in all cities] <during We Love The King Day>",
|
// "[+10]% growth [in all cities] <during We Love The King Day>",
|
||||||
|
|
||||||
// "Nullifies All Yield <while is in resistance>",
|
// "Nullifies All Yield <while is in resistance>",
|
||||||
|
|
||||||
// "[-25]% [Science] [in pupetted cities]" -- Imo cityFilters should ideally become conditionals anyway
|
// "[-25]% [Science] [in pupetted cities]" -- Imo cityFilters should ideally become conditionals anyway
|
||||||
// "[-25]% [Culture] [in pupetted cities]"
|
// "[-25]% [Culture] [in pupetted cities]"
|
||||||
|
|
||||||
// "[+20]% [Production] [in cities connected via railroad]"
|
// "[+20]% [Production] [in cities connected via railroad]"
|
||||||
// something something unit supply
|
// something something unit supply
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -108,8 +108,7 @@
|
|||||||
"terrainsCanBeBuiltOn": ["Land"],
|
"terrainsCanBeBuiltOn": ["Land"],
|
||||||
"turnsToBuild": 4,
|
"turnsToBuild": 4,
|
||||||
"techRequired": "The Wheel",
|
"techRequired": "The Wheel",
|
||||||
// "Costs [1] gold per turn when in your territory" does nothing and is only to inform the user
|
"uniques": ["Can be built outside your borders", "Costs [1] [Gold] per turn"],
|
||||||
"uniques": ["Can be built outside your borders", "Costs [1] gold per turn when in your territory"],
|
|
||||||
"shortcutKey": "R",
|
"shortcutKey": "R",
|
||||||
"civilopediaText": [
|
"civilopediaText": [
|
||||||
{"text":"Reduces movement cost to ½ if the other tile also has a Road or Railroad"},
|
{"text":"Reduces movement cost to ½ if the other tile also has a Road or Railroad"},
|
||||||
@ -122,7 +121,7 @@
|
|||||||
"terrainsCanBeBuiltOn": ["Land"],
|
"terrainsCanBeBuiltOn": ["Land"],
|
||||||
"turnsToBuild": 4,
|
"turnsToBuild": 4,
|
||||||
"techRequired": "Railroads",
|
"techRequired": "Railroads",
|
||||||
"uniques": ["Can be built outside your borders", "Costs [2] gold per turn when in your territory"],
|
"uniques": ["Can be built outside your borders", "Costs [2] [Gold] per turn"],
|
||||||
"shortcutKey": "R",
|
"shortcutKey": "R",
|
||||||
"civilopediaText": [{"text":"Reduces movement cost to ⅒ if the other tile also has a Railroad"}]
|
"civilopediaText": [{"text":"Reduces movement cost to ⅒ if the other tile also has a Railroad"}]
|
||||||
},
|
},
|
||||||
|
@ -108,8 +108,7 @@
|
|||||||
"terrainsCanBeBuiltOn": ["Land"],
|
"terrainsCanBeBuiltOn": ["Land"],
|
||||||
"turnsToBuild": 4,
|
"turnsToBuild": 4,
|
||||||
"techRequired": "The Wheel",
|
"techRequired": "The Wheel",
|
||||||
// "Costs [1] gold per turn when in your territory" does nothing and is only to inform the user
|
"uniques": ["Can be built outside your borders", "Costs [1] [Gold] per turn when in your territory"],
|
||||||
"uniques": ["Can be built outside your borders", "Costs [1] gold per turn when in your territory"],
|
|
||||||
"shortcutKey": "R",
|
"shortcutKey": "R",
|
||||||
"civilopediaText": [
|
"civilopediaText": [
|
||||||
{"text":"Reduces movement cost to ½ if the other tile also has a Road or Railroad"},
|
{"text":"Reduces movement cost to ½ if the other tile also has a Road or Railroad"},
|
||||||
@ -122,7 +121,7 @@
|
|||||||
"terrainsCanBeBuiltOn": ["Land"],
|
"terrainsCanBeBuiltOn": ["Land"],
|
||||||
"turnsToBuild": 4,
|
"turnsToBuild": 4,
|
||||||
"techRequired": "Railroads",
|
"techRequired": "Railroads",
|
||||||
"uniques": ["Can be built outside your borders", "Costs [2] gold per turn when in your territory"],
|
"uniques": ["Can be built outside your borders", "Costs [2] [Gold] per turn when in your territory"],
|
||||||
"shortcutKey": "R",
|
"shortcutKey": "R",
|
||||||
"civilopediaText": [{"text":"Reduces movement cost to ⅒ if the other tile also has a Railroad"}]
|
"civilopediaText": [{"text":"Reduces movement cost to ⅒ if the other tile also has a Railroad"}]
|
||||||
},
|
},
|
||||||
|
@ -66,7 +66,7 @@ class GameInfo : IsPartOfGameInfoSerialization, HasGameInfoSerializationVersion
|
|||||||
companion object {
|
companion object {
|
||||||
/** The current compatibility version of [GameInfo]. This number is incremented whenever changes are made to the save file structure that guarantee that
|
/** The current compatibility version of [GameInfo]. This number is incremented whenever changes are made to the save file structure that guarantee that
|
||||||
* previous versions of the game will not be able to load or play a game normally. */
|
* previous versions of the game will not be able to load or play a game normally. */
|
||||||
const val CURRENT_COMPATIBILITY_NUMBER = 2
|
const val CURRENT_COMPATIBILITY_NUMBER = 3
|
||||||
|
|
||||||
val CURRENT_COMPATIBILITY_VERSION = CompatibilityVersion(CURRENT_COMPATIBILITY_NUMBER, UncivGame.VERSION)
|
val CURRENT_COMPATIBILITY_VERSION = CompatibilityVersion(CURRENT_COMPATIBILITY_NUMBER, UncivGame.VERSION)
|
||||||
|
|
||||||
@ -498,6 +498,7 @@ class GameInfo : IsPartOfGameInfoSerialization, HasGameInfoSerializationVersion
|
|||||||
civInfo.thingsToFocusOnForVictory =
|
civInfo.thingsToFocusOnForVictory =
|
||||||
civInfo.getPreferredVictoryTypeObject()?.getThingsToFocus(civInfo) ?: setOf()
|
civInfo.getPreferredVictoryTypeObject()?.getThingsToFocus(civInfo) ?: setOf()
|
||||||
}
|
}
|
||||||
|
tileMap.setNeutralTransients() // has to happen after civInfo.setTransients() sets owningCity
|
||||||
|
|
||||||
convertFortify()
|
convertFortify()
|
||||||
|
|
||||||
|
@ -73,8 +73,8 @@ class CivInfoStats(val civInfo: CivilizationInfo) {
|
|||||||
return cost.toInt()
|
return cost.toInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getTransportationUpkeep(): Int {
|
private fun getTransportationUpkeep(): Stats {
|
||||||
var transportationUpkeep = 0f
|
val transportationUpkeep = Stats()
|
||||||
// we no longer use .flatMap, because there are a lot of tiles and keeping them all in a list
|
// we no longer use .flatMap, because there are a lot of tiles and keeping them all in a list
|
||||||
// just to go over them once is a waste of memory - there are low-end phones who don't have much ram
|
// just to go over them once is a waste of memory - there are low-end phones who don't have much ram
|
||||||
|
|
||||||
@ -88,14 +88,38 @@ class CivInfoStats(val civInfo: CivilizationInfo) {
|
|||||||
if (tile.isCityCenter()) continue
|
if (tile.isCityCenter()) continue
|
||||||
if (tile.getUnpillagedRoad() == RoadStatus.None) continue // Cheap checks before pricey checks
|
if (tile.getUnpillagedRoad() == RoadStatus.None) continue // Cheap checks before pricey checks
|
||||||
if (ignoredTileTypes.any { tile.matchesFilter(it, civInfo) }) continue
|
if (ignoredTileTypes.any { tile.matchesFilter(it, civInfo) }) continue
|
||||||
|
val road = tile.getUnpillagedRoadImprovement()
|
||||||
transportationUpkeep += tile.getUnpillagedRoad().upkeep
|
if (road!!.hasUnique(UniqueType.ImprovementMaintenance, StateForConditionals(civInfo, tile = tile))) {
|
||||||
|
for(unique in road.getMatchingUniques(UniqueType.ImprovementMaintenance)) {
|
||||||
|
transportationUpkeep.add(Stat.valueOf(unique.params[1]), unique.params[0].toFloat())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (road.hasUnique(UniqueType.ImprovementAllMaintenance, StateForConditionals(civInfo, tile = tile))) {
|
||||||
|
for(unique in road.getMatchingUniques(UniqueType.ImprovementAllMaintenance)) {
|
||||||
|
transportationUpkeep.add(Stat.valueOf(unique.params[1]), unique.params[0].toFloat())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// backwards compatible
|
||||||
|
if (road.hasUnique(UniqueType.OldImprovementMaintenance, StateForConditionals(civInfo, tile = tile))) {
|
||||||
|
transportationUpkeep.add(Stat.Gold, tile.getUnpillagedRoad().upkeep.toFloat())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// tabulate neutral roads
|
||||||
|
for (position in civInfo.neutralRoads) {
|
||||||
|
val tile = civInfo.gameInfo.tileMap[position]
|
||||||
|
if (tile.getUnpillagedRoad() == RoadStatus.None) continue // Cheap checks before pricey checks
|
||||||
|
val road = tile.getUnpillagedRoadImprovement()
|
||||||
|
if (road!!.hasUnique(UniqueType.ImprovementAllMaintenance, StateForConditionals(civInfo, tile = tile))) {
|
||||||
|
for(unique in road.getMatchingUniques(UniqueType.ImprovementAllMaintenance)) {
|
||||||
|
transportationUpkeep.add(Stat.valueOf(unique.params[1]), unique.params[0].toFloat())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (unique in civInfo.getMatchingUniques(UniqueType.RoadMaintenance))
|
for (unique in civInfo.getMatchingUniques(UniqueType.RoadMaintenance))
|
||||||
transportationUpkeep *= unique.params[0].toPercent()
|
transportationUpkeep.times(unique.params[0].toPercent())
|
||||||
|
|
||||||
return transportationUpkeep.toInt()
|
return transportationUpkeep
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getUnitSupply(): Int {
|
fun getUnitSupply(): Int {
|
||||||
@ -156,7 +180,7 @@ class CivInfoStats(val civInfo: CivilizationInfo) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
statMap["Transportation upkeep"] = Stats(gold = -getTransportationUpkeep().toFloat())
|
statMap["Transportation upkeep"] = getTransportationUpkeep() * -1
|
||||||
statMap["Unit upkeep"] = Stats(gold = -getUnitMaintenance().toFloat())
|
statMap["Unit upkeep"] = Stats(gold = -getUnitMaintenance().toFloat())
|
||||||
|
|
||||||
|
|
||||||
|
@ -145,6 +145,9 @@ class CivilizationInfo : IsPartOfGameInfoSerialization {
|
|||||||
@Transient
|
@Transient
|
||||||
var thingsToFocusOnForVictory = setOf<Victory.Focus>()
|
var thingsToFocusOnForVictory = setOf<Victory.Focus>()
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
var neutralRoads = HashSet<Vector2>()
|
||||||
|
|
||||||
var playerType = PlayerType.AI
|
var playerType = PlayerType.AI
|
||||||
|
|
||||||
/** Used in online multiplayer for human players */
|
/** Used in online multiplayer for human players */
|
||||||
@ -280,6 +283,7 @@ class CivilizationInfo : IsPartOfGameInfoSerialization {
|
|||||||
toReturn.diplomacy[diplomacyManager.otherCivName] = diplomacyManager
|
toReturn.diplomacy[diplomacyManager.otherCivName] = diplomacyManager
|
||||||
toReturn.proximity.putAll(proximity)
|
toReturn.proximity.putAll(proximity)
|
||||||
toReturn.cities = cities.map { it.clone() }
|
toReturn.cities = cities.map { it.clone() }
|
||||||
|
toReturn.neutralRoads = neutralRoads
|
||||||
|
|
||||||
// This is the only thing that is NOT switched out, which makes it a source of ConcurrentModification errors.
|
// This is the only thing that is NOT switched out, which makes it a source of ConcurrentModification errors.
|
||||||
// Cloning it by-pointer is a horrific move, since the serialization would go over it ANYWAY and still lead to concurrency problems.
|
// Cloning it by-pointer is a horrific move, since the serialization would go over it ANYWAY and still lead to concurrency problems.
|
||||||
|
@ -44,10 +44,20 @@ open class TileInfo : IsPartOfGameInfoSerialization {
|
|||||||
private set
|
private set
|
||||||
|
|
||||||
fun setOwningCity(city:CityInfo?){
|
fun setOwningCity(city:CityInfo?){
|
||||||
|
if (city != null) {
|
||||||
|
if (roadStatus != RoadStatus.None && roadOwner != "") {
|
||||||
|
// remove previous neutral tile owner
|
||||||
|
getRoadOwner()!!.neutralRoads.remove(this.position)
|
||||||
|
}
|
||||||
|
roadOwner = city.civInfo.civName // only when taking control, otherwise last owner
|
||||||
|
} else {
|
||||||
|
if (roadStatus != RoadStatus.None && owningCity != null) {
|
||||||
|
// previous tile owner still owns road, add to tracker
|
||||||
|
owningCity!!.civInfo.neutralRoads.add(this.position)
|
||||||
|
}
|
||||||
|
}
|
||||||
owningCity = city
|
owningCity = city
|
||||||
isCityCenterInternal = getCity()?.location == position
|
isCityCenterInternal = getCity()?.location == position
|
||||||
if (city != null) // only when taking control, otherwise last owner
|
|
||||||
roadOwner = city.civInfo.civName
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transient
|
@Transient
|
||||||
@ -272,6 +282,10 @@ open class TileInfo : IsPartOfGameInfoSerialization {
|
|||||||
else
|
else
|
||||||
roadStatus
|
roadStatus
|
||||||
}
|
}
|
||||||
|
fun getUnpillagedRoadImprovement(): TileImprovement? {
|
||||||
|
return if (getUnpillagedRoad() == RoadStatus.None) null
|
||||||
|
else ruleset.tileImprovements[getUnpillagedRoad().name]
|
||||||
|
}
|
||||||
|
|
||||||
fun changeImprovement(improvementStr: String?) {
|
fun changeImprovement(improvementStr: String?) {
|
||||||
improvementIsPillaged = false
|
improvementIsPillaged = false
|
||||||
@ -282,16 +296,20 @@ open class TileInfo : IsPartOfGameInfoSerialization {
|
|||||||
fun addRoad(roadType: RoadStatus, unitCivInfo: CivilizationInfo) {
|
fun addRoad(roadType: RoadStatus, unitCivInfo: CivilizationInfo) {
|
||||||
roadStatus = roadType
|
roadStatus = roadType
|
||||||
roadIsPillaged = false
|
roadIsPillaged = false
|
||||||
roadOwner = if (getOwner() == null)
|
if (getOwner() == null) {
|
||||||
unitCivInfo.civName // neutral tile, use building unit
|
roadOwner = unitCivInfo.civName // neutral tile, use building unit
|
||||||
else
|
unitCivInfo.neutralRoads.add(this.position)
|
||||||
getOwner()!!.civName
|
} else {
|
||||||
|
roadOwner = getOwner()!!.civName
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// function handling when removing a road from the tile
|
// function handling when removing a road from the tile
|
||||||
fun removeRoad() {
|
fun removeRoad() {
|
||||||
roadStatus = RoadStatus.None
|
roadStatus = RoadStatus.None
|
||||||
roadIsPillaged = false
|
roadIsPillaged = false
|
||||||
|
if (owningCity == null)
|
||||||
|
getRoadOwner()!!.neutralRoads.remove(this.position)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getShownImprovement(viewingCiv: CivilizationInfo?): String? {
|
fun getShownImprovement(viewingCiv: CivilizationInfo?): String? {
|
||||||
@ -1165,6 +1183,7 @@ open class TileInfo : IsPartOfGameInfoSerialization {
|
|||||||
fun setTransients() {
|
fun setTransients() {
|
||||||
setTerrainTransients()
|
setTerrainTransients()
|
||||||
setUnitTransients(true)
|
setUnitTransients(true)
|
||||||
|
setOwnerTransients()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setTerrainTransients() {
|
fun setTerrainTransients() {
|
||||||
@ -1194,6 +1213,11 @@ open class TileInfo : IsPartOfGameInfoSerialization {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun setOwnerTransients() {
|
||||||
|
if (owningCity == null && roadOwner != "")
|
||||||
|
getRoadOwner()!!.neutralRoads.add(this.position)
|
||||||
|
}
|
||||||
|
|
||||||
fun stripUnits() {
|
fun stripUnits() {
|
||||||
for (unit in this.getUnits()) removeUnit(unit)
|
for (unit in this.getUnits()) removeUnit(unit)
|
||||||
}
|
}
|
||||||
|
@ -459,6 +459,14 @@ class TileMap : IsPartOfGameInfoSerialization {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Initialize based on TileInfo which Civ has neutral tile roads
|
||||||
|
*/
|
||||||
|
fun setNeutralTransients() {
|
||||||
|
for (tileInfo in values) {
|
||||||
|
tileInfo.setOwnerTransients()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun removeMissingTerrainModReferences(ruleSet: Ruleset) {
|
fun removeMissingTerrainModReferences(ruleSet: Ruleset) {
|
||||||
for (tile in this.values) {
|
for (tile in this.values) {
|
||||||
for (terrainFeature in tile.terrainFeatures.filter { !ruleSet.terrains.containsKey(it) })
|
for (terrainFeature in tile.terrainFeatures.filter { !ruleSet.terrains.containsKey(it) })
|
||||||
|
@ -565,7 +565,10 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags:
|
|||||||
RemovesFeaturesIfBuilt("Removes removable features when built", UniqueTarget.Improvement),
|
RemovesFeaturesIfBuilt("Removes removable features when built", UniqueTarget.Improvement),
|
||||||
|
|
||||||
DefensiveBonus("Gives a defensive bonus of [relativeAmount]%", UniqueTarget.Improvement),
|
DefensiveBonus("Gives a defensive bonus of [relativeAmount]%", UniqueTarget.Improvement),
|
||||||
ImprovementMaintenance("Costs [amount] gold per turn when in your territory", UniqueTarget.Improvement), // Unused
|
ImprovementMaintenance("Costs [amount] [stat] per turn when in your territory", UniqueTarget.Improvement), // Roads
|
||||||
|
ImprovementAllMaintenance("Costs [amount] [stat] per turn", UniqueTarget.Improvement), // Roads
|
||||||
|
//@Deprecated("as of 4.3.9", ReplaceWith("Costs [amount] [stats] per turn when in your territory"), DeprecationLevel.ERROR)
|
||||||
|
OldImprovementMaintenance("Costs [amount] gold per turn when in your territory", UniqueTarget.Improvement), // unused
|
||||||
DamagesAdjacentEnemyUnits("Adjacent enemy units ending their turn take [amount] damage", UniqueTarget.Improvement),
|
DamagesAdjacentEnemyUnits("Adjacent enemy units ending their turn take [amount] damage", UniqueTarget.Improvement),
|
||||||
TakeOverTilesAroundWhenBuilt("Constructing it will take over the tiles around it and assign them to your closest city", UniqueTarget.Improvement),
|
TakeOverTilesAroundWhenBuilt("Constructing it will take over the tiles around it and assign them to your closest city", UniqueTarget.Improvement),
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user