mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-30 07:21:34 -04:00
Resolved #646 - Barbarians now spawn from Encampments!
This commit is contained in:
parent
b068e6f88f
commit
4b4f5e77b8
BIN
android/Images/ImprovementIcons/Barbarian encampment.png
Normal file
BIN
android/Images/ImprovementIcons/Barbarian encampment.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.0 KiB |
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Before Width: | Height: | Size: 991 KiB After Width: | Height: | Size: 998 KiB |
@ -412,7 +412,7 @@
|
||||
"Bodhgaya","Kushinagar","Amaravati","Gaur","Gwalior","Jaipur","Karachi"]
|
||||
},
|
||||
/*
|
||||
{
|
||||
{ // REQUIRES BARBARIAN CAMPS
|
||||
name:"Germany",
|
||||
leaderName:"Otto von Bismark",
|
||||
adjective:["German"],
|
||||
@ -450,14 +450,14 @@
|
||||
"Recklinghausen","Gצttingen","Wolfsburg","Koblenz","Hildesheim","Erlangen"]
|
||||
},
|
||||
|
||||
{
|
||||
{ // REQUIRES RIVERS
|
||||
name:"Aztecs",
|
||||
leaderName:"Montezuma I",
|
||||
adjective:["Aztec"],
|
||||
startBias:["Jungle"],
|
||||
|
||||
startIntroPart1: "Welcome, o divine Montezuma! We grovel in awe at your magnificence! May the heaven shower all manner of good things upon you all the days of your life! Your are the leader of the mighty Aztec people, wandering nomads from a lost home in the north who in the 12th century came to live in the mesa central in the heart of what would come to be call Mexico. Surrounded by many tribes fighting to control the rich land surrounding the sacred lakes of Texoco, Xaltocan and Zampango. Through cunning alliances and martial prowess, within a mere two hundred years, the Aztecs came to dominate the Central American basin, ruling a mighty empire stretching from sea to sea. But the empire fell soon under the assault of the accursed Spaniards, wielding fiendish weapons the likes of which your faithful warriors had never seen."
|
||||
startIntroPart2: "O great king Mintezuma, your people call upon you once more, to rise up and lead them to glory, bring them wealth and power, and give them dominion over their foes and rivals. Will you answer their call, glorious leader? Will you build a civilization that stands the test of time?"
|
||||
startIntroPart2: "O great king Montezuma, your people call upon you once more, to rise up and lead them to glory, bring them wealth and power, and give them dominion over their foes and rivals. Will you answer their call, glorious leader? Will you build a civilization that stands the test of time?"
|
||||
|
||||
declaringWar:"Xi-miqa-can! Xi-miqa-can! Xi-miqa-can! (Die, die, die!)"
|
||||
attacked:"Excellent! Let the blood flow in raging torrents!"
|
||||
|
@ -145,10 +145,7 @@
|
||||
improvingTechStats:{gold:1}
|
||||
},
|
||||
|
||||
{
|
||||
name:"Ancient ruins"
|
||||
},
|
||||
{
|
||||
name:"City ruins"
|
||||
}
|
||||
{ name:"Ancient ruins" },
|
||||
{ name:"City ruins" },
|
||||
{ name:"Barbarian encampment" },
|
||||
]
|
@ -10,5 +10,7 @@ class Constants{
|
||||
const val jungle = "Jungle"
|
||||
const val hill = "Hill"
|
||||
const val peaceTreaty = "Peace Treaty"
|
||||
const val barbarianEncampment = "Barbarian encampment"
|
||||
const val ancientRuins = "Ancient ruins"
|
||||
}
|
||||
}
|
@ -17,7 +17,7 @@ class UnCivGame(val version: String) : Game() {
|
||||
* This exists so that when debugging we can see the entire map.
|
||||
* Remember to turn this to false before commit and upload!
|
||||
*/
|
||||
val viewEntireMapForDebug = false
|
||||
val viewEntireMapForDebug = true
|
||||
|
||||
// For when you need to test something in an advanced game and don't have time to faff around
|
||||
val superchargedForDebug = false
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.unciv.logic
|
||||
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.unciv.Constants
|
||||
import com.unciv.GameParameters
|
||||
import com.unciv.logic.automation.NextTurnAutomation
|
||||
import com.unciv.logic.city.CityConstructions
|
||||
@ -11,6 +12,7 @@ import com.unciv.logic.map.TileInfo
|
||||
import com.unciv.logic.map.TileMap
|
||||
import com.unciv.models.gamebasics.Difficulty
|
||||
import com.unciv.models.gamebasics.GameBasics
|
||||
import java.util.*
|
||||
|
||||
class GameInfo {
|
||||
@Transient lateinit var difficultyObject: Difficulty // Since this is static game-wide, and was taking a large part of nextTurn
|
||||
@ -51,9 +53,25 @@ class GameInfo {
|
||||
currentPlayerIndex = (currentPlayerIndex+1) % civilizations.size
|
||||
if(currentPlayerIndex==0){
|
||||
turns++
|
||||
if (turns % 10 == 0 && !gameParameters.noBarbarians) { // every 10 turns add a barbarian in a random place
|
||||
placeBarbarianUnit(null)
|
||||
if (turns % 10 == 0 && !gameParameters.noBarbarians) {
|
||||
val encampments = tileMap.values.filter { it.improvement==Constants.barbarianEncampment }
|
||||
|
||||
if(encampments.size < civilizations.filter { it.isMajorCiv() }.size*2) {
|
||||
val newEncampmentTile = placeBarbarianEncampment(encampments)
|
||||
if (newEncampmentTile != null)
|
||||
placeBarbarianUnit(newEncampmentTile)
|
||||
}
|
||||
|
||||
val totalBarbariansAllowedOnMap = encampments.size*3
|
||||
var extraBarbarians = totalBarbariansAllowedOnMap - getBarbarianCivilization().getCivUnits().size
|
||||
|
||||
for (tile in tileMap.values.filter { it.improvement == Constants.barbarianEncampment }) {
|
||||
if(extraBarbarians<=0) break
|
||||
extraBarbarians--
|
||||
placeBarbarianUnit(tile)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
thisPlayer = civilizations[currentPlayerIndex]
|
||||
thisPlayer.startTurn()
|
||||
@ -105,19 +123,24 @@ class GameInfo {
|
||||
}
|
||||
}
|
||||
|
||||
fun placeBarbarianUnit(tileToPlace: TileInfo?) {
|
||||
var tile = tileToPlace
|
||||
if (tileToPlace == null) {
|
||||
// Barbarians will only spawn in places that no one can see
|
||||
val allViewableTiles = civilizations.filterNot { it.isBarbarianCivilization() }
|
||||
.flatMap { it.viewableTiles }.toHashSet()
|
||||
val viableTiles = tileMap.values.filter { it.militaryUnit == null
|
||||
&& it.civilianUnit == null && !it.getBaseTerrain().impassable && it.baseTerrain!="Lakes"
|
||||
&& !allViewableTiles.contains(it)}
|
||||
if (viableTiles.isEmpty()) return // no place for more barbs =(
|
||||
tile = viableTiles.random()
|
||||
fun placeBarbarianEncampment(existingEncampments: List<TileInfo>): TileInfo? {
|
||||
// Barbarians will only spawn in places that no one can see
|
||||
val allViewableTiles = civilizations.filterNot { it.isBarbarianCivilization() }
|
||||
.flatMap { it.viewableTiles }.toHashSet()
|
||||
val tilesWithin3ofExistingEncampment = existingEncampments.flatMap { it.getTilesInDistance(3) }
|
||||
val viableTiles = tileMap.values.filter {
|
||||
!it.getBaseTerrain().impassable && it.isLand
|
||||
&& it.terrainFeature==null
|
||||
&& it !in tilesWithin3ofExistingEncampment
|
||||
&& it !in allViewableTiles
|
||||
}
|
||||
if (viableTiles.isEmpty()) return null // no place for more barbs =(
|
||||
val tile = viableTiles.random()
|
||||
tile.improvement = Constants.barbarianEncampment
|
||||
return tile
|
||||
}
|
||||
|
||||
fun placeBarbarianUnit(tileToPlace: TileInfo) {
|
||||
// if we don't make this into a separate list then the retain() will happen on the Tech keys,
|
||||
// which effectively removes those techs from the game and causes all sorts of problems
|
||||
val allResearchedTechs = GameBasics.Technologies.keys.toMutableList()
|
||||
@ -127,9 +150,17 @@ class GameInfo {
|
||||
val unitList = GameBasics.Units.values.filter { !it.unitType.isCivilian() && it.uniqueTo == null }
|
||||
.filter{ allResearchedTechs.contains(it.requiredTech)
|
||||
&& (it.obsoleteTech == null || !allResearchedTechs.contains(it.obsoleteTech!!)) }
|
||||
val unit = if (unitList.isEmpty()) "Warrior" else unitList.random().name
|
||||
|
||||
tileMap.placeUnitNearTile(tile!!.position, unit, getBarbarianCivilization())
|
||||
val landUnits = unitList.filter { it.unitType.isLandUnit() }
|
||||
val waterUnits = unitList.filter { it.unitType.isWaterUnit() }
|
||||
|
||||
val unit:String
|
||||
if (unitList.isEmpty()) unit="Warrior"
|
||||
else if(waterUnits.isNotEmpty() && tileToPlace.neighbors.any{ it.baseTerrain=="Coast" } && Random().nextBoolean())
|
||||
unit=waterUnits.random().name
|
||||
else unit = landUnits.random().name
|
||||
|
||||
tileMap.placeUnitNearTile(tileToPlace.position, unit, getBarbarianCivilization())
|
||||
}
|
||||
|
||||
// All cross-game data which needs to be altered (e.g. when removing or changing a name of a building/tech)
|
||||
|
@ -29,7 +29,7 @@ class SpecificUnitAutomation{
|
||||
return createImprovementAction.action() // unit is already gone, can't "Explore"
|
||||
}
|
||||
}
|
||||
else UnitAutomation().explore(unit, unit.getDistanceToTiles())
|
||||
else UnitAutomation().tryExplore(unit, unit.getDistanceToTiles())
|
||||
}
|
||||
|
||||
fun automateGreatGeneral(unit: MapUnit){
|
||||
@ -95,8 +95,11 @@ class SpecificUnitAutomation{
|
||||
.sortedByDescending { rankTileAsCityCenter(it, nearbyTileRankings) }
|
||||
.firstOrNull { unit.movementAlgs().canReach(it) }
|
||||
|
||||
if(bestCityLocation==null) // We got a badass over here, all tiles within 5 are taken? Screw it, random walk.
|
||||
return UnitAutomation().explore(unit, unit.getDistanceToTiles())
|
||||
if(bestCityLocation==null) { // We got a badass over here, all tiles within 5 are taken? Screw it, random walk.
|
||||
if(UnitAutomation().tryExplore(unit, unit.getDistanceToTiles())) return // try to find new areas
|
||||
UnitAutomation().wander(unit, unit.getDistanceToTiles()) // go around aimlessly
|
||||
return
|
||||
}
|
||||
|
||||
if(bestCityLocation.getTilesInDistance(3).any { it.isCityCenter() })
|
||||
throw Exception("City within distance")
|
||||
|
@ -40,6 +40,10 @@ class UnitAutomation{
|
||||
val unitActions = UnitActions().getUnitActions(unit,UnCivGame.Current.worldScreen)
|
||||
var unitDistanceToTiles = unit.getDistanceToTiles()
|
||||
|
||||
if(unit.civInfo.isBarbarianCivilization() &&
|
||||
unit.currentTile.improvement==Constants.barbarianEncampment && unit.type.isLandUnit())
|
||||
return // stay in the encampment
|
||||
|
||||
if(tryGoToRuin(unit,unitDistanceToTiles)){
|
||||
if(unit.currentMovement==0f) return
|
||||
unitDistanceToTiles = unit.getDistanceToTiles()
|
||||
@ -61,7 +65,7 @@ class UnitAutomation{
|
||||
if (tryAttackNearbyEnemy(unit)) return
|
||||
|
||||
// Barbarians try to pillage improvements if no targets reachable
|
||||
if (unit.civInfo.isBarbarianCivilization() && pillageImprovement(unit, unitDistanceToTiles)) return
|
||||
if (unit.civInfo.isBarbarianCivilization() && tryPillageImprovement(unit, unitDistanceToTiles)) return
|
||||
|
||||
if (tryGarrisoningUnit(unit)) return
|
||||
|
||||
@ -75,17 +79,21 @@ class UnitAutomation{
|
||||
// Focus all units without a specific target on the enemy city closest to one of our cities
|
||||
if (tryHeadTowardsEnemyCity(unit)) return
|
||||
|
||||
// else, go to a random space
|
||||
explore(unit,unitDistanceToTiles)
|
||||
// if both failed, then... there aren't any reachable tiles. Which is possible.
|
||||
// else, try to go o unreached tiles
|
||||
if(tryExplore(unit,unitDistanceToTiles)) return
|
||||
|
||||
// Barbarians just wander all over the place
|
||||
if(unit.civInfo.isBarbarianCivilization())
|
||||
wander(unit,unitDistanceToTiles)
|
||||
}
|
||||
|
||||
|
||||
|
||||
fun tryHealUnit(unit: MapUnit, unitDistanceToTiles: HashMap<TileInfo, Float>):Boolean {
|
||||
val tilesInDistance = unitDistanceToTiles.keys.filter { unit.canMoveTo(it) }
|
||||
val unitTile = unit.getTile()
|
||||
|
||||
if (pillageImprovement(unit, unitDistanceToTiles)) return true
|
||||
if (tryPillageImprovement(unit, unitDistanceToTiles)) return true
|
||||
|
||||
val tilesByHealingRate = tilesInDistance.groupBy { unit.rankTileForHealing(it) }
|
||||
if(tilesByHealingRate.isEmpty()) return false
|
||||
@ -105,7 +113,7 @@ class UnitAutomation{
|
||||
return true
|
||||
}
|
||||
|
||||
fun pillageImprovement(unit: MapUnit, unitDistanceToTiles: HashMap<TileInfo, Float>) : Boolean {
|
||||
fun tryPillageImprovement(unit: MapUnit, unitDistanceToTiles: HashMap<TileInfo, Float>) : Boolean {
|
||||
val tilesInDistance = unitDistanceToTiles.filter {it.value < unit.currentMovement}.keys
|
||||
.filter { unit.canMoveTo(it) && it.improvement != null && UnitActions().canPillage(unit,it) }
|
||||
|
||||
@ -114,8 +122,8 @@ class UnitAutomation{
|
||||
if (unit.getTile()!=tileToPillage)
|
||||
unit.moveToTile(tileToPillage)
|
||||
|
||||
UnitActions().getUnitActions(unit,UnCivGame.Current.worldScreen)
|
||||
.first { it.name=="Pillage" }.action()
|
||||
UnitActions().getUnitActions(unit, UnCivGame.Current.worldScreen)
|
||||
.first { it.name == "Pillage" }.action()
|
||||
return true
|
||||
}
|
||||
|
||||
@ -125,7 +133,7 @@ class UnitAutomation{
|
||||
if (combatant.isRanged()) return false
|
||||
if (tile.isWater) return false // can't attack water units while embarked, only land
|
||||
}
|
||||
if (combatant.unit.hasUnique("Can only attack water") && tile.isLand) return false
|
||||
if (tile.isLand && combatant.unit.hasUnique("Can only attack water")) return false
|
||||
}
|
||||
|
||||
val tileCombatant = Battle(combatant.getCivInfo().gameInfo).getMapCombatantOfTile(tile)
|
||||
@ -391,24 +399,26 @@ class UnitAutomation{
|
||||
}
|
||||
|
||||
fun tryGoToRuin(unit:MapUnit, unitDistanceToTiles: HashMap<TileInfo, Float>): Boolean {
|
||||
val tileWithRuin = unitDistanceToTiles.keys.firstOrNull{unit.canMoveTo(it) && it.improvement == "Ancient ruins"}
|
||||
if(unit.civInfo.isBarbarianCivilization()) return false // barbs don't have anything to do in ruins
|
||||
val tileWithRuin = unitDistanceToTiles.keys.firstOrNull{unit.canMoveTo(it) && it.improvement == Constants.ancientRuins}
|
||||
if(tileWithRuin==null) return false
|
||||
unit.moveToTile(tileWithRuin)
|
||||
return true
|
||||
}
|
||||
|
||||
internal fun explore(unit: MapUnit, unitDistanceToTiles: HashMap<TileInfo, Float>) {
|
||||
internal fun tryExplore(unit: MapUnit, unitDistanceToTiles: HashMap<TileInfo, Float>): Boolean {
|
||||
if(tryGoToRuin(unit,unitDistanceToTiles))
|
||||
{
|
||||
if(unit.currentMovement==0f) return
|
||||
if(unit.currentMovement==0f) return true
|
||||
}
|
||||
|
||||
for(tile in unit.currentTile.getTilesInDistance(5))
|
||||
if(unit.canMoveTo(tile) && tile.position !in unit.civInfo.exploredTiles
|
||||
&& unit.movementAlgs().canReach(tile)){
|
||||
unit.movementAlgs().headTowards(tile)
|
||||
return
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun automatedExplore(unit:MapUnit){
|
||||
@ -432,4 +442,15 @@ class UnitAutomation{
|
||||
unit.civInfo.addNotification("[${unit.name}] finished exploring.", unit.currentTile.position, Color.GRAY)
|
||||
}
|
||||
|
||||
|
||||
fun wander(unit: MapUnit, unitDistanceToTiles: HashMap<TileInfo, Float>) {
|
||||
val reachableTiles= unitDistanceToTiles
|
||||
.filter { unit.canMoveTo(it.key) && unit.movementAlgs().canReach(it.key) }
|
||||
|
||||
val reachableTilesMaxWalkingDistance = reachableTiles.filter { it.value == unit.currentMovement }
|
||||
if (reachableTilesMaxWalkingDistance.any()) unit.moveToTile(reachableTilesMaxWalkingDistance.toList().random().first)
|
||||
else if (reachableTiles.any()) unit.moveToTile(reachableTiles.toList().random().first)
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -456,8 +456,10 @@ class MapUnit {
|
||||
tile.civilianUnit=this
|
||||
else tile.militaryUnit=this
|
||||
currentTile = tile
|
||||
if(tile.improvement=="Ancient ruins" && !civInfo.isBarbarianCivilization())
|
||||
if(tile.improvement==Constants.ancientRuins && !civInfo.isBarbarianCivilization())
|
||||
getAncientRuinBonus()
|
||||
if(tile.improvement==Constants.barbarianEncampment && !civInfo.isBarbarianCivilization())
|
||||
tile.improvement=null // todo get bonus from clearing encampment
|
||||
|
||||
updateViewableTiles()
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.unciv.logic.map
|
||||
|
||||
import com.badlogic.gdx.math.Vector2
|
||||
import com.unciv.Constants
|
||||
import com.unciv.Constants.Companion.mountain
|
||||
import com.unciv.Constants.Companion.ocean
|
||||
import com.unciv.logic.HexMath
|
||||
@ -488,7 +489,7 @@ open class RandomMapGenerator {
|
||||
fun maybeAddAncientRuins(tile: TileInfo) {
|
||||
val baseTerrain = tile.getBaseTerrain()
|
||||
if(baseTerrain.type!=TerrainType.Water && !baseTerrain.impassable && Random().nextDouble() < 1f/100)
|
||||
tile.improvement = "Ancient ruins"
|
||||
tile.improvement = Constants.ancientRuins
|
||||
}
|
||||
|
||||
|
||||
|
@ -51,14 +51,12 @@ class TradeLogic(val ourCivilization:CivilizationInfo, val otherCivilization: Ci
|
||||
}
|
||||
|
||||
val otherCivsWeKnow = civInfo.getKnownCivs()
|
||||
.filter { it.civName != otherCivilization.civName && !it.isBarbarianCivilization() && !it.isDefeated() }
|
||||
.filter { it.civName != otherCivilization.civName && it.isMajorCiv() && !it.isDefeated() }
|
||||
val civsWeKnowAndTheyDont = otherCivsWeKnow
|
||||
.filter { !otherCivilization.diplomacy.containsKey(it.civName) && !it.isDefeated() }
|
||||
|
||||
if (!otherCivilization.isCityState()) {
|
||||
for (thirdCiv in civsWeKnowAndTheyDont) {
|
||||
offers.add(TradeOffer("Introduction to " + thirdCiv.civName, TradeType.Introduction, 0))
|
||||
}
|
||||
for (thirdCiv in civsWeKnowAndTheyDont) {
|
||||
offers.add(TradeOffer("Introduction to " + thirdCiv.civName, TradeType.Introduction, 0))
|
||||
}
|
||||
|
||||
if (!civInfo.isCityState() && !otherCivilization.isCityState()) {
|
||||
@ -105,11 +103,11 @@ class TradeLogic(val ourCivilization:CivilizationInfo, val otherCivilization: Ci
|
||||
if(offer.name==Constants.peaceTreaty) to.getDiplomacyManager(from).makePeace()
|
||||
}
|
||||
if(offer.type==TradeType.Introduction)
|
||||
to.meetCivilization(to.gameInfo.getCivilization(offer.name.split(" ")[2]))
|
||||
to.meetCivilization(to.gameInfo.getCivilization(offer.name.removePrefix("Introduction to " )))
|
||||
|
||||
if(offer.type==TradeType.WarDeclaration){
|
||||
val nameOfCivToDeclareWarOn = offer.name.split(' ').last()
|
||||
from.diplomacy[nameOfCivToDeclareWarOn]!!.declareWar()
|
||||
val nameOfCivToDeclareWarOn = offer.name.removePrefix("Declare war on ")
|
||||
from.getDiplomacyManager(nameOfCivToDeclareWarOn).declareWar()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import com.badlogic.gdx.scenes.scene2d.InputEvent
|
||||
import com.badlogic.gdx.scenes.scene2d.actions.FloatAction
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane
|
||||
import com.badlogic.gdx.scenes.scene2d.utils.ActorGestureListener
|
||||
import com.unciv.Constants
|
||||
import com.unciv.UnCivGame
|
||||
import com.unciv.logic.automation.UnitAutomation
|
||||
import com.unciv.logic.city.CityInfo
|
||||
@ -216,6 +217,9 @@ class TileMapHolder(internal val worldScreen: WorldScreen, internal val tileMap:
|
||||
|| (!tileGroup.tileInfo.hasEnemySubmarine())
|
||||
tileGroup.update(canSeeTile, showSubmarine)
|
||||
|
||||
if(tileGroup.tileInfo.improvement==Constants.barbarianEncampment)
|
||||
tileGroup.showCircle(Color.RED)
|
||||
|
||||
val unitsInTile = tileGroup.tileInfo.getUnits()
|
||||
val canSeeEnemy = unitsInTile.isNotEmpty() && unitsInTile.first().civInfo.isAtWarWith(civInfo)
|
||||
&& (showSubmarine || unitsInTile.firstOrNull {!it.isInvisible()}!=null)
|
||||
@ -266,7 +270,9 @@ class TileMapHolder(internal val worldScreen: WorldScreen, internal val tileMap:
|
||||
else 0.5f
|
||||
for (tile in tileGroups.values) {
|
||||
if (tile.populationImage != null) tile.populationImage!!.color.a = fadeout
|
||||
if (tile.improvementImage != null) tile.improvementImage!!.color.a = fadeout
|
||||
if (tile.improvementImage != null && tile.tileInfo.improvement!=Constants.barbarianEncampment
|
||||
&& tile.tileInfo.improvement!=Constants.ancientRuins)
|
||||
tile.improvementImage!!.color.a = fadeout
|
||||
if (tile.resourceImage != null) tile.resourceImage!!.color.a = fadeout
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user