mirror of
https://github.com/yairm210/Unciv.git
synced 2025-02-10 10:58:13 +07:00
Added missionairy units, which can spread religion and bought with faith (#4568)
* Added missionairy units, which can spread religion and bought with faith * Forgot an include, minor additions * Forgot credit for the missionary image * Large refactor, enabling buying with almost all stats, split IConstruction into IConstruction & INonPerpetualConstruction * Does this fix the tests * Fixed accidentally removing all trailing spaces in template.properties * Thanks to someTroglodyte for paying more attention than I do :) * Implemented requested changes * Fixed large amount of question marks * Missing space, of course * Fixed function name change * Fixed merge problems Co-authored-by: Yair Morgenstern <yairm210@hotmail.com>
This commit is contained in:
parent
ee32392ecd
commit
547f5a57e5
BIN
android/ImagesToPackSeparately/UnitIcons/Missionary.png
Normal file
BIN
android/ImagesToPackSeparately/UnitIcons/Missionary.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.0 KiB |
@ -494,275 +494,282 @@ Missile Cruiser
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Mobile SAM
|
||||
Missionary
|
||||
rotate: false
|
||||
xy: 652, 214
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Modern Armor
|
||||
Mobile SAM
|
||||
rotate: false
|
||||
xy: 760, 322
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Mohawk Warrior
|
||||
Modern Armor
|
||||
rotate: false
|
||||
xy: 868, 430
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Musketeer
|
||||
Mohawk Warrior
|
||||
rotate: false
|
||||
xy: 976, 538
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Musketeer
|
||||
rotate: false
|
||||
xy: 1084, 646
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Musketman
|
||||
rotate: false
|
||||
xy: 1084, 647
|
||||
xy: 1192, 755
|
||||
size: 100, 99
|
||||
orig: 100, 99
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Naresuan's Elephant
|
||||
rotate: false
|
||||
xy: 1192, 754
|
||||
xy: 1300, 862
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Norwegian Ski Infantry
|
||||
rotate: false
|
||||
xy: 1300, 862
|
||||
xy: 652, 106
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Nuclear Missile
|
||||
rotate: false
|
||||
xy: 652, 106
|
||||
xy: 760, 214
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Nuclear Submarine
|
||||
rotate: false
|
||||
xy: 760, 214
|
||||
xy: 868, 322
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Panzer
|
||||
rotate: false
|
||||
xy: 868, 322
|
||||
xy: 976, 430
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Paratrooper
|
||||
rotate: false
|
||||
xy: 976, 430
|
||||
xy: 1084, 538
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Persian Immortal
|
||||
rotate: false
|
||||
xy: 1084, 539
|
||||
xy: 1192, 647
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Pikeman
|
||||
rotate: false
|
||||
xy: 1192, 646
|
||||
xy: 1300, 754
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Privateer
|
||||
rotate: false
|
||||
xy: 1300, 754
|
||||
xy: 1408, 862
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Rifleman
|
||||
rotate: false
|
||||
xy: 1408, 862
|
||||
xy: 760, 106
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Rocket Artillery
|
||||
rotate: false
|
||||
xy: 760, 106
|
||||
xy: 868, 214
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Samurai
|
||||
rotate: false
|
||||
xy: 868, 214
|
||||
xy: 976, 322
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Scout
|
||||
rotate: false
|
||||
xy: 976, 322
|
||||
xy: 1084, 430
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Sea Beggar
|
||||
rotate: false
|
||||
xy: 1084, 431
|
||||
xy: 1192, 539
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Settler
|
||||
rotate: false
|
||||
xy: 1192, 538
|
||||
xy: 1300, 646
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Ship of the Line
|
||||
rotate: false
|
||||
xy: 1300, 646
|
||||
xy: 1408, 754
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Sipahi
|
||||
rotate: false
|
||||
xy: 1408, 754
|
||||
xy: 1516, 862
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Slinger
|
||||
rotate: false
|
||||
xy: 1516, 862
|
||||
xy: 868, 106
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Spearman
|
||||
rotate: false
|
||||
xy: 868, 106
|
||||
xy: 976, 214
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Stealth Bomber
|
||||
rotate: false
|
||||
xy: 976, 214
|
||||
xy: 1084, 322
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Submarine
|
||||
rotate: false
|
||||
xy: 1084, 323
|
||||
xy: 1192, 431
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Swordsman
|
||||
rotate: false
|
||||
xy: 1192, 430
|
||||
xy: 1300, 538
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Tank
|
||||
rotate: false
|
||||
xy: 1300, 538
|
||||
xy: 1408, 646
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Tercio
|
||||
rotate: false
|
||||
xy: 1408, 646
|
||||
xy: 1516, 754
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Trebuchet
|
||||
rotate: false
|
||||
xy: 1516, 754
|
||||
xy: 1624, 862
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Triplane
|
||||
rotate: false
|
||||
xy: 1624, 862
|
||||
xy: 976, 106
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Trireme
|
||||
rotate: false
|
||||
xy: 1084, 214
|
||||
xy: 1084, 213
|
||||
size: 100, 101
|
||||
orig: 100, 101
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Turtle Ship
|
||||
rotate: false
|
||||
xy: 976, 106
|
||||
xy: 1192, 323
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
War Chariot
|
||||
rotate: false
|
||||
xy: 1192, 322
|
||||
xy: 1300, 430
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
War Elephant
|
||||
rotate: false
|
||||
xy: 1300, 430
|
||||
xy: 1408, 538
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Warrior
|
||||
rotate: false
|
||||
xy: 1408, 538
|
||||
xy: 1516, 646
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Work Boats
|
||||
rotate: false
|
||||
xy: 1516, 646
|
||||
xy: 1624, 754
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Worker
|
||||
rotate: false
|
||||
xy: 1624, 754
|
||||
xy: 1732, 862
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Zero
|
||||
rotate: false
|
||||
xy: 1732, 862
|
||||
xy: 1192, 215
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 339 KiB After Width: | Height: | Size: 344 KiB |
@ -847,7 +847,7 @@
|
||||
"gold": 4,
|
||||
"greatPersonPoints": {"Great Merchant": 2},
|
||||
"isWonder": true,
|
||||
"uniques": ["Cost of purchasing items in cities reduced by [15]%"],
|
||||
"uniques": ["[Gold] cost of purchasing items in cities [-15]%"],
|
||||
"requiredTech": "Industrialization",
|
||||
"quote": "'To achieve great things, two things are needed: a plan, and not quite enough time.' - Leonard Bernstein"
|
||||
},
|
||||
|
@ -10,6 +10,7 @@
|
||||
"startingMilitaryUnitCount": 1,
|
||||
"startingMilitaryUnit": "Warrior",
|
||||
"settlerPopulation": 1,
|
||||
"baseUnitBuyCost": 200,
|
||||
"iconRGB": [255, 87, 35]
|
||||
},
|
||||
{
|
||||
@ -22,6 +23,7 @@
|
||||
"startingGold": 10,
|
||||
"startingCulture": 100,
|
||||
"settlerPopulation": 1,
|
||||
"baseUnitBuyCost": 200,
|
||||
"iconRGB": [233, 31, 99]
|
||||
},
|
||||
{
|
||||
@ -36,6 +38,7 @@
|
||||
"settlerPopulation": 1,
|
||||
"settlerBuildings": ["Shrine","Monument"],
|
||||
"startingObsoleteWonders": ["Temple of Artemis", "Stonehenge", "The Great Library", "Mausoleum of Halicarnassus", "The Pyramids", "Statue of Zeus"],
|
||||
"baseUnitBuyCost": 200,
|
||||
"iconRGB": [157, 39, 176]
|
||||
},
|
||||
{
|
||||
@ -51,6 +54,7 @@
|
||||
"settlerBuildings": ["Shrine","Monument","Granary","Lighthouse"],
|
||||
"startingObsoleteWonders": ["Temple of Artemis", "Stonehenge", "The Great Library", "Mausoleum of Halicarnassus", "The Pyramids", "Statue of Zeus",
|
||||
"The Great Lighthouse", "Hanging Gardens", "Terracotta Army", "The Oracle", "Petra", "Great Wall", "Colossus"],
|
||||
"baseUnitBuyCost": 300,
|
||||
"iconRGB": [104, 58, 183]
|
||||
},
|
||||
{
|
||||
@ -67,6 +71,7 @@
|
||||
"startingObsoleteWonders": ["Temple of Artemis", "Stonehenge", "The Great Library", "Mausoleum of Halicarnassus", "The Pyramids", "Statue of Zeus",
|
||||
"The Great Lighthouse", "Hanging Gardens", "Terracotta Army", "The Oracle", "Petra", "Great Wall", "Colossus",
|
||||
"Hagia Sophia", "Chichen Itza", "Machu Picchu", "Angkor Wat", "Alhambra", "Notre Dame"],
|
||||
"baseUnitBuyCost": 400,
|
||||
"iconRGB": [63, 81, 182]
|
||||
},
|
||||
{
|
||||
@ -84,6 +89,7 @@
|
||||
"The Great Lighthouse", "Hanging Gardens", "Terracotta Army", "The Oracle", "Petra", "Great Wall", "Colossus",
|
||||
"Hagia Sophia", "Chichen Itza", "Machu Picchu", "Angkor Wat", "Alhambra", "Notre Dame",
|
||||
"Sistine Chapel", "Forbidden Palace", "Leaning Tower of Pisa", "Himeji Castle", "Taj Mahal", "Porcelain Tower", "Kremlin"],
|
||||
"baseUnitBuyCost": 600,
|
||||
"iconRGB": [33, 150, 243]
|
||||
},
|
||||
{
|
||||
@ -102,6 +108,7 @@
|
||||
"Hagia Sophia", "Chichen Itza", "Machu Picchu", "Angkor Wat", "Alhambra", "Notre Dame",
|
||||
"Sistine Chapel", "Forbidden Palace", "Leaning Tower of Pisa", "Himeji Castle", "Taj Mahal", "Porcelain Tower", "Kremlin",
|
||||
"The Louvre", "Big Ben", "Brandenburg Gate"],
|
||||
"baseUnitBuyCost": 800,
|
||||
"iconRGB": [0, 150, 136]
|
||||
},
|
||||
{
|
||||
@ -121,6 +128,7 @@
|
||||
"Sistine Chapel", "Forbidden Palace", "Leaning Tower of Pisa", "Himeji Castle", "Taj Mahal", "Porcelain Tower", "Kremlin",
|
||||
"The Louvre", "Big Ben", "Brandenburg Gate",
|
||||
"Eiffel Tower", "Statue of Liberty", "Neuschwanstein", "Cristo Redentor"],
|
||||
"baseUnitBuyCost": 1000,
|
||||
// So theoretically this is always just all the wonders at least 2 eras old. So we could just use that.
|
||||
// But where is the modularity? The excluding of very specific wonders? That is no fun.
|
||||
// So we just write down the entire long list (sorted by era!) instead.
|
||||
@ -145,6 +153,7 @@
|
||||
"Sistine Chapel", "Forbidden Palace", "Leaning Tower of Pisa", "Himeji Castle", "Taj Mahal", "Porcelain Tower", "Kremlin",
|
||||
"The Louvre", "Big Ben", "Brandenburg Gate",
|
||||
"Eiffel Tower", "Statue of Liberty", "Neuschwanstein", "Cristo Redentor"],
|
||||
"baseUnitBuyCost": 1000,
|
||||
"iconRGB": [76, 176, 81]
|
||||
}
|
||||
]
|
@ -712,7 +712,7 @@
|
||||
"innerColor": [255, 255, 255],
|
||||
"uniqueName": "Dutch East India Company",
|
||||
"uniques": ["Retain [50]% of the happiness from a luxury after the last copy has been traded away"],
|
||||
"cities": ["Amsterdam", "Rotterdam", "Utrecht", "Groningen", "Breda", "Nijmegen", "Den Haag", "Haarlem", "Arnhem", "Zutphen", "Maastricht", "Tilburg", "Eindhoven", "Dordrecht", "Leiden", "Hertogenbosch", "Almere", "Alkmaar", "Brielle", "Vlissingen", "Apeldoorn", "Enschede", "Amersfoort", "Zwolle", "Venlo", "Uden", "Grave", "Delft", "Gouda", "Nieuwstadt", "Weesp", "Coevorden", "Kerkrade"]
|
||||
"cities": ["Amsterdam", "Rotterdam", "Utrecht", "Groningen", "Breda", "Nijmegen", "Den Haag", "Haarlem", "Arnhem", "Zutphen", "Maastricht", "Tilburg", "Eindhoven", "Dordrecht", "Leiden", "'s Hertogenbosch", "Almere", "Alkmaar", "Brielle", "Vlissingen", "Apeldoorn", "Enschede", "Amersfoort", "Zwolle", "Venlo", "Uden", "Grave", "Delft", "Gouda", "Nieuwstadt", "Weesp", "Coevorden", "Kerkrade"]
|
||||
},
|
||||
|
||||
{
|
||||
|
@ -260,7 +260,7 @@
|
||||
},
|
||||
{
|
||||
"name": "Mercantilism",
|
||||
"uniques": ["Cost of purchasing items in cities reduced by [25]%", "[+1 Science] from every [Mint]", "[+1 Science] from every [Market]",
|
||||
"uniques": ["[Gold] cost of purchasing items in cities [-25]%", "[+1 Science] from every [Mint]", "[+1 Science] from every [Market]",
|
||||
"[+1 Science] from every [Bank]", "[+1 Science] from every [Stock Exchange]"],
|
||||
"requires": ["Trade Unions"],
|
||||
"row": 2,
|
||||
@ -381,7 +381,7 @@
|
||||
},
|
||||
{
|
||||
"name": "Militarism",
|
||||
"uniques": ["Gold cost of purchasing [All] units -[33]%"],
|
||||
"uniques": ["[Gold] cost of purchasing [All] units [-33]%"],
|
||||
"row": 1,
|
||||
"column": 5
|
||||
},
|
||||
|
@ -1176,9 +1176,9 @@
|
||||
"May withdraw before melee ([80]%)", "+[100]% Strength vs [submarine units]"],
|
||||
"attackSound": "shipguns"
|
||||
},
|
||||
|
||||
|
||||
// Atomic Era
|
||||
|
||||
|
||||
{
|
||||
"name": "Marine",
|
||||
"unitType": "Gunpowder",
|
||||
@ -1375,7 +1375,7 @@
|
||||
"cost": 425,
|
||||
"requiredTech": "Computers",
|
||||
"requiredResource": "Aluminum",
|
||||
"uniques": ["+[100]% Strength vs [Armored]", "No defensive terrain bonus", "Can move after attacking",
|
||||
"uniques": ["+[100]% Strength vs [Armored]", "No defensive terrain bonus", "Can move after attacking",
|
||||
"All tiles cost 1 movement", "Unable to capture cities"],
|
||||
"attackSound": "machinegun"
|
||||
},
|
||||
@ -1390,7 +1390,7 @@
|
||||
"rangedStrength": 85,
|
||||
"cost": 425,
|
||||
"requiredTech": "Telecommunications",
|
||||
"uniques": ["+[75]% Strength when attacking", "Can only attack [Water] tiles", "Can attack submarines",
|
||||
"uniques": ["+[75]% Strength when attacking", "Can only attack [Water] tiles", "Can attack submarines",
|
||||
"[+1] Visibility Range", "Can carry [2] [Missile] units"],
|
||||
"attackSound": "torpedo"
|
||||
},
|
||||
@ -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",
|
||||
"May found a religion", "Great Person - [Faith]", "Unbuildable", "Hidden when religion is disabled"],
|
||||
"May found a religion", "Great Person - [Faith]", "Unbuildable", "Religious Unit", "Hidden when religion is disabled"],
|
||||
"movement": 2
|
||||
},
|
||||
{
|
||||
@ -1518,6 +1518,16 @@
|
||||
"uniques": ["Can start an [8]-turn golden age","Bonus for units in 2 tile radius 15%",
|
||||
"Heal adjacent units for an additional 15 HP per turn", "Can construct [Citadel]", "Great Person - [War]", "Unbuildable"],
|
||||
"movement": 5
|
||||
},
|
||||
|
||||
/* Religious units */
|
||||
|
||||
{
|
||||
"name": "Missionary",
|
||||
"unitType": "Civilian",
|
||||
"uniques": ["Can spread religion [2] times", "Can be purchased with [Faith] [in all cities in which the majority religion is a major religion]",
|
||||
"Unbuildable", "Religious Unit"],
|
||||
"movement": 4
|
||||
}
|
||||
|
||||
/* Spaceship Parts */
|
||||
|
@ -1,6 +1,6 @@
|
||||
|
||||
# Tutorial tasks
|
||||
|
||||
|
||||
# Tutorial tasks
|
||||
|
||||
Move a unit!\nClick on a unit > Click on a destination > Click the arrow popup =
|
||||
Found a city!\nSelect the Settler (flag unit) > Click on 'Found city' (bottom-left corner) =
|
||||
Enter the city screen!\nClick the city button twice =
|
||||
@ -15,24 +15,24 @@ Create a trade route!\nConstruct roads between your capital and another city\nOr
|
||||
Conquer a city!\nBring an enemy city down to low health > \nEnter the city with a melee unit =
|
||||
Move an air unit!\nSelect an air unit > select another city within range > \nMove the unit to the other city =
|
||||
See your stats breakdown!\nEnter the Overview screen (top right corner) >\nClick on 'Stats' =
|
||||
|
||||
|
||||
Oh no! It looks like something went DISASTROUSLY wrong! This is ABSOLUTELY not supposed to happen! Please send me (yairm210@hotmail.com) an email with the game information (menu -> save game -> copy game info -> paste into email) and I'll try to fix it as fast as I can! =
|
||||
Oh no! It looks like something went DISASTROUSLY wrong! This is ABSOLUTELY not supposed to happen! Please send us an report and we'll try to fix it as fast as we can! =
|
||||
|
||||
# Buildings
|
||||
|
||||
|
||||
# Buildings
|
||||
|
||||
Unsellable =
|
||||
Not displayed as an available construction unless [building] is built =
|
||||
Not displayed as an available construction without [resource] =
|
||||
|
||||
|
||||
Choose a free great person =
|
||||
Get [unitName] =
|
||||
|
||||
|
||||
Hydro Plant =
|
||||
[buildingName] obsoleted =
|
||||
|
||||
# Diplomacy,Trade,Nations
|
||||
|
||||
|
||||
# Diplomacy,Trade,Nations
|
||||
|
||||
Requires [buildingName] to be built in the city =
|
||||
Requires [buildingName] to be built in all cities =
|
||||
Provides a free [buildingName] in the city =
|
||||
@ -46,14 +46,16 @@ Cannot be built with [buildingName] =
|
||||
Consumes 1 [resource] =
|
||||
Consumes [amount] [resource] =
|
||||
Required tech: [requiredTech] =
|
||||
Requires [PolicyOrNationalWonder] =
|
||||
Requires [PolicyOrNationalWonder] =
|
||||
Cannot be purchased =
|
||||
Can only be purchased =
|
||||
See also =
|
||||
|
||||
Requires at least one of the following: =
|
||||
Requires all of the following: =
|
||||
Leads to [techName] =
|
||||
Leads to: =
|
||||
|
||||
|
||||
Current construction =
|
||||
Construction queue =
|
||||
Pick a construction =
|
||||
@ -64,7 +66,7 @@ Show stats drilldown =
|
||||
Show construction queue =
|
||||
Save =
|
||||
Cancel =
|
||||
|
||||
|
||||
Diplomacy =
|
||||
War =
|
||||
Peace =
|
||||
@ -92,7 +94,7 @@ Indeed! =
|
||||
Denounce [civName]? =
|
||||
Denounce ([numberOfTurns] turns) =
|
||||
We will remember this. =
|
||||
|
||||
|
||||
[civName] has declared war on [targetCivName]! =
|
||||
[civName] and [targetCivName] have signed a Peace Treaty! =
|
||||
[civName] and [targetCivName] have signed the Declaration of Friendship! =
|
||||
@ -100,7 +102,7 @@ We will remember this. =
|
||||
Do you want to break your promise to [leaderName]? =
|
||||
We promised not to settle near them ([count] turns remaining) =
|
||||
They promised not to settle near us ([count] turns remaining) =
|
||||
|
||||
|
||||
Unforgivable =
|
||||
Enemy =
|
||||
Competitor =
|
||||
@ -108,12 +110,12 @@ Neutral =
|
||||
Favorable =
|
||||
Friend =
|
||||
Ally =
|
||||
|
||||
|
||||
[questName] (+[influenceAmount] influence) =
|
||||
[remainingTurns] turns remaining =
|
||||
|
||||
## Diplomatic modifiers
|
||||
|
||||
|
||||
## Diplomatic modifiers
|
||||
|
||||
You declared war on us! =
|
||||
Your warmongering ways are unacceptable to us. =
|
||||
You have captured our cities! =
|
||||
@ -136,15 +138,15 @@ Your arrogant demands are in bad taste =
|
||||
Your use of nuclear weapons is disgusting! =
|
||||
You have stolen our lands! =
|
||||
You gave us units! =
|
||||
|
||||
|
||||
Demands =
|
||||
Please don't settle new cities near us. =
|
||||
Very well, we shall look for new lands to settle. =
|
||||
We shall do as we please. =
|
||||
We noticed your new city near our borders, despite your promise. This will have....implications. =
|
||||
|
||||
# City-States
|
||||
|
||||
|
||||
# City-States
|
||||
|
||||
Provides [amountOfCulture] culture at 30 Influence =
|
||||
Provides 3 food in capital and 1 food in other cities at 30 Influence =
|
||||
Provides 3 happiness at 30 Influence =
|
||||
@ -156,7 +158,7 @@ Protected by =
|
||||
Revoke Protection =
|
||||
Pledge to protect =
|
||||
Declare Protection of [cityStateName]? =
|
||||
|
||||
|
||||
Cultured =
|
||||
Maritime =
|
||||
Mercantile =
|
||||
@ -170,9 +172,9 @@ Personality =
|
||||
Influence =
|
||||
Reach 30 for friendship. =
|
||||
Reach highest influence above 60 for alliance. =
|
||||
|
||||
|
||||
# Trades
|
||||
|
||||
|
||||
Trade =
|
||||
Offer trade =
|
||||
Retract offer =
|
||||
@ -199,17 +201,17 @@ Declare war on [nation] =
|
||||
Luxury resources =
|
||||
Strategic resources =
|
||||
Owned: [amountOwned] =
|
||||
|
||||
|
||||
# Nation picker
|
||||
|
||||
|
||||
[resourceName] not required =
|
||||
Lost ability =
|
||||
National ability =
|
||||
[firstValue] vs [secondValue] =
|
||||
|
||||
|
||||
# New game screen
|
||||
|
||||
|
||||
|
||||
# New game screen
|
||||
|
||||
Uniques =
|
||||
Promotions =
|
||||
Load copied data =
|
||||
@ -240,7 +242,7 @@ Victory Conditions =
|
||||
Scientific =
|
||||
Domination =
|
||||
Cultural =
|
||||
|
||||
|
||||
Map Shape =
|
||||
Hexagonal =
|
||||
Rectangular =
|
||||
@ -248,8 +250,9 @@ Height =
|
||||
Width =
|
||||
Radius =
|
||||
Enable Religion =
|
||||
|
||||
Advanced Settings =
|
||||
|
||||
Show advanced settings =
|
||||
Hide advanced settings =
|
||||
RNG Seed =
|
||||
Map Height =
|
||||
Temperature extremeness =
|
||||
@ -260,9 +263,9 @@ Max Coast extension =
|
||||
Biome areas extension =
|
||||
Water level =
|
||||
Reset to default =
|
||||
|
||||
|
||||
Online Multiplayer =
|
||||
|
||||
|
||||
World Size =
|
||||
Tiny =
|
||||
Small =
|
||||
@ -273,9 +276,9 @@ World wrap requires a minimum width of 32 tiles =
|
||||
The provided map dimensions were too small =
|
||||
The provided map dimensions were too big =
|
||||
The provided map dimensions had an unacceptable aspect ratio =
|
||||
|
||||
|
||||
Difficulty =
|
||||
|
||||
|
||||
AI =
|
||||
Remove =
|
||||
Random =
|
||||
@ -283,14 +286,14 @@ Human =
|
||||
Hotseat =
|
||||
User ID =
|
||||
Click to copy =
|
||||
|
||||
|
||||
|
||||
|
||||
Game Speed =
|
||||
Quick =
|
||||
Standard =
|
||||
Epic =
|
||||
Marathon =
|
||||
|
||||
|
||||
Starting Era =
|
||||
It looks like we can't make a map with the parameters you requested! =
|
||||
Maybe you put too many players into too small a map? =
|
||||
@ -298,14 +301,14 @@ No human players selected! =
|
||||
Mods: =
|
||||
Base ruleset mods: =
|
||||
Extension mods: =
|
||||
|
||||
|
||||
World Wrap =
|
||||
World wrap maps are very memory intensive - creating large world wrap maps on Android can lead to crashes! =
|
||||
Anything above 80 by 50 may work very slowly on Android! =
|
||||
Anything above 40 may work very slowly on Android! =
|
||||
|
||||
# Multiplayer
|
||||
|
||||
|
||||
# Multiplayer
|
||||
|
||||
Username =
|
||||
Multiplayer =
|
||||
Could not download game! =
|
||||
@ -341,9 +344,9 @@ Resign =
|
||||
Are you sure you want to resign? =
|
||||
You can only resign if it's your turn =
|
||||
[civName] resigned and is now controlled by AI =
|
||||
|
||||
# Save game menu
|
||||
|
||||
|
||||
# Save game menu
|
||||
|
||||
Current saves =
|
||||
Show autosaves =
|
||||
Saved game name =
|
||||
@ -370,9 +373,9 @@ Load from custom location =
|
||||
Could not load game from custom location! =
|
||||
Save to custom location =
|
||||
Could not save game to custom location! =
|
||||
|
||||
# Options
|
||||
|
||||
|
||||
# Options
|
||||
|
||||
Options =
|
||||
Display options =
|
||||
Gameplay options =
|
||||
@ -410,9 +413,9 @@ Enable portrait orientation =
|
||||
Generate translation files =
|
||||
Translation files are generated successfully. =
|
||||
Locate mod errors =
|
||||
|
||||
# Notifications
|
||||
|
||||
|
||||
# Notifications
|
||||
|
||||
Research of [technologyName] has completed! =
|
||||
[construction] has become obsolete and was removed from the queue in [cityName]! =
|
||||
[construction] has become obsolete and was removed from the queue in [amount] cities! =
|
||||
@ -516,9 +519,9 @@ Our [name] took [tileDamage] tile damage =
|
||||
[civName] has adopted the [policyName] policy =
|
||||
An unknown civilization has adopted the [policyName] policy =
|
||||
Our influence with City-States has started dropping faster! =
|
||||
|
||||
# World Screen UI
|
||||
|
||||
|
||||
# World Screen UI
|
||||
|
||||
Working... =
|
||||
Waiting for other players... =
|
||||
in =
|
||||
@ -571,7 +574,7 @@ Yes =
|
||||
No =
|
||||
Acquire =
|
||||
Under construction =
|
||||
|
||||
|
||||
Food =
|
||||
Production =
|
||||
Gold =
|
||||
@ -579,7 +582,7 @@ Happiness =
|
||||
Culture =
|
||||
Science =
|
||||
Faith =
|
||||
|
||||
|
||||
Crop Yield =
|
||||
Territory =
|
||||
Force =
|
||||
@ -588,7 +591,7 @@ Golden Age =
|
||||
[year] BC =
|
||||
[year] AD =
|
||||
Civilopedia =
|
||||
|
||||
|
||||
Start new game =
|
||||
Save game =
|
||||
Load game =
|
||||
@ -604,9 +607,9 @@ Close =
|
||||
Do you want to exit the game? =
|
||||
Start bias: =
|
||||
Avoid [terrain] =
|
||||
|
||||
# City screen
|
||||
|
||||
|
||||
# City screen
|
||||
|
||||
Exit city =
|
||||
Raze city =
|
||||
Stop razing city =
|
||||
@ -654,9 +657,9 @@ Worked by [cityName] =
|
||||
Lock =
|
||||
Unlock =
|
||||
Move to city =
|
||||
|
||||
# Technology UI
|
||||
|
||||
|
||||
# Technology UI
|
||||
|
||||
Pick a tech =
|
||||
Pick a free tech =
|
||||
Research [technology] =
|
||||
@ -679,9 +682,9 @@ Attack =
|
||||
Bombard =
|
||||
NUKE =
|
||||
Captured! =
|
||||
|
||||
# Battle modifier categories
|
||||
|
||||
|
||||
# Battle modifier categories
|
||||
|
||||
defence vs ranged =
|
||||
[percentage] to unit defence =
|
||||
Attacker Bonus =
|
||||
@ -703,11 +706,11 @@ defence vs [unitType] =
|
||||
[tileFilter] defence =
|
||||
Defensive Bonus =
|
||||
Stacked with [unitType] =
|
||||
|
||||
|
||||
The following improvements [stats]: =
|
||||
The following improvements on [tileType] tiles [stats]: =
|
||||
|
||||
|
||||
|
||||
|
||||
Hurry Research =
|
||||
Conduct Trade Mission =
|
||||
Your trade mission to [civName] has earned you [goldAmount] gold and [influenceAmount] influence! =
|
||||
@ -726,9 +729,9 @@ Policies =
|
||||
Base happiness =
|
||||
Occupied City =
|
||||
Buildings =
|
||||
|
||||
# terrainFilters (so for uniques like: "[stats] from [terrainFilter] tiles")
|
||||
|
||||
|
||||
# terrainFilters (so for uniques like: "[stats] from [terrainFilter] tiles")
|
||||
|
||||
All =
|
||||
Water =
|
||||
Land =
|
||||
@ -747,15 +750,15 @@ Strategic resource =
|
||||
Fresh water =
|
||||
non-fresh water =
|
||||
Natural Wonder =
|
||||
|
||||
# improvementFilters
|
||||
|
||||
|
||||
# improvementFilters
|
||||
|
||||
All =
|
||||
All Road =
|
||||
Great Improvement =
|
||||
Great =
|
||||
|
||||
|
||||
|
||||
|
||||
Wonders =
|
||||
Base values =
|
||||
Bonuses =
|
||||
@ -781,9 +784,9 @@ Known and defeated ([numberOfCivs]) =
|
||||
Tiles =
|
||||
Natural Wonders =
|
||||
Treasury deficit =
|
||||
|
||||
# Victory
|
||||
|
||||
|
||||
# Victory
|
||||
|
||||
Science victory =
|
||||
Cultural victory =
|
||||
Conquest victory =
|
||||
@ -802,7 +805,7 @@ The world has been convulsed by war. Many great and powerful civilizations have
|
||||
You have achieved victory through mastery of Science! You have conquered the mysteries of nature and led your people on a voyage to a brave new world! Your triumph will be remembered as long as the stars burn in the night sky! =
|
||||
Your civilization stands above all others! The exploits of your people shall be remembered until the end of civilization itself! =
|
||||
You have been defeated. Your civilization has been overwhelmed by its many foes. But your people do not despair, for they know that one day you shall return - and lead them forward to victory! =
|
||||
You have triumphed over your foes through the art of diplomacy! Your cunning and wisdom have earned you great friends - and divided and sown confusion among your enemies! Forever will you be remembered as the leader who brought peace to this weary world! =
|
||||
You have triumphed over your foes through the art of diplomacy! Your cunning and wisdom have earned you great friends - and divided and sown confusion among your enemies! Forever will you be remembered as the leader who brought peace to this weary world! =
|
||||
One more turn...! =
|
||||
Built Apollo Program =
|
||||
Destroy [civName] =
|
||||
@ -812,8 +815,8 @@ Rankings =
|
||||
Spaceship parts remaining =
|
||||
Branches completed =
|
||||
Undefeated civs =
|
||||
# The \n here means: put a newline (enter) here. If this is omitted, the sidebox in the diplomacy overview will become _really_ wide.
|
||||
# Feel free to replace it with a space and put it somewhere else in your translation
|
||||
# The \n here means: put a newline (enter) here. If this is omitted, the sidebox in the diplomacy overview will become _really_ wide.
|
||||
# Feel free to replace it with a space and put it somewhere else in your translation
|
||||
Turns until the next\ndiplomacy victory vote: [amount] =
|
||||
Choose a civ to vote for =
|
||||
Choose who should become the world leader and win a diplomatic victory! =
|
||||
@ -822,9 +825,9 @@ Vote for [civilizationName] =
|
||||
Continue =
|
||||
Abstained =
|
||||
Vote for World Leader =
|
||||
|
||||
# Capturing a city
|
||||
|
||||
|
||||
# Capturing a city
|
||||
|
||||
What would you like to do with the city? =
|
||||
Annex =
|
||||
Annexed cities become part of your regular empire. =
|
||||
@ -844,14 +847,14 @@ Destroying the city instantly razes the city to the ground. =
|
||||
Remove your troops in our border immediately! =
|
||||
Sorry. =
|
||||
Never! =
|
||||
|
||||
|
||||
Offer Declaration of Friendship ([30] turns) =
|
||||
My friend, shall we declare our friendship to the world? =
|
||||
Sign Declaration of Friendship ([30] turns) =
|
||||
We are not interested. =
|
||||
We have signed a Declaration of Friendship with [otherCiv]! =
|
||||
[otherCiv] has denied our Declaration of Friendship! =
|
||||
|
||||
|
||||
Basics =
|
||||
Resources =
|
||||
Terrains =
|
||||
@ -920,8 +923,8 @@ Terrain feature [feature] does not exist in ruleset! =
|
||||
Resource [resource] does not exist in ruleset! =
|
||||
Improvement [improvement] does not exist in ruleset! =
|
||||
Change map to fit selected ruleset? =
|
||||
|
||||
# Civilopedia difficulty levels
|
||||
|
||||
# Civilopedia difficulty levels
|
||||
Player settings =
|
||||
Base Happiness =
|
||||
Happiness per luxury =
|
||||
@ -931,7 +934,7 @@ Building cost modifier =
|
||||
Policy cost modifier =
|
||||
Unhappiness modifier =
|
||||
Bonus vs. Barbarians =
|
||||
|
||||
|
||||
AI settings =
|
||||
AI city growth modifier =
|
||||
AI unit cost modifier =
|
||||
@ -940,14 +943,14 @@ AI wonder cost modifier =
|
||||
AI building maintenance modifier =
|
||||
AI unit maintenance modifier =
|
||||
AI unhappiness modifier =
|
||||
|
||||
|
||||
Turns until barbarians enter player tiles =
|
||||
Gold reward for clearing barbarian camps =
|
||||
|
||||
# Other civilopedia things
|
||||
|
||||
# Other civilopedia things
|
||||
Nations =
|
||||
Available for [unitTypes] =
|
||||
Available for: =
|
||||
Available for: =
|
||||
Free promotion: =
|
||||
Free promotions: =
|
||||
Free for [units] =
|
||||
@ -956,17 +959,17 @@ Granted by [param] =
|
||||
Granted by: =
|
||||
[bonus] with [tech] =
|
||||
Difficulty levels =
|
||||
|
||||
# Policies
|
||||
|
||||
|
||||
# Policies
|
||||
|
||||
Adopt policy =
|
||||
Adopt free policy =
|
||||
Unlocked at =
|
||||
Gain 2 free technologies =
|
||||
All policies adopted =
|
||||
|
||||
# Religions
|
||||
|
||||
|
||||
# Religions
|
||||
|
||||
Choose an Icon and name for your Religion =
|
||||
Choose a [beliefType] belief! =
|
||||
Found [religionName] =
|
||||
@ -975,14 +978,14 @@ Found Religion =
|
||||
Found Pantheon =
|
||||
Follow [belief] =
|
||||
Religions and Beliefs =
|
||||
|
||||
# Terrains
|
||||
|
||||
|
||||
# Terrains
|
||||
|
||||
Impassable =
|
||||
Rare feature =
|
||||
|
||||
# Resources
|
||||
|
||||
|
||||
# Resources
|
||||
|
||||
Bison =
|
||||
Copper =
|
||||
Cocoa =
|
||||
@ -992,9 +995,9 @@ Truffles =
|
||||
Strategic =
|
||||
Bonus =
|
||||
Luxury =
|
||||
|
||||
# Unit types
|
||||
|
||||
|
||||
# Unit types
|
||||
|
||||
City =
|
||||
Civilian =
|
||||
Melee =
|
||||
@ -1003,21 +1006,21 @@ Scout =
|
||||
Mounted =
|
||||
Armor =
|
||||
Siege =
|
||||
|
||||
|
||||
WaterCivilian =
|
||||
WaterMelee =
|
||||
WaterRanged =
|
||||
WaterSubmarine =
|
||||
WaterAircraftCarrier =
|
||||
|
||||
|
||||
Fighter =
|
||||
Bomber =
|
||||
AtomicBomber =
|
||||
Missile =
|
||||
|
||||
|
||||
|
||||
|
||||
# Unit filters and other unit related things
|
||||
|
||||
|
||||
Air =
|
||||
air units =
|
||||
All =
|
||||
@ -1038,13 +1041,13 @@ Water =
|
||||
water units =
|
||||
wounded units =
|
||||
Wounded =
|
||||
|
||||
# For the All "newly-trained [relevant] units in this city receive the [] promotion" translation. Relevant as in 'units that can receive'
|
||||
|
||||
# For the All "newly-trained [relevant] units in this city receive the [] promotion" translation. Relevant as in 'units that can receive'
|
||||
relevant =
|
||||
|
||||
|
||||
# Promotions
|
||||
|
||||
|
||||
|
||||
# Promotions
|
||||
|
||||
Pick promotion =
|
||||
OR =
|
||||
units in open terrain =
|
||||
@ -1058,9 +1061,9 @@ Dogfighting II =
|
||||
Dogfighting III =
|
||||
Choose name for [unitName] =
|
||||
[unitFilter] units gain the [promotion] promotion =
|
||||
|
||||
# Multiplayer Turn Checker Service
|
||||
|
||||
|
||||
# Multiplayer Turn Checker Service
|
||||
|
||||
Multiplayer options =
|
||||
Enable out-of-game turn notifications =
|
||||
Time between turn checks out-of-game (in minutes) =
|
||||
@ -1069,10 +1072,10 @@ Take user ID from clipboard =
|
||||
Doing this will reset your current user ID to the clipboard contents - are you sure? =
|
||||
ID successfully set! =
|
||||
Invalid ID! =
|
||||
|
||||
|
||||
# Mods
|
||||
|
||||
|
||||
|
||||
# Mods
|
||||
|
||||
Mods =
|
||||
Download [modName] =
|
||||
Update [modName] =
|
||||
@ -1100,9 +1103,9 @@ No description provided =
|
||||
Author: [author] =
|
||||
Size: [size] kB =
|
||||
The mod you selected is incompatible with the defined ruleset! =
|
||||
|
||||
# Uniques that are relevant to more than one type of game object
|
||||
|
||||
|
||||
# Uniques that are relevant to more than one type of game object
|
||||
|
||||
[stats] from every [param] =
|
||||
[stats] from [param] tiles in this city =
|
||||
[stats] from every [param] on [tileFilter] tiles =
|
||||
@ -1116,8 +1119,8 @@ Can only be built on [tileFilter] tiles =
|
||||
Cannot be built on [tileFilter] tiles =
|
||||
Does not need removal of [feature] =
|
||||
Gain a free [building] [cityFilter] =
|
||||
|
||||
# City filters
|
||||
|
||||
# City filters
|
||||
in this city =
|
||||
in all cities =
|
||||
in all coastal cities =
|
||||
@ -1127,3 +1130,4 @@ in all cities with a world wonder =
|
||||
in all cities connected to capital =
|
||||
in all cities with a garrison =
|
||||
|
||||
|
||||
|
@ -2,6 +2,9 @@ package com.unciv.logic.automation
|
||||
|
||||
import com.unciv.Constants
|
||||
import com.unciv.logic.city.CityInfo
|
||||
import com.unciv.logic.city.IConstruction
|
||||
import com.unciv.logic.city.INonPerpetualConstruction
|
||||
import com.unciv.logic.city.PerpetualConstruction
|
||||
import com.unciv.logic.civilization.*
|
||||
import com.unciv.logic.civilization.diplomacy.DiplomacyFlags
|
||||
import com.unciv.logic.civilization.diplomacy.DiplomaticModifiers
|
||||
@ -15,6 +18,7 @@ import com.unciv.models.ruleset.ModOptionsConstants
|
||||
import com.unciv.models.ruleset.VictoryType
|
||||
import com.unciv.models.ruleset.tech.Technology
|
||||
import com.unciv.models.ruleset.unit.BaseUnit
|
||||
import com.unciv.models.stats.Stat
|
||||
import com.unciv.models.translations.tr
|
||||
import kotlin.math.min
|
||||
|
||||
@ -136,8 +140,9 @@ object NextTurnAutomation {
|
||||
|
||||
for (city in civInfo.cities.sortedByDescending { it.population.population }) {
|
||||
val construction = city.cityConstructions.getCurrentConstruction()
|
||||
if (construction.canBePurchased()
|
||||
&& city.civInfo.gold / 3 >= construction.getGoldCost(civInfo)) {
|
||||
if (construction is PerpetualConstruction) continue
|
||||
if ((construction as INonPerpetualConstruction).canBePurchasedWithStat(city, Stat.Gold)
|
||||
&& city.civInfo.gold / 3 >= construction.getStatBuyCost(city, Stat.Gold)!!) {
|
||||
city.cityConstructions.purchaseConstruction(construction.name, 0, true)
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import com.unciv.models.ruleset.Building
|
||||
import com.unciv.models.ruleset.Ruleset
|
||||
import com.unciv.models.ruleset.UniqueMap
|
||||
import com.unciv.models.ruleset.unit.BaseUnit
|
||||
import com.unciv.models.stats.Stat
|
||||
import com.unciv.models.stats.Stats
|
||||
import com.unciv.models.translations.tr
|
||||
import com.unciv.ui.civilopedia.CivilopediaCategories
|
||||
@ -152,15 +153,19 @@ class CityConstructions {
|
||||
}
|
||||
|
||||
|
||||
/** @constructionName needs to be a non-perpetual construction, else a cost of -1 is inferred */
|
||||
internal fun getTurnsToConstructionString(constructionName: String, useStoredProduction:Boolean = true): String {
|
||||
val construction = getConstruction(constructionName)
|
||||
val cost = construction.getProductionCost(cityInfo.civInfo)
|
||||
val cost =
|
||||
if (construction is INonPerpetualConstruction) construction.getProductionCost(cityInfo.civInfo)
|
||||
else -1 // This could _should_ never be reached
|
||||
val turnsToConstruction = turnsToConstruction(constructionName, useStoredProduction)
|
||||
val currentProgress = if (useStoredProduction) getWorkDone(constructionName) else 0
|
||||
if (currentProgress == 0) return "\n$cost${Fonts.production} $turnsToConstruction${Fonts.turn}"
|
||||
else return "\n$currentProgress/$cost${Fonts.production}\n$turnsToConstruction${Fonts.turn}"
|
||||
}
|
||||
|
||||
// This function appears unused, can it be removed?
|
||||
fun getProductionForTileInfo(): String {
|
||||
/* this is because there were rare errors that I assume were caused because
|
||||
currentConstruction changed on another thread */
|
||||
@ -246,8 +251,8 @@ class CityConstructions {
|
||||
val constr = getConstruction(constructionName)
|
||||
return when {
|
||||
constr is PerpetualConstruction -> 0
|
||||
useStoredProduction -> constr.getProductionCost(cityInfo.civInfo) - getWorkDone(constructionName)
|
||||
else -> constr.getProductionCost(cityInfo.civInfo)
|
||||
useStoredProduction -> (constr as INonPerpetualConstruction).getProductionCost(cityInfo.civInfo) - getWorkDone(constructionName)
|
||||
else -> (constr as INonPerpetualConstruction).getProductionCost(cityInfo.civInfo)
|
||||
}
|
||||
}
|
||||
|
||||
@ -315,7 +320,7 @@ class CityConstructions {
|
||||
val construction = getConstruction(currentConstructionFromQueue)
|
||||
if (construction is PerpetualConstruction) chooseNextConstruction() // check every turn if we could be doing something better, because this doesn't end by itself
|
||||
else {
|
||||
val productionCost = construction.getProductionCost(cityInfo.civInfo)
|
||||
val productionCost = (construction as INonPerpetualConstruction).getProductionCost(cityInfo.civInfo)
|
||||
if (inProgressConstructions.containsKey(currentConstructionFromQueue)
|
||||
&& inProgressConstructions[currentConstructionFromQueue]!! >= productionCost) {
|
||||
productionOverflow = inProgressConstructions[currentConstructionFromQueue]!! - productionCost
|
||||
@ -481,14 +486,25 @@ class CityConstructions {
|
||||
* Note: -1 does not guarantee queue will remain unchanged (validation)
|
||||
* @param automatic Flag whether automation should try to choose what next to build (not coming from UI)
|
||||
* Note: settings.autoAssignCityProduction is handled later
|
||||
* @param stat Stat object of the stat with which was paid for the construction
|
||||
* @return Success (false e.g. unit cannot be placed
|
||||
*/
|
||||
fun purchaseConstruction(constructionName: String, queuePosition: Int, automatic: Boolean): Boolean {
|
||||
fun purchaseConstruction(
|
||||
constructionName: String,
|
||||
queuePosition: Int,
|
||||
automatic: Boolean,
|
||||
stat: Stat = Stat.Gold
|
||||
): Boolean {
|
||||
if (!getConstruction(constructionName).postBuildEvent(this, true))
|
||||
return false // nothing built - no pay
|
||||
|
||||
if (!cityInfo.civInfo.gameInfo.gameParameters.godMode)
|
||||
cityInfo.civInfo.addGold(-getConstruction(constructionName).getGoldCost(cityInfo.civInfo))
|
||||
if (!cityInfo.civInfo.gameInfo.gameParameters.godMode) {
|
||||
val construction = getConstruction(constructionName)
|
||||
if (construction is PerpetualConstruction) return false
|
||||
val constructionCost = (construction as INonPerpetualConstruction).getStatBuyCost(cityInfo, stat)
|
||||
if (constructionCost == null) return false // We should never end up here anyway, so things have already gone _way_ wrong
|
||||
cityInfo.addStat(stat, -1 * constructionCost)
|
||||
}
|
||||
|
||||
if (queuePosition in 0 until constructionQueue.size)
|
||||
removeFromQueue(queuePosition, automatic)
|
||||
|
@ -12,6 +12,7 @@ import com.unciv.models.ruleset.Unique
|
||||
import com.unciv.models.ruleset.tile.ResourceSupplyList
|
||||
import com.unciv.models.ruleset.tile.ResourceType
|
||||
import com.unciv.models.ruleset.unit.BaseUnit
|
||||
import com.unciv.models.stats.Stat
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.collections.HashMap
|
||||
@ -398,6 +399,21 @@ class CityInfo {
|
||||
gppCounter.add(entry)
|
||||
return gppCounter
|
||||
}
|
||||
|
||||
fun addStat(stat: Stat, amount: Int) {
|
||||
when (stat) {
|
||||
Stat.Production -> cityConstructions.addProductionPoints(amount)
|
||||
Stat.Food -> population.foodStored += amount
|
||||
else -> civInfo.addStat(stat, amount)
|
||||
}
|
||||
}
|
||||
|
||||
fun getStatReserve(stat: Stat): Int {
|
||||
return when (stat) {
|
||||
Stat.Food -> population.foodStored
|
||||
else -> civInfo.getStatReserve(stat)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun getMaxHealth() = 200 + cityConstructions.getBuiltBuildings().sumBy { it.cityHealth }
|
||||
|
||||
@ -554,7 +570,7 @@ class CityInfo {
|
||||
otherCiv.getDiplomacyManager(civInfo).setFlag(DiplomacyFlags.SettledCitiesNearUs, 30)
|
||||
}
|
||||
|
||||
fun canPurchase(construction: IConstruction): Boolean {
|
||||
fun canPurchase(construction: INonPerpetualConstruction): Boolean {
|
||||
if (construction is BaseUnit) {
|
||||
val tile = getCenterTile()
|
||||
if (construction.isCivilian())
|
||||
@ -576,6 +592,9 @@ class CityInfo {
|
||||
"in all cities with a world wonder" -> cityConstructions.getBuiltBuildings().any { it.isWonder }
|
||||
"in all cities connected to capital" -> isConnectedToCapital()
|
||||
"in all cities with a garrison" -> getCenterTile().militaryUnit != null
|
||||
"in all cities in which the majority religion is a major religion" ->
|
||||
religion.getMajorityReligion() != null
|
||||
&& civInfo.gameInfo.religions[religion.getMajorityReligion()]!!.isMajorReligion()
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
@ -43,8 +43,8 @@ class CityInfoReligionManager: Counter<String>() {
|
||||
val followersPerReligion = getNumberOfFollowers()
|
||||
if (followersPerReligion.isEmpty()) return null
|
||||
val religionWithMaxFollowers = followersPerReligion.maxByOrNull { it.value }!!
|
||||
if (religionWithMaxFollowers.value >= cityInfo.population.population) return religionWithMaxFollowers.key
|
||||
else return null
|
||||
return if (religionWithMaxFollowers.value >= cityInfo.population.population) religionWithMaxFollowers.key
|
||||
else null
|
||||
}
|
||||
|
||||
fun getAffectedBySurroundingCities() {
|
||||
|
@ -1,23 +1,78 @@
|
||||
package com.unciv.logic.city
|
||||
|
||||
import com.unciv.logic.civilization.CivilizationInfo
|
||||
import com.unciv.models.ruleset.Unique
|
||||
import com.unciv.models.stats.INamed
|
||||
import com.unciv.models.stats.Stat
|
||||
import com.unciv.ui.utils.Fonts
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
interface IConstruction : INamed {
|
||||
fun getProductionCost(civInfo: CivilizationInfo): Int
|
||||
fun getGoldCost(civInfo: CivilizationInfo): Int
|
||||
fun isBuildable(cityConstructions: CityConstructions): Boolean
|
||||
fun shouldBeDisplayed(cityConstructions: CityConstructions): Boolean
|
||||
fun postBuildEvent(cityConstructions: CityConstructions, wasBought: Boolean = false): Boolean // Yes I'm hilarious.
|
||||
fun getResourceRequirements(): HashMap<String,Int>
|
||||
fun canBePurchased(): Boolean
|
||||
}
|
||||
|
||||
interface INonPerpetualConstruction : IConstruction, INamed {
|
||||
val hurryCostModifier: Int
|
||||
val uniqueObjects: List<Unique>
|
||||
val uniques: List<String>
|
||||
|
||||
fun getProductionCost(civInfo: CivilizationInfo): Int
|
||||
fun getStatBuyCost(cityInfo: CityInfo, stat: Stat): Int?
|
||||
|
||||
private fun getMatchingUniques(uniqueTemplate: String): Sequence<Unique> {
|
||||
return uniqueObjects.asSequence().filter { it.placeholderText == uniqueTemplate }
|
||||
}
|
||||
|
||||
fun canBePurchasedWithStat(cityInfo: CityInfo, stat: Stat, ignoreCityRequirements: Boolean = false): Boolean {
|
||||
if (stat in listOf(Stat.Production, Stat.Happiness)) return false
|
||||
if ("Cannot be purchased" in uniques) return false
|
||||
if (stat == Stat.Gold) return !uniques.contains("Unbuildable")
|
||||
// Can be purchased with [Stat] [cityFilter]
|
||||
if (getMatchingUniques("Can be purchased with [] []")
|
||||
.any { it.params[0] == stat.name && (ignoreCityRequirements || cityInfo.matchesFilter(it.params[1])) }
|
||||
) return true
|
||||
// Can be purchased for [amount] [Stat] [cityFilter]
|
||||
if (getMatchingUniques("Can be purchased for [] [] []")
|
||||
.any { it.params[1] == stat.name && ( ignoreCityRequirements || cityInfo.matchesFilter(it.params[2])) }
|
||||
) return true
|
||||
return false
|
||||
}
|
||||
|
||||
fun canBePurchasedWithAnyStat(cityInfo: CityInfo): Boolean {
|
||||
return Stat.values().any { canBePurchasedWithStat(cityInfo, it) }
|
||||
}
|
||||
|
||||
fun getBaseGoldCost(civInfo: CivilizationInfo): Double {
|
||||
// https://forums.civfanatics.com/threads/rush-buying-formula.393892/
|
||||
return (30.0 * getProductionCost(civInfo)).pow(0.75) * (1 + hurryCostModifier / 100f)
|
||||
}
|
||||
|
||||
// I can't make this function protected or private :(
|
||||
fun getBaseBuyCost(cityInfo: CityInfo, stat: Stat): Int? {
|
||||
if (stat == Stat.Gold) return getBaseGoldCost(cityInfo.civInfo).toInt()
|
||||
|
||||
// Can be purchased for [amount] [Stat] [cityFilter]
|
||||
val lowestCostUnique = getMatchingUniques("Can be purchased for [] [] []")
|
||||
.filter { it.params[1] == stat.name && cityInfo.matchesFilter(it.params[2]) }
|
||||
.minByOrNull { it.params[0].toInt() }
|
||||
if (lowestCostUnique != null) return lowestCostUnique.params[0].toInt()
|
||||
|
||||
// Can be purchased with [Stat] [cityFilter]
|
||||
if (getMatchingUniques("Can be purchased with [] []")
|
||||
.any { it.params[0] == stat.name && cityInfo.matchesFilter(it.params[1])}
|
||||
) return cityInfo.civInfo.gameInfo.ruleSet.eras[cityInfo.civInfo.getEra()]!!.baseUnitBuyCost
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
open class PerpetualConstruction(override var name: String, val description: String) : IConstruction {
|
||||
|
||||
override fun shouldBeDisplayed(cityConstructions: CityConstructions) = isBuildable(cityConstructions)
|
||||
open fun getProductionTooltip(cityInfo: CityInfo) : String
|
||||
= "\r\n${(cityInfo.cityStats.currentCityStats.production / CONVERSION_RATE).roundToInt()}/${Fonts.turn}"
|
||||
@ -50,12 +105,6 @@ open class PerpetualConstruction(override var name: String, val description: Str
|
||||
= mapOf(science.name to science, gold.name to gold, idle.name to idle)
|
||||
}
|
||||
|
||||
override fun canBePurchased() = false
|
||||
|
||||
override fun getProductionCost(civInfo: CivilizationInfo) = throw Exception("Impossible!")
|
||||
|
||||
override fun getGoldCost(civInfo: CivilizationInfo) = throw Exception("Impossible!")
|
||||
|
||||
override fun isBuildable(cityConstructions: CityConstructions): Boolean =
|
||||
throw Exception("Impossible!")
|
||||
|
||||
|
@ -705,6 +705,19 @@ class CivilizationInfo {
|
||||
// Happiness cannot be added as it is recalculated again, use a unique instead
|
||||
}
|
||||
}
|
||||
|
||||
fun getStatReserve(stat: Stat): Int {
|
||||
return when (stat) {
|
||||
Stat.Culture -> policies.storedCulture
|
||||
Stat.Science -> {
|
||||
if (tech.currentTechnology() == null) 0
|
||||
else tech.remainingScienceToTech(tech.currentTechnology()!!.name)
|
||||
}
|
||||
Stat.Gold -> gold
|
||||
Stat.Faith -> religionManager.storedFaith
|
||||
else -> 0
|
||||
}
|
||||
}
|
||||
|
||||
fun getGreatPersonPointsForNextTurn(): Counter<String> {
|
||||
val greatPersonPoints = Counter<String>()
|
||||
|
@ -1,8 +1,9 @@
|
||||
package com.unciv.models.ruleset
|
||||
|
||||
import com.unciv.UncivGame
|
||||
import com.unciv.logic.city.CityConstructions
|
||||
import com.unciv.logic.city.CityInfo
|
||||
import com.unciv.logic.city.IConstruction
|
||||
import com.unciv.logic.city.INonPerpetualConstruction
|
||||
import com.unciv.logic.civilization.CivilizationInfo
|
||||
import com.unciv.models.Counter
|
||||
import com.unciv.models.ruleset.tile.TileImprovement
|
||||
@ -17,10 +18,9 @@ import com.unciv.ui.utils.Fonts
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.collections.HashMap
|
||||
import kotlin.math.pow
|
||||
|
||||
|
||||
class Building : NamedStats(), IConstruction, ICivilopediaText {
|
||||
class Building : NamedStats(), INonPerpetualConstruction, ICivilopediaText {
|
||||
|
||||
var requiredTech: String? = null
|
||||
|
||||
@ -45,7 +45,7 @@ class Building : NamedStats(), IConstruction, ICivilopediaText {
|
||||
var greatPersonPoints= Counter<String>()
|
||||
|
||||
/** Extra cost percentage when purchasing */
|
||||
private var hurryCostModifier = 0
|
||||
override var hurryCostModifier = 0
|
||||
var isWonder = false
|
||||
var isNationalWonder = false
|
||||
fun isAnyWonder() = isWonder || isNationalWonder
|
||||
@ -68,9 +68,9 @@ class Building : NamedStats(), IConstruction, ICivilopediaText {
|
||||
var quote: String = ""
|
||||
@Deprecated("As of 3.15.16 - replaced with 'Provides a free [buildingName] [cityFilter]'")
|
||||
var providesFreeBuilding: String? = null
|
||||
var uniques = ArrayList<String>()
|
||||
override var uniques = ArrayList<String>()
|
||||
var replacementTextForUniques = ""
|
||||
val uniqueObjects: List<Unique> by lazy { uniques.map { Unique(it) } }
|
||||
override val uniqueObjects: List<Unique> by lazy { uniques.map { Unique(it) } }
|
||||
|
||||
override var civilopediaText = listOf<FormattedLine>()
|
||||
|
||||
@ -101,7 +101,7 @@ class Building : NamedStats(), IConstruction, ICivilopediaText {
|
||||
if (!tileBonusHashmap.containsKey(stats)) tileBonusHashmap[stats] = ArrayList()
|
||||
tileBonusHashmap[stats]!!.add(unique.params[1])
|
||||
}
|
||||
unique.placeholderText == "Consumes [] []" -> Unit // skip these,
|
||||
unique.placeholderText == "Consumes [] []" -> Unit // skip these,
|
||||
else -> yield(unique.text)
|
||||
}
|
||||
for ((key, value) in tileBonusHashmap)
|
||||
@ -173,7 +173,7 @@ class Building : NamedStats(), IConstruction, ICivilopediaText {
|
||||
|
||||
if (!isWonder)
|
||||
for (unique in city.getMatchingUniques("[] from all [] buildings")) {
|
||||
if (isStatRelated(Stat.valueOf(unique.params[1])))
|
||||
if (matchesFilter(unique.params[1]))
|
||||
stats.add(unique.stats)
|
||||
}
|
||||
else
|
||||
@ -199,13 +199,19 @@ class Building : NamedStats(), IConstruction, ICivilopediaText {
|
||||
return stats
|
||||
}
|
||||
|
||||
override fun canBePurchasedWithStat(cityInfo: CityInfo, stat: Stat, ignoreCityRequirements: Boolean): Boolean {
|
||||
if (stat == Stat.Gold && isAnyWonder()) return false
|
||||
return super.canBePurchasedWithStat(cityInfo, stat, ignoreCityRequirements)
|
||||
}
|
||||
|
||||
override fun getCivilopediaTextHeader() = FormattedLine(name, header=2, icon=makeLink())
|
||||
override fun makeLink() = if (isAnyWonder()) "Wonder/$name" else "Building/$name"
|
||||
override fun hasCivilopediaTextLines() = true
|
||||
override fun replacesCivilopediaDescription() = true
|
||||
|
||||
override fun getCivilopediaTextLines(ruleset: Ruleset): List<FormattedLine> {
|
||||
fun Float.formatSignedInt() = (if (this > 0f) "+" else "") + this.toInt().toString()
|
||||
|
||||
|
||||
val textList = ArrayList<FormattedLine>()
|
||||
|
||||
if (isAnyWonder()) {
|
||||
@ -223,7 +229,9 @@ class Building : NamedStats(), IConstruction, ICivilopediaText {
|
||||
|
||||
if (cost > 0) {
|
||||
val stats = mutableListOf("$cost${Fonts.production}")
|
||||
if (canBePurchased()) stats += "${(getBaseGoldCost()*0.1).toInt()*10}${Fonts.gold}"
|
||||
if (canBePurchasedWithStat(CityInfo(), Stat.Gold, true)) {
|
||||
stats += "${getBaseGoldCost(UncivGame.Current.gameInfo.currentPlayerCiv).toInt() / 10 * 10}${Fonts.gold}"
|
||||
}
|
||||
textList += FormattedLine(stats.joinToString(", ", "{Cost}: "))
|
||||
}
|
||||
|
||||
@ -323,12 +331,6 @@ class Building : NamedStats(), IConstruction, ICivilopediaText {
|
||||
return textList
|
||||
}
|
||||
|
||||
|
||||
override fun canBePurchased(): Boolean {
|
||||
return !isAnyWonder() && "Cannot be purchased" !in uniques
|
||||
}
|
||||
|
||||
|
||||
override fun getProductionCost(civInfo: CivilizationInfo): Int {
|
||||
var productionCost = cost.toFloat()
|
||||
|
||||
@ -351,24 +353,34 @@ class Building : NamedStats(), IConstruction, ICivilopediaText {
|
||||
return productionCost.toInt()
|
||||
}
|
||||
|
||||
private fun getBaseGoldCost() = (30.0 * cost).pow(0.75) * (1 + hurryCostModifier / 100.0)
|
||||
override fun getStatBuyCost(cityInfo: CityInfo, stat: Stat): Int? {
|
||||
var cost = getBaseBuyCost(cityInfo, stat)?.toDouble()
|
||||
if (cost == null) return null
|
||||
|
||||
override fun getGoldCost(civInfo: CivilizationInfo): Int {
|
||||
// https://forums.civfanatics.com/threads/rush-buying-formula.393892/
|
||||
var cost = (30 * getProductionCost(civInfo)).toDouble().pow(0.75) * (1 + hurryCostModifier / 100f)
|
||||
// Deprecated since 3.15.15
|
||||
if (stat == Stat.Gold) {
|
||||
for (unique in cityInfo.getMatchingUniques("Cost of purchasing items in cities reduced by []%"))
|
||||
cost *= 1 - (unique.params[0].toFloat() / 100)
|
||||
|
||||
for (unique in civInfo.getMatchingUniques("Cost of purchasing items in cities reduced by []%"))
|
||||
cost *= 1 - (unique.params[0].toFloat() / 100)
|
||||
for (unique in cityInfo.getMatchingUniques("Cost of purchasing [] buildings reduced by []%")) {
|
||||
if (matchesFilter(unique.params[0]))
|
||||
cost *= 1 - (unique.params[1].toFloat() / 100)
|
||||
}
|
||||
}
|
||||
//
|
||||
|
||||
for (unique in civInfo.getMatchingUniques("Cost of purchasing [] buildings reduced by []%")) {
|
||||
if (isStatRelated(Stat.valueOf(unique.params[0])))
|
||||
cost *= 1 - (unique.params[1].toFloat() / 100)
|
||||
for (unique in cityInfo.getMatchingUniques("[] cost of purchasing items in cities []%"))
|
||||
if (stat.name == unique.params[0])
|
||||
cost *= 1 + (unique.params[1].toFloat() / 100)
|
||||
|
||||
for (unique in cityInfo.getMatchingUniques("[] cost of purchasing [] buildings []%")) {
|
||||
if (stat.name == unique.params[0] && matchesFilter(unique.params[1]))
|
||||
cost *= 1 + (unique.params[2].toFloat() / 100)
|
||||
}
|
||||
|
||||
return (cost / 10).toInt() * 10
|
||||
return (cost / 10f).toInt() * 10
|
||||
}
|
||||
|
||||
|
||||
override fun shouldBeDisplayed(cityConstructions: CityConstructions): Boolean {
|
||||
if (cityConstructions.isBeingConstructedOrEnqueued(name))
|
||||
return false
|
||||
@ -377,22 +389,29 @@ class Building : NamedStats(), IConstruction, ICivilopediaText {
|
||||
|| rejectionReason.startsWith("Requires")
|
||||
|| rejectionReason.startsWith("Consumes")
|
||||
|| rejectionReason.endsWith("Wonder is being built elsewhere")
|
||||
|| rejectionReason == "Can only be purchased"
|
||||
}
|
||||
|
||||
fun getRejectionReason(construction: CityConstructions): String {
|
||||
if (construction.isBuilt(name)) return "Already built"
|
||||
// for buildings that are created as side effects of other things, and not directly built
|
||||
if (uniques.contains("Unbuildable")) return "Unbuildable"
|
||||
// unless they can be bought with faith
|
||||
if (uniques.contains("Unbuildable")) {
|
||||
if (canBePurchasedWithAnyStat(construction.cityInfo))
|
||||
return "Can only be purchased"
|
||||
return "Unbuildable"
|
||||
}
|
||||
|
||||
val cityCenter = construction.cityInfo.getCenterTile()
|
||||
val civInfo = construction.cityInfo.civInfo
|
||||
|
||||
// This overrides the others
|
||||
if (uniqueObjects.any {
|
||||
it.placeholderText == "Not displayed as an available construction unless [] is built"
|
||||
&& !construction.containsBuildingOrEquivalent(it.params[0])
|
||||
})
|
||||
return "Should not be displayed"
|
||||
if (uniqueObjects
|
||||
.any {
|
||||
it.placeholderText == "Not displayed as an available construction unless [] is built"
|
||||
&& !construction.containsBuildingOrEquivalent(it.params[0])
|
||||
}
|
||||
) return "Should not be displayed"
|
||||
|
||||
for (unique in uniqueObjects.filter { it.placeholderText == "Not displayed as an available construction without []" }) {
|
||||
val filter = unique.params[0]
|
||||
@ -437,7 +456,7 @@ class Building : NamedStats(), IConstruction, ICivilopediaText {
|
||||
|
||||
if (civInfo.isCityState())
|
||||
return "No world wonders for city-states"
|
||||
|
||||
|
||||
val ruleSet = civInfo.gameInfo.ruleSet
|
||||
val startingEra = civInfo.gameInfo.gameParameters.startingEra
|
||||
if (startingEra in ruleSet.eras && name in ruleSet.eras[startingEra]!!.startingObsoleteWonders)
|
||||
@ -602,7 +621,7 @@ class Building : NamedStats(), IConstruction, ICivilopediaText {
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
fun matchesFilter(filter: String): Boolean {
|
||||
return when (filter) {
|
||||
"All" -> true
|
||||
@ -612,6 +631,7 @@ class Building : NamedStats(), IConstruction, ICivilopediaText {
|
||||
replaces -> true
|
||||
else -> {
|
||||
if (uniques.contains(filter)) return true
|
||||
if (isStats(filter) && isStatRelated(Stat.valueOf(filter))) return true
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ class Era : INamed {
|
||||
var settlerPopulation = 1
|
||||
var settlerBuildings = ArrayList<String>()
|
||||
var startingObsoleteWonders = ArrayList<String>()
|
||||
var baseUnitBuyCost = 200
|
||||
var iconRGB: List<Int>? = null
|
||||
|
||||
fun getStartingUnits(): List<String> {
|
||||
|
@ -461,7 +461,7 @@ object RulesetCache : HashMap<String,Ruleset>() {
|
||||
}
|
||||
|
||||
|
||||
fun getBaseRuleset() = this[BaseRuleset.Civ_V_Vanilla.fullName]!!.clone() // safeguard, o no-one edits the base ruleset by mistake
|
||||
fun getBaseRuleset() = this[BaseRuleset.Civ_V_Vanilla.fullName]!!.clone() // safeguard, so no-one edits the base ruleset by mistake
|
||||
|
||||
fun getComplexRuleset(mods: LinkedHashSet<String>): Ruleset {
|
||||
val newRuleset = Ruleset()
|
||||
|
@ -1,15 +1,18 @@
|
||||
package com.unciv.models.ruleset.unit
|
||||
|
||||
import com.unciv.Constants
|
||||
import com.unciv.UncivGame
|
||||
import com.unciv.logic.city.CityConstructions
|
||||
import com.unciv.logic.city.IConstruction
|
||||
import com.unciv.logic.city.CityInfo
|
||||
import com.unciv.logic.city.INonPerpetualConstruction
|
||||
import com.unciv.logic.civilization.CivilizationInfo
|
||||
import com.unciv.logic.map.MapUnit
|
||||
import com.unciv.models.ruleset.Ruleset
|
||||
import com.unciv.models.ruleset.Unique
|
||||
import com.unciv.models.stats.INamed
|
||||
import com.unciv.models.stats.Stat
|
||||
import com.unciv.models.translations.tr
|
||||
import com.unciv.ui.civilopedia.ICivilopediaText
|
||||
import com.unciv.ui.civilopedia.CivilopediaText
|
||||
import com.unciv.ui.civilopedia.FormattedLine
|
||||
import com.unciv.ui.utils.Fonts
|
||||
import java.util.*
|
||||
@ -22,11 +25,11 @@ import kotlin.math.pow
|
||||
|
||||
/** This is the basic info of the units, as specified in Units.json,
|
||||
in contrast to MapUnit, which is a specific unit of a certain type that appears on the map */
|
||||
class BaseUnit : INamed, IConstruction, ICivilopediaText {
|
||||
class BaseUnit : INamed, INonPerpetualConstruction, CivilopediaText() {
|
||||
|
||||
override lateinit var name: String
|
||||
var cost: Int = 0
|
||||
var hurryCostModifier: Int = 0
|
||||
override var hurryCostModifier: Int = 0
|
||||
var movement: Int = 0
|
||||
var strength: Int = 0
|
||||
var rangedStrength: Int = 0
|
||||
@ -36,8 +39,8 @@ class BaseUnit : INamed, IConstruction, ICivilopediaText {
|
||||
fun getType() = ruleset.unitTypes[unitType]!!
|
||||
var requiredTech: String? = null
|
||||
var requiredResource: String? = null
|
||||
var uniques = HashSet<String>()
|
||||
val uniqueObjects: List<Unique> by lazy { uniques.map { Unique(it) } }
|
||||
override var uniques = ArrayList<String>() // Can not be a hashset as that would remove doubles
|
||||
override val uniqueObjects: List<Unique> by lazy { uniques.map { Unique(it) } }
|
||||
var replacementTextForUniques = ""
|
||||
var promotions = HashSet<String>()
|
||||
var obsoleteTech: String? = null
|
||||
@ -45,7 +48,7 @@ class BaseUnit : INamed, IConstruction, ICivilopediaText {
|
||||
var replaces: String? = null
|
||||
var uniqueTo: String? = null
|
||||
var attackSound: String? = null
|
||||
|
||||
|
||||
lateinit var ruleset: Ruleset
|
||||
|
||||
override var civilopediaText = listOf<FormattedLine>()
|
||||
@ -110,7 +113,8 @@ class BaseUnit : INamed, IConstruction, ICivilopediaText {
|
||||
if (cost > 0) {
|
||||
stats.clear()
|
||||
stats += "$cost${Fonts.production}"
|
||||
if (canBePurchased()) stats += "${(getBaseGoldCost()*0.1).toInt()*10}${Fonts.gold}"
|
||||
if (canBePurchasedWithStat(CityInfo(), Stat.Gold, true))
|
||||
stats += "${getBaseGoldCost(UncivGame.Current.gameInfo.currentPlayerCiv).toInt() / 10 * 10}${Fonts.gold}"
|
||||
textList += FormattedLine(stats.joinToString(", ", "{Cost}: "))
|
||||
}
|
||||
|
||||
@ -174,7 +178,7 @@ class BaseUnit : INamed, IConstruction, ICivilopediaText {
|
||||
|
||||
return textList
|
||||
}
|
||||
|
||||
|
||||
fun getMapUnit(ruleset: Ruleset): MapUnit {
|
||||
val unit = MapUnit()
|
||||
unit.name = name
|
||||
@ -184,8 +188,6 @@ class BaseUnit : INamed, IConstruction, ICivilopediaText {
|
||||
return unit
|
||||
}
|
||||
|
||||
override fun canBePurchased() = "Cannot be purchased" !in uniques
|
||||
|
||||
override fun getProductionCost(civInfo: CivilizationInfo): Int {
|
||||
var productionCost = cost.toFloat()
|
||||
if (civInfo.isCityState())
|
||||
@ -198,33 +200,44 @@ class BaseUnit : INamed, IConstruction, ICivilopediaText {
|
||||
return productionCost.toInt()
|
||||
}
|
||||
|
||||
private fun getBaseGoldCost() = (30.0 * cost).pow(0.75) * (1 + hurryCostModifier / 100.0)
|
||||
private fun getGoldCostWithGameSpeed(civInfo: CivilizationInfo) =
|
||||
getBaseGoldCost() * civInfo.gameInfo.gameParameters.gameSpeed.modifier
|
||||
|
||||
override fun getGoldCost(civInfo: CivilizationInfo): Int {
|
||||
var cost = getGoldCostWithGameSpeed(civInfo)
|
||||
for (unique in civInfo.getMatchingUniques("Gold cost of purchasing [] units -[]%")) {
|
||||
if (matchesFilter(unique.params[0]))
|
||||
cost *= 1f - unique.params[1].toFloat() / 100f
|
||||
}
|
||||
override fun getStatBuyCost(cityInfo: CityInfo, stat: Stat): Int? {
|
||||
var cost = getBaseBuyCost(cityInfo, stat)?.toDouble()
|
||||
if (cost == null) return null
|
||||
|
||||
// Deprecated since 3.15
|
||||
if (civInfo.hasUnique("Gold cost of purchasing units -33%")) cost *= 0.67f
|
||||
if (stat == Stat.Gold && cityInfo.civInfo.hasUnique("Gold cost of purchasing units -33%")) cost *= 0.67f
|
||||
//
|
||||
|
||||
for (unique in civInfo.getMatchingUniques("Cost of purchasing items in cities reduced by []%"))
|
||||
cost *= 1f - (unique.params[0].toFloat() / 100f)
|
||||
return (cost / 10).toInt() * 10 // rounded down to nearest ten
|
||||
// Deprecated since 3.15.15
|
||||
if (stat == Stat.Gold) {
|
||||
for (unique in cityInfo.getMatchingUniques("Gold cost of purchasing [] units -[]%")) {
|
||||
if (matchesFilter(unique.params[0]))
|
||||
cost *= 1f - unique.params[1].toFloat() / 100f
|
||||
}
|
||||
for (unique in cityInfo.getMatchingUniques("Cost of purchasing items in cities reduced by []%"))
|
||||
cost *= 1f - (unique.params[0].toFloat() / 100f)
|
||||
}
|
||||
//
|
||||
|
||||
for (unique in cityInfo.getMatchingUniques("[] cost of purchasing [] units []%")) {
|
||||
if (stat.name == unique.params[0] && matchesFilter(unique.params[1]))
|
||||
cost *= 1f + unique.params[2].toFloat() / 100f
|
||||
}
|
||||
for (unique in cityInfo.getMatchingUniques("[] cost of purchasing items in cities []%"))
|
||||
if (stat.name == unique.params[0])
|
||||
cost *= 1f + (unique.params[1].toFloat() / 100f)
|
||||
|
||||
return (cost / 10f).toInt() * 10
|
||||
}
|
||||
|
||||
fun getDisbandGold(civInfo: CivilizationInfo) = getGoldCostWithGameSpeed(civInfo).toInt() / 20
|
||||
fun getDisbandGold(civInfo: CivilizationInfo) = getBaseGoldCost(civInfo).toInt() / 20
|
||||
|
||||
override fun shouldBeDisplayed(construction: CityConstructions): Boolean {
|
||||
val rejectionReason = getRejectionReason(construction)
|
||||
override fun shouldBeDisplayed(cityConstructions: CityConstructions): Boolean {
|
||||
val rejectionReason = getRejectionReason(cityConstructions)
|
||||
return rejectionReason == ""
|
||||
|| rejectionReason.startsWith("Requires")
|
||||
|| rejectionReason.startsWith("Consumes")
|
||||
|| rejectionReason == "Can only be purchased"
|
||||
}
|
||||
|
||||
fun getRejectionReason(cityConstructions: CityConstructions): String {
|
||||
@ -238,7 +251,11 @@ class BaseUnit : INamed, IConstruction, ICivilopediaText {
|
||||
return "Should not be displayed"
|
||||
}
|
||||
val civRejectionReason = getRejectionReason(civInfo)
|
||||
if (civRejectionReason != "") return civRejectionReason
|
||||
if (civRejectionReason != "") {
|
||||
if (civRejectionReason == "Unbuildable" && canBePurchasedWithAnyStat(cityConstructions.cityInfo))
|
||||
return "Can only be purchased"
|
||||
return civRejectionReason
|
||||
}
|
||||
for (unique in uniqueObjects.filter { it.placeholderText == "Requires at least [] population" })
|
||||
if (unique.params[0].toInt() > cityConstructions.cityInfo.population.population)
|
||||
return unique.text
|
||||
@ -293,6 +310,10 @@ class BaseUnit : INamed, IConstruction, ICivilopediaText {
|
||||
if (wasBought && !civInfo.gameInfo.gameParameters.godMode && !unit.hasUnique("Can move immediately once bought"))
|
||||
unit.currentMovement = 0f
|
||||
|
||||
if (unit.hasUnique("Religious Unit")) {
|
||||
unit.religion = cityConstructions.cityInfo.religion.getMajorityReligion()
|
||||
}
|
||||
|
||||
if (this.isCivilian()) return true // tiny optimization makes save files a few bytes smaller
|
||||
|
||||
var XP = cityConstructions.getBuiltBuildings().sumBy { it.xpForNewUnits }
|
||||
@ -313,7 +334,7 @@ class BaseUnit : INamed, IConstruction, ICivilopediaText {
|
||||
}
|
||||
unit.promotions.XP = XP
|
||||
|
||||
for (unique in
|
||||
for (unique in
|
||||
cityConstructions.cityInfo.getMatchingUniques("All newly-trained [] units [] receive the [] promotion")
|
||||
.filter { cityConstructions.cityInfo.matchesFilter(it.params[1]) } +
|
||||
// Deprecated since 3.15.9
|
||||
@ -323,13 +344,13 @@ class BaseUnit : INamed, IConstruction, ICivilopediaText {
|
||||
val filter = unique.params[0]
|
||||
val promotion = unique.params.last()
|
||||
|
||||
if (unit.matchesFilter(filter) ||
|
||||
if (unit.matchesFilter(filter) ||
|
||||
(
|
||||
filter == "relevant" &&
|
||||
filter == "relevant" &&
|
||||
civInfo.gameInfo.ruleSet.unitPromotions.values
|
||||
.any {
|
||||
it.name == promotion
|
||||
&& unit.type.name in it.unitTypes
|
||||
it.name == promotion
|
||||
&& unit.type.name in it.unitTypes
|
||||
}
|
||||
)
|
||||
) {
|
||||
@ -353,12 +374,12 @@ class BaseUnit : INamed, IConstruction, ICivilopediaText {
|
||||
}
|
||||
|
||||
fun matchesFilter(filter: String): Boolean {
|
||||
|
||||
|
||||
return when (filter) {
|
||||
unitType -> true
|
||||
name -> true
|
||||
"All" -> true
|
||||
|
||||
|
||||
"Melee" -> isMelee()
|
||||
"Ranged" -> isRanged()
|
||||
"Civilian" -> isCivilian()
|
||||
@ -367,7 +388,7 @@ class BaseUnit : INamed, IConstruction, ICivilopediaText {
|
||||
"Water" -> isWaterUnit()
|
||||
"Air" -> isAirUnit()
|
||||
"non-air" -> !movesLikeAirUnits()
|
||||
|
||||
|
||||
"Nuclear Weapon" -> isNuclearWeapon()
|
||||
// Deprecated as of 3.15.2
|
||||
"military water" -> isMilitary() && isWaterUnit()
|
||||
@ -378,8 +399,8 @@ class BaseUnit : INamed, IConstruction, ICivilopediaText {
|
||||
// "military units" --> "Military"
|
||||
&& matchesFilter(filter.removeSuffix(" units").toLowerCase(Locale.ENGLISH).capitalize(Locale.ENGLISH))
|
||||
) return true
|
||||
return uniques.contains(filter)
|
||||
}
|
||||
return uniques.contains(filter)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -403,12 +424,12 @@ class BaseUnit : INamed, IConstruction, ICivilopediaText {
|
||||
fun isMelee() = !isRanged() && strength > 0
|
||||
fun isMilitary() = isRanged() || isMelee()
|
||||
fun isCivilian() = !isMilitary()
|
||||
|
||||
|
||||
fun isLandUnit() = getType().isLandUnit()
|
||||
fun isWaterUnit() = getType().isWaterUnit()
|
||||
fun isAirUnit() = getType().isAirUnit()
|
||||
|
||||
fun isProbablySiegeUnit() =
|
||||
fun isProbablySiegeUnit() =
|
||||
(
|
||||
isRanged()
|
||||
&& (uniqueObjects + getType().uniqueObjects)
|
||||
|
@ -1,11 +1,13 @@
|
||||
package com.unciv.models.stats
|
||||
|
||||
enum class Stat{
|
||||
Production,
|
||||
Food,
|
||||
Gold,
|
||||
Science,
|
||||
Culture,
|
||||
Happiness,
|
||||
Faith
|
||||
import com.unciv.models.UncivSound
|
||||
|
||||
enum class Stat (val sound: UncivSound) {
|
||||
Production(UncivSound.Click),
|
||||
Food(UncivSound.Click),
|
||||
Gold(UncivSound.Coin),
|
||||
Science(UncivSound.Chimes),
|
||||
Culture(UncivSound.Paper),
|
||||
Happiness(UncivSound.Click),
|
||||
Faith(UncivSound.Choir),
|
||||
}
|
@ -224,7 +224,8 @@ object TranslationFileWriter {
|
||||
"in all non-occupied cities",
|
||||
"in all cities with a world wonder",
|
||||
"in all cities connected to capital",
|
||||
"in all cities with a garrison"
|
||||
"in all cities with a garrison",
|
||||
"in all cities in which the majority religion is a major religion"
|
||||
)
|
||||
|
||||
val startMillis = System.currentTimeMillis()
|
||||
|
@ -7,10 +7,7 @@ import com.badlogic.gdx.scenes.scene2d.Touchable
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.TextButton
|
||||
import com.badlogic.gdx.utils.Align
|
||||
import com.unciv.logic.city.CityConstructions
|
||||
import com.unciv.logic.city.CityInfo
|
||||
import com.unciv.logic.city.IConstruction
|
||||
import com.unciv.logic.city.PerpetualConstruction
|
||||
import com.unciv.logic.city.*
|
||||
import com.unciv.models.UncivSound
|
||||
import com.unciv.models.ruleset.Building
|
||||
import com.unciv.models.ruleset.unit.BaseUnit
|
||||
@ -70,7 +67,9 @@ class CityConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBase
|
||||
private fun updateButtons(construction: IConstruction?) {
|
||||
buttons.clear()
|
||||
buttons.add(getQueueButton(construction)).padRight(5f)
|
||||
buttons.add(getBuyButton(construction))
|
||||
if (construction != null && construction !is PerpetualConstruction)
|
||||
for (button in getBuyButtons(construction as INonPerpetualConstruction))
|
||||
buttons.add(button).padRight(5f)
|
||||
}
|
||||
|
||||
private fun updateConstructionQueue() {
|
||||
@ -262,7 +261,7 @@ class CityConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBase
|
||||
if (cityConstructions.getWorkDone(constructionName) == 0) return Table()
|
||||
|
||||
val constructionPercentage = cityConstructions.getWorkDone(constructionName) /
|
||||
construction.getProductionCost(cityConstructions.cityInfo.civInfo).toFloat()
|
||||
(construction as INonPerpetualConstruction).getProductionCost(cityConstructions.cityInfo.civInfo).toFloat()
|
||||
return ImageGetter.getProgressBarVertical(2f, 30f, constructionPercentage,
|
||||
Color.BROWN.cpy().lerp(Color.WHITE, 0.5f), Color.WHITE)
|
||||
}
|
||||
@ -377,9 +376,9 @@ class CityConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBase
|
||||
}
|
||||
}
|
||||
|
||||
fun purchaseConstruction(construction: IConstruction) {
|
||||
fun purchaseConstruction(construction: INonPerpetualConstruction, stat: Stat = Stat.Gold) {
|
||||
val city = cityScreen.city
|
||||
if (!city.cityConstructions.purchaseConstruction(construction.name, selectedQueueEntry, false)) {
|
||||
if (!city.cityConstructions.purchaseConstruction(construction.name, selectedQueueEntry, false, stat)) {
|
||||
Popup(cityScreen).apply {
|
||||
add("No space available to place [${construction.name}] near [${city.name}]".tr()).row()
|
||||
addCloseButton()
|
||||
@ -393,38 +392,47 @@ class CityConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBase
|
||||
}
|
||||
cityScreen.update()
|
||||
}
|
||||
|
||||
private fun getBuyButtons(construction: INonPerpetualConstruction?): List<TextButton> {
|
||||
return listOf(Stat.Gold, Stat.Faith, Stat.Culture, Stat.Science, Stat.Food)
|
||||
.mapNotNull { getBuyButton(construction, it) }
|
||||
}
|
||||
|
||||
private fun getBuyButton(construction: IConstruction?): TextButton {
|
||||
private fun getBuyButton(construction: INonPerpetualConstruction?, stat: Stat = Stat.Gold): TextButton? {
|
||||
if (stat !in listOf(Stat.Gold, Stat.Faith, Stat.Culture, Stat.Science, Stat.Food))
|
||||
return null
|
||||
val city = cityScreen.city
|
||||
val cityConstructions = city.cityConstructions
|
||||
|
||||
val button = "".toTextButton()
|
||||
|
||||
if (construction == null || construction is PerpetualConstruction ||
|
||||
(!construction.canBePurchased() && !city.civInfo.gameInfo.gameParameters.godMode)) {
|
||||
(!construction.canBePurchasedWithStat(city, stat) && !city.civInfo.gameInfo.gameParameters.godMode)) {
|
||||
// fully disable a "buy" button only for "priceless" buildings such as wonders
|
||||
// for all other cases, the price should be displayed
|
||||
button.setText("Buy".tr())
|
||||
button.disable()
|
||||
if (stat == Stat.Gold) {
|
||||
button.setText("Buy".tr())
|
||||
button.disable()
|
||||
}
|
||||
else return null
|
||||
} else {
|
||||
val constructionGoldCost = construction.getGoldCost(city.civInfo)
|
||||
button.setText("Buy".tr() + " " + constructionGoldCost)
|
||||
button.add(ImageGetter.getStatIcon(Stat.Gold.name)).size(20f).padBottom(2f)
|
||||
val constructionBuyCost = construction.getStatBuyCost(city, stat)!!
|
||||
button.setText("Buy".tr() + " " + constructionBuyCost)
|
||||
button.add(ImageGetter.getStatIcon(stat.name)).size(20f).padBottom(2f)
|
||||
|
||||
button.onClick(UncivSound.Coin) {
|
||||
button.onClick(stat.sound) {
|
||||
button.disable()
|
||||
cityScreen.closeAllPopups()
|
||||
|
||||
val purchasePrompt = "Currently you have [${city.civInfo.gold}] gold.".tr() + "\n" +
|
||||
"Would you like to purchase [${construction.name}] for [$constructionGoldCost] gold?".tr()
|
||||
YesNoPopup(purchasePrompt, { purchaseConstruction(construction) }, cityScreen, { cityScreen.update() }).open()
|
||||
|
||||
val purchasePrompt = "Currently you have [${city.getStatReserve(stat)}] [${stat.name}].".tr() + "\n" +
|
||||
"Would you like to purchase [${construction.name}] for [$constructionBuyCost] [${stat.name}]?".tr()
|
||||
YesNoPopup(purchasePrompt, { purchaseConstruction(construction, stat) }, cityScreen, { cityScreen.update() }).open()
|
||||
}
|
||||
|
||||
if (!construction.isBuildable(cityConstructions)
|
||||
|| !cityScreen.canChangeState
|
||||
|| city.isPuppet || city.isInResistance()
|
||||
|
||||
if (!cityScreen.canChangeState
|
||||
|| city.isPuppet
|
||||
|| city.isInResistance()
|
||||
|| !city.canPurchase(construction)
|
||||
|| (constructionGoldCost > city.civInfo.gold && !city.civInfo.gameInfo.gameParameters.godMode))
|
||||
|| (constructionBuyCost > city.getStatReserve(stat) && !city.civInfo.gameInfo.gameParameters.godMode))
|
||||
button.disable()
|
||||
}
|
||||
|
||||
@ -432,7 +440,7 @@ class CityConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBase
|
||||
|
||||
return button
|
||||
}
|
||||
|
||||
|
||||
private fun getRaisePriorityButton(constructionQueueIndex: Int, name: String, city: CityInfo): Table {
|
||||
val tab = Table()
|
||||
tab.add(ImageGetter.getImage("OtherIcons/Up").surroundWithCircle(40f))
|
||||
|
@ -13,6 +13,7 @@ import com.badlogic.gdx.utils.Align
|
||||
import com.unciv.logic.battle.CityCombatant
|
||||
import com.unciv.logic.city.CityConstructions
|
||||
import com.unciv.logic.city.CityInfo
|
||||
import com.unciv.logic.city.INonPerpetualConstruction
|
||||
import com.unciv.logic.city.PerpetualConstruction
|
||||
import com.unciv.logic.civilization.diplomacy.RelationshipLevel
|
||||
import com.unciv.ui.cityscreen.CityScreen
|
||||
@ -386,7 +387,7 @@ class CityButton(val city: CityInfo, private val tileGroup: WorldTileGroup): Tab
|
||||
group.addActor(label)
|
||||
|
||||
val constructionPercentage = cityConstructions.getWorkDone(cityCurrentConstruction.name) /
|
||||
cityCurrentConstruction.getProductionCost(cityConstructions.cityInfo.civInfo).toFloat()
|
||||
(cityCurrentConstruction as INonPerpetualConstruction).getProductionCost(cityConstructions.cityInfo.civInfo).toFloat()
|
||||
val productionBar = ImageGetter.getProgressBarVertical(2f, groupHeight, constructionPercentage,
|
||||
Color.BROWN.cpy().lerp(Color.WHITE, 0.5f), Color.BLACK)
|
||||
productionBar.x = 10f
|
||||
|
@ -12,6 +12,7 @@ import com.badlogic.gdx.graphics.g2d.TextureRegion
|
||||
import com.badlogic.gdx.utils.Array
|
||||
import com.badlogic.gdx.utils.Disposable
|
||||
import com.unciv.UncivGame
|
||||
import com.unciv.models.stats.Stat
|
||||
|
||||
interface NativeFontImplementation {
|
||||
fun getFontSize(): Int
|
||||
@ -151,7 +152,6 @@ object Fonts {
|
||||
return pixmap
|
||||
}
|
||||
|
||||
|
||||
const val turn = '⏳' // U+23F3 'hourglass'
|
||||
const val strength = '†' // U+2020 'dagger'
|
||||
const val rangedStrength = '‡' // U+2021 'double dagger'
|
||||
@ -164,4 +164,16 @@ object Fonts {
|
||||
const val culture = '♪' // U+266A 'eighth note' (🎵 U+1F3B5 'musical note')
|
||||
const val happiness = '⌣' // U+2323 'smile' (😀 U+1F600 'grinning face')
|
||||
const val faith = '☮' // U+262E 'peace symbol' (🕊 U+1F54A 'dove of peace')
|
||||
|
||||
fun statToChar(stat: Stat): Char {
|
||||
return when (stat) {
|
||||
Stat.Food -> food
|
||||
Stat.Production -> production
|
||||
Stat.Gold -> gold
|
||||
Stat.Happiness -> happiness
|
||||
Stat.Culture -> culture
|
||||
Stat.Science -> science
|
||||
Stat.Faith -> faith
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -125,13 +125,14 @@ Unless otherwise specified, all the following are from [the Noun Project](https:
|
||||
* [Robot](https://thenounproject.com/term/robot/1182459/) by Lluisa Iborra, ES for Giant Death Robot
|
||||
|
||||
|
||||
### Great People
|
||||
### All Eras
|
||||
|
||||
* [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*
|
||||
* [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
|
||||
|
||||
## Resources
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user