Added German nation - #703

This commit is contained in:
Yair Morgenstern 2019-06-17 11:20:15 +03:00
parent eb711b9a79
commit 853a325876
16 changed files with 140 additions and 100 deletions

View File

@ -508,6 +508,7 @@
specialistSlots:{gold:1},
hurryCostModifier:15,
percentStatBonus:{gold:25},
uniques:["+5% Production for every Trade Route with a City-State in the empire"]
requiredBuilding:"Market",
requiredTech:"Banking"
},

View File

@ -430,8 +430,7 @@
"Kolhapur","Prayaga","Ayodhya","Indraprastha","Mathura","Ujjain","Gulbarga","Jaunpur","Rajagriha","Sravasti","Tiruchirapalli","Thanjavur",
"Bodhgaya","Kushinagar","Amaravati","Gaur","Gwalior","Jaipur","Karachi"]
},
/*
{ // REQUIRES BARBARIAN CAMPS
{
name:"Germany",
leaderName:"Otto von Bismark",
adjective:["German"],
@ -458,8 +457,8 @@
afterPeace:"What do ye think about calling it a draw?"
tradeRequest:"It would be in your best interest, to carefully consider this proposal."
mainColor:[224,224,224],
secondaryColor:[64,64,64],
mainColor:[150,150,150],
secondaryColor:[60,60,60],
uniqueName:"Furor Teutonicus"
unique:"67% chance to earn 25 Gold and recruit a Barbarian unit from a conquered encampment, -25% land units maintenance.",
cities:["Berlin","Hamburg","Munich","Cologne","Frankfurt","Essen","Dortmund","Stuttgart","Dusseldorf","Bremen",
@ -470,6 +469,7 @@
"Recklinghausen","Gצttingen","Wolfsburg","Koblenz","Hildesheim","Erlangen"]
},
/*
{ // REQUIRES RIVERS
name:"Aztecs",
leaderName:"Montezuma I",

View File

@ -362,6 +362,9 @@
French:"Nous avons capturé un campement barbare et pillé [goldAmount] ors"
}
"A barbarian [unitType] has joined us!":{
}
///////////////// ruins
"We have found survivors in the ruins - population added to [cityName]":{

View File

@ -516,7 +516,6 @@
attackSound:"metalhit"
//Pikeman should upgrade not only to Musketman but also to Lancer
},
/*
{
name:"Landsknecht",
replaces:"Pikeman",
@ -532,7 +531,6 @@
hurryCostModifier:20,
attackSound:"metalhit"
},
*/
{
name:"Galleass",
unitType:"WaterRanged",
@ -1014,7 +1012,6 @@
uniques:["Can move after attacking","No defensive terrain bonus"]
hurryCostModifier:20,
},
/*
{
name:"Panzer",
unitType:"Armor",
@ -1029,7 +1026,6 @@
hurryCostModifier:20,
//German unique unit, stronger than Tank
},
*/
{
name:"Anti-Tank Gun",
unitType:"Melee",

View File

@ -85,6 +85,16 @@ class Battle(val gameInfo:GameInfo) {
conquerCity(defender.city, attacker)
}
// German unique - needs to be checked before we try to move to the enemy tile, since the encampment disappears after we move in
if(defender.isDefeated() && defender.getCivInfo().isBarbarianCivilization() && attackedTile.improvement==Constants.barbarianEncampment
&& attacker.getCivInfo().getNation().unique== "67% chance to earn 25 Gold and recruit a Barbarian unit from a conquered encampment, -25% land units maintenance."
&& Random().nextDouble() > 0.67){
attacker.getCivInfo().placeUnitNearTile(attackedTile.position, defender.getName())
attacker.getCivInfo().gold += 25
attacker.getCivInfo().addNotification("A barbarian [${defender.getName()}] has joined us!",attackedTile.position, Color.RED)
}
// we're a melee unit and we destroyed\captured an enemy unit
else if (attacker.isMelee()
&& (defender.isDefeated() || defender.getCivInfo()==attacker.getCivInfo())
@ -96,6 +106,7 @@ class Battle(val gameInfo:GameInfo) {
attacker.unit.moveToTile(attackedTile)
}
if(attacker is MapUnitCombatant) {
val unit = attacker.unit
if (unit.hasUnique("Can move after attacking")
@ -141,6 +152,7 @@ class Battle(val gameInfo:GameInfo) {
addXp(defender,2,attacker)
}
// Add culture when defeating a barbarian when Honor policy is adopted (can be either attacker or defender!)
fun tryGetCultureFromHonor(civUnit:ICombatant, barbarianUnit:ICombatant){
if(barbarianUnit.isDefeated() && barbarianUnit is MapUnitCombatant

View File

@ -49,8 +49,8 @@ class CityConstructions {
fun getStatPercentBonuses(): Stats {
val stats = Stats()
for (building in getBuiltBuildings().filter { it.percentStatBonus != null })
stats.add(building.percentStatBonus!!)
for (building in getBuiltBuildings())
stats.add(building.getStatPercentageBonuses(cityInfo.civInfo))
return stats
}

View File

@ -17,7 +17,6 @@ import kotlin.math.min
class CityInfo {
@Transient lateinit var civInfo: CivilizationInfo
@Transient var isConnectedToCapital = false
@Transient lateinit var ccenterTile:TileInfo // cached for better performance
@Transient val range = 2
@Transient lateinit var tileMap: TileMap
@ -95,7 +94,6 @@ class CityInfo {
toReturn.tiles = tiles
toReturn.workedTiles = workedTiles
toReturn.isBeingRazed=isBeingRazed
toReturn.isConnectedToCapital = isConnectedToCapital
toReturn.attackedThisTurn = attackedThisTurn
toReturn.resistanceCounter = resistanceCounter
return toReturn
@ -178,6 +176,7 @@ class CityInfo {
}
fun isCapital() = cityConstructions.isBuilt("Palace")
fun isConnectedToCapital() = civInfo.citiesConnectedToCapital.contains(this)
internal fun getMaxHealth(): Int {
return 200 + cityConstructions.getBuiltBuildings().sumBy { it.cityHealth }

View File

@ -34,7 +34,7 @@ class CityStats {
private fun getStatsFromTradeRoute(): Stats {
val stats = Stats()
if (!cityInfo.isCapital() && isConnectedToCapital(RoadStatus.Road)) {
if (!cityInfo.isCapital() && cityInfo.isConnectedToCapital()) {
val civInfo = cityInfo.civInfo
var goldFromTradeRoute = civInfo.getCapital().population.population * 0.15 + cityInfo.population.population * 1.1 - 1 // Calculated by http://civilization.wikia.com/wiki/Trade_route_(Civ5)
if(civInfo.getNation().unique=="+1 Gold from each Trade Route, Oil resources provide double quantity") goldFromTradeRoute += 1
@ -196,7 +196,7 @@ class CityStats {
happinessFromPolicies += (cityInfo.population.population / 10).toFloat()
if (civInfo.policies.isAdopted("Monarchy") && cityInfo.isCapital())
happinessFromPolicies += (cityInfo.population.population / 2).toFloat()
if (civInfo.policies.isAdopted("Meritocracy") && isConnectedToCapital(RoadStatus.Road))
if (civInfo.policies.isAdopted("Meritocracy") && cityInfo.isConnectedToCapital())
happinessFromPolicies += 1f
if(civInfo.policies.isAdopted("Military Caste") && cityInfo.getCenterTile().militaryUnit!=null)
happinessFromPolicies+=1
@ -320,7 +320,7 @@ class CityStats {
fun isConnectedToCapital(roadType: RoadStatus): Boolean {
if (cityInfo.civInfo.cities.count() < 2) return false// first city!
if(roadType==RoadStatus.Road) return cityInfo.isConnectedToCapital // this transient is not applicable to connection via railroad.
if(roadType==RoadStatus.Road) return cityInfo.isConnectedToCapital() // this transient is not applicable to connection via railroad.
val capitalTile = cityInfo.civInfo.getCapital().getCenterTile()
val bfs = BFS(capitalTile){it.roadStatus == roadType}

View File

@ -0,0 +1,7 @@
package com.unciv.logic.civilization
enum class CityStateType{
Cultured,
Maritime,
Mercantile
}

View File

@ -14,7 +14,7 @@ import com.unciv.logic.map.BFS
import com.unciv.logic.map.MapUnit
import com.unciv.logic.map.RoadStatus
import com.unciv.logic.map.TileInfo
import com.unciv.logic.trade.Trade
import com.unciv.logic.trade.TradeRequest
import com.unciv.models.gamebasics.*
import com.unciv.models.gamebasics.tech.TechEra
import com.unciv.models.gamebasics.tile.ResourceSupplyList
@ -25,24 +25,10 @@ import java.util.*
import kotlin.collections.ArrayList
import kotlin.collections.HashMap
import kotlin.math.max
import kotlin.math.min
import kotlin.math.pow
import kotlin.math.roundToInt
enum class PlayerType{
AI,
Human
}
enum class CityStateType{
Cultured,
Maritime,
Mercantile
}
class TradeRequest(val requestingCiv:String,
/** Their offers are what they offer us, and our offers are what they want in return */
val trade: Trade)
class CivilizationInfo {
@Transient lateinit var gameInfo: GameInfo
/**
@ -53,6 +39,8 @@ class CivilizationInfo {
@Transient private var units=listOf<MapUnit>()
@Transient var viewableTiles = setOf<TileInfo>()
@Transient var viewableInvisibleUnitsTiles = setOf<TileInfo>()
/** Contains cities from ALL civilizations connected by trade routes to the capital */
@Transient var citiesConnectedToCapital = listOf<CityInfo>()
/** This is for performance since every movement calculation depends on this, see MapUnit comment */
@Transient var hasActiveGreatWall = false
@ -203,9 +191,16 @@ class CivilizationInfo {
val freeUnits = 3
var unitsToPayFor = getCivUnits()
if(policies.isAdopted("Oligarchy")) unitsToPayFor = unitsToPayFor.filterNot { it.getTile().isCityCenter() }
val totalPaidUnits = max(0,unitsToPayFor.count()-freeUnits)
var numberOfUnitsToPayFor = max(0f, unitsToPayFor.count().toFloat() - freeUnits)
if(getNation().unique=="67% chance to earn 25 Gold and recruit a Barbarian unit from a conquered encampment, -25% land units maintenance."){
val numberOfUnitsWithDiscount = min(numberOfUnitsToPayFor, unitsToPayFor.count { it.type.isLandUnit() }.toFloat())
numberOfUnitsToPayFor -= 0.25f * numberOfUnitsWithDiscount
}
val gameProgress = gameInfo.turns/400f // as game progresses Maintenance cost rises
var cost = baseUnitCost*totalPaidUnits*(1+gameProgress)
var cost = baseUnitCost*numberOfUnitsToPayFor*(1+gameProgress)
cost = cost.pow(1+gameProgress/3) // Why 3? To spread 1 to 1.33
if(!isPlayerCivilization())
cost *= gameInfo.getDifficulty().aiUnitMaintenanceModifier
@ -544,6 +539,7 @@ class CivilizationInfo {
val citiesReachedToMediums = HashMap<CityInfo,ArrayList<String>>()
var citiesToCheck = mutableListOf(getCapital())
citiesReachedToMediums[getCapital()] = arrayListOf("Start")
while(citiesToCheck.isNotEmpty() && citiesReachedToMediums.size<cities.size){
val newCitiesToCheck = mutableListOf<CityInfo>()
for(cityToConnectFrom in citiesToCheck){
@ -551,6 +547,7 @@ class CivilizationInfo {
// This is copypasta and can be cleaned up
if(!reachedMediums.contains("Road")){
val roadBfs = BFS(cityToConnectFrom.getCenterTile()){it.roadStatus!=RoadStatus.None}
roadBfs.stepToEnd()
val reachedCities = cities.filter { roadBfs.tilesReached.containsKey(it.getCenterTile())}
@ -586,9 +583,7 @@ class CivilizationInfo {
citiesToCheck = newCitiesToCheck
}
for(city in cities){
city.isConnectedToCapital = citiesReachedToMediums.containsKey(city)
}
citiesConnectedToCapital = citiesReachedToMediums.keys.toList()
}
fun destroy(){

View File

@ -0,0 +1,6 @@
package com.unciv.logic.civilization
enum class PlayerType{
AI,
Human
}

View File

@ -39,3 +39,8 @@ class Trade{
theirOffers.addAll(trade.theirOffers)
}
}
class TradeRequest(val requestingCiv:String,
/** Their offers are what they offer us, and our offers are what they want in return */
val trade: Trade)

View File

@ -55,10 +55,9 @@ class Building : NamedStats(), IConstruction{
val infoList= mutableListOf<String>()
val str = getStats(null).toString()
if(str.isNotEmpty()) infoList += str
if(percentStatBonus!=null){
for(stat in percentStatBonus!!.toHashMap())
for(stat in getStatPercentageBonuses(null).toHashMap())
if(stat.value!=0f) infoList+="+${stat.value.toInt()}% ${stat.key.toString().tr()}"
}
val improvedResources = GameBasics.TileResources.values.filter { it.building==name }.map { it.name.tr() }
if(improvedResources.isNotEmpty()){
// buildings that improve resources
@ -93,13 +92,14 @@ class Building : NamedStats(), IConstruction{
if(uniques.isNotEmpty()) stringBuilder.appendln(uniques.asSequence().map { it.tr() }.joinToString("\n"))
if (stats.toString() != "")
stringBuilder.appendln(stats)
if (this.percentStatBonus != null) {
if (this.percentStatBonus!!.production != 0f) stringBuilder.append("+" + this.percentStatBonus!!.production.toInt() + "% {Production}\n".tr())
if (this.percentStatBonus!!.gold != 0f) stringBuilder.append("+" + this.percentStatBonus!!.gold.toInt() + "% {Gold}\n".tr())
if (this.percentStatBonus!!.science != 0f) stringBuilder.append("+" + this.percentStatBonus!!.science.toInt() + "% {Science}\r\n".tr())
if (this.percentStatBonus!!.food != 0f) stringBuilder.append("+" + this.percentStatBonus!!.food.toInt() + "% {Food}\n".tr())
if (this.percentStatBonus!!.culture != 0f) stringBuilder.append("+" + this.percentStatBonus!!.culture.toInt() + "% {Culture}\r\n".tr())
}
val percentStats = getStatPercentageBonuses(civInfo)
if (percentStats.production != 0f) stringBuilder.append("+" + percentStats.production.toInt() + "% {Production}\n".tr())
if (percentStats.gold != 0f) stringBuilder.append("+" + percentStats.gold.toInt() + "% {Gold}\n".tr())
if (percentStats.science != 0f) stringBuilder.append("+" + percentStats.science.toInt() + "% {Science}\r\n".tr())
if (percentStats.food != 0f) stringBuilder.append("+" + percentStats.food.toInt() + "% {Food}\n".tr())
if (percentStats.culture != 0f) stringBuilder.append("+" + percentStats.culture.toInt() + "% {Culture}\r\n".tr())
if (this.greatPersonPoints != null) {
val gpp = this.greatPersonPoints!!
if (gpp.production != 0f) stringBuilder.appendln("+" + gpp.production.toInt()+" " + "[Great Engineer] points".tr())
@ -143,12 +143,6 @@ class Building : NamedStats(), IConstruction{
if (adoptedPolicies.contains("Humanism") && hashSetOf("University", "Observatory", "Public School").contains(baseBuildingName ))
stats.happiness += 1f
if (adoptedPolicies.contains("Theocracy") && baseBuildingName == "Temple")
percentStatBonus = Stats().apply { gold = 10f }
if (adoptedPolicies.contains("Free Thought") && baseBuildingName == "University")
percentStatBonus!!.science = 50f
if (adoptedPolicies.contains("Rationalism Complete") && !isWonder && stats.science > 0)
stats.gold += 1f
@ -168,6 +162,26 @@ class Building : NamedStats(), IConstruction{
return stats
}
fun getStatPercentageBonuses(civInfo: CivilizationInfo?): Stats {
val stats = percentStatBonus
if(stats==null) return Stats() // empty
if(civInfo==null) return stats // initial stats
val adoptedPolicies = civInfo.policies.adoptedPolicies
val baseBuildingName = getBaseBuilding().name
if (adoptedPolicies.contains("Theocracy") && baseBuildingName == "Temple")
stats.gold = 10f
if (adoptedPolicies.contains("Free Thought") && baseBuildingName == "University")
stats.science = 50f
if(uniques.contains("+5% Production for every Trade Route with a City-State in the empire"))
stats.production += 5*civInfo.citiesConnectedToCapital.count { it.civInfo.isCityState() }
return stats
}
override fun canBePurchased(): Boolean {
return !isWonder && !isNationalWonder
}
@ -331,7 +345,7 @@ class Building : NamedStats(), IConstruction{
fun isStatRelated(stat: Stat): Boolean {
if (get(stat) > 0) return true
if (percentStatBonus!=null && percentStatBonus!!.get(stat)>0) return true
if (getStatPercentageBonuses(null).get(stat)>0) return true
if (specialistSlots!=null && specialistSlots!!.get(stat)>0) return true
return false
}

View File

@ -56,6 +56,7 @@ class NationTable(val nation: Nation, val newGameParameters: GameParameters, ski
for (stat in building.toHashMap())
if (stat.value != originalBuildingStatMap[stat.key])
textList += " "+stat.key.toString().tr() +" "+stat.value.toInt() + " vs " + originalBuildingStatMap[stat.key]!!.toInt()
for(unique in building.uniques.filter { it !in originalBuilding.uniques })
textList += " "+unique.tr()
if (building.maintenance != originalBuilding.maintenance)
@ -74,6 +75,8 @@ class NationTable(val nation: Nation, val newGameParameters: GameParameters, ski
val originalUnit = GameBasics.Units[unit.replaces!!]!!
textList += unit.name.tr() + " - {replaces} " + originalUnit.name.tr()
if(unit.cost != originalUnit.cost)
textList += " {Cost} " + unit.cost + " vs " + originalUnit.cost
if (unit.strength != originalUnit.strength)
textList += " {Strength} " + unit.strength + " vs " + originalUnit.strength
if (unit.rangedStrength!= originalUnit.rangedStrength)

View File

@ -12,7 +12,6 @@ import com.unciv.UnCivGame
import com.unciv.logic.city.CityConstructions
import com.unciv.logic.city.CityInfo
import com.unciv.logic.city.SpecialConstruction
import com.unciv.logic.map.RoadStatus
import com.unciv.ui.cityscreen.CityScreen
import com.unciv.ui.utils.*
@ -87,7 +86,7 @@ class CityButton(val city: CityInfo, internal val tileGroup: WorldTileGroup, ski
val starImage = ImageGetter.getImage("OtherIcons/Star.png").apply { color = Color.LIGHT_GRAY }
iconTable.add(starImage).size(20f).pad(2f).padLeft(10f)
}
} else if (city.civInfo.isCurrentPlayer() && city.cityStats.isConnectedToCapital(RoadStatus.Road)) {
} else if (city.civInfo.isCurrentPlayer() && city.isConnectedToCapital()) {
val connectionImage = ImageGetter.getStatIcon("CityConnection")
iconTable.add(connectionImage).size(20f).pad(2f).padLeft(10f)
}