mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-09 03:58:46 -04:00
Add unique to allow for generalized great generals (#10828)
* Add unique to allow for generalized great generals * Don't add compatibility for rulesets with conditional generals * Add to rulesets * add in pre Kotlin 9 parenthesis * whoops missed a parenthesis * I guess pre Kotlin 9 parenthesis was unnecessary, whoops * Add back old variables to clone function * Move the list of all potential generals to Ruleset * Move list of unit construction rejections to IConstruction * flip !any{} to none{} * Fix imports * Typo
This commit is contained in:
parent
6e84377090
commit
665b5aa87c
@ -1653,6 +1653,7 @@
|
||||
"Empire enters a [8]-turn Golden Age <by consuming this unit>",
|
||||
"[+15]% Strength bonus for [Military] units within [2] tiles",
|
||||
"Can instantly construct a [Citadel] improvement <by consuming this unit>",
|
||||
"Can be earned through combat",
|
||||
"Great Person - [War]", "Unbuildable", "Uncapturable"],
|
||||
"movement": 2
|
||||
},
|
||||
@ -1666,6 +1667,7 @@
|
||||
"[+15]% Strength bonus for [Military] units within [2] tiles",
|
||||
"All adjacent units heal [+15] HP when healing", "[+15] HP when healing",
|
||||
"Can instantly construct a [Citadel] improvement <by consuming this unit>",
|
||||
"Can be earned through combat",
|
||||
"Great Person - [War]", "Unbuildable", "Uncapturable"],
|
||||
"movement": 5
|
||||
},
|
||||
|
@ -1296,6 +1296,7 @@
|
||||
"Empire enters a [8]-turn Golden Age <by consuming this unit>",
|
||||
"[+15]% Strength bonus for [Military] units within [2] tiles",
|
||||
"Can instantly construct a [Citadel] improvement <by consuming this unit>",
|
||||
"Can be earned through combat",
|
||||
"Great Person - [War]", "Unbuildable", "Uncapturable"],
|
||||
"movement": 2
|
||||
},
|
||||
@ -1309,6 +1310,7 @@
|
||||
"[+15]% Strength bonus for [Military] units within [2] tiles",
|
||||
"All adjacent units heal [+15] HP when healing", "[+15] HP when healing",
|
||||
"Can instantly construct a [Citadel] improvement <by consuming this unit>",
|
||||
"Can be earned through combat",
|
||||
"Great Person - [War]", "Unbuildable", "Uncapturable"],
|
||||
"movement": 5
|
||||
},
|
||||
|
@ -37,6 +37,19 @@ object BackwardCompatibility {
|
||||
removeTechAndPolicies()
|
||||
}
|
||||
|
||||
fun GameInfo.migrateGreatGeneralPools() {
|
||||
for (civ in civilizations) civ.greatPeople.run {
|
||||
if (pointsForNextGreatGeneral >= pointsForNextGreatGeneralCounter["Great General"]) {
|
||||
pointsForNextGreatGeneralCounter["Great General"] = pointsForNextGreatGeneral
|
||||
} else pointsForNextGreatGeneral = pointsForNextGreatGeneralCounter["Great General"]
|
||||
|
||||
|
||||
if (greatGeneralPoints >= greatGeneralPointsCounter["Great General"]) {
|
||||
greatGeneralPointsCounter["Great General"] = greatGeneralPoints
|
||||
} else greatGeneralPoints = greatGeneralPointsCounter["Great General"]
|
||||
}
|
||||
}
|
||||
|
||||
private fun GameInfo.removeUnitsAndPromotions() {
|
||||
for (tile in tileMap.values) {
|
||||
for (unit in tile.getUnits().toList()) {
|
||||
|
@ -7,6 +7,7 @@ import com.unciv.UncivGame.Version
|
||||
import com.unciv.json.json
|
||||
import com.unciv.logic.BackwardCompatibility.convertFortify
|
||||
import com.unciv.logic.BackwardCompatibility.guaranteeUnitPromotions
|
||||
import com.unciv.logic.BackwardCompatibility.migrateGreatGeneralPools
|
||||
import com.unciv.logic.BackwardCompatibility.migrateToTileHistory
|
||||
import com.unciv.logic.BackwardCompatibility.removeMissingModReferences
|
||||
import com.unciv.logic.GameInfo.Companion.CURRENT_COMPATIBILITY_NUMBER
|
||||
@ -670,6 +671,8 @@ class GameInfo : IsPartOfGameInfoSerialization, HasGameInfoSerializationVersion
|
||||
guaranteeUnitPromotions()
|
||||
|
||||
migrateToTileHistory()
|
||||
|
||||
migrateGreatGeneralPools()
|
||||
}
|
||||
|
||||
private fun updateCivilizationState() {
|
||||
|
@ -482,19 +482,29 @@ object Battle {
|
||||
promotions.XP += xpGained
|
||||
|
||||
if (!otherIsBarbarian && civ.isMajorCiv()) { // Can't get great generals from Barbarians
|
||||
val greatGeneralPointsBonus = thisCombatant
|
||||
.getMatchingUniques(UniqueType.GreatPersonEarnedFaster, stateForConditionals, true)
|
||||
.filter { unique ->
|
||||
val unitName = unique.params[0]
|
||||
// From the unique we know this unit exists
|
||||
val unit = civ.gameInfo.ruleset.units[unitName]!!
|
||||
unit.uniques.contains("Great Person - [War]")
|
||||
}
|
||||
.sumOf { it.params[1].toDouble() }
|
||||
val greatGeneralPointsModifier = 1.0 + greatGeneralPointsBonus / 100
|
||||
var greatGeneralUnits = civ.gameInfo.ruleset.greatGeneralUnits
|
||||
.filter { it.hasUnique(UniqueType.GreatPersonFromCombat, stateForConditionals) &&
|
||||
// Check if the unit is allowed for the Civ, ignoring build constrants
|
||||
it.getRejectionReasons(civ).none { reason ->
|
||||
!reason.isConstructionRejection() &&
|
||||
// Allow Generals even if not allowed via tech
|
||||
!reason.techPolicyEraWonderRequirements() }
|
||||
}.asSequence()
|
||||
// For compatibility with older rulesets
|
||||
if (civ.gameInfo.ruleset.greatGeneralUnits.isEmpty() &&
|
||||
civ.gameInfo.ruleset.units["Great General"] != null)
|
||||
greatGeneralUnits += civ.gameInfo.ruleset.units["Great General"]!!
|
||||
|
||||
val greatGeneralPointsGained = (xpGained * greatGeneralPointsModifier).toInt()
|
||||
civ.greatPeople.greatGeneralPoints += greatGeneralPointsGained
|
||||
for (unit in greatGeneralUnits) {
|
||||
val greatGeneralPointsBonus = thisCombatant
|
||||
.getMatchingUniques(UniqueType.GreatPersonEarnedFaster, stateForConditionals, true)
|
||||
.filter { unit.matchesFilter(it.params[0]) }
|
||||
.sumOf { it.params[1].toDouble() }
|
||||
val greatGeneralPointsModifier = 1.0 + greatGeneralPointsBonus / 100
|
||||
|
||||
val greatGeneralPointsGained = (xpGained * greatGeneralPointsModifier).toInt()
|
||||
civ.greatPeople.greatGeneralPointsCounter[unit.name] += greatGeneralPointsGained
|
||||
}
|
||||
}
|
||||
|
||||
if (!thisCombatant.isDefeated() && !unitCouldAlreadyPromote && promotions.canBePromoted()) {
|
||||
|
@ -19,8 +19,10 @@ class GreatPersonManager : IsPartOfGameInfoSerialization {
|
||||
/** Base points, without speed modifier */
|
||||
var pointsForNextGreatPersonCounter = Counter<String>() // Initial values assigned in getPointsRequiredForGreatPerson as needed
|
||||
var pointsForNextGreatGeneral = 200
|
||||
var pointsForNextGreatGeneralCounter = Counter<String>() // Initial values assigned when needed
|
||||
|
||||
var greatPersonPointsCounter = Counter<String>()
|
||||
var greatGeneralPointsCounter = Counter<String>()
|
||||
var greatGeneralPoints = 0
|
||||
var freeGreatPeople = 0
|
||||
/** Marks subset of [freeGreatPeople] as subject to maya ability restrictions (each only once untill all used) */
|
||||
@ -33,6 +35,8 @@ class GreatPersonManager : IsPartOfGameInfoSerialization {
|
||||
toReturn.freeGreatPeople = freeGreatPeople
|
||||
toReturn.greatPersonPointsCounter = greatPersonPointsCounter.clone()
|
||||
toReturn.pointsForNextGreatPersonCounter = pointsForNextGreatPersonCounter.clone()
|
||||
toReturn.pointsForNextGreatGeneralCounter = pointsForNextGreatGeneralCounter.clone()
|
||||
toReturn.greatGeneralPointsCounter = greatGeneralPointsCounter.clone()
|
||||
toReturn.pointsForNextGreatGeneral = pointsForNextGreatGeneral
|
||||
toReturn.greatGeneralPoints = greatGeneralPoints
|
||||
toReturn.mayaLimitedFreeGP = mayaLimitedFreeGP
|
||||
@ -54,10 +58,16 @@ class GreatPersonManager : IsPartOfGameInfoSerialization {
|
||||
}
|
||||
|
||||
fun getNewGreatPerson(): String? {
|
||||
if (greatGeneralPoints > pointsForNextGreatGeneral) {
|
||||
greatGeneralPoints -= pointsForNextGreatGeneral
|
||||
pointsForNextGreatGeneral += 50
|
||||
return "Great General"
|
||||
for ((unit, value) in greatGeneralPointsCounter){
|
||||
if (pointsForNextGreatGeneralCounter[unit] == 0) {
|
||||
pointsForNextGreatGeneralCounter[unit] = 200
|
||||
}
|
||||
val requiredPoints = pointsForNextGreatGeneralCounter[unit]
|
||||
if (value > requiredPoints) {
|
||||
greatGeneralPointsCounter[unit] -= requiredPoints
|
||||
pointsForNextGreatGeneralCounter[unit] += 50
|
||||
return unit
|
||||
}
|
||||
}
|
||||
|
||||
for ((greatPerson, value) in greatPersonPointsCounter) {
|
||||
|
@ -118,6 +118,8 @@ class RejectionReason(val type: RejectionReasonType,
|
||||
|
||||
fun isImportantRejection(): Boolean = type in orderedImportantRejectionTypes
|
||||
|
||||
fun isConstructionRejection(): Boolean = type in constructionRejectionReasonType
|
||||
|
||||
/** Returns the index of [orderedImportantRejectionTypes] with the smallest index having the
|
||||
* highest precedence */
|
||||
fun getRejectionPrecedence(): Int {
|
||||
@ -152,6 +154,12 @@ class RejectionReason(val type: RejectionReasonType,
|
||||
RejectionReasonType.MaxNumberBuildable,
|
||||
RejectionReasonType.NoPlaceToPutUnit,
|
||||
)
|
||||
// Used for units spawned, not built
|
||||
private val constructionRejectionReasonType = listOf(
|
||||
RejectionReasonType.Unbuildable,
|
||||
RejectionReasonType.CannotBeBuiltUnhappiness,
|
||||
RejectionReasonType.CannotBeBuilt,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
@ -15,6 +15,7 @@ import com.unciv.models.ruleset.tile.Terrain
|
||||
import com.unciv.models.ruleset.tile.TileImprovement
|
||||
import com.unciv.models.ruleset.tile.TileResource
|
||||
import com.unciv.models.ruleset.unique.IHasUniques
|
||||
import com.unciv.models.ruleset.unique.StateForConditionals
|
||||
import com.unciv.models.ruleset.unique.Unique
|
||||
import com.unciv.models.ruleset.unique.UniqueType
|
||||
import com.unciv.models.ruleset.unit.BaseUnit
|
||||
@ -69,6 +70,10 @@ class Ruleset {
|
||||
var victories = LinkedHashMap<String, Victory>()
|
||||
var cityStateTypes = LinkedHashMap<String, CityStateType>()
|
||||
|
||||
val greatGeneralUnits by lazy {
|
||||
units.values.filter { it.hasUnique(UniqueType.GreatPersonFromCombat, StateForConditionals.IgnoreConditionals) }
|
||||
}
|
||||
|
||||
val mods = LinkedHashSet<String>()
|
||||
var modOptions = ModOptions()
|
||||
|
||||
|
@ -437,6 +437,7 @@ enum class UniqueType(
|
||||
// XP
|
||||
FlatXPGain("[amount] XP gained from combat", UniqueTarget.Unit, UniqueTarget.Global),
|
||||
PercentageXPGain("[relativeAmount]% XP gained from combat", UniqueTarget.Unit, UniqueTarget.Global),
|
||||
GreatPersonFromCombat("Can be earned through combat", UniqueTarget.Unit),
|
||||
GreatPersonEarnedFaster("[greatPerson] is earned [relativeAmount]% faster", UniqueTarget.Unit, UniqueTarget.Global),
|
||||
|
||||
// Invisibility
|
||||
|
@ -211,10 +211,14 @@ class StatsOverviewTab(
|
||||
add(greatPersonPointsPerTurn[greatPerson].toLabel()).right().row()
|
||||
}
|
||||
|
||||
val pointsForGreatGeneral = viewingPlayer.greatPeople.greatGeneralPoints
|
||||
val pointsForNextGreatGeneral = viewingPlayer.greatPeople.pointsForNextGreatGeneral
|
||||
add("Great General".toLabel()).left()
|
||||
add("$pointsForGreatGeneral/$pointsForNextGreatGeneral".toLabel())
|
||||
val greatGeneralPoints = viewingPlayer.greatPeople.greatGeneralPointsCounter
|
||||
val pointsForNextGreatGeneral = viewingPlayer.greatPeople.pointsForNextGreatGeneralCounter
|
||||
for ((unit, points) in greatGeneralPoints) {
|
||||
val pointsToGreatGeneral = pointsForNextGreatGeneral[unit]
|
||||
add(unit.toLabel()).left()
|
||||
add("$points/$pointsToGreatGeneral".toLabel())
|
||||
}
|
||||
|
||||
pack()
|
||||
}
|
||||
|
||||
|
@ -216,8 +216,8 @@ class BattleTest {
|
||||
Battle.attack(MapUnitCombatant(defaultAttackerUnit), MapUnitCombatant(defaultDefenderUnit))
|
||||
|
||||
// then
|
||||
assertEquals(5, attackerCiv.greatPeople.greatGeneralPoints)
|
||||
assertEquals(4, defenderCiv.greatPeople.greatGeneralPoints)
|
||||
assertEquals(5, attackerCiv.greatPeople.greatGeneralPointsCounter["Great General"])
|
||||
assertEquals(4, defenderCiv.greatPeople.greatGeneralPointsCounter["Great General"])
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -230,8 +230,8 @@ class BattleTest {
|
||||
Battle.attack(MapUnitCombatant(defaultAttackerUnit), MapUnitCombatant(barbarianUnit))
|
||||
|
||||
// then
|
||||
assertEquals(0, attackerCiv.greatPeople.greatGeneralPoints)
|
||||
assertEquals(0, barbarianCiv.greatPeople.greatGeneralPoints)
|
||||
assertEquals(0, attackerCiv.greatPeople.greatGeneralPointsCounter["Great General"])
|
||||
assertEquals(0, barbarianCiv.greatPeople.greatGeneralPointsCounter["Great General"])
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -243,7 +243,7 @@ class BattleTest {
|
||||
Battle.attack(MapUnitCombatant(attackerUnit), MapUnitCombatant(defaultDefenderUnit))
|
||||
|
||||
// then
|
||||
assertEquals(10, attackerCiv.greatPeople.greatGeneralPoints)
|
||||
assertEquals(10, attackerCiv.greatPeople.greatGeneralPointsCounter["Great General"])
|
||||
}
|
||||
|
||||
@Test
|
||||
|
Loading…
x
Reference in New Issue
Block a user