This commit is contained in:
Yair Morgenstern 2021-07-09 11:01:40 +03:00
commit df7bba02a1
19 changed files with 828 additions and 699 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -263,485 +263,492 @@ Great Merchant
orig: 100, 100
offset: 0, 0
index: -1
Great Scientist
Great Prophet
rotate: false
xy: 112, 112
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Great War Bomber
Great Scientist
rotate: false
xy: 220, 220
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Great War Infantry
Great War Bomber
rotate: false
xy: 328, 328
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Guided Missile
Great War Infantry
rotate: false
xy: 436, 436
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Helicopter Gunship
Guided Missile
rotate: false
xy: 544, 544
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Hoplite
Helicopter Gunship
rotate: false
xy: 652, 652
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Horse Archer
Hoplite
rotate: false
xy: 760, 766
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Horseman
Horse Archer
rotate: false
xy: 868, 868
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Hwach'a
Horseman
rotate: false
xy: 112, 4
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Infantry
Hwach'a
rotate: false
xy: 220, 112
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Ironclad
Infantry
rotate: false
xy: 328, 220
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Jaguar
Ironclad
rotate: false
xy: 436, 328
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Janissary
Jaguar
rotate: false
xy: 544, 436
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Jet Fighter
Janissary
rotate: false
xy: 652, 544
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Keshik
Jet Fighter
rotate: false
xy: 760, 658
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Khan
Keshik
rotate: false
xy: 868, 760
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Knight
Khan
rotate: false
xy: 976, 868
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Lancer
Knight
rotate: false
xy: 220, 4
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Landship
Lancer
rotate: false
xy: 328, 112
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Landsknecht
Landship
rotate: false
xy: 436, 220
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Legion
Landsknecht
rotate: false
xy: 544, 328
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Longbowman
Legion
rotate: false
xy: 652, 436
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Longswordsman
Longbowman
rotate: false
xy: 760, 550
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Machine Gun
Longswordsman
rotate: false
xy: 868, 652
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Mandekalu Cavalry
Machine Gun
rotate: false
xy: 976, 760
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Maori Warrior
Mandekalu Cavalry
rotate: false
xy: 1084, 868
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Marine
Maori Warrior
rotate: false
xy: 328, 4
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Mechanized Infantry
Marine
rotate: false
xy: 436, 112
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Minuteman
Mechanized Infantry
rotate: false
xy: 544, 220
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Missile Cruiser
Minuteman
rotate: false
xy: 652, 328
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Mobile SAM
Missile Cruiser
rotate: false
xy: 760, 442
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Modern Armor
Mobile SAM
rotate: false
xy: 868, 544
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Mohawk Warrior
Modern Armor
rotate: false
xy: 976, 652
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Musketeer
Mohawk Warrior
rotate: false
xy: 1084, 760
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Musketeer
rotate: false
xy: 1192, 868
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Musketman
rotate: false
xy: 1192, 869
xy: 436, 5
size: 100, 99
orig: 100, 99
offset: 0, 0
index: -1
Naresuan's Elephant
rotate: false
xy: 436, 4
xy: 544, 112
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Norwegian Ski Infantry
rotate: false
xy: 544, 112
xy: 652, 220
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Nuclear Missile
rotate: false
xy: 652, 220
xy: 760, 334
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Nuclear Submarine
rotate: false
xy: 760, 334
xy: 868, 436
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Panzer
rotate: false
xy: 868, 436
xy: 976, 544
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Paratrooper
rotate: false
xy: 976, 544
xy: 1084, 652
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Persian Immortal
rotate: false
xy: 1084, 652
xy: 1192, 760
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Pikeman
rotate: false
xy: 1192, 761
xy: 1300, 868
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Privateer
rotate: false
xy: 1300, 868
xy: 652, 112
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Rifleman
rotate: false
xy: 544, 4
xy: 760, 226
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Rocket Artillery
rotate: false
xy: 652, 112
xy: 868, 328
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Samurai
rotate: false
xy: 760, 226
xy: 976, 436
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Scout
rotate: false
xy: 868, 328
xy: 1084, 544
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Sea Beggar
rotate: false
xy: 976, 436
xy: 1192, 652
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Settler
rotate: false
xy: 1084, 544
xy: 1300, 760
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Ship of the Line
rotate: false
xy: 1192, 653
xy: 1408, 868
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Sipahi
rotate: false
xy: 1300, 760
xy: 760, 118
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Slinger
rotate: false
xy: 1408, 868
xy: 868, 220
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Spearman
rotate: false
xy: 652, 4
xy: 976, 328
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Stealth Bomber
rotate: false
xy: 760, 118
xy: 1084, 436
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Submarine
rotate: false
xy: 868, 220
xy: 1192, 544
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Swordsman
rotate: false
xy: 976, 328
xy: 1300, 652
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Tank
rotate: false
xy: 1084, 436
xy: 1408, 760
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Tercio
rotate: false
xy: 1192, 545
xy: 1516, 868
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Trebuchet
rotate: false
xy: 1300, 652
xy: 976, 220
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Triplane
rotate: false
xy: 1408, 760
xy: 1084, 328
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Trireme
rotate: false
xy: 1516, 867
xy: 1192, 435
size: 100, 101
orig: 100, 101
offset: 0, 0
index: -1
Turtle Ship
rotate: false
xy: 760, 10
xy: 1300, 544
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
War Chariot
rotate: false
xy: 868, 112
xy: 1408, 652
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
War Elephant
rotate: false
xy: 976, 220
xy: 1516, 760
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Warrior
rotate: false
xy: 1084, 328
xy: 1624, 868
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Work Boats
rotate: false
xy: 1192, 437
xy: 1084, 220
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Worker
rotate: false
xy: 1300, 544
xy: 1192, 327
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
Zero
rotate: false
xy: 1408, 652
xy: 1300, 436
size: 100, 100
orig: 100, 100
offset: 0, 0

