diff --git a/core/src/com/unciv/models/ruleset/unique/Unique.kt b/core/src/com/unciv/models/ruleset/unique/Unique.kt index 355f29e365..f059867261 100644 --- a/core/src/com/unciv/models/ruleset/unique/Unique.kt +++ b/core/src/com/unciv/models/ruleset/unique/Unique.kt @@ -125,7 +125,8 @@ class Unique(val text: String, val sourceObjectType: UniqueTarget? = null, val s state: StateForConditionals ): Boolean { - if (condition.type!!.targetTypes.contains(UniqueTarget.TriggerCondition)) + val nonConditionalConditionTypes = setOf(UniqueTarget.TriggerCondition, UniqueTarget.UnitTriggerCondition, UniqueTarget.UnitActionModifier) + if (condition.type!!.targetTypes.any { it in nonConditionalConditionTypes }) return true // not a filtering condition fun ruleset() = state.civInfo!!.gameInfo.ruleset @@ -146,7 +147,6 @@ 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.ConditionalBeforeTurns -> state.civInfo != null && state.civInfo.gameInfo.turns < condition.params[0].toInt() UniqueType.ConditionalAfterTurns -> state.civInfo != null && state.civInfo.gameInfo.turns >= condition.params[0].toInt() diff --git a/core/src/com/unciv/models/ruleset/unique/UniqueType.kt b/core/src/com/unciv/models/ruleset/unique/UniqueType.kt index c795130651..7deb29310f 100644 --- a/core/src/com/unciv/models/ruleset/unique/UniqueType.kt +++ b/core/src/com/unciv/models/ruleset/unique/UniqueType.kt @@ -53,7 +53,8 @@ enum class UniqueTarget(val inheritsFrom: UniqueTarget? = null) { ModOptions, Conditional, TriggerCondition(Global), - UnitTriggerCondition(TriggerCondition) + UnitTriggerCondition(TriggerCondition), + UnitActionModifier, ; fun canAcceptUniqueTarget(uniqueTarget: UniqueTarget): Boolean { @@ -345,11 +346,30 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags: ///////////////////////////////////////// region UNIT UNIQUES ///////////////////////////////////////// + // Unit action uniques FoundCity("Founds a new city", UniqueTarget.Unit), ConstructImprovementConsumingUnit("Can construct [improvementName]", UniqueTarget.Unit), BuildImprovements("Can build [improvementFilter/terrainFilter] improvements on tiles", UniqueTarget.Unit), CreateWaterImprovements("May create improvements on water resources", UniqueTarget.Unit), + MayFoundReligion("May found a religion", UniqueTarget.Unit), + MayEnhanceReligion("May enhance a religion", UniqueTarget.Unit), + + StartGoldenAge("Can start an [amount]-turn golden age", UniqueTarget.Unit), + AddInCapital("Can be added to [comment] in the Capital", UniqueTarget.Unit), + PreventSpreadingReligion("Prevents spreading of religion to the city it is next to", UniqueTarget.Unit), + RemoveOtherReligions("Removes other religions when spreading religion", UniqueTarget.Unit), + + MayParadrop("May Paradrop up to [amount] tiles from inside friendly territory", UniqueTarget.Unit), + CanAirsweep("Can perform Air Sweep", UniqueTarget.Unit), + CanActionSeveralTimes("Can [action] [amount] times", UniqueTarget.Unit), + CanSpeedupConstruction("Can speed up construction of a building", UniqueTarget.Unit), + CanSpeedupWonderConstruction("Can speed up the construction of a wonder", UniqueTarget.Unit), + CanHurryResearch("Can hurry technology research", UniqueTarget.Unit), + CanTradeWithCityStateForGoldAndInfluence("Can undertake a trade mission with City-State, giving a large sum of gold and [amount] Influence", UniqueTarget.Unit), + CanTransform("Can transform to [unit]", UniqueTarget.Unit), + + // Strength bonuses Strength("[relativeAmount]% Strength", UniqueTarget.Unit, UniqueTarget.Global), StrengthNearCapital("[relativeAmount]% Strength decreasing with distance from the capital", UniqueTarget.Unit, UniqueTarget.Global), FlankAttackBonus("[relativeAmount]% to Flank Attack bonuses", UniqueTarget.Unit, UniqueTarget.Global), @@ -359,6 +379,7 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags: StrengthWhenStacked("[relativeAmount]% Strength when stacked with [mapUnitFilter]", UniqueTarget.Unit), // candidate for conditional! StrengthBonusInRadius("[relativeAmount]% Strength bonus for [mapUnitFilter] units within [amount] tiles", UniqueTarget.Unit), + // Stat bonuses AdditionalAttacks("[amount] additional attacks per turn", UniqueTarget.Unit, UniqueTarget.Global), Movement("[amount] Movement", UniqueTarget.Unit, UniqueTarget.Global), Sight("[amount] Sight", UniqueTarget.Unit, UniqueTarget.Global, UniqueTarget.Terrain), @@ -366,15 +387,21 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags: Heal("[amount] HP when healing", UniqueTarget.Unit, UniqueTarget.Global), SpreadReligionStrength("[relativeAmount]% Spread Religion Strength", UniqueTarget.Unit, UniqueTarget.Global), - MayFoundReligion("May found a religion", UniqueTarget.Unit), - MayEnhanceReligion("May enhance a religion", UniqueTarget.Unit), StatsWhenSpreading("When spreading religion to a city, gain [amount] times the amount of followers of other religions as [stat]", UniqueTarget.Unit, UniqueTarget.Global), + // Attack restrictions CanOnlyAttackUnits("Can only attack [combatantFilter] units", UniqueTarget.Unit), CanOnlyAttackTiles("Can only attack [tileFilter] tiles", UniqueTarget.Unit), CannotAttack("Cannot attack", UniqueTarget.Unit), MustSetUp("Must set up to ranged attack", UniqueTarget.Unit), SelfDestructs("Self-destructs when attacking", UniqueTarget.Unit), + + // Attack unrestrictions + AttackAcrossCoast("Eliminates combat penalty for attacking across a coast", UniqueTarget.Unit), + AttackOnSea("May attack when embarked", UniqueTarget.Unit), + AttackAcrossRiver("Eliminates combat penalty for attacking over a river", UniqueTarget.Unit), + + // Missiles BlastRadius("Blast radius [amount]", UniqueTarget.Unit), IndirectFire("Ranged attacks may be performed over obstacles", UniqueTarget.Unit), NuclearWeapon("Nuclear weapon of Strength [amount]", UniqueTarget.Unit), @@ -387,12 +414,13 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags: MayWithdraw("May withdraw before melee ([amount]%)", UniqueTarget.Unit), CannotCaptureCities("Unable to capture cities", UniqueTarget.Unit), + // Movement NoMovementToPillage("No movement cost to pillage", UniqueTarget.Unit, UniqueTarget.Global), CanMoveAfterAttacking("Can move after attacking", UniqueTarget.Unit), TransferMovement("Transfer Movement to [mapUnitFilter]", UniqueTarget.Unit), MoveImmediatelyOnceBought("Can move immediately once bought", UniqueTarget.Unit), - MayParadrop("May Paradrop up to [amount] tiles from inside friendly territory", UniqueTarget.Unit), + // Healing HealsOutsideFriendlyTerritory("May heal outside of friendly territory", UniqueTarget.Unit, UniqueTarget.Global), HealingEffectsDoubled("All healing effects doubled", UniqueTarget.Unit, UniqueTarget.Global), HealsAfterKilling("Heals [amount] damage if it kills a unit", UniqueTarget.Unit, UniqueTarget.Global), @@ -400,41 +428,42 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags: HealsEvenAfterAction("Unit will heal every turn, even if it performs an action", UniqueTarget.Unit), HealAdjacentUnits("All adjacent units heal [amount] HP when healing", UniqueTarget.Unit), + // Vision NormalVisionWhenEmbarked("Normal vision when embarked", UniqueTarget.Unit, UniqueTarget.Global), DefenceBonusWhenEmbarked("Defense bonus when embarked", UniqueTarget.Unit, UniqueTarget.Global), - AttackAcrossCoast("Eliminates combat penalty for attacking across a coast", UniqueTarget.Unit), - AttackOnSea("May attack when embarked", UniqueTarget.Unit), - AttackAcrossRiver("Eliminates combat penalty for attacking over a river", UniqueTarget.Unit), - NoSight("No Sight", UniqueTarget.Unit), CanSeeOverObstacles("Can see over obstacles", UniqueTarget.Unit), + // Carrying CarryAirUnits("Can carry [amount] [mapUnitFilter] units", UniqueTarget.Unit), CarryExtraAirUnits("Can carry [amount] extra [mapUnitFilter] units", UniqueTarget.Unit), CannotBeCarriedBy("Cannot be carried by [mapUnitFilter] units", UniqueTarget.Unit), + // Interception ChanceInterceptAirAttacks("[relativeAmount]% chance to intercept air attacks", UniqueTarget.Unit), DamageFromInterceptionReduced("Damage taken from interception reduced by [relativeAmount]%", UniqueTarget.Unit), DamageWhenIntercepting("[relativeAmount]% Damage when intercepting", UniqueTarget.Unit), ExtraInterceptionsPerTurn("[amount] extra interceptions may be made per turn", UniqueTarget.Unit), CannotBeIntercepted("Cannot be intercepted", UniqueTarget.Unit), CannotInterceptUnits("Cannot intercept [mapUnitFilter] units", UniqueTarget.Unit), - CanAirsweep("Can perform Air Sweep", UniqueTarget.Unit), StrengthWhenAirsweep("[relativeAmount]% Strength when performing Air Sweep", UniqueTarget.Unit), UnitMaintenanceDiscount("[relativeAmount]% maintenance costs", UniqueTarget.Unit, UniqueTarget.Global), UnitUpgradeCost("[relativeAmount]% Gold cost of upgrading", UniqueTarget.Unit, UniqueTarget.Global), + // Gains from battle DamageUnitsPlunder("Earn [amount]% of the damage done to [combatantFilter] units as [civWideStat]", UniqueTarget.Unit, UniqueTarget.Global), CaptureCityPlunder("Upon capturing a city, receive [amount] times its [stat] production as [civWideStat] immediately", UniqueTarget.Unit, UniqueTarget.Global), KillUnitPlunder("Earn [amount]% of killed [mapUnitFilter] unit's [costOrStrength] as [civWideStat]", UniqueTarget.Unit, UniqueTarget.Global), KillUnitPlunderNearCity("Earn [amount]% of [mapUnitFilter] unit's [costOrStrength] as [civWideStat] when killed within 4 tiles of a city following this religion", UniqueTarget.FollowerBelief), KillUnitCapture("May capture killed [mapUnitFilter] units", UniqueTarget.Unit), + // XP FlatXPGain("[amount] XP gained from combat", UniqueTarget.Unit, UniqueTarget.Global), PercentageXPGain("[relativeAmount]% XP gained from combat", UniqueTarget.Unit, UniqueTarget.Global), GreatPersonEarnedFaster("[greatPerson] is earned [relativeAmount]% faster", UniqueTarget.Unit, UniqueTarget.Global), + // Invisibility Invisible("Invisible to others", UniqueTarget.Unit), InvisibleToNonAdjacent("Invisible to non-adjacent units", UniqueTarget.Unit), CanSeeInvisibleUnits("Can see invisible [mapUnitFilter] units", UniqueTarget.Unit), @@ -443,7 +472,7 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags: DestroysImprovementUponAttack("Destroys tile improvements when attacking", UniqueTarget.Unit), - // The following block gets cached in MapUnit for faster getMovementCostBetweenAdjacentTiles + // Movement - The following block gets cached in MapUnit for faster getMovementCostBetweenAdjacentTiles CannotMove("Cannot move", UniqueTarget.Unit), DoubleMovementOnTerrain("Double movement in [terrainFilter]", UniqueTarget.Unit), AllTilesCost1Move("All tiles cost 1 movement", UniqueTarget.Unit), @@ -462,28 +491,20 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags: ReligiousUnit("Religious Unit", UniqueTarget.Unit), SpaceshipPart("Spaceship part", UniqueTarget.Unit, UniqueTarget.Building), // Should be deprecated in the near future - AddInCapital("Can be added to [comment] in the Capital", UniqueTarget.Unit), - - StartGoldenAge("Can start an [amount]-turn golden age", UniqueTarget.Unit), - GreatPerson("Great Person - [comment]", UniqueTarget.Unit), - - PreventSpreadingReligion("Prevents spreading of religion to the city it is next to", UniqueTarget.Unit), TakeReligionOverBirthCity("Takes your religion over the one in their birth city", UniqueTarget.Unit), - RemoveOtherReligions("Removes other religions when spreading religion", UniqueTarget.Unit), - - CanActionSeveralTimes("Can [action] [amount] times", UniqueTarget.Unit), // Hurried means: sped up using great engineer/scientist ability, so this is in some sense a unit unique that should be here CannotBeHurried("Cannot be hurried", UniqueTarget.Building, UniqueTarget.Tech), - CanSpeedupConstruction("Can speed up construction of a building", UniqueTarget.Unit), - CanSpeedupWonderConstruction("Can speed up the construction of a wonder", UniqueTarget.Unit), - CanHurryResearch("Can hurry technology research", UniqueTarget.Unit), - CanTradeWithCityStateForGoldAndInfluence("Can undertake a trade mission with City-State, giving a large sum of gold and [amount] Influence", UniqueTarget.Unit), - - CanTransform("Can transform to [unit]", UniqueTarget.Unit), + GreatPerson("Great Person - [comment]", UniqueTarget.Unit), //endregion + ///////////////////////////////////////// region UNIT ACTION MODIFIERS ///////////////////////////////////////// + + ConditionalConsumeUnit("by consuming this unit", UniqueTarget.UnitActionModifier), + + // endregion + ///////////////////////////////////////// region TILE UNIQUES ///////////////////////////////////////// // Natural wonders @@ -585,12 +606,12 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags: /////// general conditionals ConditionalTimedUnique("for [amount] turns", UniqueTarget.Conditional), - ConditionalConsumeUnit("by consuming this unit", UniqueTarget.Conditional), ConditionalChance("with [amount]% chance", UniqueTarget.Conditional), - ConditionalBeforeTurns("before [amount] turns", UniqueTarget.Conditional), + ConditionalAfterTurns("after [amount] turns", UniqueTarget.Conditional), + /////// civ conditionals ConditionalWar("when at war", UniqueTarget.Conditional), ConditionalNotWar("when not at war", UniqueTarget.Conditional), diff --git a/core/src/com/unciv/ui/screens/worldscreen/unit/actions/UnitActions.kt b/core/src/com/unciv/ui/screens/worldscreen/unit/actions/UnitActions.kt index f30b99d1b0..557a67ddb8 100644 --- a/core/src/com/unciv/ui/screens/worldscreen/unit/actions/UnitActions.kt +++ b/core/src/com/unciv/ui/screens/worldscreen/unit/actions/UnitActions.kt @@ -21,13 +21,11 @@ import com.unciv.models.ruleset.unique.StateForConditionals import com.unciv.models.ruleset.unique.UniqueTriggerActivation import com.unciv.models.ruleset.unique.UniqueType import com.unciv.models.translations.tr -import com.unciv.ui.screens.pickerscreens.ImprovementPickerScreen -import com.unciv.ui.screens.pickerscreens.PromotionPickerScreen +import com.unciv.ui.components.Fonts import com.unciv.ui.popups.ConfirmPopup import com.unciv.ui.popups.hasOpenPopups -import com.unciv.ui.components.Fonts -import com.unciv.ui.screens.worldscreen.WorldScreen -import com.unciv.ui.screens.worldscreen.unit.UnitTable +import com.unciv.ui.screens.pickerscreens.ImprovementPickerScreen +import com.unciv.ui.screens.pickerscreens.PromotionPickerScreen object UnitActions { @@ -52,8 +50,13 @@ object UnitActions { addPromoteAction(unit, actionList) UnitActionsUpgrade.addUnitUpgradeAction(unit, actionList) - addTransformAction(unit, actionList) UnitActionsPillage.addPillageAction(unit, actionList) + addExplorationActions(unit, actionList) + addWaitAction(unit, actionList) + addToggleActionsAction(unit, actionList) + + // Determined by unit uniques + addTransformAction(unit, actionList) addParadropAction(unit, actionList) addAirSweepAction(unit, actionList) addSetupAction(unit, actionList) @@ -66,15 +69,10 @@ object UnitActions { UnitActionsReligion.addEnhanceReligionAction(unit, actionList) actionList += getImprovementConstructionActions(unit, tile) UnitActionsReligion.addActionsWithLimitedUses(unit, actionList, tile) - addExplorationActions(unit, actionList) addAutomateBuildingImprovementsAction(unit, actionList) addTriggerUniqueActions(unit, actionList) addAddInCapitalAction(unit, actionList, tile) - addWaitAction(unit, actionList) - - addToggleActionsAction(unit, actionList) - return actionList } diff --git a/desktop/src/com/unciv/app/desktop/UniqueDocsWriter.kt b/desktop/src/com/unciv/app/desktop/UniqueDocsWriter.kt index 8545489d1b..f3d636f90d 100644 --- a/desktop/src/com/unciv/app/desktop/UniqueDocsWriter.kt +++ b/desktop/src/com/unciv/app/desktop/UniqueDocsWriter.kt @@ -57,7 +57,8 @@ class UniqueDocsWriter { lines += "# Uniques" lines += "Simple unique parameters are explained by mouseover. Complex parameters are explained in [Unique parameter types](../Unique-parameters)" - val conditionalLikeUniqueTargets = setOf(UniqueTarget.Conditional, UniqueTarget.TriggerCondition, UniqueTarget.UnitTriggerCondition) + val conditionalLikeUniqueTargets = setOf(UniqueTarget.Conditional, UniqueTarget.TriggerCondition, + UniqueTarget.UnitTriggerCondition, UniqueTarget.UnitActionModifier) for ((targetType, uniqueTypes) in targetTypesToUniques) { if (uniqueTypes.isEmpty()) continue diff --git a/docs/Modders/uniques.md b/docs/Modders/uniques.md index 8a698368d3..e6ee0cd964 100644 --- a/docs/Modders/uniques.md +++ b/docs/Modders/uniques.md @@ -1052,6 +1052,60 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl ??? example "May create improvements on water resources" Applicable to: Unit +??? example "May found a religion" + Applicable to: Unit + +??? example "May enhance a religion" + Applicable to: Unit + +??? example "Can start an [amount]-turn golden age" + Example: "Can start an [3]-turn golden age" + + Applicable to: Unit + +??? example "Can be added to [comment] in the Capital" + Example: "Can be added to [comment] in the Capital" + + Applicable to: Unit + +??? example "Prevents spreading of religion to the city it is next to" + Applicable to: Unit + +??? example "Removes other religions when spreading religion" + Applicable to: Unit + +??? example "May Paradrop up to [amount] tiles from inside friendly territory" + Example: "May Paradrop up to [3] tiles from inside friendly territory" + + Applicable to: Unit + +??? example "Can perform Air Sweep" + Applicable to: Unit + +??? example "Can [action] [amount] times" + Example: "Can [Spread Religion] [3] times" + + Applicable to: Unit + +??? example "Can speed up construction of a building" + Applicable to: Unit + +??? example "Can speed up the construction of a wonder" + Applicable to: Unit + +??? example "Can hurry technology research" + Applicable to: Unit + +??? example "Can undertake a trade mission with City-State, giving a large sum of gold and [amount] Influence" + Example: "Can undertake a trade mission with City-State, giving a large sum of gold and [3] Influence" + + Applicable to: Unit + +??? example "Can transform to [unit]" + Example: "Can transform to [Musketman]" + + Applicable to: Unit + ??? example "[relativeAmount]% Strength for enemy [combatantFilter] units in adjacent [tileFilter] tiles" Example: "[+20]% Strength for enemy [City] units in adjacent [Farm] tiles" @@ -1067,12 +1121,6 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl Applicable to: Unit -??? example "May found a religion" - Applicable to: Unit - -??? example "May enhance a religion" - Applicable to: Unit - ??? example "Can only attack [combatantFilter] units" Example: "Can only attack [City] units" @@ -1092,6 +1140,15 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl ??? example "Self-destructs when attacking" Applicable to: Unit +??? example "Eliminates combat penalty for attacking across a coast" + Applicable to: Unit + +??? example "May attack when embarked" + Applicable to: Unit + +??? example "Eliminates combat penalty for attacking over a river" + Applicable to: Unit + ??? example "Blast radius [amount]" Example: "Blast radius [3]" @@ -1127,11 +1184,6 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl ??? example "Can move immediately once bought" Applicable to: Unit -??? example "May Paradrop up to [amount] tiles from inside friendly territory" - Example: "May Paradrop up to [3] tiles from inside friendly territory" - - Applicable to: Unit - ??? example "Unit will heal every turn, even if it performs an action" Applicable to: Unit @@ -1140,15 +1192,6 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl Applicable to: Unit -??? example "Eliminates combat penalty for attacking across a coast" - Applicable to: Unit - -??? example "May attack when embarked" - Applicable to: Unit - -??? example "Eliminates combat penalty for attacking over a river" - Applicable to: Unit - ??? example "No Sight" Applicable to: Unit @@ -1198,9 +1241,6 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl Applicable to: Unit -??? example "Can perform Air Sweep" - Applicable to: Unit - ??? example "[relativeAmount]% Strength when performing Air Sweep" Example: "[+20]% Strength when performing Air Sweep" @@ -1273,14 +1313,7 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl ??? example "Religious Unit" Applicable to: Unit -??? example "Can be added to [comment] in the Capital" - Example: "Can be added to [comment] in the Capital" - - Applicable to: Unit - -??? example "Can start an [amount]-turn golden age" - Example: "Can start an [3]-turn golden age" - +??? example "Takes your religion over the one in their birth city" Applicable to: Unit ??? example "Great Person - [comment]" @@ -1288,39 +1321,6 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl Applicable to: Unit -??? example "Prevents spreading of religion to the city it is next to" - Applicable to: Unit - -??? example "Takes your religion over the one in their birth city" - Applicable to: Unit - -??? example "Removes other religions when spreading religion" - Applicable to: Unit - -??? example "Can [action] [amount] times" - Example: "Can [Spread Religion] [3] times" - - Applicable to: Unit - -??? example "Can speed up construction of a building" - Applicable to: Unit - -??? example "Can speed up the construction of a wonder" - Applicable to: Unit - -??? example "Can hurry technology research" - Applicable to: Unit - -??? example "Can undertake a trade mission with City-State, giving a large sum of gold and [amount] Influence" - Example: "Can undertake a trade mission with City-State, giving a large sum of gold and [3] Influence" - - Applicable to: Unit - -??? example "Can transform to [unit]" - Example: "Can transform to [Musketman]" - - Applicable to: Unit - ## Promotion uniques ??? example "Doing so will consume this opportunity to choose a Promotion" Applicable to: Promotion @@ -1649,9 +1649,6 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl Applicable to: Conditional -??? example "<by consuming this unit>" - Applicable to: Conditional - ??? example "<with [amount]% chance>" Example: "<with [3]% chance>" @@ -1977,6 +1974,10 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl Applicable to: UnitTriggerCondition +## UnitActionModifier uniques +??? example "<by consuming this unit>" + Applicable to: UnitActionModifier + *[action]: An action that a unit can perform. Currently, there are only two actions part of this: 'Spread Religion' and 'Remove Foreign religions from your own cities' *[amount]: This indicates a whole number, possibly with a + or - sign, such as `2`, `+13`, or `-3`.