mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-28 22:37:02 -04:00
Merge remote-tracking branch 'upstream/master'
update
This commit is contained in:
commit
f7e34353b7
BIN
android/Images/BuildingIcons/Courthouse.png
Normal file
BIN
android/Images/BuildingIcons/Courthouse.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.0 KiB |
BIN
android/Images/OtherIcons/Puppet.png
Normal file
BIN
android/Images/OtherIcons/Puppet.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Before Width: | Height: | Size: 1007 KiB After Width: | Height: | Size: 1007 KiB |
@ -178,6 +178,14 @@
|
|||||||
requiredTech:"Mathematics",
|
requiredTech:"Mathematics",
|
||||||
quote:"'I think that if ever a mortal heard the word of God it would be in a garden at the cool of the day.' - F. Frankfort Moore"
|
quote:"'I think that if ever a mortal heard the word of God it would be in a garden at the cool of the day.' - F. Frankfort Moore"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name:"Courthouse",
|
||||||
|
maintenance:4,
|
||||||
|
hurryCostModifier:25,
|
||||||
|
uniques:["Remove extra unhappiness from annexed cities",
|
||||||
|
"Can only be built in annexed cities"],
|
||||||
|
requiredTech:"Mathematics"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name:"Colosseum",
|
name:"Colosseum",
|
||||||
maintenance:1,
|
maintenance:1,
|
||||||
|
@ -425,19 +425,21 @@
|
|||||||
Russian:"Все военно-морские юниты получают +1 к движению и обзору"
|
Russian:"Все военно-морские юниты получают +1 к движению и обзору"
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
"Courthouse":{
|
"Courthouse":{
|
||||||
Italian:"Palazzo di giustizia"
|
Italian:"Palazzo di giustizia"
|
||||||
French:"Palais de justice"
|
French:"Palais de justice"
|
||||||
Polish:"Sąd"
|
Polish:"Sąd"
|
||||||
}
|
}
|
||||||
|
|
||||||
"Eliminates extra Unhappiness from an Occupied City":{
|
"Remove extra unhappiness from annexed cities":{
|
||||||
Italian:"Elimina l'Infelicità supplementare proveniente da una Città occupata"
|
Italian:"Elimina l'Infelicità extra proveniente dalle Città occupate"
|
||||||
French:"Enlève le mécontentement supplémentaire des villes occupées"
|
French:"Enlève le mécontentement supplémentaire des villes occupées"
|
||||||
Polish:"Usuwa niezadowolenie z okupowanych miast"
|
Polish:"Usuwa niezadowolenie z okupowanych miast"
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
"Can only be built in annexed cities":{
|
||||||
|
Italian:"Costruibile solamente nelle città annesse"
|
||||||
|
}
|
||||||
|
|
||||||
"Stable":{
|
"Stable":{
|
||||||
Italian:"Scuderia"
|
Italian:"Scuderia"
|
||||||
|
@ -185,7 +185,9 @@ class ConstructionAutomation(val cityConstructions: CityConstructions){
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun addHappinessBuildingChoice() {
|
private fun addHappinessBuildingChoice() {
|
||||||
val happinessBuilding = buildableNotWonders.filter { it.isStatRelated(Stat.Happiness) }
|
val happinessBuilding = buildableNotWonders
|
||||||
|
.filter { it.isStatRelated(Stat.Happiness)
|
||||||
|
|| it.uniques.contains("Remove extra unhappiness from annexed cities") }
|
||||||
.minBy { it.cost }
|
.minBy { it.cost }
|
||||||
if (happinessBuilding != null) {
|
if (happinessBuilding != null) {
|
||||||
var modifier = 1f
|
var modifier = 1f
|
||||||
|
@ -429,10 +429,7 @@ class NextTurnAutomation{
|
|||||||
|
|
||||||
private fun reassignWorkedTiles(civInfo: CivilizationInfo) {
|
private fun reassignWorkedTiles(civInfo: CivilizationInfo) {
|
||||||
for (city in civInfo.cities) {
|
for (city in civInfo.cities) {
|
||||||
city.workedTiles = hashSetOf()
|
city.reassignWorkers()
|
||||||
city.population.specialists.clear()
|
|
||||||
for (i in 0..city.population.population)
|
|
||||||
city.population.autoAssignPopulation()
|
|
||||||
|
|
||||||
city.cityConstructions.chooseNextConstruction()
|
city.cityConstructions.chooseNextConstruction()
|
||||||
if (city.health < city.getMaxHealth())
|
if (city.health < city.getMaxHealth())
|
||||||
|
@ -7,12 +7,10 @@ import com.unciv.logic.automation.UnitAutomation
|
|||||||
import com.unciv.logic.city.CityInfo
|
import com.unciv.logic.city.CityInfo
|
||||||
import com.unciv.logic.civilization.AlertType
|
import com.unciv.logic.civilization.AlertType
|
||||||
import com.unciv.logic.civilization.PopupAlert
|
import com.unciv.logic.civilization.PopupAlert
|
||||||
import com.unciv.logic.civilization.diplomacy.DiplomaticModifiers
|
|
||||||
import com.unciv.logic.map.TileInfo
|
import com.unciv.logic.map.TileInfo
|
||||||
import com.unciv.models.gamebasics.unit.UnitType
|
import com.unciv.models.gamebasics.unit.UnitType
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
import kotlin.math.roundToInt
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Damage calculations according to civ v wiki and https://steamcommunity.com/sharedfiles/filedetails/?id=170194443
|
* Damage calculations according to civ v wiki and https://steamcommunity.com/sharedfiles/filedetails/?id=170194443
|
||||||
@ -96,12 +94,6 @@ class Battle(val gameInfo:GameInfo) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(defender.isDefeated()
|
|
||||||
&& defender is CityCombatant
|
|
||||||
&& attacker.isMelee()){
|
|
||||||
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
|
// 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().isBarbarian()
|
if(defender.isDefeated() && defender.getCivInfo().isBarbarian()
|
||||||
@ -151,6 +143,11 @@ class Battle(val gameInfo:GameInfo) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if(defender.isDefeated()
|
||||||
|
&& defender is CityCombatant
|
||||||
|
&& attacker.isMelee())
|
||||||
|
conquerCity(defender.city, attacker)
|
||||||
|
|
||||||
|
|
||||||
if(attacker.isMelee()){
|
if(attacker.isMelee()){
|
||||||
if(!defender.getUnitType().isCivilian()) // unit was not captured but actually attacked
|
if(!defender.getUnitType().isCivilian()) // unit was not captured but actually attacked
|
||||||
@ -204,69 +201,22 @@ class Battle(val gameInfo:GameInfo) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun conquerCity(city: CityInfo, attacker: ICombatant) {
|
private fun conquerCity(city: CityInfo, attacker: ICombatant) {
|
||||||
val cityCiv = city.civInfo
|
|
||||||
val attackerCiv = attacker.getCivInfo()
|
val attackerCiv = attacker.getCivInfo()
|
||||||
|
|
||||||
attackerCiv.addNotification("We have conquered the city of [${city.name}]!",city.location, Color.RED)
|
attackerCiv.addNotification("We have conquered the city of [${city.name}]!", city.location, Color.RED)
|
||||||
attackerCiv.popupAlerts.add(PopupAlert(AlertType.CityConquered,city.name))
|
|
||||||
|
|
||||||
city.getCenterTile().apply {
|
city.getCenterTile().apply {
|
||||||
if(militaryUnit!=null) militaryUnit!!.destroy()
|
if(militaryUnit!=null) militaryUnit!!.destroy()
|
||||||
if(civilianUnit!=null) captureCivilianUnit(attacker,MapUnitCombatant(civilianUnit!!))
|
if(civilianUnit!=null) captureCivilianUnit(attacker, MapUnitCombatant(civilianUnit!!))
|
||||||
for(airUnit in airUnits.toList()) airUnit.destroy()
|
for(airUnit in airUnits.toList()) airUnit.destroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!attackerCiv.isMajorCiv()){
|
|
||||||
city.destroyCity()
|
if (attacker.getCivInfo().isPlayerCivilization()) {
|
||||||
|
attackerCiv.popupAlerts.add(PopupAlert(AlertType.CityConquered, city.name))
|
||||||
|
} else {
|
||||||
|
city.annexCity(attacker.getCivInfo())
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
val currentPopulation = city.population.population
|
|
||||||
|
|
||||||
val percentageOfCivPopulationInThatCity = currentPopulation*100f / cityCiv.cities.sumBy { it.population.population }
|
|
||||||
val aggroGenerated = 10f+percentageOfCivPopulationInThatCity.roundToInt()
|
|
||||||
cityCiv.getDiplomacyManager(attacker.getCivInfo())
|
|
||||||
.addModifier(DiplomaticModifiers.CapturedOurCities, -aggroGenerated)
|
|
||||||
|
|
||||||
for(thirdPartyCiv in attackerCiv.getKnownCivs().filter { it.isMajorCiv() }){
|
|
||||||
val aggroGeneratedForOtherCivs = (aggroGenerated/10).roundToInt().toFloat()
|
|
||||||
if(thirdPartyCiv.isAtWarWith(cityCiv)) // You annoyed our enemy?
|
|
||||||
thirdPartyCiv.getDiplomacyManager(attackerCiv)
|
|
||||||
.addModifier(DiplomaticModifiers.SharedEnemy, aggroGeneratedForOtherCivs) // Cool, keep at at! =D
|
|
||||||
else thirdPartyCiv.getDiplomacyManager(attackerCiv)
|
|
||||||
.addModifier(DiplomaticModifiers.WarMongerer, -aggroGeneratedForOtherCivs) // Uncool bro.
|
|
||||||
}
|
|
||||||
|
|
||||||
if(currentPopulation>1) city.population.population -= 1 + currentPopulation/4 // so from 2-4 population, remove 1, from 5-8, remove 2, etc.
|
|
||||||
city.population.unassignExtraPopulation()
|
|
||||||
|
|
||||||
city.health = city.getMaxHealth() / 2 // I think that cities recover to half health when conquered?
|
|
||||||
|
|
||||||
if(!attacker.getCivInfo().policies.isAdopted("Police State")) {
|
|
||||||
city.expansion.cultureStored = 0
|
|
||||||
city.expansion.reset()
|
|
||||||
}
|
|
||||||
|
|
||||||
city.moveToCiv(attacker.getCivInfo())
|
|
||||||
city.resistanceCounter = city.population.population
|
|
||||||
city.workedTiles = hashSetOf() //reassign 1st working tile
|
|
||||||
city.population.specialists.clear()
|
|
||||||
for (i in 0..city.population.population)
|
|
||||||
city.population.autoAssignPopulation()
|
|
||||||
city.cityStats.update()
|
|
||||||
}
|
|
||||||
|
|
||||||
if(city.cityConstructions.isBuilt("Palace")){
|
|
||||||
city.cityConstructions.removeBuilding("Palace")
|
|
||||||
if(cityCiv.isDefeated()) {
|
|
||||||
cityCiv.destroy()
|
|
||||||
attacker.getCivInfo().popupAlerts.add(PopupAlert(AlertType.Defeated,cityCiv.civName))
|
|
||||||
}
|
|
||||||
else if(cityCiv.cities.isNotEmpty()){
|
|
||||||
cityCiv.cities.first().cityConstructions.addBuilding("Palace") // relocate palace
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
(attacker as MapUnitCombatant).unit.movement.moveToTile(city.getCenterTile())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getMapCombatantOfTile(tile:TileInfo): ICombatant? {
|
fun getMapCombatantOfTile(tile:TileInfo): ICombatant? {
|
||||||
|
@ -3,8 +3,12 @@ package com.unciv.logic.city
|
|||||||
import com.badlogic.gdx.graphics.Color
|
import com.badlogic.gdx.graphics.Color
|
||||||
import com.badlogic.gdx.math.Vector2
|
import com.badlogic.gdx.math.Vector2
|
||||||
import com.unciv.Constants
|
import com.unciv.Constants
|
||||||
|
import com.unciv.UnCivGame
|
||||||
|
import com.unciv.logic.civilization.AlertType
|
||||||
import com.unciv.logic.civilization.CivilizationInfo
|
import com.unciv.logic.civilization.CivilizationInfo
|
||||||
|
import com.unciv.logic.civilization.PopupAlert
|
||||||
import com.unciv.logic.civilization.diplomacy.DiplomacyFlags
|
import com.unciv.logic.civilization.diplomacy.DiplomacyFlags
|
||||||
|
import com.unciv.logic.civilization.diplomacy.DiplomaticModifiers
|
||||||
import com.unciv.logic.map.RoadStatus
|
import com.unciv.logic.map.RoadStatus
|
||||||
import com.unciv.logic.map.TileInfo
|
import com.unciv.logic.map.TileInfo
|
||||||
import com.unciv.logic.map.TileMap
|
import com.unciv.logic.map.TileMap
|
||||||
@ -14,6 +18,7 @@ import com.unciv.models.gamebasics.tile.ResourceType
|
|||||||
import com.unciv.models.stats.Stats
|
import com.unciv.models.stats.Stats
|
||||||
import com.unciv.ui.utils.withoutItem
|
import com.unciv.ui.utils.withoutItem
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
class CityInfo {
|
class CityInfo {
|
||||||
@Transient lateinit var civInfo: CivilizationInfo
|
@Transient lateinit var civInfo: CivilizationInfo
|
||||||
@ -38,6 +43,7 @@ class CityInfo {
|
|||||||
var isBeingRazed = false
|
var isBeingRazed = false
|
||||||
var attackedThisTurn = false
|
var attackedThisTurn = false
|
||||||
var hasSoldBuildingThisTurn = false
|
var hasSoldBuildingThisTurn = false
|
||||||
|
var isPuppet = false
|
||||||
|
|
||||||
constructor() // for json parsing, we need to have a default constructor
|
constructor() // for json parsing, we need to have a default constructor
|
||||||
constructor(civInfo: CivilizationInfo, cityLocation: Vector2) { // new city!
|
constructor(civInfo: CivilizationInfo, cityLocation: Vector2) { // new city!
|
||||||
@ -99,6 +105,8 @@ class CityInfo {
|
|||||||
toReturn.isBeingRazed=isBeingRazed
|
toReturn.isBeingRazed=isBeingRazed
|
||||||
toReturn.attackedThisTurn = attackedThisTurn
|
toReturn.attackedThisTurn = attackedThisTurn
|
||||||
toReturn.resistanceCounter = resistanceCounter
|
toReturn.resistanceCounter = resistanceCounter
|
||||||
|
toReturn.foundingCiv = foundingCiv
|
||||||
|
toReturn.isPuppet = isPuppet
|
||||||
return toReturn
|
return toReturn
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -210,6 +218,16 @@ class CityInfo {
|
|||||||
tryUpdateRoadStatus()
|
tryUpdateRoadStatus()
|
||||||
attackedThisTurn = false
|
attackedThisTurn = false
|
||||||
if (resistanceCounter > 0) resistanceCounter--
|
if (resistanceCounter > 0) resistanceCounter--
|
||||||
|
|
||||||
|
if (isPuppet) reassignWorkers()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun reassignWorkers() {
|
||||||
|
workedTiles = hashSetOf()
|
||||||
|
population.specialists.clear()
|
||||||
|
for (i in 0..population.population)
|
||||||
|
population.autoAssignPopulation()
|
||||||
|
cityStats.update()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun endTurn() {
|
fun endTurn() {
|
||||||
@ -221,22 +239,21 @@ class CityInfo {
|
|||||||
|
|
||||||
cityConstructions.endTurn(stats)
|
cityConstructions.endTurn(stats)
|
||||||
expansion.nextTurn(stats.culture)
|
expansion.nextTurn(stats.culture)
|
||||||
if(isBeingRazed){
|
if (isBeingRazed) {
|
||||||
population.population--
|
population.population--
|
||||||
if(population.population<=0){ // there are strange cases where we geet to -1
|
if (population.population <= 0) { // there are strange cases where we geet to -1
|
||||||
civInfo.addNotification("[$name] has been razed to the ground!",location, Color.RED)
|
civInfo.addNotification("[$name] has been razed to the ground!", location, Color.RED)
|
||||||
destroyCity()
|
destroyCity()
|
||||||
if(isCapital() && civInfo.cities.isNotEmpty()) // Yes, we actually razed the capital. Some people do this.
|
if (isCapital() && civInfo.cities.isNotEmpty()) // Yes, we actually razed the capital. Some people do this.
|
||||||
civInfo.cities.first().cityConstructions.addBuilding("Palace")
|
civInfo.cities.first().cityConstructions.addBuilding("Palace")
|
||||||
}else{//if not razed yet:
|
} else {//if not razed yet:
|
||||||
if(population.foodStored>=population.getFoodToNextPopulation()) {//if surplus in the granary...
|
if (population.foodStored >= population.getFoodToNextPopulation()) {//if surplus in the granary...
|
||||||
population.foodStored=population.getFoodToNextPopulation()-1//...reduce below the new growth treshold
|
population.foodStored = population.getFoodToNextPopulation() - 1//...reduce below the new growth treshold
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else population.nextTurn(stats.food)
|
||||||
else population.nextTurn(stats.food)
|
|
||||||
|
|
||||||
if(this in civInfo.cities) { // city was not destroyed
|
if (this in civInfo.cities) { // city was not destroyed
|
||||||
health = min(health + 20, getMaxHealth())
|
health = min(health + 20, getMaxHealth())
|
||||||
population.unassignExtraPopulation()
|
population.unassignExtraPopulation()
|
||||||
}
|
}
|
||||||
@ -254,7 +271,99 @@ class CityInfo {
|
|||||||
getCenterTile().improvement="City ruins"
|
getCenterTile().improvement="City ruins"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun annexCity(conqueringCiv: CivilizationInfo) {
|
||||||
|
puppetCity(conqueringCiv)
|
||||||
|
|
||||||
|
if(!conqueringCiv.policies.isAdopted("Police State")) {
|
||||||
|
expansion.cultureStored = 0
|
||||||
|
expansion.reset()
|
||||||
|
}
|
||||||
|
|
||||||
|
isPuppet=false
|
||||||
|
|
||||||
|
UnCivGame.Current.worldScreen.shouldUpdate=true
|
||||||
|
}
|
||||||
|
|
||||||
|
/** This happens when we either puppet OR annex, basically whenever we conquer a city and don't liberate it */
|
||||||
|
fun puppetCity(conqueringCiv: CivilizationInfo) {
|
||||||
|
if (!conqueringCiv.isMajorCiv()){
|
||||||
|
destroyCity()
|
||||||
|
}
|
||||||
|
|
||||||
|
val oldCiv = civInfo
|
||||||
|
moveToCiv(conqueringCiv)
|
||||||
|
if(oldCiv.isDefeated()) {
|
||||||
|
oldCiv.destroy()
|
||||||
|
conqueringCiv.popupAlerts.add(PopupAlert(AlertType.Defeated,oldCiv.civName))
|
||||||
|
}
|
||||||
|
|
||||||
|
diplomaticRepercussionsForConqueringCity(oldCiv, conqueringCiv)
|
||||||
|
|
||||||
|
if(population.population>1) population.population -= 1 + population.population/4 // so from 2-4 population, remove 1, from 5-8, remove 2, etc.
|
||||||
|
reassignWorkers()
|
||||||
|
|
||||||
|
resistanceCounter = population.population // I checked, and even if you puppet there's resistance for conquering
|
||||||
|
isPuppet = true
|
||||||
|
health = getMaxHealth() / 2 // I think that cities recover to half health when conquered?
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun diplomaticRepercussionsForConqueringCity(oldCiv: CivilizationInfo, conqueringCiv: CivilizationInfo) {
|
||||||
|
val currentPopulation = population.population
|
||||||
|
val percentageOfCivPopulationInThatCity = currentPopulation * 100f / civInfo.cities.sumBy { it.population.population }
|
||||||
|
val aggroGenerated = 10f + percentageOfCivPopulationInThatCity.roundToInt()
|
||||||
|
oldCiv.getDiplomacyManager(conqueringCiv)
|
||||||
|
.addModifier(DiplomaticModifiers.CapturedOurCities, -aggroGenerated)
|
||||||
|
|
||||||
|
for (thirdPartyCiv in conqueringCiv.getKnownCivs().filter { it.isMajorCiv() }) {
|
||||||
|
val aggroGeneratedForOtherCivs = (aggroGenerated / 10).roundToInt().toFloat()
|
||||||
|
if (thirdPartyCiv.isAtWarWith(civInfo)) // You annoyed our enemy?
|
||||||
|
thirdPartyCiv.getDiplomacyManager(conqueringCiv)
|
||||||
|
.addModifier(DiplomaticModifiers.SharedEnemy, aggroGeneratedForOtherCivs) // Cool, keep at at! =D
|
||||||
|
else thirdPartyCiv.getDiplomacyManager(conqueringCiv)
|
||||||
|
.addModifier(DiplomaticModifiers.WarMongerer, -aggroGeneratedForOtherCivs) // Uncool bro.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Liberating is returning a city to its founder - makes you LOSE warmongering points **/
|
||||||
|
fun liberateCity(conqueringCiv: CivilizationInfo) {
|
||||||
|
if (foundingCiv == "") { // this should never happen but just in case...
|
||||||
|
annexCity(conqueringCiv)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
diplomaticRepercussionsForLiberatingCity(conqueringCiv)
|
||||||
|
|
||||||
|
val foundingCiv = civInfo.gameInfo.civilizations.first { it.civName == foundingCiv }
|
||||||
|
|
||||||
|
moveToCiv(foundingCiv)
|
||||||
|
health = getMaxHealth() / 2 // I think that cities recover to half health when conquered?
|
||||||
|
|
||||||
|
reassignWorkers()
|
||||||
|
|
||||||
|
if(foundingCiv.cities.size == 1) cityConstructions.addBuilding("Palace") // Resurrection!
|
||||||
|
|
||||||
|
UnCivGame.Current.worldScreen.shouldUpdate=true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun diplomaticRepercussionsForLiberatingCity(conqueringCiv: CivilizationInfo) {
|
||||||
|
val oldOwningCiv = civInfo
|
||||||
|
val foundingCiv = civInfo.gameInfo.civilizations.first { it.civName == foundingCiv }
|
||||||
|
val percentageOfCivPopulationInThatCity = population.population *
|
||||||
|
100f / (foundingCiv.cities.sumBy { it.population.population } + population.population)
|
||||||
|
val respecForLiberatingOurCity = 10f + percentageOfCivPopulationInThatCity.roundToInt()
|
||||||
|
foundingCiv.getDiplomacyManager(conqueringCiv)
|
||||||
|
.addModifier(DiplomaticModifiers.CapturedOurCities, respecForLiberatingOurCity)
|
||||||
|
|
||||||
|
val otherCivsRespecForLiberating = (respecForLiberatingOurCity / 10).roundToInt().toFloat()
|
||||||
|
for (thirdPartyCiv in conqueringCiv.getKnownCivs().filter { it.isMajorCiv() && it != oldOwningCiv }) {
|
||||||
|
thirdPartyCiv.getDiplomacyManager(conqueringCiv)
|
||||||
|
.addModifier(DiplomaticModifiers.WarMongerer, otherCivsRespecForLiberating) // Cool, keep at at! =D
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun moveToCiv(newCivInfo: CivilizationInfo){
|
fun moveToCiv(newCivInfo: CivilizationInfo){
|
||||||
|
val oldCiv = civInfo
|
||||||
civInfo.cities = civInfo.cities.toMutableList().apply { remove(this@CityInfo) }
|
civInfo.cities = civInfo.cities.toMutableList().apply { remove(this@CityInfo) }
|
||||||
newCivInfo.cities = newCivInfo.cities.toMutableList().apply { add(this@CityInfo) }
|
newCivInfo.cities = newCivInfo.cities.toMutableList().apply { add(this@CityInfo) }
|
||||||
civInfo = newCivInfo
|
civInfo = newCivInfo
|
||||||
@ -266,6 +375,15 @@ class CityInfo {
|
|||||||
// Remove all national wonders
|
// Remove all national wonders
|
||||||
for(building in cityConstructions.getBuiltBuildings().filter { it.requiredBuildingInAllCities!=null })
|
for(building in cityConstructions.getBuiltBuildings().filter { it.requiredBuildingInAllCities!=null })
|
||||||
cityConstructions.removeBuilding(building.name)
|
cityConstructions.removeBuilding(building.name)
|
||||||
|
|
||||||
|
// Remove/relocate palace
|
||||||
|
if(cityConstructions.isBuilt("Palace")){
|
||||||
|
cityConstructions.removeBuilding("Palace")
|
||||||
|
if(oldCiv.cities.isNotEmpty()){
|
||||||
|
oldCiv.cities.first().cityConstructions.addBuilding("Palace") // relocate palace
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
isBeingRazed=false
|
isBeingRazed=false
|
||||||
|
|
||||||
// Transfer unique buildings
|
// Transfer unique buildings
|
||||||
|
@ -165,6 +165,14 @@ class CityStats {
|
|||||||
return stats
|
return stats
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getStatPercentBonusesFromPuppetCity(): Stats {
|
||||||
|
val stats = Stats()
|
||||||
|
if (cityInfo.isPuppet) {
|
||||||
|
stats.science -= 25f
|
||||||
|
stats.culture -= 25f
|
||||||
|
}
|
||||||
|
return stats
|
||||||
|
}
|
||||||
|
|
||||||
fun getGrowthBonusFromPolicies(): Float {
|
fun getGrowthBonusFromPolicies(): Float {
|
||||||
var bonus = 0f
|
var bonus = 0f
|
||||||
@ -194,6 +202,11 @@ class CityStats {
|
|||||||
var unhappinessFromCitizens = cityInfo.population.population.toFloat()
|
var unhappinessFromCitizens = cityInfo.population.population.toFloat()
|
||||||
if (civInfo.policies.isAdopted("Democracy"))
|
if (civInfo.policies.isAdopted("Democracy"))
|
||||||
unhappinessFromCitizens -= cityInfo.population.getNumberOfSpecialists() * 0.5f
|
unhappinessFromCitizens -= cityInfo.population.getNumberOfSpecialists() * 0.5f
|
||||||
|
|
||||||
|
if (cityInfo.isPuppet)
|
||||||
|
unhappinessFromCitizens *= 1.5f
|
||||||
|
else if (hasExtraAnnexUnhappiness())
|
||||||
|
unhappinessFromCitizens *= 2f
|
||||||
if (civInfo.containsBuildingUnique("Unhappiness from population decreased by 10%"))
|
if (civInfo.containsBuildingUnique("Unhappiness from population decreased by 10%"))
|
||||||
unhappinessFromCitizens *= 0.9f
|
unhappinessFromCitizens *= 0.9f
|
||||||
if (civInfo.policies.isAdopted("Meritocracy"))
|
if (civInfo.policies.isAdopted("Meritocracy"))
|
||||||
@ -215,6 +228,8 @@ class CityStats {
|
|||||||
|
|
||||||
newHappinessList["Policies"] = happinessFromPolicies
|
newHappinessList["Policies"] = happinessFromPolicies
|
||||||
|
|
||||||
|
if (hasExtraAnnexUnhappiness()) newHappinessList["Occupied City"] = -2f //annexed city
|
||||||
|
|
||||||
val happinessFromBuildings = cityInfo.cityConstructions.getStats().happiness.toInt().toFloat()
|
val happinessFromBuildings = cityInfo.cityConstructions.getStats().happiness.toInt().toFloat()
|
||||||
newHappinessList["Buildings"] = happinessFromBuildings
|
newHappinessList["Buildings"] = happinessFromBuildings
|
||||||
|
|
||||||
@ -226,6 +241,12 @@ class CityStats {
|
|||||||
happinessList = newHappinessList
|
happinessList = newHappinessList
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun hasExtraAnnexUnhappiness() : Boolean {
|
||||||
|
if (cityInfo.civInfo.civName == cityInfo.foundingCiv || cityInfo.foundingCiv == "" || cityInfo.isPuppet) return false
|
||||||
|
return !cityInfo.containsBuildingUnique("Remove extra unhappiness from annexed cities")
|
||||||
|
}
|
||||||
|
|
||||||
fun getStatsOfSpecialist(stat: Stat, policies: HashSet<String>): Stats {
|
fun getStatsOfSpecialist(stat: Stat, policies: HashSet<String>): Stats {
|
||||||
val stats = Stats()
|
val stats = Stats()
|
||||||
if (stat == Stat.Culture || stat == Stat.Science) stats.add(stat, 3f)
|
if (stat == Stat.Culture || stat == Stat.Science) stats.add(stat, 3f)
|
||||||
@ -373,6 +394,7 @@ class CityStats {
|
|||||||
newStatPercentBonusList["Computers"]=getStatPercentBonusesFromComputers()
|
newStatPercentBonusList["Computers"]=getStatPercentBonusesFromComputers()
|
||||||
newStatPercentBonusList["Difficulty"]=getStatPercentBonusesFromDifficulty()
|
newStatPercentBonusList["Difficulty"]=getStatPercentBonusesFromDifficulty()
|
||||||
newStatPercentBonusList["National ability"]=getStatPercentBonusesFromNationUnique()
|
newStatPercentBonusList["National ability"]=getStatPercentBonusesFromNationUnique()
|
||||||
|
newStatPercentBonusList["Puppet City"]=getStatPercentBonusesFromPuppetCity()
|
||||||
|
|
||||||
if(UnCivGame.Current.superchargedForDebug) {
|
if(UnCivGame.Current.superchargedForDebug) {
|
||||||
val stats = Stats()
|
val stats = Stats()
|
||||||
|
@ -240,6 +240,11 @@ class Building : NamedStats(), IConstruction{
|
|||||||
&& !construction.cityInfo.getCenterTile().neighbors.any { it.baseTerrain==Constants.coast })
|
&& !construction.cityInfo.getCenterTile().neighbors.any { it.baseTerrain==Constants.coast })
|
||||||
return "Can only be built in coastal cities"
|
return "Can only be built in coastal cities"
|
||||||
|
|
||||||
|
if("Can only be built in annexed cities" in uniques
|
||||||
|
&& (construction.cityInfo.isPuppet || construction.cityInfo.foundingCiv == ""
|
||||||
|
|| construction.cityInfo.civInfo.civName == construction.cityInfo.foundingCiv))
|
||||||
|
return "Can only be built in annexed cities"
|
||||||
|
|
||||||
val civInfo = construction.cityInfo.civInfo
|
val civInfo = construction.cityInfo.civInfo
|
||||||
if (uniqueTo!=null && uniqueTo!=civInfo.civName) return "Unique to $uniqueTo"
|
if (uniqueTo!=null && uniqueTo!=civInfo.civName) return "Unique to $uniqueTo"
|
||||||
if (GameBasics.Buildings.values.any { it.uniqueTo==civInfo.civName && it.replaces==name }) return "Our unique building replaces this"
|
if (GameBasics.Buildings.values.any { it.uniqueTo==civInfo.civName && it.replaces==name }) return "Our unique building replaces this"
|
||||||
|
@ -176,7 +176,10 @@ class CityInfoTable(private val cityScreen: CityScreen) : Table(CameraStageBaseS
|
|||||||
if(specificStatValue==0f) continue
|
if(specificStatValue==0f) continue
|
||||||
statValuesTable.add(entry.key.toLabel())
|
statValuesTable.add(entry.key.toLabel())
|
||||||
val decimal = DecimalFormat("0.#").format(specificStatValue)
|
val decimal = DecimalFormat("0.#").format(specificStatValue)
|
||||||
statValuesTable.add("+$decimal%".toLabel()).row()
|
if (specificStatValue > 0)
|
||||||
|
statValuesTable.add("+$decimal%".toLabel()).row()
|
||||||
|
else
|
||||||
|
statValuesTable.add("$decimal%".toLabel()).row()
|
||||||
}
|
}
|
||||||
if(stat==Stat.Food){
|
if(stat==Stat.Food){
|
||||||
statValuesTable.add("Food eaten".toLabel())
|
statValuesTable.add("Food eaten".toLabel())
|
||||||
@ -223,7 +226,7 @@ class CityInfoTable(private val cityScreen: CityScreen) : Table(CameraStageBaseS
|
|||||||
// these two are conflictingly named compared to above...
|
// these two are conflictingly named compared to above...
|
||||||
val assignedSpecialists = currentSpecialists[stat]!!.toInt()
|
val assignedSpecialists = currentSpecialists[stat]!!.toInt()
|
||||||
val maxSpecialists = statToMaximumSpecialist.value.toInt()
|
val maxSpecialists = statToMaximumSpecialist.value.toInt()
|
||||||
if (assignedSpecialists > 0) {
|
if (assignedSpecialists > 0 && !cityInfo.isPuppet) {
|
||||||
val unassignButton = TextButton("-", skin)
|
val unassignButton = TextButton("-", skin)
|
||||||
unassignButton.label.setFontSize(24)
|
unassignButton.label.setFontSize(24)
|
||||||
unassignButton.onClick {
|
unassignButton.onClick {
|
||||||
@ -241,7 +244,7 @@ class CityInfoTable(private val cityScreen: CityScreen) : Table(CameraStageBaseS
|
|||||||
specialistIconTable.add(icon).size(30f)
|
specialistIconTable.add(icon).size(30f)
|
||||||
}
|
}
|
||||||
specialistPickerTable.add(specialistIconTable)
|
specialistPickerTable.add(specialistIconTable)
|
||||||
if (assignedSpecialists < maxSpecialists) {
|
if (assignedSpecialists < maxSpecialists && !cityInfo.isPuppet) {
|
||||||
val assignButton = TextButton("+", skin)
|
val assignButton = TextButton("+", skin)
|
||||||
assignButton.label.setFontSize(24)
|
assignButton.label.setFontSize(24)
|
||||||
assignButton.onClick {
|
assignButton.onClick {
|
||||||
|
@ -79,7 +79,7 @@ class CityScreen(internal val city: CityInfo) : CameraStageBaseScreen() {
|
|||||||
cityPickerTable.centerX(stage)
|
cityPickerTable.centerX(stage)
|
||||||
|
|
||||||
constructionsTable.update()
|
constructionsTable.update()
|
||||||
updateRazeCityButton()
|
updateAnnexAndRazeCityButton()
|
||||||
tileTable.update(selectedTile)
|
tileTable.update(selectedTile)
|
||||||
tileTable.setPosition(stage.width-5, 5f,Align.bottomRight)
|
tileTable.setPosition(stage.width-5, 5f,Align.bottomRight)
|
||||||
updateTileGroups()
|
updateTileGroups()
|
||||||
@ -161,10 +161,21 @@ class CityScreen(internal val city: CityInfo) : CameraStageBaseScreen() {
|
|||||||
return table.addBorder(2f, beige)
|
return table.addBorder(2f, beige)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateRazeCityButton() {
|
private fun updateAnnexAndRazeCityButton() {
|
||||||
razeCityButtonHolder.clear()
|
razeCityButtonHolder.clear()
|
||||||
|
|
||||||
if(!city.isBeingRazed) {
|
if(city.isPuppet) {
|
||||||
|
val annexCityButton = TextButton("Annex city".tr(), skin)
|
||||||
|
annexCityButton.labelCell.pad(10f)
|
||||||
|
annexCityButton.onClick {
|
||||||
|
city.isPuppet=false
|
||||||
|
city.isBeingRazed=false
|
||||||
|
city.resistanceCounter = city.population.population
|
||||||
|
update()
|
||||||
|
}
|
||||||
|
razeCityButtonHolder.add(annexCityButton).colspan(cityPickerTable.columns)
|
||||||
|
}
|
||||||
|
else if(!city.isBeingRazed) {
|
||||||
val razeCityButton = TextButton("Raze city".tr(), skin)
|
val razeCityButton = TextButton("Raze city".tr(), skin)
|
||||||
razeCityButton.labelCell.pad(10f)
|
razeCityButton.labelCell.pad(10f)
|
||||||
razeCityButton.onClick { city.isBeingRazed=true; update() }
|
razeCityButton.onClick { city.isBeingRazed=true; update() }
|
||||||
@ -197,14 +208,16 @@ class CityScreen(internal val city: CityInfo) : CameraStageBaseScreen() {
|
|||||||
val tileInfo = tileGroup.tileInfo
|
val tileInfo = tileGroup.tileInfo
|
||||||
|
|
||||||
tileGroup.onClick {
|
tileGroup.onClick {
|
||||||
selectedTile = tileInfo
|
if (!city.isPuppet) {
|
||||||
if (tileGroup.isWorkable && UnCivGame.Current.worldScreen.isPlayersTurn) {
|
selectedTile = tileInfo
|
||||||
if (!tileInfo.isWorked() && city.population.getFreePopulation() > 0)
|
if (tileGroup.isWorkable && UnCivGame.Current.worldScreen.isPlayersTurn) {
|
||||||
city.workedTiles.add(tileInfo.position)
|
if (!tileInfo.isWorked() && city.population.getFreePopulation() > 0)
|
||||||
else if (tileInfo.isWorked()) city.workedTiles.remove(tileInfo.position)
|
city.workedTiles.add(tileInfo.position)
|
||||||
city.cityStats.update()
|
else if (tileInfo.isWorked()) city.workedTiles.remove(tileInfo.position)
|
||||||
|
city.cityStats.update()
|
||||||
|
}
|
||||||
|
update()
|
||||||
}
|
}
|
||||||
update()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tileGroups.add(tileGroup)
|
tileGroups.add(tileGroup)
|
||||||
|
@ -38,6 +38,17 @@ class CityScreenCityPickerTable(val cityScreen: CityScreen) : Table(){
|
|||||||
cityNameTable.add(starImage).size(20f).padRight(5f)
|
cityNameTable.add(starImage).size(20f).padRight(5f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(city.isPuppet){
|
||||||
|
val starImage = Image(ImageGetter.getDrawable("OtherIcons/Puppet").tint(Color.LIGHT_GRAY))
|
||||||
|
cityNameTable.add(starImage).size(20f).padRight(5f)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (city.resistanceCounter > 0) {
|
||||||
|
val resistanceImage = ImageGetter.getImage("StatIcons/Resistance")
|
||||||
|
cityNameTable.add(resistanceImage).size(20f).padRight(5f)
|
||||||
|
}
|
||||||
|
|
||||||
val currentCityLabel = Label(city.name + " (" + city.population.population + ")", CameraStageBaseScreen.skin)
|
val currentCityLabel = Label(city.name + " (" + city.population.population + ")", CameraStageBaseScreen.skin)
|
||||||
currentCityLabel.setFontSize(30)
|
currentCityLabel.setFontSize(30)
|
||||||
currentCityLabel.onClick {
|
currentCityLabel.onClick {
|
||||||
|
@ -53,7 +53,7 @@ class CityScreenTileTable(val city: CityInfo): Table(){
|
|||||||
city.expansion.buyTile(selectedTile)
|
city.expansion.buyTile(selectedTile)
|
||||||
UnCivGame.Current.screen = CityScreen(city)
|
UnCivGame.Current.screen = CityScreen(city)
|
||||||
}
|
}
|
||||||
if(goldCostOfTile>city.civInfo.gold || !UnCivGame.Current.worldScreen.isPlayersTurn)
|
if(goldCostOfTile>city.civInfo.gold || city.isPuppet || !UnCivGame.Current.worldScreen.isPlayersTurn)
|
||||||
buyTileButton.disable()
|
buyTileButton.disable()
|
||||||
|
|
||||||
innerTable.add(buyTileButton)
|
innerTable.add(buyTileButton)
|
||||||
|
@ -50,11 +50,13 @@ class ConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBaseScre
|
|||||||
|
|
||||||
if(rejectionReason=="" && UnCivGame.Current.worldScreen.isPlayersTurn) { // no rejection reason means we can build it!
|
if(rejectionReason=="" && UnCivGame.Current.worldScreen.isPlayersTurn) { // no rejection reason means we can build it!
|
||||||
pickProductionButton.onClick {
|
pickProductionButton.onClick {
|
||||||
lastConstruction = cityScreen.city.cityConstructions.currentConstruction
|
if (!cityScreen.city.isPuppet) {
|
||||||
cityScreen.city.cityConstructions.currentConstruction = construction
|
lastConstruction = cityScreen.city.cityConstructions.currentConstruction
|
||||||
cityScreen.city.cityConstructions.currentConstructionIsUserSet=true
|
cityScreen.city.cityConstructions.currentConstruction = construction
|
||||||
cityScreen.city.cityStats.update()
|
cityScreen.city.cityConstructions.currentConstructionIsUserSet = true
|
||||||
cityScreen.update()
|
cityScreen.city.cityStats.update()
|
||||||
|
cityScreen.update()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -147,7 +149,7 @@ class ConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBaseScre
|
|||||||
|
|
||||||
row()
|
row()
|
||||||
val purchaseConstructionButton: TextButton
|
val purchaseConstructionButton: TextButton
|
||||||
if (construction.canBePurchased()) {
|
if (construction.canBePurchased() && !city.isPuppet) {
|
||||||
val constructionGoldCost = construction.getGoldCost(city.civInfo)
|
val constructionGoldCost = construction.getGoldCost(city.civInfo)
|
||||||
purchaseConstructionButton = TextButton("Buy for [$constructionGoldCost] gold".tr(), CameraStageBaseScreen.skin)
|
purchaseConstructionButton = TextButton("Buy for [$constructionGoldCost] gold".tr(), CameraStageBaseScreen.skin)
|
||||||
purchaseConstructionButton.onClick("coin") {
|
purchaseConstructionButton.onClick("coin") {
|
||||||
|
@ -100,6 +100,12 @@ class CityButton(val city: CityInfo, internal val tileGroup: WorldTileGroup, ski
|
|||||||
iconTable.add(resistanceImage).size(20f).pad(2f).padLeft(5f)
|
iconTable.add(resistanceImage).size(20f).pad(2f).padLeft(5f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (city.isPuppet) {
|
||||||
|
val puppetImage = ImageGetter.getImage("OtherIcons/Puppet")
|
||||||
|
puppetImage.setColor(secondaryColor)
|
||||||
|
iconTable.add(puppetImage).size(20f).pad(2f).padLeft(5f)
|
||||||
|
}
|
||||||
|
|
||||||
if (city.isBeingRazed) {
|
if (city.isBeingRazed) {
|
||||||
val fireImage = ImageGetter.getImage("OtherIcons/Fire")
|
val fireImage = ImageGetter.getImage("OtherIcons/Fire")
|
||||||
iconTable.add(fireImage).size(20f).pad(2f).padLeft(5f)
|
iconTable.add(fireImage).size(20f).pad(2f).padLeft(5f)
|
||||||
@ -116,7 +122,7 @@ class CityButton(val city: CityInfo, internal val tileGroup: WorldTileGroup, ski
|
|||||||
} else if (city.civInfo.isCurrentPlayer() && city.isConnectedToCapital()) {
|
} else if (city.civInfo.isCurrentPlayer() && city.isConnectedToCapital()) {
|
||||||
val connectionImage = ImageGetter.getStatIcon("CityConnection")
|
val connectionImage = ImageGetter.getStatIcon("CityConnection")
|
||||||
connectionImage.color = secondaryColor
|
connectionImage.color = secondaryColor
|
||||||
iconTable.add(connectionImage).size(20f).pad(2f).padLeft(10f)
|
iconTable.add(connectionImage).size(20f).pad(2f).padLeft(5f)
|
||||||
}
|
}
|
||||||
|
|
||||||
val cityButtonText = city.population.population.toString() + " | " + city.name
|
val cityButtonText = city.population.population.toString() + " | " + city.name
|
||||||
|
@ -59,10 +59,31 @@ class AlertPopup(val worldScreen: WorldScreen, val popupAlert: PopupAlert): Popu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
AlertType.CityConquered -> {
|
AlertType.CityConquered -> {
|
||||||
|
val city = worldScreen.gameInfo.civilizations.flatMap { it.cities }.first { it.name == popupAlert.value}
|
||||||
addGoodSizedLabel("What would you like to do with the city?").row()
|
addGoodSizedLabel("What would you like to do with the city?").row()
|
||||||
add(getCloseButton("Annex")).row()
|
val conqueringCiv = worldScreen.gameInfo.currentPlayerCiv
|
||||||
|
if (city.foundingCiv != ""
|
||||||
|
&& city.civInfo.civName != city.foundingCiv // can't liberate if the city actually belongs to those guys
|
||||||
|
&& conqueringCiv.civName != city.foundingCiv) { // or belongs originally to us
|
||||||
|
add(TextButton("Liberate".tr(), skin).onClick {
|
||||||
|
city.liberateCity(conqueringCiv)
|
||||||
|
worldScreen.shouldUpdate=true
|
||||||
|
close()
|
||||||
|
}).row()
|
||||||
|
}
|
||||||
|
add(TextButton("Annex".tr(), skin).onClick {
|
||||||
|
city.annexCity(conqueringCiv)
|
||||||
|
worldScreen.shouldUpdate=true
|
||||||
|
close()
|
||||||
|
}).row()
|
||||||
|
add(TextButton("Puppet City".tr(), skin).onClick {
|
||||||
|
city.puppetCity(conqueringCiv)
|
||||||
|
worldScreen.shouldUpdate=true
|
||||||
|
close()
|
||||||
|
}).row()
|
||||||
add(TextButton("Raze".tr(), skin).onClick {
|
add(TextButton("Raze".tr(), skin).onClick {
|
||||||
worldScreen.viewingCiv.cities.first { it.name==popupAlert.value }.isBeingRazed=true
|
city.annexCity(conqueringCiv)
|
||||||
|
city.isBeingRazed = true
|
||||||
worldScreen.shouldUpdate=true
|
worldScreen.shouldUpdate=true
|
||||||
close()
|
close()
|
||||||
})
|
})
|
||||||
|
@ -41,6 +41,7 @@ Unless otherwise specified, all the following are from [the Noun Project](https:
|
|||||||
* [Roman Helmet](https://thenounproject.com/search/?q=legion&i=440134) By parkjisun for Legion
|
* [Roman Helmet](https://thenounproject.com/search/?q=legion&i=440134) By parkjisun for Legion
|
||||||
* [Horse](https://thenounproject.com/search/?q=Horse&i=1373793) By AFY Studio for Horseman
|
* [Horse](https://thenounproject.com/search/?q=Horse&i=1373793) By AFY Studio for Horseman
|
||||||
* [Horse Head](https://thenounproject.com/search/?q=Cavalry&i=374037) By Juan Pablo Bravo for Companion Cavalry
|
* [Horse Head](https://thenounproject.com/search/?q=Cavalry&i=374037) By Juan Pablo Bravo for Companion Cavalry
|
||||||
|
* [Judge](https://thenounproject.com/search/?q=judge&i=1076388) By Krisztián Mátyás for Courthouse
|
||||||
|
|
||||||
### Medieval Era
|
### Medieval Era
|
||||||
|
|
||||||
@ -490,6 +491,7 @@ Unless otherwise specified, all the following are from [the Noun Project](https:
|
|||||||
* [Aircraft](https://thenounproject.com/search/?q=aircraft&i=1629000) By Tom Fricker for aircraft icon in city button
|
* [Aircraft](https://thenounproject.com/search/?q=aircraft&i=1629000) By Tom Fricker for aircraft icon in city button
|
||||||
* [radar scan](https://thenounproject.com/search/?q=range&i=1500234) By icon 54 for Range
|
* [radar scan](https://thenounproject.com/search/?q=range&i=1500234) By icon 54 for Range
|
||||||
* [short range radar](https://thenounproject.com/search/?q=air%20range&i=2612731) by Vectors Point for Intercept range
|
* [short range radar](https://thenounproject.com/search/?q=air%20range&i=2612731) by Vectors Point for Intercept range
|
||||||
|
* [Puppet](https://thenounproject.com/search/?q=puppet&i=285735) By Ben Davis for puppeted cities
|
||||||
|
|
||||||
# Sound credits
|
# Sound credits
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user