Can now trade Peace Treaty! Which leads to actual fukken peace!

This commit is contained in:
Yair Morgenstern 2018-07-31 17:48:57 +03:00
parent fa8e8a148d
commit d8bb0eb9e5
12 changed files with 130 additions and 57 deletions

View file

@ -21,8 +21,8 @@ android {
applicationId "com.unciv.game"
minSdkVersion 14
targetSdkVersion 26
versionCode 107
versionName "2.6.9"
versionCode 108
versionName "2.6.10"
}
buildTypes {
release {

View file

@ -38,7 +38,7 @@ class UnitAutomation{
fun containsAttackableEnemy(tile: TileInfo, civInfo: CivilizationInfo): Boolean {
val tileCombatant = Battle().getMapCombatantOfTile(tile)
if(tileCombatant==null) return false
return tileCombatant.getCivilization()!=civInfo// && civInfo.isAtWarWith(tileCombatant.getCivilization())
return tileCombatant.getCivilization()!=civInfo && civInfo.isAtWarWith(tileCombatant.getCivilization())
}
class AttackableTile(val tileToAttackFrom:TileInfo, val tileToAttack:TileInfo)

View file

@ -103,22 +103,13 @@ class Battle(val gameInfo:GameInfo=UnCivGame.Current.gameInfo) {
private fun conquerCity(city: CityInfo, attacker: ICombatant) {
val enemyCiv = city.civInfo
attacker.getCivilization().addNotification("We have conquered the city of [${city.name}]!",city.location, Color.RED)
enemyCiv.cities.remove(city)
attacker.getCivilization().cities.add(city)
city.civInfo = attacker.getCivilization()
city.moveToCiv(attacker.getCivilization())
city.health = city.getMaxHealth() / 2 // I think that cities recover to half health when conquered?
city.getCenterTile().apply {
militaryUnit = null
if(civilianUnit!=null) captureCivilianUnit(attacker,MapUnitCombatant(civilianUnit!!))
}
city.expansion.cultureStored = 0
city.expansion.reset()
// now that the tiles have changed, we need to reassign population
city.workedTiles.filterNot { city.tiles.contains(it) }
.forEach { city.workedTiles.remove(it); city.population.autoAssignPopulation() }
if(city.cityConstructions.isBuilt("Palace")){
city.cityConstructions.builtBuildings.remove("Palace")
if(enemyCiv.isDefeated()) {
@ -131,12 +122,7 @@ class Battle(val gameInfo:GameInfo=UnCivGame.Current.gameInfo) {
}
}
// Remove all national wonders when conquering a city
for(building in city.cityConstructions.getBuiltBuildings().filter { it.requiredBuildingInAllCities!=null })
city.cityConstructions.builtBuildings.remove(building.name)
(attacker as MapUnitCombatant).unit.moveToTile(city.getCenterTile())
city.civInfo.gameInfo.updateTilesToCities()
}
fun getMapCombatantOfTile(tile:TileInfo): ICombatant? {

View file

@ -25,7 +25,7 @@ class CityCombatant(val city: CityInfo) : ICombatant {
return getCityStrength()
}
private fun getCityStrength(): Int { // Civ fanatics forum, from a modder who went through the original code
fun getCityStrength(): Int { // Civ fanatics forum, from a modder who went through the original code
var strength = 8f
if(city.isCapital()) strength+=2.5f
strength += (city.population.population/5) * 2 // Each 5 pop gives 2 defence

View file

@ -149,6 +149,25 @@ class CityInfo {
fun isCapital() = cityConstructions.isBuilt("Palace")
fun moveToCiv(newCivInfo: CivilizationInfo){
civInfo.cities.remove(this)
newCivInfo.cities.add(this)
civInfo = newCivInfo
expansion.cultureStored = 0
expansion.reset()
// now that the tiles have changed, we need to reassign population
workedTiles.filterNot { tiles.contains(it) }
.forEach { workedTiles.remove(it); population.autoAssignPopulation() }
// Remove all national wonders
for(building in cityConstructions.getBuiltBuildings().filter { it.requiredBuildingInAllCities!=null })
cityConstructions.builtBuildings.remove(building.name)
civInfo.gameInfo.updateTilesToCities()
}
internal fun getMaxHealth(): Int {
return 200 + cityConstructions.getBuiltBuildings().sumBy { it.cityHealth }
}

View file

@ -289,12 +289,17 @@ class CivilizationInfo {
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 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 canEnterTiles(otherCiv: CivilizationInfo): Boolean {
if(isAtWarWith(otherCiv)) return true
return false
}
}

View file

@ -22,7 +22,6 @@ class DiplomacyManager() {
otherCivName=OtherCivName
}
// var status:DiplomaticStatus = DiplomaticStatus.War
var trades = ArrayList<Trade>()
fun goldPerTurn():Int{
@ -80,9 +79,9 @@ class DiplomacyManager() {
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
// }
var diplomaticStatus = DiplomaticStatus.War
fun declareWar(){
diplomaticStatus = DiplomaticStatus.War
otherCiv().diplomacy[civInfo.civName]!!.diplomaticStatus = DiplomaticStatus.War
}
}

View file

@ -189,7 +189,10 @@ class MapUnit {
* Designates whether we can walk to the tile - without attacking
*/
fun canMoveTo(tile: TileInfo): Boolean {
if(tile.isCityCenter() && tile.getOwner()!!.civName!=owner) return false
val tileOwner = tile.getOwner()
if(tileOwner!=null && tileOwner.civName!=owner) {
if (tile.isCityCenter() || !civInfo.canEnterTiles(tileOwner)) return false
}
if (getBaseUnit().unitType== UnitType.Civilian)
return tile.civilianUnit==null && (tile.militaryUnit==null || tile.militaryUnit!!.owner==owner)
else return tile.militaryUnit==null && (tile.civilianUnit==null || tile.civilianUnit!!.owner==owner)

View file

@ -1,6 +1,7 @@
package com.unciv.logic.map
import com.badlogic.gdx.math.Vector2
import com.unciv.models.gamebasics.unit.UnitType
class UnitMovementAlgorithms(val unit:MapUnit) {
val tileMap = unit.getTile().tileMap
@ -167,14 +168,19 @@ class UnitMovementAlgorithms(val unit:MapUnit) {
throw Exception("We couldn't get the path between the two tiles")
}
// fun moveToClosestMoveableTile(){
// val unitCurrentTile = unit.getTile()
// var allowedTile:TileInfo? = null
// var distance=0
// while(allowedTile==null){
// distance++
// allowedTile = tileMap.tilesat
// }
// }
fun teleportToClosestMoveableTile(){
val unitCurrentTilePosition = unit.getTile().position
var allowedTile:TileInfo? = null
var distance=0
while(allowedTile==null){
distance++
allowedTile = tileMap.getTilesAtDistance(unitCurrentTilePosition,distance)
.firstOrNull{unit.canMoveTo(it)}
}
unit.removeFromTile() // we "teleport" them away
if(unit.getBaseUnit().unitType==UnitType.Civilian)
allowedTile.civilianUnit=unit
else allowedTile.militaryUnit=unit
}
}

View file

@ -10,6 +10,7 @@ import com.unciv.ui.utils.tr
import kotlin.math.min
class OffersList(val offers: TradeOffersList, val correspondingOffers: TradeOffersList,
val otherCivOffers: TradeOffersList, val otherCivCorrespondingOffers:TradeOffersList,
val onChange: () -> Unit) : ScrollPane(null) {
val table= Table(CameraStageBaseScreen.skin).apply { defaults().pad(5f) }
init {
@ -32,6 +33,11 @@ class OffersList(val offers: TradeOffersList, val correspondingOffers: TradeOffe
val amountTransferred = min(amountPerClick, offer.amount)
offers += offer.copy(amount = -amountTransferred)
correspondingOffers += offer.copy(amount = amountTransferred)
if(offer.type==TradeType.Treaty) { // this goes both ways, so it doesn't matter which side you click
otherCivOffers += offer.copy(amount = -amountTransferred)
otherCivCorrespondingOffers += offer.copy(amount = amountTransferred)
}
onChange()
update()
}

View file

@ -1,11 +1,11 @@
package com.unciv.logic.trade
enum class TradeType{
Luxury_Resource,
Strategic_Resource,
Gold,
Gold_Per_Turn,
City,
Treaty,
Luxury_Resource,
Strategic_Resource,
Technology,
Treaty
City
}

View file

@ -4,7 +4,9 @@ import com.badlogic.gdx.scenes.scene2d.ui.Label
import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.badlogic.gdx.scenes.scene2d.ui.TextButton
import com.unciv.UnCivGame
import com.unciv.logic.battle.CityCombatant
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.logic.civilization.DiplomaticStatus
import com.unciv.logic.trade.OffersList
import com.unciv.logic.trade.Trade
import com.unciv.logic.trade.TradeOffersList
@ -12,6 +14,7 @@ import com.unciv.logic.trade.TradeType
import com.unciv.models.gamebasics.GameBasics
import com.unciv.models.gamebasics.tile.ResourceType
import com.unciv.ui.utils.*
import kotlin.math.max
import kotlin.math.sqrt
@ -45,12 +48,18 @@ class TradeScreen(val otherCivilization: CivilizationInfo) : CameraStageBaseScre
tradeText.setText("What do you have in mind?".tr())
}
val ourAvailableOffersTable = OffersList(ourAvailableOffers, currentTrade.ourOffers) { onChange() }
val ourOffersTable = OffersList(currentTrade.ourOffers, ourAvailableOffers) { onChange() }
val theirOffersTable = OffersList(currentTrade.theirOffers, theirAvailableOffers) { onChange() }
val theirAvailableOffersTable = OffersList(theirAvailableOffers, currentTrade.theirOffers) { onChange() }
val ourAvailableOffersTable = OffersList(ourAvailableOffers, currentTrade.ourOffers,
theirAvailableOffers, currentTrade.theirOffers) { onChange() }
val ourOffersTable = OffersList(currentTrade.ourOffers, ourAvailableOffers,
currentTrade.theirOffers, theirAvailableOffers) { onChange() }
val theirOffersTable = OffersList(currentTrade.theirOffers, theirAvailableOffers,
currentTrade.ourOffers, ourAvailableOffers) { onChange() }
val theirAvailableOffersTable = OffersList(theirAvailableOffers, currentTrade.theirOffers,
ourAvailableOffers, currentTrade.ourOffers) { onChange() }
init {
val peaceCost = evaluatePeaceCostForThem()
val closeButton = TextButton("Close".tr(), skin)
closeButton.addClickListener { UnCivGame.Current.setWorldScreen() }
closeButton.y = stage.height - closeButton.height - 5
@ -90,9 +99,15 @@ class TradeScreen(val otherCivilization: CivilizationInfo) : CameraStageBaseScre
}
if(offer.type==TradeType.City){
val city = them.cities.first { it.name==offer.name }
us.cities.add(city)
them.cities.remove(city)
city.moveToCiv(us)
city.getCenterTile().getUnits().forEach { it.movementAlgs().teleportToClosestMoveableTile() }
}
if(offer.type==TradeType.Treaty){
if(offer.name=="Peace Treaty"){
us.diplomacy[them.civName]!!.diplomaticStatus=DiplomaticStatus.Peace
for(unit in us.getCivUnits().filter { it.getTile().getOwner()==them })
unit.movementAlgs().teleportToClosestMoveableTile()
}
}
}
}
@ -138,6 +153,8 @@ class TradeScreen(val otherCivilization: CivilizationInfo) : CameraStageBaseScre
fun getAvailableOffers(civInfo: CivilizationInfo, otherCivilization: CivilizationInfo): TradeOffersList {
val offers = TradeOffersList()
if(civInfo.isAtWarWith(otherCivilization))
offers.add(TradeOffer("Peace Treaty",TradeType.Treaty,20,1))
for(entry in civInfo.getCivResources().filterNot { it.key.resourceType == ResourceType.Bonus }) {
val resourceTradeType = if(entry.key.resourceType==ResourceType.Luxury) TradeType.Luxury_Resource
else TradeType.Strategic_Resource
@ -150,13 +167,14 @@ class TradeScreen(val otherCivilization: CivilizationInfo) : CameraStageBaseScre
}
offers.add(TradeOffer("Gold".tr(), TradeType.Gold,0,civInfo.gold))
offers.add(TradeOffer("Gold per turn".tr(), TradeType.Gold_Per_Turn,30,civInfo.getStatsForNextTurn().gold.toInt()))
// for(city in civInfo.cities.filterNot { it.isCapital() })
// offers.add(TradeOffer(city.name,TradeType.City,0,1))
for(city in civInfo.cities.filterNot { it.isCapital() })
offers.add(TradeOffer(city.name,TradeType.City,0,1))
return offers
}
fun isTradeAcceptable(trade: Trade): Boolean {
val sumOfTheirOffers = trade.theirOffers.map { evaluateOffer(it,false) }.sum()
val sumOfTheirOffers = trade.theirOffers.filter { it.type!=TradeType.Treaty } // since treaties should only be evaluated once for 2 sides
.map { evaluateOffer(it,false) }.sum()
val sumOfOurOffers = trade.ourOffers.map { evaluateOffer(it,true)}.sum()
return sumOfOurOffers >= sumOfTheirOffers
}
@ -180,18 +198,49 @@ class TradeScreen(val otherCivilization: CivilizationInfo) : CameraStageBaseScre
}
}
TradeType.Technology -> return sqrt(GameBasics.Technologies[offer.name]!!.cost.toDouble()).toInt()*10 // gold cost is science cost
TradeType.Technology -> return sqrt(GameBasics.Technologies[offer.name]!!.cost.toDouble()).toInt()*10
TradeType.Strategic_Resource -> return 50 * offer.amount
TradeType.City -> {
val civ = if(otherCivIsRecieving) civInfo else otherCivilization
val city = civ.cities.first { it.name==offer.name }
val stats = city.cityStats.currentCityStats
val sumOfStats = stats.culture+stats.gold+stats.science+stats.production+stats.happiness+stats.food
return sumOfStats.toInt() * 10
return sumOfStats.toInt() * 100
}
TradeType.Treaty -> {
if(offer.name=="Peace Treaty")
return evaluatePeaceCostForThem() // Since it will be evaluated twice, once when they evaluate our offer and once when they evaluate theirs
else return 1000
}
// Dunno what this is?
else -> return 1000
}
}
fun evaluteCombatStrength(civInfo: CivilizationInfo): Int {
// Since units become exponentially stronger per combat strength increase, we square em all
fun square(x:Int) = x*x
val unitStrength = civInfo.getCivUnits().map { square(max(it.getBaseUnit().strength,it.getBaseUnit().rangedStrength)) }.sum()
val cityStrength = civInfo.cities.map { square(CityCombatant(it).getCityStrength()) }.sum()
return (sqrt(unitStrength.toDouble()) /*+ sqrt(cityStrength.toDouble())*/).toInt()
}
fun evaluatePeaceCostForThem(): Int {
val ourCombatStrength = evaluteCombatStrength(civInfo)
val theirCombatStrength = evaluteCombatStrength(otherCivilization)
if(ourCombatStrength==theirCombatStrength) return 0
if(ourCombatStrength==0) return 1000
if(theirCombatStrength==0) return -1000 // Chumps got no cities or units
if(ourCombatStrength>theirCombatStrength){
val absoluteAdvantage = ourCombatStrength-theirCombatStrength
val percentageAdvantage = absoluteAdvantage / theirCombatStrength.toFloat()
return (absoluteAdvantage*percentageAdvantage).toInt() * 10
}
else{
val absoluteAdvantage = theirCombatStrength-ourCombatStrength
val percentageAdvantage = absoluteAdvantage / ourCombatStrength.toFloat()
return -(absoluteAdvantage*percentageAdvantage).toInt() * 10
}
}
}