mirror of
https://github.com/yairm210/Unciv.git
synced 2025-03-15 04:14:44 +07:00
Barbarian fixes (#5573)
* no new camps in 4 tiles for 15 turns after cleared * can't spawn land units on water or vice versa, unit choice * UniqueType.MustSetUp
This commit is contained in:
parent
87d24e89c4
commit
d8bb60f06c
@ -7,6 +7,7 @@ import com.unciv.logic.map.TileInfo
|
||||
import com.unciv.logic.map.TileMap
|
||||
import com.unciv.models.metadata.GameSpeed
|
||||
import com.unciv.models.ruleset.unique.UniqueType
|
||||
import com.unciv.ui.utils.randomWeighted
|
||||
import java.util.*
|
||||
import kotlin.collections.HashMap
|
||||
import kotlin.math.max
|
||||
@ -38,8 +39,7 @@ class BarbarianManager {
|
||||
for (tile in tileMap.values) {
|
||||
if (tile.improvement == Constants.barbarianEncampment
|
||||
&& camps[tile.position] == null) {
|
||||
val newCamp = Encampment()
|
||||
newCamp.position = tile.position
|
||||
val newCamp = Encampment(tile.position)
|
||||
camps[newCamp.position] = newCamp
|
||||
}
|
||||
}
|
||||
@ -50,11 +50,17 @@ class BarbarianManager {
|
||||
|
||||
fun updateEncampments() {
|
||||
// Check if camps were destroyed
|
||||
for (position in camps.keys.toList()) {
|
||||
val positionsToRemove = ArrayList<Vector2>()
|
||||
for ((position, camp) in camps) {
|
||||
if (tileMap[position].improvement != Constants.barbarianEncampment) {
|
||||
camps.remove(position)
|
||||
camp.wasDestroyed()
|
||||
}
|
||||
// Check if the ghosts are ready to depart
|
||||
if (camp.destroyed && camp.countdown == 0)
|
||||
positionsToRemove.add(position)
|
||||
}
|
||||
for (position in positionsToRemove)
|
||||
camps.remove(position)
|
||||
|
||||
// Possibly place a new encampment
|
||||
placeBarbarianEncampment()
|
||||
@ -83,7 +89,7 @@ class BarbarianManager {
|
||||
val fogTilesPerCamp = (tileMap.values.size.toFloat().pow(0.4f)).toInt() // Approximately
|
||||
|
||||
// Check if we have more room
|
||||
var campsToAdd = (fogTiles.size / fogTilesPerCamp) - camps.size
|
||||
var campsToAdd = (fogTiles.size / fogTilesPerCamp) - camps.count { !it.value.destroyed }
|
||||
|
||||
// First turn of the game add 1/3 of all possible camps
|
||||
if (gameInfo.turns == 1) {
|
||||
@ -98,7 +104,9 @@ class BarbarianManager {
|
||||
val tooCloseToCapitals = gameInfo.civilizations.filterNot { it.isBarbarian() || it.isSpectator() || it.cities.isEmpty() || it.isCityState() }
|
||||
.flatMap { it.getCapital().getCenterTile().getTilesInDistance(4) }.toSet()
|
||||
val tooCloseToCamps = camps
|
||||
.flatMap { tileMap[it.key].getTilesInDistance(7) }.toSet()
|
||||
.flatMap { tileMap[it.key].getTilesInDistance(
|
||||
if (it.value.destroyed) 4 else 7
|
||||
) }.toSet()
|
||||
|
||||
val viableTiles = fogTiles.filter {
|
||||
!it.isImpassible()
|
||||
@ -127,8 +135,7 @@ class BarbarianManager {
|
||||
tile = viableTiles.random()
|
||||
|
||||
tile.improvement = Constants.barbarianEncampment
|
||||
val newCamp = Encampment()
|
||||
newCamp.position = tile.position
|
||||
val newCamp = Encampment(tile.position)
|
||||
newCamp.gameInfo = gameInfo
|
||||
camps[newCamp.position] = newCamp
|
||||
notifyCivsOfBarbarianEncampment(tile)
|
||||
@ -160,26 +167,26 @@ class BarbarianManager {
|
||||
}
|
||||
}
|
||||
|
||||
class Encampment {
|
||||
class Encampment (val position: Vector2) {
|
||||
var countdown = 0
|
||||
var spawnedUnits = -1
|
||||
lateinit var position: Vector2
|
||||
var destroyed = false // destroyed encampments haunt the vicinity for 15 turns preventing new spawns
|
||||
|
||||
@Transient
|
||||
lateinit var gameInfo: GameInfo
|
||||
|
||||
fun clone(): Encampment {
|
||||
val toReturn = Encampment()
|
||||
toReturn.position = position
|
||||
val toReturn = Encampment(position)
|
||||
toReturn.countdown = countdown
|
||||
toReturn.spawnedUnits = spawnedUnits
|
||||
toReturn.destroyed = destroyed
|
||||
return toReturn
|
||||
}
|
||||
|
||||
fun update() {
|
||||
if (countdown > 0) // Not yet
|
||||
countdown--
|
||||
else if (spawnBarbarian()) { // Countdown at 0, try to spawn a barbarian
|
||||
else if (!destroyed && spawnBarbarian()) { // Countdown at 0, try to spawn a barbarian
|
||||
// Successful
|
||||
spawnedUnits++
|
||||
resetCountdown()
|
||||
@ -187,7 +194,15 @@ class Encampment {
|
||||
}
|
||||
|
||||
fun wasAttacked() {
|
||||
countdown /= 2
|
||||
if (!destroyed)
|
||||
countdown /= 2
|
||||
}
|
||||
|
||||
fun wasDestroyed() {
|
||||
if (!destroyed) {
|
||||
countdown = 15
|
||||
destroyed = true
|
||||
}
|
||||
}
|
||||
|
||||
/** Attempts to spawn a Barbarian from this encampment. Returns true if a unit was spawned. */
|
||||
@ -238,18 +253,20 @@ class Encampment {
|
||||
val barbarianCiv = gameInfo.getBarbarianCivilization()
|
||||
barbarianCiv.tech.techsResearched = allResearchedTechs.toHashSet()
|
||||
val unitList = gameInfo.ruleSet.units.values
|
||||
.filter { it.isMilitary() }
|
||||
.filter { it.isBuildable(barbarianCiv) }
|
||||
.filter { it.isMilitary() &&
|
||||
it.isBuildable(barbarianCiv) &&
|
||||
!(it.hasUnique(UniqueType.MustSetUp) || it.hasUnique(UniqueType.CannotAttack)) &&
|
||||
(if (naval) it.isWaterUnit() else it.isLandUnit()) }
|
||||
|
||||
var unit = if (naval)
|
||||
unitList.filter { it.isWaterUnit() }.randomOrNull()
|
||||
else
|
||||
unitList.filter { it.isLandUnit() }.randomOrNull()
|
||||
if (unitList.isEmpty()) return null // No naval tech yet? Mad modders?
|
||||
|
||||
if (unit == null) // Didn't find a unit for preferred domain
|
||||
unit = unitList.randomOrNull() // Try picking another
|
||||
// Civ V weights its list by FAST_ATTACK or ATTACK_SEA AI types, we'll do it a bit differently
|
||||
// getForceEvaluation is already conveniently biased towards fast units and against ranged naval
|
||||
val weightings = unitList.map { it.getForceEvaluation().toFloat() }
|
||||
|
||||
return unit?.name // Could still be null in case of mad modders
|
||||
val unit = unitList.randomWeighted(weightings)
|
||||
|
||||
return unit.name
|
||||
}
|
||||
|
||||
/** When a barbarian is spawned, seed the counter for next spawn */
|
||||
|
@ -49,7 +49,7 @@ object BattleHelper {
|
||||
// So the poor unit thought it could attack from the tile, but when it comes to do so it has no movement points!
|
||||
// Silly floats, basically
|
||||
|
||||
val unitMustBeSetUp = unit.hasUnique("Must set up to ranged attack")
|
||||
val unitMustBeSetUp = unit.hasUnique(UniqueType.MustSetUp)
|
||||
val tilesToAttackFrom = if (stayOnTile || unit.baseUnit.movesLikeAirUnits())
|
||||
sequenceOf(Pair(unit.currentTile, unit.currentMovement))
|
||||
else
|
||||
|
@ -36,7 +36,7 @@ object Battle {
|
||||
* but the hidden tile is actually IMPASSIBLE so you stop halfway!
|
||||
*/
|
||||
if (attacker.getTile() != attackableTile.tileToAttackFrom) return
|
||||
if (attacker.unit.hasUnique("Must set up to ranged attack") && !attacker.unit.isSetUpForSiege()) {
|
||||
if (attacker.unit.hasUnique(UniqueType.MustSetUp) && !attacker.unit.isSetUpForSiege()) {
|
||||
attacker.unit.action = UnitActionType.SetUp.value
|
||||
attacker.unit.useMovementPoints(1f)
|
||||
}
|
||||
|
@ -222,6 +222,7 @@ enum class UniqueType(val text:String, vararg targets: UniqueTarget) {
|
||||
MayEnhanceReligion("May enhance a religion", UniqueTarget.Unit),
|
||||
NormalVisionWhenEmbarked("Normal vision when embarked", UniqueTarget.Unit, UniqueTarget.Global),
|
||||
CannotAttack("Cannot attack", UniqueTarget.Unit),
|
||||
MustSetUp("Must set up to ranged attack", UniqueTarget.Unit),
|
||||
|
||||
@Deprecated("As of 3.16.11 - removed as of 3.17.11", ReplaceWith("[+1] Movement <for [Embarked] units>"), DeprecationLevel.ERROR)
|
||||
EmbarkedUnitMovement1("Increases embarked movement +1", UniqueTarget.Global),
|
||||
|
@ -659,7 +659,7 @@ class BaseUnit : RulesetObject(), INonPerpetualConstruction {
|
||||
//
|
||||
unique.placeholderText == "May Paradrop up to [] tiles from inside friendly territory" // Paradrop - 25% bonus
|
||||
-> power += power / 4
|
||||
unique.placeholderText == "Must set up to ranged attack" // Must set up - 20 % penalty
|
||||
unique.isOfType(UniqueType.MustSetUp) // Must set up - 20 % penalty
|
||||
-> power -= power / 5
|
||||
unique.placeholderText == "[] additional attacks per turn" // Extra attacks - 20% bonus per extra attack
|
||||
-> power += (power * unique.params[0].toInt()) / 5
|
||||
|
@ -230,7 +230,7 @@ object UnitActions {
|
||||
}
|
||||
|
||||
private fun addSetupAction(unit: MapUnit, actionList: ArrayList<UnitAction>) {
|
||||
if (!unit.hasUnique("Must set up to ranged attack") || unit.isEmbarked()) return
|
||||
if (!unit.hasUnique(UniqueType.MustSetUp) || unit.isEmbarked()) return
|
||||
val isSetUp = unit.isSetUpForSiege()
|
||||
actionList += UnitAction(UnitActionType.SetUp,
|
||||
isCurrentAction = isSetUp,
|
||||
|
Loading…
Reference in New Issue
Block a user