mirror of
https://github.com/yairm210/Unciv.git
synced 2025-03-10 04:43:29 +07:00
Trigger uniques by sacrificing units with conditional (#6157)
* Triggered uniques currently come from researching techs, adopting policies, and building buildings. This adds a third way of triggering uniques, by attaching them to units with a "by consuming this unit" conditional, which will be added as a possible unit action. So for example, "[amount] Free Technologies <by consuming this unit>", "Reveals the entire map <by consuming this unit>" etc. * Added a new uniquetype for triggerable uniques, to make them separate from regular global uniques, so that triggerable uniques can become unit uniques when necessary * And added translations so the tests will pass
This commit is contained in:
parent
a8be359ed2
commit
6d48f99206
@ -740,6 +740,7 @@ Pillage =
|
||||
Are you sure you want to pillage this [improvement]? =
|
||||
Create [improvement] =
|
||||
Start Golden Age =
|
||||
Trigger unique =
|
||||
Show more =
|
||||
Yes =
|
||||
No =
|
||||
|
@ -124,6 +124,8 @@ enum class UnitActionType(
|
||||
{ ImageGetter.getUnitIcon("Great Merchant") }, 'g', UncivSound.Chimes),
|
||||
FoundReligion("Found a Religion",
|
||||
{ ImageGetter.getUnitIcon("Great Prophet") }, 'g', UncivSound.Choir),
|
||||
TriggerUnique("Trigger unique",
|
||||
{ ImageGetter.getImage("OtherIcons/Star") }, 'g', UncivSound.Chimes),
|
||||
SpreadReligion("Spread Religion",
|
||||
null, 'g', UncivSound.Choir),
|
||||
RemoveHeresy("Remove Heresy",
|
||||
|
@ -417,7 +417,11 @@ class Ruleset {
|
||||
rulesetErrors.add(deprecationText, severity)
|
||||
}
|
||||
|
||||
if (unique.type.targetTypes.none { uniqueTarget.canAcceptUniqueTarget(it) })
|
||||
if (unique.type.targetTypes.none { uniqueTarget.canAcceptUniqueTarget(it) }
|
||||
// the 'consume unit' conditional causes a triggerable unique to become a unit action
|
||||
&& !(uniqueTarget==UniqueTarget.Unit
|
||||
&& unique.isTriggerable
|
||||
&& unique.conditionals.any { it.type == UniqueType.ConditionalConsumeUnit }))
|
||||
rulesetErrors.add(
|
||||
"$name's unique \"${unique.text}\" cannot be put on this type of object!",
|
||||
RulesetErrorSeverity.Warning
|
||||
|
@ -24,6 +24,9 @@ class Unique(val text: String, val sourceObjectType: UniqueTarget? = null, val s
|
||||
else Stats.parse(firstStatParam)
|
||||
}
|
||||
val conditionals: List<Unique> = text.getConditionals()
|
||||
val isTriggerable = type != null && type.targetTypes.contains(UniqueTarget.Triggerable)
|
||||
// <for [amount] turns]> in effect makes any unique become a triggerable unique
|
||||
|| conditionals.any { it.type == UniqueType.ConditionalTimedUnique }
|
||||
|
||||
val allParams = params + conditionals.flatMap { it.params }
|
||||
|
||||
@ -86,7 +89,10 @@ class Unique(val text: String, val sourceObjectType: UniqueTarget? = null, val s
|
||||
}
|
||||
|
||||
return when (condition.type) {
|
||||
// These are 'what to do' and not 'when to do' conditionals
|
||||
UniqueType.ConditionalTimedUnique -> true
|
||||
UniqueType.ConditionalConsumeUnit -> true
|
||||
|
||||
UniqueType.ConditionalWar -> state.civInfo?.isAtWar() == true
|
||||
UniqueType.ConditionalNotWar -> state.civInfo?.isAtWar() == false
|
||||
UniqueType.ConditionalWithResource -> state.civInfo?.hasResource(condition.params[0]) == true
|
||||
|
@ -10,9 +10,11 @@ import kotlin.collections.HashSet
|
||||
* For example, all Global uniques are acceptable for Nations, Eras, etc. */
|
||||
enum class UniqueTarget(val inheritsFrom: UniqueTarget? = null) {
|
||||
|
||||
/** Only includes uniques that have immediate effects, caused by UniqueTriggerActivation */
|
||||
Triggerable,
|
||||
/** Buildings, units, nations, policies, religions, techs etc.
|
||||
* Basically anything caught by CivInfo.getMatchingUniques. */
|
||||
Global,
|
||||
Global(Triggerable),
|
||||
|
||||
// Civilization-specific
|
||||
Nation(Global),
|
||||
@ -41,7 +43,7 @@ enum class UniqueTarget(val inheritsFrom: UniqueTarget? = null) {
|
||||
Terrain,
|
||||
Improvement,
|
||||
Resource(Global),
|
||||
Ruins,
|
||||
Ruins(Triggerable),
|
||||
|
||||
// Other
|
||||
CityState,
|
||||
@ -595,6 +597,7 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags:
|
||||
ConditionalNoPolicy("before adopting [policy]", UniqueTarget.Conditional),
|
||||
|
||||
ConditionalTimedUnique("for [amount] turns", UniqueTarget.Conditional),
|
||||
ConditionalConsumeUnit("by consuming this unit", UniqueTarget.Conditional),
|
||||
|
||||
/////// city conditionals
|
||||
ConditionalCityWithBuilding("in cities with a [buildingFilter]", UniqueTarget.Conditional),
|
||||
@ -635,19 +638,19 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags:
|
||||
///////////////////////////////////////// region TRIGGERED ONE-TIME /////////////////////////////////////////
|
||||
|
||||
|
||||
OneTimeFreeUnit("Free [baseUnitFilter] appears", UniqueTarget.Global), // used in Policies, Buildings
|
||||
OneTimeAmountFreeUnits("[amount] free [baseUnitFilter] units appear", UniqueTarget.Global), // used in Buildings
|
||||
OneTimeFreeUnit("Free [baseUnitFilter] appears", UniqueTarget.Triggerable), // used in Policies, Buildings
|
||||
OneTimeAmountFreeUnits("[amount] free [baseUnitFilter] units appear", UniqueTarget.Triggerable), // used in Buildings
|
||||
OneTimeFreeUnitRuins("Free [baseUnitFilter] found in the ruins", UniqueTarget.Ruins), // Differs from "Free [] appears" in that it spawns near the ruins instead of in a city
|
||||
OneTimeFreePolicy("Free Social Policy", UniqueTarget.Global), // used in Buildings
|
||||
OneTimeAmountFreePolicies("[amount] Free Social Policies", UniqueTarget.Global), // Not used in Vanilla
|
||||
OneTimeEnterGoldenAge("Empire enters golden age", UniqueTarget.Global), // used in Policies, Buildings
|
||||
OneTimeFreeGreatPerson("Free Great Person", UniqueTarget.Global), // used in Policies, Buildings
|
||||
OneTimeGainPopulation("[amount] population [cityFilter]", UniqueTarget.Global), // used in CN tower
|
||||
OneTimeFreePolicy("Free Social Policy", UniqueTarget.Triggerable), // used in Buildings
|
||||
OneTimeAmountFreePolicies("[amount] Free Social Policies", UniqueTarget.Triggerable), // Not used in Vanilla
|
||||
OneTimeEnterGoldenAge("Empire enters golden age", UniqueTarget.Triggerable), // used in Policies, Buildings
|
||||
OneTimeFreeGreatPerson("Free Great Person", UniqueTarget.Triggerable), // used in Policies, Buildings
|
||||
OneTimeGainPopulation("[amount] population [cityFilter]", UniqueTarget.Triggerable), // used in CN tower
|
||||
OneTimeGainPopulationRandomCity("[amount] population in a random city", UniqueTarget.Ruins),
|
||||
OneTimeFreeTech("Free Technology", UniqueTarget.Global), // used in Buildings
|
||||
OneTimeAmountFreeTechs("[amount] Free Technologies", UniqueTarget.Global), // used in Policy
|
||||
OneTimeFreeTech("Free Technology", UniqueTarget.Triggerable), // used in Buildings
|
||||
OneTimeAmountFreeTechs("[amount] Free Technologies", UniqueTarget.Triggerable), // used in Policy
|
||||
OneTimeFreeTechRuins("[amount] free random researchable Tech(s) from the [era]", UniqueTarget.Ruins), // todo: Not picked up by TranslationFileWriter?
|
||||
OneTimeRevealEntireMap("Reveals the entire map", UniqueTarget.Global), // used in tech
|
||||
OneTimeRevealEntireMap("Reveals the entire map", UniqueTarget.Triggerable), // used in tech
|
||||
OneTimeGainStat("Gain [amount] [stat]", UniqueTarget.Ruins),
|
||||
OneTimeGainStatRange("Gain [amount]-[amount] [stat]", UniqueTarget.Ruins),
|
||||
OneTimeGainPantheon("Gain enough Faith for a Pantheon", UniqueTarget.Ruins),
|
||||
@ -655,20 +658,20 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags:
|
||||
// todo: The "up to [All]" used in vanilla json is not nice to read. Split?
|
||||
OneTimeRevealSpecificMapTiles("Reveal up to [amount/'all'] [tileFilter] within a [amount] tile radius", UniqueTarget.Ruins),
|
||||
OneTimeRevealCrudeMap("From a randomly chosen tile [amount] tiles away from the ruins, reveal tiles up to [amount] tiles away with [amount]% chance", UniqueTarget.Ruins),
|
||||
OneTimeTriggerVoting("Triggers voting for the Diplomatic Victory", UniqueTarget.Global), // used in Building
|
||||
OneTimeTriggerVoting("Triggers voting for the Diplomatic Victory", UniqueTarget.Triggerable), // used in Building
|
||||
|
||||
OneTimeUnitHeal("Heal this unit by [amount] HP", UniqueTarget.Promotion),
|
||||
OneTimeUnitGainXP("This Unit gains [amount] XP", UniqueTarget.Ruins),
|
||||
OneTimeUnitUpgrade("This Unit upgrades for free", UniqueTarget.Global), // Not used in Vanilla
|
||||
OneTimeUnitSpecialUpgrade("This Unit upgrades for free including special upgrades", UniqueTarget.Ruins),
|
||||
OneTimeUnitGainPromotion("This Unit gains the [promotion] promotion", UniqueTarget.Global), // Not used in Vanilla
|
||||
OneTimeUnitGainPromotion("This Unit gains the [promotion] promotion", UniqueTarget.Triggerable), // Not used in Vanilla
|
||||
|
||||
UnitsGainPromotion("[mapUnitFilter] units gain the [promotion] promotion", UniqueTarget.Global), // Not used in Vanilla
|
||||
UnitsGainPromotion("[mapUnitFilter] units gain the [promotion] promotion", UniqueTarget.Triggerable), // Not used in Vanilla
|
||||
// todo: remove forced sign
|
||||
@Deprecated("as of 3.19.8", ReplaceWith("[+amount]% Strength <when attacking> <for [mapUnitFilter] units> <for [amount2] turns>"))
|
||||
TimedAttackStrength("+[amount]% attack strength to all [mapUnitFilter] units for [amount2] turns", UniqueTarget.Global), // used in Policy
|
||||
FreeStatBuildings("Provides the cheapest [stat] building in your first [amount] cities for free", UniqueTarget.Global), // used in Policy
|
||||
FreeSpecificBuildings("Provides a [buildingName] in your first [amount] cities for free", UniqueTarget.Global), // used in Policy
|
||||
FreeStatBuildings("Provides the cheapest [stat] building in your first [amount] cities for free", UniqueTarget.Triggerable), // used in Policy
|
||||
FreeSpecificBuildings("Provides a [buildingName] in your first [amount] cities for free", UniqueTarget.Triggerable), // used in Policy
|
||||
|
||||
//endregion
|
||||
|
||||
|
@ -16,6 +16,7 @@ import com.unciv.models.UncivSound
|
||||
import com.unciv.models.UnitAction
|
||||
import com.unciv.models.UnitActionType
|
||||
import com.unciv.models.ruleset.Building
|
||||
import com.unciv.models.ruleset.unique.UniqueTriggerActivation
|
||||
import com.unciv.models.ruleset.unique.UniqueType
|
||||
import com.unciv.models.stats.Stat
|
||||
import com.unciv.models.stats.Stats
|
||||
@ -64,7 +65,7 @@ object UnitActions {
|
||||
addActionsWithLimitedUses(unit, actionList, tile)
|
||||
addExplorationActions(unit, actionList)
|
||||
addAutomateBuildingImprovementsAction(unit, actionList)
|
||||
|
||||
addTriggerUniqueActions(unit, actionList)
|
||||
|
||||
addToggleActionsAction(unit, actionList, unitTable)
|
||||
|
||||
@ -814,6 +815,18 @@ object UnitActions {
|
||||
return UnitAction(UnitActionType.GiftUnit, action = giftAction)
|
||||
}
|
||||
|
||||
fun addTriggerUniqueActions(unit: MapUnit, actionList: ArrayList<UnitAction>){
|
||||
for (unique in unit.getUniques()) {
|
||||
if (!unique.conditionals.any { it.type == UniqueType.ConditionalConsumeUnit }) continue
|
||||
val unitAction = UnitAction(type = UnitActionType.TriggerUnique, unique.text){
|
||||
UniqueTriggerActivation.triggerCivwideUnique(unique, unit.civInfo)
|
||||
addStatsPerGreatPersonUsage(unit)
|
||||
unit.destroy()
|
||||
}
|
||||
actionList += unitAction
|
||||
}
|
||||
}
|
||||
|
||||
private fun addToggleActionsAction(unit: MapUnit, actionList: ArrayList<UnitAction>, unitTable: UnitTable) {
|
||||
actionList += UnitAction(
|
||||
type = if (unit.showAdditionalActions) UnitActionType.HideAdditionalActions
|
||||
|
@ -65,7 +65,7 @@ class TranslationTests {
|
||||
val key = if (entry.contains('[')) entry.replace(squareBraceRegex, "[]") else entry
|
||||
if (!translations.containsKey(key)) {
|
||||
allStringsHaveTranslation = false
|
||||
println(entry)
|
||||
println("$entry not translated!")
|
||||
}
|
||||
}
|
||||
return allStringsHaveTranslation
|
||||
|
Loading…
Reference in New Issue
Block a user