Binary file not shown.

Before

Width:  |  Height:  |  Size: 334 KiB

After

Width:  |  Height:  |  Size: 337 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

View File

@ -189,6 +189,11 @@
"gold": 4,
"uniques": ["Great Improvement", "[+1 Gold] once [Economics] is discovered"]
},
{
"name": "Holy site",
"faith": 6,
"uniques": ["Great Improvement"]
},
{
"name": "Citadel",
"uniques": ["Gives a defensive bonus of [100]%", "Deal 30 damage to adjacent enemy units", "Great Improvement", "Can be built just outside your borders"],

View File

@ -1472,6 +1472,12 @@
"uniques": ["Can speed up construction of a wonder", "Can construct [Manufactory]", "Great Person - [Production]", "Unbuildable"],
"movement": 2
},
{
"name": "Great Prophet",
"unitType": "Civilian",
"uniques": ["Can construct [Holy site] if it hasn't spread religion yet", "Can spread religion [4] times","Great Person - [Faith]", "Unbuildable"],
"movement": 2
},
{
"name": "Great General",
"unitType": "Civilian",

View File

@ -714,6 +714,8 @@ Hurry Research = Versnel Onderzoek
Conduct Trade Mission = Voer handelsmissie uit
Your trade mission to [civName] has earned you [goldAmount] gold and [influenceAmount] influence! = Jouw handelsmissie naar [civName] heeft je [goldAmount] goud en [influenceAmount] invloed opgeleverd!
Hurry Wonder = Versnel Wonder
Spread Religion = Verkondig Religie
Spread [religionName] = Verkondig [religionName]
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.
You have entered the [newEra]! = Jij bent in het/de [newEra] aangekomen!
[civName] has entered the [eraName]! = [civName] is aangekomen in de [eraName]!

View File

@ -674,6 +674,8 @@ Hurry Research =
Conduct Trade Mission =
Your trade mission to [civName] has earned you [goldAmount] gold and [influenceAmount] influence! =
Hurry Wonder =
Spread Religion =
Spread [religionName] =
Your citizens have been happy with your rule for so long that the empire enters a Golden Age! =
You have entered the [newEra]! =
[civName] has entered the [eraName]! =

View File

@ -505,6 +505,7 @@ class CivilizationInfo {
if (cities.isNotEmpty()) { //if no city available, addGreatPerson will throw exception
val greatPerson = greatPeople.getNewGreatPerson()
if (greatPerson != null && gameInfo.ruleSet.units.containsKey(greatPerson)) addUnit(greatPerson)
religionManager.startTurn()
}
updateViewableTiles() // adds explored tiles so that the units will be able to perform automated actions better
@ -654,16 +655,18 @@ class CivilizationInfo {
notifications.add(Notification(text, arrayList, action))
}
fun addUnit(unitName: String, city: CityInfo? = null) {
if (cities.isEmpty()) return
fun addUnit(unitName: String, city: CityInfo? = null): MapUnit? {
if (cities.isEmpty()) return null
val cityToAddTo = city ?: cities.random()
if (!gameInfo.ruleSet.units.containsKey(unitName)) return
if (!gameInfo.ruleSet.units.containsKey(unitName)) return null
val unit = getEquivalentUnit(unitName)
// silently bail if no tile to place the unit is found
val placedUnit = placeUnitNearTile(cityToAddTo.location, unit.name)
if (placedUnit != null && unit.isGreatPerson()) {
// silently bail if no tile to place the unit is found
if (placedUnit == null) return null
if (unit.isGreatPerson()) {
addNotification("A [${unit.name}] has been born in [${cityToAddTo.name}]!", placedUnit.getTile().position, unit.name)
}
return placedUnit
}
/** Tries to place the a [unitName] unit into the [TileInfo] closest to the given the [position]

View File

@ -1,7 +1,7 @@
package com.unciv.logic.civilization
import com.unciv.models.ruleset.Belief
import com.unciv.models.ruleset.Unique
import kotlin.random.Random
class ReligionManager {
@Transient
@ -11,6 +11,33 @@ class ReligionManager {
var pantheonBelief: String? = null
var greatProphetsEarned = 0
fun clone(): ReligionManager {
val clone = ReligionManager()
clone.pantheonBelief = pantheonBelief
clone.storedFaith = storedFaith
return clone
}
fun startTurn() {
if (canGenerateProphet()) {
val prophetSpawnChange = (5f + storedFaith - faithForNextGreatProphet()) / 100f
if (Random(civInfo.gameInfo.turns).nextFloat() < prophetSpawnChange) {
val birthCity = civInfo.cities.filter { it.religion.getMajorityReligion() == pantheonBelief }.random()
val prophet = civInfo.addUnit("Great Prophet", birthCity)
if (prophet == null) return
prophet.religion = pantheonBelief
prophet.abilityUsedCount["Religion Spread"] = 0
storedFaith -= faithForNextGreatProphet()
}
}
}
fun endTurn(faithFromNewTurn: Int) {
storedFaith += faithFromNewTurn
}
private fun faithForPantheon() = 10 + civInfo.gameInfo.civilizations.count { it.isMajorCiv() && it.religionManager.pantheonBelief != null } * 5
fun canFoundPantheon(): Boolean {
@ -28,21 +55,24 @@ class ReligionManager {
return true
}
fun endTurn(faithFromNewTurn: Int) {
storedFaith += faithFromNewTurn
}
fun choosePantheonBelief(belief: Belief){
storedFaith -= faithForPantheon()
pantheonBelief = belief.name
// This should later be changed when religions can have multiple beliefs
civInfo.getCapital().religion[belief.name] = 100 // Capital is religious, other cities are not
}
fun clone(): ReligionManager {
val clone = ReligionManager()
clone.pantheonBelief = pantheonBelief
clone.storedFaith = storedFaith
return clone
// https://www.reddit.com/r/civ/comments/2m82wu/can_anyone_detail_the_finer_points_of_great/
// Game files (globaldefines.xml)
fun faithForNextGreatProphet() = ((200 + 100 * greatProphetsEarned * (greatProphetsEarned + 1)/2) * civInfo.gameInfo.gameParameters.gameSpeed.modifier).toInt()
fun canGenerateProphet(): Boolean {
if (pantheonBelief == null) return false // First get a pantheon, then we'll talk about a real religion
if (storedFaith < faithForNextGreatProphet()) return false
// In the base game, great prophets shouldn't generate anymore starting from the industrial era
// This is difficult to implement in the current codebase, probably requires an additional variable in eras.json
// Also only if you either [have founded a religion] or [the max amount of religions (players/2 + 1) has not been reached].
// As this is yet to be implemented, this function does almost nothing
return true
}
}

View File

@ -13,6 +13,7 @@ import com.unciv.models.ruleset.Unique
import com.unciv.models.ruleset.tile.TileImprovement
import com.unciv.models.ruleset.unit.BaseUnit
import com.unciv.models.ruleset.unit.UnitType
import com.unciv.models.translations.getPlaceholderParameters
import java.text.DecimalFormat
import kotlin.math.pow
import kotlin.random.Random
@ -92,8 +93,10 @@ class MapUnit {
* Name which should be displayed in UI
*/
fun displayName(): String {
return if (instanceName == null) name
else "$instanceName ({$name})"
val name = if (instanceName == null) name
else "$instanceName (${name})"
return if (religion != null && maxReligionSpreads() > 0) "$name ($religion)"
else name
}
var currentMovement: Float = 0f
@ -105,6 +108,9 @@ class MapUnit {
var promotions = UnitPromotions()
var due: Boolean = true
var isTransported: Boolean = false
var abilityUsedCount: HashMap<String, Int> = hashMapOf()
var religion: String? = null
companion object {
private const val ANCIENT_RUIN_MAP_REVEAL_OFFSET = 4
@ -126,6 +132,8 @@ class MapUnit {
toReturn.attacksThisTurn = attacksThisTurn
toReturn.promotions = promotions.clone()
toReturn.isTransported = isTransported
toReturn.abilityUsedCount.putAll(abilityUsedCount)
toReturn.religion = religion
return toReturn
}
@ -975,6 +983,16 @@ class MapUnit {
val matchingUniques = getMatchingUniques(Constants.canBuildImprovements)
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 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}"
}
//endregion
}

View File

@ -30,6 +30,7 @@ enum class UnitActionType(val value: String) {
ConstructRoad("Construct road"),
//
Create("Create"),
SpreadReligion("Spread Religion"),
HurryResearch("Hurry Research"),
StartGoldenAge("Start Golden Age"),
HurryWonder("Hurry Wonder"),

View File

@ -42,6 +42,10 @@ class CityStatsTable(val cityScreen: CityScreen): Table() {
addText()
innerTable.addSeparator()
innerTable.add(SpecialistAllocationTable(cityScreen).apply { update() })
if (cityInfo.civInfo.gameInfo.hasReligionEnabled()) {
innerTable.addSeparator()
addReligionInfo()
}
pack()
}
@ -78,4 +82,11 @@ class CityStatsTable(val cityScreen: CityScreen): Table() {
if (cityInfo.isInResistance())
innerTable.add("In resistance for another [${cityInfo.resistanceCounter}] turns".toLabel()).row()
}
private fun addReligionInfo() {
// This will later become large enough to be its own class, but for now it is small enough to fit inside a single function
val majorityReligion = cityInfo.religion.getMajorityReligion()
val label = majorityReligion ?: "None"
innerTable.add("Majority Religion: $label".toLabel())
}
}

View File

@ -63,6 +63,7 @@ object UnitActions {
//
addCreateWaterImprovements(unit, actionList)
addGreatPersonActions(unit, actionList, tile)
addSpreadReligionActions(unit, actionList, tile)
actionList += getImprovementConstructionActions(unit, tile)
addDisbandAction(actionList, unit, worldScreen)
@ -423,9 +424,34 @@ object UnitActions {
}
}
private fun addSpreadReligionActions(unit: MapUnit, actionList: ArrayList<UnitAction>, tile: TileInfo) {
if (!unit.hasUnique("Can spread religion [] times")) return
if (unit.religion == null) return
val maxReligionSpreads = unit.maxReligionSpreads()
if (!unit.abilityUsedCount.containsKey("Religion Spread")) return // This should be impossible anways, but just in case
if (maxReligionSpreads <= unit.abilityUsedCount["Religion Spread"]!!) return
val city = tile.getCity()
actionList += UnitAction(UnitActionType.SpreadReligion,
title = "Spread [${unit.religion!!}]",
uncivSound = UncivSound.Choir,
action = {
unit.abilityUsedCount["Religion Spread"] = unit.abilityUsedCount["Religion Spread"]!! + 1
city!!.religion[unit.religion!!] = 100
unit.currentMovement = 0f
if (unit.abilityUsedCount["Religion Spread"] == maxReligionSpreads) {
addGoldPerGreatPersonUsage(unit.civInfo)
unit.destroy()
}
}.takeIf { unit.currentMovement > 0 && city != null && city.civInfo == unit.civInfo } // For now you can only convert your own cities
)
}
fun getImprovementConstructionActions(unit: MapUnit, tile: TileInfo): ArrayList<UnitAction> {
val finalActions = ArrayList<UnitAction>()
for (unique in unit.getMatchingUniques("Can construct []")) {
var uniquesToCheck = unit.getMatchingUniques("Can construct []")
if (unit.abilityUsedCount.containsKey("Religion Spread") && unit.abilityUsedCount["Religion Spread"]!! == 0 && unit.maxReligionSpreads() > 0)
uniquesToCheck += unit.getMatchingUniques("Can construct [] if it hasn't spread religion yet")
for (unique in uniquesToCheck) {
val improvementName = unique.params[0]
val improvement = tile.ruleset.tileImprovements[improvementName]
if (improvement == null) continue

View File

@ -35,6 +35,10 @@ class UnitActionsTable(val worldScreen: WorldScreen) : Table() {
val improvementName = unitAction.getPlaceholderParameters()[0]
return UnitIconAndKey(ImageGetter.getImprovementIcon(improvementName), 'i')
}
unitAction.equalsPlaceholderText("Spread []") -> {
// This should later include icons for the different religions. For now, just use the great prophet icon
return UnitIconAndKey(ImageGetter.getUnitIcon("Great Prophet"), 'g')
}
unitAction.startsWith("Sleep") -> return UnitIconAndKey(ImageGetter.getImage("OtherIcons/Sleep"), 'f')
unitAction.startsWith("Fortify") -> return UnitIconAndKey(ImageGetter.getImage("OtherIcons/Shield").apply { color = Color.BLACK }, 'f')
else -> when (unitAction) {

View File

@ -159,6 +159,11 @@ class UnitTable(val worldScreen: WorldScreen) : Table(){
unitDescriptionTable.add("XP")
unitDescriptionTable.add(unit.promotions.XP.toString() + "/" + unit.promotions.xpForNextPromotion())
}
if (unit.maxReligionSpreads() > 0) {
unitDescriptionTable.add(ImageGetter.getStatIcon("Faith")).size(20f)
unitDescriptionTable.add(unit.getReligionString())
}
if (unit.promotions.promotions.size != promotionsTable.children.size) // The unit has been promoted! Reload promotions!
selectedUnitHasChanged = true

View File

@ -128,6 +128,7 @@ Unless otherwise specified, all the following are from [the Noun Project](https:
* [Pallet](https://thenounproject.com/search/?q=Pallet&i=6862) By James Keuning for Great Artist
* [Gear](https://thenounproject.com/search/?q=Gear&i=17369) By Melvin Salas for Great Engineer
* [Beaker](https://thenounproject.com/search/?q=Beaker&i=621510) By Delwar Hossain for Great Scientist
* [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
## Resources
@ -183,6 +184,7 @@ Unless otherwise specified, all the following are from [the Noun Project](https:
### Ancient Era
* [Storehouse](https://thenounproject.com/term/storehouse/966786/) By Pedro Santos for Granary
* [Shinto Gate](https://thenounproject.com/search/?q=shrine&i=253325) by Alexander Skowalsky for Shrine
* [Great Wall Of China](https://thenounproject.com/term/great-wall-of-china/146039/) By Arthur Shlain for Walls
* [Markadan Tower](https://thenounproject.com/search/?q=fortification&i=2107694) by Vectors Market for Walls of Babylon
* [Block](https://thenounproject.com/term/block/1711553/) By Monjin Friends for Stone Works