Implemented Inquisitors (#4909)
* Added inquisitor unit including image * Inquisitor now blocks spreading of religions * Added 'remove heresy' action * Fixed tests * Reworded remove heresy unique, updated sprites * Fix Crash * Implemented requested changes & fixed a few minor bugs * Implemented requested changes
BIN
android/Images/OtherIcons/Remove Heresy.png
Normal file
After Width: | Height: | Size: 4.0 KiB |
BIN
android/ImagesToPackSeparately/UnitIcons/Inquisitor.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
@ -354,422 +354,429 @@ Infantry
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Ironclad
|
||||
Inquisitor
|
||||
rotate: false
|
||||
xy: 760, 646
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Jaguar
|
||||
Ironclad
|
||||
rotate: false
|
||||
xy: 868, 754
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Janissary
|
||||
Jaguar
|
||||
rotate: false
|
||||
xy: 976, 862
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Jet Fighter
|
||||
Janissary
|
||||
rotate: false
|
||||
xy: 328, 106
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Keshik
|
||||
Jet Fighter
|
||||
rotate: false
|
||||
xy: 436, 214
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Khan
|
||||
Keshik
|
||||
rotate: false
|
||||
xy: 544, 322
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Knight
|
||||
Khan
|
||||
rotate: false
|
||||
xy: 652, 430
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Lancer
|
||||
Knight
|
||||
rotate: false
|
||||
xy: 760, 538
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Landship
|
||||
Lancer
|
||||
rotate: false
|
||||
xy: 868, 646
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Landsknecht
|
||||
Landship
|
||||
rotate: false
|
||||
xy: 976, 754
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Legion
|
||||
Landsknecht
|
||||
rotate: false
|
||||
xy: 1084, 862
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Longbowman
|
||||
Legion
|
||||
rotate: false
|
||||
xy: 436, 106
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Longswordsman
|
||||
Longbowman
|
||||
rotate: false
|
||||
xy: 544, 214
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Machine Gun
|
||||
Longswordsman
|
||||
rotate: false
|
||||
xy: 652, 322
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Mandekalu Cavalry
|
||||
Machine Gun
|
||||
rotate: false
|
||||
xy: 760, 430
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Maori Warrior
|
||||
Mandekalu Cavalry
|
||||
rotate: false
|
||||
xy: 868, 538
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Marine
|
||||
Maori Warrior
|
||||
rotate: false
|
||||
xy: 976, 646
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Mechanized Infantry
|
||||
Marine
|
||||
rotate: false
|
||||
xy: 1084, 754
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Minuteman
|
||||
Mechanized Infantry
|
||||
rotate: false
|
||||
xy: 1192, 862
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Missile Cruiser
|
||||
Minuteman
|
||||
rotate: false
|
||||
xy: 544, 106
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Missionary
|
||||
Missile Cruiser
|
||||
rotate: false
|
||||
xy: 652, 214
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Mobile SAM
|
||||
Missionary
|
||||
rotate: false
|
||||
xy: 760, 322
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Modern Armor
|
||||
Mobile SAM
|
||||
rotate: false
|
||||
xy: 868, 430
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Mohawk Warrior
|
||||
Modern Armor
|
||||
rotate: false
|
||||
xy: 976, 538
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Musketeer
|
||||
Mohawk Warrior
|
||||
rotate: false
|
||||
xy: 1084, 646
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Musketeer
|
||||
rotate: false
|
||||
xy: 1192, 754
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Musketman
|
||||
rotate: false
|
||||
xy: 1192, 755
|
||||
xy: 1300, 863
|
||||
size: 100, 99
|
||||
orig: 100, 99
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Naresuan's Elephant
|
||||
rotate: false
|
||||
xy: 1300, 862
|
||||
xy: 652, 106
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Norwegian Ski Infantry
|
||||
rotate: false
|
||||
xy: 652, 106
|
||||
xy: 760, 214
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Nuclear Missile
|
||||
rotate: false
|
||||
xy: 760, 214
|
||||
xy: 868, 322
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Nuclear Submarine
|
||||
rotate: false
|
||||
xy: 868, 322
|
||||
xy: 976, 430
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Panzer
|
||||
rotate: false
|
||||
xy: 976, 430
|
||||
xy: 1084, 538
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Paratrooper
|
||||
rotate: false
|
||||
xy: 1084, 538
|
||||
xy: 1192, 646
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Persian Immortal
|
||||
rotate: false
|
||||
xy: 1192, 647
|
||||
xy: 1300, 755
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Pikeman
|
||||
rotate: false
|
||||
xy: 1300, 754
|
||||
xy: 1408, 862
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Privateer
|
||||
rotate: false
|
||||
xy: 1408, 862
|
||||
xy: 760, 106
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Rifleman
|
||||
rotate: false
|
||||
xy: 760, 106
|
||||
xy: 868, 214
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Rocket Artillery
|
||||
rotate: false
|
||||
xy: 868, 214
|
||||
xy: 976, 322
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Samurai
|
||||
rotate: false
|
||||
xy: 976, 322
|
||||
xy: 1084, 430
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Scout
|
||||
rotate: false
|
||||
xy: 1084, 430
|
||||
xy: 1192, 538
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Sea Beggar
|
||||
rotate: false
|
||||
xy: 1192, 539
|
||||
xy: 1300, 647
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Settler
|
||||
rotate: false
|
||||
xy: 1300, 646
|
||||
xy: 1408, 754
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Ship of the Line
|
||||
rotate: false
|
||||
xy: 1408, 754
|
||||
xy: 1516, 862
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Sipahi
|
||||
rotate: false
|
||||
xy: 1516, 862
|
||||
xy: 868, 106
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Slinger
|
||||
rotate: false
|
||||
xy: 868, 106
|
||||
xy: 976, 214
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Spearman
|
||||
rotate: false
|
||||
xy: 976, 214
|
||||
xy: 1084, 322
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Stealth Bomber
|
||||
rotate: false
|
||||
xy: 1084, 322
|
||||
xy: 1192, 430
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Submarine
|
||||
rotate: false
|
||||
xy: 1192, 431
|
||||
xy: 1300, 539
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Swordsman
|
||||
rotate: false
|
||||
xy: 1300, 538
|
||||
xy: 1408, 646
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Tank
|
||||
rotate: false
|
||||
xy: 1408, 646
|
||||
xy: 1516, 754
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Tercio
|
||||
rotate: false
|
||||
xy: 1516, 754
|
||||
xy: 1624, 862
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Trebuchet
|
||||
rotate: false
|
||||
xy: 1624, 862
|
||||
xy: 976, 106
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Triplane
|
||||
rotate: false
|
||||
xy: 976, 106
|
||||
xy: 1084, 214
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Trireme
|
||||
rotate: false
|
||||
xy: 1084, 213
|
||||
xy: 1192, 321
|
||||
size: 100, 101
|
||||
orig: 100, 101
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Turtle Ship
|
||||
rotate: false
|
||||
xy: 1192, 323
|
||||
xy: 1300, 431
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
War Chariot
|
||||
rotate: false
|
||||
xy: 1300, 430
|
||||
xy: 1408, 538
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
War Elephant
|
||||
rotate: false
|
||||
xy: 1408, 538
|
||||
xy: 1516, 646
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Warrior
|
||||
rotate: false
|
||||
xy: 1516, 646
|
||||
xy: 1624, 754
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Work Boats
|
||||
rotate: false
|
||||
xy: 1624, 754
|
||||
xy: 1732, 862
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Worker
|
||||
rotate: false
|
||||
xy: 1732, 862
|
||||
xy: 1084, 106
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Zero
|
||||
rotate: false
|
||||
xy: 1192, 215
|
||||
xy: 1192, 213
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
|
Before Width: | Height: | Size: 344 KiB After Width: | Height: | Size: 346 KiB |
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.1 MiB |
BIN
android/assets/game2.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
@ -1500,7 +1500,7 @@
|
||||
{
|
||||
"name": "Great Prophet",
|
||||
"unitType": "Civilian",
|
||||
"uniques": ["Can construct [Holy site] if it hasn't spread religion yet", "Can spread religion [4] times",
|
||||
"uniques": ["Can construct [Holy site] if it hasn't used other actions yet", "Can [Spread Religion] [4] times",
|
||||
"May found a religion", "May enter foreign tiles without open borders", "[-1] Visibility Range",
|
||||
"Great Person - [Faith]", "Unbuildable", "Religious Unit", "Hidden when religion is disabled"],
|
||||
"movement": 2,
|
||||
@ -1528,11 +1528,22 @@
|
||||
{
|
||||
"name": "Missionary",
|
||||
"unitType": "Civilian",
|
||||
"uniques": ["Can spread religion [2] times", "May enter foreign tiles without open borders, but loses [250] religious strength each turn it ends there",
|
||||
"uniques": ["Can [Spread Religion] [2] times", "May enter foreign tiles without open borders, but loses [250] religious strength each turn it ends there",
|
||||
"Can be purchased with [Faith] [in all cities in which the majority religion is a major religion]",
|
||||
"[-1] Visibility Range", "Unbuildable", "Religious Unit", "Hidden when religion is disabled"],
|
||||
"movement": 4,
|
||||
"religiousStrength": 1000
|
||||
},
|
||||
{
|
||||
"name": "Inquisitor",
|
||||
"unitType": "Civilian",
|
||||
"uniques": ["Prevents spreading of religion to the city it is next to",
|
||||
// ToDo: change this to an _enhanced_ religion when that is implemented
|
||||
"Can [Remove Foreign religions from your own cities] [1] times",
|
||||
"Can be purchased with [Faith] [in all cities in which the majority religion is a major religion]",
|
||||
"[+1] Visibility Range", "Hidden when religion is disabled", "Unbuildable", "Religious Unit"
|
||||
],
|
||||
"movement": 3,
|
||||
}
|
||||
|
||||
/* Spaceship Parts */
|
||||
|
@ -826,9 +826,10 @@ Your trade mission to [civName] has earned you [goldAmount] gold and [influenceA
|
||||
Hurry Wonder = Versnel Wonder
|
||||
Hurry Construction = Versnel Constructie
|
||||
Spread Religion = Verkondig Religie
|
||||
Remove Heresy = Verwijder Heidense Denkbeelden
|
||||
Spread [religionName] = Verkondig [religionName]
|
||||
Found a Religion = Begin een religie
|
||||
Your citizens have been happy with your rule for so long that the empire enters a Golden Age! = Jouw dorpelingen zijn voor zo een lange tijd blij met jouw leiderschap dat jouw rijk de Gulden Eeuw binnen gaat.
|
||||
Found a Religion = Richt een religie op
|
||||
Your citizens have been happy with your rule for so long that the empire enters a Golden Age! = Je inwoners zijn al zo lang blij met jouw leiderschap, dat jouw rijk een Gouden Eeuw binnengaat!
|
||||
You have entered the [newEra]! = Jij bent in het/de [newEra] aangekomen!
|
||||
[civName] has entered the [eraName]! = [civName] is aangekomen in de [eraName]!
|
||||
[policyBranch] policy branch unlocked! = Het/De [policyBranch] beleid is ontgrendeld!
|
||||
@ -843,7 +844,7 @@ Buildings = Gebouwen
|
||||
# terrainFilters (so for uniques like: "[stats] from [terrainFilter] tiles")
|
||||
|
||||
# Requires translation!
|
||||
All =
|
||||
All = Alle
|
||||
Water = Water
|
||||
Land = Land
|
||||
# Requires translation!
|
||||
|
@ -735,6 +735,7 @@ Hurry Construction =
|
||||
Hurry Construction (+[productionAmount]) =
|
||||
Spread Religion =
|
||||
Spread [religionName] =
|
||||
Remove Heresy =
|
||||
Found a Religion =
|
||||
Your citizens have been happy with your rule for so long that the empire enters a Golden Age! =
|
||||
You have entered the [newEra]! =
|
||||
|
BIN
android/assets/sounds/fire.mp3
Normal file
@ -9,6 +9,8 @@ object Constants {
|
||||
const val settler = "Settler"
|
||||
const val settlerUnique = "Founds a new city"
|
||||
const val eraSpecificUnit = "Era Starting Unit"
|
||||
const val spreadReligionAbilityCount = "Spread Religion"
|
||||
const val removeHeresyAbilityCount = "Remove Foreign religions from your own cities"
|
||||
const val hiddenWithoutReligionUnique = "Hidden when religion is disabled"
|
||||
const val hideFromCivilopediaUnique = "Will not be displayed in Civilopedia"
|
||||
|
||||
|
@ -444,13 +444,6 @@ object Battle {
|
||||
}
|
||||
|
||||
private fun captureCivilianUnit(attacker: ICombatant, defender: MapUnitCombatant, checkDefeat: Boolean = true) {
|
||||
// barbarians don't capture civilians
|
||||
if (attacker.getCivInfo().isBarbarian()
|
||||
|| defender.unit.hasUnique("Uncapturable")) {
|
||||
defender.takeDamage(100)
|
||||
return
|
||||
}
|
||||
|
||||
// need to save this because if the unit is captured its owner wil be overwritten
|
||||
val defenderCiv = defender.getCivInfo()
|
||||
|
||||
@ -460,21 +453,28 @@ object Battle {
|
||||
|
||||
val capturedUnitTile = capturedUnit.getTile()
|
||||
|
||||
// Apparently in Civ V, captured settlers are converted to workers.
|
||||
if (capturedUnit.name == Constants.settler) {
|
||||
capturedUnit.destroy()
|
||||
// This is so that future checks which check if a unit has been captured are caught give the right answer
|
||||
// For example, in postBattleMoveToAttackedTile
|
||||
capturedUnit.civInfo = attacker.getCivInfo()
|
||||
attacker.getCivInfo().placeUnitNearTile(capturedUnitTile.position, Constants.worker)
|
||||
} else {
|
||||
capturedUnit.civInfo.removeUnit(capturedUnit)
|
||||
capturedUnit.assignOwner(attacker.getCivInfo())
|
||||
capturedUnit.currentMovement = 0f
|
||||
// It's possible that the unit can no longer stand on the tile it was captured on.
|
||||
// For example, because it's embarked and the capturing civ cannot embark units yet.
|
||||
if (!capturedUnit.movement.canPassThrough(capturedUnitTile)) {
|
||||
capturedUnit.movement.teleportToClosestMoveableTile()
|
||||
when {
|
||||
// Uncapturable units are destroyed (units captured by barbarians also - for now)
|
||||
defender.unit.hasUnique("Uncapturable") || attacker.getCivInfo().isBarbarian() -> {
|
||||
capturedUnit.destroy()
|
||||
}
|
||||
// Captured settlers are converted to workers.
|
||||
capturedUnit.name == Constants.settler -> {
|
||||
capturedUnit.destroy()
|
||||
// This is so that future checks which check if a unit has been captured are caught give the right answer
|
||||
// For example, in postBattleMoveToAttackedTile
|
||||
capturedUnit.civInfo = attacker.getCivInfo()
|
||||
attacker.getCivInfo().placeUnitNearTile(capturedUnitTile.position, Constants.worker)
|
||||
}
|
||||
else -> {
|
||||
capturedUnit.civInfo.removeUnit(capturedUnit)
|
||||
capturedUnit.assignOwner(attacker.getCivInfo())
|
||||
capturedUnit.currentMovement = 0f
|
||||
// It's possible that the unit can no longer stand on the tile it was captured on.
|
||||
// For example, because it's embarked and the capturing civ cannot embark units yet.
|
||||
if (!capturedUnit.movement.canPassThrough(capturedUnitTile)) {
|
||||
capturedUnit.movement.teleportToClosestMoveableTile()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -683,7 +683,6 @@ class CityInfo {
|
||||
}
|
||||
fun getImprovableTiles(): Sequence<TileInfo> = getTiles()
|
||||
.filter {it.hasViewableResource(civInfo) && it.improvement == null}
|
||||
|
||||
|
||||
|
||||
//endregion
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ class CityInfoReligionManager {
|
||||
val religionsAtSomePointAdopted: HashSet<String> = hashSetOf()
|
||||
|
||||
private val pressures: Counter<String> = Counter()
|
||||
// `getNumberOfFollowers()` was called a surprisingly large amount of time, so caching it feels useful
|
||||
// Cached because using `updateNumberOfFollowers` to get this value resulted in many calls
|
||||
@Transient
|
||||
private val followers: Counter<String> = Counter()
|
||||
|
||||
@ -68,6 +68,10 @@ class CityInfoReligionManager {
|
||||
return getUniques().filter { it.placeholderText == unique }
|
||||
}
|
||||
|
||||
fun getPressures(): Counter<String> {
|
||||
return pressures.clone()
|
||||
}
|
||||
|
||||
fun clearAllPressures() {
|
||||
pressures.clear()
|
||||
// We add pressure for following no religion
|
||||
@ -85,6 +89,13 @@ class CityInfoReligionManager {
|
||||
updateNumberOfFollowers(shouldUpdateFollowers)
|
||||
}
|
||||
}
|
||||
|
||||
fun removeAllPressuresExceptFor(religion: String) {
|
||||
val pressureFromThisReligion = pressures[religion]!!
|
||||
clearAllPressures()
|
||||
pressures.add(religion, pressureFromThisReligion)
|
||||
updateNumberOfFollowers()
|
||||
}
|
||||
|
||||
fun updatePressureOnPopulationChange(populationChangeAmount: Int) {
|
||||
val majorityReligion =
|
||||
@ -204,9 +215,12 @@ class CityInfoReligionManager {
|
||||
|
||||
fun getMajorityReligionName(): String? {
|
||||
if (followers.isEmpty()) return null
|
||||
val religionWithMaxFollowers = followers.maxByOrNull { it.value }!!
|
||||
return if (religionWithMaxFollowers.value >= cityInfo.population.population / 2) religionWithMaxFollowers.key
|
||||
else null
|
||||
val religionWithMaxPressure = pressures.maxByOrNull { it.value }!!.key
|
||||
return when {
|
||||
religionWithMaxPressure == Constants.noReligionName -> null
|
||||
followers[religionWithMaxPressure]!! >= cityInfo.population.population / 2 -> religionWithMaxPressure
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
fun getMajorityReligion(): Religion? {
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.unciv.logic.civilization
|
||||
|
||||
import com.badlogic.gdx.math.Vector2
|
||||
import com.unciv.Constants
|
||||
import com.unciv.UncivGame
|
||||
import com.unciv.logic.GameInfo
|
||||
import com.unciv.logic.UncivShowableException
|
||||
@ -803,8 +804,6 @@ class CivilizationInfo {
|
||||
placedUnit.religion =
|
||||
if (city != null) city.cityConstructions.cityInfo.religion.getMajorityReligionName()
|
||||
else religionManager.religion?.name
|
||||
if (placedUnit.hasUnique("Can spread religion [] times"))
|
||||
placedUnit.abilityUsedCount["Religion Spread"] = 0
|
||||
}
|
||||
|
||||
return placedUnit
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.unciv.logic.civilization
|
||||
|
||||
import com.unciv.Constants
|
||||
import com.unciv.logic.map.MapUnit
|
||||
import com.unciv.models.Religion
|
||||
import com.unciv.models.ruleset.Belief
|
||||
@ -125,7 +126,7 @@ class ReligionManager {
|
||||
fun mayFoundReligionAtAll(prophet: MapUnit): Boolean {
|
||||
if (religion == null) return false // First found a pantheon
|
||||
if (religion!!.isMajorReligion()) return false // Already created a major religion
|
||||
if (prophet.abilityUsedCount["Religion Spread"] != 0) return false // Already used its power for other things
|
||||
if (prophet.abilityUsedCount.any { it.value != 0 }) return false // Already used its power for other things
|
||||
if (!civInfo.isMajorCiv()) return false // Only major civs may use religion
|
||||
|
||||
val foundedReligionsCount = civInfo.gameInfo.civilizations.count {
|
||||
|
@ -446,6 +446,14 @@ class MapUnit {
|
||||
promotions.setTransients(this)
|
||||
baseUnit = ruleset.units[name]
|
||||
?: throw java.lang.Exception("Unit $name is not found!")
|
||||
|
||||
// "Religion Spread" ability deprecated since 3.16.7, replaced with "Spread Religion"
|
||||
if ("Religion Spread" in abilityUsedCount) {
|
||||
abilityUsedCount[Constants.spreadReligionAbilityCount] = abilityUsedCount["Religion Spread"]!!
|
||||
abilityUsedCount.remove("Religion Spread")
|
||||
}
|
||||
//
|
||||
|
||||
updateUniques()
|
||||
}
|
||||
|
||||
@ -955,22 +963,29 @@ class MapUnit {
|
||||
return matchingUniques.any { improvement.matchesFilter(it.params[0]) || tile.matchesTerrainFilter(it.params[0]) }
|
||||
}
|
||||
|
||||
fun maxReligionSpreads(): Int {
|
||||
return getMatchingUniques("Can spread religion [] times").sumBy { it.params[0].toInt() }
|
||||
fun religiousActionsUnitCanDo(): Sequence<String> {
|
||||
return getMatchingUniques("Can [] [] times")
|
||||
.map { it.params[0] }
|
||||
}
|
||||
|
||||
fun canSpreadReligion(): Boolean {
|
||||
return hasUnique("Can spread religion [] times")
|
||||
fun canDoReligiousAction(action: String): Boolean {
|
||||
return getMatchingUniques("Can [] [] times").any { it.params[0] == action }
|
||||
}
|
||||
|
||||
|
||||
fun getMaxReligiousActionUses(action: String): Int {
|
||||
return getMatchingUniques("Can [] [] times")
|
||||
.filter { it.params[0] == action }
|
||||
.sumBy { it.params[1].toInt() }
|
||||
}
|
||||
|
||||
fun getPressureAddedFromSpread(): Int {
|
||||
return baseUnit.religiousStrength
|
||||
}
|
||||
|
||||
fun getReligionString(): String {
|
||||
val maxSpreads = maxReligionSpreads()
|
||||
if (abilityUsedCount["Religion Spread"] == null) return "" // That is, either the key doesn't exist, or it does exist and the value is null.
|
||||
return "${maxSpreads - abilityUsedCount["Religion Spread"]!!}/${maxSpreads}"
|
||||
|
||||
fun getActionString(action: String): String {
|
||||
val maxActionUses = getMaxReligiousActionUses(action)
|
||||
if (abilityUsedCount[action] == null) return "0/0" // Something went wrong
|
||||
return "${maxActionUses - abilityUsedCount[action]!!}/${maxActionUses}"
|
||||
}
|
||||
|
||||
fun actionsOnDeselect() {
|
||||
|
@ -436,6 +436,11 @@ class TileMap {
|
||||
unit.promotions.addPromotion(unique.params[1], true)
|
||||
}
|
||||
}
|
||||
|
||||
// If this unit has special abilities that need to be kept track of, start doing so here
|
||||
for (action in unit.religiousActionsUnitCanDo()) {
|
||||
unit.abilityUsedCount[action] = 0
|
||||
}
|
||||
|
||||
// And update civ stats, since the new unit changes both unit upkeep and resource consumption
|
||||
civInfo.updateStatsForNextTurn()
|
||||
|
@ -9,6 +9,7 @@ private enum class UncivSoundConstants (val value: String) {
|
||||
Chimes("chimes"),
|
||||
Coin("coin"),
|
||||
Choir("choir"),
|
||||
Fire("fire"),
|
||||
Policy("policy"),
|
||||
Paper("paper"),
|
||||
Whoosh("whoosh"),
|
||||
@ -57,6 +58,7 @@ class UncivSound private constructor (
|
||||
val Construction = UncivSound(UncivSoundConstants.Construction)
|
||||
val Swap = UncivSound(UncivSoundConstants.Swap)
|
||||
val Silent = UncivSound(UncivSoundConstants.Silent)
|
||||
val Fire = UncivSound(UncivSoundConstants.Fire)
|
||||
/** Creates an UncivSound instance for a custom sound.
|
||||
* @param filename The base filename without extension.
|
||||
*/
|
||||
|
@ -114,8 +114,6 @@ enum class UnitActionType(
|
||||
//
|
||||
Create("Create",
|
||||
null, 'i', UncivSound.Chimes),
|
||||
SpreadReligion("Spread Religion",
|
||||
null, 'g', UncivSound.Choir),
|
||||
HurryResearch("Hurry Research",
|
||||
{ ImageGetter.getUnitIcon("Great Scientist") }, 'g', UncivSound.Chimes),
|
||||
StartGoldenAge("Start Golden Age",
|
||||
@ -128,6 +126,10 @@ enum class UnitActionType(
|
||||
{ ImageGetter.getUnitIcon("Great Merchant") }, 'g', UncivSound.Chimes),
|
||||
FoundReligion("Found a Religion",
|
||||
{ ImageGetter.getUnitIcon("Great Prophet") }, 'g', UncivSound.Choir),
|
||||
SpreadReligion("Spread Religion",
|
||||
null, 'g', UncivSound.Choir),
|
||||
RemoveHeresy("Remove Heresy",
|
||||
{ ImageGetter.getImage("OtherIcons/Remove Heresy") }, 'h', UncivSound.Fire),
|
||||
DisbandUnit("Disband unit",
|
||||
{ ImageGetter.getImage("OtherIcons/DisbandUnit") }, KeyCharAndCode.DEL),
|
||||
GiftUnit("Gift unit",
|
||||
|
@ -330,8 +330,6 @@ class BaseUnit : INamed, INonPerpetualConstruction, ICivilopediaText {
|
||||
|
||||
if (unit.hasUnique("Religious Unit")) {
|
||||
unit.religion = cityConstructions.cityInfo.religion.getMajorityReligionName()
|
||||
if (unit.canSpreadReligion())
|
||||
unit.abilityUsedCount["Religion Spread"] = 0
|
||||
}
|
||||
|
||||
if (this.isCivilian()) return true // tiny optimization makes save files a few bytes smaller
|
||||
@ -340,12 +338,10 @@ class BaseUnit : INamed, INonPerpetualConstruction, ICivilopediaText {
|
||||
|
||||
|
||||
for (unique in
|
||||
// Deprecated since 3.15.9
|
||||
cityConstructions.cityInfo.getMatchingUniques("New [] units start with [] Experience") +
|
||||
//
|
||||
cityConstructions.cityInfo.getMatchingUniques("New [] units start with [] Experience []")
|
||||
.filter { cityConstructions.cityInfo.matchesFilter(it.params[2]) } +
|
||||
// Deprecated since 3.15.9
|
||||
cityConstructions.cityInfo.getMatchingUniques("New [] units start with [] Experience") +
|
||||
cityConstructions.cityInfo.getLocalMatchingUniques("New [] units start with [] Experience in this city")
|
||||
//
|
||||
) {
|
||||
|
@ -83,7 +83,7 @@ class CityStatsTable(val cityScreen: CityScreen): Table() {
|
||||
}
|
||||
|
||||
private fun addReligionInfo() {
|
||||
val label = cityInfo.religion.getMajorityReligionName()
|
||||
val label = cityInfo.religion.getMajorityReligion()?.iconName
|
||||
?: "None"
|
||||
val icon = if (label == "None") "Religion" else label
|
||||
val expanderTab =
|
||||
@ -97,7 +97,7 @@ class CityStatsTable(val cityScreen: CityScreen): Table() {
|
||||
onChange = {
|
||||
pack()
|
||||
// We have to re-anchor as our position in the city screen, otherwise it expands upwards.
|
||||
// This probably should be refactored so its placed somewhere else in due time
|
||||
// ToDo: This probably should be refactored so its placed somewhere else in due time
|
||||
setPosition(stage.width - CityScreen.posFromEdge, stage.height - CityScreen.posFromEdge, Align.topRight)
|
||||
}
|
||||
) {
|
||||
|
@ -4,6 +4,7 @@ import com.unciv.Constants
|
||||
import com.unciv.UncivGame
|
||||
import com.unciv.logic.automation.UnitAutomation
|
||||
import com.unciv.logic.automation.WorkerAutomation
|
||||
import com.unciv.logic.city.CityInfo
|
||||
import com.unciv.logic.civilization.CivilizationInfo
|
||||
import com.unciv.logic.civilization.NotificationIcon
|
||||
import com.unciv.logic.civilization.PlayerType
|
||||
@ -56,9 +57,9 @@ object UnitActions {
|
||||
addGreatPersonActions(unit, actionList, tile)
|
||||
addFoundReligionAction(unit, actionList, tile)
|
||||
actionList += getImprovementConstructionActions(unit, tile)
|
||||
addSpreadReligionActions(unit, actionList, tile)
|
||||
|
||||
addActionsWithLimitedUses(unit, actionList, tile)
|
||||
|
||||
|
||||
addToggleActionsAction(unit, actionList, unitTable)
|
||||
|
||||
return actionList
|
||||
@ -374,6 +375,7 @@ object UnitActions {
|
||||
|
||||
private fun addAutomateBuildingImprovementsAction(unit: MapUnit, actionList: ArrayList<UnitAction>) {
|
||||
if (!unit.hasUniqueToBuildImprovements) return
|
||||
if (unit.isAutomated()) return
|
||||
|
||||
actionList += UnitAction(UnitActionType.Automate,
|
||||
isCurrentAction = unit.isAutomated(),
|
||||
@ -489,37 +491,76 @@ object UnitActions {
|
||||
}.takeIf { unit.civInfo.religionManager.mayFoundReligionNow(unit) }
|
||||
)
|
||||
}
|
||||
|
||||
private fun addSpreadReligionActions(unit: MapUnit, actionList: ArrayList<UnitAction>, tile: TileInfo) {
|
||||
if (!unit.hasUnique("Can spread religion [] times")) return
|
||||
|
||||
private fun addActionsWithLimitedUses(unit: MapUnit, actionList: ArrayList<UnitAction>, tile: TileInfo) {
|
||||
val actionsToAdd = unit.religiousActionsUnitCanDo()
|
||||
if (actionsToAdd.none()) return
|
||||
if (unit.religion == null || unit.civInfo.gameInfo.religions[unit.religion]!!.isPantheon()) return
|
||||
val maxReligionSpreads = unit.maxReligionSpreads()
|
||||
if (!unit.abilityUsedCount.containsKey("Religion Spread")) return // This should be impossible anyways, but just in case
|
||||
if (maxReligionSpreads <= unit.abilityUsedCount["Religion Spread"]!!) return
|
||||
val city = tile.getCity() ?: return
|
||||
for (action in actionsToAdd) {
|
||||
if (!unit.abilityUsedCount.containsKey(action)) continue
|
||||
val maxActionUses = unit.getMaxReligiousActionUses(action)
|
||||
if (maxActionUses <= unit.abilityUsedCount[action]!!) continue
|
||||
when (action) {
|
||||
Constants.spreadReligionAbilityCount -> addSpreadReligionActions(unit, actionList, city, maxActionUses)
|
||||
Constants.removeHeresyAbilityCount -> addRemoveHeresyActions(unit, actionList, city, maxActionUses)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun useActionWithLimitedUses(unit: MapUnit, action: String, maximumUses: Int) {
|
||||
unit.abilityUsedCount[action] = unit.abilityUsedCount[action]!! + 1
|
||||
if (unit.abilityUsedCount[action] == maximumUses) {
|
||||
if (unit.isGreatPerson())
|
||||
addGoldPerGreatPersonUsage(unit.civInfo)
|
||||
unit.destroy()
|
||||
}
|
||||
}
|
||||
|
||||
private fun addSpreadReligionActions(unit: MapUnit, actionList: ArrayList<UnitAction>, city: CityInfo, maxSpreadUses: Int) {
|
||||
val blockedByInquisitor =
|
||||
city.getCenterTile()
|
||||
.getTilesInDistance(1)
|
||||
.flatMap { it.getUnits() }
|
||||
.any {
|
||||
it.hasUnique("Prevents spreading of religion to the city it is next to")
|
||||
&& it.religion != unit.religion
|
||||
}
|
||||
actionList += UnitAction(UnitActionType.SpreadReligion,
|
||||
title = "Spread [${unit.religion!!}]",
|
||||
action = {
|
||||
unit.abilityUsedCount["Religion Spread"] = unit.abilityUsedCount["Religion Spread"]!! + 1
|
||||
val followersOfOtherReligions = city.religion.getFollowersOfOtherReligionsThan(unit.religion!!)
|
||||
for (unique in unit.civInfo.getMatchingUniques("When spreading religion to a city, gain [] times the amount of followers of other religions as []")) {
|
||||
unit.civInfo.addStat(Stat.valueOf(unique.params[1]), followersOfOtherReligions * unique.params[0].toInt())
|
||||
}
|
||||
city.religion.addPressure(unit.religion!!, unit.getPressureAddedFromSpread())
|
||||
unit.currentMovement = 0f
|
||||
if (unit.abilityUsedCount["Religion Spread"] == maxReligionSpreads) {
|
||||
addGoldPerGreatPersonUsage(unit.civInfo)
|
||||
unit.destroy()
|
||||
}
|
||||
}.takeIf { unit.currentMovement > 0 }
|
||||
useActionWithLimitedUses(unit, Constants.spreadReligionAbilityCount, maxSpreadUses)
|
||||
}.takeIf { unit.currentMovement > 0 && !blockedByInquisitor }
|
||||
)
|
||||
}
|
||||
|
||||
private fun addRemoveHeresyActions(unit: MapUnit, actionList: ArrayList<UnitAction>, city: CityInfo, maxHerseyUses: Int) {
|
||||
if (city.civInfo != unit.civInfo) return
|
||||
// Only allow the action if the city actually has any foreign religion
|
||||
// This will almost be always due to pressure from cities close-by
|
||||
if (city.religion.getPressures().none { it.key != unit.religion!! }) return
|
||||
actionList += UnitAction(UnitActionType.RemoveHeresy,
|
||||
title = "Remove Heresy",
|
||||
action = {
|
||||
city.religion.removeAllPressuresExceptFor(unit.religion!!)
|
||||
unit.currentMovement = 0f
|
||||
useActionWithLimitedUses(unit, Constants.removeHeresyAbilityCount, maxHerseyUses)
|
||||
}.takeIf { unit.currentMovement > 0f }
|
||||
)
|
||||
}
|
||||
|
||||
fun getImprovementConstructionActions(unit: MapUnit, tile: TileInfo): ArrayList<UnitAction> {
|
||||
val finalActions = ArrayList<UnitAction>()
|
||||
var uniquesToCheck = unit.getMatchingUniques("Can construct []")
|
||||
if (unit.abilityUsedCount.containsKey("Religion Spread") && unit.abilityUsedCount["Religion Spread"]!! == 0 && unit.canSpreadReligion())
|
||||
uniquesToCheck += unit.getMatchingUniques("Can construct [] if it hasn't spread religion yet")
|
||||
if (unit.religiousActionsUnitCanDo().all { unit.abilityUsedCount[it] == 0 })
|
||||
uniquesToCheck += unit.getMatchingUniques("Can construct [] if it hasn't used other actions yet")
|
||||
|
||||
for (unique in uniquesToCheck) {
|
||||
val improvementName = unique.params[0]
|
||||
val improvement = tile.ruleset.tileImprovements[improvementName]
|
||||
|
@ -7,6 +7,7 @@ import com.badlogic.gdx.scenes.scene2d.Actor
|
||||
import com.badlogic.gdx.scenes.scene2d.Touchable
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.VerticalGroup
|
||||
import com.unciv.Constants
|
||||
import com.unciv.UncivGame
|
||||
import com.unciv.logic.battle.CityCombatant
|
||||
import com.unciv.logic.city.CityInfo
|
||||
@ -163,9 +164,14 @@ class UnitTable(val worldScreen: WorldScreen) : Table(){
|
||||
unitDescriptionTable.add(unit.promotions.XP.toString() + "/" + unit.promotions.xpForNextPromotion())
|
||||
}
|
||||
|
||||
if (unit.canSpreadReligion()) {
|
||||
if (unit.canDoReligiousAction(Constants.spreadReligionAbilityCount)) {
|
||||
unitDescriptionTable.add(ImageGetter.getStatIcon("Faith")).size(20f)
|
||||
unitDescriptionTable.add(unit.getReligionString())
|
||||
unitDescriptionTable.add(unit.getActionString(Constants.spreadReligionAbilityCount))
|
||||
}
|
||||
|
||||
if (unit.canDoReligiousAction(Constants.removeHeresyAbilityCount)) {
|
||||
unitDescriptionTable.add(ImageGetter.getImage("OtherIcons/Remove Heresy")).size(20f)
|
||||
unitDescriptionTable.add(unit.getActionString(Constants.removeHeresyAbilityCount))
|
||||
}
|
||||
|
||||
if (unit.baseUnit.religiousStrength > 0) {
|
||||
|
@ -133,6 +133,7 @@ Unless otherwise specified, all the following are from [the Noun Project](https:
|
||||
* [Dove](https://thenounproject.com/search/?q=dove&i=1344088) by sandra for Great Prophet
|
||||
* [General](https://thenounproject.com/search/?q=general&i=933566) By anbileru adaleru for Great General
|
||||
* [Religion](https://thenounproject.com/search/?q=preach&i=53064) by Bruno Gätjens González adapted for Missionary
|
||||
* [invisibility cloak ](https://thenounproject.com/term/invisibility-cloak/1419648/) by Locad for Inquisitor
|
||||
|
||||
## Resources
|
||||
|
||||
@ -614,6 +615,7 @@ Unless otherwise specified, all the following are from [the Noun Project](https:
|
||||
* [Hourglass](https://thenounproject.com/search/?q=hourglass&i=142268) by I Create Stuff for the 'Turn' icon
|
||||
* [Dove](https://thenounproject.com/search/?q=dove&i=1344084) by Sandra for Faith
|
||||
* [Shield](https://thenounproject.com/search/?q=shield&i=813568) by Gregor Cresnar for Religious Strength
|
||||
* [skill sword flame](https://thenounproject.com/term/skill-sword-flame/2360212/) by Maxicons) for Remove Heresy
|
||||
|
||||
## Main menu
|
||||
|
||||
@ -627,7 +629,7 @@ Unless otherwise specified, all the following are from [the Noun Project](https:
|
||||
|
||||
# Sound credits
|
||||
|
||||
Sounds are from FreeSound.org and are either Creative Commons or Public Domain
|
||||
Sounds are from FreeSound.org unless otherwise noted and are either Creative Commons or Public Domain unless otherwise noted
|
||||
|
||||
* [Soft two-fingered snap](https://freesound.org/people/EathanMarkson/sounds/388958/) By EathanMarkson as 'click' for most clicks
|
||||
* [Pencil1](https://freesound.org/people/stijn/sounds/43673/) By stijn as 'paper' for opening and closing the tech picker
|
||||
@ -670,6 +672,8 @@ Sounds are from FreeSound.org and are either Creative Commons or Public Domain
|
||||
* [elephant 44](https://freesound.org/people/y89312/sounds/139875/) by y89312 for Naruesan's Elephant sound
|
||||
* Excerpt from [Missile Strike](https://freesound.org/people/BaDoink/sounds/570690/) by BaDoink for guided missile
|
||||
|
||||
* Excerpt from [Campfire](https://www.soundjay.com/nature/sounds/campfire-1.mp3) by SoundJay for Fire & 'remove heresy' action of inquisitor
|
||||
|
||||
# Music
|
||||
The following music is from https://filmmusic.io
|
||||
"Thatched Villagers" by Kevin MacLeod (https://incompetech.com)
|
||||
|