mirror of
https://github.com/yairm210/Unciv.git
synced 2025-02-11 11:28:03 +07:00
Code reorganization - separated variables, pure functions and state-changing functions in all main logic classes
This commit is contained in:
parent
749ff90fe0
commit
1957c4ca80
@ -21,8 +21,8 @@ android {
|
||||
applicationId "com.unciv.game"
|
||||
minSdkVersion 14
|
||||
targetSdkVersion 26
|
||||
versionCode 121
|
||||
versionName "2.7.8"
|
||||
versionCode 122
|
||||
versionName "2.7.9"
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
|
@ -20,7 +20,6 @@ class UnCivGame : Game() {
|
||||
*/
|
||||
val viewEntireMapForDebug = false
|
||||
|
||||
|
||||
lateinit var worldScreen: WorldScreen
|
||||
|
||||
override fun create() {
|
||||
@ -72,9 +71,7 @@ class UnCivGame : Game() {
|
||||
setWorldScreen()
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
lateinit var Current: UnCivGame
|
||||
}
|
||||
|
||||
}
|
@ -11,16 +11,28 @@ import com.unciv.models.gamebasics.GameBasics
|
||||
import com.unciv.ui.utils.getRandom
|
||||
|
||||
class GameInfo {
|
||||
@Transient var tilesToCities = HashMap<TileInfo,CityInfo>()
|
||||
|
||||
var notifications = mutableListOf<Notification>()
|
||||
@Deprecated("As of 2.6.9") var tutorial = mutableListOf<String>()
|
||||
var civilizations = mutableListOf<CivilizationInfo>()
|
||||
var tileMap: TileMap = TileMap()
|
||||
var turns = 0
|
||||
@Transient var tilesToCities = HashMap<TileInfo,CityInfo>()
|
||||
|
||||
//region pure functions
|
||||
fun clone():GameInfo{
|
||||
val toReturn = GameInfo()
|
||||
toReturn.civilizations.addAll(civilizations.map { it.clone() })
|
||||
toReturn.tileMap=tileMap.clone()
|
||||
toReturn.notifications.addAll(notifications)
|
||||
toReturn.turns=turns
|
||||
toReturn.setTransients()
|
||||
return toReturn
|
||||
}
|
||||
|
||||
fun getPlayerCivilization(): CivilizationInfo = civilizations[0]
|
||||
fun getBarbarianCivilization(): CivilizationInfo = civilizations[1]
|
||||
//endregion
|
||||
|
||||
fun nextTurn() {
|
||||
notifications.clear()
|
||||
@ -98,15 +110,5 @@ class GameInfo {
|
||||
for (tile in city.getTiles()) tilesToCities.put(tile,city)
|
||||
}
|
||||
}
|
||||
|
||||
fun clone():GameInfo{
|
||||
val toReturn = GameInfo()
|
||||
toReturn.civilizations.addAll(civilizations.map { it.clone() })
|
||||
toReturn.tileMap=tileMap.clone()
|
||||
toReturn.notifications.addAll(notifications)
|
||||
toReturn.turns=turns
|
||||
toReturn.setTransients()
|
||||
return toReturn
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,14 @@ class CityConstructions {
|
||||
private val inProgressConstructions = HashMap<String, Int>()
|
||||
var currentConstruction: String = "Monument" // default starting building!
|
||||
|
||||
//region pure functions
|
||||
fun clone(): CityConstructions {
|
||||
val toReturn = CityConstructions()
|
||||
toReturn.currentConstruction=currentConstruction
|
||||
toReturn.builtBuildings.addAll(builtBuildings)
|
||||
toReturn.inProgressConstructions.putAll(inProgressConstructions)
|
||||
return toReturn
|
||||
}
|
||||
|
||||
internal fun getBuildableBuildings(): List<Building> = GameBasics.Buildings.values
|
||||
.filter { it.isBuildable(this) }
|
||||
@ -24,7 +32,6 @@ class CityConstructions {
|
||||
fun getConstructableUnits() = GameBasics.Units.values
|
||||
.filter { it.isBuildable(this) }
|
||||
|
||||
// Library and public school unique (not actualy unique, though...hmm)
|
||||
fun getStats(): Stats {
|
||||
val stats = Stats()
|
||||
for (building in getBuiltBuildings())
|
||||
@ -58,7 +65,7 @@ class CityConstructions {
|
||||
|
||||
fun getAmountConstructedText(): String =
|
||||
if (SpecialConstruction.getSpecialConstructions().any { it.name== currentConstruction}) ""
|
||||
else " (" + workDone(currentConstruction) + "/" +
|
||||
else " (" + getWorkDone(currentConstruction) + "/" +
|
||||
getCurrentConstruction().getProductionCost(cityInfo.civInfo.policies.adoptedPolicies) + ")"
|
||||
|
||||
fun getCurrentConstruction(): IConstruction = getConstruction(currentConstruction)
|
||||
@ -82,6 +89,26 @@ class CityConstructions {
|
||||
|
||||
internal fun getBuiltBuildings(): List<Building> = builtBuildings.map { GameBasics.Buildings[it]!! }
|
||||
|
||||
|
||||
private fun getWorkDone(constructionName: String): Int {
|
||||
if (inProgressConstructions.containsKey(constructionName)) return inProgressConstructions[constructionName]!!
|
||||
else return 0
|
||||
}
|
||||
|
||||
fun turnsToConstruction(constructionName: String): Int {
|
||||
val productionCost = getConstruction(constructionName).getProductionCost(cityInfo.civInfo.policies.adoptedPolicies)
|
||||
|
||||
val workLeft = (productionCost - getWorkDone(constructionName)).toFloat() // needs to be float so that we get the cieling properly ;)
|
||||
|
||||
val cityStats = cityInfo.cityStats.currentCityStats
|
||||
var production = Math.round(cityStats.production)
|
||||
if (constructionName == Settler) production += cityStats.food.toInt()
|
||||
|
||||
return Math.ceil((workLeft / production.toDouble())).toInt()
|
||||
}
|
||||
//endregion
|
||||
|
||||
//region state0changing functions
|
||||
fun addConstruction(constructionToAdd: Int) {
|
||||
if (!inProgressConstructions.containsKey(currentConstruction)) inProgressConstructions[currentConstruction] = 0
|
||||
inProgressConstructions[currentConstruction] = inProgressConstructions[currentConstruction]!! + constructionToAdd
|
||||
@ -126,23 +153,6 @@ class CityConstructions {
|
||||
|
||||
}
|
||||
|
||||
private fun workDone(constructionName: String): Int {
|
||||
if (inProgressConstructions.containsKey(constructionName)) return inProgressConstructions[constructionName]!!
|
||||
else return 0
|
||||
}
|
||||
|
||||
fun turnsToConstruction(constructionName: String): Int {
|
||||
val productionCost = getConstruction(constructionName).getProductionCost(cityInfo.civInfo.policies.adoptedPolicies)
|
||||
|
||||
val workLeft = (productionCost - workDone(constructionName)).toFloat() // needs to be float so that we get the cieling properly ;)
|
||||
|
||||
val cityStats = cityInfo.cityStats.currentCityStats
|
||||
var production = Math.round(cityStats.production)
|
||||
if (constructionName == Settler) production += cityStats.food.toInt()
|
||||
|
||||
return Math.ceil((workLeft / production.toDouble())).toInt()
|
||||
}
|
||||
|
||||
fun purchaseBuilding(buildingName: String) {
|
||||
cityInfo.civInfo.gold -= getConstruction(buildingName).getGoldCost(cityInfo.civInfo.policies.adoptedPolicies)
|
||||
getConstruction(buildingName).postBuildEvent(this)
|
||||
@ -161,21 +171,14 @@ class CityConstructions {
|
||||
Automation().chooseNextConstruction(this)
|
||||
}
|
||||
|
||||
fun chooseNextConstruction() {
|
||||
Automation().chooseNextConstruction(this)
|
||||
}
|
||||
//endregion
|
||||
|
||||
companion object {
|
||||
internal const val Worker = "Worker"
|
||||
internal const val Settler = "Settler"
|
||||
}
|
||||
|
||||
fun chooseNextConstruction() {
|
||||
Automation().chooseNextConstruction(this)
|
||||
}
|
||||
|
||||
fun clone(): CityConstructions {
|
||||
val toReturn = CityConstructions()
|
||||
toReturn.currentConstruction=currentConstruction
|
||||
toReturn.builtBuildings.addAll(builtBuildings)
|
||||
toReturn.inProgressConstructions.putAll(inProgressConstructions)
|
||||
return toReturn
|
||||
}
|
||||
|
||||
} // for json parsing, we need to have a default constructor
|
@ -5,14 +5,15 @@ import com.unciv.logic.automation.Automation
|
||||
import com.unciv.logic.map.TileInfo
|
||||
|
||||
class CityExpansionManager {
|
||||
|
||||
@Transient
|
||||
lateinit var cityInfo: CityInfo
|
||||
var cultureStored: Int = 0
|
||||
|
||||
fun reset() {
|
||||
cityInfo.tiles.clear()
|
||||
cityInfo.getCenterTile().getTilesInDistance(1).forEach { takeOwnership(it) }
|
||||
|
||||
fun clone(): CityExpansionManager {
|
||||
val toReturn = CityExpansionManager()
|
||||
toReturn.cultureStored=cultureStored
|
||||
return toReturn
|
||||
}
|
||||
|
||||
// This one has conflicting sources -
|
||||
@ -29,6 +30,26 @@ class CityExpansionManager {
|
||||
return Math.round(cultureToNextTile).toInt()
|
||||
}
|
||||
|
||||
|
||||
fun getNewTile(): TileInfo? {
|
||||
for (i in 2..5) {
|
||||
val tiles = cityInfo.getCenterTile().getTilesInDistance(i).filter {
|
||||
it.getOwner() != cityInfo.civInfo
|
||||
&& it.getTilesInDistance(1).none { tile->tile.isCityCenter() } // This SHOULD stop cities from grabbing tiles surrounding a city
|
||||
}
|
||||
if (tiles.isEmpty()) continue
|
||||
val chosenTile = tiles.maxBy { Automation().rankTile(it,cityInfo.civInfo) }
|
||||
return chosenTile
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
//region state-changing functions
|
||||
fun reset() {
|
||||
cityInfo.tiles.clear()
|
||||
cityInfo.getCenterTile().getTilesInDistance(1).forEach { takeOwnership(it) }
|
||||
}
|
||||
|
||||
private fun addNewTileWithCulture() {
|
||||
cultureStored -= getCultureToNextTile()
|
||||
|
||||
@ -48,18 +69,6 @@ class CityExpansionManager {
|
||||
unit.movementAlgs().teleportToClosestMoveableTile()
|
||||
}
|
||||
|
||||
fun getNewTile(): TileInfo? {
|
||||
for (i in 2..5) {
|
||||
val tiles = cityInfo.getCenterTile().getTilesInDistance(i).filter {
|
||||
it.getOwner() != cityInfo.civInfo
|
||||
&& it.getTilesInDistance(1).none { tile->tile.isCityCenter() } // This SHOULD stop cities from grabbing tiles surrounding a city
|
||||
}
|
||||
if (tiles.isEmpty()) continue
|
||||
val chosenTile = tiles.maxBy { Automation().rankTile(it,cityInfo.civInfo) }
|
||||
return chosenTile
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun nextTurn(culture: Float) {
|
||||
cultureStored += culture.toInt()
|
||||
@ -68,11 +77,5 @@ class CityExpansionManager {
|
||||
cityInfo.civInfo.addNotification(cityInfo.name + " {has expanded its borders}!", cityInfo.location, Color.PURPLE)
|
||||
}
|
||||
}
|
||||
|
||||
fun clone(): CityExpansionManager {
|
||||
val toReturn = CityExpansionManager()
|
||||
toReturn.cultureStored=cultureStored
|
||||
return toReturn
|
||||
}
|
||||
|
||||
//endregion
|
||||
}
|
@ -28,16 +28,63 @@ class CityInfo {
|
||||
var workedTiles = HashSet<Vector2>()
|
||||
var isBeingRazed = false
|
||||
|
||||
|
||||
constructor() // for json parsing, we need to have a default constructor
|
||||
constructor(civInfo: CivilizationInfo, cityLocation: Vector2) {
|
||||
this.civInfo = civInfo
|
||||
setTransients()
|
||||
|
||||
// Since cities can be captures between civilizations,
|
||||
// we need to check which other cities exist globally and name accordingly
|
||||
val allExistingCityNames = civInfo.gameInfo.civilizations.flatMap { it.cities }.map { it.name }.toHashSet()
|
||||
val probablyName = civInfo.getNation().cities.firstOrNull { !allExistingCityNames.contains(it) }
|
||||
if(probablyName!=null) name=probablyName
|
||||
else name = civInfo.getNation().cities.map { "New $it" }.first { !allExistingCityNames.contains(it) }
|
||||
|
||||
this.location = cityLocation
|
||||
civInfo.cities.add(this)
|
||||
if(civInfo == civInfo.gameInfo.getPlayerCivilization())
|
||||
civInfo.addNotification("$name {has been founded}!", cityLocation, Color.PURPLE)
|
||||
if (civInfo.policies.isAdopted("Legalism") && civInfo.cities.size <= 4) cityConstructions.addCultureBuilding()
|
||||
if (civInfo.cities.size == 1) {
|
||||
cityConstructions.builtBuildings.add("Palace")
|
||||
cityConstructions.currentConstruction = "Worker" // Default for first city only!
|
||||
}
|
||||
|
||||
expansion.reset()
|
||||
civInfo.gameInfo.updateTilesToCities()
|
||||
|
||||
val tile = getCenterTile()
|
||||
tile.roadStatus = RoadStatus.Railroad
|
||||
if (listOf("Forest", "Jungle", "Marsh").contains(tile.terrainFeature))
|
||||
tile.terrainFeature = null
|
||||
|
||||
population.autoAssignPopulation()
|
||||
cityStats.update()
|
||||
}
|
||||
|
||||
//region pure functions
|
||||
fun clone(): CityInfo {
|
||||
val toReturn = CityInfo()
|
||||
toReturn.population = population.clone()
|
||||
toReturn.health=health
|
||||
toReturn.name=name
|
||||
toReturn.tiles.addAll(tiles)
|
||||
toReturn.workedTiles.addAll(workedTiles)
|
||||
toReturn.cityConstructions=cityConstructions.clone()
|
||||
toReturn.expansion = expansion.clone()
|
||||
toReturn.isBeingRazed=isBeingRazed
|
||||
toReturn.location=location
|
||||
return toReturn
|
||||
}
|
||||
|
||||
internal val tileMap: TileMap
|
||||
get() = civInfo.gameInfo.tileMap
|
||||
|
||||
fun getCenterTile(): TileInfo = tileMap[location]
|
||||
fun getTiles(): List<TileInfo> = tiles.map { tileMap[it] }
|
||||
|
||||
fun getTilesInRange(): List<TileInfo> = getCenterTile().getTilesInDistance( 3)
|
||||
|
||||
|
||||
// Remove resources required by buildings
|
||||
fun getCityResources(): Counter<TileResource> {
|
||||
val cityResources = Counter<TileResource>()
|
||||
|
||||
@ -77,42 +124,16 @@ class CityInfo {
|
||||
return greatPersonPoints
|
||||
}
|
||||
|
||||
constructor() // for json parsing, we need to have a default constructor
|
||||
fun isCapital() = cityConstructions.isBuilt("Palace")
|
||||
|
||||
|
||||
constructor(civInfo: CivilizationInfo, cityLocation: Vector2) {
|
||||
this.civInfo = civInfo
|
||||
setTransients()
|
||||
|
||||
// Since cities can be captures between civilizations,
|
||||
// we need to check which other cities exist globally and name accordingly
|
||||
val allExistingCityNames = civInfo.gameInfo.civilizations.flatMap { it.cities }.map { it.name }.toHashSet()
|
||||
val probablyName = civInfo.getNation().cities.firstOrNull { !allExistingCityNames.contains(it) }
|
||||
if(probablyName!=null) name=probablyName
|
||||
else name = civInfo.getNation().cities.map { "New $it" }.first { !allExistingCityNames.contains(it) }
|
||||
|
||||
this.location = cityLocation
|
||||
civInfo.cities.add(this)
|
||||
if(civInfo == civInfo.gameInfo.getPlayerCivilization())
|
||||
civInfo.addNotification("$name {has been founded}!", cityLocation, Color.PURPLE)
|
||||
if (civInfo.policies.isAdopted("Legalism") && civInfo.cities.size <= 4) cityConstructions.addCultureBuilding()
|
||||
if (civInfo.cities.size == 1) {
|
||||
cityConstructions.builtBuildings.add("Palace")
|
||||
cityConstructions.currentConstruction = "Worker" // Default for first city only!
|
||||
}
|
||||
|
||||
expansion.reset()
|
||||
civInfo.gameInfo.updateTilesToCities()
|
||||
|
||||
val tile = getCenterTile()
|
||||
tile.roadStatus = RoadStatus.Railroad
|
||||
if (listOf("Forest", "Jungle", "Marsh").contains(tile.terrainFeature))
|
||||
tile.terrainFeature = null
|
||||
|
||||
population.autoAssignPopulation()
|
||||
cityStats.update()
|
||||
internal fun getMaxHealth(): Int {
|
||||
return 200 + cityConstructions.getBuiltBuildings().sumBy { it.cityHealth }
|
||||
}
|
||||
|
||||
override fun toString(): String {return name} // for debug
|
||||
//endregion
|
||||
|
||||
//region state-changing functions
|
||||
fun setTransients() {
|
||||
population.cityInfo = this
|
||||
expansion.cityInfo = this
|
||||
@ -120,7 +141,6 @@ class CityInfo {
|
||||
cityConstructions.cityInfo = this
|
||||
}
|
||||
|
||||
|
||||
fun endTurn() {
|
||||
val stats = cityStats.currentCityStats
|
||||
if (cityConstructions.currentConstruction == CityConstructions.Settler && stats.food > 0) {
|
||||
@ -146,8 +166,6 @@ class CityInfo {
|
||||
population.unassignExtraPopulation()
|
||||
}
|
||||
|
||||
fun isCapital() = cityConstructions.isBuilt("Palace")
|
||||
|
||||
fun moveToCiv(newCivInfo: CivilizationInfo){
|
||||
civInfo.cities.remove(this)
|
||||
newCivInfo.cities.add(this)
|
||||
@ -166,24 +184,5 @@ class CityInfo {
|
||||
|
||||
civInfo.gameInfo.updateTilesToCities()
|
||||
}
|
||||
|
||||
internal fun getMaxHealth(): Int {
|
||||
return 200 + cityConstructions.getBuiltBuildings().sumBy { it.cityHealth }
|
||||
}
|
||||
|
||||
override fun toString(): String {return name} // for debug
|
||||
|
||||
fun clone(): CityInfo {
|
||||
val toReturn = CityInfo()
|
||||
toReturn.population = population.clone()
|
||||
toReturn.health=health
|
||||
toReturn.name=name
|
||||
toReturn.tiles.addAll(tiles)
|
||||
toReturn.workedTiles.addAll(workedTiles)
|
||||
toReturn.cityConstructions=cityConstructions.clone()
|
||||
toReturn.expansion = expansion.clone()
|
||||
toReturn.isBeingRazed=isBeingRazed
|
||||
toReturn.location=location
|
||||
return toReturn
|
||||
}
|
||||
//endregion
|
||||
}
|
@ -19,6 +19,7 @@ class CityStats {
|
||||
@Transient
|
||||
lateinit var cityInfo: CityInfo
|
||||
|
||||
//region pure fuctions
|
||||
private fun getStatsFromTiles(): Stats {
|
||||
val stats = Stats()
|
||||
for (cell in cityInfo.getTilesInRange().filter { cityInfo.workedTiles.contains(it.position) || cityInfo.location == it.position })
|
||||
@ -38,7 +39,6 @@ class CityStats {
|
||||
return stats
|
||||
}
|
||||
|
||||
|
||||
private fun getStatsFromProduction(production: Float): Stats {
|
||||
val stats = Stats()
|
||||
|
||||
@ -54,7 +54,6 @@ class CityStats {
|
||||
return stats
|
||||
}
|
||||
|
||||
|
||||
private fun getStatPercentBonusesFromRailroad(): Stats {
|
||||
val stats = Stats()
|
||||
if (cityInfo.civInfo.tech.isResearched("Combustion")
|
||||
@ -178,7 +177,6 @@ class CityStats {
|
||||
return stats
|
||||
}
|
||||
|
||||
|
||||
private fun getStatPercentBonusesFromWonders(): Stats {
|
||||
val stats = Stats()
|
||||
val civUniques = cityInfo.civInfo.getBuildingUniques()
|
||||
@ -208,6 +206,28 @@ class CityStats {
|
||||
return stats
|
||||
}
|
||||
|
||||
fun isConnectedToCapital(roadType: RoadStatus): Boolean {
|
||||
if (cityInfo.civInfo.cities.count() < 2) return false// first city!
|
||||
val capitalTile = cityInfo.civInfo.getCapital().getCenterTile()
|
||||
val tilesReached = HashSet<TileInfo>()
|
||||
var tilesToCheck: List<TileInfo> = listOf(cityInfo.getCenterTile())
|
||||
while (tilesToCheck.isNotEmpty()) {
|
||||
val newTiles = tilesToCheck
|
||||
.flatMap { it.neighbors }.distinct()
|
||||
.filter {
|
||||
!tilesReached.contains(it) && !tilesToCheck.contains(it)
|
||||
&& (roadType !== RoadStatus.Road || it.roadStatus !== RoadStatus.None)
|
||||
&& (roadType !== RoadStatus.Railroad || it.roadStatus === roadType)
|
||||
}
|
||||
|
||||
if (newTiles.contains(capitalTile)) return true
|
||||
tilesReached.addAll(tilesToCheck)
|
||||
tilesToCheck = newTiles
|
||||
}
|
||||
return false
|
||||
}
|
||||
//endregion
|
||||
|
||||
fun update() {
|
||||
baseStatList = LinkedHashMap<String, Stats>()
|
||||
val civInfo = cityInfo.civInfo
|
||||
@ -270,25 +290,4 @@ class CityStats {
|
||||
if(currentCityStats.production<1) currentCityStats.production=1f
|
||||
}
|
||||
|
||||
|
||||
fun isConnectedToCapital(roadType: RoadStatus): Boolean {
|
||||
if (cityInfo.civInfo.cities.count() < 2) return false// first city!
|
||||
val capitalTile = cityInfo.civInfo.getCapital().getCenterTile()
|
||||
val tilesReached = HashSet<TileInfo>()
|
||||
var tilesToCheck: List<TileInfo> = listOf(cityInfo.getCenterTile())
|
||||
while (tilesToCheck.isNotEmpty()) {
|
||||
val newTiles = tilesToCheck
|
||||
.flatMap { it.neighbors }.distinct()
|
||||
.filter {
|
||||
!tilesReached.contains(it) && !tilesToCheck.contains(it)
|
||||
&& (roadType !== RoadStatus.Road || it.roadStatus !== RoadStatus.None)
|
||||
&& (roadType !== RoadStatus.Railroad || it.roadStatus === roadType)
|
||||
}
|
||||
|
||||
if (newTiles.contains(capitalTile)) return true
|
||||
tilesReached.addAll(tilesToCheck)
|
||||
tilesToCheck = newTiles
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
@ -7,14 +7,21 @@ import com.unciv.models.stats.Stats
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class PopulationManager {
|
||||
|
||||
@Transient
|
||||
lateinit var cityInfo: CityInfo
|
||||
|
||||
var population = 1
|
||||
var foodStored = 0
|
||||
|
||||
var buildingsSpecialists = HashMap<String, Stats>()
|
||||
|
||||
//region pure functions
|
||||
fun clone(): PopulationManager {
|
||||
val toReturn = PopulationManager()
|
||||
toReturn.population=population
|
||||
toReturn.foodStored=foodStored
|
||||
return toReturn
|
||||
}
|
||||
|
||||
fun getSpecialists(): Stats {
|
||||
val allSpecialists = Stats()
|
||||
for (stats in buildingsSpecialists.values)
|
||||
@ -27,14 +34,11 @@ class PopulationManager {
|
||||
return (specialists.science + specialists.production + specialists.culture + specialists.gold).toInt()
|
||||
}
|
||||
|
||||
|
||||
// 1 is the city center
|
||||
fun getFreePopulation(): Int {
|
||||
val workingPopulation = cityInfo.workedTiles.size
|
||||
return population - workingPopulation - getNumberOfSpecialists()
|
||||
}
|
||||
|
||||
|
||||
fun getFoodToNextPopulation(): Int {
|
||||
// civ v math, civilization.wikia
|
||||
var foodRequired = 15 + 6 * (population - 1) + Math.floor(Math.pow((population - 1).toDouble(), 1.8))
|
||||
@ -43,6 +47,7 @@ class PopulationManager {
|
||||
return foodRequired.toInt()
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
fun nextTurn(food: Float) {
|
||||
foodStored += food.roundToInt()
|
||||
@ -89,11 +94,4 @@ class PopulationManager {
|
||||
}
|
||||
}
|
||||
|
||||
fun clone(): PopulationManager {
|
||||
val toReturn = PopulationManager()
|
||||
toReturn.population=population
|
||||
toReturn.foodStored=foodStored
|
||||
return toReturn
|
||||
}
|
||||
|
||||
}
|
@ -22,30 +22,51 @@ import kotlin.math.roundToInt
|
||||
|
||||
|
||||
class CivilizationInfo {
|
||||
|
||||
@Transient
|
||||
lateinit var gameInfo: GameInfo
|
||||
@Transient lateinit var gameInfo: GameInfo
|
||||
|
||||
var gold = 0
|
||||
var happiness = 15
|
||||
var difficulty = "Chieftain"
|
||||
var civName = "Babylon"
|
||||
|
||||
var tech = TechManager()
|
||||
var policies = PolicyManager()
|
||||
var goldenAges = GoldenAgeManager()
|
||||
var greatPeople = GreatPersonManager()
|
||||
var scienceVictory = ScienceVictoryManager()
|
||||
var diplomacy = HashMap<String,DiplomacyManager>()
|
||||
|
||||
var cities = ArrayList<CityInfo>()
|
||||
var exploredTiles = HashSet<Vector2>()
|
||||
|
||||
constructor()
|
||||
|
||||
constructor(civName: String, startingLocation: Vector2, gameInfo: GameInfo) {
|
||||
this.civName = civName
|
||||
this.gameInfo = gameInfo
|
||||
tech.techsResearched.add("Agriculture")
|
||||
this.placeUnitNearTile(startingLocation, "Settler")
|
||||
this.placeUnitNearTile(startingLocation, "Scout")
|
||||
}
|
||||
|
||||
fun clone(): CivilizationInfo {
|
||||
val toReturn = CivilizationInfo()
|
||||
toReturn.exploredTiles=exploredTiles.toHashSet()
|
||||
toReturn.diplomacy.putAll(diplomacy.values.map { it.clone() }.associateBy { it.otherCivName })
|
||||
toReturn.cities.addAll(cities.map { it.clone() })
|
||||
toReturn.tech = tech.clone()
|
||||
toReturn.difficulty=difficulty
|
||||
toReturn.policies = policies.clone()
|
||||
toReturn.happiness=happiness
|
||||
toReturn.greatPeople=greatPeople.clone()
|
||||
toReturn.gold = gold
|
||||
toReturn.goldenAges = goldenAges.clone()
|
||||
toReturn.civName=civName
|
||||
return toReturn
|
||||
}
|
||||
|
||||
//region pure functions
|
||||
fun getDifficulty() = GameBasics.Difficulties[difficulty]!!
|
||||
fun getNation() = GameBasics.Nations[civName]!!
|
||||
|
||||
fun getCapital()=cities.first { it.isCapital() }
|
||||
|
||||
fun isPlayerCivilization() = gameInfo.getPlayerCivilization()==this
|
||||
fun isBarbarianCivilization() = gameInfo.getBarbarianCivilization()==this
|
||||
|
||||
@ -118,7 +139,6 @@ class CivilizationInfo {
|
||||
return transportationUpkeep
|
||||
}
|
||||
|
||||
// base happiness
|
||||
fun getHappinessForNextTurn(): HashMap<String, Float> {
|
||||
val statMap = HashMap<String,Float>()
|
||||
statMap["Base happiness"] = getDifficulty().baseHappiness.toFloat()
|
||||
@ -153,17 +173,56 @@ class CivilizationInfo {
|
||||
|
||||
fun getBuildingUniques(): List<String> = cities.flatMap { it.cityConstructions.getBuiltBuildings().map { it.unique }.filterNotNull() }.distinct()
|
||||
|
||||
|
||||
constructor()
|
||||
|
||||
constructor(civName: String, startingLocation: Vector2, gameInfo: GameInfo) {
|
||||
this.civName = civName
|
||||
this.gameInfo = gameInfo
|
||||
tech.techsResearched.add("Agriculture")
|
||||
this.placeUnitNearTile(startingLocation, "Settler")
|
||||
this.placeUnitNearTile(startingLocation, "Scout")
|
||||
fun getCivUnits(): List<MapUnit> {
|
||||
return gameInfo.tileMap.values.flatMap { it.getUnits() }.filter { it.owner==civName }
|
||||
}
|
||||
|
||||
fun getViewableTiles(): List<TileInfo> {
|
||||
var viewablePositions = emptyList<TileInfo>()
|
||||
viewablePositions += cities.flatMap { it.getTiles() }
|
||||
.flatMap { it.neighbors } // tiles adjacent to city tiles
|
||||
viewablePositions += getCivUnits()
|
||||
.flatMap { it.getViewableTiles()} // Tiles within 2 tiles of units
|
||||
viewablePositions.map { it.position }.filterNot { exploredTiles.contains(it) }.toCollection(exploredTiles)
|
||||
|
||||
val viewedCivs = viewablePositions
|
||||
.flatMap { it.getUnits().map { u->u.civInfo }.union(listOf(it.getOwner())) }
|
||||
.filterNotNull().filterNot { it==this || it.isBarbarianCivilization() }
|
||||
|
||||
for(otherCiv in viewedCivs)
|
||||
if(!diplomacy.containsKey(otherCiv.civName)){
|
||||
diplomacy[otherCiv.civName] = DiplomacyManager(this@CivilizationInfo,otherCiv.civName)
|
||||
.apply { diplomaticStatus = DiplomaticStatus.Peace }
|
||||
otherCiv.diplomacy[civName] = DiplomacyManager(otherCiv,civName)
|
||||
.apply { diplomaticStatus = DiplomaticStatus.Peace }
|
||||
addNotification("We have encountered [${otherCiv.civName}]!".tr(),null, Color.GOLD)
|
||||
}
|
||||
|
||||
return viewablePositions.distinct()
|
||||
}
|
||||
|
||||
override fun toString(): String {return civName} // for debug
|
||||
|
||||
fun isDefeated()= cities.isEmpty() && !getCivUnits().any{it.name=="Settler"}
|
||||
fun getEra(): TechEra {
|
||||
val maxEraOfTech = tech.techsResearched.map { GameBasics.Technologies[it]!! }
|
||||
.map { it.era() }
|
||||
.max()
|
||||
if(maxEraOfTech!=null) return maxEraOfTech
|
||||
else return TechEra.Ancient
|
||||
}
|
||||
|
||||
fun isAtWarWith(otherCiv:CivilizationInfo): Boolean {
|
||||
if(otherCiv.isBarbarianCivilization() || isBarbarianCivilization()) return true
|
||||
if(!diplomacy.containsKey(otherCiv.civName)) // not encountered yet
|
||||
return false
|
||||
return diplomacy[otherCiv.civName]!!.diplomaticStatus == DiplomaticStatus.War
|
||||
}
|
||||
|
||||
fun isAtWar() = diplomacy.values.any { it.diplomaticStatus==DiplomaticStatus.War && !it.otherCiv().isDefeated() }
|
||||
//endregion
|
||||
|
||||
//region state-changing functions
|
||||
fun setTransients() {
|
||||
goldenAges.civInfo = this
|
||||
policies.civInfo = this
|
||||
@ -185,11 +244,6 @@ class CivilizationInfo {
|
||||
}
|
||||
}
|
||||
|
||||
fun addCity(location: Vector2) {
|
||||
val newCity = CityInfo(this, location)
|
||||
newCity.cityConstructions.chooseNextConstruction()
|
||||
}
|
||||
|
||||
fun endTurn() {
|
||||
val nextTurnStats = getStatsForNextTurn()
|
||||
|
||||
@ -236,6 +290,17 @@ class CivilizationInfo {
|
||||
getCivUnits().forEach { it.startTurn() }
|
||||
}
|
||||
|
||||
fun canEnterTiles(otherCiv: CivilizationInfo): Boolean {
|
||||
if(otherCiv==this) return true
|
||||
if(isAtWarWith(otherCiv)) return true
|
||||
return false
|
||||
}
|
||||
|
||||
fun addNotification(text: String, location: Vector2?,color: Color) {
|
||||
if(isPlayerCivilization())
|
||||
gameInfo.notifications.add(Notification(text, location,color))
|
||||
}
|
||||
|
||||
fun addGreatPerson(greatPerson: String) {
|
||||
val randomCity = cities.getRandom()
|
||||
placeUnitNearTile(cities.getRandom().location, greatPerson)
|
||||
@ -246,78 +311,10 @@ class CivilizationInfo {
|
||||
return gameInfo.tileMap.placeUnitNearTile(location, unitName, this)
|
||||
}
|
||||
|
||||
fun getCivUnits(): List<MapUnit> {
|
||||
return gameInfo.tileMap.values.flatMap { it.getUnits() }.filter { it.owner==civName }
|
||||
fun addCity(location: Vector2) {
|
||||
val newCity = CityInfo(this, location)
|
||||
newCity.cityConstructions.chooseNextConstruction()
|
||||
}
|
||||
|
||||
fun getViewableTiles(): List<TileInfo> {
|
||||
var viewablePositions = emptyList<TileInfo>()
|
||||
viewablePositions += cities.flatMap { it.getTiles() }
|
||||
.flatMap { it.neighbors } // tiles adjacent to city tiles
|
||||
viewablePositions += getCivUnits()
|
||||
.flatMap { it.getViewableTiles()} // Tiles within 2 tiles of units
|
||||
viewablePositions.map { it.position }.filterNot { exploredTiles.contains(it) }.toCollection(exploredTiles)
|
||||
|
||||
val viewedCivs = viewablePositions
|
||||
.flatMap { it.getUnits().map { u->u.civInfo }.union(listOf(it.getOwner())) }
|
||||
.filterNotNull().filterNot { it==this || it.isBarbarianCivilization() }
|
||||
|
||||
for(otherCiv in viewedCivs)
|
||||
if(!diplomacy.containsKey(otherCiv.civName)){
|
||||
diplomacy[otherCiv.civName] = DiplomacyManager(this@CivilizationInfo,otherCiv.civName)
|
||||
.apply { diplomaticStatus = DiplomaticStatus.Peace }
|
||||
otherCiv.diplomacy[civName] = DiplomacyManager(otherCiv,civName)
|
||||
.apply { diplomaticStatus = DiplomaticStatus.Peace }
|
||||
addNotification("We have encountered [${otherCiv.civName}]!".tr(),null, Color.GOLD)
|
||||
}
|
||||
|
||||
return viewablePositions.distinct()
|
||||
}
|
||||
|
||||
fun addNotification(text: String, location: Vector2?,color: Color) {
|
||||
if(isPlayerCivilization())
|
||||
gameInfo.notifications.add(Notification(text, location,color))
|
||||
}
|
||||
|
||||
override fun toString(): String {return civName} // for debug
|
||||
|
||||
fun isDefeated()= cities.isEmpty() && !getCivUnits().any{it.name=="Settler"}
|
||||
fun getEra(): TechEra {
|
||||
val maxEraOfTech = tech.techsResearched.map { GameBasics.Technologies[it]!! }
|
||||
.map { it.era() }
|
||||
.max()
|
||||
if(maxEraOfTech!=null) return maxEraOfTech
|
||||
else return TechEra.Ancient
|
||||
}
|
||||
|
||||
fun isAtWarWith(otherCiv:CivilizationInfo): Boolean {
|
||||
if(otherCiv.isBarbarianCivilization() || isBarbarianCivilization()) return true
|
||||
if(!diplomacy.containsKey(otherCiv.civName)) // not encountered yet
|
||||
return false
|
||||
return diplomacy[otherCiv.civName]!!.diplomaticStatus == DiplomaticStatus.War
|
||||
}
|
||||
|
||||
fun isAtWar() = diplomacy.values.any { it.diplomaticStatus==DiplomaticStatus.War && !it.otherCiv().isDefeated() }
|
||||
|
||||
fun canEnterTiles(otherCiv: CivilizationInfo): Boolean {
|
||||
if(otherCiv==this) return true
|
||||
if(isAtWarWith(otherCiv)) return true
|
||||
return false
|
||||
}
|
||||
|
||||
fun clone(): CivilizationInfo {
|
||||
val toReturn = CivilizationInfo()
|
||||
toReturn.exploredTiles=exploredTiles.toHashSet()
|
||||
toReturn.diplomacy.putAll(diplomacy.values.map { it.clone() }.associateBy { it.otherCivName })
|
||||
toReturn.cities.addAll(cities.map { it.clone() })
|
||||
toReturn.tech = tech.clone()
|
||||
toReturn.difficulty=difficulty
|
||||
toReturn.policies = policies.clone()
|
||||
toReturn.happiness=happiness
|
||||
toReturn.greatPeople=greatPeople.clone()
|
||||
toReturn.gold = gold
|
||||
toReturn.goldenAges = goldenAges.clone()
|
||||
toReturn.civName=civName
|
||||
return toReturn
|
||||
}
|
||||
//endregion
|
||||
}
|
@ -16,13 +16,33 @@ enum class DiplomaticStatus{
|
||||
class DiplomacyManager() {
|
||||
@Transient lateinit var civInfo: CivilizationInfo
|
||||
lateinit var otherCivName:String
|
||||
var trades = ArrayList<Trade>()
|
||||
var diplomaticStatus = DiplomaticStatus.War
|
||||
|
||||
fun clone(): DiplomacyManager {
|
||||
val toReturn = DiplomacyManager()
|
||||
toReturn.otherCivName=otherCivName
|
||||
toReturn.diplomaticStatus=diplomaticStatus
|
||||
toReturn.trades.addAll(trades.map { it.clone() })
|
||||
return toReturn
|
||||
}
|
||||
|
||||
constructor(civilizationInfo: CivilizationInfo, OtherCivName:String) : this() {
|
||||
civInfo=civilizationInfo
|
||||
otherCivName=OtherCivName
|
||||
}
|
||||
|
||||
var trades = ArrayList<Trade>()
|
||||
//region pure functions
|
||||
fun turnsToPeaceTreaty(): Int {
|
||||
for(trade in trades)
|
||||
for(offer in trade.ourOffers)
|
||||
if(offer.name=="Peace Treaty") return offer.duration
|
||||
return 0
|
||||
}
|
||||
|
||||
fun canDeclareWar() = turnsToPeaceTreaty()==0
|
||||
|
||||
fun otherCiv() = civInfo.gameInfo.civilizations.first{it.civName==otherCivName}
|
||||
|
||||
fun goldPerTurn():Int{
|
||||
var goldPerTurnForUs = 0
|
||||
@ -47,7 +67,9 @@ class DiplomacyManager() {
|
||||
}
|
||||
return counter
|
||||
}
|
||||
//endregion
|
||||
|
||||
//region state-changing functions
|
||||
fun removeUntenebleTrades(){
|
||||
val negativeCivResources = civInfo.getCivResources().filter { it.value<0 }.map { it.key.name }
|
||||
for(trade in trades.toList()) {
|
||||
@ -77,28 +99,10 @@ class DiplomacyManager() {
|
||||
removeUntenebleTrades()
|
||||
}
|
||||
|
||||
fun otherCiv() = civInfo.gameInfo.civilizations.first{it.civName==otherCivName}
|
||||
|
||||
var diplomaticStatus = DiplomaticStatus.War
|
||||
fun declareWar(){
|
||||
diplomaticStatus = DiplomaticStatus.War
|
||||
otherCiv().diplomacy[civInfo.civName]!!.diplomaticStatus = DiplomaticStatus.War
|
||||
otherCiv().addNotification("[civName] has declared war on us!",null, Color.RED)
|
||||
}
|
||||
|
||||
fun turnsToPeaceTreaty(): Int {
|
||||
for(trade in trades)
|
||||
for(offer in trade.ourOffers)
|
||||
if(offer.name=="Peace Treaty") return offer.duration
|
||||
return 0
|
||||
}
|
||||
|
||||
fun canDeclareWar() = turnsToPeaceTreaty()==0
|
||||
fun clone(): DiplomacyManager {
|
||||
val toReturn = DiplomacyManager()
|
||||
toReturn.otherCivName=otherCivName
|
||||
toReturn.diplomaticStatus=diplomaticStatus
|
||||
toReturn.trades.addAll(trades.map { it.clone() })
|
||||
return toReturn
|
||||
}
|
||||
//endregion
|
||||
}
|
@ -10,6 +10,14 @@ class GoldenAgeManager{
|
||||
private var numberOfGoldenAges = 0
|
||||
var turnsLeftForCurrentGoldenAge = 0
|
||||
|
||||
fun clone(): GoldenAgeManager {
|
||||
val toReturn = GoldenAgeManager()
|
||||
toReturn.numberOfGoldenAges=numberOfGoldenAges
|
||||
toReturn.storedHappiness=storedHappiness
|
||||
toReturn.turnsLeftForCurrentGoldenAge=turnsLeftForCurrentGoldenAge
|
||||
return toReturn
|
||||
}
|
||||
|
||||
fun isGoldenAge(): Boolean = turnsLeftForCurrentGoldenAge > 0
|
||||
|
||||
fun happinessRequiredForNextGoldenAge(): Int {
|
||||
@ -36,11 +44,4 @@ class GoldenAgeManager{
|
||||
}
|
||||
}
|
||||
|
||||
fun clone(): GoldenAgeManager {
|
||||
val toReturn = GoldenAgeManager()
|
||||
toReturn.numberOfGoldenAges=numberOfGoldenAges
|
||||
toReturn.storedHappiness=storedHappiness
|
||||
toReturn.turnsLeftForCurrentGoldenAge=turnsLeftForCurrentGoldenAge
|
||||
return toReturn
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,14 @@ class GreatPersonManager {
|
||||
private var greatPersonPoints = Stats()
|
||||
var freeGreatPeople=0
|
||||
|
||||
fun clone(): GreatPersonManager {
|
||||
val toReturn = GreatPersonManager()
|
||||
toReturn.freeGreatPeople=freeGreatPeople
|
||||
toReturn.greatPersonPoints=greatPersonPoints.clone()
|
||||
toReturn.pointsForNextGreatPerson=pointsForNextGreatPerson
|
||||
return toReturn
|
||||
}
|
||||
|
||||
fun getNewGreatPerson(): String? {
|
||||
var greatPerson: String? = null
|
||||
when {
|
||||
@ -27,12 +35,5 @@ class GreatPersonManager {
|
||||
greatPersonPoints.add(greatPersonPoints)
|
||||
}
|
||||
|
||||
fun clone(): GreatPersonManager {
|
||||
val toReturn = GreatPersonManager()
|
||||
toReturn.freeGreatPeople=freeGreatPeople
|
||||
toReturn.greatPersonPoints=greatPersonPoints.clone()
|
||||
toReturn.pointsForNextGreatPerson=pointsForNextGreatPerson
|
||||
return toReturn
|
||||
}
|
||||
|
||||
}
|
@ -28,14 +28,15 @@ class PolicyManager {
|
||||
return cost - (cost % 5)
|
||||
}
|
||||
|
||||
|
||||
fun getAdoptedPolicies(): HashSet<String> = adoptedPolicies
|
||||
|
||||
fun isAdopted(policyName: String): Boolean = adoptedPolicies.contains(policyName)
|
||||
|
||||
fun isAdoptable(policy: Policy) = !policy.name.endsWith("Complete")
|
||||
&& getAdoptedPolicies().containsAll(policy.requires!!)
|
||||
&& policy.getBranch().era <= civInfo.getEra()
|
||||
fun isAdoptable(policy: Policy): Boolean {
|
||||
return (!policy.name.endsWith("Complete")
|
||||
&& getAdoptedPolicies().containsAll(policy.requires!!)
|
||||
&& policy.getBranch().era <= civInfo.getEra())
|
||||
}
|
||||
|
||||
fun canAdoptPolicy(): Boolean = freePolicies > 0 || storedCulture >= getCultureNeededForNextPolicy()
|
||||
|
||||
|
@ -3,10 +3,16 @@ package com.unciv.logic.civilization
|
||||
import com.unciv.models.Counter
|
||||
|
||||
class ScienceVictoryManager {
|
||||
|
||||
var requiredParts = Counter<String>()
|
||||
var currentParts = Counter<String>()
|
||||
|
||||
init {
|
||||
requiredParts.add("SS Booster", 3)
|
||||
requiredParts.add("SS Cockpit", 1)
|
||||
requiredParts.add("SS Engine", 1)
|
||||
requiredParts.add("SS Statis Chamber", 1)
|
||||
}
|
||||
|
||||
fun unconstructedParts(): Counter<String> {
|
||||
val counter = requiredParts.clone()
|
||||
counter.remove(currentParts)
|
||||
@ -14,11 +20,4 @@ class ScienceVictoryManager {
|
||||
}
|
||||
|
||||
fun hasWon() = requiredParts.equals(currentParts)
|
||||
|
||||
init {
|
||||
requiredParts.add("SS Booster", 3)
|
||||
requiredParts.add("SS Cockpit", 1)
|
||||
requiredParts.add("SS Engine", 1)
|
||||
requiredParts.add("SS Statis Chamber", 1)
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,16 @@ class TechManager {
|
||||
var techsToResearch = ArrayList<String>()
|
||||
private var techsInProgress = HashMap<String, Int>()
|
||||
|
||||
//region state-changing functions
|
||||
fun clone(): TechManager {
|
||||
val toReturn = TechManager()
|
||||
toReturn.techsResearched.addAll(techsResearched)
|
||||
toReturn.freeTechs=freeTechs
|
||||
toReturn.techsInProgress.putAll(techsInProgress)
|
||||
toReturn.techsToResearch.addAll(techsToResearch)
|
||||
return toReturn
|
||||
}
|
||||
|
||||
private fun getCurrentTechnology(): Technology = GameBasics.Technologies[currentTechnology()]!!
|
||||
|
||||
fun costOfTech(techName: String): Int {
|
||||
@ -45,6 +55,7 @@ class TechManager {
|
||||
fun canBeResearched(TechName: String): Boolean {
|
||||
return GameBasics.Technologies[TechName]!!.prerequisites.all { isResearched(it) }
|
||||
}
|
||||
//endregion
|
||||
|
||||
fun nextTurn(scienceForNewTurn: Int) {
|
||||
val currentTechnology = currentTechnology()
|
||||
@ -92,15 +103,6 @@ class TechManager {
|
||||
city.cityConstructions.currentConstruction = currentConstructionUnit.upgradesTo!!
|
||||
}
|
||||
}
|
||||
|
||||
fun clone(): TechManager {
|
||||
val toReturn = TechManager()
|
||||
toReturn.techsResearched.addAll(techsResearched)
|
||||
toReturn.freeTechs=freeTechs
|
||||
toReturn.techsInProgress.putAll(techsInProgress)
|
||||
toReturn.techsToResearch.addAll(techsToResearch)
|
||||
return toReturn
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user