Organized unit image credits

Sea civilian units are now universally recognized as civilian units
This commit is contained in:
Yair Morgenstern 2018-10-11 23:05:49 +03:00
parent 1111a23c14
commit a855bc0e7b
23 changed files with 200 additions and 140 deletions

View file

@ -9,60 +9,79 @@ All the following are from [the Noun Project](https://thenounproject.com) licenc
## Units
* [Sword](https://thenounproject.com/search/?q=Sword&i=1215443) By Guilherme Furtado
* [Sword](https://thenounproject.com/search/?q=Sword&i=1432662) By uzeir syarief
* [Flag](https://thenounproject.com/search/?q=Flag&i=50114) By Melvin Poppelaars
* [Eagle](https://thenounproject.com/search/?q=Eagle&i=1619932) By anggun
* [Bow And Arrow](https://thenounproject.com/search/?q=Bow%20and%20Arrow&i=338261) By Viktor Ostrovsky
* [Chariot](https://thenounproject.com/search/?q=Chariot&i=1189930) By Andrew Doane
* [Pallet](https://thenounproject.com/search/?q=Pallet&i=6862) By James Keuning
* [Gear](https://thenounproject.com/search/?q=Gear&i=17369) By Melvin Salas
* [Beaker](https://thenounproject.com/search/?q=Beaker&i=621510) By Delwar Hossain
* [Horse](https://thenounproject.com/search/?q=Horse&i=1373793) By AFY Studio
* [Axe](https://thenounproject.com/search/?q=Axe&i=1688143) By ehab.abdullah
* [Hammer](https://thenounproject.com/search/?q=Hammer&i=667666) By Hea Poh Lin
* [Spear](https://thenounproject.com/search/?q=Spear&i=11432) By Stephen Copinger
* [Spear](https://thenounproject.com/search/?q=Spear&i=1233840) By Alvaro Cabrera
### Ancient Era
* [Hammer](https://thenounproject.com/search/?q=Hammer&i=667666) By Hea Poh Lin for Worker
* [Flag](https://thenounproject.com/search/?q=Flag&i=50114) By Melvin Poppelaars for Settler
* [Eagle](https://thenounproject.com/search/?q=Eagle&i=1619932) By anggun for Scout
* [Axe](https://thenounproject.com/search/?q=Axe&i=1688143) By ehab.abdullah for Warrior
* [Bow And Arrow](https://thenounproject.com/search/?q=Bow%20and%20Arrow&i=338261) By Viktor Ostrovsky for Archer
* [Bow](https://thenounproject.com/search/?q=bow&i=101736) By Arthur Shlain for Bowman
* Work Boats
* [Chariot](https://thenounproject.com/search/?q=Chariot&i=1189930) By Andrew Doane for Chariot Archer
* [Spear](https://thenounproject.com/search/?q=Spear&i=11432) By Stephen Copinger for Spearman
### Classical Era
* [Catapult](https://thenounproject.com/search/?q=Spear&i=1233840) By Jakub Ukrop
* [Crossbow](https://thenounproject.com/term/crossbow/965389/) By Creaticca Creative Agency
* [Unloaded Crossbow](https://thenounproject.com/term/unloaded-crossbow/815992/) By Hamish as Ballista
* [Sword](https://thenounproject.com/search/?q=Sword&i=1215443) By Guilherme Furtado for Swordsman
* [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
### Medieval Era
* [Crossbow](https://thenounproject.com/term/crossbow/965389/) By Creaticca Creative Agency for Crossbowman
* [Longbow](https://thenounproject.com/search/?q=longbow&i=815991) By Hamish for Longbowman
* [Trebuchet](https://thenounproject.com/search/?q=Trebuchet&i=827987) By Ben Davis
* [Sword](https://thenounproject.com/search/?q=Sword&i=1432662) By uzeir syarief for Longswordsman
* [Spear](https://thenounproject.com/search/?q=Spear&i=1233840) By Alvaro Cabrera for Pikeman
* [Knight](https://thenounproject.com/search/?q=Knight&i=30912) By Tyler Glaude
* [Lance](https://thenounproject.com/search/?q=Lance&i=440122) By parkjisun
* [Musket](https://thenounproject.com/search/?q=Musket&i=298302) By Cezary Lopacinski
### Renaissance Era
* [Cannon](https://thenounproject.com/search/?q=Cannon&i=1618747) By Orin Zuu
* [Bow](https://thenounproject.com/search/?q=bow&i=101736) By Arthur Shlain
* [Longbow](https://thenounproject.com/search/?q=longbow&i=815991) By Hamish
* [Horse Head](https://thenounproject.com/search/?q=Cavalry&i=374037) By Juan Pablo Bravo
* [Rifle](https://thenounproject.com/search/?q=Rifle&i=604291) By Chameleon Design
* [Horse](https://thenounproject.com/search/?q=Horse&i=1023745) By Bakunetso Kaito
* [Musket](https://thenounproject.com/search/?q=Musket&i=298302) By Cezary Lopacinski for Musketman
* [Rapier](https://thenounproject.com/search/?q=musketeer&i=819822) By Hamish for Musketeer
* [Lance](https://thenounproject.com/search/?q=Lance&i=440122) By parkjisun for Lancer
### Industrial
* [Rifle](https://thenounproject.com/search/?q=Rifle&i=604291) By Chameleon Design for Rifleman
* [Horse](https://thenounproject.com/search/?q=Horse&i=1023745) By Bakunetso Kaito for Cavalry
* [Artillery](https://thenounproject.com/search/?q=Artillery&i=1165261) By Creative Mania
* [Rapier](https://thenounproject.com/search/?q=musketeer&i=819822) By Hamish
* [Unloaded Crossbow](https://thenounproject.com/term/unloaded-crossbow/815992/) By Hamish
### Great People
* [Pallet](https://thenounproject.com/search/?q=Pallet&i=6862) By James Keuning for Great Artist
* [Gear](https://thenounproject.com/search/?q=Gear&i=17369) By Melvin Salas for Great Engineer
* [Beaker](https://thenounproject.com/search/?q=Beaker&i=621510) By Delwar Hossain for Great Scientist
## Resources
* [Saffron](https://thenounproject.com/term/saffron/1576606/) By parkjisun
* [Can](https://thenounproject.com/term/can/708971/) By Nick Bluth
* [Saffron](https://thenounproject.com/term/saffron/1576606/) By parkjisun for Dye
* [Can](https://thenounproject.com/term/can/708971/) By Nick Bluth for Aluminum
* [Coal](https://thenounproject.com/term/coal/213892/) By Michael Wohlwend
* [Anvil](https://thenounproject.com/term/anvil/166414/) By Jason Dilworth
* [Anvil](https://thenounproject.com/term/anvil/166414/) By Jason Dilworth for Iron
* [Deer](https://thenounproject.com/term/deer/338013/) By Richard Nixon
* [Banana](https://thenounproject.com/term/banana/1262865/) By Adrian Coquet
* [Oil](https://thenounproject.com/term/oil/88649/) By Tiago Maricate
* [Statue](https://thenounproject.com/term/statue/5221/) By Joris Hoogendoorn
* [Ribbon](https://thenounproject.com/term/ribbon/418996) By Anton
* [Statue](https://thenounproject.com/term/statue/5221/) By Joris Hoogendoorn for Marble
* [Ribbon](https://thenounproject.com/term/ribbon/418996) By Anton for Silk
* [Stone](https://thenounproject.com/term/stone/1373902/) By AFY Studio
* [Goblet](https://thenounproject.com/term/goblet/1005208/) By Pedro Santos
* [Goblet](https://thenounproject.com/term/goblet/1005208/) By Pedro Santos for Silver
* [Sugar](https://thenounproject.com/term/sugar/1689203/) By ahmad
* [Spice](https://thenounproject.com/term/spice/1689206/) By ahmad
* [Radiation symbol](https://thenounproject.com/term/radiation-symbol/211059/) By icon 54
* [Radiation symbol](https://thenounproject.com/term/radiation-symbol/211059/) By icon 54 for Uranium
* [Wine](https://thenounproject.com/term/wine/1290951/) By Adrien Coquet
* [Wheat](https://thenounproject.com/term/wheat/1048428/) By Juraj Sedlak
* [Sheep](https://thenounproject.com/term/sheep/8389/) By Unrecognized
* [Elephant](https://thenounproject.com/term/elephant/1853192/) By Kelsey Armstrong
* [Elephant](https://thenounproject.com/term/elephant/1853192/) By Kelsey Armstrong for Ivory
* [Cattle](https://thenounproject.com/term/cattle/781342/) By Daniela Baptista
* [Leather](https://thenounproject.com/term/leather/16499/) By Alen Krummenacher
* [Leather](https://thenounproject.com/term/leather/16499/) By Alen Krummenacher for Furs
* [Gem](https://thenounproject.com/term/gem/948920/) By Lluisa Iborra
* [Joss Stick](https://thenounproject.com/search/?q=incense&i=583033) By Hea Poh Lin
* [Joss Stick](https://thenounproject.com/search/?q=incense&i=583033) By Hea Poh Lin for Incense
## Improvements
@ -74,7 +93,7 @@ All the following are from [the Noun Project](https://thenounproject.com) licenc
* [Academy](https://thenounproject.com/term/academy/1689703/) By CJS
* [Factory](https://thenounproject.com/term/factory/1049531/) By RULI
* [Mine](https://thenounproject.com/term/mine/543/) By Edward Boatman
* [Corral](https://thenounproject.com/term/corral/1340751/) By Luis Prado
* [Corral](https://thenounproject.com/term/corral/1340751/) By Luis Prado for Pasture
* [Plants](https://thenounproject.com/term/plants/1760916/) By hendra sudibyo
* [Pickaxe](https://thenounproject.com/term/pickaxe/175792/) By Creative Stall
* [Food stall](https://thenounproject.com/term/food-stall/1618358/) By I Putu Kharismayadi

View file

@ -5,6 +5,7 @@ import com.unciv.logic.GameInfo
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.logic.map.TileMap
import com.unciv.models.gamebasics.GameBasics
import com.unciv.models.gamebasics.tile.TerrainType
import com.unciv.ui.NewGameScreen
import com.unciv.ui.utils.getRandom
@ -24,7 +25,9 @@ class GameStarter(){
}
val distanceAroundStartingPointNoOneElseWillStartIn = 5
val freeTiles = gameInfo.tileMap.values.toMutableList().filter { vectorIsWithinNTilesOfEdge(it.position,3)}.toMutableList()
val freeTiles = gameInfo.tileMap.values
.filter { it.getBaseTerrain().type==TerrainType.Land && vectorIsWithinNTilesOfEdge(it.position,3)}
.toMutableList()
val playerPosition = freeTiles.getRandom().position
val playerCiv = CivilizationInfo(newGameParameters.nation, gameInfo)
playerCiv.difficulty=newGameParameters.difficulty
@ -63,15 +66,6 @@ class GameStarter(){
freeTiles.removeAll(gameInfo.tileMap.getTilesInDistance(startingLocation, distanceAroundStartingPointNoOneElseWillStartIn ))
}
(1..5).forEach {
val freeTilesList = freeTiles.toList()
if(freeTilesList.isNotEmpty()){
val placedTile = freeTilesList.getRandom()
gameInfo.placeBarbarianUnit(placedTile)
freeTiles.remove(placedTile)
}
}
return gameInfo
}
}

View file

@ -7,12 +7,12 @@ import kotlin.math.max
class HexMath {
fun GetVectorForAngle(angle: Float): Vector2 {
private fun getVectorForAngle(angle: Float): Vector2 {
return Vector2(Math.sin(angle.toDouble()).toFloat(), Math.cos(angle.toDouble()).toFloat())
}
fun GetVectorByClockHour(hour: Int): Vector2 {
return GetVectorForAngle((2 * Math.PI * (hour / 12f)).toFloat())
private fun getVectorByClockHour(hour: Int): Vector2 {
return getVectorForAngle((2 * Math.PI * (hour / 12f)).toFloat())
}
// HexCoordinates are a (x,y) vector, where x is the vector getting us to the top-left hex (e.g. 10 o'clock)
@ -22,54 +22,54 @@ class HexMath {
// For example, to get to the cell above me, I'll use a (1,1) vector.
// To get to the cell below the cell to my bottom-right, I'll use a (-1,-2) vector.
fun Hex2WorldCoords(hexCoord: Vector2): Vector2 {
fun hex2WorldCoords(hexCoord: Vector2): Vector2 {
// Distance between cells = 2* normal of triangle = 2* (sqrt(3)/2) = sqrt(3)
val xVector = GetVectorByClockHour(10).scl(Math.sqrt(3.0).toFloat())
val yVector = GetVectorByClockHour(2).scl(Math.sqrt(3.0).toFloat())
val xVector = getVectorByClockHour(10).scl(Math.sqrt(3.0).toFloat())
val yVector = getVectorByClockHour(2).scl(Math.sqrt(3.0).toFloat())
return xVector.scl(hexCoord.x).add(yVector.scl(hexCoord.y))
}
fun GetAdjacentVectors(origin: Vector2): ArrayList<Vector2> {
fun getAdjacentVectors(origin: Vector2): ArrayList<Vector2> {
val vectors = ArrayList<Vector2>()
vectors.add(Vector2(1f, 0f))
vectors.add(Vector2(1f, 1f))
vectors.add(Vector2(0f, 1f))
vectors.add(Vector2(-1f, 0f))
vectors.add(Vector2(-1f, -1f))
vectors.add(Vector2(0f, -1f))
vectors += Vector2(1f, 0f)
vectors += Vector2(1f, 1f)
vectors += Vector2(0f, 1f)
vectors += Vector2(-1f, 0f)
vectors += Vector2(-1f, -1f)
vectors += Vector2(0f, -1f)
for (vector in vectors) vector.add(origin)
return vectors
}
fun GetVectorsAtDistance(origin: Vector2, distance: Int): List<Vector2> {
fun getVectorsAtDistance(origin: Vector2, distance: Int): List<Vector2> {
val vectors = mutableListOf<Vector2>()
if (distance == 0) {
vectors.add(origin.cpy())
vectors += origin.cpy()
return vectors
}
val Current = origin.cpy().sub(distance.toFloat(), distance.toFloat()) // start at 6 o clock
val current = origin.cpy().sub(distance.toFloat(), distance.toFloat()) // start at 6 o clock
for (i in 0 until distance) { // From 6 to 8
vectors.add(Current.cpy())
vectors.add(origin.cpy().scl(2f).sub(Current)) // Get vector on other side of cloick
Current.add(1f, 0f)
vectors += current.cpy()
vectors += origin.cpy().scl(2f).sub(current) // Get vector on other side of cloick
current.add(1f, 0f)
}
for (i in 0 until distance) { // 8 to 10
vectors.add(Current.cpy())
vectors.add(origin.cpy().scl(2f).sub(Current)) // Get vector on other side of clock
Current.add(1f, 1f)
vectors += current.cpy()
vectors += origin.cpy().scl(2f).sub(current) // Get vector on other side of clock
current.add(1f, 1f)
}
for (i in 0 until distance) { // 10 to 12
vectors.add(Current.cpy())
vectors.add(origin.cpy().scl(2f).sub(Current)) // Get vector on other side of clock
Current.add(0f, 1f)
vectors += current.cpy()
vectors += origin.cpy().scl(2f).sub(current) // Get vector on other side of clock
current.add(0f, 1f)
}
return vectors
}
fun GetVectorsInDistance(origin: Vector2, distance: Int): List<Vector2> {
fun getVectorsInDistance(origin: Vector2, distance: Int): List<Vector2> {
val hexesToReturn = mutableListOf<Vector2>()
for (i in 0 .. distance) {
hexesToReturn.addAll(GetVectorsAtDistance(origin, i))
hexesToReturn += getVectorsAtDistance(origin, i)
}
return hexesToReturn
}

View file

@ -77,7 +77,7 @@ class Automation {
// Declare war?
if(civInfo.cities.isNotEmpty() && civInfo.diplomacy.isNotEmpty()
&& !civInfo.isAtWar()
&& civInfo.getCivUnits().filter { it.baseUnit.unitType != UnitType.Civilian }.size > civInfo.cities.size*2) {
&& civInfo.getCivUnits().filter { !it.baseUnit.unitType.isCivilian() }.size > civInfo.cities.size*2) {
val enemyCivsByDistanceToOurs = civInfo.diplomacy.values.map { it.otherCiv() }
.filterNot { it == civInfo || it.cities.isEmpty() || !civInfo.diplomacy[it.civName]!!.canDeclareWar() }
@ -142,7 +142,7 @@ class Automation {
}
private fun trainCombatUnit(city: CityInfo) {
val combatUnits = city.cityConstructions.getConstructableUnits().filter { it.unitType != UnitType.Civilian }
val combatUnits = city.cityConstructions.getConstructableUnits().filter { !it.unitType.isCivilian() }
val chosenUnit: BaseUnit
if(!city.civInfo.isAtWar() && city.civInfo.cities.any { it.getCenterTile().militaryUnit==null}
&& combatUnits.any { it.unitType== UnitType.Ranged }) // this is for city defence so get an archery unit if we can
@ -166,7 +166,7 @@ class Automation {
val buildableWonders = getBuildableBuildings().filter { it.isWonder }
val civUnits = cityInfo.civInfo.getCivUnits()
val militaryUnits = civUnits.filter { it.baseUnit().unitType != UnitType.Civilian }.size
val militaryUnits = civUnits.filter { !it.baseUnit().unitType.isCivilian()}.size
val workers = civUnits.filter { it.name == CityConstructions.Worker }.size
val cities = cityInfo.civInfo.cities.size

View file

@ -11,6 +11,7 @@ import com.unciv.logic.civilization.DiplomaticStatus
import com.unciv.logic.map.MapUnit
import com.unciv.logic.map.TileInfo
import com.unciv.models.gamebasics.GameBasics
import com.unciv.models.gamebasics.tile.TerrainType
import com.unciv.ui.utils.getRandom
import com.unciv.ui.worldscreen.unit.UnitAction
import com.unciv.ui.worldscreen.unit.UnitActions
@ -29,6 +30,11 @@ class UnitAutomation{
return
}
if(unit.name=="Work Boats"){
automateWorkBoats(unit)
return
}
if(unit.name.startsWith("Great")) return // I don't know what to do with you yet.
val unitActions = UnitActions().getUnitActions(unit,UnCivGame.Current.worldScreen)
@ -75,6 +81,26 @@ class UnitAutomation{
// if both failed, then... there aren't any reachable tiles. Which is possible.
}
private fun hasWorkableSeaResource(tileInfo: TileInfo): Boolean {
return tileInfo.resource!=null && tileInfo.getBaseTerrain().type==TerrainType.Water && tileInfo.improvement==null
}
private fun automateWorkBoats(unit: MapUnit) {
val seaResourcesInCities = unit.civInfo.cities.flatMap { it.getTilesInRange() }
.filter { hasWorkableSeaResource(it) && (unit.canMoveTo(it) || unit.currentTile==it) }
if (seaResourcesInCities.any()) {
val reachableResource = seaResourcesInCities.asSequence().sortedBy { it.arialDistanceTo(unit.currentTile) }
.firstOrNull { unit.movementAlgs().canReach(it) }
if (reachableResource != null) {
unit.movementAlgs().headTowards(reachableResource)
if(unit.currentMovement>0 && hasWorkableSeaResource(unit.currentTile))
UnitActions().getUnitActions(unit,UnCivGame.Current.worldScreen)
.first { it.name=="Create Fishing Boats" }.action()
}
}
explore(unit, unit.getDistanceToTiles())
}
fun rankTileForHealing(tileInfo: TileInfo, unit: MapUnit): Int {
val tileOwner = tileInfo.getOwner()
when{
@ -127,8 +153,8 @@ class UnitAutomation{
for(reachableTile in tilesToAttackFrom){ // tiles we'll still have energy after we reach there
val tilesInAttackRange = if (unit.hasUnique("Indirect fire")) reachableTile.getTilesInDistance(rangeOfAttack)
else reachableTile.getViewableTiles(rangeOfAttack)
attackableTiles += tilesInAttackRange.filter { it in tilesWithEnemies }
.map { AttackableTile(reachableTile,it) }
attackableTiles += tilesInAttackRange.asSequence().filter { it in tilesWithEnemies }
.map { AttackableTile(reachableTile,it) }.toList()
}
return attackableTiles
}
@ -150,14 +176,13 @@ class UnitAutomation{
}
private fun tryAccompanySettler(unit: MapUnit, unitDistanceToTiles: HashMap<TileInfo, Float>): Boolean {
val closeTileWithSettler = unitDistanceToTiles.keys.firstOrNull {
it.civilianUnit != null && it.civilianUnit!!.name == "Settler"
}
if (closeTileWithSettler != null && unit.canMoveTo(closeTileWithSettler)) {
unit.movementAlgs().headTowards(closeTileWithSettler)
return true
}
return false
val settlerToAccompany = unit.civInfo.getCivUnits()
.firstOrNull { val tile = it.currentTile;
it.name=="Settler" && tile.militaryUnit==null
&& unit.canMoveTo(tile) && unit.movementAlgs().canReach(tile) }
if(settlerToAccompany==null) return false
unit.movementAlgs().headTowards(settlerToAccompany.currentTile)
return true
}
private fun tryUpgradeUnit(unit: MapUnit, unitActions: List<UnitAction>): Boolean {
@ -303,11 +328,15 @@ class UnitAutomation{
fun rankTileAsCityCenter(tileInfo: TileInfo, nearbyTileRankings: Map<TileInfo, Float>): Float {
val bestTilesFromOuterLayer = tileInfo.getTilesAtDistance(2)
.asSequence()
.sortedByDescending { nearbyTileRankings[it] }.take(2)
.toList()
val top5Tiles = tileInfo.neighbors.union(bestTilesFromOuterLayer)
.asSequence()
.sortedByDescending { nearbyTileRankings[it] }
.take(5)
var rank = top5Tiles.map { nearbyTileRankings[it]!! }.sum()
.toList()
var rank = top5Tiles.asSequence().map { nearbyTileRankings[it]!! }.sum()
if(tileInfo.neighbors.any{it.baseTerrain == "Coast"}) rank += 5
return rank
}
@ -315,18 +344,18 @@ class UnitAutomation{
private fun automateSettlerActions(unit: MapUnit) {
if(unit.getTile().militaryUnit==null) return // Don't move until you're accompanied by a military unit
// find best city location within 5 tiles
val tilesNearCities = unit.civInfo.gameInfo.civilizations.flatMap { it.cities }
.flatMap { it.getCenterTile().getTilesInDistance(3) }
.flatMap { it.getCenterTile().getTilesInDistance(3) }.toHashSet()
// This is to improve performance - instead of ranking each tile in the area up to 19 times, do it once.
val nearbyTileRankings = unit.getTile().getTilesInDistance(7)
.associateBy ( {it},{ Automation().rankTile(it,unit.civInfo) })
val possibleTiles = unit.getTile().getTilesInDistance(5)
.minus(tilesNearCities)
val possibleCityLocations = unit.getTile().getTilesInDistance(5)
.filter { (unit.canMoveTo(it) || unit.currentTile==it) && it !in tilesNearCities }
val bestCityLocation: TileInfo? = possibleTiles
val bestCityLocation: TileInfo? = possibleCityLocations
.asSequence()
.sortedByDescending { rankTileAsCityCenter(it, nearbyTileRankings) }
.firstOrNull { unit.movementAlgs().canReach(it) }
@ -336,7 +365,10 @@ class UnitAutomation{
return
}
if (unit.getTile() == bestCityLocation) // already there!
if(bestCityLocation.getTilesInDistance(3).any { it.isCityCenter() })
throw Exception("City within distance")
if (unit.getTile() == bestCityLocation)
UnitActions().getUnitActions(unit, UnCivGame.Current.worldScreen).first { it.name == "Found city" }.action()
else {
unit.movementAlgs().headTowards(bestCityLocation)

View file

@ -18,7 +18,7 @@ class Battle(val gameInfo:GameInfo) {
var damageToDefender = BattleDamage().calculateDamageToDefender(attacker,defender)
var damageToAttacker = BattleDamage().calculateDamageToAttacker(attacker,defender)
if(defender.getUnitType() == UnitType.Civilian && attacker.isMelee()){
if(defender.getUnitType().isCivilian() && attacker.isMelee()){
captureCivilianUnit(attacker,defender)
}
else if (attacker.isRanged()) {
@ -98,7 +98,7 @@ class Battle(val gameInfo:GameInfo) {
}
if(attacker.isMelee()){
if(defender.getUnitType()!=UnitType.Civilian) // unit was not captured but actually attacked
if(!defender.getUnitType().isCivilian()) // unit was not captured but actually attacked
{
addXp(attacker,5,defender)
addXp(defender,4,attacker)
@ -109,7 +109,7 @@ class Battle(val gameInfo:GameInfo) {
addXp(defender,2,attacker)
}
if(defender.isDefeated() && defender is MapUnitCombatant && defender.getUnitType()!=UnitType.Civilian
if(defender.isDefeated() && defender is MapUnitCombatant && !defender.getUnitType().isCivilian()
&& attacker.getCivilization().policies.isAdopted("Honor Complete"))
attacker.getCivilization().gold += defender.unit.baseUnit.getGoldCost(hashSetOf()) / 10

View file

@ -43,7 +43,7 @@ class BattleDamage{
if(combatant.getCivilization().policies.isAdopted("Dicipline") && combatant.isMelee()
&& combatant.getTile().neighbors.flatMap { it.getUnits() }
.any { it.civInfo==combatant.getCivilization() && it.baseUnit.unitType!=UnitType.Civilian})
.any { it.civInfo==combatant.getCivilization() && !it.baseUnit.unitType.isCivilian()})
modifiers["Dicipline"] = 0.15f
}
@ -154,7 +154,7 @@ class BattleDamage{
fun calculateDamageToAttacker(attacker: ICombatant, defender: ICombatant): Int {
if(attacker.isRanged()) return 0
if(defender.getUnitType()== UnitType.Civilian) return 0
if(defender.getUnitType().isCivilian()) return 0
val ratio = getDefendingStrength(attacker,defender) / getAttackingStrength(attacker,defender)
return (ratio * 30 * getHealthDependantDamageRatio(defender)).toInt()
}

View file

@ -85,6 +85,7 @@ class CityExpansionManager {
}
private fun takeOwnership(tileInfo: TileInfo){
if(tileInfo.isCityCenter()) throw Exception("What?")
if(tileInfo.getCity()!=null) tileInfo.getCity()!!.expansion.relinquishOwnership(tileInfo)
cityInfo.tiles.add(tileInfo.position)

View file

@ -212,7 +212,7 @@ class CityStats {
stats.gold += 25f
if (policies.contains("Sovereignty") && cityInfo.civInfo.happiness >= 0)
stats.science += 15f
if (policies.contains("Total War") && currentConstruction is BaseUnit && currentConstruction.unitType!=UnitType.Civilian )
if (policies.contains("Total War") && currentConstruction is BaseUnit && !currentConstruction.unitType.isCivilian() )
stats.production += 15f
if (policies.contains("Aristocracy")
&& currentConstruction is Building

View file

@ -265,7 +265,7 @@ class CivilizationInfo {
// disband units until there are none left OR the gold values are normal
if(!isBarbarianCivilization() && gold < -100 && nextTurnStats.gold.toInt() < 0) {
for (i in 1 until (gold / -100)) {
var civMilitaryUnits = getCivUnits().filter { it.baseUnit().unitType != UnitType.Civilian }
var civMilitaryUnits = getCivUnits().filter { !it.baseUnit().unitType.isCivilian() }
if (civMilitaryUnits.isNotEmpty()) {
val unitToDisband = civMilitaryUnits.first()
unitToDisband.destroy()

View file

@ -110,7 +110,7 @@ class MapUnit {
if(tileOwner!=null && tileOwner.civName!=owner
&& (tile.isCityCenter() || !civInfo.canEnterTiles(tileOwner))) return false
if (baseUnit().unitType== UnitType.Civilian)
if (baseUnit().unitType.isCivilian())
return tile.civilianUnit==null && (tile.militaryUnit==null || tile.militaryUnit!!.owner==owner)
else return tile.militaryUnit==null && (tile.civilianUnit==null || tile.civilianUnit!!.owner==owner)
}
@ -264,13 +264,13 @@ class MapUnit {
}
fun removeFromTile(){
if (baseUnit().unitType== UnitType.Civilian) getTile().civilianUnit=null
if (baseUnit().unitType.isCivilian()) getTile().civilianUnit=null
else getTile().militaryUnit=null
}
fun putInTile(tile:TileInfo){
if(!canMoveTo(tile)) throw Exception("I can't go there!")
if(baseUnit().unitType== UnitType.Civilian)
if(baseUnit().unitType.isCivilian())
tile.civilianUnit=this
else tile.militaryUnit=this
currentTile = tile
@ -302,7 +302,7 @@ class MapUnit {
civInfo.addNotification("A [$chosenUnit] has joined us!",null, Color.BLUE)
}
if(baseUnit.unitType!=UnitType.Civilian)
if(!baseUnit.unitType.isCivilian())
actions.add {
promotions.XP+=10
civInfo.addNotification("An ancient tribe trains our [$name] in their ways of combat!",null, Color.RED)

View file

@ -15,7 +15,7 @@ class PerlinNoiseRandomMapGenerator:SeedRandomMapGenerator(){
override fun generateMap(distance: Int): HashMap<String, TileInfo> {
val map = HashMap<Vector2, TileInfo>()
val mapRandomSeed = Random().nextDouble() // without this, all the "random" maps would look the same
for (vector in HexMath().GetVectorsInDistance(Vector2.Zero, distance))
for (vector in HexMath().getVectorsInDistance(Vector2.Zero, distance))
map[vector] = generateTile(vector,mapRandomSeed)
divideIntoAreas(6, 0f, map)
@ -50,7 +50,7 @@ class AlexanderRandomMapGenerator:RandomMapGenerator(){
fun generateMap(distance: Int, landExpansionChance:Float): HashMap<String, TileInfo> {
val map = HashMap<Vector2, TileInfo?>()
for (vector in HexMath().GetVectorsInDistance(Vector2.Zero, distance))
for (vector in HexMath().getVectorsInDistance(Vector2.Zero, distance))
map[vector] = null
val sparkList = ArrayList<Vector2>()
@ -64,7 +64,7 @@ class AlexanderRandomMapGenerator:RandomMapGenerator(){
while(sparkList.any()){
val currentSpark = sparkList.getRandom()
val emptyTilesAroundSpark = HexMath().GetAdjacentVectors(currentSpark)
val emptyTilesAroundSpark = HexMath().getAdjacentVectors(currentSpark)
.filter { map.containsKey(it) && map[it]==null }
if(map[currentSpark]!!.baseTerrain==grassland){
for(tile in emptyTilesAroundSpark){
@ -84,7 +84,7 @@ class AlexanderRandomMapGenerator:RandomMapGenerator(){
for(entry in map){
entry.value!!.position = entry.key
if(entry.value!!.baseTerrain==ocean
&& HexMath().GetAdjacentVectors(entry.key).all { !map.containsKey(it) || map[it]!!.baseTerrain==grassland })
&& HexMath().getAdjacentVectors(entry.key).all { !map.containsKey(it) || map[it]!!.baseTerrain==grassland })
entry.value!!.baseTerrain=grassland
newmap[entry.key.toString()] = entry.value!!
@ -117,7 +117,7 @@ open class SeedRandomMapGenerator : RandomMapGenerator() {
val map = HashMap<Vector2, TileInfo>()
for (vector in HexMath().GetVectorsInDistance(Vector2.Zero, distance))
for (vector in HexMath().getVectorsInDistance(Vector2.Zero, distance))
map[vector] = TileInfo().apply { position=vector; baseTerrain="" }
@ -182,14 +182,14 @@ open class SeedRandomMapGenerator : RandomMapGenerator() {
continue
}
val availableExpansionVectors = areaToExpand.locations
.flatMap { HexMath().GetAdjacentVectors(it) }.asSequence().distinct()
.flatMap { HexMath().getAdjacentVectors(it) }.asSequence().distinct()
.filter { map.containsKey(it) && map[it]!!.baseTerrain=="" }.toList()
if (availableExpansionVectors.isEmpty()) expandableAreas -= areaToExpand
else {
val expansionVector = availableExpansionVectors.getRandom()
areaToExpand.addTile(map[expansionVector]!!)
val neighbors = HexMath().GetAdjacentVectors(expansionVector)
val neighbors = HexMath().getAdjacentVectors(expansionVector)
val areasToJoin = areas.filter {
it.terrain == areaToExpand.terrain
&& it != areaToExpand
@ -261,7 +261,7 @@ open class RandomMapGenerator {
open fun generateMap(distance: Int): HashMap<String, TileInfo> {
val map = HashMap<String, TileInfo>()
for (vector in HexMath().GetVectorsInDistance(Vector2.Zero, distance))
for (vector in HexMath().getVectorsInDistance(Vector2.Zero, distance))
map[vector.toString()] = addRandomTile(vector)
return map
}
@ -278,7 +278,7 @@ open class RandomMapGenerator {
fun setWaterTiles(map: HashMap<String, TileInfo>) {
for (tile in map.values.filter { it.baseTerrain == "Ocean" }) {
if (HexMath().GetVectorsInDistance(tile.position,2).any { hasWaterTile(map,it) })
if (HexMath().getVectorsInDistance(tile.position,2).any { hasWaterTile(map,it) })
tile.baseTerrain = "Coast"
}
}

View file

@ -51,11 +51,13 @@ class TileMap {
}
fun getTilesInDistance(origin: Vector2, distance: Int): List<TileInfo> {
return HexMath().GetVectorsInDistance(origin, distance).filter {contains(it)}.map { get(it) }
return HexMath().getVectorsInDistance(origin, distance).asSequence()
.filter {contains(it)}.map { get(it) }.toList()
}
fun getTilesAtDistance(origin: Vector2, distance: Int): List<TileInfo> {
return HexMath().GetVectorsAtDistance(origin, distance).filter {contains(it)}.map { get(it) }
return HexMath().getVectorsAtDistance(origin, distance).asSequence()
.filter {contains(it)}.map { get(it) }.toList()
}
@ -88,10 +90,10 @@ class TileMap {
if(tiles.any()) //
tileList.addAll(tiles.values)
val topY=tileList.map { it.position.y.toInt() }.max()!!
bottomY= tileList.map { it.position.y.toInt() }.min()!!
val rightX=tileList.map { it.position.x.toInt() }.max()!!
leftX = tileList.map { it.position.x.toInt() }.min()!!
val topY= tileList.asSequence().map { it.position.y.toInt() }.max()!!
bottomY= tileList.asSequence().map { it.position.y.toInt() }.min()!!
val rightX= tileList.asSequence().map { it.position.x.toInt() }.max()!!
leftX = tileList.asSequence().map { it.position.x.toInt() }.min()!!
for(x in leftX..rightX){
val row = ArrayList<TileInfo?>()

View file

@ -89,18 +89,24 @@ class BaseUnit : INamed, IConstruction, ICivilopedia {
return (cost / 10).toInt() * 10 // rounded down o nearest ten
}
override fun isBuildable(construction: CityConstructions): Boolean {
val civInfo = construction.cityInfo.civInfo
fun isBuildable(civInfo:CivilizationInfo): Boolean {
if (unbuildable) return false
if (requiredTech!=null && !civInfo.tech.isResearched(requiredTech!!)) return false
if (obsoleteTech!=null && civInfo.tech.isResearched(obsoleteTech!!)) return false
if (uniqueTo!=null && uniqueTo!=civInfo.civName) return false
if (GameBasics.Units.values.any { it.uniqueTo==civInfo.civName && it.replaces==name }) return false
if (requiredResource!=null && !civInfo.getCivResources().keys.any { it.name == requiredResource }) return false
if(unitType.isWaterUnit() && construction.cityInfo.getCenterTile().neighbors.none { it.baseTerrain=="Coast" })
return true
}
override fun isBuildable(construction: CityConstructions): Boolean {
if(!isBuildable(construction.cityInfo.civInfo)) return false
if(unitType.isWaterUnit() && construction.cityInfo.getCenterTile().neighbors.none { it.baseTerrain=="Coast" })
return false
return true
}
override fun postBuildEvent(construction: CityConstructions) {
val unit = construction.cityInfo.civInfo.placeUnitNearTile(construction.cityInfo.location, name)
unit.promotions.XP += construction.getBuiltBuildings().sumBy { it.xpForNewUnits }

View file

@ -28,6 +28,12 @@ enum class UnitType{
|| this == Ranged
|| this == Siege
}
fun isCivilian(): Boolean {
return this == Civilian
|| this == WaterCivilian
}
fun isWaterUnit(): Boolean {
return this == WaterCivilian
}

View file

@ -218,7 +218,7 @@ class CityScreen(internal val city: CityInfo) : CameraStageBaseScreen() {
}
val positionalVector = HexMath().Hex2WorldCoords(tileInfo.position.cpy().sub(cityInfo.location))
val positionalVector = HexMath().hex2WorldCoords(tileInfo.position.cpy().sub(cityInfo.location))
val groupSize = 50
tileGroup.setPosition(stage.width / 2 + positionalVector.x * 0.8f * groupSize.toFloat(),
stage.height / 2 + positionalVector.y * 0.8f * groupSize.toFloat())

View file

@ -179,7 +179,7 @@ open class TileGroup(var tileInfo: TileInfo) : Group() {
if (neigborOwner != tileOwner && !borderImages.containsKey(neighbor)) { // there should be a border here but there isn't
val relativeHexPosition = tileInfo.position.cpy().sub(neighbor.position)
val relativeWorldPosition = HexMath().Hex2WorldCoords(relativeHexPosition)
val relativeWorldPosition = HexMath().hex2WorldCoords(relativeHexPosition)
// This is some crazy voodoo magic so I'll explain.
val images = mutableListOf<Image>()
@ -233,7 +233,7 @@ open class TileGroup(var tileInfo: TileInfo) : Group() {
roadImage.image = image
val relativeHexPosition = tileInfo.position.cpy().sub(neighbor.position)
val relativeWorldPosition = HexMath().Hex2WorldCoords(relativeHexPosition)
val relativeWorldPosition = HexMath().hex2WorldCoords(relativeHexPosition)
// This is some crazy voodoo magic so I'll explain.
image.moveBy(25f, 25f) // Move road to center of tile
@ -327,7 +327,7 @@ open class TileGroup(var tileInfo: TileInfo) : Group() {
newImage.center(this)
newImage.y += yFromCenter
if (!unit.isIdle()) newImage.color.a = 0.5f
if (!unit.isIdle() && unit.civInfo.isPlayerCivilization()) newImage.color.a = 0.5f
}
return newImage
}

View file

@ -13,7 +13,6 @@ import com.unciv.logic.city.SpecialConstruction
import com.unciv.logic.map.MapUnit
import com.unciv.logic.map.RoadStatus
import com.unciv.logic.map.TileInfo
import com.unciv.models.gamebasics.unit.UnitType
import com.unciv.ui.cityscreen.CityScreen
import com.unciv.ui.utils.*
@ -25,7 +24,7 @@ class WorldTileGroup(tileInfo: TileInfo) : TileGroup(tileInfo) {
val whiteHalo = if(unit.isFortified()) ImageGetter.getImage("OtherIcons/Shield.png")
else ImageGetter.getImage("OtherIcons/Circle.png")
whiteHalo.setSize(30f,30f)
val unitImage = if(unit.baseUnit().unitType== UnitType.Civilian) civilianUnitImage
val unitImage = if(unit.baseUnit().unitType.isCivilian()) civilianUnitImage
else militaryUnitImage
if(unitImage==null) //Stuff has changed since we requested this, the unit is no longer here...
return

View file

@ -10,6 +10,7 @@ import com.unciv.UnCivGame
import com.unciv.logic.HexMath
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.logic.map.TileInfo
import com.unciv.models.gamebasics.tile.TerrainType
import com.unciv.ui.utils.ImageGetter
import com.unciv.ui.utils.onClick
@ -32,7 +33,7 @@ class Minimap(val tileMapHolder: TileMapHolder) : ScrollPane(null){
for (tileInfo in tileMapHolder.tileMap.values) {
val hex = ImageGetter.getImage("TerrainIcons/Hexagon.png")
val positionalVector = HexMath().Hex2WorldCoords(tileInfo.position)
val positionalVector = HexMath().hex2WorldCoords(tileInfo.position)
val groupSize = 10f
hex.setSize(groupSize,groupSize)
hex.setPosition(positionalVector.x * 0.5f * groupSize,
@ -73,9 +74,10 @@ class Minimap(val tileMapHolder: TileMapHolder) : ScrollPane(null){
val exploredTiles = cloneCivilization.exploredTiles
for(tileInfo in tileMapHolder.tileMap.values) {
val hex = tileImages[tileInfo]!!
val isWaterTile = tileInfo.getBaseTerrain().type==TerrainType.Water
if (!(exploredTiles.contains(tileInfo.position) || UnCivGame.Current.viewEntireMapForDebug)) hex.color = Color.BLACK
else if (tileInfo.isCityCenter()) hex.color = tileInfo.getOwner()!!.getNation().getSecondaryColor()
else if (tileInfo.getCity() != null) hex.color = tileInfo.getOwner()!!.getNation().getColor()
else if (tileInfo.isCityCenter() && !isWaterTile) hex.color = tileInfo.getOwner()!!.getNation().getSecondaryColor()
else if (tileInfo.getCity() != null && !isWaterTile) hex.color = tileInfo.getOwner()!!.getNation().getColor()
else hex.color = tileInfo.getBaseTerrain().getColor().lerp(Color.GRAY, 0.5f) // Todo add to baseterrain as function
}
}

View file

@ -81,7 +81,7 @@ class TileMapHolder(internal val worldScreen: WorldScreen, internal val tileMap:
val positionalVector = HexMath().Hex2WorldCoords(tileInfo.position)
val positionalVector = HexMath().hex2WorldCoords(tileInfo.position)
val groupSize = 50
group.setPosition(worldScreen.stage.width / 2 + positionalVector.x * 0.8f * groupSize.toFloat(),
worldScreen.stage.height / 2 + positionalVector.y * 0.8f * groupSize.toFloat())
@ -156,7 +156,7 @@ class TileMapHolder(internal val worldScreen: WorldScreen, internal val tileMap:
val unitType = unit.baseUnit().unitType
val attackableTiles: List<TileInfo> = when{
unitType==UnitType.Civilian -> unit.getDistanceToTiles().keys.toList()
unitType.isCivilian() -> unit.getDistanceToTiles().keys.toList()
else -> UnitAutomation().getAttackableEnemies(unit, unit.getDistanceToTiles()).map { it.tileToAttack }
}
@ -165,7 +165,7 @@ class TileMapHolder(internal val worldScreen: WorldScreen, internal val tileMap:
it.getUnits().isNotEmpty()
&& it.getUnits().first().owner != unit.owner
&& (playerViewableTilePositions.contains(it.position) || UnCivGame.Current.viewEntireMapForDebug)}) {
if(unit.baseUnit().unitType== UnitType.Civilian) tileGroups[tile]!!.hideCircle()
if(unit.baseUnit().unitType.isCivilian()) tileGroups[tile]!!.hideCircle()
else {
tileGroups[tile]!!.showCircle(colorFromRGB(237, 41, 57))
tileGroups[tile]!!.showCrosshair()

View file

@ -31,7 +31,7 @@ class BattleTable(val worldScreen: WorldScreen): Table() {
fun update() {
val unitTable = worldScreen.bottomBar.unitTable
if (unitTable.selectedUnit == null
|| unitTable.selectedUnit!!.baseUnit().unitType == UnitType.Civilian){
|| unitTable.selectedUnit!!.baseUnit().unitType.isCivilian()){
hide()
return
} // no attacker
@ -102,7 +102,7 @@ class BattleTable(val worldScreen: WorldScreen): Table() {
else if (damageToDefender>defender.getHealth()) damageToDefender=defender.getHealth()
if(attacker.isMelee() && (defender.getUnitType()==UnitType.Civilian
if(attacker.isMelee() && (defender.getUnitType().isCivilian()
|| defender.getUnitType()==UnitType.City && defender.isDefeated())) {
add("")
add("{Captured!}".tr())

View file

@ -42,7 +42,7 @@ class UnitActions {
},true)
}
if(unit.baseUnit().unitType!= UnitType.Civilian
if(!unit.baseUnit().unitType.isCivilian()
&& !unit.hasUnique("No defensive terrain bonus") && !unit.isFortified()) {
actionList += UnitAction("Fortify", { unit.action = "Fortify 0" }, unit.currentMovement != 0f)
}
@ -59,7 +59,7 @@ class UnitActions {
actionList += UnitAction("Stop exploration", { unit.action = null }, true)
}
if(unit.baseUnit().unitType!= UnitType.Civilian && unit.promotions.canBePromoted()){
if(!unit.baseUnit().unitType.isCivilian() && unit.promotions.canBePromoted()){
actionList += UnitAction("Promote",
{UnCivGame.Current.screen = PromotionPickerScreen(unit)},
unit.currentMovement != 0f)

View file

@ -4,7 +4,6 @@ import com.badlogic.gdx.scenes.scene2d.ui.Label
import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.unciv.logic.map.MapUnit
import com.unciv.logic.map.TileInfo
import com.unciv.models.gamebasics.unit.UnitType
import com.unciv.ui.tilegroups.TileGroup
import com.unciv.ui.utils.*
import com.unciv.ui.worldscreen.WorldScreen
@ -65,13 +64,13 @@ class UnitTable(val worldScreen: WorldScreen) : Table(){
unitNameLabel.setText(nameLabelText)
var unitLabelText = "Movement".tr()+": " + unit.getMovementString()
if (unit.baseUnit().unitType != UnitType.Civilian)
if (!unit.baseUnit().unitType.isCivilian())
unitLabelText += "\n"+"Strength".tr()+": " + unit.baseUnit().strength
if (unit.baseUnit().rangedStrength!=0)
unitLabelText += "\n"+"Ranged strength".tr()+": "+unit.baseUnit().rangedStrength
if (unit.baseUnit().unitType != UnitType.Civilian)
if (!unit.baseUnit().unitType.isCivilian())
unitLabelText += "\n"+"XP".tr()+": "+unit.promotions.XP+"/"+unit.promotions.xpForNextPromotion()
if(unit.isFortified() && unit.getFortificationTurns()>0)